From fe66edcc1c5ad8fbbf40dc15d9061c8668bb0ccf Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 22 Jan 2019 13:50:38 -0800 Subject: [PATCH 001/196] add tests to show that implicit joins with order by work fine if ordering by columns of first table, but not if ordering by columns of second table Signed-off-by: deepthi --- data/test/vtgate/postprocess_cases.txt | 117 +++++++++++++++++++++++++ data/test/vtgate/unsupported_cases.txt | 4 + go/vt/vtgate/planbuilder/plan_test.go | 2 +- 3 files changed, 122 insertions(+), 1 deletion(-) diff --git a/data/test/vtgate/postprocess_cases.txt b/data/test/vtgate/postprocess_cases.txt index 4f21d74d498..6a63e85c0ad 100644 --- a/data/test/vtgate/postprocess_cases.txt +++ b/data/test/vtgate/postprocess_cases.txt @@ -398,6 +398,123 @@ } } +# ORDER BY non-key column for join +"select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by a" +{ + "Original": "select user.col1 as a, user.col2, music.col3 from user join music on user.id = music.id where user.id = 1 order by a", + "Instructions": { + "Opcode": "Join", + "Left": { + "Opcode": "SelectEqualUnique", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "select user.col1 as a, user.col2, user.id from user where user.id = 1 order by a asc", + "FieldQuery": "select user.col1 as a, user.col2, user.id from user where 1 != 1", + "Vindex": "user_index", + "Values": [1] + }, + "Right": { + "Opcode": "SelectEqualUnique", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "select music.col3 from music where music.id = :user_id", + "FieldQuery": "select music.col3 from music where 1 != 1", + "Vindex": "music_user_map", + "Values": [":user_id"] + }, + "Cols": [ + -1, + -2, + 1 + ], + "Vars": { + "user_id": 2 + } + } +} + +# ORDER BY non-key column for implicit join +"select user.col1 as a, user.col2, music.col3 from user, music where user.id = music.id and user.id = 1 order by a" +{ + "Original": "select user.col1 as a, user.col2, music.col3 from user, music where user.id = music.id and user.id = 1 order by a", + "Instructions": { + "Opcode": "Join", + "Left": { + "Opcode": "SelectEqualUnique", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "select user.col1 as a, user.col2, user.id from user where user.id = 1 order by a asc", + "FieldQuery": "select user.col1 as a, user.col2, user.id from user where 1 != 1", + "Vindex": "user_index", + "Values": [1] + }, + "Right": { + "Opcode": "SelectEqualUnique", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "select music.col3 from music where music.id = :user_id", + "FieldQuery": "select music.col3 from music where 1 != 1", + "Vindex": "music_user_map", + "Values": [":user_id"] + }, + "Cols": [ + -1, + -2, + 1 + ], + "Vars": { + "user_id": 2 + } + } +} + +# ORDER BY non-key column from second table for implicit join FAILS!! +"select user.col1 a, user.col2 b, music.col3 c from user, music where user.id = music.id and user.id = 1 order by c" +{ + "Original": "select user.col1 a, user.col2 b, music.col3 c from user, music where user.id = music.id and user.id = 1 order by c", + "Instructions": { + "Opcode": "Join", + "Left": { + "Opcode": "SelectEqualUnique", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "select user.col1 a, user.col2 b, user.id from user where user.id = 1", + "FieldQuery": "select user.col1 a, user.col2 b, user.id from user where 1 != 1", + "Vindex": "user_index", + "Values": [1] + }, + "Right": { + "Opcode": "SelectEqualUnique", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "Query": "select music.col3 c from music where music.id = :user_id order by c", + "FieldQuery": "select music.col3 c from music where 1 != 1", + "Vindex": "music_user_map", + "Values": [":user_id"] + }, + "Cols": [ + -1, + -2, + 1 + ], + "Vars": { + "user_id": 2 + } + } +} + # ORDER BY NULL after pull-out subquery "select col from user where col in (select col2 from user) order by null" { diff --git a/data/test/vtgate/unsupported_cases.txt b/data/test/vtgate/unsupported_cases.txt index af1cb7af617..d360aa0f368 100644 --- a/data/test/vtgate/unsupported_cases.txt +++ b/data/test/vtgate/unsupported_cases.txt @@ -55,6 +55,10 @@ "select id from (select user.id, user.col from user join user_extra) as t order by id" "unsupported: cannot order by on a cross-shard subquery" +# order by on a cross-shard query. Note: this is only a problem when an order by column is from the second table +"select user.col1 as a, user.col2 b, music.col3 c from user, music where user.id = music.id and user.id = 1 order by c" +"unsupported: order by spans across shards" + # scatter order by with * expression "select * from user order by id" "unsupported: in scatter query: order by must reference a column in the select list: id asc" diff --git a/go/vt/vtgate/planbuilder/plan_test.go b/go/vt/vtgate/planbuilder/plan_test.go index d6bcd90d667..7bdb2fd56ac 100644 --- a/go/vt/vtgate/planbuilder/plan_test.go +++ b/go/vt/vtgate/planbuilder/plan_test.go @@ -237,7 +237,7 @@ func testFile(t *testing.T, filename string, vschema *vindexes.VSchema) { out = string(bout) } if out != tcase.output { - t.Errorf("File: %s, Line:%v\n%s, want\n%s", filename, tcase.lineno, out, tcase.output) + t.Errorf("File: %s, Line:%v\n got:\n%s, \nwant:\n%s", filename, tcase.lineno, out, tcase.output) // Uncomment these lines to re-generate input files if err != nil { out = fmt.Sprintf("\"%s\"", out) From 16ca2c34d371db7be941c463bdb7100e7eb7f7df Mon Sep 17 00:00:00 2001 From: deepthi Date: Thu, 24 Jan 2019 17:08:13 -0800 Subject: [PATCH 002/196] #4481 rollback changes made during reparent if we encounter errors Signed-off-by: deepthi --- .../tabletmanagerdata/tabletmanagerdata.pb.go | 514 +++++++++-------- .../tabletmanagerservice.pb.go | 174 +++--- go/vt/vtcombo/tablet_map.go | 4 + go/vt/vttablet/agentrpctest/test_agent_rpc.go | 22 + go/vt/vttablet/faketmclient/fake_client.go | 5 + go/vt/vttablet/grpctmclient/client.go | 11 + go/vt/vttablet/grpctmserver/server.go | 8 + go/vt/vttablet/tabletmanager/rpc_agent.go | 2 + .../vttablet/tabletmanager/rpc_replication.go | 53 ++ go/vt/vttablet/tmclient/rpc_client_api.go | 4 + go/vt/wrangler/reparent.go | 5 + .../testlib/planned_reparent_shard_test.go | 96 ++++ proto/tabletmanagerdata.proto | 6 + proto/tabletmanagerservice.proto | 3 + py/vtproto/tabletmanagerdata_pb2.py | 536 ++++++++++-------- py/vtproto/tabletmanagerservice_pb2.py | 122 ++-- py/vtproto/tabletmanagerservice_pb2_grpc.py | 17 + test/utils.py | 2 +- 18 files changed, 993 insertions(+), 591 deletions(-) diff --git a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go index 432b78cad9b..479fa1358af 100644 --- a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go +++ b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go @@ -46,7 +46,7 @@ func (m *TableDefinition) Reset() { *m = TableDefinition{} } func (m *TableDefinition) String() string { return proto.CompactTextString(m) } func (*TableDefinition) ProtoMessage() {} func (*TableDefinition) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{0} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{0} } func (m *TableDefinition) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TableDefinition.Unmarshal(m, b) @@ -128,7 +128,7 @@ func (m *SchemaDefinition) Reset() { *m = SchemaDefinition{} } func (m *SchemaDefinition) String() string { return proto.CompactTextString(m) } func (*SchemaDefinition) ProtoMessage() {} func (*SchemaDefinition) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{1} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{1} } func (m *SchemaDefinition) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SchemaDefinition.Unmarshal(m, b) @@ -183,7 +183,7 @@ func (m *SchemaChangeResult) Reset() { *m = SchemaChangeResult{} } func (m *SchemaChangeResult) String() string { return proto.CompactTextString(m) } func (*SchemaChangeResult) ProtoMessage() {} func (*SchemaChangeResult) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{2} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{2} } func (m *SchemaChangeResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SchemaChangeResult.Unmarshal(m, b) @@ -234,7 +234,7 @@ func (m *UserPermission) Reset() { *m = UserPermission{} } func (m *UserPermission) String() string { return proto.CompactTextString(m) } func (*UserPermission) ProtoMessage() {} func (*UserPermission) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{3} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{3} } func (m *UserPermission) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UserPermission.Unmarshal(m, b) @@ -298,7 +298,7 @@ func (m *DbPermission) Reset() { *m = DbPermission{} } func (m *DbPermission) String() string { return proto.CompactTextString(m) } func (*DbPermission) ProtoMessage() {} func (*DbPermission) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{4} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{4} } func (m *DbPermission) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DbPermission.Unmarshal(m, b) @@ -360,7 +360,7 @@ func (m *Permissions) Reset() { *m = Permissions{} } func (m *Permissions) String() string { return proto.CompactTextString(m) } func (*Permissions) ProtoMessage() {} func (*Permissions) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{5} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{5} } func (m *Permissions) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Permissions.Unmarshal(m, b) @@ -405,7 +405,7 @@ func (m *PingRequest) Reset() { *m = PingRequest{} } func (m *PingRequest) String() string { return proto.CompactTextString(m) } func (*PingRequest) ProtoMessage() {} func (*PingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{6} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{6} } func (m *PingRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PingRequest.Unmarshal(m, b) @@ -443,7 +443,7 @@ func (m *PingResponse) Reset() { *m = PingResponse{} } func (m *PingResponse) String() string { return proto.CompactTextString(m) } func (*PingResponse) ProtoMessage() {} func (*PingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{7} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{7} } func (m *PingResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PingResponse.Unmarshal(m, b) @@ -482,7 +482,7 @@ func (m *SleepRequest) Reset() { *m = SleepRequest{} } func (m *SleepRequest) String() string { return proto.CompactTextString(m) } func (*SleepRequest) ProtoMessage() {} func (*SleepRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{8} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{8} } func (m *SleepRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SleepRequest.Unmarshal(m, b) @@ -519,7 +519,7 @@ func (m *SleepResponse) Reset() { *m = SleepResponse{} } func (m *SleepResponse) String() string { return proto.CompactTextString(m) } func (*SleepResponse) ProtoMessage() {} func (*SleepResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{9} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{9} } func (m *SleepResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SleepResponse.Unmarshal(m, b) @@ -552,7 +552,7 @@ func (m *ExecuteHookRequest) Reset() { *m = ExecuteHookRequest{} } func (m *ExecuteHookRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteHookRequest) ProtoMessage() {} func (*ExecuteHookRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{10} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{10} } func (m *ExecuteHookRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteHookRequest.Unmarshal(m, b) @@ -606,7 +606,7 @@ func (m *ExecuteHookResponse) Reset() { *m = ExecuteHookResponse{} } func (m *ExecuteHookResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteHookResponse) ProtoMessage() {} func (*ExecuteHookResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{11} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{11} } func (m *ExecuteHookResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteHookResponse.Unmarshal(m, b) @@ -660,7 +660,7 @@ func (m *GetSchemaRequest) Reset() { *m = GetSchemaRequest{} } func (m *GetSchemaRequest) String() string { return proto.CompactTextString(m) } func (*GetSchemaRequest) ProtoMessage() {} func (*GetSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{12} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{12} } func (m *GetSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSchemaRequest.Unmarshal(m, b) @@ -712,7 +712,7 @@ func (m *GetSchemaResponse) Reset() { *m = GetSchemaResponse{} } func (m *GetSchemaResponse) String() string { return proto.CompactTextString(m) } func (*GetSchemaResponse) ProtoMessage() {} func (*GetSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{13} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{13} } func (m *GetSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSchemaResponse.Unmarshal(m, b) @@ -749,7 +749,7 @@ func (m *GetPermissionsRequest) Reset() { *m = GetPermissionsRequest{} } func (m *GetPermissionsRequest) String() string { return proto.CompactTextString(m) } func (*GetPermissionsRequest) ProtoMessage() {} func (*GetPermissionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{14} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{14} } func (m *GetPermissionsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetPermissionsRequest.Unmarshal(m, b) @@ -780,7 +780,7 @@ func (m *GetPermissionsResponse) Reset() { *m = GetPermissionsResponse{} func (m *GetPermissionsResponse) String() string { return proto.CompactTextString(m) } func (*GetPermissionsResponse) ProtoMessage() {} func (*GetPermissionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{15} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{15} } func (m *GetPermissionsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetPermissionsResponse.Unmarshal(m, b) @@ -817,7 +817,7 @@ func (m *SetReadOnlyRequest) Reset() { *m = SetReadOnlyRequest{} } func (m *SetReadOnlyRequest) String() string { return proto.CompactTextString(m) } func (*SetReadOnlyRequest) ProtoMessage() {} func (*SetReadOnlyRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{16} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{16} } func (m *SetReadOnlyRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadOnlyRequest.Unmarshal(m, b) @@ -847,7 +847,7 @@ func (m *SetReadOnlyResponse) Reset() { *m = SetReadOnlyResponse{} } func (m *SetReadOnlyResponse) String() string { return proto.CompactTextString(m) } func (*SetReadOnlyResponse) ProtoMessage() {} func (*SetReadOnlyResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{17} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{17} } func (m *SetReadOnlyResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadOnlyResponse.Unmarshal(m, b) @@ -877,7 +877,7 @@ func (m *SetReadWriteRequest) Reset() { *m = SetReadWriteRequest{} } func (m *SetReadWriteRequest) String() string { return proto.CompactTextString(m) } func (*SetReadWriteRequest) ProtoMessage() {} func (*SetReadWriteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{18} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{18} } func (m *SetReadWriteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadWriteRequest.Unmarshal(m, b) @@ -907,7 +907,7 @@ func (m *SetReadWriteResponse) Reset() { *m = SetReadWriteResponse{} } func (m *SetReadWriteResponse) String() string { return proto.CompactTextString(m) } func (*SetReadWriteResponse) ProtoMessage() {} func (*SetReadWriteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{19} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{19} } func (m *SetReadWriteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadWriteResponse.Unmarshal(m, b) @@ -938,7 +938,7 @@ func (m *ChangeTypeRequest) Reset() { *m = ChangeTypeRequest{} } func (m *ChangeTypeRequest) String() string { return proto.CompactTextString(m) } func (*ChangeTypeRequest) ProtoMessage() {} func (*ChangeTypeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{20} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{20} } func (m *ChangeTypeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChangeTypeRequest.Unmarshal(m, b) @@ -975,7 +975,7 @@ func (m *ChangeTypeResponse) Reset() { *m = ChangeTypeResponse{} } func (m *ChangeTypeResponse) String() string { return proto.CompactTextString(m) } func (*ChangeTypeResponse) ProtoMessage() {} func (*ChangeTypeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{21} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{21} } func (m *ChangeTypeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChangeTypeResponse.Unmarshal(m, b) @@ -1005,7 +1005,7 @@ func (m *RefreshStateRequest) Reset() { *m = RefreshStateRequest{} } func (m *RefreshStateRequest) String() string { return proto.CompactTextString(m) } func (*RefreshStateRequest) ProtoMessage() {} func (*RefreshStateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{22} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{22} } func (m *RefreshStateRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RefreshStateRequest.Unmarshal(m, b) @@ -1035,7 +1035,7 @@ func (m *RefreshStateResponse) Reset() { *m = RefreshStateResponse{} } func (m *RefreshStateResponse) String() string { return proto.CompactTextString(m) } func (*RefreshStateResponse) ProtoMessage() {} func (*RefreshStateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{23} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{23} } func (m *RefreshStateResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RefreshStateResponse.Unmarshal(m, b) @@ -1065,7 +1065,7 @@ func (m *RunHealthCheckRequest) Reset() { *m = RunHealthCheckRequest{} } func (m *RunHealthCheckRequest) String() string { return proto.CompactTextString(m) } func (*RunHealthCheckRequest) ProtoMessage() {} func (*RunHealthCheckRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{24} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{24} } func (m *RunHealthCheckRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RunHealthCheckRequest.Unmarshal(m, b) @@ -1095,7 +1095,7 @@ func (m *RunHealthCheckResponse) Reset() { *m = RunHealthCheckResponse{} func (m *RunHealthCheckResponse) String() string { return proto.CompactTextString(m) } func (*RunHealthCheckResponse) ProtoMessage() {} func (*RunHealthCheckResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{25} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{25} } func (m *RunHealthCheckResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RunHealthCheckResponse.Unmarshal(m, b) @@ -1126,7 +1126,7 @@ func (m *IgnoreHealthErrorRequest) Reset() { *m = IgnoreHealthErrorReque func (m *IgnoreHealthErrorRequest) String() string { return proto.CompactTextString(m) } func (*IgnoreHealthErrorRequest) ProtoMessage() {} func (*IgnoreHealthErrorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{26} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{26} } func (m *IgnoreHealthErrorRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IgnoreHealthErrorRequest.Unmarshal(m, b) @@ -1163,7 +1163,7 @@ func (m *IgnoreHealthErrorResponse) Reset() { *m = IgnoreHealthErrorResp func (m *IgnoreHealthErrorResponse) String() string { return proto.CompactTextString(m) } func (*IgnoreHealthErrorResponse) ProtoMessage() {} func (*IgnoreHealthErrorResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{27} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{27} } func (m *IgnoreHealthErrorResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IgnoreHealthErrorResponse.Unmarshal(m, b) @@ -1197,7 +1197,7 @@ func (m *ReloadSchemaRequest) Reset() { *m = ReloadSchemaRequest{} } func (m *ReloadSchemaRequest) String() string { return proto.CompactTextString(m) } func (*ReloadSchemaRequest) ProtoMessage() {} func (*ReloadSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{28} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{28} } func (m *ReloadSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReloadSchemaRequest.Unmarshal(m, b) @@ -1234,7 +1234,7 @@ func (m *ReloadSchemaResponse) Reset() { *m = ReloadSchemaResponse{} } func (m *ReloadSchemaResponse) String() string { return proto.CompactTextString(m) } func (*ReloadSchemaResponse) ProtoMessage() {} func (*ReloadSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{29} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{29} } func (m *ReloadSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReloadSchemaResponse.Unmarshal(m, b) @@ -1265,7 +1265,7 @@ func (m *PreflightSchemaRequest) Reset() { *m = PreflightSchemaRequest{} func (m *PreflightSchemaRequest) String() string { return proto.CompactTextString(m) } func (*PreflightSchemaRequest) ProtoMessage() {} func (*PreflightSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{30} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{30} } func (m *PreflightSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PreflightSchemaRequest.Unmarshal(m, b) @@ -1305,7 +1305,7 @@ func (m *PreflightSchemaResponse) Reset() { *m = PreflightSchemaResponse func (m *PreflightSchemaResponse) String() string { return proto.CompactTextString(m) } func (*PreflightSchemaResponse) ProtoMessage() {} func (*PreflightSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{31} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{31} } func (m *PreflightSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PreflightSchemaResponse.Unmarshal(m, b) @@ -1347,7 +1347,7 @@ func (m *ApplySchemaRequest) Reset() { *m = ApplySchemaRequest{} } func (m *ApplySchemaRequest) String() string { return proto.CompactTextString(m) } func (*ApplySchemaRequest) ProtoMessage() {} func (*ApplySchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{32} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{32} } func (m *ApplySchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ApplySchemaRequest.Unmarshal(m, b) @@ -1414,7 +1414,7 @@ func (m *ApplySchemaResponse) Reset() { *m = ApplySchemaResponse{} } func (m *ApplySchemaResponse) String() string { return proto.CompactTextString(m) } func (*ApplySchemaResponse) ProtoMessage() {} func (*ApplySchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{33} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{33} } func (m *ApplySchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ApplySchemaResponse.Unmarshal(m, b) @@ -1458,7 +1458,7 @@ func (m *LockTablesRequest) Reset() { *m = LockTablesRequest{} } func (m *LockTablesRequest) String() string { return proto.CompactTextString(m) } func (*LockTablesRequest) ProtoMessage() {} func (*LockTablesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{34} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{34} } func (m *LockTablesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LockTablesRequest.Unmarshal(m, b) @@ -1488,7 +1488,7 @@ func (m *LockTablesResponse) Reset() { *m = LockTablesResponse{} } func (m *LockTablesResponse) String() string { return proto.CompactTextString(m) } func (*LockTablesResponse) ProtoMessage() {} func (*LockTablesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{35} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{35} } func (m *LockTablesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LockTablesResponse.Unmarshal(m, b) @@ -1518,7 +1518,7 @@ func (m *UnlockTablesRequest) Reset() { *m = UnlockTablesRequest{} } func (m *UnlockTablesRequest) String() string { return proto.CompactTextString(m) } func (*UnlockTablesRequest) ProtoMessage() {} func (*UnlockTablesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{36} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{36} } func (m *UnlockTablesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UnlockTablesRequest.Unmarshal(m, b) @@ -1548,7 +1548,7 @@ func (m *UnlockTablesResponse) Reset() { *m = UnlockTablesResponse{} } func (m *UnlockTablesResponse) String() string { return proto.CompactTextString(m) } func (*UnlockTablesResponse) ProtoMessage() {} func (*UnlockTablesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{37} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{37} } func (m *UnlockTablesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UnlockTablesResponse.Unmarshal(m, b) @@ -1583,7 +1583,7 @@ func (m *ExecuteFetchAsDbaRequest) Reset() { *m = ExecuteFetchAsDbaReque func (m *ExecuteFetchAsDbaRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsDbaRequest) ProtoMessage() {} func (*ExecuteFetchAsDbaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{38} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{38} } func (m *ExecuteFetchAsDbaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsDbaRequest.Unmarshal(m, b) @@ -1649,7 +1649,7 @@ func (m *ExecuteFetchAsDbaResponse) Reset() { *m = ExecuteFetchAsDbaResp func (m *ExecuteFetchAsDbaResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsDbaResponse) ProtoMessage() {} func (*ExecuteFetchAsDbaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{39} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{39} } func (m *ExecuteFetchAsDbaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsDbaResponse.Unmarshal(m, b) @@ -1690,7 +1690,7 @@ func (m *ExecuteFetchAsAllPrivsRequest) Reset() { *m = ExecuteFetchAsAll func (m *ExecuteFetchAsAllPrivsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAllPrivsRequest) ProtoMessage() {} func (*ExecuteFetchAsAllPrivsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{40} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{40} } func (m *ExecuteFetchAsAllPrivsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAllPrivsRequest.Unmarshal(m, b) @@ -1749,7 +1749,7 @@ func (m *ExecuteFetchAsAllPrivsResponse) Reset() { *m = ExecuteFetchAsAl func (m *ExecuteFetchAsAllPrivsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAllPrivsResponse) ProtoMessage() {} func (*ExecuteFetchAsAllPrivsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{41} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{41} } func (m *ExecuteFetchAsAllPrivsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAllPrivsResponse.Unmarshal(m, b) @@ -1788,7 +1788,7 @@ func (m *ExecuteFetchAsAppRequest) Reset() { *m = ExecuteFetchAsAppReque func (m *ExecuteFetchAsAppRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAppRequest) ProtoMessage() {} func (*ExecuteFetchAsAppRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{42} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{42} } func (m *ExecuteFetchAsAppRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAppRequest.Unmarshal(m, b) @@ -1833,7 +1833,7 @@ func (m *ExecuteFetchAsAppResponse) Reset() { *m = ExecuteFetchAsAppResp func (m *ExecuteFetchAsAppResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAppResponse) ProtoMessage() {} func (*ExecuteFetchAsAppResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{43} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{43} } func (m *ExecuteFetchAsAppResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAppResponse.Unmarshal(m, b) @@ -1870,7 +1870,7 @@ func (m *SlaveStatusRequest) Reset() { *m = SlaveStatusRequest{} } func (m *SlaveStatusRequest) String() string { return proto.CompactTextString(m) } func (*SlaveStatusRequest) ProtoMessage() {} func (*SlaveStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{44} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{44} } func (m *SlaveStatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveStatusRequest.Unmarshal(m, b) @@ -1901,7 +1901,7 @@ func (m *SlaveStatusResponse) Reset() { *m = SlaveStatusResponse{} } func (m *SlaveStatusResponse) String() string { return proto.CompactTextString(m) } func (*SlaveStatusResponse) ProtoMessage() {} func (*SlaveStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{45} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{45} } func (m *SlaveStatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveStatusResponse.Unmarshal(m, b) @@ -1938,7 +1938,7 @@ func (m *MasterPositionRequest) Reset() { *m = MasterPositionRequest{} } func (m *MasterPositionRequest) String() string { return proto.CompactTextString(m) } func (*MasterPositionRequest) ProtoMessage() {} func (*MasterPositionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{46} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{46} } func (m *MasterPositionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MasterPositionRequest.Unmarshal(m, b) @@ -1969,7 +1969,7 @@ func (m *MasterPositionResponse) Reset() { *m = MasterPositionResponse{} func (m *MasterPositionResponse) String() string { return proto.CompactTextString(m) } func (*MasterPositionResponse) ProtoMessage() {} func (*MasterPositionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{47} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{47} } func (m *MasterPositionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MasterPositionResponse.Unmarshal(m, b) @@ -2006,7 +2006,7 @@ func (m *StopSlaveRequest) Reset() { *m = StopSlaveRequest{} } func (m *StopSlaveRequest) String() string { return proto.CompactTextString(m) } func (*StopSlaveRequest) ProtoMessage() {} func (*StopSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{48} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{48} } func (m *StopSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveRequest.Unmarshal(m, b) @@ -2036,7 +2036,7 @@ func (m *StopSlaveResponse) Reset() { *m = StopSlaveResponse{} } func (m *StopSlaveResponse) String() string { return proto.CompactTextString(m) } func (*StopSlaveResponse) ProtoMessage() {} func (*StopSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{49} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{49} } func (m *StopSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveResponse.Unmarshal(m, b) @@ -2068,7 +2068,7 @@ func (m *StopSlaveMinimumRequest) Reset() { *m = StopSlaveMinimumRequest func (m *StopSlaveMinimumRequest) String() string { return proto.CompactTextString(m) } func (*StopSlaveMinimumRequest) ProtoMessage() {} func (*StopSlaveMinimumRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{50} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{50} } func (m *StopSlaveMinimumRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveMinimumRequest.Unmarshal(m, b) @@ -2113,7 +2113,7 @@ func (m *StopSlaveMinimumResponse) Reset() { *m = StopSlaveMinimumRespon func (m *StopSlaveMinimumResponse) String() string { return proto.CompactTextString(m) } func (*StopSlaveMinimumResponse) ProtoMessage() {} func (*StopSlaveMinimumResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{51} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{51} } func (m *StopSlaveMinimumResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveMinimumResponse.Unmarshal(m, b) @@ -2150,7 +2150,7 @@ func (m *StartSlaveRequest) Reset() { *m = StartSlaveRequest{} } func (m *StartSlaveRequest) String() string { return proto.CompactTextString(m) } func (*StartSlaveRequest) ProtoMessage() {} func (*StartSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{52} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{52} } func (m *StartSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveRequest.Unmarshal(m, b) @@ -2180,7 +2180,7 @@ func (m *StartSlaveResponse) Reset() { *m = StartSlaveResponse{} } func (m *StartSlaveResponse) String() string { return proto.CompactTextString(m) } func (*StartSlaveResponse) ProtoMessage() {} func (*StartSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{53} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{53} } func (m *StartSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveResponse.Unmarshal(m, b) @@ -2212,7 +2212,7 @@ func (m *StartSlaveUntilAfterRequest) Reset() { *m = StartSlaveUntilAfte func (m *StartSlaveUntilAfterRequest) String() string { return proto.CompactTextString(m) } func (*StartSlaveUntilAfterRequest) ProtoMessage() {} func (*StartSlaveUntilAfterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{54} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{54} } func (m *StartSlaveUntilAfterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveUntilAfterRequest.Unmarshal(m, b) @@ -2256,7 +2256,7 @@ func (m *StartSlaveUntilAfterResponse) Reset() { *m = StartSlaveUntilAft func (m *StartSlaveUntilAfterResponse) String() string { return proto.CompactTextString(m) } func (*StartSlaveUntilAfterResponse) ProtoMessage() {} func (*StartSlaveUntilAfterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{55} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{55} } func (m *StartSlaveUntilAfterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveUntilAfterResponse.Unmarshal(m, b) @@ -2290,7 +2290,7 @@ func (m *TabletExternallyReparentedRequest) Reset() { *m = TabletExterna func (m *TabletExternallyReparentedRequest) String() string { return proto.CompactTextString(m) } func (*TabletExternallyReparentedRequest) ProtoMessage() {} func (*TabletExternallyReparentedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{56} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{56} } func (m *TabletExternallyReparentedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyReparentedRequest.Unmarshal(m, b) @@ -2327,7 +2327,7 @@ func (m *TabletExternallyReparentedResponse) Reset() { *m = TabletExtern func (m *TabletExternallyReparentedResponse) String() string { return proto.CompactTextString(m) } func (*TabletExternallyReparentedResponse) ProtoMessage() {} func (*TabletExternallyReparentedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{57} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{57} } func (m *TabletExternallyReparentedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyReparentedResponse.Unmarshal(m, b) @@ -2357,7 +2357,7 @@ func (m *TabletExternallyElectedRequest) Reset() { *m = TabletExternally func (m *TabletExternallyElectedRequest) String() string { return proto.CompactTextString(m) } func (*TabletExternallyElectedRequest) ProtoMessage() {} func (*TabletExternallyElectedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{58} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{58} } func (m *TabletExternallyElectedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyElectedRequest.Unmarshal(m, b) @@ -2387,7 +2387,7 @@ func (m *TabletExternallyElectedResponse) Reset() { *m = TabletExternall func (m *TabletExternallyElectedResponse) String() string { return proto.CompactTextString(m) } func (*TabletExternallyElectedResponse) ProtoMessage() {} func (*TabletExternallyElectedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{59} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{59} } func (m *TabletExternallyElectedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyElectedResponse.Unmarshal(m, b) @@ -2417,7 +2417,7 @@ func (m *GetSlavesRequest) Reset() { *m = GetSlavesRequest{} } func (m *GetSlavesRequest) String() string { return proto.CompactTextString(m) } func (*GetSlavesRequest) ProtoMessage() {} func (*GetSlavesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{60} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{60} } func (m *GetSlavesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSlavesRequest.Unmarshal(m, b) @@ -2448,7 +2448,7 @@ func (m *GetSlavesResponse) Reset() { *m = GetSlavesResponse{} } func (m *GetSlavesResponse) String() string { return proto.CompactTextString(m) } func (*GetSlavesResponse) ProtoMessage() {} func (*GetSlavesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{61} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{61} } func (m *GetSlavesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSlavesResponse.Unmarshal(m, b) @@ -2485,7 +2485,7 @@ func (m *ResetReplicationRequest) Reset() { *m = ResetReplicationRequest func (m *ResetReplicationRequest) String() string { return proto.CompactTextString(m) } func (*ResetReplicationRequest) ProtoMessage() {} func (*ResetReplicationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{62} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{62} } func (m *ResetReplicationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResetReplicationRequest.Unmarshal(m, b) @@ -2515,7 +2515,7 @@ func (m *ResetReplicationResponse) Reset() { *m = ResetReplicationRespon func (m *ResetReplicationResponse) String() string { return proto.CompactTextString(m) } func (*ResetReplicationResponse) ProtoMessage() {} func (*ResetReplicationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{63} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{63} } func (m *ResetReplicationResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResetReplicationResponse.Unmarshal(m, b) @@ -2546,7 +2546,7 @@ func (m *VReplicationExecRequest) Reset() { *m = VReplicationExecRequest func (m *VReplicationExecRequest) String() string { return proto.CompactTextString(m) } func (*VReplicationExecRequest) ProtoMessage() {} func (*VReplicationExecRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{64} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{64} } func (m *VReplicationExecRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VReplicationExecRequest.Unmarshal(m, b) @@ -2584,7 +2584,7 @@ func (m *VReplicationExecResponse) Reset() { *m = VReplicationExecRespon func (m *VReplicationExecResponse) String() string { return proto.CompactTextString(m) } func (*VReplicationExecResponse) ProtoMessage() {} func (*VReplicationExecResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{65} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{65} } func (m *VReplicationExecResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VReplicationExecResponse.Unmarshal(m, b) @@ -2623,7 +2623,7 @@ func (m *VReplicationWaitForPosRequest) Reset() { *m = VReplicationWaitF func (m *VReplicationWaitForPosRequest) String() string { return proto.CompactTextString(m) } func (*VReplicationWaitForPosRequest) ProtoMessage() {} func (*VReplicationWaitForPosRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{66} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{66} } func (m *VReplicationWaitForPosRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VReplicationWaitForPosRequest.Unmarshal(m, b) @@ -2667,7 +2667,7 @@ func (m *VReplicationWaitForPosResponse) Reset() { *m = VReplicationWait func (m *VReplicationWaitForPosResponse) String() string { return proto.CompactTextString(m) } func (*VReplicationWaitForPosResponse) ProtoMessage() {} func (*VReplicationWaitForPosResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{67} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{67} } func (m *VReplicationWaitForPosResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VReplicationWaitForPosResponse.Unmarshal(m, b) @@ -2697,7 +2697,7 @@ func (m *InitMasterRequest) Reset() { *m = InitMasterRequest{} } func (m *InitMasterRequest) String() string { return proto.CompactTextString(m) } func (*InitMasterRequest) ProtoMessage() {} func (*InitMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{68} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{68} } func (m *InitMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitMasterRequest.Unmarshal(m, b) @@ -2728,7 +2728,7 @@ func (m *InitMasterResponse) Reset() { *m = InitMasterResponse{} } func (m *InitMasterResponse) String() string { return proto.CompactTextString(m) } func (*InitMasterResponse) ProtoMessage() {} func (*InitMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{69} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{69} } func (m *InitMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitMasterResponse.Unmarshal(m, b) @@ -2769,7 +2769,7 @@ func (m *PopulateReparentJournalRequest) Reset() { *m = PopulateReparent func (m *PopulateReparentJournalRequest) String() string { return proto.CompactTextString(m) } func (*PopulateReparentJournalRequest) ProtoMessage() {} func (*PopulateReparentJournalRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{70} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{70} } func (m *PopulateReparentJournalRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PopulateReparentJournalRequest.Unmarshal(m, b) @@ -2827,7 +2827,7 @@ func (m *PopulateReparentJournalResponse) Reset() { *m = PopulateReparen func (m *PopulateReparentJournalResponse) String() string { return proto.CompactTextString(m) } func (*PopulateReparentJournalResponse) ProtoMessage() {} func (*PopulateReparentJournalResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{71} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{71} } func (m *PopulateReparentJournalResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PopulateReparentJournalResponse.Unmarshal(m, b) @@ -2860,7 +2860,7 @@ func (m *InitSlaveRequest) Reset() { *m = InitSlaveRequest{} } func (m *InitSlaveRequest) String() string { return proto.CompactTextString(m) } func (*InitSlaveRequest) ProtoMessage() {} func (*InitSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{72} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{72} } func (m *InitSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitSlaveRequest.Unmarshal(m, b) @@ -2911,7 +2911,7 @@ func (m *InitSlaveResponse) Reset() { *m = InitSlaveResponse{} } func (m *InitSlaveResponse) String() string { return proto.CompactTextString(m) } func (*InitSlaveResponse) ProtoMessage() {} func (*InitSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{73} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{73} } func (m *InitSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitSlaveResponse.Unmarshal(m, b) @@ -2941,7 +2941,7 @@ func (m *DemoteMasterRequest) Reset() { *m = DemoteMasterRequest{} } func (m *DemoteMasterRequest) String() string { return proto.CompactTextString(m) } func (*DemoteMasterRequest) ProtoMessage() {} func (*DemoteMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{74} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{74} } func (m *DemoteMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DemoteMasterRequest.Unmarshal(m, b) @@ -2972,7 +2972,7 @@ func (m *DemoteMasterResponse) Reset() { *m = DemoteMasterResponse{} } func (m *DemoteMasterResponse) String() string { return proto.CompactTextString(m) } func (*DemoteMasterResponse) ProtoMessage() {} func (*DemoteMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{75} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{75} } func (m *DemoteMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DemoteMasterResponse.Unmarshal(m, b) @@ -2999,6 +2999,66 @@ func (m *DemoteMasterResponse) GetPosition() string { return "" } +type UndoDemoteMasterRequest struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UndoDemoteMasterRequest) Reset() { *m = UndoDemoteMasterRequest{} } +func (m *UndoDemoteMasterRequest) String() string { return proto.CompactTextString(m) } +func (*UndoDemoteMasterRequest) ProtoMessage() {} +func (*UndoDemoteMasterRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{76} +} +func (m *UndoDemoteMasterRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UndoDemoteMasterRequest.Unmarshal(m, b) +} +func (m *UndoDemoteMasterRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UndoDemoteMasterRequest.Marshal(b, m, deterministic) +} +func (dst *UndoDemoteMasterRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_UndoDemoteMasterRequest.Merge(dst, src) +} +func (m *UndoDemoteMasterRequest) XXX_Size() int { + return xxx_messageInfo_UndoDemoteMasterRequest.Size(m) +} +func (m *UndoDemoteMasterRequest) XXX_DiscardUnknown() { + xxx_messageInfo_UndoDemoteMasterRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_UndoDemoteMasterRequest proto.InternalMessageInfo + +type UndoDemoteMasterResponse struct { + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *UndoDemoteMasterResponse) Reset() { *m = UndoDemoteMasterResponse{} } +func (m *UndoDemoteMasterResponse) String() string { return proto.CompactTextString(m) } +func (*UndoDemoteMasterResponse) ProtoMessage() {} +func (*UndoDemoteMasterResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{77} +} +func (m *UndoDemoteMasterResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_UndoDemoteMasterResponse.Unmarshal(m, b) +} +func (m *UndoDemoteMasterResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_UndoDemoteMasterResponse.Marshal(b, m, deterministic) +} +func (dst *UndoDemoteMasterResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_UndoDemoteMasterResponse.Merge(dst, src) +} +func (m *UndoDemoteMasterResponse) XXX_Size() int { + return xxx_messageInfo_UndoDemoteMasterResponse.Size(m) +} +func (m *UndoDemoteMasterResponse) XXX_DiscardUnknown() { + xxx_messageInfo_UndoDemoteMasterResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_UndoDemoteMasterResponse proto.InternalMessageInfo + type PromoteSlaveWhenCaughtUpRequest struct { Position string `protobuf:"bytes,1,opt,name=position,proto3" json:"position,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -3010,7 +3070,7 @@ func (m *PromoteSlaveWhenCaughtUpRequest) Reset() { *m = PromoteSlaveWhe func (m *PromoteSlaveWhenCaughtUpRequest) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveWhenCaughtUpRequest) ProtoMessage() {} func (*PromoteSlaveWhenCaughtUpRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{76} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{78} } func (m *PromoteSlaveWhenCaughtUpRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveWhenCaughtUpRequest.Unmarshal(m, b) @@ -3048,7 +3108,7 @@ func (m *PromoteSlaveWhenCaughtUpResponse) Reset() { *m = PromoteSlaveWh func (m *PromoteSlaveWhenCaughtUpResponse) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveWhenCaughtUpResponse) ProtoMessage() {} func (*PromoteSlaveWhenCaughtUpResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{77} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{79} } func (m *PromoteSlaveWhenCaughtUpResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveWhenCaughtUpResponse.Unmarshal(m, b) @@ -3085,7 +3145,7 @@ func (m *SlaveWasPromotedRequest) Reset() { *m = SlaveWasPromotedRequest func (m *SlaveWasPromotedRequest) String() string { return proto.CompactTextString(m) } func (*SlaveWasPromotedRequest) ProtoMessage() {} func (*SlaveWasPromotedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{78} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{80} } func (m *SlaveWasPromotedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasPromotedRequest.Unmarshal(m, b) @@ -3115,7 +3175,7 @@ func (m *SlaveWasPromotedResponse) Reset() { *m = SlaveWasPromotedRespon func (m *SlaveWasPromotedResponse) String() string { return proto.CompactTextString(m) } func (*SlaveWasPromotedResponse) ProtoMessage() {} func (*SlaveWasPromotedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{79} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{81} } func (m *SlaveWasPromotedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasPromotedResponse.Unmarshal(m, b) @@ -3148,7 +3208,7 @@ func (m *SetMasterRequest) Reset() { *m = SetMasterRequest{} } func (m *SetMasterRequest) String() string { return proto.CompactTextString(m) } func (*SetMasterRequest) ProtoMessage() {} func (*SetMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{80} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{82} } func (m *SetMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetMasterRequest.Unmarshal(m, b) @@ -3199,7 +3259,7 @@ func (m *SetMasterResponse) Reset() { *m = SetMasterResponse{} } func (m *SetMasterResponse) String() string { return proto.CompactTextString(m) } func (*SetMasterResponse) ProtoMessage() {} func (*SetMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{81} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{83} } func (m *SetMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetMasterResponse.Unmarshal(m, b) @@ -3231,7 +3291,7 @@ func (m *SlaveWasRestartedRequest) Reset() { *m = SlaveWasRestartedReque func (m *SlaveWasRestartedRequest) String() string { return proto.CompactTextString(m) } func (*SlaveWasRestartedRequest) ProtoMessage() {} func (*SlaveWasRestartedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{82} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{84} } func (m *SlaveWasRestartedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasRestartedRequest.Unmarshal(m, b) @@ -3268,7 +3328,7 @@ func (m *SlaveWasRestartedResponse) Reset() { *m = SlaveWasRestartedResp func (m *SlaveWasRestartedResponse) String() string { return proto.CompactTextString(m) } func (*SlaveWasRestartedResponse) ProtoMessage() {} func (*SlaveWasRestartedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{83} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{85} } func (m *SlaveWasRestartedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasRestartedResponse.Unmarshal(m, b) @@ -3298,7 +3358,7 @@ func (m *StopReplicationAndGetStatusRequest) Reset() { *m = StopReplicat func (m *StopReplicationAndGetStatusRequest) String() string { return proto.CompactTextString(m) } func (*StopReplicationAndGetStatusRequest) ProtoMessage() {} func (*StopReplicationAndGetStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{84} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{86} } func (m *StopReplicationAndGetStatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopReplicationAndGetStatusRequest.Unmarshal(m, b) @@ -3329,7 +3389,7 @@ func (m *StopReplicationAndGetStatusResponse) Reset() { *m = StopReplica func (m *StopReplicationAndGetStatusResponse) String() string { return proto.CompactTextString(m) } func (*StopReplicationAndGetStatusResponse) ProtoMessage() {} func (*StopReplicationAndGetStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{85} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{87} } func (m *StopReplicationAndGetStatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopReplicationAndGetStatusResponse.Unmarshal(m, b) @@ -3366,7 +3426,7 @@ func (m *PromoteSlaveRequest) Reset() { *m = PromoteSlaveRequest{} } func (m *PromoteSlaveRequest) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveRequest) ProtoMessage() {} func (*PromoteSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{86} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{88} } func (m *PromoteSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveRequest.Unmarshal(m, b) @@ -3397,7 +3457,7 @@ func (m *PromoteSlaveResponse) Reset() { *m = PromoteSlaveResponse{} } func (m *PromoteSlaveResponse) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveResponse) ProtoMessage() {} func (*PromoteSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{87} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{89} } func (m *PromoteSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveResponse.Unmarshal(m, b) @@ -3435,7 +3495,7 @@ func (m *BackupRequest) Reset() { *m = BackupRequest{} } func (m *BackupRequest) String() string { return proto.CompactTextString(m) } func (*BackupRequest) ProtoMessage() {} func (*BackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{88} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{90} } func (m *BackupRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BackupRequest.Unmarshal(m, b) @@ -3473,7 +3533,7 @@ func (m *BackupResponse) Reset() { *m = BackupResponse{} } func (m *BackupResponse) String() string { return proto.CompactTextString(m) } func (*BackupResponse) ProtoMessage() {} func (*BackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{89} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{91} } func (m *BackupResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BackupResponse.Unmarshal(m, b) @@ -3510,7 +3570,7 @@ func (m *RestoreFromBackupRequest) Reset() { *m = RestoreFromBackupReque func (m *RestoreFromBackupRequest) String() string { return proto.CompactTextString(m) } func (*RestoreFromBackupRequest) ProtoMessage() {} func (*RestoreFromBackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{90} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{92} } func (m *RestoreFromBackupRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RestoreFromBackupRequest.Unmarshal(m, b) @@ -3541,7 +3601,7 @@ func (m *RestoreFromBackupResponse) Reset() { *m = RestoreFromBackupResp func (m *RestoreFromBackupResponse) String() string { return proto.CompactTextString(m) } func (*RestoreFromBackupResponse) ProtoMessage() {} func (*RestoreFromBackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_9e0123608316bc1a, []int{91} + return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{93} } func (m *RestoreFromBackupResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RestoreFromBackupResponse.Unmarshal(m, b) @@ -3648,6 +3708,8 @@ func init() { proto.RegisterType((*InitSlaveResponse)(nil), "tabletmanagerdata.InitSlaveResponse") proto.RegisterType((*DemoteMasterRequest)(nil), "tabletmanagerdata.DemoteMasterRequest") proto.RegisterType((*DemoteMasterResponse)(nil), "tabletmanagerdata.DemoteMasterResponse") + proto.RegisterType((*UndoDemoteMasterRequest)(nil), "tabletmanagerdata.UndoDemoteMasterRequest") + proto.RegisterType((*UndoDemoteMasterResponse)(nil), "tabletmanagerdata.UndoDemoteMasterResponse") proto.RegisterType((*PromoteSlaveWhenCaughtUpRequest)(nil), "tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest") proto.RegisterType((*PromoteSlaveWhenCaughtUpResponse)(nil), "tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse") proto.RegisterType((*SlaveWasPromotedRequest)(nil), "tabletmanagerdata.SlaveWasPromotedRequest") @@ -3667,138 +3729,138 @@ func init() { } func init() { - proto.RegisterFile("tabletmanagerdata.proto", fileDescriptor_tabletmanagerdata_9e0123608316bc1a) -} - -var fileDescriptor_tabletmanagerdata_9e0123608316bc1a = []byte{ - // 2050 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x59, 0x5b, 0x6f, 0x1b, 0xc7, - 0x15, 0x06, 0x49, 0x49, 0x96, 0x0e, 0x2f, 0x22, 0x97, 0x94, 0x48, 0xc9, 0x8d, 0x24, 0xaf, 0x9d, - 0xc6, 0x75, 0x51, 0x2a, 0x56, 0xd2, 0x20, 0x48, 0x91, 0xa2, 0xb2, 0x2e, 0xb6, 0x13, 0x25, 0x56, - 0x56, 0xbe, 0x14, 0x41, 0x81, 0xc5, 0x70, 0x77, 0x44, 0x2e, 0xb4, 0xdc, 0x59, 0xcf, 0xcc, 0x52, - 0xe2, 0x9f, 0xe8, 0x5b, 0xdf, 0xfa, 0x56, 0xa0, 0x7d, 0xef, 0x8f, 0x49, 0xd1, 0x5f, 0xd2, 0x87, - 0xbe, 0x14, 0x73, 0x59, 0x72, 0x96, 0x17, 0x5b, 0x12, 0x5c, 0x20, 0x2f, 0xc6, 0x9e, 0x6f, 0xce, - 0x7d, 0xce, 0x39, 0x73, 0x68, 0x41, 0x93, 0xa3, 0x4e, 0x88, 0x79, 0x1f, 0x45, 0xa8, 0x8b, 0xa9, - 0x8f, 0x38, 0x6a, 0xc7, 0x94, 0x70, 0x62, 0xd5, 0xa6, 0x0e, 0x36, 0x8b, 0x6f, 0x13, 0x4c, 0x87, - 0xea, 0x7c, 0xb3, 0xc2, 0x49, 0x4c, 0xc6, 0xfc, 0x9b, 0x6b, 0x14, 0xc7, 0x61, 0xe0, 0x21, 0x1e, - 0x90, 0xc8, 0x80, 0xcb, 0x21, 0xe9, 0x26, 0x3c, 0x08, 0x15, 0x69, 0xff, 0x3b, 0x07, 0xab, 0x2f, - 0x85, 0xe2, 0x43, 0x7c, 0x1e, 0x44, 0x81, 0x60, 0xb6, 0x2c, 0x58, 0x88, 0x50, 0x1f, 0xb7, 0x72, - 0x3b, 0xb9, 0x87, 0x2b, 0x8e, 0xfc, 0xb6, 0xd6, 0x61, 0x89, 0x79, 0x3d, 0xdc, 0x47, 0xad, 0xbc, - 0x44, 0x35, 0x65, 0xb5, 0xe0, 0x8e, 0x47, 0xc2, 0xa4, 0x1f, 0xb1, 0x56, 0x61, 0xa7, 0xf0, 0x70, - 0xc5, 0x49, 0x49, 0xab, 0x0d, 0xf5, 0x98, 0x06, 0x7d, 0x44, 0x87, 0xee, 0x05, 0x1e, 0xba, 0x29, - 0xd7, 0x82, 0xe4, 0xaa, 0xe9, 0xa3, 0x6f, 0xf1, 0xf0, 0x40, 0xf3, 0x5b, 0xb0, 0xc0, 0x87, 0x31, - 0x6e, 0x2d, 0x2a, 0xab, 0xe2, 0xdb, 0xda, 0x86, 0xa2, 0x70, 0xdd, 0x0d, 0x71, 0xd4, 0xe5, 0xbd, - 0xd6, 0xd2, 0x4e, 0xee, 0xe1, 0x82, 0x03, 0x02, 0x3a, 0x91, 0x88, 0x75, 0x17, 0x56, 0x28, 0xb9, - 0x74, 0x3d, 0x92, 0x44, 0xbc, 0x75, 0x47, 0x1e, 0x2f, 0x53, 0x72, 0x79, 0x20, 0x68, 0xfb, 0xef, - 0x39, 0xa8, 0x9e, 0x49, 0x37, 0x8d, 0xe0, 0x3e, 0x81, 0x55, 0x21, 0xdf, 0x41, 0x0c, 0xbb, 0x3a, - 0x22, 0x15, 0x67, 0x25, 0x85, 0x95, 0x88, 0xf5, 0x02, 0x54, 0xc6, 0x5d, 0x7f, 0x24, 0xcc, 0x5a, - 0xf9, 0x9d, 0xc2, 0xc3, 0xe2, 0x9e, 0xdd, 0x9e, 0xbe, 0xa4, 0x89, 0x24, 0x3a, 0x55, 0x9e, 0x05, - 0x98, 0x48, 0xd5, 0x00, 0x53, 0x16, 0x90, 0xa8, 0x55, 0x90, 0x16, 0x53, 0x52, 0x38, 0x6a, 0x29, - 0xab, 0x07, 0x3d, 0x14, 0x75, 0xb1, 0x83, 0x59, 0x12, 0x72, 0xeb, 0x19, 0x94, 0x3b, 0xf8, 0x9c, - 0xd0, 0x8c, 0xa3, 0xc5, 0xbd, 0xfb, 0x33, 0xac, 0x4f, 0x86, 0xe9, 0x94, 0x94, 0xa4, 0x8e, 0xe5, - 0x18, 0x4a, 0xe8, 0x9c, 0x63, 0xea, 0x1a, 0x77, 0x78, 0x4d, 0x45, 0x45, 0x29, 0xa8, 0x60, 0xfb, - 0x3f, 0x39, 0xa8, 0xbc, 0x62, 0x98, 0x9e, 0x62, 0xda, 0x0f, 0x18, 0xd3, 0xc5, 0xd2, 0x23, 0x8c, - 0xa7, 0xc5, 0x22, 0xbe, 0x05, 0x96, 0x30, 0x4c, 0x75, 0xa9, 0xc8, 0x6f, 0xeb, 0xd7, 0x50, 0x8b, - 0x11, 0x63, 0x97, 0x84, 0xfa, 0xae, 0xd7, 0xc3, 0xde, 0x05, 0x4b, 0xfa, 0x32, 0x0f, 0x0b, 0x4e, - 0x35, 0x3d, 0x38, 0xd0, 0xb8, 0xf5, 0x03, 0x40, 0x4c, 0x83, 0x41, 0x10, 0xe2, 0x2e, 0x56, 0x25, - 0x53, 0xdc, 0x7b, 0x3c, 0xc3, 0xdb, 0xac, 0x2f, 0xed, 0xd3, 0x91, 0xcc, 0x51, 0xc4, 0xe9, 0xd0, - 0x31, 0x94, 0x6c, 0x7e, 0x0d, 0xab, 0x13, 0xc7, 0x56, 0x15, 0x0a, 0x17, 0x78, 0xa8, 0x3d, 0x17, - 0x9f, 0x56, 0x03, 0x16, 0x07, 0x28, 0x4c, 0xb0, 0xf6, 0x5c, 0x11, 0x5f, 0xe5, 0xbf, 0xcc, 0xd9, - 0x3f, 0xe5, 0xa0, 0x74, 0xd8, 0x79, 0x4f, 0xdc, 0x15, 0xc8, 0xfb, 0x1d, 0x2d, 0x9b, 0xf7, 0x3b, - 0xa3, 0x3c, 0x14, 0x8c, 0x3c, 0xbc, 0x98, 0x11, 0xda, 0xee, 0x8c, 0xd0, 0x4c, 0x63, 0xff, 0xcf, - 0xc0, 0xfe, 0x96, 0x83, 0xe2, 0xd8, 0x12, 0xb3, 0x4e, 0xa0, 0x2a, 0xfc, 0x74, 0xe3, 0x31, 0xd6, - 0xca, 0x49, 0x2f, 0xef, 0xbd, 0xf7, 0x02, 0x9c, 0xd5, 0x24, 0x43, 0x33, 0xeb, 0x18, 0x2a, 0x7e, - 0x27, 0xa3, 0x4b, 0x75, 0xd0, 0xf6, 0x7b, 0x22, 0x76, 0xca, 0xbe, 0x41, 0x31, 0xfb, 0x13, 0x28, - 0x9e, 0x06, 0x51, 0xd7, 0xc1, 0x6f, 0x13, 0xcc, 0xb8, 0x68, 0xa5, 0x18, 0x0d, 0x43, 0x82, 0x7c, - 0x1d, 0x64, 0x4a, 0xda, 0x0f, 0xa1, 0xa4, 0x18, 0x59, 0x4c, 0x22, 0x86, 0xdf, 0xc1, 0xf9, 0x08, - 0x4a, 0x67, 0x21, 0xc6, 0x71, 0xaa, 0x73, 0x13, 0x96, 0xfd, 0x84, 0xca, 0x71, 0x29, 0x59, 0x0b, - 0xce, 0x88, 0xb6, 0x57, 0xa1, 0xac, 0x79, 0x95, 0x5a, 0xfb, 0x5f, 0x39, 0xb0, 0x8e, 0xae, 0xb0, - 0x97, 0x70, 0xfc, 0x8c, 0x90, 0x8b, 0x54, 0xc7, 0xac, 0xc9, 0xb9, 0x05, 0x10, 0x23, 0x8a, 0xfa, - 0x98, 0x63, 0xaa, 0xc2, 0x5f, 0x71, 0x0c, 0xc4, 0x3a, 0x85, 0x15, 0x7c, 0xc5, 0x29, 0x72, 0x71, - 0x34, 0x90, 0x33, 0xb4, 0xb8, 0xf7, 0xd9, 0x8c, 0xec, 0x4c, 0x5b, 0x6b, 0x1f, 0x09, 0xb1, 0xa3, - 0x68, 0xa0, 0x6a, 0x62, 0x19, 0x6b, 0x72, 0xf3, 0x77, 0x50, 0xce, 0x1c, 0xdd, 0xa8, 0x1e, 0xce, - 0xa1, 0x9e, 0x31, 0xa5, 0xf3, 0xb8, 0x0d, 0x45, 0x7c, 0x15, 0x70, 0x97, 0x71, 0xc4, 0x13, 0xa6, - 0x13, 0x04, 0x02, 0x3a, 0x93, 0x88, 0x7c, 0x20, 0xb8, 0x4f, 0x12, 0x3e, 0x7a, 0x20, 0x24, 0xa5, - 0x71, 0x4c, 0xd3, 0x2e, 0xd0, 0x94, 0x3d, 0x80, 0xea, 0x53, 0xcc, 0xd5, 0x5c, 0x49, 0xd3, 0xb7, - 0x0e, 0x4b, 0x32, 0x70, 0x55, 0x71, 0x2b, 0x8e, 0xa6, 0xac, 0xfb, 0x50, 0x0e, 0x22, 0x2f, 0x4c, - 0x7c, 0xec, 0x0e, 0x02, 0x7c, 0xc9, 0xa4, 0x89, 0x65, 0xa7, 0xa4, 0xc1, 0xd7, 0x02, 0xb3, 0x3e, - 0x86, 0x0a, 0xbe, 0x52, 0x4c, 0x5a, 0x89, 0x7a, 0x90, 0xca, 0x1a, 0x95, 0x03, 0x9a, 0xd9, 0x18, - 0x6a, 0x86, 0x5d, 0x1d, 0xdd, 0x29, 0xd4, 0xd4, 0x64, 0x34, 0x86, 0xfd, 0x4d, 0xa6, 0x6d, 0x95, - 0x4d, 0x20, 0x76, 0x13, 0xd6, 0x9e, 0x62, 0x6e, 0x94, 0xb0, 0x8e, 0xd1, 0xfe, 0x11, 0xd6, 0x27, - 0x0f, 0xb4, 0x13, 0x7f, 0x80, 0x62, 0xb6, 0xe9, 0x84, 0xf9, 0xad, 0x19, 0xe6, 0x4d, 0x61, 0x53, - 0xc4, 0x6e, 0x80, 0x75, 0x86, 0xb9, 0x83, 0x91, 0xff, 0x22, 0x0a, 0x87, 0xa9, 0xc5, 0x35, 0xa8, - 0x67, 0x50, 0x5d, 0xc2, 0x63, 0xf8, 0x0d, 0x0d, 0x38, 0x4e, 0xb9, 0xd7, 0xa1, 0x91, 0x85, 0x35, - 0xfb, 0x37, 0x50, 0x53, 0x8f, 0xd3, 0xcb, 0x61, 0x9c, 0x32, 0x5b, 0xbf, 0x85, 0xa2, 0x72, 0xcf, - 0x95, 0x4f, 0xb7, 0x70, 0xb9, 0xb2, 0xd7, 0x68, 0x8f, 0x36, 0x11, 0x99, 0x73, 0x2e, 0x25, 0x80, - 0x8f, 0xbe, 0x85, 0x9f, 0xa6, 0xae, 0xb1, 0x43, 0x0e, 0x3e, 0xa7, 0x98, 0xf5, 0x44, 0x49, 0x99, - 0x0e, 0x65, 0x61, 0xcd, 0xde, 0x84, 0x35, 0x27, 0x89, 0x9e, 0x61, 0x14, 0xf2, 0x9e, 0x7c, 0x38, - 0x52, 0x81, 0x16, 0xac, 0x4f, 0x1e, 0x68, 0x91, 0xcf, 0xa1, 0xf5, 0xbc, 0x1b, 0x11, 0x8a, 0xd5, - 0xe1, 0x11, 0xa5, 0x84, 0x66, 0x46, 0x0a, 0xe7, 0x98, 0x46, 0xe3, 0x41, 0x21, 0x49, 0xfb, 0x2e, - 0x6c, 0xcc, 0x90, 0xd2, 0x2a, 0xbf, 0x12, 0x4e, 0x8b, 0x79, 0x92, 0xad, 0xe4, 0xfb, 0x50, 0xbe, - 0x44, 0x01, 0x77, 0x63, 0xc2, 0xc6, 0xc5, 0xb4, 0xe2, 0x94, 0x04, 0x78, 0xaa, 0x31, 0x15, 0x99, - 0x29, 0xab, 0x75, 0xee, 0xc1, 0xfa, 0x29, 0xc5, 0xe7, 0x61, 0xd0, 0xed, 0x4d, 0x34, 0x88, 0xd8, - 0xb6, 0x64, 0xe2, 0xd2, 0x0e, 0x49, 0x49, 0xbb, 0x0b, 0xcd, 0x29, 0x19, 0x5d, 0x57, 0x27, 0x50, - 0x51, 0x5c, 0x2e, 0x95, 0x7b, 0x45, 0x3a, 0xcf, 0x3f, 0x9e, 0x5b, 0xd9, 0xe6, 0x16, 0xe2, 0x94, - 0x3d, 0x83, 0x62, 0xf6, 0x7f, 0x73, 0x60, 0xed, 0xc7, 0x71, 0x38, 0xcc, 0x7a, 0x56, 0x85, 0x02, - 0x7b, 0x1b, 0xa6, 0x23, 0x86, 0xbd, 0x0d, 0xc5, 0x88, 0x39, 0x27, 0xd4, 0xc3, 0xba, 0x59, 0x15, - 0x21, 0xd6, 0x00, 0x14, 0x86, 0xe4, 0xd2, 0x35, 0xb6, 0x53, 0x39, 0x19, 0x96, 0x9d, 0xaa, 0x3c, - 0x70, 0xc6, 0xf8, 0xf4, 0x02, 0xb4, 0xf0, 0xa1, 0x16, 0xa0, 0xc5, 0x5b, 0x2e, 0x40, 0xff, 0xc8, - 0x41, 0x3d, 0x13, 0xbd, 0xce, 0xf1, 0xcf, 0x6f, 0x55, 0xab, 0x43, 0xed, 0x84, 0x78, 0x17, 0x6a, - 0xea, 0xa5, 0xad, 0xd1, 0x00, 0xcb, 0x04, 0xc7, 0x8d, 0xf7, 0x2a, 0x0a, 0xa7, 0x98, 0xd7, 0xa1, - 0x91, 0x85, 0x35, 0xfb, 0x3f, 0x73, 0xd0, 0xd2, 0x4f, 0xc4, 0x31, 0xe6, 0x5e, 0x6f, 0x9f, 0x1d, - 0x76, 0x46, 0x75, 0xd0, 0x80, 0x45, 0xf9, 0xa3, 0x44, 0x26, 0xa0, 0xe4, 0x28, 0xc2, 0x6a, 0xc2, - 0x1d, 0xbf, 0xe3, 0xca, 0xa7, 0x51, 0xbf, 0x0e, 0x7e, 0xe7, 0x7b, 0xf1, 0x38, 0x6e, 0xc0, 0x72, - 0x1f, 0x5d, 0xb9, 0x94, 0x5c, 0x32, 0xbd, 0x0c, 0xde, 0xe9, 0xa3, 0x2b, 0x87, 0x5c, 0x32, 0xb9, - 0xa8, 0x07, 0x4c, 0x6e, 0xe0, 0x9d, 0x20, 0x0a, 0x49, 0x97, 0xc9, 0xeb, 0x5f, 0x76, 0x2a, 0x1a, - 0x7e, 0xa2, 0x50, 0xd1, 0x6b, 0x54, 0xb6, 0x91, 0x79, 0xb9, 0xcb, 0x4e, 0x89, 0x1a, 0xbd, 0x65, - 0x3f, 0x85, 0x8d, 0x19, 0x3e, 0xeb, 0xdb, 0x7b, 0x04, 0x4b, 0xaa, 0x35, 0xf4, 0xb5, 0x59, 0x6d, - 0xf5, 0xc3, 0xea, 0x07, 0xf1, 0xaf, 0x6e, 0x03, 0xcd, 0x61, 0xff, 0x39, 0x07, 0x1f, 0x65, 0x35, - 0xed, 0x87, 0xa1, 0x58, 0xc0, 0xd8, 0x87, 0x4f, 0xc1, 0x54, 0x64, 0x0b, 0x33, 0x22, 0x3b, 0x81, - 0xad, 0x79, 0xfe, 0xdc, 0x22, 0xbc, 0x6f, 0x27, 0xef, 0x76, 0x3f, 0x8e, 0xdf, 0x1d, 0x98, 0xe9, - 0x7f, 0x3e, 0xe3, 0xff, 0x74, 0xd2, 0xa5, 0xb2, 0x5b, 0x78, 0x25, 0x1e, 0xb6, 0x10, 0x0d, 0xb0, - 0xda, 0x35, 0xd2, 0x02, 0x3d, 0x86, 0x7a, 0x06, 0xd5, 0x8a, 0x77, 0xc5, 0xc6, 0x31, 0xda, 0x52, - 0x8a, 0x7b, 0xcd, 0xf6, 0xe4, 0x2f, 0x61, 0x2d, 0xa0, 0xd9, 0xc4, 0x4b, 0xf2, 0x1d, 0x62, 0x1c, - 0xd3, 0x74, 0x32, 0xa7, 0x06, 0x3e, 0x87, 0xf5, 0xc9, 0x03, 0x6d, 0x63, 0x13, 0x96, 0x27, 0x46, - 0xfb, 0x88, 0xb6, 0x2d, 0xa8, 0x9e, 0x71, 0x12, 0x4b, 0xd7, 0x52, 0x4d, 0x75, 0xa8, 0x19, 0x98, - 0x6e, 0xa4, 0x3f, 0x42, 0x73, 0x04, 0x7e, 0x17, 0x44, 0x41, 0x3f, 0xe9, 0x1b, 0xcb, 0xe8, 0x3c, - 0xfd, 0xd6, 0x3d, 0x90, 0xcf, 0x88, 0xcb, 0x83, 0x3e, 0x4e, 0xf7, 0xad, 0x82, 0x53, 0x14, 0xd8, - 0x4b, 0x05, 0xd9, 0x5f, 0x40, 0x6b, 0x5a, 0xf3, 0x35, 0x5c, 0x97, 0x6e, 0x22, 0xca, 0x33, 0xbe, - 0x8b, 0xe4, 0x1b, 0xa0, 0x76, 0xfe, 0x4f, 0x70, 0x77, 0x8c, 0xbe, 0x8a, 0x78, 0x10, 0xee, 0x8b, - 0xe9, 0xf3, 0x81, 0x02, 0xd8, 0x82, 0x5f, 0xcc, 0xd6, 0xae, 0xad, 0x1f, 0xc2, 0x3d, 0xb5, 0x5b, - 0x1c, 0x5d, 0x89, 0x37, 0x1a, 0x85, 0x62, 0xb1, 0x89, 0x11, 0xc5, 0x11, 0xc7, 0x7e, 0xea, 0x83, - 0xdc, 0x59, 0xd5, 0xb1, 0x1b, 0xa4, 0xfb, 0x3f, 0xa4, 0xd0, 0x73, 0xdf, 0x7e, 0x00, 0xf6, 0xbb, - 0xb4, 0x68, 0x5b, 0x3b, 0xb0, 0x35, 0xc9, 0x75, 0x14, 0x62, 0x6f, 0x6c, 0xc8, 0xbe, 0x07, 0xdb, - 0x73, 0x39, 0xb4, 0x12, 0x4b, 0xad, 0xbb, 0x22, 0x9c, 0x51, 0xfd, 0xfe, 0x4a, 0xad, 0xa2, 0x1a, - 0xd3, 0xd7, 0xd3, 0x80, 0x45, 0xe4, 0xfb, 0x34, 0x7d, 0xe0, 0x15, 0x61, 0x6f, 0x40, 0xd3, 0xc1, - 0x4c, 0xec, 0x65, 0xa3, 0x4a, 0x4e, 0xb5, 0x6c, 0x42, 0x6b, 0xfa, 0x48, 0x5b, 0xdd, 0x85, 0xe6, - 0x6b, 0x03, 0x17, 0xcd, 0x38, 0xb3, 0x99, 0x57, 0x74, 0x33, 0xdb, 0xc7, 0xd0, 0x9a, 0x16, 0xb8, - 0xd5, 0x18, 0xf9, 0xc8, 0xd4, 0xf3, 0x06, 0x05, 0xfc, 0x98, 0x88, 0x36, 0x4a, 0xcd, 0x57, 0x20, - 0xaf, 0xaf, 0xa4, 0xe0, 0xe4, 0x03, 0x3f, 0x53, 0x2f, 0xf9, 0x89, 0xaa, 0xdc, 0x81, 0xad, 0x79, - 0xca, 0x74, 0x9c, 0x75, 0xa8, 0x3d, 0x8f, 0x02, 0xae, 0x9a, 0x35, 0x4d, 0xcc, 0xa7, 0x60, 0x99, - 0xe0, 0x35, 0xca, 0xff, 0xa7, 0x1c, 0x6c, 0x9d, 0x92, 0x38, 0x09, 0xe5, 0x9e, 0xa9, 0x0a, 0xe1, - 0x1b, 0x92, 0x88, 0x1b, 0x4d, 0xfd, 0xfe, 0x25, 0xac, 0x8a, 0xb2, 0x75, 0x3d, 0x8a, 0x11, 0xc7, - 0xbe, 0x1b, 0xa5, 0xbf, 0x85, 0xca, 0x02, 0x3e, 0x50, 0xe8, 0xf7, 0x4c, 0xd4, 0x1e, 0xf2, 0x84, - 0x52, 0x73, 0xe4, 0x83, 0x82, 0xe4, 0xd8, 0xff, 0x12, 0x4a, 0x7d, 0xe9, 0x99, 0x8b, 0xc2, 0x00, - 0xa9, 0xd1, 0x5f, 0xdc, 0x5b, 0x9b, 0xdc, 0x9d, 0xf7, 0xc5, 0xa1, 0x53, 0x54, 0xac, 0x92, 0xb0, - 0x1e, 0x43, 0xc3, 0x18, 0x68, 0xe3, 0x15, 0x73, 0x41, 0xda, 0xa8, 0x1b, 0x67, 0xa3, 0x4d, 0xf3, - 0x1e, 0x6c, 0xcf, 0x8d, 0x4b, 0xa7, 0xf0, 0xaf, 0x39, 0xa8, 0x8a, 0x74, 0x99, 0xad, 0x6f, 0xfd, - 0x06, 0x96, 0x14, 0xb7, 0xbe, 0xf2, 0x39, 0xee, 0x69, 0xa6, 0xb9, 0x9e, 0xe5, 0xe7, 0x7a, 0x36, - 0x2b, 0x9f, 0x85, 0x19, 0xf9, 0x4c, 0x6f, 0x38, 0x3b, 0x83, 0xd6, 0xa0, 0x7e, 0x88, 0xfb, 0x84, - 0xe3, 0xec, 0xc5, 0xef, 0x41, 0x23, 0x0b, 0x5f, 0xe3, 0xea, 0xbf, 0x86, 0xed, 0x53, 0x4a, 0x84, - 0x90, 0x34, 0xf1, 0xa6, 0x87, 0xa3, 0x03, 0x94, 0x74, 0x7b, 0xfc, 0x55, 0x7c, 0x8d, 0x91, 0x66, - 0xff, 0x1e, 0x76, 0xe6, 0x8b, 0x5f, 0xc3, 0xfc, 0x06, 0x34, 0x95, 0x20, 0x62, 0x5a, 0x8f, 0x6f, - 0xf4, 0xf7, 0xf4, 0x91, 0x4e, 0xc0, 0x5f, 0x72, 0x50, 0x3d, 0xc3, 0xd9, 0xba, 0xbf, 0xe9, 0xa5, - 0xcd, 0xb8, 0x81, 0xfc, 0xac, 0x8a, 0x7e, 0x04, 0x35, 0xb9, 0xc2, 0xbb, 0x4c, 0x0c, 0x66, 0x97, - 0x09, 0x9f, 0xf4, 0xe6, 0xbe, 0x2a, 0x0f, 0xc6, 0x03, 0x5b, 0xbe, 0x23, 0x78, 0xa2, 0xf3, 0xec, - 0xe7, 0xe3, 0x40, 0x1c, 0x2c, 0x95, 0x8c, 0x47, 0xf5, 0xcd, 0x7c, 0x16, 0x3f, 0xc9, 0x66, 0xa8, - 0xd2, 0x76, 0x1e, 0x80, 0x2d, 0x1e, 0x3f, 0x63, 0x62, 0xec, 0x47, 0xbe, 0x18, 0xb4, 0x99, 0xe5, - 0xe1, 0x35, 0xdc, 0x7f, 0x27, 0xd7, 0x6d, 0x97, 0x89, 0x35, 0xa8, 0x9b, 0x95, 0x60, 0xd4, 0x64, - 0x16, 0xbe, 0x46, 0x51, 0x3c, 0x86, 0xf2, 0x13, 0xe4, 0x5d, 0x24, 0xa3, 0x0a, 0xdc, 0x81, 0xa2, - 0x47, 0x22, 0x2f, 0xa1, 0x14, 0x47, 0xde, 0x50, 0x0f, 0x1e, 0x13, 0xb2, 0xbf, 0x80, 0x4a, 0x2a, - 0xa2, 0x0d, 0x3c, 0x80, 0x45, 0x3c, 0x18, 0x27, 0xb6, 0xd2, 0x4e, 0xff, 0xff, 0xff, 0x48, 0xa0, - 0x8e, 0x3a, 0xd4, 0x8f, 0x08, 0x27, 0x14, 0x1f, 0x53, 0xd2, 0xcf, 0x58, 0xb5, 0xf7, 0x61, 0x63, - 0xc6, 0xd9, 0x4d, 0xd4, 0x3f, 0xf9, 0xf4, 0xc7, 0xf6, 0x20, 0xe0, 0x98, 0xb1, 0x76, 0x40, 0x76, - 0xd5, 0xd7, 0x6e, 0x97, 0xec, 0x0e, 0xf8, 0xae, 0xfc, 0x2b, 0xc4, 0xee, 0xd4, 0x8f, 0x9b, 0xce, - 0x92, 0x3c, 0xf8, 0xec, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0x30, 0x7f, 0x51, 0x40, 0x0f, 0x19, - 0x00, 0x00, + proto.RegisterFile("tabletmanagerdata.proto", fileDescriptor_tabletmanagerdata_56f589a6303df775) +} + +var fileDescriptor_tabletmanagerdata_56f589a6303df775 = []byte{ + // 2063 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x59, 0x5f, 0x6f, 0x1b, 0xc7, + 0x11, 0x07, 0x49, 0x49, 0x96, 0x86, 0x7f, 0x44, 0x1e, 0x29, 0x91, 0x92, 0x1b, 0x49, 0x3e, 0x3b, + 0x8d, 0xeb, 0xa2, 0x54, 0xac, 0xa4, 0x41, 0x90, 0x22, 0x45, 0x65, 0x59, 0xb2, 0x9d, 0x28, 0xb1, + 0x72, 0xb2, 0xec, 0x22, 0x28, 0x70, 0x58, 0xf2, 0x56, 0xe4, 0x41, 0xc7, 0xdb, 0xf3, 0xee, 0x1e, + 0x25, 0x7e, 0x89, 0xbe, 0xf5, 0xad, 0x6f, 0x05, 0xda, 0xf7, 0x7e, 0x98, 0x14, 0xfd, 0x24, 0x7d, + 0xe8, 0x4b, 0xb1, 0x7f, 0x8e, 0xdc, 0x23, 0x8f, 0xb6, 0x24, 0xb8, 0x40, 0x5e, 0x84, 0x9b, 0xdf, + 0xcc, 0xce, 0xbf, 0x9d, 0x99, 0x1d, 0x42, 0xd0, 0xe4, 0xa8, 0x13, 0x60, 0x3e, 0x40, 0x21, 0xea, + 0x61, 0xea, 0x21, 0x8e, 0xda, 0x11, 0x25, 0x9c, 0x58, 0xb5, 0x19, 0xc6, 0x66, 0xf1, 0x6d, 0x8c, + 0xe9, 0x48, 0xf1, 0x37, 0x2b, 0x9c, 0x44, 0x64, 0x22, 0xbf, 0xb9, 0x46, 0x71, 0x14, 0xf8, 0x5d, + 0xc4, 0x7d, 0x12, 0x1a, 0x70, 0x39, 0x20, 0xbd, 0x98, 0xfb, 0x81, 0x22, 0xed, 0x7f, 0xe7, 0x60, + 0xf5, 0x95, 0x50, 0xfc, 0x14, 0x9f, 0xfb, 0xa1, 0x2f, 0x84, 0x2d, 0x0b, 0x16, 0x42, 0x34, 0xc0, + 0xad, 0xdc, 0x4e, 0xee, 0xe1, 0x8a, 0x23, 0xbf, 0xad, 0x75, 0x58, 0x62, 0xdd, 0x3e, 0x1e, 0xa0, + 0x56, 0x5e, 0xa2, 0x9a, 0xb2, 0x5a, 0x70, 0xa7, 0x4b, 0x82, 0x78, 0x10, 0xb2, 0x56, 0x61, 0xa7, + 0xf0, 0x70, 0xc5, 0x49, 0x48, 0xab, 0x0d, 0xf5, 0x88, 0xfa, 0x03, 0x44, 0x47, 0xee, 0x05, 0x1e, + 0xb9, 0x89, 0xd4, 0x82, 0x94, 0xaa, 0x69, 0xd6, 0xb7, 0x78, 0x74, 0xa0, 0xe5, 0x2d, 0x58, 0xe0, + 0xa3, 0x08, 0xb7, 0x16, 0x95, 0x55, 0xf1, 0x6d, 0x6d, 0x43, 0x51, 0xb8, 0xee, 0x06, 0x38, 0xec, + 0xf1, 0x7e, 0x6b, 0x69, 0x27, 0xf7, 0x70, 0xc1, 0x01, 0x01, 0x1d, 0x4b, 0xc4, 0xba, 0x0b, 0x2b, + 0x94, 0x5c, 0xba, 0x5d, 0x12, 0x87, 0xbc, 0x75, 0x47, 0xb2, 0x97, 0x29, 0xb9, 0x3c, 0x10, 0xb4, + 0xfd, 0xf7, 0x1c, 0x54, 0x4f, 0xa5, 0x9b, 0x46, 0x70, 0x9f, 0xc0, 0xaa, 0x38, 0xdf, 0x41, 0x0c, + 0xbb, 0x3a, 0x22, 0x15, 0x67, 0x25, 0x81, 0xd5, 0x11, 0xeb, 0x25, 0xa8, 0x8c, 0xbb, 0xde, 0xf8, + 0x30, 0x6b, 0xe5, 0x77, 0x0a, 0x0f, 0x8b, 0x7b, 0x76, 0x7b, 0xf6, 0x92, 0xa6, 0x92, 0xe8, 0x54, + 0x79, 0x1a, 0x60, 0x22, 0x55, 0x43, 0x4c, 0x99, 0x4f, 0xc2, 0x56, 0x41, 0x5a, 0x4c, 0x48, 0xe1, + 0xa8, 0xa5, 0xac, 0x1e, 0xf4, 0x51, 0xd8, 0xc3, 0x0e, 0x66, 0x71, 0xc0, 0xad, 0xe7, 0x50, 0xee, + 0xe0, 0x73, 0x42, 0x53, 0x8e, 0x16, 0xf7, 0xee, 0x67, 0x58, 0x9f, 0x0e, 0xd3, 0x29, 0xa9, 0x93, + 0x3a, 0x96, 0x23, 0x28, 0xa1, 0x73, 0x8e, 0xa9, 0x6b, 0xdc, 0xe1, 0x35, 0x15, 0x15, 0xe5, 0x41, + 0x05, 0xdb, 0xff, 0xc9, 0x41, 0xe5, 0x8c, 0x61, 0x7a, 0x82, 0xe9, 0xc0, 0x67, 0x4c, 0x17, 0x4b, + 0x9f, 0x30, 0x9e, 0x14, 0x8b, 0xf8, 0x16, 0x58, 0xcc, 0x30, 0xd5, 0xa5, 0x22, 0xbf, 0xad, 0x5f, + 0x43, 0x2d, 0x42, 0x8c, 0x5d, 0x12, 0xea, 0xb9, 0xdd, 0x3e, 0xee, 0x5e, 0xb0, 0x78, 0x20, 0xf3, + 0xb0, 0xe0, 0x54, 0x13, 0xc6, 0x81, 0xc6, 0xad, 0x1f, 0x00, 0x22, 0xea, 0x0f, 0xfd, 0x00, 0xf7, + 0xb0, 0x2a, 0x99, 0xe2, 0xde, 0xe3, 0x0c, 0x6f, 0xd3, 0xbe, 0xb4, 0x4f, 0xc6, 0x67, 0x0e, 0x43, + 0x4e, 0x47, 0x8e, 0xa1, 0x64, 0xf3, 0x6b, 0x58, 0x9d, 0x62, 0x5b, 0x55, 0x28, 0x5c, 0xe0, 0x91, + 0xf6, 0x5c, 0x7c, 0x5a, 0x0d, 0x58, 0x1c, 0xa2, 0x20, 0xc6, 0xda, 0x73, 0x45, 0x7c, 0x95, 0xff, + 0x32, 0x67, 0xff, 0x94, 0x83, 0xd2, 0xd3, 0xce, 0x7b, 0xe2, 0xae, 0x40, 0xde, 0xeb, 0xe8, 0xb3, + 0x79, 0xaf, 0x33, 0xce, 0x43, 0xc1, 0xc8, 0xc3, 0xcb, 0x8c, 0xd0, 0x76, 0x33, 0x42, 0x33, 0x8d, + 0xfd, 0x3f, 0x03, 0xfb, 0x5b, 0x0e, 0x8a, 0x13, 0x4b, 0xcc, 0x3a, 0x86, 0xaa, 0xf0, 0xd3, 0x8d, + 0x26, 0x58, 0x2b, 0x27, 0xbd, 0xbc, 0xf7, 0xde, 0x0b, 0x70, 0x56, 0xe3, 0x14, 0xcd, 0xac, 0x23, + 0xa8, 0x78, 0x9d, 0x94, 0x2e, 0xd5, 0x41, 0xdb, 0xef, 0x89, 0xd8, 0x29, 0x7b, 0x06, 0xc5, 0xec, + 0x4f, 0xa0, 0x78, 0xe2, 0x87, 0x3d, 0x07, 0xbf, 0x8d, 0x31, 0xe3, 0xa2, 0x95, 0x22, 0x34, 0x0a, + 0x08, 0xf2, 0x74, 0x90, 0x09, 0x69, 0x3f, 0x84, 0x92, 0x12, 0x64, 0x11, 0x09, 0x19, 0x7e, 0x87, + 0xe4, 0x23, 0x28, 0x9d, 0x06, 0x18, 0x47, 0x89, 0xce, 0x4d, 0x58, 0xf6, 0x62, 0x2a, 0xc7, 0xa5, + 0x14, 0x2d, 0x38, 0x63, 0xda, 0x5e, 0x85, 0xb2, 0x96, 0x55, 0x6a, 0xed, 0x7f, 0xe5, 0xc0, 0x3a, + 0xbc, 0xc2, 0xdd, 0x98, 0xe3, 0xe7, 0x84, 0x5c, 0x24, 0x3a, 0xb2, 0x26, 0xe7, 0x16, 0x40, 0x84, + 0x28, 0x1a, 0x60, 0x8e, 0xa9, 0x0a, 0x7f, 0xc5, 0x31, 0x10, 0xeb, 0x04, 0x56, 0xf0, 0x15, 0xa7, + 0xc8, 0xc5, 0xe1, 0x50, 0xce, 0xd0, 0xe2, 0xde, 0x67, 0x19, 0xd9, 0x99, 0xb5, 0xd6, 0x3e, 0x14, + 0xc7, 0x0e, 0xc3, 0xa1, 0xaa, 0x89, 0x65, 0xac, 0xc9, 0xcd, 0xdf, 0x41, 0x39, 0xc5, 0xba, 0x51, + 0x3d, 0x9c, 0x43, 0x3d, 0x65, 0x4a, 0xe7, 0x71, 0x1b, 0x8a, 0xf8, 0xca, 0xe7, 0x2e, 0xe3, 0x88, + 0xc7, 0x4c, 0x27, 0x08, 0x04, 0x74, 0x2a, 0x11, 0xf9, 0x40, 0x70, 0x8f, 0xc4, 0x7c, 0xfc, 0x40, + 0x48, 0x4a, 0xe3, 0x98, 0x26, 0x5d, 0xa0, 0x29, 0x7b, 0x08, 0xd5, 0x67, 0x98, 0xab, 0xb9, 0x92, + 0xa4, 0x6f, 0x1d, 0x96, 0x64, 0xe0, 0xaa, 0xe2, 0x56, 0x1c, 0x4d, 0x59, 0xf7, 0xa1, 0xec, 0x87, + 0xdd, 0x20, 0xf6, 0xb0, 0x3b, 0xf4, 0xf1, 0x25, 0x93, 0x26, 0x96, 0x9d, 0x92, 0x06, 0x5f, 0x0b, + 0xcc, 0xfa, 0x18, 0x2a, 0xf8, 0x4a, 0x09, 0x69, 0x25, 0xea, 0x41, 0x2a, 0x6b, 0x54, 0x0e, 0x68, + 0x66, 0x63, 0xa8, 0x19, 0x76, 0x75, 0x74, 0x27, 0x50, 0x53, 0x93, 0xd1, 0x18, 0xf6, 0x37, 0x99, + 0xb6, 0x55, 0x36, 0x85, 0xd8, 0x4d, 0x58, 0x7b, 0x86, 0xb9, 0x51, 0xc2, 0x3a, 0x46, 0xfb, 0x47, + 0x58, 0x9f, 0x66, 0x68, 0x27, 0xfe, 0x00, 0xc5, 0x74, 0xd3, 0x09, 0xf3, 0x5b, 0x19, 0xe6, 0xcd, + 0xc3, 0xe6, 0x11, 0xbb, 0x01, 0xd6, 0x29, 0xe6, 0x0e, 0x46, 0xde, 0xcb, 0x30, 0x18, 0x25, 0x16, + 0xd7, 0xa0, 0x9e, 0x42, 0x75, 0x09, 0x4f, 0xe0, 0x37, 0xd4, 0xe7, 0x38, 0x91, 0x5e, 0x87, 0x46, + 0x1a, 0xd6, 0xe2, 0xdf, 0x40, 0x4d, 0x3d, 0x4e, 0xaf, 0x46, 0x51, 0x22, 0x6c, 0xfd, 0x16, 0x8a, + 0xca, 0x3d, 0x57, 0x3e, 0xdd, 0xc2, 0xe5, 0xca, 0x5e, 0xa3, 0x3d, 0xde, 0x44, 0x64, 0xce, 0xb9, + 0x3c, 0x01, 0x7c, 0xfc, 0x2d, 0xfc, 0x34, 0x75, 0x4d, 0x1c, 0x72, 0xf0, 0x39, 0xc5, 0xac, 0x2f, + 0x4a, 0xca, 0x74, 0x28, 0x0d, 0x6b, 0xf1, 0x26, 0xac, 0x39, 0x71, 0xf8, 0x1c, 0xa3, 0x80, 0xf7, + 0xe5, 0xc3, 0x91, 0x1c, 0x68, 0xc1, 0xfa, 0x34, 0x43, 0x1f, 0xf9, 0x1c, 0x5a, 0x2f, 0x7a, 0x21, + 0xa1, 0x58, 0x31, 0x0f, 0x29, 0x25, 0x34, 0x35, 0x52, 0x38, 0xc7, 0x34, 0x9c, 0x0c, 0x0a, 0x49, + 0xda, 0x77, 0x61, 0x23, 0xe3, 0x94, 0x56, 0xf9, 0x95, 0x70, 0x5a, 0xcc, 0x93, 0x74, 0x25, 0xdf, + 0x87, 0xf2, 0x25, 0xf2, 0xb9, 0x1b, 0x11, 0x36, 0x29, 0xa6, 0x15, 0xa7, 0x24, 0xc0, 0x13, 0x8d, + 0xa9, 0xc8, 0xcc, 0xb3, 0x5a, 0xe7, 0x1e, 0xac, 0x9f, 0x50, 0x7c, 0x1e, 0xf8, 0xbd, 0xfe, 0x54, + 0x83, 0x88, 0x6d, 0x4b, 0x26, 0x2e, 0xe9, 0x90, 0x84, 0xb4, 0x7b, 0xd0, 0x9c, 0x39, 0xa3, 0xeb, + 0xea, 0x18, 0x2a, 0x4a, 0xca, 0xa5, 0x72, 0xaf, 0x48, 0xe6, 0xf9, 0xc7, 0x73, 0x2b, 0xdb, 0xdc, + 0x42, 0x9c, 0x72, 0xd7, 0xa0, 0x98, 0xfd, 0xdf, 0x1c, 0x58, 0xfb, 0x51, 0x14, 0x8c, 0xd2, 0x9e, + 0x55, 0xa1, 0xc0, 0xde, 0x06, 0xc9, 0x88, 0x61, 0x6f, 0x03, 0x31, 0x62, 0xce, 0x09, 0xed, 0x62, + 0xdd, 0xac, 0x8a, 0x10, 0x6b, 0x00, 0x0a, 0x02, 0x72, 0xe9, 0x1a, 0xdb, 0xa9, 0x9c, 0x0c, 0xcb, + 0x4e, 0x55, 0x32, 0x9c, 0x09, 0x3e, 0xbb, 0x00, 0x2d, 0x7c, 0xa8, 0x05, 0x68, 0xf1, 0x96, 0x0b, + 0xd0, 0x3f, 0x72, 0x50, 0x4f, 0x45, 0xaf, 0x73, 0xfc, 0xf3, 0x5b, 0xd5, 0xea, 0x50, 0x3b, 0x26, + 0xdd, 0x0b, 0x35, 0xf5, 0x92, 0xd6, 0x68, 0x80, 0x65, 0x82, 0x93, 0xc6, 0x3b, 0x0b, 0x83, 0x19, + 0xe1, 0x75, 0x68, 0xa4, 0x61, 0x2d, 0xfe, 0xcf, 0x1c, 0xb4, 0xf4, 0x13, 0x71, 0x84, 0x79, 0xb7, + 0xbf, 0xcf, 0x9e, 0x76, 0xc6, 0x75, 0xd0, 0x80, 0x45, 0xf9, 0xa3, 0x44, 0x26, 0xa0, 0xe4, 0x28, + 0xc2, 0x6a, 0xc2, 0x1d, 0xaf, 0xe3, 0xca, 0xa7, 0x51, 0xbf, 0x0e, 0x5e, 0xe7, 0x7b, 0xf1, 0x38, + 0x6e, 0xc0, 0xf2, 0x00, 0x5d, 0xb9, 0x94, 0x5c, 0x32, 0xbd, 0x0c, 0xde, 0x19, 0xa0, 0x2b, 0x87, + 0x5c, 0x32, 0xb9, 0xa8, 0xfb, 0x4c, 0x6e, 0xe0, 0x1d, 0x3f, 0x0c, 0x48, 0x8f, 0xc9, 0xeb, 0x5f, + 0x76, 0x2a, 0x1a, 0x7e, 0xa2, 0x50, 0xd1, 0x6b, 0x54, 0xb6, 0x91, 0x79, 0xb9, 0xcb, 0x4e, 0x89, + 0x1a, 0xbd, 0x65, 0x3f, 0x83, 0x8d, 0x0c, 0x9f, 0xf5, 0xed, 0x3d, 0x82, 0x25, 0xd5, 0x1a, 0xfa, + 0xda, 0xac, 0xb6, 0xfa, 0x61, 0xf5, 0x83, 0xf8, 0xab, 0xdb, 0x40, 0x4b, 0xd8, 0x7f, 0xce, 0xc1, + 0x47, 0x69, 0x4d, 0xfb, 0x41, 0x20, 0x16, 0x30, 0xf6, 0xe1, 0x53, 0x30, 0x13, 0xd9, 0x42, 0x46, + 0x64, 0xc7, 0xb0, 0x35, 0xcf, 0x9f, 0x5b, 0x84, 0xf7, 0xed, 0xf4, 0xdd, 0xee, 0x47, 0xd1, 0xbb, + 0x03, 0x33, 0xfd, 0xcf, 0xa7, 0xfc, 0x9f, 0x4d, 0xba, 0x54, 0x76, 0x0b, 0xaf, 0xc4, 0xc3, 0x16, + 0xa0, 0x21, 0x56, 0xbb, 0x46, 0x52, 0xa0, 0x47, 0x50, 0x4f, 0xa1, 0x5a, 0xf1, 0xae, 0xd8, 0x38, + 0xc6, 0x5b, 0x4a, 0x71, 0xaf, 0xd9, 0x9e, 0xfe, 0x25, 0xac, 0x0f, 0x68, 0x31, 0xf1, 0x92, 0x7c, + 0x87, 0x18, 0xc7, 0x34, 0x99, 0xcc, 0x89, 0x81, 0xcf, 0x61, 0x7d, 0x9a, 0xa1, 0x6d, 0x6c, 0xc2, + 0xf2, 0xd4, 0x68, 0x1f, 0xd3, 0xb6, 0x05, 0xd5, 0x53, 0x4e, 0x22, 0xe9, 0x5a, 0xa2, 0xa9, 0x0e, + 0x35, 0x03, 0xd3, 0x8d, 0xf4, 0x47, 0x68, 0x8e, 0xc1, 0xef, 0xfc, 0xd0, 0x1f, 0xc4, 0x03, 0x63, + 0x19, 0x9d, 0xa7, 0xdf, 0xba, 0x07, 0xf2, 0x19, 0x71, 0xb9, 0x3f, 0xc0, 0xc9, 0xbe, 0x55, 0x70, + 0x8a, 0x02, 0x7b, 0xa5, 0x20, 0xfb, 0x0b, 0x68, 0xcd, 0x6a, 0xbe, 0x86, 0xeb, 0xd2, 0x4d, 0x44, + 0x79, 0xca, 0x77, 0x91, 0x7c, 0x03, 0xd4, 0xce, 0xff, 0x09, 0xee, 0x4e, 0xd0, 0xb3, 0x90, 0xfb, + 0xc1, 0xbe, 0x98, 0x3e, 0x1f, 0x28, 0x80, 0x2d, 0xf8, 0x45, 0xb6, 0x76, 0x6d, 0xfd, 0x29, 0xdc, + 0x53, 0xbb, 0xc5, 0xe1, 0x95, 0x78, 0xa3, 0x51, 0x20, 0x16, 0x9b, 0x08, 0x51, 0x1c, 0x72, 0xec, + 0x25, 0x3e, 0xc8, 0x9d, 0x55, 0xb1, 0x5d, 0x3f, 0xd9, 0xff, 0x21, 0x81, 0x5e, 0x78, 0xf6, 0x03, + 0xb0, 0xdf, 0xa5, 0x45, 0xdb, 0xda, 0x81, 0xad, 0x69, 0xa9, 0xc3, 0x00, 0x77, 0x27, 0x86, 0xec, + 0x7b, 0xb0, 0x3d, 0x57, 0x42, 0x2b, 0xb1, 0xd4, 0xba, 0x2b, 0xc2, 0x19, 0xd7, 0xef, 0xaf, 0xd4, + 0x2a, 0xaa, 0x31, 0x7d, 0x3d, 0x0d, 0x58, 0x44, 0x9e, 0x47, 0x93, 0x07, 0x5e, 0x11, 0xf6, 0x06, + 0x34, 0x1d, 0xcc, 0xc4, 0x5e, 0x36, 0xae, 0xe4, 0x44, 0xcb, 0x26, 0xb4, 0x66, 0x59, 0xda, 0xea, + 0x2e, 0x34, 0x5f, 0x1b, 0xb8, 0x68, 0xc6, 0xcc, 0x66, 0x5e, 0xd1, 0xcd, 0x6c, 0x1f, 0x41, 0x6b, + 0xf6, 0xc0, 0xad, 0xc6, 0xc8, 0x47, 0xa6, 0x9e, 0x37, 0xc8, 0xe7, 0x47, 0x44, 0xb4, 0x51, 0x62, + 0xbe, 0x02, 0x79, 0x7d, 0x25, 0x05, 0x27, 0xef, 0x7b, 0xa9, 0x7a, 0xc9, 0x4f, 0x55, 0xe5, 0x0e, + 0x6c, 0xcd, 0x53, 0xa6, 0xe3, 0xac, 0x43, 0xed, 0x45, 0xe8, 0x73, 0xd5, 0xac, 0x49, 0x62, 0x3e, + 0x05, 0xcb, 0x04, 0xaf, 0x51, 0xfe, 0x3f, 0xe5, 0x60, 0xeb, 0x84, 0x44, 0x71, 0x20, 0xf7, 0x4c, + 0x55, 0x08, 0xdf, 0x90, 0x58, 0xdc, 0x68, 0xe2, 0xf7, 0x2f, 0x61, 0x55, 0x94, 0xad, 0xdb, 0xa5, + 0x18, 0x71, 0xec, 0xb9, 0x61, 0xf2, 0x5b, 0xa8, 0x2c, 0xe0, 0x03, 0x85, 0x7e, 0xcf, 0x44, 0xed, + 0xa1, 0xae, 0x50, 0x6a, 0x8e, 0x7c, 0x50, 0x90, 0x1c, 0xfb, 0x5f, 0x42, 0x69, 0x20, 0x3d, 0x73, + 0x51, 0xe0, 0x23, 0x35, 0xfa, 0x8b, 0x7b, 0x6b, 0xd3, 0xbb, 0xf3, 0xbe, 0x60, 0x3a, 0x45, 0x25, + 0x2a, 0x09, 0xeb, 0x31, 0x34, 0x8c, 0x81, 0x36, 0x59, 0x31, 0x17, 0xa4, 0x8d, 0xba, 0xc1, 0x1b, + 0x6f, 0x9a, 0xf7, 0x60, 0x7b, 0x6e, 0x5c, 0x3a, 0x85, 0x7f, 0xcd, 0x41, 0x55, 0xa4, 0xcb, 0x6c, + 0x7d, 0xeb, 0x37, 0xb0, 0xa4, 0xa4, 0xf5, 0x95, 0xcf, 0x71, 0x4f, 0x0b, 0xcd, 0xf5, 0x2c, 0x3f, + 0xd7, 0xb3, 0xac, 0x7c, 0x16, 0x32, 0xf2, 0x99, 0xdc, 0x70, 0x7a, 0x06, 0xad, 0x41, 0xfd, 0x29, + 0x1e, 0x10, 0x8e, 0xd3, 0x17, 0xbf, 0x07, 0x8d, 0x34, 0x7c, 0x8d, 0xab, 0xdf, 0x80, 0xe6, 0x59, + 0xe8, 0x91, 0x2c, 0x75, 0x9b, 0xd0, 0x9a, 0x65, 0x69, 0x0f, 0xbe, 0x86, 0xed, 0x13, 0x4a, 0x04, + 0x43, 0x7a, 0xf6, 0xa6, 0x8f, 0xc3, 0x03, 0x14, 0xf7, 0xfa, 0xfc, 0x2c, 0xba, 0xc6, 0x24, 0xb4, + 0x7f, 0x0f, 0x3b, 0xf3, 0x8f, 0x5f, 0xcf, 0x6b, 0x75, 0x10, 0x31, 0xad, 0xc7, 0x33, 0xbc, 0x9e, + 0x65, 0x69, 0xaf, 0xff, 0x92, 0x83, 0xea, 0x29, 0x4e, 0xb7, 0xcb, 0x4d, 0xef, 0x3a, 0xe3, 0xe2, + 0xf2, 0x59, 0x8d, 0xf0, 0x08, 0x6a, 0x72, 0xf3, 0x77, 0x99, 0x98, 0xe7, 0x2e, 0x13, 0x3e, 0xe9, + 0x85, 0x7f, 0x55, 0x32, 0x26, 0x73, 0x5e, 0x3e, 0x3f, 0x78, 0xaa, 0x61, 0xed, 0x17, 0x93, 0x40, + 0x1c, 0x2c, 0x95, 0x4c, 0x26, 0xfc, 0xcd, 0x7c, 0x16, 0xbf, 0xe4, 0x32, 0x54, 0x69, 0x3b, 0x0f, + 0xc0, 0x16, 0x6f, 0xa6, 0x31, 0x68, 0xf6, 0x43, 0x4f, 0xcc, 0xe7, 0xd4, 0xce, 0xf1, 0x1a, 0xee, + 0xbf, 0x53, 0xea, 0xb6, 0x3b, 0xc8, 0x1a, 0xd4, 0xcd, 0x4a, 0x30, 0x4a, 0x39, 0x0d, 0x5f, 0xa3, + 0x28, 0x1e, 0x43, 0xf9, 0x09, 0xea, 0x5e, 0xc4, 0xe3, 0x0a, 0xdc, 0x81, 0x62, 0x97, 0x84, 0xdd, + 0x98, 0x52, 0x1c, 0x76, 0x47, 0x7a, 0x5e, 0x99, 0x90, 0xfd, 0x05, 0x54, 0x92, 0x23, 0xda, 0xc0, + 0x03, 0x58, 0xc4, 0xc3, 0x49, 0x62, 0x2b, 0xed, 0xe4, 0xdf, 0x06, 0x87, 0x02, 0x75, 0x14, 0x53, + 0xbf, 0x3d, 0x9c, 0x50, 0x7c, 0x44, 0xc9, 0x20, 0x65, 0xd5, 0xde, 0x87, 0x8d, 0x0c, 0xde, 0x4d, + 0xd4, 0x3f, 0xf9, 0xf4, 0xc7, 0xf6, 0xd0, 0xe7, 0x98, 0xb1, 0xb6, 0x4f, 0x76, 0xd5, 0xd7, 0x6e, + 0x8f, 0xec, 0x0e, 0xf9, 0xae, 0xfc, 0xe7, 0xc5, 0xee, 0xcc, 0x6f, 0xa2, 0xce, 0x92, 0x64, 0x7c, + 0xf6, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x00, 0xea, 0x85, 0x46, 0x19, 0x00, 0x00, } diff --git a/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go b/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go index 41169028ed6..acb13b630d7 100644 --- a/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go +++ b/go/vt/proto/tabletmanagerservice/tabletmanagerservice.pb.go @@ -117,6 +117,8 @@ type TabletManagerClient interface { InitSlave(ctx context.Context, in *tabletmanagerdata.InitSlaveRequest, opts ...grpc.CallOption) (*tabletmanagerdata.InitSlaveResponse, error) // DemoteMaster tells the soon-to-be-former master it's gonna change DemoteMaster(ctx context.Context, in *tabletmanagerdata.DemoteMasterRequest, opts ...grpc.CallOption) (*tabletmanagerdata.DemoteMasterResponse, error) + // UndoDemoteMaster reverts all changes made by DemoteMaster + UndoDemoteMaster(ctx context.Context, in *tabletmanagerdata.UndoDemoteMasterRequest, opts ...grpc.CallOption) (*tabletmanagerdata.UndoDemoteMasterResponse, error) // PromoteSlaveWhenCaughtUp tells the remote tablet to catch up, // and then be the master PromoteSlaveWhenCaughtUp(ctx context.Context, in *tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest, opts ...grpc.CallOption) (*tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse, error) @@ -459,6 +461,15 @@ func (c *tabletManagerClient) DemoteMaster(ctx context.Context, in *tabletmanage return out, nil } +func (c *tabletManagerClient) UndoDemoteMaster(ctx context.Context, in *tabletmanagerdata.UndoDemoteMasterRequest, opts ...grpc.CallOption) (*tabletmanagerdata.UndoDemoteMasterResponse, error) { + out := new(tabletmanagerdata.UndoDemoteMasterResponse) + err := c.cc.Invoke(ctx, "/tabletmanagerservice.TabletManager/UndoDemoteMaster", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *tabletManagerClient) PromoteSlaveWhenCaughtUp(ctx context.Context, in *tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest, opts ...grpc.CallOption) (*tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse, error) { out := new(tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse) err := c.cc.Invoke(ctx, "/tabletmanagerservice.TabletManager/PromoteSlaveWhenCaughtUp", in, out, opts...) @@ -660,6 +671,8 @@ type TabletManagerServer interface { InitSlave(context.Context, *tabletmanagerdata.InitSlaveRequest) (*tabletmanagerdata.InitSlaveResponse, error) // DemoteMaster tells the soon-to-be-former master it's gonna change DemoteMaster(context.Context, *tabletmanagerdata.DemoteMasterRequest) (*tabletmanagerdata.DemoteMasterResponse, error) + // UndoDemoteMaster reverts all changes made by DemoteMaster + UndoDemoteMaster(context.Context, *tabletmanagerdata.UndoDemoteMasterRequest) (*tabletmanagerdata.UndoDemoteMasterResponse, error) // PromoteSlaveWhenCaughtUp tells the remote tablet to catch up, // and then be the master PromoteSlaveWhenCaughtUp(context.Context, *tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest) (*tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse, error) @@ -1313,6 +1326,24 @@ func _TabletManager_DemoteMaster_Handler(srv interface{}, ctx context.Context, d return interceptor(ctx, in, info, handler) } +func _TabletManager_UndoDemoteMaster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(tabletmanagerdata.UndoDemoteMasterRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(TabletManagerServer).UndoDemoteMaster(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/tabletmanagerservice.TabletManager/UndoDemoteMaster", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(TabletManagerServer).UndoDemoteMaster(ctx, req.(*tabletmanagerdata.UndoDemoteMasterRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _TabletManager_PromoteSlaveWhenCaughtUp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest) if err := dec(in); err != nil { @@ -1607,6 +1638,10 @@ var _TabletManager_serviceDesc = grpc.ServiceDesc{ MethodName: "DemoteMaster", Handler: _TabletManager_DemoteMaster_Handler, }, + { + MethodName: "UndoDemoteMaster", + Handler: _TabletManager_UndoDemoteMaster_Handler, + }, { MethodName: "PromoteSlaveWhenCaughtUp", Handler: _TabletManager_PromoteSlaveWhenCaughtUp_Handler, @@ -1648,73 +1683,74 @@ var _TabletManager_serviceDesc = grpc.ServiceDesc{ } func init() { - proto.RegisterFile("tabletmanagerservice.proto", fileDescriptor_tabletmanagerservice_d0dfb5502bc9cb1c) -} - -var fileDescriptor_tabletmanagerservice_d0dfb5502bc9cb1c = []byte{ - // 1012 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0x5b, 0x6f, 0x1b, 0x45, - 0x14, 0xc7, 0xb1, 0x04, 0x95, 0x18, 0xae, 0x1d, 0x55, 0x14, 0x05, 0x89, 0x5b, 0x5a, 0x2e, 0x2d, - 0x8a, 0x9b, 0x86, 0xf2, 0xee, 0xa6, 0x49, 0x1b, 0xd4, 0x08, 0x63, 0x37, 0x04, 0x81, 0x84, 0x34, - 0xb1, 0x4f, 0xbc, 0x4b, 0xd6, 0x3b, 0xc3, 0xcc, 0xac, 0x95, 0x3c, 0x21, 0x21, 0xf1, 0x84, 0xc4, - 0x67, 0xe3, 0x23, 0xa1, 0xbd, 0xcc, 0xec, 0x19, 0xfb, 0xec, 0xd8, 0x7e, 0x8b, 0xfc, 0xff, 0x9d, - 0xcb, 0x9c, 0x39, 0x73, 0x66, 0xb2, 0x6c, 0xc7, 0x8a, 0x8b, 0x0c, 0xec, 0x5c, 0xe4, 0x62, 0x06, - 0xda, 0x80, 0x5e, 0xa4, 0x13, 0xd8, 0x53, 0x5a, 0x5a, 0xc9, 0xef, 0x50, 0xda, 0xce, 0xdd, 0xe0, - 0xd7, 0xa9, 0xb0, 0xa2, 0xc6, 0x1f, 0xff, 0xb7, 0xcb, 0xde, 0x79, 0x55, 0x69, 0xa7, 0xb5, 0xc6, - 0x4f, 0xd8, 0xeb, 0xc3, 0x34, 0x9f, 0xf1, 0x8f, 0xf7, 0x56, 0x6d, 0x4a, 0x61, 0x04, 0x7f, 0x14, - 0x60, 0xec, 0xce, 0x27, 0x9d, 0xba, 0x51, 0x32, 0x37, 0xf0, 0xf9, 0x6b, 0xfc, 0x25, 0x7b, 0x63, - 0x9c, 0x01, 0x28, 0x4e, 0xb1, 0x95, 0xe2, 0x9c, 0x7d, 0xda, 0x0d, 0x78, 0x6f, 0xbf, 0xb1, 0xb7, - 0x8e, 0xae, 0x61, 0x52, 0x58, 0x78, 0x21, 0xe5, 0x15, 0xbf, 0x4f, 0x98, 0x20, 0xdd, 0x79, 0xfe, - 0x62, 0x1d, 0xe6, 0xfd, 0xff, 0xcc, 0xde, 0x7c, 0x0e, 0x76, 0x3c, 0x49, 0x60, 0x2e, 0xf8, 0x2e, - 0x61, 0xe6, 0x55, 0xe7, 0xfb, 0x5e, 0x1c, 0xf2, 0x9e, 0x67, 0xec, 0xdd, 0xe7, 0x60, 0x87, 0xa0, - 0xe7, 0xa9, 0x31, 0xa9, 0xcc, 0x0d, 0xff, 0x8a, 0xb6, 0x44, 0x88, 0x8b, 0xf1, 0xf5, 0x06, 0x24, - 0x2e, 0xd1, 0x18, 0xec, 0x08, 0xc4, 0xf4, 0x87, 0x3c, 0xbb, 0x21, 0x4b, 0x84, 0xf4, 0x58, 0x89, - 0x02, 0xcc, 0xfb, 0x17, 0xec, 0xed, 0x46, 0x38, 0xd7, 0xa9, 0x05, 0x1e, 0xb1, 0xac, 0x00, 0x17, - 0xe1, 0xcb, 0xb5, 0x9c, 0x0f, 0xf1, 0x2b, 0x63, 0x87, 0x89, 0xc8, 0x67, 0xf0, 0xea, 0x46, 0x01, - 0xa7, 0x2a, 0xdc, 0xca, 0xce, 0xfd, 0xfd, 0x35, 0x14, 0xce, 0x7f, 0x04, 0x97, 0x1a, 0x4c, 0x32, - 0xb6, 0xa2, 0x23, 0x7f, 0x0c, 0xc4, 0xf2, 0x0f, 0x39, 0xbc, 0xd7, 0xa3, 0x22, 0x7f, 0x01, 0x22, - 0xb3, 0xc9, 0x61, 0x02, 0x93, 0x2b, 0x72, 0xaf, 0x43, 0x24, 0xb6, 0xd7, 0xcb, 0xa4, 0x0f, 0xa4, - 0xd8, 0xed, 0x93, 0x59, 0x2e, 0x35, 0xd4, 0xf2, 0x91, 0xd6, 0x52, 0xf3, 0x87, 0x84, 0x87, 0x15, - 0xca, 0x85, 0xfb, 0x66, 0x33, 0x38, 0xac, 0x5e, 0x26, 0xc5, 0xb4, 0x39, 0x23, 0x74, 0xf5, 0x5a, - 0x20, 0x5e, 0x3d, 0xcc, 0xf9, 0x10, 0xbf, 0xb3, 0xf7, 0x86, 0x1a, 0x2e, 0xb3, 0x74, 0x96, 0xb8, - 0x93, 0x48, 0x15, 0x65, 0x89, 0x71, 0x81, 0x1e, 0x6c, 0x82, 0xe2, 0xc3, 0x32, 0x50, 0x2a, 0xbb, - 0x69, 0xe2, 0x50, 0x4d, 0x84, 0xf4, 0xd8, 0x61, 0x09, 0x30, 0xdc, 0xc9, 0x2f, 0xe5, 0xe4, 0xaa, - 0x9a, 0xae, 0x86, 0xec, 0xe4, 0x56, 0x8e, 0x75, 0x32, 0xa6, 0xf0, 0x5e, 0x9c, 0xe5, 0x59, 0xeb, - 0x9e, 0x4a, 0x0b, 0x03, 0xb1, 0xbd, 0x08, 0x39, 0xdc, 0x60, 0xcd, 0xa0, 0x3c, 0x06, 0x3b, 0x49, - 0x06, 0xe6, 0xd9, 0x85, 0x20, 0x1b, 0x6c, 0x85, 0x8a, 0x35, 0x18, 0x01, 0xfb, 0x88, 0x7f, 0xb2, - 0x0f, 0x42, 0x79, 0x90, 0x65, 0x43, 0x9d, 0x2e, 0x0c, 0x7f, 0xb4, 0xd6, 0x93, 0x43, 0x5d, 0xec, - 0xfd, 0x2d, 0x2c, 0xba, 0x97, 0x3c, 0x50, 0x6a, 0x83, 0x25, 0x0f, 0x94, 0xda, 0x7c, 0xc9, 0x15, - 0x1c, 0x4c, 0xec, 0x4c, 0x2c, 0xa0, 0x1c, 0x23, 0x85, 0xa1, 0x27, 0x76, 0xab, 0x47, 0x27, 0x36, - 0xc6, 0xf0, 0x38, 0x3a, 0x15, 0xc6, 0x82, 0x1e, 0x4a, 0x93, 0xda, 0x54, 0xe6, 0xe4, 0x38, 0x0a, - 0x91, 0xd8, 0x38, 0x5a, 0x26, 0xf1, 0xed, 0x39, 0xb6, 0x52, 0x55, 0x59, 0x90, 0xb7, 0xa7, 0x57, - 0x63, 0xb7, 0x27, 0x82, 0xbc, 0xe7, 0x39, 0x7b, 0xdf, 0xff, 0x7c, 0x9a, 0xe6, 0xe9, 0xbc, 0x98, - 0xf3, 0x07, 0x31, 0xdb, 0x06, 0x72, 0x71, 0x1e, 0x6e, 0xc4, 0xe2, 0x63, 0x3b, 0xb6, 0x42, 0xdb, - 0x7a, 0x25, 0x74, 0x92, 0x4e, 0x8e, 0x1d, 0x5b, 0x4c, 0x79, 0xe7, 0x37, 0xec, 0x4e, 0xfb, 0xfb, - 0x59, 0x6e, 0xd3, 0x6c, 0x70, 0x69, 0x41, 0xf3, 0xbd, 0xa8, 0x83, 0x16, 0x74, 0x01, 0xfb, 0x1b, - 0xf3, 0x3e, 0xf4, 0x3f, 0x3d, 0xb6, 0x53, 0xbf, 0xf4, 0x8e, 0xae, 0x2d, 0xe8, 0x5c, 0x64, 0xe5, - 0xd5, 0xae, 0x84, 0x86, 0xdc, 0xc2, 0x94, 0x7f, 0x4b, 0x78, 0xec, 0xc6, 0x5d, 0x1e, 0x4f, 0xb6, - 0xb4, 0xf2, 0xd9, 0xfc, 0xd5, 0x63, 0x77, 0x97, 0xc1, 0xa3, 0x0c, 0x26, 0x65, 0x2a, 0xfb, 0x1b, - 0x38, 0x6d, 0x58, 0x97, 0xc7, 0xe3, 0x6d, 0x4c, 0x96, 0x5f, 0x7c, 0x65, 0xc9, 0x4c, 0xe7, 0x8b, - 0xaf, 0x52, 0xd7, 0xbd, 0xf8, 0x1a, 0x08, 0xf7, 0xec, 0x4f, 0x23, 0x50, 0x59, 0x3a, 0x11, 0xe5, - 0x39, 0x29, 0x27, 0x00, 0xd9, 0xb3, 0xcb, 0x50, 0xac, 0x67, 0x57, 0x59, 0x3c, 0x38, 0xb1, 0x7a, - 0x2e, 0x52, 0x7b, 0x2c, 0xcb, 0x53, 0x4a, 0x0e, 0x4e, 0x1a, 0x8d, 0x0d, 0xce, 0x2e, 0x0b, 0xbc, - 0xde, 0x11, 0x98, 0xf2, 0x45, 0xe7, 0x39, 0x72, 0xbd, 0xcb, 0x50, 0x6c, 0xbd, 0xab, 0x2c, 0x3e, - 0xa3, 0x27, 0x79, 0x6a, 0xeb, 0x61, 0x44, 0x9e, 0xd1, 0x56, 0x8e, 0x9d, 0x51, 0x4c, 0x05, 0xad, - 0x39, 0x94, 0xaa, 0xc8, 0xaa, 0x87, 0x5d, 0xdd, 0xbb, 0xdf, 0xcb, 0xa2, 0x6c, 0x22, 0xb2, 0x35, - 0x3b, 0xd8, 0x58, 0x6b, 0x76, 0x9a, 0xe0, 0xd6, 0x2c, 0x93, 0xeb, 0x1e, 0xa7, 0x5e, 0x8d, 0xb5, - 0x26, 0x82, 0xf0, 0xcb, 0xe1, 0x19, 0xcc, 0xa5, 0x85, 0xa6, 0x7a, 0xd4, 0x5d, 0x82, 0x81, 0xd8, - 0xcb, 0x21, 0xe4, 0x7c, 0x88, 0xbf, 0x7b, 0xec, 0xc3, 0xa1, 0x96, 0xa5, 0x56, 0x45, 0x3f, 0x4f, - 0x20, 0x3f, 0x14, 0xc5, 0x2c, 0xb1, 0x67, 0x8a, 0x93, 0xf5, 0xe8, 0x80, 0x5d, 0xec, 0x83, 0xad, - 0x6c, 0x82, 0x9b, 0xa3, 0x92, 0x85, 0x69, 0xe8, 0x29, 0x7d, 0x73, 0x2c, 0x41, 0xd1, 0x9b, 0x63, - 0x85, 0x0d, 0xae, 0x40, 0x70, 0x4d, 0xb9, 0x4b, 0xff, 0xcb, 0x13, 0xd6, 0xf4, 0x5e, 0x1c, 0xc2, - 0xef, 0x12, 0x17, 0x77, 0x04, 0xa6, 0x9c, 0xf3, 0x30, 0xe5, 0xb1, 0xec, 0x3c, 0x15, 0x7b, 0x97, - 0x10, 0xb0, 0x8f, 0xf8, 0x6f, 0x8f, 0x7d, 0x54, 0x5e, 0x92, 0xe8, 0xfc, 0x0d, 0xf2, 0x69, 0x39, - 0xea, 0xea, 0x87, 0xca, 0x93, 0x8e, 0x4b, 0xb5, 0x83, 0x77, 0x69, 0x7c, 0xb7, 0xad, 0x19, 0x6e, - 0x5b, 0xbc, 0xe3, 0x64, 0xdb, 0x62, 0x20, 0xd6, 0xb6, 0x21, 0xe7, 0x43, 0xfc, 0xc8, 0x6e, 0x3d, - 0x15, 0x93, 0xab, 0x42, 0x71, 0xea, 0x73, 0x44, 0x2d, 0x39, 0xb7, 0x9f, 0x45, 0x08, 0xe7, 0xf0, - 0x51, 0x8f, 0x6b, 0x76, 0xbb, 0xac, 0xae, 0xd4, 0x70, 0xac, 0xe5, 0xbc, 0xf1, 0xde, 0x31, 0xec, - 0x42, 0x2a, 0xb6, 0x71, 0x04, 0xdc, 0xc6, 0x7c, 0x7a, 0xf0, 0xcb, 0xfe, 0x22, 0xb5, 0x60, 0xcc, - 0x5e, 0x2a, 0xfb, 0xf5, 0x5f, 0xfd, 0x99, 0xec, 0x2f, 0x6c, 0xbf, 0xfa, 0xe4, 0xd3, 0xa7, 0x3e, - 0x10, 0x5d, 0xdc, 0xaa, 0xb4, 0x83, 0xff, 0x03, 0x00, 0x00, 0xff, 0xff, 0x6a, 0x46, 0xe6, 0xae, - 0x5b, 0x12, 0x00, 0x00, + proto.RegisterFile("tabletmanagerservice.proto", fileDescriptor_tabletmanagerservice_0dc181478a076ccc) +} + +var fileDescriptor_tabletmanagerservice_0dc181478a076ccc = []byte{ + // 1030 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x98, 0x6d, 0x6f, 0x1b, 0x45, + 0x10, 0xc7, 0xb1, 0x04, 0x95, 0x58, 0x1e, 0xbb, 0xaa, 0x28, 0x0a, 0x12, 0x4f, 0x4d, 0x79, 0x48, + 0x51, 0xdc, 0x34, 0x94, 0xf7, 0x6e, 0x9a, 0xb4, 0x41, 0x8d, 0x30, 0x76, 0x43, 0x10, 0x48, 0x48, + 0x1b, 0x7b, 0xe2, 0x3b, 0x72, 0xde, 0x3d, 0x76, 0xf7, 0xac, 0xe6, 0x15, 0x12, 0x12, 0xaf, 0x90, + 0xf8, 0x4a, 0x7c, 0x35, 0x74, 0x0f, 0xbb, 0x37, 0x6b, 0xcf, 0xad, 0xed, 0x77, 0x91, 0xff, 0xbf, + 0x9d, 0x99, 0x9d, 0x9d, 0x99, 0xdd, 0x1c, 0xdb, 0xb1, 0xe2, 0x32, 0x03, 0x3b, 0x17, 0x52, 0xcc, + 0x40, 0x1b, 0xd0, 0x8b, 0x74, 0x02, 0xfb, 0xb9, 0x56, 0x56, 0xf1, 0x3b, 0x94, 0xb6, 0x73, 0x37, + 0xf8, 0x75, 0x2a, 0xac, 0xa8, 0xf1, 0x47, 0xff, 0xed, 0xb2, 0x77, 0x5e, 0x56, 0xda, 0x59, 0xad, + 0xf1, 0x53, 0xf6, 0xfa, 0x30, 0x95, 0x33, 0xfe, 0xf1, 0xfe, 0xea, 0x9a, 0x52, 0x18, 0xc1, 0x1f, + 0x05, 0x18, 0xbb, 0xf3, 0x49, 0xa7, 0x6e, 0x72, 0x25, 0x0d, 0x7c, 0xfe, 0x1a, 0x7f, 0xc1, 0xde, + 0x18, 0x67, 0x00, 0x39, 0xa7, 0xd8, 0x4a, 0x71, 0xc6, 0x3e, 0xed, 0x06, 0xbc, 0xb5, 0xdf, 0xd8, + 0x5b, 0xc7, 0xaf, 0x60, 0x52, 0x58, 0x78, 0xae, 0xd4, 0x35, 0xbf, 0x4f, 0x2c, 0x41, 0xba, 0xb3, + 0xfc, 0xc5, 0x3a, 0xcc, 0xdb, 0xff, 0x99, 0xbd, 0xf9, 0x0c, 0xec, 0x78, 0x92, 0xc0, 0x5c, 0xf0, + 0x7b, 0xc4, 0x32, 0xaf, 0x3a, 0xdb, 0xbb, 0x71, 0xc8, 0x5b, 0x9e, 0xb1, 0x77, 0x9f, 0x81, 0x1d, + 0x82, 0x9e, 0xa7, 0xc6, 0xa4, 0x4a, 0x1a, 0xfe, 0x15, 0xbd, 0x12, 0x21, 0xce, 0xc7, 0xd7, 0x1b, + 0x90, 0x38, 0x45, 0x63, 0xb0, 0x23, 0x10, 0xd3, 0x1f, 0x64, 0x76, 0x43, 0xa6, 0x08, 0xe9, 0xb1, + 0x14, 0x05, 0x98, 0xb7, 0x2f, 0xd8, 0xdb, 0x8d, 0x70, 0xa1, 0x53, 0x0b, 0x3c, 0xb2, 0xb2, 0x02, + 0x9c, 0x87, 0x2f, 0xd7, 0x72, 0xde, 0xc5, 0xaf, 0x8c, 0x1d, 0x25, 0x42, 0xce, 0xe0, 0xe5, 0x4d, + 0x0e, 0x9c, 0xca, 0x70, 0x2b, 0x3b, 0xf3, 0xf7, 0xd7, 0x50, 0x38, 0xfe, 0x11, 0x5c, 0x69, 0x30, + 0xc9, 0xd8, 0x8a, 0x8e, 0xf8, 0x31, 0x10, 0x8b, 0x3f, 0xe4, 0xf0, 0x59, 0x8f, 0x0a, 0xf9, 0x1c, + 0x44, 0x66, 0x93, 0xa3, 0x04, 0x26, 0xd7, 0xe4, 0x59, 0x87, 0x48, 0xec, 0xac, 0x97, 0x49, 0xef, + 0x28, 0x67, 0xb7, 0x4f, 0x67, 0x52, 0x69, 0xa8, 0xe5, 0x63, 0xad, 0x95, 0xe6, 0x0f, 0x08, 0x0b, + 0x2b, 0x94, 0x73, 0xf7, 0xcd, 0x66, 0x70, 0x98, 0xbd, 0x4c, 0x89, 0x69, 0xd3, 0x23, 0x74, 0xf6, + 0x5a, 0x20, 0x9e, 0x3d, 0xcc, 0x79, 0x17, 0xbf, 0xb3, 0xf7, 0x86, 0x1a, 0xae, 0xb2, 0x74, 0x96, + 0xb8, 0x4e, 0xa4, 0x92, 0xb2, 0xc4, 0x38, 0x47, 0x7b, 0x9b, 0xa0, 0xb8, 0x59, 0x06, 0x79, 0x9e, + 0xdd, 0x34, 0x7e, 0xa8, 0x22, 0x42, 0x7a, 0xac, 0x59, 0x02, 0x0c, 0x57, 0xf2, 0x0b, 0x35, 0xb9, + 0xae, 0xa6, 0xab, 0x21, 0x2b, 0xb9, 0x95, 0x63, 0x95, 0x8c, 0x29, 0x7c, 0x16, 0xe7, 0x32, 0x6b, + 0xcd, 0x53, 0x61, 0x61, 0x20, 0x76, 0x16, 0x21, 0x87, 0x0b, 0xac, 0x19, 0x94, 0x27, 0x60, 0x27, + 0xc9, 0xc0, 0x3c, 0xbd, 0x14, 0x64, 0x81, 0xad, 0x50, 0xb1, 0x02, 0x23, 0x60, 0xef, 0xf1, 0x4f, + 0xf6, 0x41, 0x28, 0x0f, 0xb2, 0x6c, 0xa8, 0xd3, 0x85, 0xe1, 0x0f, 0xd7, 0x5a, 0x72, 0xa8, 0xf3, + 0x7d, 0xb0, 0xc5, 0x8a, 0xee, 0x2d, 0x0f, 0xf2, 0x7c, 0x83, 0x2d, 0x0f, 0xf2, 0x7c, 0xf3, 0x2d, + 0x57, 0x70, 0x30, 0xb1, 0x33, 0xb1, 0x80, 0x72, 0x8c, 0x14, 0x86, 0x9e, 0xd8, 0xad, 0x1e, 0x9d, + 0xd8, 0x18, 0xc3, 0xe3, 0xe8, 0x4c, 0x18, 0x0b, 0x7a, 0xa8, 0x4c, 0x6a, 0x53, 0x25, 0xc9, 0x71, + 0x14, 0x22, 0xb1, 0x71, 0xb4, 0x4c, 0xe2, 0xdb, 0x73, 0x6c, 0x55, 0x5e, 0x45, 0x41, 0xde, 0x9e, + 0x5e, 0x8d, 0xdd, 0x9e, 0x08, 0xf2, 0x96, 0xe7, 0xec, 0x7d, 0xff, 0xf3, 0x59, 0x2a, 0xd3, 0x79, + 0x31, 0xe7, 0x7b, 0xb1, 0xb5, 0x0d, 0xe4, 0xfc, 0x3c, 0xd8, 0x88, 0xc5, 0x6d, 0x3b, 0xb6, 0x42, + 0xdb, 0x7a, 0x27, 0x74, 0x90, 0x4e, 0x8e, 0xb5, 0x2d, 0xa6, 0xbc, 0xf1, 0x1b, 0x76, 0xa7, 0xfd, + 0xfd, 0x5c, 0xda, 0x34, 0x1b, 0x5c, 0x59, 0xd0, 0x7c, 0x3f, 0x6a, 0xa0, 0x05, 0x9d, 0xc3, 0xfe, + 0xc6, 0xbc, 0x77, 0xfd, 0x4f, 0x8f, 0xed, 0xd4, 0x2f, 0xbd, 0xe3, 0x57, 0x16, 0xb4, 0x14, 0x59, + 0x79, 0xb5, 0xe7, 0x42, 0x83, 0xb4, 0x30, 0xe5, 0xdf, 0x12, 0x16, 0xbb, 0x71, 0x17, 0xc7, 0xe3, + 0x2d, 0x57, 0xf9, 0x68, 0xfe, 0xea, 0xb1, 0xbb, 0xcb, 0xe0, 0x71, 0x06, 0x93, 0x32, 0x94, 0x83, + 0x0d, 0x8c, 0x36, 0xac, 0x8b, 0xe3, 0xd1, 0x36, 0x4b, 0x96, 0x5f, 0x7c, 0x65, 0xca, 0x4c, 0xe7, + 0x8b, 0xaf, 0x52, 0xd7, 0xbd, 0xf8, 0x1a, 0x08, 0xd7, 0xec, 0x4f, 0x23, 0xc8, 0xb3, 0x74, 0x22, + 0xca, 0x3e, 0x29, 0x27, 0x00, 0x59, 0xb3, 0xcb, 0x50, 0xac, 0x66, 0x57, 0x59, 0x3c, 0x38, 0xb1, + 0x7a, 0x21, 0x52, 0x7b, 0xa2, 0xca, 0x2e, 0x25, 0x07, 0x27, 0x8d, 0xc6, 0x06, 0x67, 0xd7, 0x0a, + 0xbc, 0xdf, 0x11, 0x98, 0xf2, 0x45, 0xe7, 0x39, 0x72, 0xbf, 0xcb, 0x50, 0x6c, 0xbf, 0xab, 0x2c, + 0xee, 0xd1, 0x53, 0x99, 0xda, 0x7a, 0x18, 0x91, 0x3d, 0xda, 0xca, 0xb1, 0x1e, 0xc5, 0x54, 0x50, + 0x9a, 0x43, 0x95, 0x17, 0x59, 0xf5, 0xb0, 0xab, 0x6b, 0xf7, 0x7b, 0x55, 0x94, 0x45, 0x44, 0x96, + 0x66, 0x07, 0x1b, 0x2b, 0xcd, 0xce, 0x25, 0xb8, 0x34, 0xcb, 0xe0, 0xba, 0xc7, 0xa9, 0x57, 0x63, + 0xa5, 0x89, 0x20, 0xfc, 0x72, 0x78, 0x0a, 0x73, 0x65, 0xa1, 0xc9, 0x1e, 0x75, 0x97, 0x60, 0x20, + 0xf6, 0x72, 0x08, 0x39, 0x5c, 0x0d, 0xe7, 0x72, 0xaa, 0x02, 0x37, 0x7b, 0xe4, 0xc3, 0x23, 0x84, + 0x62, 0xd5, 0xb0, 0xca, 0x7a, 0x77, 0x7f, 0xf7, 0xd8, 0x87, 0x43, 0xad, 0x4a, 0xad, 0xda, 0xec, + 0x45, 0x02, 0xf2, 0x48, 0x14, 0xb3, 0xc4, 0x9e, 0xe7, 0x9c, 0x4c, 0x7f, 0x07, 0xec, 0xfc, 0x1f, + 0x6e, 0xb5, 0x26, 0xb8, 0xa8, 0x2a, 0x59, 0x98, 0x86, 0x9e, 0xd2, 0x17, 0xd5, 0x12, 0x14, 0xbd, + 0xa8, 0x56, 0xd8, 0xe0, 0xc6, 0x05, 0xd7, 0x03, 0xf7, 0xe8, 0xff, 0xb0, 0xc2, 0xbc, 0xee, 0xc6, + 0x21, 0xfc, 0x0c, 0x72, 0x7e, 0x47, 0x60, 0xca, 0x6b, 0x05, 0xa6, 0x3c, 0x16, 0x9d, 0xa7, 0x62, + 0xcf, 0x20, 0x02, 0xf6, 0x1e, 0xff, 0xed, 0xb1, 0x8f, 0xca, 0x3b, 0x19, 0xb5, 0xfb, 0x40, 0x4e, + 0xcb, 0xc9, 0x5a, 0xbf, 0x8b, 0x1e, 0x77, 0xdc, 0xe1, 0x1d, 0xbc, 0x0b, 0xe3, 0xbb, 0x6d, 0x97, + 0xe1, 0x2e, 0xc1, 0x27, 0x4e, 0x76, 0x09, 0x06, 0x62, 0x5d, 0x12, 0x72, 0xde, 0xc5, 0x8f, 0xec, + 0xd6, 0x13, 0x31, 0xb9, 0x2e, 0x72, 0x4e, 0x7d, 0xfd, 0xa8, 0x25, 0x67, 0xf6, 0xb3, 0x08, 0xe1, + 0x0c, 0x3e, 0xec, 0x71, 0xcd, 0x6e, 0x97, 0xd9, 0x55, 0x1a, 0x4e, 0xb4, 0x9a, 0x37, 0xd6, 0x3b, + 0x66, 0x6b, 0x48, 0xc5, 0x0e, 0x8e, 0x80, 0x5b, 0x9f, 0x4f, 0x0e, 0x7f, 0x39, 0x58, 0xa4, 0x16, + 0x8c, 0xd9, 0x4f, 0x55, 0xbf, 0xfe, 0xab, 0x3f, 0x53, 0xfd, 0x85, 0xed, 0x57, 0x5f, 0x98, 0xfa, + 0xd4, 0xf7, 0xa8, 0xcb, 0x5b, 0x95, 0x76, 0xf8, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xae, 0x75, + 0xbb, 0x5f, 0xca, 0x12, 0x00, 0x00, } diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index afda516f43f..36e7e1c3a53 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -664,6 +664,10 @@ func (itmc *internalTabletManagerClient) DemoteMaster(ctx context.Context, table return "", fmt.Errorf("not implemented in vtcombo") } +func (itmc *internalTabletManagerClient) UndoDemoteMaster(ctx context.Context, tablet *topodatapb.Tablet) error { + return fmt.Errorf("not implemented in vtcombo") +} + func (itmc *internalTabletManagerClient) PromoteSlaveWhenCaughtUp(ctx context.Context, tablet *topodatapb.Tablet, pos string) (string, error) { return "", fmt.Errorf("not implemented in vtcombo") } diff --git a/go/vt/vttablet/agentrpctest/test_agent_rpc.go b/go/vt/vttablet/agentrpctest/test_agent_rpc.go index 7039a216a46..de979f35482 100644 --- a/go/vt/vttablet/agentrpctest/test_agent_rpc.go +++ b/go/vt/vttablet/agentrpctest/test_agent_rpc.go @@ -1008,6 +1008,26 @@ func agentRPCTestDemoteMasterPanic(ctx context.Context, t *testing.T, client tmc expectHandleRPCPanic(t, "DemoteMaster", true /*verbose*/, err) } +var testUndoDemoteMasterCalled = false + +func (fra *fakeRPCAgent) UndoDemoteMaster(ctx context.Context) error { + if fra.panics { + panic(fmt.Errorf("test-triggered panic")) + } + return nil +} + +func agentRPCTestUndoDemoteMaster(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { + err := client.UndoDemoteMaster(ctx, tablet) + testUndoDemoteMasterCalled = true + compareError(t, "UndoDemoteMaster", err, true, testUndoDemoteMasterCalled) +} + +func agentRPCTestUndoDemoteMasterPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { + err := client.UndoDemoteMaster(ctx, tablet) + expectHandleRPCPanic(t, "UndoDemoteMaster", true /*verbose*/, err) +} + var testReplicationPositionReturned = "MariaDB/5-567-3456" func (fra *fakeRPCAgent) PromoteSlaveWhenCaughtUp(ctx context.Context, position string) (string, error) { @@ -1262,6 +1282,7 @@ func Run(t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.T agentRPCTestPopulateReparentJournal(ctx, t, client, tablet) agentRPCTestInitSlave(ctx, t, client, tablet) agentRPCTestDemoteMaster(ctx, t, client, tablet) + agentRPCTestUndoDemoteMaster(ctx, t, client, tablet) agentRPCTestPromoteSlaveWhenCaughtUp(ctx, t, client, tablet) agentRPCTestSlaveWasPromoted(ctx, t, client, tablet) agentRPCTestSetMaster(ctx, t, client, tablet) @@ -1315,6 +1336,7 @@ func Run(t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.T agentRPCTestPopulateReparentJournalPanic(ctx, t, client, tablet) agentRPCTestInitSlavePanic(ctx, t, client, tablet) agentRPCTestDemoteMasterPanic(ctx, t, client, tablet) + agentRPCTestUndoDemoteMasterPanic(ctx, t, client, tablet) agentRPCTestPromoteSlaveWhenCaughtUpPanic(ctx, t, client, tablet) agentRPCTestSlaveWasPromotedPanic(ctx, t, client, tablet) agentRPCTestSetMasterPanic(ctx, t, client, tablet) diff --git a/go/vt/vttablet/faketmclient/fake_client.go b/go/vt/vttablet/faketmclient/fake_client.go index 5ce41a95adf..436d7ee09bb 100644 --- a/go/vt/vttablet/faketmclient/fake_client.go +++ b/go/vt/vttablet/faketmclient/fake_client.go @@ -255,6 +255,11 @@ func (client *FakeTabletManagerClient) DemoteMaster(ctx context.Context, tablet return "", nil } +// UndoDemoteMaster is part of the tmclient.TabletManagerClient interface. +func (client *FakeTabletManagerClient) UndoDemoteMaster(ctx context.Context, tablet *topodatapb.Tablet) error { + return nil +} + // PromoteSlaveWhenCaughtUp is part of the tmclient.TabletManagerClient interface. func (client *FakeTabletManagerClient) PromoteSlaveWhenCaughtUp(ctx context.Context, tablet *topodatapb.Tablet, position string) (string, error) { return "", nil diff --git a/go/vt/vttablet/grpctmclient/client.go b/go/vt/vttablet/grpctmclient/client.go index 7b83101e1be..4dd9c0be243 100644 --- a/go/vt/vttablet/grpctmclient/client.go +++ b/go/vt/vttablet/grpctmclient/client.go @@ -663,6 +663,17 @@ func (client *Client) DemoteMaster(ctx context.Context, tablet *topodatapb.Table return response.Position, nil } +// UndoDemoteMaster is part of the tmclient.TabletManagerClient interface. +func (client *Client) UndoDemoteMaster(ctx context.Context, tablet *topodatapb.Tablet) error { + cc, c, err := client.dial(tablet) + if err != nil { + return err + } + defer cc.Close() + _, err = c.UndoDemoteMaster(ctx, &tabletmanagerdatapb.UndoDemoteMasterRequest{}) + return err +} + // PromoteSlaveWhenCaughtUp is part of the tmclient.TabletManagerClient interface. func (client *Client) PromoteSlaveWhenCaughtUp(ctx context.Context, tablet *topodatapb.Tablet, pos string) (string, error) { cc, c, err := client.dial(tablet) diff --git a/go/vt/vttablet/grpctmserver/server.go b/go/vt/vttablet/grpctmserver/server.go index bba4157a885..6caa9bdfc54 100644 --- a/go/vt/vttablet/grpctmserver/server.go +++ b/go/vt/vttablet/grpctmserver/server.go @@ -372,6 +372,14 @@ func (s *server) DemoteMaster(ctx context.Context, request *tabletmanagerdatapb. return response, err } +func (s *server) UndoDemoteMaster(ctx context.Context, request *tabletmanagerdatapb.UndoDemoteMasterRequest) (response *tabletmanagerdatapb.UndoDemoteMasterResponse, err error) { + defer s.agent.HandleRPCPanic(ctx, "UndoDemoteMaster", request, response, true /*verbose*/, &err) + ctx = callinfo.GRPCCallInfo(ctx) + response = &tabletmanagerdatapb.UndoDemoteMasterResponse{} + err = s.agent.UndoDemoteMaster(ctx) + return response, err +} + func (s *server) PromoteSlaveWhenCaughtUp(ctx context.Context, request *tabletmanagerdatapb.PromoteSlaveWhenCaughtUpRequest) (response *tabletmanagerdatapb.PromoteSlaveWhenCaughtUpResponse, err error) { defer s.agent.HandleRPCPanic(ctx, "PromoteSlaveWhenCaughtUp", request, response, true /*verbose*/, &err) ctx = callinfo.GRPCCallInfo(ctx) diff --git a/go/vt/vttablet/tabletmanager/rpc_agent.go b/go/vt/vttablet/tabletmanager/rpc_agent.go index 1bef381a7e8..29d8249c03f 100644 --- a/go/vt/vttablet/tabletmanager/rpc_agent.go +++ b/go/vt/vttablet/tabletmanager/rpc_agent.go @@ -110,6 +110,8 @@ type RPCAgent interface { DemoteMaster(ctx context.Context) (string, error) + UndoDemoteMaster(ctx context.Context) error + PromoteSlaveWhenCaughtUp(ctx context.Context, replicationPosition string) (string, error) SlaveWasPromoted(ctx context.Context) error diff --git a/go/vt/vttablet/tabletmanager/rpc_replication.go b/go/vt/vttablet/tabletmanager/rpc_replication.go index 4b255b68632..802d6141e1e 100644 --- a/go/vt/vttablet/tabletmanager/rpc_replication.go +++ b/go/vt/vttablet/tabletmanager/rpc_replication.go @@ -332,16 +332,40 @@ func (agent *ActionAgent) DemoteMaster(ctx context.Context) (string, error) { // Now, set the server read-only. Note all active connections are not // affected. if err := agent.MysqlDaemon.SetReadOnly(true); err != nil { + // if this failed, revert the change to serving + if _ /* state changed */, err1 := agent.QueryServiceControl.SetServingType(tablet.Type, true, nil); err1 != nil { + log.Warningf("SetServingType(serving=true) failed after failed SetReadOnly %v", err1) + } return "", err } // If using semi-sync, we need to disable master-side. if err := agent.fixSemiSync(topodatapb.TabletType_REPLICA); err != nil { + // if this failed, set server read-only back to false, set tablet back to serving + if err1 := agent.MysqlDaemon.SetReadOnly(false); err1 != nil { + log.Warningf("SetReadOnly(false) failed after failed fixSemiSync %v", err1) + } + if _ /* state changed */, err1 := agent.QueryServiceControl.SetServingType(tablet.Type, true, nil); err1 != nil { + log.Warningf("SetServingType(serving=true) failed after failed fixSemiSync %v", err1) + } return "", err } pos, err := agent.MysqlDaemon.DemoteMaster() if err != nil { + // if DemoteMaster failed, undo all the steps before + // 1. set server back to read-only false + if err1 := agent.MysqlDaemon.SetReadOnly(false); err1 != nil { + log.Warningf("SetReadOnly(false) failed after failed DemoteMaster %v", err1) + } + // 2. set tablet back to serving + if _ /* state changed */, err1 := agent.QueryServiceControl.SetServingType(tablet.Type, true, nil); err1 != nil { + log.Warningf("SetServingType(serving=true) failed after failed DemoteMaster %v", err1) + } + // 3. enable master side again + if err1 := agent.fixSemiSync(topodatapb.TabletType_MASTER); err1 != nil { + log.Warningf("fixSemiSync(MASTER) failed after failed DemoteMaster %v", err1) + } return "", err } return mysql.EncodePosition(pos), nil @@ -351,6 +375,35 @@ func (agent *ActionAgent) DemoteMaster(ctx context.Context) (string, error) { // until we'll promote the master. } +// UndoDemoteMaster reverts a previous call to DemoteMaster +// it sets read-only to false, fixes semi-sync +// and returns its master position. +func (agent *ActionAgent) UndoDemoteMaster(ctx context.Context) error { + if err := agent.lock(ctx); err != nil { + return err + } + defer agent.unlock() + + // If using semi-sync, we need to enable master-side. + if err := agent.fixSemiSync(topodatapb.TabletType_MASTER); err != nil { + return err + } + + // Now, set the server read-only false. + if err := agent.MysqlDaemon.SetReadOnly(false); err != nil { + return err + } + + // Update serving graph + tablet := agent.Tablet() + log.Infof("UndoDemoteMaster re-enabling query service") + if _ /* state changed */, err := agent.QueryServiceControl.SetServingType(tablet.Type, true, nil); err != nil { + return vterrors.Wrap(err, "SetServingType(serving=true) failed") + } + + return nil +} + // PromoteSlaveWhenCaughtUp waits for this slave to be caught up on // replication up to the provided point, and then makes the slave the // shard master. diff --git a/go/vt/vttablet/tmclient/rpc_client_api.go b/go/vt/vttablet/tmclient/rpc_client_api.go index 77c344d35d4..063f5243708 100644 --- a/go/vt/vttablet/tmclient/rpc_client_api.go +++ b/go/vt/vttablet/tmclient/rpc_client_api.go @@ -171,6 +171,10 @@ type TabletManagerClient interface { // and it should go read-only and return its current position. DemoteMaster(ctx context.Context, tablet *topodatapb.Tablet) (string, error) + // UndoDemoteMaster reverts all changes made by DemoteMaster + // To be used if we are unable to promote the chosen new master + UndoDemoteMaster(ctx context.Context, tablet *topodatapb.Tablet) error + // PromoteSlaveWhenCaughtUp transforms the tablet from a slave to a master. PromoteSlaveWhenCaughtUp(ctx context.Context, tablet *topodatapb.Tablet, pos string) (string, error) diff --git a/go/vt/wrangler/reparent.go b/go/vt/wrangler/reparent.go index 4b8a1d09148..46adcca7b69 100644 --- a/go/vt/wrangler/reparent.go +++ b/go/vt/wrangler/reparent.go @@ -30,6 +30,7 @@ import ( "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/vt/concurrency" + "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/topotools" @@ -426,6 +427,10 @@ func (wr *Wrangler) plannedReparentShardLocked(ctx context.Context, ev *events.R event.DispatchUpdate(ev, "promoting slave") rp, err = wr.tmc.PromoteSlaveWhenCaughtUp(ctx, masterElectTabletInfo.Tablet, rp) if err != nil { + // if this fails it is not enough to return an error. we should rollback all the changes made by DemoteMaster + if err1 := wr.tmc.UndoDemoteMaster(ctx, oldMasterTabletInfo.Tablet); err1 != nil { + log.Warningf("Encountered error %v while trying to undo DemoteMaster", err1) + } return fmt.Errorf("master-elect tablet %v failed to catch up with replication or be upgraded to master: %v", masterElectTabletAliasStr, err) } diff --git a/go/vt/wrangler/testlib/planned_reparent_shard_test.go b/go/vt/wrangler/testlib/planned_reparent_shard_test.go index 24edf62800d..1dce7483370 100644 --- a/go/vt/wrangler/testlib/planned_reparent_shard_test.go +++ b/go/vt/wrangler/testlib/planned_reparent_shard_test.go @@ -281,3 +281,99 @@ func TestPlannedReparentNoMaster(t *testing.T) { t.Fatalf("PlannedReparentShard failed with the wrong error: %v", err) } } + +func TestPlannedReparentShardPromoteSlaveFail(t *testing.T) { + ts := memorytopo.NewServer("cell1", "cell2") + wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient()) + vp := NewVtctlPipe(t, ts) + defer vp.Close() + + // Create a master, a couple good slaves + oldMaster := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_MASTER, nil) + newMaster := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, nil) + goodSlave1 := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, nil) + goodSlave2 := NewFakeTablet(t, wr, "cell2", 3, topodatapb.TabletType_REPLICA, nil) + + // new master + newMaster.FakeMysqlDaemon.ReadOnly = true + newMaster.FakeMysqlDaemon.Replicating = true + newMaster.FakeMysqlDaemon.WaitMasterPosition = mysql.Position{ + GTIDSet: mysql.MariadbGTIDSet{ + mysql.MariadbGTID{ + Domain: 6, + Server: 123, + Sequence: 990, + }, + }, + } + newMaster.FakeMysqlDaemon.PromoteSlaveResult = mysql.Position{ + GTIDSet: mysql.MariadbGTIDSet{ + mysql.MariadbGTID{ + Domain: 7, + Server: 456, + Sequence: 991, + }, + }, + } + newMaster.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "CREATE DATABASE IF NOT EXISTS _vt", + "SUBCREATE TABLE IF NOT EXISTS _vt.reparent_journal", + "SUBINSERT INTO _vt.reparent_journal (time_created_ns, action_name, master_alias, replication_position) VALUES", + } + newMaster.StartActionLoop(t, wr) + defer newMaster.StopActionLoop(t) + + // old master + oldMaster.FakeMysqlDaemon.ReadOnly = false + oldMaster.FakeMysqlDaemon.Replicating = false + // to make promote fail on WaitForMasterPos + oldMaster.FakeMysqlDaemon.DemoteMasterPosition = newMaster.FakeMysqlDaemon.PromoteSlaveResult + oldMaster.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) + oldMaster.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "FAKE SET MASTER", + "START SLAVE", + } + oldMaster.StartActionLoop(t, wr) + defer oldMaster.StopActionLoop(t) + oldMaster.Agent.QueryServiceControl.(*tabletservermock.Controller).SetQueryServiceEnabledForTests(true) + + // good slave 1 is replicating + goodSlave1.FakeMysqlDaemon.ReadOnly = true + goodSlave1.FakeMysqlDaemon.Replicating = true + goodSlave1.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) + goodSlave1.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "STOP SLAVE", + "FAKE SET MASTER", + "START SLAVE", + } + goodSlave1.StartActionLoop(t, wr) + defer goodSlave1.StopActionLoop(t) + + // good slave 2 is not replicating + goodSlave2.FakeMysqlDaemon.ReadOnly = true + goodSlave2.FakeMysqlDaemon.Replicating = false + goodSlave2.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) + goodSlave2.StartActionLoop(t, wr) + goodSlave2.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "FAKE SET MASTER", + } + defer goodSlave2.StopActionLoop(t) + + // run PlannedReparentShard + err := vp.Run([]string{"PlannedReparentShard", "-wait_slave_timeout", "10s", "-keyspace_shard", newMaster.Tablet.Keyspace + "/" + newMaster.Tablet.Shard, "-new_master", topoproto.TabletAliasString(newMaster.Tablet.Alias)}) + + if err == nil { + t.Fatalf("PlannedReparentShard succeeded: %v", err) + } + if !strings.Contains(err.Error(), "master-elect tablet cell1-0000000001 failed to catch up with replication or be upgraded to master") { + t.Fatalf("PlannedReparentShard failed with the wrong error: %v", err) + } + + // now check that DemoteMaster was undone and old master is still master + if !newMaster.FakeMysqlDaemon.ReadOnly { + t.Errorf("newMaster.FakeMysqlDaemon.ReadOnly not set") + } + if oldMaster.FakeMysqlDaemon.ReadOnly { + t.Errorf("oldMaster.FakeMysqlDaemon.ReadOnly set") + } +} diff --git a/proto/tabletmanagerdata.proto b/proto/tabletmanagerdata.proto index 7606d568405..e52944035d8 100644 --- a/proto/tabletmanagerdata.proto +++ b/proto/tabletmanagerdata.proto @@ -378,6 +378,12 @@ message DemoteMasterResponse { string position = 1; } +message UndoDemoteMasterRequest { +} + +message UndoDemoteMasterResponse { +} + message PromoteSlaveWhenCaughtUpRequest { string position = 1; } diff --git a/proto/tabletmanagerservice.proto b/proto/tabletmanagerservice.proto index ebc83056d86..467f249851d 100644 --- a/proto/tabletmanagerservice.proto +++ b/proto/tabletmanagerservice.proto @@ -157,6 +157,9 @@ service TabletManager { // DemoteMaster tells the soon-to-be-former master it's gonna change rpc DemoteMaster(tabletmanagerdata.DemoteMasterRequest) returns (tabletmanagerdata.DemoteMasterResponse) {}; + // UndoDemoteMaster reverts all changes made by DemoteMaster + rpc UndoDemoteMaster(tabletmanagerdata.UndoDemoteMasterRequest) returns (tabletmanagerdata.UndoDemoteMasterResponse) {}; + // PromoteSlaveWhenCaughtUp tells the remote tablet to catch up, // and then be the master rpc PromoteSlaveWhenCaughtUp(tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest) returns (tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse) {}; diff --git a/py/vtproto/tabletmanagerdata_pb2.py b/py/vtproto/tabletmanagerdata_pb2.py index 62f4a97b3b1..bdb2701df21 100644 --- a/py/vtproto/tabletmanagerdata_pb2.py +++ b/py/vtproto/tabletmanagerdata_pb2.py @@ -7,7 +7,6 @@ from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -23,7 +22,8 @@ name='tabletmanagerdata.proto', package='tabletmanagerdata', syntax='proto3', - serialized_pb=_b('\n\x17tabletmanagerdata.proto\x12\x11tabletmanagerdata\x1a\x0bquery.proto\x1a\x0etopodata.proto\x1a\x15replicationdata.proto\x1a\rlogutil.proto\"\x93\x01\n\x0fTableDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06schema\x18\x02 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x03 \x03(\t\x12\x1b\n\x13primary_key_columns\x18\x04 \x03(\t\x12\x0c\n\x04type\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x61ta_length\x18\x06 \x01(\x04\x12\x11\n\trow_count\x18\x07 \x01(\x04\"{\n\x10SchemaDefinition\x12\x17\n\x0f\x64\x61tabase_schema\x18\x01 \x01(\t\x12=\n\x11table_definitions\x18\x02 \x03(\x0b\x32\".tabletmanagerdata.TableDefinition\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x8b\x01\n\x12SchemaChangeResult\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\xc1\x01\n\x0eUserPermission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\x12\x19\n\x11password_checksum\x18\x03 \x01(\x04\x12\x45\n\nprivileges\x18\x04 \x03(\x0b\x32\x31.tabletmanagerdata.UserPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xae\x01\n\x0c\x44\x62Permission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\n\n\x02\x64\x62\x18\x02 \x01(\t\x12\x0c\n\x04user\x18\x03 \x01(\t\x12\x43\n\nprivileges\x18\x04 \x03(\x0b\x32/.tabletmanagerdata.DbPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x83\x01\n\x0bPermissions\x12;\n\x10user_permissions\x18\x01 \x03(\x0b\x32!.tabletmanagerdata.UserPermission\x12\x37\n\x0e\x64\x62_permissions\x18\x02 \x03(\x0b\x32\x1f.tabletmanagerdata.DbPermission\"\x1e\n\x0bPingRequest\x12\x0f\n\x07payload\x18\x01 \x01(\t\"\x1f\n\x0cPingResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t\" \n\x0cSleepRequest\x12\x10\n\x08\x64uration\x18\x01 \x01(\x03\"\x0f\n\rSleepResponse\"\xaf\x01\n\x12\x45xecuteHookRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nparameters\x18\x02 \x03(\t\x12\x46\n\textra_env\x18\x03 \x03(\x0b\x32\x33.tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry\x1a/\n\rExtraEnvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"J\n\x13\x45xecuteHookResponse\x12\x13\n\x0b\x65xit_status\x18\x01 \x01(\x03\x12\x0e\n\x06stdout\x18\x02 \x01(\t\x12\x0e\n\x06stderr\x18\x03 \x01(\t\"Q\n\x10GetSchemaRequest\x12\x0e\n\x06tables\x18\x01 \x03(\t\x12\x15\n\rinclude_views\x18\x02 \x01(\x08\x12\x16\n\x0e\x65xclude_tables\x18\x03 \x03(\t\"S\n\x11GetSchemaResponse\x12>\n\x11schema_definition\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x17\n\x15GetPermissionsRequest\"M\n\x16GetPermissionsResponse\x12\x33\n\x0bpermissions\x18\x01 \x01(\x0b\x32\x1e.tabletmanagerdata.Permissions\"\x14\n\x12SetReadOnlyRequest\"\x15\n\x13SetReadOnlyResponse\"\x15\n\x13SetReadWriteRequest\"\x16\n\x14SetReadWriteResponse\">\n\x11\x43hangeTypeRequest\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\"\x14\n\x12\x43hangeTypeResponse\"\x15\n\x13RefreshStateRequest\"\x16\n\x14RefreshStateResponse\"\x17\n\x15RunHealthCheckRequest\"\x18\n\x16RunHealthCheckResponse\"+\n\x18IgnoreHealthErrorRequest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"\x1b\n\x19IgnoreHealthErrorResponse\",\n\x13ReloadSchemaRequest\x12\x15\n\rwait_position\x18\x01 \x01(\t\"\x16\n\x14ReloadSchemaResponse\")\n\x16PreflightSchemaRequest\x12\x0f\n\x07\x63hanges\x18\x01 \x03(\t\"X\n\x17PreflightSchemaResponse\x12=\n\x0e\x63hange_results\x18\x01 \x03(\x0b\x32%.tabletmanagerdata.SchemaChangeResult\"\xc2\x01\n\x12\x41pplySchemaRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12\r\n\x05\x66orce\x18\x02 \x01(\x08\x12\x19\n\x11\x61llow_replication\x18\x03 \x01(\x08\x12:\n\rbefore_schema\x18\x04 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x05 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x8c\x01\n\x13\x41pplySchemaResponse\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x13\n\x11LockTablesRequest\"\x14\n\x12LockTablesResponse\"\x15\n\x13UnlockTablesRequest\"\x16\n\x14UnlockTablesResponse\"|\n\x18\x45xecuteFetchAsDbaRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x17\n\x0f\x64isable_binlogs\x18\x04 \x01(\x08\x12\x15\n\rreload_schema\x18\x05 \x01(\x08\"?\n\x19\x45xecuteFetchAsDbaResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"h\n\x1d\x45xecuteFetchAsAllPrivsRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x15\n\rreload_schema\x18\x04 \x01(\x08\"D\n\x1e\x45xecuteFetchAsAllPrivsResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\";\n\x18\x45xecuteFetchAsAppRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x10\n\x08max_rows\x18\x02 \x01(\x04\"?\n\x19\x45xecuteFetchAsAppResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\x14\n\x12SlaveStatusRequest\">\n\x13SlaveStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x17\n\x15MasterPositionRequest\"*\n\x16MasterPositionResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x12\n\x10StopSlaveRequest\"\x13\n\x11StopSlaveResponse\"A\n\x17StopSlaveMinimumRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\",\n\x18StopSlaveMinimumResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x13\n\x11StartSlaveRequest\"\x14\n\x12StartSlaveResponse\"E\n\x1bStartSlaveUntilAfterRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\"\x1e\n\x1cStartSlaveUntilAfterResponse\"8\n!TabletExternallyReparentedRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"$\n\"TabletExternallyReparentedResponse\" \n\x1eTabletExternallyElectedRequest\"!\n\x1fTabletExternallyElectedResponse\"\x12\n\x10GetSlavesRequest\"\"\n\x11GetSlavesResponse\x12\r\n\x05\x61\x64\x64rs\x18\x01 \x03(\t\"\x19\n\x17ResetReplicationRequest\"\x1a\n\x18ResetReplicationResponse\"(\n\x17VReplicationExecRequest\x12\r\n\x05query\x18\x01 \x01(\t\">\n\x18VReplicationExecResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"=\n\x1dVReplicationWaitForPosRequest\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08position\x18\x02 \x01(\t\" \n\x1eVReplicationWaitForPosResponse\"\x13\n\x11InitMasterRequest\"&\n\x12InitMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x99\x01\n\x1ePopulateReparentJournalRequest\x12\x17\n\x0ftime_created_ns\x18\x01 \x01(\x03\x12\x13\n\x0b\x61\x63tion_name\x18\x02 \x01(\t\x12+\n\x0cmaster_alias\x18\x03 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x04 \x01(\t\"!\n\x1fPopulateReparentJournalResponse\"p\n\x10InitSlaveRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x02 \x01(\t\x12\x17\n\x0ftime_created_ns\x18\x03 \x01(\x03\"\x13\n\x11InitSlaveResponse\"\x15\n\x13\x44\x65moteMasterRequest\"(\n\x14\x44\x65moteMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"3\n\x1fPromoteSlaveWhenCaughtUpRequest\x12\x10\n\x08position\x18\x01 \x01(\t\"4\n PromoteSlaveWhenCaughtUpResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17SlaveWasPromotedRequest\"\x1a\n\x18SlaveWasPromotedResponse\"m\n\x10SetMasterRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x17\n\x0ftime_created_ns\x18\x02 \x01(\x03\x12\x19\n\x11\x66orce_start_slave\x18\x03 \x01(\x08\"\x13\n\x11SetMasterResponse\"A\n\x18SlaveWasRestartedRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"\x1b\n\x19SlaveWasRestartedResponse\"$\n\"StopReplicationAndGetStatusRequest\"N\n#StopReplicationAndGetStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x15\n\x13PromoteSlaveRequest\"(\n\x14PromoteSlaveResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"$\n\rBackupRequest\x12\x13\n\x0b\x63oncurrency\x18\x01 \x01(\x03\"/\n\x0e\x42\x61\x63kupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.Event\"\x1a\n\x18RestoreFromBackupRequest\":\n\x19RestoreFromBackupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.EventB0Z.vitess.io/vitess/go/vt/proto/tabletmanagerdatab\x06proto3') + serialized_options=_b('Z.vitess.io/vitess/go/vt/proto/tabletmanagerdata'), + serialized_pb=_b('\n\x17tabletmanagerdata.proto\x12\x11tabletmanagerdata\x1a\x0bquery.proto\x1a\x0etopodata.proto\x1a\x15replicationdata.proto\x1a\rlogutil.proto\"\x93\x01\n\x0fTableDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06schema\x18\x02 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x03 \x03(\t\x12\x1b\n\x13primary_key_columns\x18\x04 \x03(\t\x12\x0c\n\x04type\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x61ta_length\x18\x06 \x01(\x04\x12\x11\n\trow_count\x18\x07 \x01(\x04\"{\n\x10SchemaDefinition\x12\x17\n\x0f\x64\x61tabase_schema\x18\x01 \x01(\t\x12=\n\x11table_definitions\x18\x02 \x03(\x0b\x32\".tabletmanagerdata.TableDefinition\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x8b\x01\n\x12SchemaChangeResult\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\xc1\x01\n\x0eUserPermission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\x12\x19\n\x11password_checksum\x18\x03 \x01(\x04\x12\x45\n\nprivileges\x18\x04 \x03(\x0b\x32\x31.tabletmanagerdata.UserPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xae\x01\n\x0c\x44\x62Permission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\n\n\x02\x64\x62\x18\x02 \x01(\t\x12\x0c\n\x04user\x18\x03 \x01(\t\x12\x43\n\nprivileges\x18\x04 \x03(\x0b\x32/.tabletmanagerdata.DbPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x83\x01\n\x0bPermissions\x12;\n\x10user_permissions\x18\x01 \x03(\x0b\x32!.tabletmanagerdata.UserPermission\x12\x37\n\x0e\x64\x62_permissions\x18\x02 \x03(\x0b\x32\x1f.tabletmanagerdata.DbPermission\"\x1e\n\x0bPingRequest\x12\x0f\n\x07payload\x18\x01 \x01(\t\"\x1f\n\x0cPingResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t\" \n\x0cSleepRequest\x12\x10\n\x08\x64uration\x18\x01 \x01(\x03\"\x0f\n\rSleepResponse\"\xaf\x01\n\x12\x45xecuteHookRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nparameters\x18\x02 \x03(\t\x12\x46\n\textra_env\x18\x03 \x03(\x0b\x32\x33.tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry\x1a/\n\rExtraEnvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"J\n\x13\x45xecuteHookResponse\x12\x13\n\x0b\x65xit_status\x18\x01 \x01(\x03\x12\x0e\n\x06stdout\x18\x02 \x01(\t\x12\x0e\n\x06stderr\x18\x03 \x01(\t\"Q\n\x10GetSchemaRequest\x12\x0e\n\x06tables\x18\x01 \x03(\t\x12\x15\n\rinclude_views\x18\x02 \x01(\x08\x12\x16\n\x0e\x65xclude_tables\x18\x03 \x03(\t\"S\n\x11GetSchemaResponse\x12>\n\x11schema_definition\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x17\n\x15GetPermissionsRequest\"M\n\x16GetPermissionsResponse\x12\x33\n\x0bpermissions\x18\x01 \x01(\x0b\x32\x1e.tabletmanagerdata.Permissions\"\x14\n\x12SetReadOnlyRequest\"\x15\n\x13SetReadOnlyResponse\"\x15\n\x13SetReadWriteRequest\"\x16\n\x14SetReadWriteResponse\">\n\x11\x43hangeTypeRequest\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\"\x14\n\x12\x43hangeTypeResponse\"\x15\n\x13RefreshStateRequest\"\x16\n\x14RefreshStateResponse\"\x17\n\x15RunHealthCheckRequest\"\x18\n\x16RunHealthCheckResponse\"+\n\x18IgnoreHealthErrorRequest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"\x1b\n\x19IgnoreHealthErrorResponse\",\n\x13ReloadSchemaRequest\x12\x15\n\rwait_position\x18\x01 \x01(\t\"\x16\n\x14ReloadSchemaResponse\")\n\x16PreflightSchemaRequest\x12\x0f\n\x07\x63hanges\x18\x01 \x03(\t\"X\n\x17PreflightSchemaResponse\x12=\n\x0e\x63hange_results\x18\x01 \x03(\x0b\x32%.tabletmanagerdata.SchemaChangeResult\"\xc2\x01\n\x12\x41pplySchemaRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12\r\n\x05\x66orce\x18\x02 \x01(\x08\x12\x19\n\x11\x61llow_replication\x18\x03 \x01(\x08\x12:\n\rbefore_schema\x18\x04 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x05 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x8c\x01\n\x13\x41pplySchemaResponse\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x13\n\x11LockTablesRequest\"\x14\n\x12LockTablesResponse\"\x15\n\x13UnlockTablesRequest\"\x16\n\x14UnlockTablesResponse\"|\n\x18\x45xecuteFetchAsDbaRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x17\n\x0f\x64isable_binlogs\x18\x04 \x01(\x08\x12\x15\n\rreload_schema\x18\x05 \x01(\x08\"?\n\x19\x45xecuteFetchAsDbaResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"h\n\x1d\x45xecuteFetchAsAllPrivsRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x15\n\rreload_schema\x18\x04 \x01(\x08\"D\n\x1e\x45xecuteFetchAsAllPrivsResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\";\n\x18\x45xecuteFetchAsAppRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x10\n\x08max_rows\x18\x02 \x01(\x04\"?\n\x19\x45xecuteFetchAsAppResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\x14\n\x12SlaveStatusRequest\">\n\x13SlaveStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x17\n\x15MasterPositionRequest\"*\n\x16MasterPositionResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x12\n\x10StopSlaveRequest\"\x13\n\x11StopSlaveResponse\"A\n\x17StopSlaveMinimumRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\",\n\x18StopSlaveMinimumResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x13\n\x11StartSlaveRequest\"\x14\n\x12StartSlaveResponse\"E\n\x1bStartSlaveUntilAfterRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\"\x1e\n\x1cStartSlaveUntilAfterResponse\"8\n!TabletExternallyReparentedRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"$\n\"TabletExternallyReparentedResponse\" \n\x1eTabletExternallyElectedRequest\"!\n\x1fTabletExternallyElectedResponse\"\x12\n\x10GetSlavesRequest\"\"\n\x11GetSlavesResponse\x12\r\n\x05\x61\x64\x64rs\x18\x01 \x03(\t\"\x19\n\x17ResetReplicationRequest\"\x1a\n\x18ResetReplicationResponse\"(\n\x17VReplicationExecRequest\x12\r\n\x05query\x18\x01 \x01(\t\">\n\x18VReplicationExecResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"=\n\x1dVReplicationWaitForPosRequest\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08position\x18\x02 \x01(\t\" \n\x1eVReplicationWaitForPosResponse\"\x13\n\x11InitMasterRequest\"&\n\x12InitMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x99\x01\n\x1ePopulateReparentJournalRequest\x12\x17\n\x0ftime_created_ns\x18\x01 \x01(\x03\x12\x13\n\x0b\x61\x63tion_name\x18\x02 \x01(\t\x12+\n\x0cmaster_alias\x18\x03 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x04 \x01(\t\"!\n\x1fPopulateReparentJournalResponse\"p\n\x10InitSlaveRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x02 \x01(\t\x12\x17\n\x0ftime_created_ns\x18\x03 \x01(\x03\"\x13\n\x11InitSlaveResponse\"\x15\n\x13\x44\x65moteMasterRequest\"(\n\x14\x44\x65moteMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17UndoDemoteMasterRequest\"\x1a\n\x18UndoDemoteMasterResponse\"3\n\x1fPromoteSlaveWhenCaughtUpRequest\x12\x10\n\x08position\x18\x01 \x01(\t\"4\n PromoteSlaveWhenCaughtUpResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17SlaveWasPromotedRequest\"\x1a\n\x18SlaveWasPromotedResponse\"m\n\x10SetMasterRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x17\n\x0ftime_created_ns\x18\x02 \x01(\x03\x12\x19\n\x11\x66orce_start_slave\x18\x03 \x01(\x08\"\x13\n\x11SetMasterResponse\"A\n\x18SlaveWasRestartedRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"\x1b\n\x19SlaveWasRestartedResponse\"$\n\"StopReplicationAndGetStatusRequest\"N\n#StopReplicationAndGetStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x15\n\x13PromoteSlaveRequest\"(\n\x14PromoteSlaveResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"$\n\rBackupRequest\x12\x13\n\x0b\x63oncurrency\x18\x01 \x01(\x03\"/\n\x0e\x42\x61\x63kupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.Event\"\x1a\n\x18RestoreFromBackupRequest\":\n\x19RestoreFromBackupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.EventB0Z.vitess.io/vitess/go/vt/proto/tabletmanagerdatab\x06proto3') , dependencies=[query__pb2.DESCRIPTOR,topodata__pb2.DESCRIPTOR,replicationdata__pb2.DESCRIPTOR,logutil__pb2.DESCRIPTOR,]) @@ -43,56 +43,56 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='schema', full_name='tabletmanagerdata.TableDefinition.schema', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='columns', full_name='tabletmanagerdata.TableDefinition.columns', index=2, number=3, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='primary_key_columns', full_name='tabletmanagerdata.TableDefinition.primary_key_columns', index=3, number=4, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='type', full_name='tabletmanagerdata.TableDefinition.type', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='data_length', full_name='tabletmanagerdata.TableDefinition.data_length', index=5, number=6, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='row_count', full_name='tabletmanagerdata.TableDefinition.row_count', index=6, number=7, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -116,28 +116,28 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='table_definitions', full_name='tabletmanagerdata.SchemaDefinition.table_definitions', index=1, number=2, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='version', full_name='tabletmanagerdata.SchemaDefinition.version', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -161,21 +161,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='after_schema', full_name='tabletmanagerdata.SchemaChangeResult.after_schema', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -199,21 +199,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='tabletmanagerdata.UserPermission.PrivilegesEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], @@ -236,35 +236,35 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='user', full_name='tabletmanagerdata.UserPermission.user', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='password_checksum', full_name='tabletmanagerdata.UserPermission.password_checksum', index=2, number=3, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='privileges', full_name='tabletmanagerdata.UserPermission.privileges', index=3, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[_USERPERMISSION_PRIVILEGESENTRY, ], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -288,21 +288,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='tabletmanagerdata.DbPermission.PrivilegesEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], @@ -325,35 +325,35 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='db', full_name='tabletmanagerdata.DbPermission.db', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='user', full_name='tabletmanagerdata.DbPermission.user', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='privileges', full_name='tabletmanagerdata.DbPermission.privileges', index=3, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[_DBPERMISSION_PRIVILEGESENTRY, ], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -377,21 +377,21 @@ has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='db_permissions', full_name='tabletmanagerdata.Permissions.db_permissions', index=1, number=2, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -415,14 +415,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -446,14 +446,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -477,14 +477,14 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -508,7 +508,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -532,21 +532,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry.value', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=_descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')), + serialized_options=_b('8\001'), is_extendable=False, syntax='proto3', extension_ranges=[], @@ -569,28 +569,28 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='parameters', full_name='tabletmanagerdata.ExecuteHookRequest.parameters', index=1, number=2, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='extra_env', full_name='tabletmanagerdata.ExecuteHookRequest.extra_env', index=2, number=3, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[_EXECUTEHOOKREQUEST_EXTRAENVENTRY, ], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -614,28 +614,28 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='stdout', full_name='tabletmanagerdata.ExecuteHookResponse.stdout', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='stderr', full_name='tabletmanagerdata.ExecuteHookResponse.stderr', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -659,28 +659,28 @@ has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='include_views', full_name='tabletmanagerdata.GetSchemaRequest.include_views', index=1, number=2, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='exclude_tables', full_name='tabletmanagerdata.GetSchemaRequest.exclude_tables', index=2, number=3, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -704,14 +704,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -735,7 +735,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -759,14 +759,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -790,7 +790,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -814,7 +814,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -838,7 +838,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -862,7 +862,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -886,14 +886,14 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -917,7 +917,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -941,7 +941,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -965,7 +965,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -989,7 +989,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1013,7 +1013,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1037,14 +1037,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1068,7 +1068,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1092,14 +1092,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1123,7 +1123,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1147,14 +1147,14 @@ has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1178,14 +1178,14 @@ has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1209,42 +1209,42 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='force', full_name='tabletmanagerdata.ApplySchemaRequest.force', index=1, number=2, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='allow_replication', full_name='tabletmanagerdata.ApplySchemaRequest.allow_replication', index=2, number=3, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='before_schema', full_name='tabletmanagerdata.ApplySchemaRequest.before_schema', index=3, number=4, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='after_schema', full_name='tabletmanagerdata.ApplySchemaRequest.after_schema', index=4, number=5, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1268,21 +1268,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='after_schema', full_name='tabletmanagerdata.ApplySchemaResponse.after_schema', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1306,7 +1306,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1330,7 +1330,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1354,7 +1354,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1378,7 +1378,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1402,42 +1402,42 @@ has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='db_name', full_name='tabletmanagerdata.ExecuteFetchAsDbaRequest.db_name', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='max_rows', full_name='tabletmanagerdata.ExecuteFetchAsDbaRequest.max_rows', index=2, number=3, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='disable_binlogs', full_name='tabletmanagerdata.ExecuteFetchAsDbaRequest.disable_binlogs', index=3, number=4, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='reload_schema', full_name='tabletmanagerdata.ExecuteFetchAsDbaRequest.reload_schema', index=4, number=5, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1461,14 +1461,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1492,35 +1492,35 @@ has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='db_name', full_name='tabletmanagerdata.ExecuteFetchAsAllPrivsRequest.db_name', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='max_rows', full_name='tabletmanagerdata.ExecuteFetchAsAllPrivsRequest.max_rows', index=2, number=3, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='reload_schema', full_name='tabletmanagerdata.ExecuteFetchAsAllPrivsRequest.reload_schema', index=3, number=4, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1544,14 +1544,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1575,21 +1575,21 @@ has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='max_rows', full_name='tabletmanagerdata.ExecuteFetchAsAppRequest.max_rows', index=1, number=2, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1613,14 +1613,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1644,7 +1644,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1668,14 +1668,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1699,7 +1699,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1723,14 +1723,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1754,7 +1754,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1778,7 +1778,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1802,21 +1802,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='wait_timeout', full_name='tabletmanagerdata.StopSlaveMinimumRequest.wait_timeout', index=1, number=2, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1840,14 +1840,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1871,7 +1871,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1895,7 +1895,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1919,21 +1919,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='wait_timeout', full_name='tabletmanagerdata.StartSlaveUntilAfterRequest.wait_timeout', index=1, number=2, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1957,7 +1957,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1981,14 +1981,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2012,7 +2012,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2036,7 +2036,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2060,7 +2060,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2084,7 +2084,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2108,14 +2108,14 @@ has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2139,7 +2139,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2163,7 +2163,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2187,14 +2187,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2218,14 +2218,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2249,21 +2249,21 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='position', full_name='tabletmanagerdata.VReplicationWaitForPosRequest.position', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2287,7 +2287,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2311,7 +2311,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2335,14 +2335,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2366,35 +2366,35 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='action_name', full_name='tabletmanagerdata.PopulateReparentJournalRequest.action_name', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='master_alias', full_name='tabletmanagerdata.PopulateReparentJournalRequest.master_alias', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='replication_position', full_name='tabletmanagerdata.PopulateReparentJournalRequest.replication_position', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2418,7 +2418,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2442,28 +2442,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='replication_position', full_name='tabletmanagerdata.InitSlaveRequest.replication_position', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='time_created_ns', full_name='tabletmanagerdata.InitSlaveRequest.time_created_ns', index=2, number=3, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2487,7 +2487,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2511,7 +2511,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2535,14 +2535,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2553,6 +2553,54 @@ ) +_UNDODEMOTEMASTERREQUEST = _descriptor.Descriptor( + name='UndoDemoteMasterRequest', + full_name='tabletmanagerdata.UndoDemoteMasterRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4541, + serialized_end=4566, +) + + +_UNDODEMOTEMASTERRESPONSE = _descriptor.Descriptor( + name='UndoDemoteMasterResponse', + full_name='tabletmanagerdata.UndoDemoteMasterResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4568, + serialized_end=4594, +) + + _PROMOTESLAVEWHENCAUGHTUPREQUEST = _descriptor.Descriptor( name='PromoteSlaveWhenCaughtUpRequest', full_name='tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest', @@ -2566,21 +2614,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4541, - serialized_end=4592, + serialized_start=4596, + serialized_end=4647, ) @@ -2597,21 +2645,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4594, - serialized_end=4646, + serialized_start=4649, + serialized_end=4701, ) @@ -2628,14 +2676,14 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4648, - serialized_end=4673, + serialized_start=4703, + serialized_end=4728, ) @@ -2652,14 +2700,14 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4675, - serialized_end=4701, + serialized_start=4730, + serialized_end=4756, ) @@ -2676,35 +2724,35 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='time_created_ns', full_name='tabletmanagerdata.SetMasterRequest.time_created_ns', index=1, number=2, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='force_start_slave', full_name='tabletmanagerdata.SetMasterRequest.force_start_slave', index=2, number=3, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4703, - serialized_end=4812, + serialized_start=4758, + serialized_end=4867, ) @@ -2721,14 +2769,14 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4814, - serialized_end=4833, + serialized_start=4869, + serialized_end=4888, ) @@ -2745,21 +2793,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4835, - serialized_end=4900, + serialized_start=4890, + serialized_end=4955, ) @@ -2776,14 +2824,14 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4902, - serialized_end=4929, + serialized_start=4957, + serialized_end=4984, ) @@ -2800,14 +2848,14 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4931, - serialized_end=4967, + serialized_start=4986, + serialized_end=5022, ) @@ -2824,21 +2872,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=4969, - serialized_end=5047, + serialized_start=5024, + serialized_end=5102, ) @@ -2855,14 +2903,14 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=5049, - serialized_end=5070, + serialized_start=5104, + serialized_end=5125, ) @@ -2879,21 +2927,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=5072, - serialized_end=5112, + serialized_start=5127, + serialized_end=5167, ) @@ -2910,21 +2958,21 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=5114, - serialized_end=5150, + serialized_start=5169, + serialized_end=5205, ) @@ -2941,21 +2989,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=5152, - serialized_end=5199, + serialized_start=5207, + serialized_end=5254, ) @@ -2972,14 +3020,14 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=5201, - serialized_end=5227, + serialized_start=5256, + serialized_end=5282, ) @@ -2996,21 +3044,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], oneofs=[ ], - serialized_start=5229, - serialized_end=5287, + serialized_start=5284, + serialized_end=5342, ) _SCHEMADEFINITION.fields_by_name['table_definitions'].message_type = _TABLEDEFINITION @@ -3120,6 +3168,8 @@ DESCRIPTOR.message_types_by_name['InitSlaveResponse'] = _INITSLAVERESPONSE DESCRIPTOR.message_types_by_name['DemoteMasterRequest'] = _DEMOTEMASTERREQUEST DESCRIPTOR.message_types_by_name['DemoteMasterResponse'] = _DEMOTEMASTERRESPONSE +DESCRIPTOR.message_types_by_name['UndoDemoteMasterRequest'] = _UNDODEMOTEMASTERREQUEST +DESCRIPTOR.message_types_by_name['UndoDemoteMasterResponse'] = _UNDODEMOTEMASTERRESPONSE DESCRIPTOR.message_types_by_name['PromoteSlaveWhenCaughtUpRequest'] = _PROMOTESLAVEWHENCAUGHTUPREQUEST DESCRIPTOR.message_types_by_name['PromoteSlaveWhenCaughtUpResponse'] = _PROMOTESLAVEWHENCAUGHTUPRESPONSE DESCRIPTOR.message_types_by_name['SlaveWasPromotedRequest'] = _SLAVEWASPROMOTEDREQUEST @@ -3694,6 +3744,20 @@ )) _sym_db.RegisterMessage(DemoteMasterResponse) +UndoDemoteMasterRequest = _reflection.GeneratedProtocolMessageType('UndoDemoteMasterRequest', (_message.Message,), dict( + DESCRIPTOR = _UNDODEMOTEMASTERREQUEST, + __module__ = 'tabletmanagerdata_pb2' + # @@protoc_insertion_point(class_scope:tabletmanagerdata.UndoDemoteMasterRequest) + )) +_sym_db.RegisterMessage(UndoDemoteMasterRequest) + +UndoDemoteMasterResponse = _reflection.GeneratedProtocolMessageType('UndoDemoteMasterResponse', (_message.Message,), dict( + DESCRIPTOR = _UNDODEMOTEMASTERRESPONSE, + __module__ = 'tabletmanagerdata_pb2' + # @@protoc_insertion_point(class_scope:tabletmanagerdata.UndoDemoteMasterResponse) + )) +_sym_db.RegisterMessage(UndoDemoteMasterResponse) + PromoteSlaveWhenCaughtUpRequest = _reflection.GeneratedProtocolMessageType('PromoteSlaveWhenCaughtUpRequest', (_message.Message,), dict( DESCRIPTOR = _PROMOTESLAVEWHENCAUGHTUPREQUEST, __module__ = 'tabletmanagerdata_pb2' @@ -3807,12 +3871,8 @@ _sym_db.RegisterMessage(RestoreFromBackupResponse) -DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('Z.vitess.io/vitess/go/vt/proto/tabletmanagerdata')) -_USERPERMISSION_PRIVILEGESENTRY.has_options = True -_USERPERMISSION_PRIVILEGESENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) -_DBPERMISSION_PRIVILEGESENTRY.has_options = True -_DBPERMISSION_PRIVILEGESENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) -_EXECUTEHOOKREQUEST_EXTRAENVENTRY.has_options = True -_EXECUTEHOOKREQUEST_EXTRAENVENTRY._options = _descriptor._ParseOptions(descriptor_pb2.MessageOptions(), _b('8\001')) +DESCRIPTOR._options = None +_USERPERMISSION_PRIVILEGESENTRY._options = None +_DBPERMISSION_PRIVILEGESENTRY._options = None +_EXECUTEHOOKREQUEST_EXTRAENVENTRY._options = None # @@protoc_insertion_point(module_scope) diff --git a/py/vtproto/tabletmanagerservice_pb2.py b/py/vtproto/tabletmanagerservice_pb2.py index 33d62d43bdc..d9f607b5ada 100644 --- a/py/vtproto/tabletmanagerservice_pb2.py +++ b/py/vtproto/tabletmanagerservice_pb2.py @@ -7,7 +7,6 @@ from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -20,7 +19,8 @@ name='tabletmanagerservice.proto', package='tabletmanagerservice', syntax='proto3', - serialized_pb=_b('\n\x1atabletmanagerservice.proto\x12\x14tabletmanagerservice\x1a\x17tabletmanagerdata.proto2\xd0#\n\rTabletManager\x12I\n\x04Ping\x12\x1e.tabletmanagerdata.PingRequest\x1a\x1f.tabletmanagerdata.PingResponse\"\x00\x12L\n\x05Sleep\x12\x1f.tabletmanagerdata.SleepRequest\x1a .tabletmanagerdata.SleepResponse\"\x00\x12^\n\x0b\x45xecuteHook\x12%.tabletmanagerdata.ExecuteHookRequest\x1a&.tabletmanagerdata.ExecuteHookResponse\"\x00\x12X\n\tGetSchema\x12#.tabletmanagerdata.GetSchemaRequest\x1a$.tabletmanagerdata.GetSchemaResponse\"\x00\x12g\n\x0eGetPermissions\x12(.tabletmanagerdata.GetPermissionsRequest\x1a).tabletmanagerdata.GetPermissionsResponse\"\x00\x12^\n\x0bSetReadOnly\x12%.tabletmanagerdata.SetReadOnlyRequest\x1a&.tabletmanagerdata.SetReadOnlyResponse\"\x00\x12\x61\n\x0cSetReadWrite\x12&.tabletmanagerdata.SetReadWriteRequest\x1a\'.tabletmanagerdata.SetReadWriteResponse\"\x00\x12[\n\nChangeType\x12$.tabletmanagerdata.ChangeTypeRequest\x1a%.tabletmanagerdata.ChangeTypeResponse\"\x00\x12\x61\n\x0cRefreshState\x12&.tabletmanagerdata.RefreshStateRequest\x1a\'.tabletmanagerdata.RefreshStateResponse\"\x00\x12g\n\x0eRunHealthCheck\x12(.tabletmanagerdata.RunHealthCheckRequest\x1a).tabletmanagerdata.RunHealthCheckResponse\"\x00\x12p\n\x11IgnoreHealthError\x12+.tabletmanagerdata.IgnoreHealthErrorRequest\x1a,.tabletmanagerdata.IgnoreHealthErrorResponse\"\x00\x12\x61\n\x0cReloadSchema\x12&.tabletmanagerdata.ReloadSchemaRequest\x1a\'.tabletmanagerdata.ReloadSchemaResponse\"\x00\x12j\n\x0fPreflightSchema\x12).tabletmanagerdata.PreflightSchemaRequest\x1a*.tabletmanagerdata.PreflightSchemaResponse\"\x00\x12^\n\x0b\x41pplySchema\x12%.tabletmanagerdata.ApplySchemaRequest\x1a&.tabletmanagerdata.ApplySchemaResponse\"\x00\x12[\n\nLockTables\x12$.tabletmanagerdata.LockTablesRequest\x1a%.tabletmanagerdata.LockTablesResponse\"\x00\x12\x61\n\x0cUnlockTables\x12&.tabletmanagerdata.UnlockTablesRequest\x1a\'.tabletmanagerdata.UnlockTablesResponse\"\x00\x12p\n\x11\x45xecuteFetchAsDba\x12+.tabletmanagerdata.ExecuteFetchAsDbaRequest\x1a,.tabletmanagerdata.ExecuteFetchAsDbaResponse\"\x00\x12\x7f\n\x16\x45xecuteFetchAsAllPrivs\x12\x30.tabletmanagerdata.ExecuteFetchAsAllPrivsRequest\x1a\x31.tabletmanagerdata.ExecuteFetchAsAllPrivsResponse\"\x00\x12p\n\x11\x45xecuteFetchAsApp\x12+.tabletmanagerdata.ExecuteFetchAsAppRequest\x1a,.tabletmanagerdata.ExecuteFetchAsAppResponse\"\x00\x12^\n\x0bSlaveStatus\x12%.tabletmanagerdata.SlaveStatusRequest\x1a&.tabletmanagerdata.SlaveStatusResponse\"\x00\x12g\n\x0eMasterPosition\x12(.tabletmanagerdata.MasterPositionRequest\x1a).tabletmanagerdata.MasterPositionResponse\"\x00\x12X\n\tStopSlave\x12#.tabletmanagerdata.StopSlaveRequest\x1a$.tabletmanagerdata.StopSlaveResponse\"\x00\x12m\n\x10StopSlaveMinimum\x12*.tabletmanagerdata.StopSlaveMinimumRequest\x1a+.tabletmanagerdata.StopSlaveMinimumResponse\"\x00\x12[\n\nStartSlave\x12$.tabletmanagerdata.StartSlaveRequest\x1a%.tabletmanagerdata.StartSlaveResponse\"\x00\x12y\n\x14StartSlaveUntilAfter\x12..tabletmanagerdata.StartSlaveUntilAfterRequest\x1a/.tabletmanagerdata.StartSlaveUntilAfterResponse\"\x00\x12\x8b\x01\n\x1aTabletExternallyReparented\x12\x34.tabletmanagerdata.TabletExternallyReparentedRequest\x1a\x35.tabletmanagerdata.TabletExternallyReparentedResponse\"\x00\x12\x82\x01\n\x17TabletExternallyElected\x12\x31.tabletmanagerdata.TabletExternallyElectedRequest\x1a\x32.tabletmanagerdata.TabletExternallyElectedResponse\"\x00\x12X\n\tGetSlaves\x12#.tabletmanagerdata.GetSlavesRequest\x1a$.tabletmanagerdata.GetSlavesResponse\"\x00\x12m\n\x10VReplicationExec\x12*.tabletmanagerdata.VReplicationExecRequest\x1a+.tabletmanagerdata.VReplicationExecResponse\"\x00\x12\x7f\n\x16VReplicationWaitForPos\x12\x30.tabletmanagerdata.VReplicationWaitForPosRequest\x1a\x31.tabletmanagerdata.VReplicationWaitForPosResponse\"\x00\x12m\n\x10ResetReplication\x12*.tabletmanagerdata.ResetReplicationRequest\x1a+.tabletmanagerdata.ResetReplicationResponse\"\x00\x12[\n\nInitMaster\x12$.tabletmanagerdata.InitMasterRequest\x1a%.tabletmanagerdata.InitMasterResponse\"\x00\x12\x82\x01\n\x17PopulateReparentJournal\x12\x31.tabletmanagerdata.PopulateReparentJournalRequest\x1a\x32.tabletmanagerdata.PopulateReparentJournalResponse\"\x00\x12X\n\tInitSlave\x12#.tabletmanagerdata.InitSlaveRequest\x1a$.tabletmanagerdata.InitSlaveResponse\"\x00\x12\x61\n\x0c\x44\x65moteMaster\x12&.tabletmanagerdata.DemoteMasterRequest\x1a\'.tabletmanagerdata.DemoteMasterResponse\"\x00\x12\x85\x01\n\x18PromoteSlaveWhenCaughtUp\x12\x32.tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest\x1a\x33.tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse\"\x00\x12m\n\x10SlaveWasPromoted\x12*.tabletmanagerdata.SlaveWasPromotedRequest\x1a+.tabletmanagerdata.SlaveWasPromotedResponse\"\x00\x12X\n\tSetMaster\x12#.tabletmanagerdata.SetMasterRequest\x1a$.tabletmanagerdata.SetMasterResponse\"\x00\x12p\n\x11SlaveWasRestarted\x12+.tabletmanagerdata.SlaveWasRestartedRequest\x1a,.tabletmanagerdata.SlaveWasRestartedResponse\"\x00\x12\x8e\x01\n\x1bStopReplicationAndGetStatus\x12\x35.tabletmanagerdata.StopReplicationAndGetStatusRequest\x1a\x36.tabletmanagerdata.StopReplicationAndGetStatusResponse\"\x00\x12\x61\n\x0cPromoteSlave\x12&.tabletmanagerdata.PromoteSlaveRequest\x1a\'.tabletmanagerdata.PromoteSlaveResponse\"\x00\x12Q\n\x06\x42\x61\x63kup\x12 .tabletmanagerdata.BackupRequest\x1a!.tabletmanagerdata.BackupResponse\"\x00\x30\x01\x12r\n\x11RestoreFromBackup\x12+.tabletmanagerdata.RestoreFromBackupRequest\x1a,.tabletmanagerdata.RestoreFromBackupResponse\"\x00\x30\x01\x42\x33Z1vitess.io/vitess/go/vt/proto/tabletmanagerserviceb\x06proto3') + serialized_options=_b('Z1vitess.io/vitess/go/vt/proto/tabletmanagerservice'), + serialized_pb=_b('\n\x1atabletmanagerservice.proto\x12\x14tabletmanagerservice\x1a\x17tabletmanagerdata.proto2\xbf$\n\rTabletManager\x12I\n\x04Ping\x12\x1e.tabletmanagerdata.PingRequest\x1a\x1f.tabletmanagerdata.PingResponse\"\x00\x12L\n\x05Sleep\x12\x1f.tabletmanagerdata.SleepRequest\x1a .tabletmanagerdata.SleepResponse\"\x00\x12^\n\x0b\x45xecuteHook\x12%.tabletmanagerdata.ExecuteHookRequest\x1a&.tabletmanagerdata.ExecuteHookResponse\"\x00\x12X\n\tGetSchema\x12#.tabletmanagerdata.GetSchemaRequest\x1a$.tabletmanagerdata.GetSchemaResponse\"\x00\x12g\n\x0eGetPermissions\x12(.tabletmanagerdata.GetPermissionsRequest\x1a).tabletmanagerdata.GetPermissionsResponse\"\x00\x12^\n\x0bSetReadOnly\x12%.tabletmanagerdata.SetReadOnlyRequest\x1a&.tabletmanagerdata.SetReadOnlyResponse\"\x00\x12\x61\n\x0cSetReadWrite\x12&.tabletmanagerdata.SetReadWriteRequest\x1a\'.tabletmanagerdata.SetReadWriteResponse\"\x00\x12[\n\nChangeType\x12$.tabletmanagerdata.ChangeTypeRequest\x1a%.tabletmanagerdata.ChangeTypeResponse\"\x00\x12\x61\n\x0cRefreshState\x12&.tabletmanagerdata.RefreshStateRequest\x1a\'.tabletmanagerdata.RefreshStateResponse\"\x00\x12g\n\x0eRunHealthCheck\x12(.tabletmanagerdata.RunHealthCheckRequest\x1a).tabletmanagerdata.RunHealthCheckResponse\"\x00\x12p\n\x11IgnoreHealthError\x12+.tabletmanagerdata.IgnoreHealthErrorRequest\x1a,.tabletmanagerdata.IgnoreHealthErrorResponse\"\x00\x12\x61\n\x0cReloadSchema\x12&.tabletmanagerdata.ReloadSchemaRequest\x1a\'.tabletmanagerdata.ReloadSchemaResponse\"\x00\x12j\n\x0fPreflightSchema\x12).tabletmanagerdata.PreflightSchemaRequest\x1a*.tabletmanagerdata.PreflightSchemaResponse\"\x00\x12^\n\x0b\x41pplySchema\x12%.tabletmanagerdata.ApplySchemaRequest\x1a&.tabletmanagerdata.ApplySchemaResponse\"\x00\x12[\n\nLockTables\x12$.tabletmanagerdata.LockTablesRequest\x1a%.tabletmanagerdata.LockTablesResponse\"\x00\x12\x61\n\x0cUnlockTables\x12&.tabletmanagerdata.UnlockTablesRequest\x1a\'.tabletmanagerdata.UnlockTablesResponse\"\x00\x12p\n\x11\x45xecuteFetchAsDba\x12+.tabletmanagerdata.ExecuteFetchAsDbaRequest\x1a,.tabletmanagerdata.ExecuteFetchAsDbaResponse\"\x00\x12\x7f\n\x16\x45xecuteFetchAsAllPrivs\x12\x30.tabletmanagerdata.ExecuteFetchAsAllPrivsRequest\x1a\x31.tabletmanagerdata.ExecuteFetchAsAllPrivsResponse\"\x00\x12p\n\x11\x45xecuteFetchAsApp\x12+.tabletmanagerdata.ExecuteFetchAsAppRequest\x1a,.tabletmanagerdata.ExecuteFetchAsAppResponse\"\x00\x12^\n\x0bSlaveStatus\x12%.tabletmanagerdata.SlaveStatusRequest\x1a&.tabletmanagerdata.SlaveStatusResponse\"\x00\x12g\n\x0eMasterPosition\x12(.tabletmanagerdata.MasterPositionRequest\x1a).tabletmanagerdata.MasterPositionResponse\"\x00\x12X\n\tStopSlave\x12#.tabletmanagerdata.StopSlaveRequest\x1a$.tabletmanagerdata.StopSlaveResponse\"\x00\x12m\n\x10StopSlaveMinimum\x12*.tabletmanagerdata.StopSlaveMinimumRequest\x1a+.tabletmanagerdata.StopSlaveMinimumResponse\"\x00\x12[\n\nStartSlave\x12$.tabletmanagerdata.StartSlaveRequest\x1a%.tabletmanagerdata.StartSlaveResponse\"\x00\x12y\n\x14StartSlaveUntilAfter\x12..tabletmanagerdata.StartSlaveUntilAfterRequest\x1a/.tabletmanagerdata.StartSlaveUntilAfterResponse\"\x00\x12\x8b\x01\n\x1aTabletExternallyReparented\x12\x34.tabletmanagerdata.TabletExternallyReparentedRequest\x1a\x35.tabletmanagerdata.TabletExternallyReparentedResponse\"\x00\x12\x82\x01\n\x17TabletExternallyElected\x12\x31.tabletmanagerdata.TabletExternallyElectedRequest\x1a\x32.tabletmanagerdata.TabletExternallyElectedResponse\"\x00\x12X\n\tGetSlaves\x12#.tabletmanagerdata.GetSlavesRequest\x1a$.tabletmanagerdata.GetSlavesResponse\"\x00\x12m\n\x10VReplicationExec\x12*.tabletmanagerdata.VReplicationExecRequest\x1a+.tabletmanagerdata.VReplicationExecResponse\"\x00\x12\x7f\n\x16VReplicationWaitForPos\x12\x30.tabletmanagerdata.VReplicationWaitForPosRequest\x1a\x31.tabletmanagerdata.VReplicationWaitForPosResponse\"\x00\x12m\n\x10ResetReplication\x12*.tabletmanagerdata.ResetReplicationRequest\x1a+.tabletmanagerdata.ResetReplicationResponse\"\x00\x12[\n\nInitMaster\x12$.tabletmanagerdata.InitMasterRequest\x1a%.tabletmanagerdata.InitMasterResponse\"\x00\x12\x82\x01\n\x17PopulateReparentJournal\x12\x31.tabletmanagerdata.PopulateReparentJournalRequest\x1a\x32.tabletmanagerdata.PopulateReparentJournalResponse\"\x00\x12X\n\tInitSlave\x12#.tabletmanagerdata.InitSlaveRequest\x1a$.tabletmanagerdata.InitSlaveResponse\"\x00\x12\x61\n\x0c\x44\x65moteMaster\x12&.tabletmanagerdata.DemoteMasterRequest\x1a\'.tabletmanagerdata.DemoteMasterResponse\"\x00\x12m\n\x10UndoDemoteMaster\x12*.tabletmanagerdata.UndoDemoteMasterRequest\x1a+.tabletmanagerdata.UndoDemoteMasterResponse\"\x00\x12\x85\x01\n\x18PromoteSlaveWhenCaughtUp\x12\x32.tabletmanagerdata.PromoteSlaveWhenCaughtUpRequest\x1a\x33.tabletmanagerdata.PromoteSlaveWhenCaughtUpResponse\"\x00\x12m\n\x10SlaveWasPromoted\x12*.tabletmanagerdata.SlaveWasPromotedRequest\x1a+.tabletmanagerdata.SlaveWasPromotedResponse\"\x00\x12X\n\tSetMaster\x12#.tabletmanagerdata.SetMasterRequest\x1a$.tabletmanagerdata.SetMasterResponse\"\x00\x12p\n\x11SlaveWasRestarted\x12+.tabletmanagerdata.SlaveWasRestartedRequest\x1a,.tabletmanagerdata.SlaveWasRestartedResponse\"\x00\x12\x8e\x01\n\x1bStopReplicationAndGetStatus\x12\x35.tabletmanagerdata.StopReplicationAndGetStatusRequest\x1a\x36.tabletmanagerdata.StopReplicationAndGetStatusResponse\"\x00\x12\x61\n\x0cPromoteSlave\x12&.tabletmanagerdata.PromoteSlaveRequest\x1a\'.tabletmanagerdata.PromoteSlaveResponse\"\x00\x12Q\n\x06\x42\x61\x63kup\x12 .tabletmanagerdata.BackupRequest\x1a!.tabletmanagerdata.BackupResponse\"\x00\x30\x01\x12r\n\x11RestoreFromBackup\x12+.tabletmanagerdata.RestoreFromBackupRequest\x1a,.tabletmanagerdata.RestoreFromBackupResponse\"\x00\x30\x01\x42\x33Z1vitess.io/vitess/go/vt/proto/tabletmanagerserviceb\x06proto3') , dependencies=[tabletmanagerdata__pb2.DESCRIPTOR,]) @@ -29,17 +29,16 @@ _sym_db.RegisterFileDescriptor(DESCRIPTOR) -DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('Z1vitess.io/vitess/go/vt/proto/tabletmanagerservice')) +DESCRIPTOR._options = None _TABLETMANAGER = _descriptor.ServiceDescriptor( name='TabletManager', full_name='tabletmanagerservice.TabletManager', file=DESCRIPTOR, index=0, - options=None, + serialized_options=None, serialized_start=78, - serialized_end=4638, + serialized_end=4749, methods=[ _descriptor.MethodDescriptor( name='Ping', @@ -48,7 +47,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._PINGREQUEST, output_type=tabletmanagerdata__pb2._PINGRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='Sleep', @@ -57,7 +56,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._SLEEPREQUEST, output_type=tabletmanagerdata__pb2._SLEEPRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='ExecuteHook', @@ -66,7 +65,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._EXECUTEHOOKREQUEST, output_type=tabletmanagerdata__pb2._EXECUTEHOOKRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='GetSchema', @@ -75,7 +74,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._GETSCHEMAREQUEST, output_type=tabletmanagerdata__pb2._GETSCHEMARESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='GetPermissions', @@ -84,7 +83,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._GETPERMISSIONSREQUEST, output_type=tabletmanagerdata__pb2._GETPERMISSIONSRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='SetReadOnly', @@ -93,7 +92,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._SETREADONLYREQUEST, output_type=tabletmanagerdata__pb2._SETREADONLYRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='SetReadWrite', @@ -102,7 +101,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._SETREADWRITEREQUEST, output_type=tabletmanagerdata__pb2._SETREADWRITERESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='ChangeType', @@ -111,7 +110,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._CHANGETYPEREQUEST, output_type=tabletmanagerdata__pb2._CHANGETYPERESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='RefreshState', @@ -120,7 +119,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._REFRESHSTATEREQUEST, output_type=tabletmanagerdata__pb2._REFRESHSTATERESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='RunHealthCheck', @@ -129,7 +128,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._RUNHEALTHCHECKREQUEST, output_type=tabletmanagerdata__pb2._RUNHEALTHCHECKRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='IgnoreHealthError', @@ -138,7 +137,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._IGNOREHEALTHERRORREQUEST, output_type=tabletmanagerdata__pb2._IGNOREHEALTHERRORRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='ReloadSchema', @@ -147,7 +146,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._RELOADSCHEMAREQUEST, output_type=tabletmanagerdata__pb2._RELOADSCHEMARESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='PreflightSchema', @@ -156,7 +155,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._PREFLIGHTSCHEMAREQUEST, output_type=tabletmanagerdata__pb2._PREFLIGHTSCHEMARESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='ApplySchema', @@ -165,7 +164,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._APPLYSCHEMAREQUEST, output_type=tabletmanagerdata__pb2._APPLYSCHEMARESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='LockTables', @@ -174,7 +173,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._LOCKTABLESREQUEST, output_type=tabletmanagerdata__pb2._LOCKTABLESRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='UnlockTables', @@ -183,7 +182,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._UNLOCKTABLESREQUEST, output_type=tabletmanagerdata__pb2._UNLOCKTABLESRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='ExecuteFetchAsDba', @@ -192,7 +191,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._EXECUTEFETCHASDBAREQUEST, output_type=tabletmanagerdata__pb2._EXECUTEFETCHASDBARESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='ExecuteFetchAsAllPrivs', @@ -201,7 +200,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._EXECUTEFETCHASALLPRIVSREQUEST, output_type=tabletmanagerdata__pb2._EXECUTEFETCHASALLPRIVSRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='ExecuteFetchAsApp', @@ -210,7 +209,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._EXECUTEFETCHASAPPREQUEST, output_type=tabletmanagerdata__pb2._EXECUTEFETCHASAPPRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='SlaveStatus', @@ -219,7 +218,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._SLAVESTATUSREQUEST, output_type=tabletmanagerdata__pb2._SLAVESTATUSRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='MasterPosition', @@ -228,7 +227,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._MASTERPOSITIONREQUEST, output_type=tabletmanagerdata__pb2._MASTERPOSITIONRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='StopSlave', @@ -237,7 +236,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._STOPSLAVEREQUEST, output_type=tabletmanagerdata__pb2._STOPSLAVERESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='StopSlaveMinimum', @@ -246,7 +245,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._STOPSLAVEMINIMUMREQUEST, output_type=tabletmanagerdata__pb2._STOPSLAVEMINIMUMRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='StartSlave', @@ -255,7 +254,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._STARTSLAVEREQUEST, output_type=tabletmanagerdata__pb2._STARTSLAVERESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='StartSlaveUntilAfter', @@ -264,7 +263,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._STARTSLAVEUNTILAFTERREQUEST, output_type=tabletmanagerdata__pb2._STARTSLAVEUNTILAFTERRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='TabletExternallyReparented', @@ -273,7 +272,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._TABLETEXTERNALLYREPARENTEDREQUEST, output_type=tabletmanagerdata__pb2._TABLETEXTERNALLYREPARENTEDRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='TabletExternallyElected', @@ -282,7 +281,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._TABLETEXTERNALLYELECTEDREQUEST, output_type=tabletmanagerdata__pb2._TABLETEXTERNALLYELECTEDRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='GetSlaves', @@ -291,7 +290,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._GETSLAVESREQUEST, output_type=tabletmanagerdata__pb2._GETSLAVESRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='VReplicationExec', @@ -300,7 +299,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._VREPLICATIONEXECREQUEST, output_type=tabletmanagerdata__pb2._VREPLICATIONEXECRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='VReplicationWaitForPos', @@ -309,7 +308,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._VREPLICATIONWAITFORPOSREQUEST, output_type=tabletmanagerdata__pb2._VREPLICATIONWAITFORPOSRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='ResetReplication', @@ -318,7 +317,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._RESETREPLICATIONREQUEST, output_type=tabletmanagerdata__pb2._RESETREPLICATIONRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='InitMaster', @@ -327,7 +326,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._INITMASTERREQUEST, output_type=tabletmanagerdata__pb2._INITMASTERRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='PopulateReparentJournal', @@ -336,7 +335,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._POPULATEREPARENTJOURNALREQUEST, output_type=tabletmanagerdata__pb2._POPULATEREPARENTJOURNALRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='InitSlave', @@ -345,7 +344,7 @@ containing_service=None, input_type=tabletmanagerdata__pb2._INITSLAVEREQUEST, output_type=tabletmanagerdata__pb2._INITSLAVERESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='DemoteMaster', @@ -354,79 +353,88 @@ containing_service=None, input_type=tabletmanagerdata__pb2._DEMOTEMASTERREQUEST, output_type=tabletmanagerdata__pb2._DEMOTEMASTERRESPONSE, - options=None, + serialized_options=None, + ), + _descriptor.MethodDescriptor( + name='UndoDemoteMaster', + full_name='tabletmanagerservice.TabletManager.UndoDemoteMaster', + index=35, + containing_service=None, + input_type=tabletmanagerdata__pb2._UNDODEMOTEMASTERREQUEST, + output_type=tabletmanagerdata__pb2._UNDODEMOTEMASTERRESPONSE, + serialized_options=None, ), _descriptor.MethodDescriptor( name='PromoteSlaveWhenCaughtUp', full_name='tabletmanagerservice.TabletManager.PromoteSlaveWhenCaughtUp', - index=35, + index=36, containing_service=None, input_type=tabletmanagerdata__pb2._PROMOTESLAVEWHENCAUGHTUPREQUEST, output_type=tabletmanagerdata__pb2._PROMOTESLAVEWHENCAUGHTUPRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='SlaveWasPromoted', full_name='tabletmanagerservice.TabletManager.SlaveWasPromoted', - index=36, + index=37, containing_service=None, input_type=tabletmanagerdata__pb2._SLAVEWASPROMOTEDREQUEST, output_type=tabletmanagerdata__pb2._SLAVEWASPROMOTEDRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='SetMaster', full_name='tabletmanagerservice.TabletManager.SetMaster', - index=37, + index=38, containing_service=None, input_type=tabletmanagerdata__pb2._SETMASTERREQUEST, output_type=tabletmanagerdata__pb2._SETMASTERRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='SlaveWasRestarted', full_name='tabletmanagerservice.TabletManager.SlaveWasRestarted', - index=38, + index=39, containing_service=None, input_type=tabletmanagerdata__pb2._SLAVEWASRESTARTEDREQUEST, output_type=tabletmanagerdata__pb2._SLAVEWASRESTARTEDRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='StopReplicationAndGetStatus', full_name='tabletmanagerservice.TabletManager.StopReplicationAndGetStatus', - index=39, + index=40, containing_service=None, input_type=tabletmanagerdata__pb2._STOPREPLICATIONANDGETSTATUSREQUEST, output_type=tabletmanagerdata__pb2._STOPREPLICATIONANDGETSTATUSRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='PromoteSlave', full_name='tabletmanagerservice.TabletManager.PromoteSlave', - index=40, + index=41, containing_service=None, input_type=tabletmanagerdata__pb2._PROMOTESLAVEREQUEST, output_type=tabletmanagerdata__pb2._PROMOTESLAVERESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='Backup', full_name='tabletmanagerservice.TabletManager.Backup', - index=41, + index=42, containing_service=None, input_type=tabletmanagerdata__pb2._BACKUPREQUEST, output_type=tabletmanagerdata__pb2._BACKUPRESPONSE, - options=None, + serialized_options=None, ), _descriptor.MethodDescriptor( name='RestoreFromBackup', full_name='tabletmanagerservice.TabletManager.RestoreFromBackup', - index=42, + index=43, containing_service=None, input_type=tabletmanagerdata__pb2._RESTOREFROMBACKUPREQUEST, output_type=tabletmanagerdata__pb2._RESTOREFROMBACKUPRESPONSE, - options=None, + serialized_options=None, ), ]) _sym_db.RegisterServiceDescriptor(_TABLETMANAGER) diff --git a/py/vtproto/tabletmanagerservice_pb2_grpc.py b/py/vtproto/tabletmanagerservice_pb2_grpc.py index e559823327e..d7133c24429 100644 --- a/py/vtproto/tabletmanagerservice_pb2_grpc.py +++ b/py/vtproto/tabletmanagerservice_pb2_grpc.py @@ -192,6 +192,11 @@ def __init__(self, channel): request_serializer=tabletmanagerdata__pb2.DemoteMasterRequest.SerializeToString, response_deserializer=tabletmanagerdata__pb2.DemoteMasterResponse.FromString, ) + self.UndoDemoteMaster = channel.unary_unary( + '/tabletmanagerservice.TabletManager/UndoDemoteMaster', + request_serializer=tabletmanagerdata__pb2.UndoDemoteMasterRequest.SerializeToString, + response_deserializer=tabletmanagerdata__pb2.UndoDemoteMasterResponse.FromString, + ) self.PromoteSlaveWhenCaughtUp = channel.unary_unary( '/tabletmanagerservice.TabletManager/PromoteSlaveWhenCaughtUp', request_serializer=tabletmanagerdata__pb2.PromoteSlaveWhenCaughtUpRequest.SerializeToString, @@ -522,6 +527,13 @@ def DemoteMaster(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def UndoDemoteMaster(self, request, context): + """UndoDemoteMaster reverts all changes made by DemoteMaster + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def PromoteSlaveWhenCaughtUp(self, request, context): """PromoteSlaveWhenCaughtUp tells the remote tablet to catch up, and then be the master @@ -761,6 +773,11 @@ def add_TabletManagerServicer_to_server(servicer, server): request_deserializer=tabletmanagerdata__pb2.DemoteMasterRequest.FromString, response_serializer=tabletmanagerdata__pb2.DemoteMasterResponse.SerializeToString, ), + 'UndoDemoteMaster': grpc.unary_unary_rpc_method_handler( + servicer.UndoDemoteMaster, + request_deserializer=tabletmanagerdata__pb2.UndoDemoteMasterRequest.FromString, + response_serializer=tabletmanagerdata__pb2.UndoDemoteMasterResponse.SerializeToString, + ), 'PromoteSlaveWhenCaughtUp': grpc.unary_unary_rpc_method_handler( servicer.PromoteSlaveWhenCaughtUp, request_deserializer=tabletmanagerdata__pb2.PromoteSlaveWhenCaughtUpRequest.FromString, diff --git a/test/utils.py b/test/utils.py index 2bae9fa3ebf..fb28df445bd 100644 --- a/test/utils.py +++ b/test/utils.py @@ -827,7 +827,7 @@ def run_vtctl(clargs, auto_log=False, expect_fail=False, logging.debug('vtctl: %s', ' '.join(clargs)) result = vtctl_client.execute_vtctl_command(vtctld_connection, clargs, info_to_debug=True, - action_timeout=120) + action_timeout=10) return result, '' raise Exception('Unknown mode: %s', mode) From 1dfe8c9efcd342259f671d4d5f4c817c0b86b2af Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 29 Jan 2019 14:43:37 -0800 Subject: [PATCH 003/196] implement checking for DeadlineExceeded + testcase Signed-off-by: deepthi --- .../fakemysqldaemon/fakemysqldaemon.go | 7 ++ go/vt/wrangler/reparent.go | 4 +- .../testlib/planned_reparent_shard_test.go | 101 +++++++++++++++++- 3 files changed, 108 insertions(+), 4 deletions(-) diff --git a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go index f240b04c0c9..55961a13a32 100644 --- a/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go +++ b/go/vt/mysqlctl/fakemysqldaemon/fakemysqldaemon.go @@ -135,6 +135,10 @@ type FakeMysqlDaemon struct { SemiSyncMasterEnabled bool // SemiSyncSlaveEnabled represents the state of rpl_semi_sync_slave_enabled. SemiSyncSlaveEnabled bool + + // TimeoutHook is a func that can be called at the beginning of any method to fake a timeout. + // all a test needs to do is make it { return context.DeadlineExceeded } + TimeoutHook func() error } // NewFakeMysqlDaemon returns a FakeMysqlDaemon where mysqld appears @@ -300,6 +304,9 @@ func (fmd *FakeMysqlDaemon) DemoteMaster() (mysql.Position, error) { // WaitMasterPos is part of the MysqlDaemon interface func (fmd *FakeMysqlDaemon) WaitMasterPos(_ context.Context, pos mysql.Position) error { + if fmd.TimeoutHook != nil { + return fmd.TimeoutHook() + } if reflect.DeepEqual(fmd.WaitMasterPosition, pos) { return nil } diff --git a/go/vt/wrangler/reparent.go b/go/vt/wrangler/reparent.go index 46adcca7b69..7632b8bdf90 100644 --- a/go/vt/wrangler/reparent.go +++ b/go/vt/wrangler/reparent.go @@ -21,11 +21,11 @@ This file handles the reparenting operations. */ import ( + "context" "fmt" "sync" "time" - "golang.org/x/net/context" "vitess.io/vitess/go/event" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqlescape" @@ -426,7 +426,7 @@ func (wr *Wrangler) plannedReparentShardLocked(ctx context.Context, ev *events.R wr.logger.Infof("promote slave %v", masterElectTabletAliasStr) event.DispatchUpdate(ev, "promoting slave") rp, err = wr.tmc.PromoteSlaveWhenCaughtUp(ctx, masterElectTabletInfo.Tablet, rp) - if err != nil { + if err != nil || (ctx.Err() != nil && ctx.Err() == context.DeadlineExceeded) { // if this fails it is not enough to return an error. we should rollback all the changes made by DemoteMaster if err1 := wr.tmc.UndoDemoteMaster(ctx, oldMasterTabletInfo.Tablet); err1 != nil { log.Warningf("Encountered error %v while trying to undo DemoteMaster", err1) diff --git a/go/vt/wrangler/testlib/planned_reparent_shard_test.go b/go/vt/wrangler/testlib/planned_reparent_shard_test.go index 1dce7483370..36448189d42 100644 --- a/go/vt/wrangler/testlib/planned_reparent_shard_test.go +++ b/go/vt/wrangler/testlib/planned_reparent_shard_test.go @@ -17,6 +17,7 @@ limitations under the License. package testlib import ( + "context" "strings" "testing" @@ -300,7 +301,7 @@ func TestPlannedReparentShardPromoteSlaveFail(t *testing.T) { newMaster.FakeMysqlDaemon.WaitMasterPosition = mysql.Position{ GTIDSet: mysql.MariadbGTIDSet{ mysql.MariadbGTID{ - Domain: 6, + Domain: 7, Server: 123, Sequence: 990, }, @@ -326,7 +327,7 @@ func TestPlannedReparentShardPromoteSlaveFail(t *testing.T) { // old master oldMaster.FakeMysqlDaemon.ReadOnly = false oldMaster.FakeMysqlDaemon.Replicating = false - // to make promote fail on WaitForMasterPos + // set to incorrect value to make promote fail on WaitForMasterPos oldMaster.FakeMysqlDaemon.DemoteMasterPosition = newMaster.FakeMysqlDaemon.PromoteSlaveResult oldMaster.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) oldMaster.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ @@ -377,3 +378,99 @@ func TestPlannedReparentShardPromoteSlaveFail(t *testing.T) { t.Errorf("oldMaster.FakeMysqlDaemon.ReadOnly set") } } + +func TestPlannedReparentShardPromoteSlaveTimeout(t *testing.T) { + ts := memorytopo.NewServer("cell1", "cell2") + wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient()) + vp := NewVtctlPipe(t, ts) + defer vp.Close() + + // Create a master, a couple good slaves + oldMaster := NewFakeTablet(t, wr, "cell1", 0, topodatapb.TabletType_MASTER, nil) + newMaster := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, nil) + goodSlave1 := NewFakeTablet(t, wr, "cell1", 2, topodatapb.TabletType_REPLICA, nil) + goodSlave2 := NewFakeTablet(t, wr, "cell2", 3, topodatapb.TabletType_REPLICA, nil) + + // new master + newMaster.FakeMysqlDaemon.TimeoutHook = func() error { return context.DeadlineExceeded } + newMaster.FakeMysqlDaemon.ReadOnly = true + newMaster.FakeMysqlDaemon.Replicating = true + newMaster.FakeMysqlDaemon.WaitMasterPosition = mysql.Position{ + GTIDSet: mysql.MariadbGTIDSet{ + mysql.MariadbGTID{ + Domain: 7, + Server: 123, + Sequence: 990, + }, + }, + } + newMaster.FakeMysqlDaemon.PromoteSlaveResult = mysql.Position{ + GTIDSet: mysql.MariadbGTIDSet{ + mysql.MariadbGTID{ + Domain: 7, + Server: 456, + Sequence: 991, + }, + }, + } + newMaster.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "CREATE DATABASE IF NOT EXISTS _vt", + "SUBCREATE TABLE IF NOT EXISTS _vt.reparent_journal", + "SUBINSERT INTO _vt.reparent_journal (time_created_ns, action_name, master_alias, replication_position) VALUES", + } + newMaster.StartActionLoop(t, wr) + defer newMaster.StopActionLoop(t) + + // old master + oldMaster.FakeMysqlDaemon.ReadOnly = false + oldMaster.FakeMysqlDaemon.Replicating = false + oldMaster.FakeMysqlDaemon.DemoteMasterPosition = newMaster.FakeMysqlDaemon.WaitMasterPosition + oldMaster.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) + oldMaster.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "FAKE SET MASTER", + "START SLAVE", + } + oldMaster.StartActionLoop(t, wr) + defer oldMaster.StopActionLoop(t) + oldMaster.Agent.QueryServiceControl.(*tabletservermock.Controller).SetQueryServiceEnabledForTests(true) + + // good slave 1 is replicating + goodSlave1.FakeMysqlDaemon.ReadOnly = true + goodSlave1.FakeMysqlDaemon.Replicating = true + goodSlave1.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) + goodSlave1.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "STOP SLAVE", + "FAKE SET MASTER", + "START SLAVE", + } + goodSlave1.StartActionLoop(t, wr) + defer goodSlave1.StopActionLoop(t) + + // good slave 2 is not replicating + goodSlave2.FakeMysqlDaemon.ReadOnly = true + goodSlave2.FakeMysqlDaemon.Replicating = false + goodSlave2.FakeMysqlDaemon.SetMasterInput = topoproto.MysqlAddr(newMaster.Tablet) + goodSlave2.StartActionLoop(t, wr) + goodSlave2.FakeMysqlDaemon.ExpectedExecuteSuperQueryList = []string{ + "FAKE SET MASTER", + } + defer goodSlave2.StopActionLoop(t) + + // run PlannedReparentShard + err := vp.Run([]string{"PlannedReparentShard", "-wait_slave_timeout", "10s", "-keyspace_shard", newMaster.Tablet.Keyspace + "/" + newMaster.Tablet.Shard, "-new_master", topoproto.TabletAliasString(newMaster.Tablet.Alias)}) + + if err == nil { + t.Fatalf("PlannedReparentShard succeeded: %v", err) + } + if !strings.Contains(err.Error(), "master-elect tablet cell1-0000000001 failed to catch up with replication or be upgraded to master") { + t.Fatalf("PlannedReparentShard failed with the wrong error: %v", err) + } + + // now check that DemoteMaster was undone and old master is still master + if !newMaster.FakeMysqlDaemon.ReadOnly { + t.Errorf("newMaster.FakeMysqlDaemon.ReadOnly not set") + } + if oldMaster.FakeMysqlDaemon.ReadOnly { + t.Errorf("oldMaster.FakeMysqlDaemon.ReadOnly set") + } +} From 2efaecfa67ad5aa24354bde12de3c88dd9e5479e Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Wed, 30 Jan 2019 10:47:51 -0500 Subject: [PATCH 004/196] update .md and .txt and .proto Signed-off-by: xichengliudui --- doc/VindexAsTable.md | 2 +- go/vt/vtgate/planbuilder/testdata/filter_cases.txt | 2 +- proto/vtgate.proto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/VindexAsTable.md b/doc/VindexAsTable.md index 594b4ea4cde..5e633795088 100644 --- a/doc/VindexAsTable.md +++ b/doc/VindexAsTable.md @@ -37,7 +37,7 @@ For `select` statements, we can follow the V3 design principles, there will be a While analyzing the `WHERE` clause, if the primitive is a `vindexFunc`, we look for the three possible combinations listed above. Once they're matched, we can assign the corresponding opcode. -While analyizing the `SELECT` expression list, we verify that that the user has specified expressions as required by each opcode. +While analyizing the `SELECT` expression list, we verify that the user has specified expressions as required by each opcode. Joins and subqueries will not be allowed, at least for now. diff --git a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt index 48ae26d6f7b..b9b9da4a4f5 100644 --- a/go/vt/vtgate/planbuilder/testdata/filter_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/filter_cases.txt @@ -936,6 +936,6 @@ # outer and inner subquery route reference the same "uu.id" name # but they refer to different things. The first reference is to the outermost query, -# and the second reference is to the the innermost 'from' subquery. +# and the second reference is to the innermost 'from' subquery. "select id2 from user uu where id in (select id from user where id = uu.id and user.col in (select col from (select id from user_extra where user_id = 5) uu where uu.user_id = uu.id))" "unsupported: cross-shard correlated subquery" diff --git a/proto/vtgate.proto b/proto/vtgate.proto index 823f4f4d07a..58ae2b6106c 100644 --- a/proto/vtgate.proto +++ b/proto/vtgate.proto @@ -702,7 +702,7 @@ message ResolveTransactionResponse { // SplitQuery takes a "SELECT" query and generates a list of queries called // "query-parts". Each query-part consists of the original query with an // added WHERE clause that restricts the query-part to operate only on -// rows whose values in the the columns listed in the "split_column" field +// rows whose values in the columns listed in the "split_column" field // of the request (see below) are in a particular range. // // It is guaranteed that the set of rows obtained from From 2fd81adc94e5f972bba79a712d052a7e01748fa3 Mon Sep 17 00:00:00 2001 From: deepthi Date: Thu, 31 Jan 2019 12:02:18 -0800 Subject: [PATCH 005/196] add fsp to current date/time function calls Signed-off-by: deepthi --- go/vt/sqlparser/ast.go | 27 + go/vt/sqlparser/parse_test.go | 62 +- go/vt/sqlparser/sql.go | 2631 +++++++++++++++++---------------- go/vt/sqlparser/sql.y | 30 + 4 files changed, 1473 insertions(+), 1277 deletions(-) diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index 83ee5657440..3316e76cc51 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -2172,6 +2172,7 @@ func (*IntervalExpr) iExpr() {} func (*CollateExpr) iExpr() {} func (*FuncExpr) iExpr() {} func (*TimestampFuncExpr) iExpr() {} +func (*CurTimeFuncExpr) iExpr() {} func (*CaseExpr) iExpr() {} func (*ValuesFuncExpr) iExpr() {} func (*ConvertExpr) iExpr() {} @@ -2903,6 +2904,32 @@ func (node *TimestampFuncExpr) replace(from, to Expr) bool { return false } +// CurTimeFuncExpr represents the function and arguments for CURRENT DATE/TIME functions +// supported functions are documented in the grammar +type CurTimeFuncExpr struct { + Name ColIdent + Fsp Expr // fractional seconds precision, integer from 0 to 6 +} + +// Format formats the node. +func (node *CurTimeFuncExpr) Format(buf *TrackedBuffer) { + buf.Myprintf("%s(%v)", node.Name.String(), node.Fsp) +} + +func (node *CurTimeFuncExpr) walkSubtree(visit Visit) error { + if node == nil { + return nil + } + return Walk( + visit, + node.Fsp, + ) +} + +func (node *CurTimeFuncExpr) replace(from, to Expr) bool { + return replaceExprs(from, to, &node.Fsp) +} + // CollateExpr represents dynamic collate operator. type CollateExpr struct { Expr Expr diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index a0141afd880..8dbc38d0e7d 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -425,8 +425,50 @@ var ( input: "select /* function with distinct */ count(distinct a) from t", }, { input: "select /* if as func */ 1 from t where a = if(b)", + }, { + input: "select /* current_timestamp */ current_timestamp() from t", }, { input: "select /* current_timestamp as func */ current_timestamp() from t", + }, { + input: "select /* current_timestamp with fsp */ current_timestamp(3) from t", + }, { + input: "select /* current_date */ current_date() from t", + }, { + input: "select /* current_date as func */ current_date() from t", + }, { + input: "select /* current_time */ current_time() from t", + }, { + input: "select /* current_time as func */ current_time() from t", + }, { + input: "select /* current_time with fsp */ current_time(1) from t", + }, { + input: "select /* utc_timestamp */ utc_timestamp() from t", + }, { + input: "select /* utc_timestamp as func */ utc_timestamp() from t", + }, { + input: "select /* utc_timestamp with fsp */ utc_timestamp(0) from t", + }, { + input: "select /* utc_time */ utc_time() from t", + }, { + input: "select /* utc_time as func */ utc_time() from t", + }, { + input: "select /* utc_time with fsp */ utc_time(4) from t", + }, { + input: "select /* utc_date */ utc_date() from t", + }, { + input: "select /* utc_date as func */ utc_date() from t", + }, { + input: "select /* localtime */ localtime() from t", + }, { + input: "select /* localtime as func */ localtime() from t", + }, { + input: "select /* localtime with fsp */ localtime(5) from t", + }, { + input: "select /* localtimestamp */ localtimestamp() from t", + }, { + input: "select /* localtimestamp as func */ localtimestamp() from t", + }, { + input: "select /* localtimestamp with fsp */ localtimestamp(7) from t", }, { input: "select /* mod as func */ a from tab where mod(b, 2) = 0", }, { @@ -1579,6 +1621,8 @@ func TestKeywords(t *testing.T) { output: "select current_timestamp() from dual", }, { input: "update t set a = current_timestamp()", + }, { + input: "update t set a = current_timestamp(5)", }, { input: "select a, current_date from t", output: "select a, current_date() from t", @@ -1587,18 +1631,26 @@ func TestKeywords(t *testing.T) { output: "insert into t(a, b) values (current_date(), current_date())", }, { input: "select * from t where a > utc_timestmp()", + }, { + input: "select * from t where a > utc_timestamp(4)", }, { input: "update t set b = utc_timestamp + 5", output: "update t set b = utc_timestamp() + 5", }, { - input: "select utc_time, utc_date", - output: "select utc_time(), utc_date() from dual", + input: "select utc_time, utc_date, utc_time(6)", + output: "select utc_time(), utc_date(), utc_time(6) from dual", }, { input: "select 1 from dual where localtime > utc_time", output: "select 1 from dual where localtime() > utc_time()", + }, { + input: "select 1 from dual where localtime(2) > utc_time(1)", + output: "select 1 from dual where localtime(2) > utc_time(1)", }, { input: "update t set a = localtimestamp(), b = utc_timestamp", output: "update t set a = localtimestamp(), b = utc_timestamp()", + }, { + input: "update t set a = localtimestamp(10), b = utc_timestamp(13)", + output: "update t set a = localtimestamp(10), b = utc_timestamp(13)", }, { input: "insert into t(a) values (unix_timestamp)", }, { @@ -2061,13 +2113,15 @@ func TestCreateTable(t *testing.T) { " time1 timestamp default current_timestamp,\n" + " time2 timestamp default current_timestamp(),\n" + " time3 timestamp default current_timestamp on update current_timestamp,\n" + - " time4 timestamp default current_timestamp() on update current_timestamp()\n" + + " time4 timestamp default current_timestamp() on update current_timestamp(),\n" + + " time5 timestamp(3) default current_timestamp(3) on update current_timestamp(3)\n" + ")", output: "create table t (\n" + " time1 timestamp default current_timestamp,\n" + " time2 timestamp default current_timestamp,\n" + " time3 timestamp default current_timestamp on update current_timestamp,\n" + - " time4 timestamp default current_timestamp on update current_timestamp\n" + + " time4 timestamp default current_timestamp on update current_timestamp,\n" + + " time5 timestamp(3) default current_timestamp(3) on update current_timestamp(3)\n" + ")", }, } diff --git a/go/vt/sqlparser/sql.go b/go/vt/sqlparser/sql.go index 24382a6f1c2..f9bd182cd27 100644 --- a/go/vt/sqlparser/sql.go +++ b/go/vt/sqlparser/sql.go @@ -6,7 +6,6 @@ package sqlparser import __yyfmt__ "fmt" //line sql.y:18 - func setParseTree(yylex interface{}, stmt Statement) { yylex.(*Tokenizer).ParseTree = stmt } @@ -643,24 +642,24 @@ var yyExca = [...]int{ 160, 300, -2, 290, -1, 267, - 112, 638, - -2, 634, + 112, 644, + -2, 640, -1, 268, - 112, 639, - -2, 635, + 112, 645, + -2, 641, -1, 333, - 82, 811, + 82, 817, -2, 60, -1, 334, - 82, 768, + 82, 774, -2, 61, -1, 339, - 82, 747, - -2, 600, + 82, 753, + -2, 606, -1, 341, - 82, 789, - -2, 602, - -1, 603, + 82, 795, + -2, 608, + -1, 609, 1, 352, 5, 352, 12, 352, @@ -684,300 +683,317 @@ var yyExca = [...]int{ 56, 352, 268, 352, -2, 370, - -1, 606, + -1, 612, 53, 43, 55, 43, -2, 45, - -1, 746, - 112, 641, - -2, 637, - -1, 966, + -1, 752, + 112, 647, + -2, 643, + -1, 978, 5, 30, -2, 436, - -1, 997, + -1, 1015, 5, 29, - -2, 574, - -1, 1254, + -2, 580, + -1, 1272, 5, 30, - -2, 575, - -1, 1311, + -2, 581, + -1, 1329, 5, 29, - -2, 577, - -1, 1394, + -2, 583, + -1, 1412, 5, 30, - -2, 578, + -2, 584, } const yyPrivate = 57344 -const yyLast = 12360 +const yyLast = 12774 var yyAct = [...]int{ - 268, 1209, 1382, 1089, 852, 1429, 1288, 566, 272, 1323, - 1144, 1018, 1000, 298, 1419, 1178, 829, 1141, 1145, 1001, - 861, 246, 931, 895, 881, 851, 781, 1274, 1151, 1112, - 848, 237, 81, 57, 771, 778, 208, 1157, 338, 208, - 1024, 711, 1069, 1060, 831, 1043, 958, 780, 799, 816, - 299, 51, 616, 865, 748, 498, 504, 439, 615, 827, - 891, 332, 809, 565, 3, 270, 599, 208, 81, 510, - 940, 255, 208, 327, 208, 518, 238, 239, 240, 241, - 329, 580, 244, 56, 1422, 1406, 1417, 1392, 1414, 1210, - 259, 1405, 1391, 1134, 1246, 444, 1334, 1031, 1172, 472, - 1030, 842, 51, 1032, 600, 203, 199, 200, 201, 243, - 251, 1173, 1174, 843, 844, 245, 1356, 531, 530, 540, - 541, 533, 534, 535, 536, 537, 538, 539, 532, 61, - 617, 542, 618, 1186, 1187, 1188, 488, 492, 242, 1051, - 914, 1191, 1189, 874, 489, 486, 487, 1277, 1294, 882, - 1229, 236, 1227, 686, 913, 63, 64, 65, 66, 67, - 195, 1416, 197, 481, 482, 474, 1092, 476, 1091, 684, - 1413, 1383, 1088, 810, 1374, 1433, 457, 866, 1332, 1324, - 1437, 458, 918, 446, 1019, 1021, 197, 685, 1093, 690, - 677, 912, 1326, 868, 1167, 491, 208, 473, 475, 208, - 1166, 868, 1085, 1165, 442, 208, 687, 449, 1087, 210, - 198, 208, 925, 1363, 81, 924, 81, 1257, 81, 81, - 1113, 81, 1044, 81, 554, 555, 202, 1099, 976, 952, - 454, 720, 81, 522, 868, 464, 1195, 532, 849, 542, - 542, 909, 906, 907, 717, 905, 496, 712, 535, 536, - 537, 538, 539, 532, 933, 196, 542, 1115, 440, 517, - 1325, 1020, 81, 440, 469, 1372, 469, 70, 469, 469, - 1342, 469, 1155, 469, 494, 495, 916, 919, 882, 1333, - 1331, 1431, 469, 506, 1432, 471, 1430, 1196, 1357, 867, - 1117, 438, 1121, 451, 1116, 452, 1114, 867, 453, 619, - 1136, 1119, 51, 71, 1086, 1390, 1084, 800, 800, 985, - 1118, 1076, 911, 515, 1049, 507, 1190, 551, 679, 1377, - 553, 512, 1396, 1120, 1122, 208, 208, 208, 713, 517, - 867, 81, 932, 871, 910, 864, 862, 81, 863, 872, - 1074, 1284, 1438, 860, 866, 949, 950, 951, 564, 470, - 568, 569, 570, 571, 572, 573, 574, 575, 576, 875, - 579, 581, 581, 581, 581, 581, 581, 581, 581, 589, - 590, 591, 592, 593, 594, 755, 604, 915, 460, 461, - 462, 1439, 508, 1283, 1249, 598, 1064, 971, 1063, 753, - 754, 752, 917, 582, 583, 584, 585, 586, 587, 588, - 607, 1052, 516, 515, 723, 724, 1398, 1075, 54, 1138, - 22, 613, 1080, 1077, 1070, 1078, 1073, 335, 751, 517, - 1071, 1072, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 1079, 445, 542, 516, 515, 208, - 516, 515, 194, 970, 81, 969, 1373, 1305, 1370, 208, - 208, 81, 516, 515, 517, 208, 1281, 517, 208, 1096, - 274, 208, 516, 515, 772, 208, 773, 81, 81, 517, - 250, 1061, 81, 81, 81, 81, 81, 81, 1033, 517, - 1034, 1212, 81, 81, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 469, 1044, 542, 1039, 738, 740, - 741, 469, 774, 699, 739, 1329, 1415, 324, 325, 696, - 81, 695, 447, 448, 208, 1401, 497, 469, 469, 680, - 81, 678, 469, 469, 469, 469, 469, 469, 725, 1242, - 497, 691, 469, 469, 675, 697, 1329, 1386, 497, 749, - 466, 531, 530, 540, 541, 533, 534, 535, 536, 537, - 538, 539, 532, 1329, 497, 542, 1329, 1364, 1329, 1328, - 1399, 746, 1272, 1271, 81, 1259, 497, 531, 530, 540, - 541, 533, 534, 535, 536, 537, 538, 539, 532, 459, - 727, 542, 790, 794, 1256, 497, 1202, 1201, 801, 1339, - 81, 81, 1338, 744, 959, 742, 1154, 208, 288, 287, - 290, 291, 292, 293, 51, 208, 208, 289, 294, 208, - 208, 1198, 1199, 81, 1198, 1197, 24, 786, 787, 568, - 775, 776, 1335, 796, 964, 497, 81, 1192, 806, 813, - 497, 58, 785, 783, 497, 626, 625, 869, 719, 805, - 995, 807, 808, 783, 996, 1102, 797, 533, 534, 535, - 536, 537, 538, 539, 532, 828, 1025, 542, 610, 604, - 1142, 261, 980, 1154, 54, 883, 884, 885, 837, 835, - 1252, 964, 297, 840, 839, 718, 812, 24, 208, 81, - 335, 81, 1341, 813, 856, 81, 81, 208, 208, 964, - 208, 208, 516, 515, 208, 81, 1025, 978, 897, 813, - 611, 813, 609, 975, 79, 1310, 979, 973, 836, 517, - 609, 208, 24, 208, 208, 1200, 208, 818, 821, 822, - 823, 819, 1035, 820, 824, 54, 252, 1158, 1159, 469, - 552, 469, 893, 894, 841, 989, 988, 964, 609, 1154, - 337, 977, 612, 721, 689, 469, 1090, 974, 54, 1407, - 899, 972, 1380, 1290, 726, 1279, 876, 1264, 896, 746, - 54, 818, 821, 822, 823, 819, 749, 820, 824, 1183, - 1158, 1159, 733, 1411, 54, 1038, 892, 887, 941, 886, - 948, 942, 1424, 1420, 1185, 1161, 603, 1142, 1065, 715, - 693, 1164, 1012, 1010, 1163, 1009, 953, 1013, 1011, 1014, - 1008, 822, 823, 256, 257, 1404, 1098, 954, 937, 511, - 1409, 947, 782, 784, 208, 208, 208, 208, 208, 946, - 499, 1002, 1056, 624, 509, 467, 208, 963, 802, 208, - 1250, 1048, 500, 208, 1379, 1378, 1308, 208, 1046, 1040, - 1286, 902, 692, 826, 511, 982, 945, 984, 253, 254, - 247, 58, 81, 1346, 944, 248, 1036, 1345, 1292, 1025, - 998, 999, 490, 710, 604, 604, 604, 604, 604, 1426, - 1425, 1426, 745, 997, 1015, 513, 1360, 1023, 1027, 828, - 1003, 1022, 1278, 1006, 716, 60, 337, 604, 337, 265, - 337, 337, 785, 337, 1028, 337, 1026, 62, 608, 55, - 81, 81, 1053, 1054, 337, 1, 1418, 1211, 1287, 501, - 505, 1045, 1055, 908, 1057, 1058, 1059, 1041, 1042, 1004, - 1005, 1381, 1007, 1322, 1177, 859, 523, 850, 69, 81, - 437, 1062, 68, 1371, 520, 858, 1068, 857, 1330, 1276, - 870, 1050, 873, 1184, 208, 1376, 1047, 632, 630, 1081, - 631, 469, 629, 81, 634, 633, 628, 221, 330, 825, - 620, 567, 335, 898, 514, 72, 1083, 1082, 904, 484, - 578, 485, 1095, 223, 550, 853, 943, 1029, 336, 469, - 1149, 722, 503, 1344, 1291, 983, 750, 577, 798, 1105, - 273, 1111, 737, 286, 283, 877, 878, 879, 880, 81, - 81, 1124, 1106, 337, 1002, 1123, 285, 284, 1143, 621, - 1146, 888, 889, 890, 728, 746, 1135, 994, 524, 271, - 263, 961, 602, 81, 595, 962, 817, 815, 814, 1160, - 1156, 601, 966, 967, 968, 1101, 81, 1245, 81, 81, - 1355, 1153, 1176, 981, 1162, 732, 26, 1147, 987, 51, - 59, 1168, 990, 991, 992, 993, 258, 19, 1169, 18, - 1180, 1175, 1148, 17, 20, 603, 208, 1171, 16, 603, - 745, 15, 14, 455, 1017, 30, 21, 13, 12, 11, - 10, 9, 8, 208, 1193, 1194, 1248, 1181, 1182, 81, - 7, 6, 81, 81, 208, 5, 4, 249, 23, 2, - 81, 1204, 0, 208, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1205, 0, 1207, 337, 0, 1216, 0, - 0, 0, 0, 337, 531, 530, 540, 541, 533, 534, - 535, 536, 537, 538, 539, 532, 0, 0, 542, 337, - 337, 1225, 1217, 0, 337, 337, 337, 337, 337, 337, - 0, 0, 714, 604, 337, 337, 0, 0, 0, 0, - 0, 1251, 1218, 1002, 0, 556, 557, 558, 559, 560, - 561, 562, 563, 0, 1261, 0, 81, 735, 736, 0, - 1036, 0, 729, 0, 81, 1244, 0, 1260, 0, 0, - 0, 1270, 520, 0, 0, 337, 0, 0, 0, 0, - 0, 853, 0, 0, 81, 0, 0, 0, 0, 0, - 1110, 81, 0, 750, 0, 0, 1266, 1267, 1268, 0, - 0, 0, 1280, 0, 1282, 0, 0, 0, 0, 0, - 567, 0, 0, 788, 789, 0, 777, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 792, 792, 1293, 0, - 0, 0, 792, 0, 469, 0, 0, 81, 81, 0, - 81, 0, 803, 804, 605, 81, 1146, 81, 81, 81, - 208, 1309, 0, 81, 603, 603, 603, 603, 603, 0, - 0, 847, 1316, 0, 0, 337, 1321, 0, 1327, 603, - 0, 81, 1317, 0, 1318, 1319, 1320, 603, 337, 0, - 205, 0, 1104, 1147, 0, 0, 1312, 0, 0, 0, - 0, 1336, 0, 1337, 0, 0, 0, 0, 1343, 1311, - 0, 1361, 0, 0, 1146, 0, 1129, 0, 0, 0, - 81, 328, 1369, 1368, 0, 0, 441, 1340, 443, 0, - 0, 0, 81, 81, 0, 0, 0, 1385, 1384, 0, - 0, 337, 1219, 337, 1388, 0, 0, 920, 921, 1221, - 0, 1147, 0, 51, 81, 0, 0, 337, 0, 1002, - 1230, 1231, 1232, 1393, 1235, 208, 1362, 1238, 0, 1241, - 938, 939, 0, 505, 81, 853, 0, 853, 0, 0, - 1403, 0, 0, 337, 1253, 1254, 1255, 0, 1258, 0, - 0, 0, 0, 0, 1408, 1410, 0, 0, 81, 0, - 0, 0, 0, 0, 747, 1269, 0, 756, 757, 758, - 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, - 769, 770, 1434, 1423, 0, 1412, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 965, 0, 0, 0, 1104, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 450, 0, 986, 456, 0, 0, 0, 1421, 0, 463, - 0, 0, 0, 1222, 1223, 465, 1224, 0, 0, 1226, - 0, 1228, 0, 0, 0, 792, 526, 0, 529, 1239, - 497, 0, 1304, 0, 543, 544, 545, 546, 547, 548, - 549, 0, 527, 528, 525, 531, 530, 540, 541, 533, - 534, 535, 536, 537, 538, 539, 532, 0, 0, 542, - 0, 0, 0, 0, 337, 853, 0, 531, 530, 540, - 541, 533, 534, 535, 536, 537, 538, 539, 532, 1273, - 0, 542, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, - 0, 0, 0, 1358, 1359, 0, 1107, 0, 0, 0, - 1289, 0, 0, 603, 0, 1365, 1366, 1367, 0, 0, - 0, 0, 1066, 337, 1236, 497, 531, 530, 540, 541, - 533, 534, 535, 536, 537, 538, 539, 532, 502, 597, - 542, 606, 0, 0, 0, 1097, 0, 0, 0, 0, - 0, 337, 1389, 0, 0, 0, 0, 0, 0, 1394, - 468, 0, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 206, 337, 542, 235, 1400, 0, - 0, 0, 24, 25, 52, 27, 28, 0, 0, 0, - 0, 0, 0, 955, 956, 957, 0, 1137, 0, 337, - 0, 43, 262, 0, 0, 206, 29, 48, 49, 0, - 206, 0, 206, 0, 0, 0, 0, 0, 792, 0, - 0, 1150, 1152, 0, 1435, 1436, 38, 0, 0, 0, - 54, 0, 0, 0, 0, 0, 0, 1170, 1233, 497, - 0, 1289, 853, 0, 0, 1152, 0, 0, 0, 0, - 0, 0, 0, 627, 0, 0, 0, 0, 337, 0, - 337, 1179, 497, 681, 682, 0, 0, 0, 0, 688, - 0, 0, 328, 0, 0, 694, 531, 530, 540, 541, + 268, 1447, 1437, 1227, 1400, 1018, 272, 566, 1341, 1292, + 1306, 1036, 864, 1107, 1162, 1196, 57, 841, 1163, 246, + 860, 1159, 1019, 943, 907, 565, 3, 1061, 873, 893, + 887, 863, 81, 298, 1042, 1169, 208, 839, 1175, 208, + 777, 1130, 717, 1087, 338, 787, 970, 611, 1078, 784, + 622, 877, 843, 828, 805, 237, 754, 498, 504, 903, + 621, 606, 439, 332, 952, 518, 821, 208, 81, 605, + 255, 329, 208, 327, 208, 56, 510, 245, 1440, 1424, + 1435, 580, 1410, 205, 1432, 1228, 1423, 1152, 1264, 1409, + 444, 1352, 261, 472, 1191, 1192, 274, 61, 1190, 270, + 238, 239, 240, 241, 1049, 854, 244, 1048, 492, 259, + 1050, 855, 856, 243, 328, 203, 199, 200, 201, 441, + 242, 443, 218, 63, 64, 65, 66, 67, 926, 1374, + 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, + 539, 532, 925, 623, 542, 624, 231, 1204, 1205, 1206, + 195, 886, 197, 1069, 488, 1209, 1207, 786, 1295, 474, + 1312, 476, 489, 486, 487, 457, 491, 894, 1247, 1245, + 930, 236, 481, 482, 692, 1110, 1109, 690, 1434, 924, + 1431, 1401, 1106, 822, 1392, 1451, 878, 1342, 1455, 458, + 446, 473, 475, 1037, 1039, 197, 208, 211, 1111, 208, + 1344, 696, 683, 1185, 214, 208, 1184, 1183, 691, 880, + 442, 208, 222, 217, 81, 693, 81, 880, 81, 81, + 454, 81, 449, 81, 210, 198, 861, 554, 555, 921, + 918, 919, 81, 917, 1350, 1381, 202, 937, 1062, 1275, + 936, 1103, 1117, 450, 220, 196, 456, 1105, 988, 964, + 230, 880, 463, 726, 522, 542, 464, 532, 465, 1213, + 542, 470, 81, 723, 928, 931, 506, 718, 1343, 517, + 1038, 945, 516, 515, 1390, 1360, 212, 507, 1173, 471, + 440, 440, 70, 451, 1154, 452, 625, 806, 453, 517, + 894, 1449, 685, 806, 1450, 997, 1448, 1067, 494, 495, + 923, 1375, 1408, 224, 215, 879, 225, 226, 227, 229, + 1214, 228, 234, 879, 438, 1094, 216, 219, 71, 213, + 233, 232, 922, 299, 51, 208, 208, 208, 883, 335, + 1208, 81, 1456, 1131, 884, 1351, 1349, 81, 515, 983, + 501, 505, 1395, 1104, 1092, 1102, 54, 879, 719, 944, + 508, 1414, 876, 874, 517, 875, 757, 523, 512, 1302, + 872, 878, 761, 604, 1301, 927, 552, 460, 461, 462, + 1133, 1457, 603, 1082, 612, 51, 759, 760, 758, 778, + 929, 779, 445, 251, 961, 962, 963, 1388, 1081, 516, + 515, 1070, 567, 582, 584, 586, 588, 590, 592, 593, + 613, 578, 619, 1135, 1416, 1139, 517, 1134, 1051, 1132, + 1052, 1093, 1391, 1323, 1137, 1299, 1098, 1095, 1088, 1096, + 1091, 22, 609, 1136, 1089, 1090, 535, 536, 537, 538, + 539, 532, 1114, 982, 542, 981, 1138, 1140, 1097, 208, + 516, 515, 1079, 1230, 81, 1347, 1433, 1156, 497, 208, + 208, 81, 516, 515, 1062, 208, 194, 517, 208, 447, + 448, 208, 725, 729, 730, 208, 1057, 81, 81, 517, + 1419, 497, 81, 81, 81, 81, 81, 81, 744, 746, + 747, 250, 81, 81, 745, 780, 633, 702, 533, 534, + 535, 536, 537, 538, 539, 532, 687, 688, 542, 724, + 1347, 1404, 694, 1347, 497, 328, 1347, 1382, 700, 705, + 81, 516, 515, 701, 208, 686, 516, 515, 1347, 1346, + 81, 324, 325, 1290, 1289, 1417, 731, 684, 517, 703, + 681, 697, 466, 517, 1277, 497, 1357, 469, 459, 469, + 616, 469, 469, 1356, 469, 1172, 469, 288, 287, 290, + 291, 292, 293, 1274, 497, 469, 289, 294, 1353, 755, + 1210, 740, 1220, 1219, 81, 1216, 1217, 752, 1216, 1215, + 976, 497, 825, 497, 1043, 51, 789, 497, 58, 733, + 796, 800, 617, 720, 615, 748, 807, 750, 632, 631, + 551, 881, 335, 553, 791, 1160, 81, 81, 1172, 848, + 789, 615, 1270, 208, 1359, 825, 1218, 1120, 741, 742, + 1053, 208, 208, 1043, 992, 208, 208, 825, 976, 81, + 24, 564, 756, 568, 569, 570, 571, 572, 573, 574, + 575, 576, 81, 579, 581, 583, 585, 587, 589, 591, + 587, 594, 595, 596, 597, 598, 599, 600, 818, 610, + 823, 976, 849, 803, 781, 782, 1172, 853, 991, 990, + 987, 567, 985, 850, 794, 795, 1007, 1006, 54, 1442, + 976, 615, 889, 890, 891, 892, 895, 896, 897, 847, + 618, 852, 851, 824, 208, 81, 24, 81, 900, 901, + 902, 81, 81, 208, 208, 868, 208, 208, 24, 727, + 208, 81, 695, 989, 986, 909, 984, 609, 825, 54, + 1013, 609, 1425, 1398, 1014, 1308, 1297, 208, 859, 208, + 208, 888, 208, 1282, 252, 908, 1328, 792, 793, 1201, + 1056, 912, 904, 802, 54, 809, 297, 905, 906, 899, + 934, 935, 898, 938, 939, 1438, 54, 940, 1176, 1177, + 1108, 911, 1203, 1179, 1160, 817, 1083, 819, 820, 830, + 833, 834, 835, 831, 942, 832, 836, 469, 79, 948, + 739, 752, 54, 721, 469, 699, 1030, 1028, 1182, 1181, + 1027, 1031, 1029, 1026, 751, 1032, 953, 834, 835, 954, + 469, 469, 755, 256, 257, 469, 469, 469, 469, 469, + 469, 1429, 1422, 1116, 337, 469, 469, 949, 511, 1427, + 959, 958, 499, 1074, 630, 966, 467, 950, 951, 1066, + 505, 1304, 1397, 509, 500, 1396, 208, 208, 208, 208, + 208, 1020, 1326, 830, 833, 834, 835, 831, 208, 832, + 836, 208, 1064, 1176, 1177, 208, 1058, 1015, 1268, 208, + 914, 698, 838, 253, 254, 756, 511, 957, 247, 996, + 1364, 248, 58, 1363, 81, 956, 791, 1310, 1043, 490, + 1444, 1443, 60, 716, 513, 1444, 1054, 51, 1378, 1296, + 335, 722, 977, 62, 1045, 614, 1044, 55, 1022, 1023, + 1033, 1025, 568, 865, 1, 1021, 960, 1041, 1024, 998, + 1436, 1229, 1305, 920, 1046, 1063, 1399, 1340, 1195, 871, + 862, 69, 81, 81, 1073, 437, 1075, 1076, 1077, 1071, + 1072, 68, 609, 609, 609, 609, 609, 1059, 1060, 1389, + 870, 869, 1348, 1294, 840, 882, 1068, 609, 610, 885, + 1202, 81, 1394, 975, 1065, 609, 638, 636, 1080, 637, + 337, 635, 337, 640, 337, 337, 208, 337, 639, 337, + 634, 994, 1099, 221, 330, 81, 837, 626, 337, 910, + 514, 72, 1086, 1101, 1100, 916, 484, 485, 223, 550, + 955, 496, 1047, 336, 1167, 1113, 728, 503, 751, 1362, + 1309, 995, 577, 804, 273, 743, 286, 283, 520, 285, + 284, 734, 1012, 1118, 524, 271, 263, 608, 469, 601, + 469, 1153, 829, 827, 1124, 1123, 826, 81, 81, 1161, + 1020, 468, 1129, 1141, 469, 1142, 1178, 1174, 607, 1119, + 1263, 1373, 738, 752, 26, 59, 258, 19, 1115, 18, + 17, 81, 1166, 20, 16, 15, 14, 455, 1164, 30, + 21, 13, 12, 1171, 81, 11, 81, 81, 10, 1187, + 9, 8, 7, 1180, 6, 5, 4, 337, 1194, 249, + 23, 2, 0, 627, 0, 965, 1186, 0, 0, 1189, + 0, 0, 0, 0, 208, 1193, 1198, 1199, 1200, 0, + 1155, 0, 1211, 1212, 0, 0, 0, 0, 0, 0, + 0, 208, 0, 0, 0, 0, 0, 81, 0, 0, + 81, 81, 208, 0, 0, 0, 0, 0, 81, 0, + 0, 208, 0, 0, 0, 865, 0, 0, 0, 0, + 0, 1221, 0, 0, 265, 0, 1188, 1234, 0, 0, + 0, 0, 0, 1222, 0, 1016, 1017, 0, 1224, 610, + 610, 610, 610, 610, 1235, 1223, 0, 1225, 1236, 1233, + 1243, 0, 1240, 1241, 840, 1242, 1040, 0, 1244, 0, + 1246, 0, 610, 0, 0, 0, 0, 0, 0, 1020, + 337, 0, 0, 1269, 0, 0, 0, 337, 1278, 0, + 0, 0, 0, 0, 81, 1279, 0, 0, 0, 0, + 0, 0, 81, 337, 337, 0, 1054, 1288, 337, 337, + 337, 337, 337, 337, 0, 0, 0, 609, 337, 337, + 0, 0, 81, 0, 0, 0, 1122, 0, 1291, 81, + 0, 0, 0, 0, 0, 0, 469, 477, 0, 478, + 479, 0, 480, 732, 483, 1298, 735, 1300, 0, 1265, + 1147, 0, 0, 493, 0, 0, 520, 0, 567, 337, + 0, 0, 0, 0, 469, 0, 1280, 0, 0, 1281, + 0, 1311, 1283, 0, 0, 81, 81, 0, 81, 0, + 0, 0, 0, 81, 0, 81, 81, 81, 208, 1327, + 0, 81, 1335, 0, 1336, 1337, 1338, 0, 1334, 1329, + 783, 788, 790, 0, 1164, 1339, 1345, 0, 0, 81, + 798, 798, 0, 0, 0, 865, 798, 865, 1361, 1354, + 0, 1355, 540, 541, 533, 534, 535, 536, 537, 538, + 539, 532, 815, 816, 542, 0, 0, 0, 1165, 0, + 51, 0, 0, 1379, 0, 0, 0, 0, 81, 1387, + 0, 1386, 0, 0, 0, 337, 1380, 0, 0, 0, + 81, 81, 1164, 0, 0, 0, 0, 0, 337, 0, + 1402, 0, 1406, 1403, 0, 0, 0, 0, 0, 1122, + 0, 0, 81, 0, 1411, 1020, 0, 0, 0, 0, + 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, + 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, + 556, 557, 558, 559, 560, 561, 562, 563, 1421, 0, + 0, 337, 0, 337, 1426, 1428, 81, 932, 933, 0, + 0, 0, 0, 0, 0, 1430, 0, 337, 0, 1441, + 1415, 0, 0, 0, 610, 0, 1452, 0, 0, 0, + 0, 0, 0, 0, 0, 865, 1405, 567, 0, 0, + 0, 0, 0, 337, 0, 682, 0, 0, 0, 0, + 0, 0, 689, 0, 0, 0, 1262, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 706, 707, + 1307, 0, 0, 708, 709, 710, 711, 712, 713, 0, + 0, 0, 0, 714, 715, 0, 0, 1284, 1285, 1286, + 0, 0, 0, 0, 0, 0, 973, 0, 0, 0, + 974, 0, 0, 0, 0, 0, 0, 978, 979, 980, + 0, 0, 0, 0, 0, 0, 0, 0, 993, 1260, + 497, 0, 0, 999, 1000, 469, 1001, 1002, 1003, 1004, + 1005, 0, 0, 1008, 1009, 1010, 1011, 0, 0, 0, + 0, 798, 531, 530, 540, 541, 533, 534, 535, 536, + 537, 538, 539, 532, 0, 1035, 542, 531, 530, 540, + 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, + 0, 542, 1257, 497, 1165, 0, 0, 1330, 0, 0, + 337, 0, 531, 530, 540, 541, 533, 534, 535, 536, + 537, 538, 539, 532, 0, 971, 542, 0, 0, 0, + 0, 1307, 865, 0, 0, 0, 0, 0, 1358, 0, + 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, + 539, 532, 1254, 497, 542, 0, 0, 0, 1084, 337, + 0, 0, 1165, 0, 51, 0, 0, 0, 0, 753, + 0, 0, 762, 763, 764, 765, 766, 767, 768, 769, + 770, 771, 772, 773, 774, 775, 776, 337, 0, 0, + 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, + 539, 532, 0, 0, 542, 0, 0, 0, 0, 0, + 0, 337, 0, 0, 0, 0, 913, 0, 915, 0, + 0, 1128, 0, 0, 0, 0, 808, 0, 810, 0, + 811, 0, 941, 497, 812, 337, 813, 0, 0, 814, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 502, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 798, 0, 0, 1168, 1170, 0, 0, 0, 1439, 0, + 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, + 539, 532, 0, 0, 542, 0, 206, 1170, 0, 235, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 337, 0, 337, 1197, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 262, 0, 0, 206, 526, 0, + 529, 0, 206, 0, 206, 0, 543, 544, 545, 546, + 547, 548, 549, 0, 527, 528, 525, 531, 530, 540, + 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, + 0, 542, 0, 1226, 0, 0, 1231, 1232, 0, 0, + 0, 0, 0, 0, 337, 0, 0, 0, 0, 1237, + 0, 0, 0, 0, 0, 0, 1239, 0, 0, 0, + 0, 0, 1251, 497, 0, 0, 0, 1248, 1249, 1250, + 0, 1253, 0, 0, 1256, 0, 1259, 0, 0, 0, + 0, 0, 0, 0, 967, 968, 969, 0, 0, 0, + 0, 1271, 1272, 1273, 0, 1276, 0, 0, 0, 798, + 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, + 539, 532, 1287, 0, 542, 0, 0, 0, 1267, 0, + 337, 0, 0, 0, 1085, 0, 206, 0, 1293, 206, + 0, 0, 0, 1266, 0, 206, 0, 0, 0, 0, + 0, 206, 0, 0, 1261, 0, 0, 0, 337, 0, + 0, 0, 1112, 0, 0, 337, 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, 0, - 542, 31, 32, 34, 33, 36, 0, 50, 0, 531, + 542, 531, 530, 540, 541, 533, 534, 535, 536, 537, + 538, 539, 532, 0, 0, 542, 0, 0, 0, 1322, 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, - 532, 1208, 0, 542, 1213, 1214, 0, 0, 37, 44, - 45, 0, 337, 46, 47, 35, 0, 0, 734, 0, - 0, 0, 0, 0, 206, 0, 0, 206, 39, 40, - 0, 41, 42, 206, 0, 0, 0, 0, 0, 206, - 1247, 0, 0, 0, 0, 0, 218, 0, 0, 567, - 0, 0, 0, 0, 0, 0, 0, 1262, 0, 0, - 1263, 0, 0, 1265, 1243, 0, 477, 792, 478, 479, - 231, 480, 0, 483, 0, 0, 0, 0, 0, 0, - 0, 0, 493, 0, 0, 0, 0, 0, 337, 1108, - 1109, 0, 0, 0, 0, 0, 1275, 0, 0, 0, - 0, 811, 1125, 1126, 1127, 1128, 0, 1130, 1131, 1132, - 1133, 0, 0, 0, 838, 0, 337, 53, 1139, 1140, - 0, 211, 0, 337, 0, 0, 0, 0, 214, 0, - 0, 0, 0, 0, 0, 0, 222, 217, 531, 530, + 532, 1331, 1332, 542, 1333, 0, 0, 0, 0, 1293, + 0, 1293, 1293, 1293, 0, 0, 0, 1197, 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, - 0, 0, 542, 206, 206, 206, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 220, 1313, - 1314, 0, 1315, 0, 230, 0, 0, 1275, 0, 1275, - 1275, 1275, 900, 0, 0, 1179, 0, 0, 0, 0, - 0, 922, 923, 0, 926, 927, 0, 0, 928, 0, - 212, 0, 0, 1275, 530, 540, 541, 533, 534, 535, - 536, 537, 538, 539, 532, 930, 0, 542, 0, 0, - 936, 0, 0, 0, 0, 0, 0, 224, 215, 0, - 225, 226, 227, 229, 0, 228, 234, 1220, 0, 0, - 216, 219, 1375, 213, 233, 232, 0, 1387, 567, 0, - 0, 0, 0, 0, 337, 337, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 206, 0, 0, - 0, 0, 0, 792, 0, 0, 1395, 206, 206, 0, - 0, 0, 0, 206, 0, 960, 206, 0, 0, 206, - 0, 0, 0, 698, 676, 0, 1402, 0, 0, 0, - 0, 683, 0, 0, 649, 531, 530, 540, 541, 533, - 534, 535, 536, 537, 538, 539, 532, 700, 701, 542, - 1275, 0, 702, 703, 704, 705, 706, 707, 0, 0, - 0, 0, 708, 709, 0, 0, 0, 0, 0, 0, - 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, - 0, 698, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1295, 1296, 0, 1297, 1298, 0, 1299, - 1300, 0, 1301, 1302, 1303, 0, 0, 0, 1306, 1307, - 0, 0, 637, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 262, 0, 0, 0, 0, 262, 262, - 0, 0, 793, 793, 262, 0, 0, 0, 793, 1240, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 650, - 262, 262, 262, 262, 0, 206, 0, 0, 0, 0, - 0, 0, 0, 206, 833, 0, 0, 206, 206, 0, - 0, 663, 664, 665, 666, 667, 668, 669, 1100, 670, - 671, 672, 673, 674, 651, 652, 653, 654, 635, 636, - 0, 0, 638, 0, 639, 640, 641, 642, 643, 644, - 645, 646, 647, 648, 655, 656, 657, 658, 659, 660, - 661, 662, 0, 531, 530, 540, 541, 533, 534, 535, - 536, 537, 538, 539, 532, 0, 0, 542, 1237, 0, - 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, - 0, 0, 0, 0, 0, 206, 206, 0, 206, 206, - 0, 0, 206, 0, 0, 0, 0, 0, 0, 901, - 0, 903, 0, 0, 0, 1234, 0, 0, 0, 206, - 0, 934, 935, 0, 206, 929, 0, 0, 0, 698, - 0, 1427, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 262, 0, 0, 0, 0, 0, 0, 0, 0, - 1203, 0, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 0, 0, 542, 1206, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1215, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 262, 531, - 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, - 532, 0, 0, 542, 0, 0, 262, 0, 0, 0, + 0, 0, 542, 0, 0, 1293, 0, 0, 0, 1365, + 1366, 1367, 1368, 1369, 1370, 1371, 1372, 0, 0, 0, + 1376, 1377, 0, 0, 0, 206, 206, 206, 0, 0, + 0, 0, 1383, 1384, 1385, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1393, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 337, 337, 0, 0, + 0, 0, 0, 0, 0, 0, 1126, 1127, 0, 1407, + 0, 0, 0, 0, 0, 798, 1412, 0, 1413, 1143, + 1144, 1145, 1146, 0, 1148, 1149, 1150, 1151, 0, 24, + 25, 52, 27, 28, 1258, 1418, 0, 0, 1420, 0, + 0, 1157, 1158, 0, 0, 0, 0, 0, 43, 1255, + 0, 0, 0, 29, 48, 49, 0, 0, 0, 0, + 0, 0, 1293, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 38, 0, 0, 0, 54, 0, 206, + 0, 1453, 1454, 0, 0, 0, 0, 0, 0, 206, + 206, 0, 0, 0, 0, 206, 0, 0, 206, 1252, + 0, 206, 0, 0, 0, 704, 0, 0, 531, 530, + 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, + 0, 0, 542, 531, 530, 540, 541, 533, 534, 535, + 536, 537, 538, 539, 532, 0, 0, 542, 31, 32, + 34, 33, 36, 1303, 50, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, + 1238, 0, 0, 704, 0, 37, 44, 45, 0, 0, + 46, 47, 35, 531, 530, 540, 541, 533, 534, 535, + 536, 537, 538, 539, 532, 39, 40, 542, 41, 42, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1125, 0, 0, 262, 0, 0, 0, 0, + 262, 262, 0, 0, 799, 799, 262, 0, 0, 0, + 799, 0, 531, 530, 540, 541, 533, 534, 535, 536, + 537, 538, 539, 532, 0, 655, 542, 972, 262, 262, + 262, 262, 0, 206, 0, 0, 0, 0, 0, 0, + 0, 206, 845, 0, 0, 206, 206, 531, 530, 540, + 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, + 0, 542, 0, 0, 53, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1313, 1314, 0, 1315, + 1316, 0, 1317, 1318, 0, 1319, 1320, 1321, 0, 0, + 0, 1324, 1325, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 643, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, + 0, 0, 0, 206, 206, 0, 206, 206, 0, 0, + 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 656, 0, 0, 0, 0, 0, 0, 206, 0, 946, + 947, 0, 206, 0, 0, 0, 0, 704, 0, 0, + 0, 0, 669, 670, 671, 672, 673, 674, 675, 262, + 676, 677, 678, 679, 680, 657, 658, 659, 660, 641, + 642, 0, 0, 644, 0, 645, 646, 647, 648, 649, + 650, 651, 652, 653, 654, 661, 662, 663, 664, 665, + 666, 667, 668, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 793, 206, 206, 206, 206, 206, 0, 0, 0, - 0, 0, 0, 0, 1016, 0, 0, 206, 0, 0, - 0, 833, 0, 0, 0, 206, 531, 530, 540, 541, - 533, 534, 535, 536, 537, 538, 539, 532, 0, 0, - 542, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 799, 206, 206, 206, 206, + 206, 0, 0, 0, 1445, 0, 0, 0, 1034, 0, + 0, 206, 0, 0, 0, 845, 0, 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1067, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 206, 0, 0, 0, 0, 0, 0, 1094, - 0, 0, 262, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 698, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 793, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 262, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 704, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 799, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1397, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -988,18 +1004,18 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 793, 425, 414, 0, 385, 428, 363, + 0, 0, 0, 799, 425, 414, 0, 385, 428, 363, 377, 436, 378, 379, 407, 349, 393, 138, 375, 0, 366, 344, 372, 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, 429, - 376, 405, 430, 0, 0, 0, 80, 0, 854, 855, + 376, 405, 430, 0, 0, 0, 80, 0, 866, 867, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, - 404, 406, 343, 402, 1285, 347, 350, 435, 420, 369, - 370, 1037, 0, 0, 0, 0, 0, 0, 388, 392, + 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, + 370, 1055, 0, 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, 0, 0, 0, 0, 0, 0, 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, - 386, 0, 0, 0, 353, 0, 368, 410, 833, 342, + 386, 0, 0, 0, 353, 0, 368, 410, 845, 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 417, 365, 373, 98, 371, 152, 140, 174, 398, @@ -1008,7 +1024,7 @@ var yyAct = [...]int{ 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 346, 793, + 143, 124, 144, 112, 132, 131, 133, 0, 346, 799, 159, 176, 193, 93, 361, 164, 183, 184, 185, 186, 187, 188, 0, 206, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, @@ -1020,7 +1036,7 @@ var yyAct = [...]int{ 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, 429, 376, 405, 430, 0, 0, 0, 80, - 0, 854, 855, 0, 0, 0, 0, 0, 95, 0, + 0, 866, 867, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, 0, 0, 0, 0, @@ -1076,7 +1092,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, - 382, 0, 0, 0, 0, 0, 0, 1103, 0, 367, + 382, 0, 0, 0, 0, 0, 0, 1121, 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, 386, 0, 0, 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, 0, @@ -1103,7 +1119,7 @@ var yyAct = [...]int{ 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, 0, 0, 0, 0, 0, - 743, 0, 367, 0, 399, 0, 0, 0, 351, 348, + 749, 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, 386, 0, 0, 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, 0, 161, 110, 118, 83, 89, 0, 109, @@ -1241,7 +1257,7 @@ var yyAct = [...]int{ 118, 83, 89, 0, 109, 136, 150, 154, 417, 365, 373, 98, 371, 152, 140, 174, 398, 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, - 614, 96, 155, 86, 170, 160, 128, 114, 115, 85, + 620, 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, 340, 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, @@ -1281,9 +1297,9 @@ var yyAct = [...]int{ 0, 0, 269, 0, 0, 0, 102, 0, 266, 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, - 0, 845, 0, 54, 0, 0, 267, 288, 287, 290, + 0, 857, 0, 54, 0, 0, 267, 288, 287, 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, - 846, 0, 0, 264, 281, 0, 308, 0, 0, 0, + 858, 0, 0, 264, 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, 279, 0, 0, 0, 0, 322, 0, 280, 0, 0, 275, 276, 277, @@ -1303,7 +1319,7 @@ var yyAct = [...]int{ 157, 310, 321, 316, 317, 314, 315, 313, 312, 311, 323, 302, 303, 304, 305, 307, 0, 318, 319, 306, 82, 0, 120, 190, 147, 105, 177, 138, 0, 0, - 779, 0, 269, 0, 0, 0, 102, 0, 266, 0, + 785, 0, 269, 0, 0, 0, 102, 0, 266, 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 267, 288, 287, 290, @@ -1440,7 +1456,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, - 0, 152, 140, 174, 1428, 141, 151, 122, 166, 146, + 0, 152, 140, 174, 1446, 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, @@ -1455,7 +1471,7 @@ var yyAct = [...]int{ 105, 177, 0, 0, 0, 102, 0, 0, 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 267, 288, 287, 290, 291, + 0, 0, 54, 0, 497, 267, 288, 287, 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, 0, 0, 0, 0, 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1477,17 +1493,17 @@ var yyAct = [...]int{ 310, 321, 316, 317, 314, 315, 313, 312, 311, 323, 302, 303, 304, 305, 307, 0, 318, 319, 306, 82, 138, 120, 190, 147, 105, 177, 0, 0, 0, 102, - 0, 0, 0, 0, 0, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 531, 530, 540, 541, 533, - 534, 535, 536, 537, 538, 539, 532, 0, 0, 542, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 119, 309, 121, 0, 0, + 158, 130, 0, 0, 0, 0, 300, 301, 0, 0, + 0, 0, 0, 0, 0, 0, 54, 0, 0, 267, + 288, 287, 290, 291, 292, 293, 0, 0, 95, 289, + 294, 295, 296, 0, 0, 0, 0, 281, 0, 308, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, + 279, 0, 0, 0, 0, 322, 0, 280, 0, 0, + 275, 276, 277, 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, + 320, 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, @@ -1498,43 +1514,115 @@ var yyAct = [...]int{ 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 0, 0, 0, 519, - 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, + 153, 97, 175, 157, 310, 321, 316, 317, 314, 315, + 313, 312, 311, 323, 302, 303, 304, 305, 307, 0, + 318, 319, 306, 82, 138, 120, 190, 147, 105, 177, + 0, 0, 0, 102, 0, 0, 0, 0, 0, 119, + 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, + 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 531, + 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, + 532, 0, 0, 542, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, + 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, + 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, + 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, + 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, + 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, + 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, + 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, + 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, + 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, + 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, + 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, + 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, + 0, 0, 0, 519, 0, 0, 0, 82, 102, 120, + 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, + 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, + 521, 0, 0, 0, 0, 0, 0, 95, 0, 0, + 0, 0, 0, 516, 515, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 517, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, + 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, + 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, + 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, + 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, + 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, + 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, + 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, + 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, + 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, + 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, + 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, + 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, + 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, + 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 80, 0, 521, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 516, - 515, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 517, 0, 0, 0, + 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, + 0, 0, 95, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, - 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 76, 77, + 0, 73, 0, 0, 0, 78, 145, 0, 161, 110, + 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, + 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, + 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, + 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, + 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, + 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, + 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, + 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, + 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, + 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, + 123, 148, 191, 139, 153, 97, 175, 157, 0, 75, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, + 0, 0, 0, 844, 0, 0, 0, 82, 102, 120, + 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, + 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, + 846, 0, 0, 0, 0, 0, 0, 95, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, + 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, + 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, + 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, + 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, + 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, + 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, + 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, + 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, + 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, + 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, + 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, + 97, 175, 157, 0, 0, 0, 0, 0, 24, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 138, 0, 82, 0, 120, 190, 147, 105, 177, 102, + 0, 0, 0, 0, 0, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, + 0, 0, 0, 0, 0, 0, 54, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 76, 77, 0, 73, 0, 0, - 0, 78, 145, 0, 161, 110, 118, 83, 89, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, + 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, @@ -1545,36 +1633,36 @@ var yyAct = [...]int{ 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 75, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 0, 0, 0, 832, - 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, + 153, 97, 175, 157, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 207, 0, 834, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, + 0, 138, 0, 82, 0, 120, 190, 147, 105, 177, + 102, 0, 0, 0, 0, 0, 119, 0, 121, 0, + 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 207, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 138, 0, 82, 0, - 120, 190, 147, 105, 177, 102, 0, 0, 0, 0, - 0, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 0, 80, 0, 0, 0, 0, + 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, + 0, 0, 0, 145, 0, 161, 110, 118, 83, 89, + 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, + 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, + 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, + 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, + 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, + 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, + 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, + 133, 0, 0, 0, 159, 176, 193, 93, 0, 164, + 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, + 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, + 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 138, 0, 0, 0, + 844, 0, 0, 0, 82, 102, 120, 190, 147, 105, + 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 207, 0, 846, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1583,7 +1671,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, - 0, 0, 0, 98, 0, 152, 140, 174, 0, 141, + 0, 0, 0, 98, 0, 152, 140, 174, 0, 842, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, @@ -1593,10 +1681,57 @@ var yyAct = [...]int{ 176, 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, - 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 138, 0, 82, - 0, 120, 190, 147, 105, 177, 102, 0, 0, 0, - 0, 0, 119, 0, 121, 0, 0, 158, 130, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 138, 0, 0, 0, 0, 0, 0, 0, 82, + 102, 120, 190, 147, 105, 177, 119, 0, 121, 0, + 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 0, 736, 0, 0, 737, 0, 0, 95, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, + 0, 0, 0, 145, 0, 161, 110, 118, 83, 89, + 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, + 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, + 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, + 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, + 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, + 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, + 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, + 133, 0, 0, 0, 159, 176, 193, 93, 0, 164, + 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, + 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, + 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 138, 0, 82, 0, 120, 190, 147, 105, + 177, 102, 0, 629, 0, 0, 0, 119, 0, 121, + 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 80, 0, 628, 0, 0, 0, 0, 0, 0, + 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, + 0, 0, 0, 0, 145, 0, 161, 110, 118, 83, + 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, + 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, + 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, + 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, + 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, + 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, + 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, + 131, 133, 0, 0, 0, 159, 176, 193, 93, 0, + 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, + 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, + 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, + 0, 0, 0, 0, 0, 82, 102, 120, 190, 147, + 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, @@ -1618,11 +1753,11 @@ var yyAct = [...]int{ 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 138, 0, 0, 0, 832, 0, 0, 0, + 0, 0, 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 207, 0, 834, 0, 0, 0, 0, 0, 0, + 0, 207, 0, 846, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1631,7 +1766,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, - 0, 152, 140, 174, 0, 830, 151, 122, 166, 146, + 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, @@ -1645,8 +1780,8 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 80, 0, 0, 730, - 0, 0, 731, 0, 0, 95, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 267, 0, 801, 0, + 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1665,302 +1800,208 @@ var yyAct = [...]int{ 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, - 82, 0, 120, 190, 147, 105, 177, 102, 0, 623, - 0, 0, 0, 119, 0, 121, 0, 0, 158, 130, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 80, 0, 622, - 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 138, 0, 0, 0, 0, 0, 0, 0, + 82, 102, 120, 190, 147, 105, 177, 119, 0, 121, + 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 267, 0, 797, 0, 0, 0, 0, 0, 0, + 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, - 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, - 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, - 0, 0, 207, 0, 0, 0, 0, 0, 0, 0, - 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, + 0, 0, 0, 0, 145, 0, 161, 110, 118, 83, + 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, + 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, + 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, + 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, + 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, + 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, + 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, + 131, 133, 0, 0, 0, 159, 176, 193, 93, 0, + 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, + 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, + 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, + 0, 0, 0, 0, 0, 82, 102, 120, 190, 147, + 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 80, 0, 521, 0, + 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, - 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, - 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, - 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, - 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, - 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, - 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, - 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, - 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, - 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, - 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, - 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, - 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, - 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, - 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 207, 0, 834, - 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 108, 0, 0, 0, 209, 0, 0, 0, 0, 145, + 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, + 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, + 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, + 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, + 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, + 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, + 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, + 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, + 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, + 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, + 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, + 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, + 82, 0, 120, 190, 147, 105, 177, 602, 102, 0, + 0, 0, 0, 0, 119, 0, 121, 0, 0, 158, + 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, + 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, - 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, - 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 267, 0, 795, 0, 0, 0, 0, 0, - 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, + 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, + 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, + 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, + 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, + 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, + 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, + 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, + 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, + 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, + 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, + 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, + 97, 175, 157, 0, 0, 0, 0, 326, 0, 0, + 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, + 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, + 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, + 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, - 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, - 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, - 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, - 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, - 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, - 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, - 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, - 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, - 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, - 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, - 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, - 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, - 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, - 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 267, 0, 791, - 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, + 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, + 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, + 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, + 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, + 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, + 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, + 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, + 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, + 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, + 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, + 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, + 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, + 0, 0, 0, 0, 0, 0, 0, 82, 102, 120, + 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, + 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, + 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, - 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, - 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 80, 0, 521, 0, 0, 0, 0, 0, - 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 204, 0, 209, 0, 0, 0, + 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, + 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, + 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, + 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, + 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, + 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, + 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, + 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, + 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, + 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, + 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, + 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, + 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, + 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, + 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, - 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, - 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, - 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, - 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, - 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, - 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, - 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, - 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, - 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, - 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, - 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, - 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 82, 0, 120, 190, - 147, 105, 177, 596, 102, 0, 0, 0, 0, 0, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, + 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, + 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, + 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, + 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, + 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, + 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, + 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, + 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, + 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, + 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, + 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, + 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, + 0, 0, 0, 0, 0, 0, 0, 82, 102, 120, + 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, + 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, + 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 0, 0, 0, 326, 0, 0, 0, 0, 0, 0, - 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, - 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, + 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, + 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, + 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, + 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, + 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, + 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, + 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, + 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, + 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, + 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, + 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, + 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, + 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, + 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, + 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, - 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, + 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, + 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, + 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, + 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, + 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, + 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, + 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, + 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, + 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, + 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, + 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, + 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 204, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, - 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, - 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, - 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 267, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 82, 0, 120, 190, 147, 105, 177, + 0, 0, 0, 0, 0, 0, 0, 82, 0, 120, + 190, 147, 105, 177, } var yyPact = [...]int{ - 1626, -1000, -185, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 2123, -1000, -193, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 836, 880, -1000, -1000, -1000, -1000, -1000, -1000, - 213, 8072, 35, 87, -17, 11387, 86, 1773, 11857, -1000, - -13, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -78, -107, - -1000, 706, -1000, -1000, -1000, -1000, -1000, 833, 839, 720, - 828, 763, -1000, 6369, 59, 59, 11152, 5369, -1000, -1000, - 201, 11857, 80, 11857, -156, 55, 55, 55, -1000, -1000, + -1000, -1000, 847, 867, -1000, -1000, -1000, -1000, -1000, -1000, + 228, 8486, 25, 102, -7, 11801, 101, 89, 12271, -1000, + 7, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -96, -103, + -1000, 614, -1000, -1000, -1000, -1000, -1000, 841, 845, 718, + 833, 753, -1000, 6539, 68, 68, 11566, 5539, -1000, -1000, + 224, 12271, 86, 12271, -161, 62, 62, 62, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -1972,22 +2013,22 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 84, 11857, 178, -1000, 11857, 53, - 522, 53, 53, 53, 11857, -1000, 123, -1000, -1000, -1000, - 11857, 483, 795, 3265, 42, 3265, -1000, 3265, 3265, -1000, - 3265, 4, 3265, -80, 850, -1000, -1000, -1000, -1000, -21, - -1000, 3265, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 482, 801, 6870, 6870, 836, - -1000, 706, -1000, -1000, -1000, 788, -1000, -1000, 256, 864, - -1000, 7837, 121, -1000, 6870, 1412, 694, -1000, -1000, 694, - -1000, -1000, 111, -1000, -1000, 7358, 7358, 7358, 7358, 7358, - 7358, 7358, 7358, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 694, -1000, 6620, - 694, 694, 694, 694, 694, 694, 694, 694, 6870, 694, - 694, 694, 694, 694, 694, 694, 694, 694, 694, 694, - 694, 694, 694, 694, 10917, 9735, 11857, 647, -1000, 687, - 5106, -103, -1000, -1000, -1000, 217, 9500, -1000, -1000, -1000, - 793, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 99, 12271, 168, -1000, 12271, 61, + 481, 61, 61, 61, 12271, -1000, 144, -1000, -1000, -1000, + 12271, 475, 786, 3435, 36, 3435, -1000, 3435, 3435, -1000, + 3435, 13, 3435, -62, 857, -1000, -1000, -1000, -1000, -50, + -1000, 3435, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 392, 793, 7040, 7040, 847, + -1000, 614, -1000, -1000, -1000, 787, -1000, -1000, 293, 863, + -1000, 8251, 142, -1000, 7040, 1734, 655, -1000, -1000, 655, + -1000, -1000, 114, -1000, -1000, 7772, 7772, 7772, 7772, 7772, + 7772, 7772, 7772, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 655, -1000, 6790, + 655, 655, 655, 655, 655, 655, 655, 655, 7040, 655, + 655, 655, 655, 655, 655, 655, 655, 655, 655, 655, + 655, 655, 655, 655, 11331, 10149, 12271, 529, -1000, 625, + 5276, -90, -1000, -1000, -1000, 204, 9914, -1000, -1000, -1000, + 784, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -1996,130 +2037,132 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 580, 11857, -1000, - 2034, -1000, 477, 3265, 65, 464, 244, 462, 11857, 11857, - 3265, 12, 30, 83, 11857, 689, 63, 11857, 819, 738, - 11857, 454, 452, -1000, 4843, -1000, 3265, 3265, -1000, -1000, - -1000, 3265, 3265, 3265, 3265, 3265, 3265, -1000, -1000, -1000, - -1000, 3265, 3265, -1000, 852, 236, -1000, -1000, -1000, -1000, - 6870, -1000, 737, -1000, -1000, -1000, -1000, -1000, -1000, 875, - 152, 620, 119, 688, -1000, 380, 833, 482, 763, 9259, - 729, -1000, -1000, 11857, -1000, 6870, 6870, 430, -1000, 10675, - -1000, -1000, 3791, 170, 7358, 354, 299, 7358, 7358, 7358, - 7358, 7358, 7358, 7358, 7358, 7358, 7358, 7358, 7358, 7358, - 7358, 7358, 407, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 445, -1000, 706, 540, 540, 132, 132, 132, 132, - 132, 132, 132, 7602, 5869, 482, 578, 368, 6620, 6369, - 6369, 6870, 6870, 10440, 10205, 6369, 823, 230, 368, 12092, - -1000, 482, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 11622, - 11622, 6369, 6369, 6369, 6369, 22, 11857, -1000, 646, 719, - -1000, -1000, -1000, 821, 8789, 9024, 22, 655, 9735, 11857, - -1000, -1000, 4580, 687, -103, 679, -1000, -133, -123, 5619, - 131, -1000, -1000, -1000, -1000, 3002, 206, 581, 265, -69, - -1000, -1000, -1000, 702, -1000, 702, 702, 702, 702, -38, - -38, -38, -38, -1000, -1000, -1000, -1000, -1000, 725, 723, - -1000, 702, 702, 702, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 533, 12271, -1000, + 2305, -1000, 473, 3435, 77, 470, 218, 458, 12271, 12271, + 3435, 20, 51, 92, 12271, 647, 75, 12271, 828, 723, + 12271, 456, 430, -1000, 5013, -1000, 3435, 3435, -1000, -1000, + -1000, 3435, 3435, 3435, 3435, 3435, 3435, -1000, -1000, -1000, + -1000, 3435, 3435, -1000, 862, 256, -1000, -1000, -1000, -1000, + 7040, -1000, 721, -1000, -1000, -1000, -1000, -1000, -1000, 872, + 171, 444, 141, 644, -1000, 439, 841, 392, 753, 9673, + 727, -1000, -1000, 12271, -1000, 7040, 7040, 410, -1000, 11089, + -1000, -1000, 3961, 180, 7772, 292, 286, 7772, 7772, 7772, + 7772, 7772, 7772, 7772, 7772, 7772, 7772, 7772, 7772, 7772, + 7772, 7772, 322, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 428, -1000, 614, 489, 489, 148, 148, 148, 148, + 148, 148, 148, 8016, 6039, 392, 521, 200, 6790, 6539, + 6539, 7040, 7040, 10854, 10619, 6539, 835, 209, 200, 12506, + -1000, 7528, -1000, 7528, -1000, 7528, -1000, 392, -1000, 7528, + -1000, 7528, -1000, -1000, 7528, 12036, 12036, 6539, 6539, 6539, + 6539, 32, 12271, -1000, 653, 717, -1000, -1000, -1000, 830, + 9203, 9438, 32, 546, 10149, 12271, -1000, -1000, 4750, 625, + -90, 602, -1000, -129, -125, 5789, 119, -1000, -1000, -1000, + -1000, 3172, 223, 535, 260, -61, -1000, -1000, -1000, 667, + -1000, 667, 667, 667, 667, -20, -20, -20, -20, -1000, + -1000, -1000, -1000, -1000, 688, 685, -1000, 667, 667, 667, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 722, 722, 722, 704, 704, 697, -1000, 11857, 3265, 818, - 3265, -1000, 125, -1000, 11622, 11622, 11857, 11857, 95, 11857, - 11857, 683, -1000, 11857, 3265, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 678, 678, 678, 671, + 671, 698, -1000, 12271, 3435, 827, 3435, -1000, 113, -1000, + 12036, 12036, 12271, 12271, 120, 12271, 12271, 616, -1000, 12271, + 3435, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 12271, 259, 12271, 12271, + 200, 12271, -1000, 769, 7040, 7040, 4487, 7040, -1000, -1000, + -1000, 793, -1000, 835, 846, -1000, 777, 776, 6539, -1000, + -1000, 180, 265, -1000, -1000, 316, -1000, -1000, -1000, -1000, + 137, 655, -1000, 1509, -1000, -1000, -1000, -1000, 292, 7772, + 7772, 7772, 1469, 1509, 2264, 1227, 1906, 148, 327, 327, + 153, 153, 153, 153, 153, 391, 391, -1000, -1000, -1000, + 392, -1000, -1000, -1000, 392, 6539, 615, -1000, -1000, 7040, + -1000, 392, 515, 515, 380, 317, 651, 649, -1000, 136, + 648, 603, 515, 6539, 215, -1000, 7040, 392, 1667, -1000, + 1667, 1667, 1667, 1667, 1667, 612, 611, 515, 392, 515, + 515, 680, 655, -1000, 12506, 10149, 10149, 10149, 10149, 10149, + -1000, 741, 738, -1000, 735, 734, 743, 12271, -1000, 517, + 9203, 143, 655, -1000, 10384, -1000, -1000, 856, 10149, 562, + -1000, -1000, 602, -90, -131, -1000, -1000, -1000, -1000, 200, + -1000, 351, 555, 2909, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 676, 409, -1000, 818, 189, 181, 397, 814, -1000, + -1000, -1000, 790, -1000, 229, -60, -1000, -1000, 331, -20, + -20, -1000, -1000, 119, 783, 119, 119, 119, 383, 383, + -1000, -1000, -1000, -1000, 328, -1000, -1000, -1000, 313, -1000, + 704, 12036, 3435, -1000, -1000, -1000, -1000, 287, 287, 219, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 11857, 242, 11857, 11857, 368, 11857, -1000, 770, 6870, 6870, - 4317, 6870, -1000, -1000, -1000, 801, -1000, 823, 835, -1000, - 785, 777, 6369, -1000, -1000, 170, 240, -1000, -1000, 277, - -1000, -1000, -1000, -1000, 117, 694, -1000, 2333, -1000, -1000, - -1000, -1000, 354, 7358, 7358, 7358, 448, 2333, 1972, 389, - 1870, 132, 149, 149, 133, 133, 133, 133, 133, 550, - 550, -1000, -1000, -1000, 482, -1000, -1000, -1000, 482, 6369, - 682, -1000, -1000, 6870, -1000, 482, 569, 569, 390, 365, - 696, 692, -1000, 116, 686, 651, 569, 6369, 229, -1000, - 6870, 482, -1000, 681, 680, 569, 482, 569, 569, 610, - 694, -1000, 12092, 9735, 9735, 9735, 9735, 9735, -1000, 758, - 753, -1000, 751, 750, 757, 11857, -1000, 574, 8789, 134, - 694, -1000, 9970, -1000, -1000, 847, 9735, 644, -1000, -1000, - 679, -103, -138, -1000, -1000, -1000, -1000, 368, -1000, 421, - 667, 2739, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 721, - 440, -1000, 811, 173, 165, 438, 810, -1000, -1000, -1000, - 802, -1000, 246, -74, -1000, -1000, 341, -38, -38, -1000, - -1000, 131, 792, 131, 131, 131, 412, 412, -1000, -1000, - -1000, -1000, 328, -1000, -1000, -1000, 326, -1000, 736, 11622, - 3265, -1000, -1000, -1000, -1000, 283, 283, 180, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 21, - 693, -1000, -1000, -1000, 11, 9, 62, -1000, 3265, -1000, - 236, -1000, 400, 6870, -1000, -1000, -1000, 767, 368, 368, - 115, -1000, -1000, 11857, -1000, -1000, -1000, -1000, 634, -1000, - -1000, -1000, 3528, 6369, -1000, 448, 2333, 1483, -1000, 7358, - 7358, -1000, -1000, 569, 6369, 368, -1000, -1000, -1000, 112, - 407, 112, 7358, 7358, 7358, 7358, 4317, 7358, 7358, 7358, - 7358, -168, 616, 219, -1000, 6870, 330, -1000, 7358, 7358, - -1000, -1000, -1000, -1000, 735, 12092, 694, -1000, 8548, 11622, - 684, -1000, 190, 719, 718, 733, 675, -1000, -1000, -1000, - -1000, 752, -1000, 749, -1000, -1000, -1000, -1000, -1000, 79, - 76, 70, 11622, -1000, 836, 6870, 644, -1000, -1000, -1000, - -137, -128, -1000, -1000, -1000, 3002, -1000, 3002, 11622, 39, - -1000, 438, 438, -1000, -1000, -1000, 715, 732, 74, -1000, - -1000, -1000, 571, 131, 131, -1000, 179, -1000, -1000, -1000, - 559, -1000, 556, 660, 531, 11857, -1000, -1000, -1000, -1000, + -1000, 31, 697, -1000, -1000, -1000, 19, 18, 72, -1000, + 3435, -1000, 256, -1000, 373, 7040, -1000, -1000, -1000, 764, + 200, 200, 130, -1000, -1000, 12271, -1000, -1000, -1000, -1000, + 596, -1000, -1000, -1000, 3698, 6539, -1000, 1469, 1509, 2229, + -1000, 7772, 7772, -1000, -1000, 515, 6539, 200, -1000, -1000, + -1000, 225, 322, 225, 7772, 7772, 7772, 7772, 4487, 7772, + 7772, 7772, 7772, -174, 563, 203, -1000, 7040, 368, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 7772, 7772, -1000, -1000, + -1000, -1000, 702, 12506, 655, -1000, 8962, 12036, 601, -1000, + 196, 717, 696, 701, 791, -1000, -1000, -1000, -1000, 737, + -1000, 736, -1000, -1000, -1000, -1000, -1000, 83, 82, 79, + 12036, -1000, 847, 7040, 562, -1000, -1000, -1000, -137, -145, + -1000, -1000, -1000, 3172, -1000, 3172, 12036, 48, -1000, 397, + 397, -1000, -1000, -1000, 675, 700, 88, -1000, -1000, -1000, + 504, 119, 119, -1000, 202, -1000, -1000, -1000, 513, -1000, + 510, 551, 507, 12271, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 11857, -1000, -1000, -1000, -1000, -1000, 11622, -175, - 424, 11622, 11622, 11857, -1000, 242, -1000, 368, -1000, 4054, - -1000, 847, 9735, -1000, -1000, 482, -1000, 7358, 2333, 2333, - -1000, -1000, 482, 702, 702, -1000, 702, 704, -1000, 702, - -20, 702, -22, 482, 482, 1633, 2276, 1519, 2239, -1000, - 1434, 2150, 474, 1805, 694, -163, -1000, 368, 6870, 1031, - 329, -1000, 803, 608, 615, -1000, -1000, 6119, 482, 529, - 105, 510, -1000, 836, 12092, 6870, -1000, -1000, 6870, 703, - -1000, 6870, -1000, -1000, -1000, 694, 694, 694, 510, 833, - 368, -1000, -1000, -1000, -1000, 2739, -1000, 507, -1000, 702, - -1000, -1000, -1000, 11622, -62, 873, -1000, -1000, -1000, -1000, - 701, -1000, -1000, -1000, -1000, -1000, -1000, -38, 397, -38, - 323, -1000, 281, 3265, -1000, -1000, -1000, -1000, 814, -1000, - 4054, -1000, -1000, 699, -1000, -1000, -1000, 845, 628, -1000, - 2333, -1000, -1000, 91, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 7358, 7358, -1000, 7358, 7358, -1000, 7358, - 7358, -1000, 7358, 7358, 7358, 482, 388, 368, 7358, 7358, - 808, -1000, 694, -1000, -1000, 671, 11622, 11622, -1000, 11622, - 833, -1000, 368, 368, 11622, 368, 11622, 11622, 11622, 8307, - -1000, 126, 11622, -1000, 503, -1000, 150, -1000, -146, 566, - 131, -1000, 131, 536, 533, -1000, 694, 627, -1000, 188, - 11622, 843, 837, -1000, -1000, 1656, 1656, 1656, 1656, 1656, - 1656, 1656, 1656, 24, -1000, -1000, 1656, 1656, 867, -1000, - 694, -1000, 706, 101, -1000, -1000, -1000, 501, 498, 498, - 498, 134, 126, -1000, 391, 183, 387, -1000, 34, 11622, - 253, 807, -1000, 806, 698, -1000, -1000, -1000, -1000, -1000, - 20, 4054, 3002, 481, -1000, 6870, 6870, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 482, 43, -178, -1000, -1000, - 12092, 615, 482, 11622, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 262, -1000, -1000, 11857, -1000, -1000, 347, -1000, -1000, - 504, 460, -1000, 11622, -1000, -1000, 693, 368, 588, -1000, - 766, -172, -181, 541, -1000, -1000, -1000, 695, -1000, -1000, - -1000, 20, 776, -175, -1000, 734, -1000, 11622, -1000, 17, - -1000, -176, 450, 7, -179, 731, 694, -182, 730, -1000, - 860, 7114, -1000, -1000, 862, 145, 145, 1656, 482, -1000, - -1000, -1000, 45, 313, -1000, -1000, -1000, -1000, -1000, -1000, + 12271, -1000, -1000, -1000, -1000, -1000, 12036, -179, 386, 12036, + 12036, 12271, -1000, 259, -1000, 200, -1000, 4224, -1000, 856, + 10149, -1000, -1000, 392, -1000, 7772, 1509, 1509, -1000, -1000, + 392, 667, 667, -1000, 667, 671, -1000, 667, -3, 667, + -4, 392, 392, 1817, 2180, 1587, 2130, -1000, 1537, 2115, + 1484, 1935, 655, -169, -1000, 200, 7040, 1888, 1873, -1000, + 821, 543, 547, -1000, -1000, 6289, 392, 498, 127, 479, + -1000, 847, 12506, 7040, -1000, -1000, 7040, 669, -1000, 7040, + -1000, -1000, -1000, 655, 655, 655, 479, 841, 200, -1000, + -1000, -1000, -1000, 2909, -1000, 468, -1000, 667, -1000, -1000, + -1000, 12036, -51, 870, -1000, -1000, -1000, -1000, 662, -1000, + -1000, -1000, -1000, -1000, -1000, -20, 356, -20, 304, -1000, + 299, 3435, -1000, -1000, -1000, -1000, 795, -1000, 4224, -1000, + -1000, 661, -1000, -1000, -1000, 854, 550, -1000, 1509, -1000, + -1000, 103, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 7772, 7772, -1000, 7772, 7772, -1000, 7772, 7772, -1000, + 7772, 7772, 7772, 392, 354, 200, 7772, 7772, 804, -1000, + 655, -1000, -1000, 692, 12036, 12036, -1000, 12036, 841, -1000, + 200, 200, 12036, 200, 12036, 12036, 12036, 8721, -1000, 134, + 12036, -1000, 463, -1000, 206, -1000, -151, 502, 119, -1000, + 119, 487, 480, -1000, 655, 549, -1000, 193, 12036, 849, + 844, -1000, -1000, 1667, 1667, 1667, 1667, 1667, 1667, 1667, + 1667, 37, -1000, -1000, 1667, 1667, 869, -1000, 655, -1000, + 614, 123, -1000, -1000, -1000, 451, 448, 448, 448, 143, + 134, -1000, 330, 192, 353, -1000, 44, 12036, 276, 797, + -1000, 794, 659, -1000, -1000, -1000, -1000, -1000, 30, 4224, + 3172, 445, -1000, 7040, 7040, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 392, 40, -183, -1000, -1000, 12506, 547, + 392, 12036, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 291, + -1000, -1000, 12271, -1000, -1000, 345, -1000, -1000, 469, 415, + -1000, 12036, -1000, -1000, 697, 200, 545, -1000, 763, -177, + -187, 490, -1000, -1000, -1000, 658, -1000, -1000, -1000, 30, + 775, -179, -1000, 762, -1000, 12036, -1000, 27, -1000, -180, + 390, 24, -185, 693, 655, -188, 617, -1000, 861, 7284, + -1000, -1000, 866, 155, 155, 1667, 392, -1000, -1000, -1000, + 53, 303, -1000, -1000, -1000, -1000, -1000, -1000, } var yyPgo = [...]int{ - 0, 1099, 63, 410, 1098, 1097, 1096, 1095, 1091, 1090, - 1082, 1081, 1080, 1079, 1078, 1077, 1076, 1075, 1073, 1072, - 1071, 1068, 1064, 1063, 1059, 1057, 129, 1056, 1050, 1046, - 69, 1045, 71, 1040, 1037, 46, 47, 35, 26, 661, - 1035, 59, 66, 104, 1031, 37, 1030, 1029, 73, 1028, - 49, 1027, 1026, 1264, 1024, 1022, 11, 40, 1020, 1019, - 1018, 1017, 65, 889, 1014, 1007, 1006, 994, 993, 992, - 54, 7, 10, 13, 18, 990, 460, 8, 988, 48, - 987, 985, 984, 983, 33, 982, 56, 981, 21, 55, - 980, 27, 62, 28, 17, 12, 80, 58, 978, 19, - 61, 52, 977, 976, 442, 974, 973, 41, 971, 969, - 22, 176, 435, 968, 967, 966, 965, 38, 0, 672, - 349, 75, 964, 963, 960, 1588, 70, 44, 16, 959, - 31, 1610, 34, 958, 957, 29, 956, 955, 954, 952, - 950, 948, 947, 359, 946, 945, 943, 24, 30, 942, - 941, 60, 23, 940, 939, 938, 43, 57, 937, 935, - 53, 45, 933, 932, 930, 928, 927, 25, 4, 925, - 15, 924, 9, 923, 20, 921, 2, 913, 6, 908, - 1, 907, 3, 42, 5, 906, 14, 905, 899, 50, - 246, 898, 897, 81, + 0, 1071, 25, 421, 1070, 1069, 1066, 1065, 1064, 1062, + 1061, 1060, 1058, 1055, 1052, 1051, 1050, 1049, 1047, 1046, + 1045, 1044, 1043, 1040, 1039, 1037, 97, 1036, 1035, 1034, + 76, 1032, 70, 1031, 1030, 46, 157, 49, 45, 92, + 1029, 37, 69, 61, 1028, 38, 1027, 1026, 73, 1016, + 53, 1013, 1012, 47, 1009, 1007, 11, 34, 1006, 1005, + 1004, 1002, 99, 1134, 1001, 1000, 999, 997, 996, 995, + 56, 7, 14, 33, 18, 994, 96, 6, 993, 54, + 992, 991, 990, 989, 16, 987, 58, 986, 19, 57, + 984, 9, 66, 35, 21, 5, 71, 60, 983, 22, + 63, 50, 982, 980, 456, 979, 978, 42, 977, 976, + 23, 165, 382, 975, 974, 973, 971, 44, 0, 736, + 261, 65, 970, 969, 967, 1740, 64, 52, 17, 966, + 55, 1021, 40, 964, 963, 41, 960, 958, 953, 951, + 949, 947, 946, 30, 944, 942, 940, 29, 20, 939, + 936, 59, 24, 935, 933, 932, 48, 62, 931, 930, + 51, 27, 929, 921, 915, 911, 910, 31, 12, 909, + 15, 908, 8, 907, 28, 906, 4, 903, 10, 902, + 3, 901, 13, 43, 1, 900, 2, 894, 887, 323, + 735, 885, 883, 81, } var yyR1 = [...]int{ @@ -2173,21 +2216,21 @@ var yyR1 = [...]int{ 63, 67, 67, 67, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 66, 193, 193, 68, 68, 68, - 68, 33, 33, 33, 33, 33, 132, 132, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 135, 135, 135, - 135, 80, 80, 34, 34, 78, 78, 79, 81, 81, - 77, 77, 77, 62, 62, 62, 62, 62, 62, 62, - 62, 64, 64, 64, 82, 82, 83, 83, 84, 84, - 85, 85, 86, 87, 87, 87, 88, 88, 88, 88, - 89, 89, 89, 61, 61, 61, 61, 61, 61, 90, - 90, 90, 90, 94, 94, 72, 72, 74, 74, 73, - 75, 95, 95, 99, 96, 96, 100, 100, 100, 100, - 98, 98, 98, 124, 124, 124, 103, 103, 111, 111, - 112, 112, 104, 104, 113, 113, 113, 113, 113, 113, - 113, 113, 113, 113, 114, 114, 114, 115, 115, 116, - 116, 116, 123, 123, 119, 119, 120, 120, 125, 125, - 126, 126, 117, 117, 117, 117, 117, 117, 117, 117, + 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, + 66, 193, 193, 68, 68, 68, 68, 33, 33, 33, + 33, 33, 132, 132, 135, 135, 135, 135, 135, 135, + 135, 135, 135, 135, 135, 135, 135, 80, 80, 34, + 34, 78, 78, 79, 81, 81, 77, 77, 77, 62, + 62, 62, 62, 62, 62, 62, 62, 64, 64, 64, + 82, 82, 83, 83, 84, 84, 85, 85, 86, 87, + 87, 87, 88, 88, 88, 88, 89, 89, 89, 61, + 61, 61, 61, 61, 61, 90, 90, 90, 90, 94, + 94, 72, 72, 74, 74, 73, 75, 95, 95, 99, + 96, 96, 100, 100, 100, 100, 98, 98, 98, 124, + 124, 124, 103, 103, 111, 111, 112, 112, 104, 104, + 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, + 114, 114, 114, 115, 115, 116, 116, 116, 123, 123, + 119, 119, 120, 120, 125, 125, 126, 126, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, @@ -2196,8 +2239,8 @@ var yyR1 = [...]int{ 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, + 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, + 117, 117, 117, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, @@ -2208,7 +2251,8 @@ var yyR1 = [...]int{ 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, - 189, 190, 130, 131, 131, 131, + 118, 118, 118, 118, 118, 118, 189, 190, 130, 131, + 131, 131, } var yyR2 = [...]int{ @@ -2262,21 +2306,20 @@ var yyR2 = [...]int{ 1, 4, 5, 6, 4, 4, 6, 6, 6, 6, 8, 8, 6, 8, 8, 6, 8, 8, 6, 8, 8, 9, 7, 5, 4, 2, 2, 2, 2, 2, - 2, 2, 2, 8, 8, 0, 2, 4, 4, 4, - 4, 0, 3, 4, 7, 3, 1, 1, 2, 3, - 3, 1, 2, 2, 1, 2, 1, 2, 2, 1, - 2, 0, 1, 0, 2, 1, 2, 4, 0, 2, - 1, 3, 5, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 0, 3, 0, 2, 0, 3, - 1, 3, 2, 0, 1, 1, 0, 2, 4, 4, - 0, 2, 4, 2, 1, 3, 5, 4, 6, 1, - 3, 3, 5, 0, 5, 1, 3, 1, 2, 3, - 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, - 1, 2, 1, 1, 1, 1, 1, 1, 0, 2, - 0, 3, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, - 1, 1, 0, 2, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 4, 4, 4, 4, 4, 4, 8, + 8, 0, 2, 4, 4, 4, 4, 0, 3, 4, + 7, 3, 1, 1, 2, 3, 3, 1, 2, 2, + 1, 2, 1, 2, 2, 1, 2, 0, 1, 0, + 2, 1, 2, 4, 0, 2, 1, 3, 5, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, + 0, 3, 0, 2, 0, 3, 1, 3, 2, 0, + 1, 1, 0, 2, 4, 4, 0, 2, 4, 2, + 1, 3, 5, 4, 6, 1, 3, 3, 5, 0, + 5, 1, 3, 1, 2, 3, 1, 1, 3, 3, + 1, 3, 3, 3, 3, 3, 1, 2, 1, 1, + 1, 1, 1, 1, 0, 2, 0, 3, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 0, 1, 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -2297,7 +2340,9 @@ var yyR2 = [...]int{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, + 1, 1, } var yyChk = [...]int{ @@ -2359,239 +2404,243 @@ var yyChk = [...]int{ -105, -189, -76, -189, 113, 114, -63, -63, -63, -63, -63, -63, -63, -63, -189, -2, -71, -39, -189, -189, -189, -189, -189, -189, -189, -189, -189, -80, -39, -189, - -193, -189, -193, -193, -193, -193, -193, -193, -193, -189, - -189, -189, -189, -189, -189, -54, 26, -53, -41, -42, - -43, -44, -55, -76, -189, -53, -53, -48, -191, 55, - 11, 53, 55, -96, 164, -97, -101, 233, 235, 82, - -124, -119, 59, 29, 30, 56, 55, -53, -136, -139, - -141, -140, -142, -137, -138, 184, 185, 108, 188, 190, - 191, 192, 193, 194, 195, 196, 197, 198, 199, 30, - 145, 180, 181, 182, 183, 200, 201, 202, 203, 204, - 205, 206, 207, 167, 168, 169, 170, 171, 172, 173, - 175, 176, 177, 178, 179, 57, -131, 125, 57, 74, - 57, -53, -53, -131, 157, 157, 123, 123, -53, 55, - 126, -48, 23, 52, -53, 57, 57, -126, -125, -117, - -131, -131, -131, -131, -131, -131, -131, -131, -131, -131, - 11, -107, 11, 92, -39, 52, 9, 92, 55, 18, - 112, 55, -87, 24, 25, -88, -190, -32, -64, -119, - 60, 63, -31, 43, -53, -39, -39, -69, 68, 74, - 69, 70, -121, 99, -126, -120, -117, -63, -70, -73, - -76, 64, 92, 90, 91, 76, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -132, 57, 59, 57, -62, -62, -119, -37, 21, - -36, -38, -190, 55, -190, -2, -36, -36, -39, -39, - -77, 59, -119, -125, -77, 59, -36, -30, -78, -79, - 78, -77, -190, -119, -119, -36, -37, -36, -36, -92, - 151, -53, 30, 55, -49, -51, -50, -52, 42, 46, - 48, 43, 44, 45, 49, -129, 22, -41, -189, -128, - 151, -127, 22, -125, 59, -92, 53, -41, -53, -100, - -97, 55, 234, 236, 237, 52, 71, -39, -148, 107, - -166, -167, -168, -120, 59, 60, -157, -158, -159, -169, - 137, -174, 130, 132, 129, -160, 138, 124, 28, 56, - -153, 68, 74, -149, 212, -143, 54, -143, -143, -143, - -143, -147, 187, -147, -147, -147, 54, 54, -143, -143, - -143, -151, 54, -151, -151, -152, 54, -152, -123, 53, - -53, -131, 23, -131, -113, 120, 117, 118, -177, 116, - 209, 187, 66, 29, 15, 252, 151, 267, 57, 152, - -119, -119, -53, -53, 120, 117, -53, -53, -53, -131, - -53, -110, 90, 12, -125, -125, -53, 38, -39, -39, - -126, -86, -89, -103, 19, 11, 34, 34, -36, 68, - 69, 70, 112, -189, -70, -63, -63, -63, -35, 146, - 73, -190, -190, -36, 55, -39, -190, -190, -190, 55, - 53, 22, 55, 11, 55, 11, 112, 55, 11, 55, - 11, -190, -36, -81, -79, 80, -39, -190, 55, 55, - -190, -190, -190, -190, -61, 30, 34, -2, -189, -189, - -95, -99, -77, -42, -43, -43, -42, -43, 42, 42, - 42, 47, 42, 47, 42, -50, -125, -190, -56, 50, - 127, 51, -189, -127, -57, 12, -41, -57, -101, -102, - 238, 235, 241, 57, 59, 55, -168, 82, 54, 57, - 28, -160, -160, -161, 57, -161, 28, -144, 29, 68, - -150, 213, 60, -147, -147, -148, 30, -148, -148, -148, - -156, 59, -156, 60, 60, 52, -119, -131, -130, -183, - 131, 137, 138, 133, 57, 124, 28, 130, 132, 151, - 129, -183, -114, -115, 126, 22, 124, 28, 151, -182, - 53, 157, 157, 126, -131, -107, 59, -39, 39, 112, - -53, -40, 11, 99, -120, -37, -35, 73, -63, -63, - -190, -38, -135, 108, 184, 145, 182, 178, 198, 189, - 211, 180, 212, -132, -135, -63, -63, -63, -63, -120, - -63, -63, -63, -63, 261, -84, 81, -39, 79, -63, - -63, -94, 52, -95, -72, -74, -73, -189, -2, -90, - -119, -93, -119, -57, 55, 82, -46, -45, 52, 53, - -47, 52, -45, 42, 42, 124, 124, 124, -93, -84, - -39, -57, 235, 239, 240, -167, -168, -171, -170, -119, - -174, -161, -161, 54, -146, 52, 59, 60, 61, 68, - 242, 67, 56, -148, -148, 57, 108, 56, 55, 56, - 55, 56, 55, -53, -130, -130, -53, -130, -119, -180, - 264, -181, 57, -119, -119, -53, -110, -57, -41, -190, - -63, -190, -143, -143, -143, -152, -143, 172, -143, 172, - -190, -190, -190, 55, 19, -190, 55, 19, -190, 55, - 19, -190, 55, 19, -189, -34, 257, -39, 55, 55, - 27, -94, 55, -190, -190, -190, 55, 112, -190, 55, - -84, -99, -39, -39, 54, -39, -189, -189, -189, -190, - -88, 56, 55, -143, -91, -119, -154, 209, 9, 54, - -147, 59, -147, 60, 60, -131, 26, -179, -178, -120, - 54, -82, 13, -147, 57, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -190, 59, -63, -63, 28, -74, - 34, -2, -189, -119, -119, -119, -88, -91, -91, -91, - -91, -128, -173, -172, 53, 134, 66, -170, 56, 55, - -155, 130, 28, 129, 242, 56, -148, -148, 56, 56, - -189, 55, 82, -91, -83, 14, 16, -190, -190, -190, - -190, -190, -190, -190, -190, -33, 92, 264, -190, -190, - 9, -72, -2, 112, 56, -190, -190, -190, -56, -172, - 57, -162, 82, 59, 140, -119, -145, 66, 28, 28, - 54, -175, -176, 151, -178, -168, 56, -39, -71, -190, - 262, 49, 265, -95, -190, -119, 60, -53, 59, 56, - -190, 55, -119, -182, 39, 263, 266, 54, -176, 34, - -180, 39, -91, 153, 264, 56, 154, 265, -185, -186, - 52, -189, 266, -186, 52, 10, 9, -63, 150, -184, - 141, 136, 139, 30, -184, -190, -190, 135, 29, 68, + -193, -189, -193, -189, -193, -189, -193, -189, -193, -189, + -193, -189, -193, -193, -189, -189, -189, -189, -189, -189, + -189, -54, 26, -53, -41, -42, -43, -44, -55, -76, + -189, -53, -53, -48, -191, 55, 11, 53, 55, -96, + 164, -97, -101, 233, 235, 82, -124, -119, 59, 29, + 30, 56, 55, -53, -136, -139, -141, -140, -142, -137, + -138, 184, 185, 108, 188, 190, 191, 192, 193, 194, + 195, 196, 197, 198, 199, 30, 145, 180, 181, 182, + 183, 200, 201, 202, 203, 204, 205, 206, 207, 167, + 168, 169, 170, 171, 172, 173, 175, 176, 177, 178, + 179, 57, -131, 125, 57, 74, 57, -53, -53, -131, + 157, 157, 123, 123, -53, 55, 126, -48, 23, 52, + -53, 57, 57, -126, -125, -117, -131, -131, -131, -131, + -131, -131, -131, -131, -131, -131, 11, -107, 11, 92, + -39, 52, 9, 92, 55, 18, 112, 55, -87, 24, + 25, -88, -190, -32, -64, -119, 60, 63, -31, 43, + -53, -39, -39, -69, 68, 74, 69, 70, -121, 99, + -126, -120, -117, -63, -70, -73, -76, 64, 92, 90, + 91, 76, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -132, 57, 59, + 57, -62, -62, -119, -37, 21, -36, -38, -190, 55, + -190, -2, -36, -36, -39, -39, -77, 59, -119, -125, + -77, 59, -36, -30, -78, -79, 78, -77, -63, -190, + -63, -63, -63, -63, -63, -119, -119, -36, -37, -36, + -36, -92, 151, -53, 30, 55, -49, -51, -50, -52, + 42, 46, 48, 43, 44, 45, 49, -129, 22, -41, + -189, -128, 151, -127, 22, -125, 59, -92, 53, -41, + -53, -100, -97, 55, 234, 236, 237, 52, 71, -39, + -148, 107, -166, -167, -168, -120, 59, 60, -157, -158, + -159, -169, 137, -174, 130, 132, 129, -160, 138, 124, + 28, 56, -153, 68, 74, -149, 212, -143, 54, -143, + -143, -143, -143, -147, 187, -147, -147, -147, 54, 54, + -143, -143, -143, -151, 54, -151, -151, -152, 54, -152, + -123, 53, -53, -131, 23, -131, -113, 120, 117, 118, + -177, 116, 209, 187, 66, 29, 15, 252, 151, 267, + 57, 152, -119, -119, -53, -53, 120, 117, -53, -53, + -53, -131, -53, -110, 90, 12, -125, -125, -53, 38, + -39, -39, -126, -86, -89, -103, 19, 11, 34, 34, + -36, 68, 69, 70, 112, -189, -70, -63, -63, -63, + -35, 146, 73, -190, -190, -36, 55, -39, -190, -190, + -190, 55, 53, 22, 55, 11, 55, 11, 112, 55, + 11, 55, 11, -190, -36, -81, -79, 80, -39, -190, + -190, -190, -190, -190, -190, -190, 55, 55, -190, -190, + -190, -190, -61, 30, 34, -2, -189, -189, -95, -99, + -77, -42, -43, -43, -42, -43, 42, 42, 42, 47, + 42, 47, 42, -50, -125, -190, -56, 50, 127, 51, + -189, -127, -57, 12, -41, -57, -101, -102, 238, 235, + 241, 57, 59, 55, -168, 82, 54, 57, 28, -160, + -160, -161, 57, -161, 28, -144, 29, 68, -150, 213, + 60, -147, -147, -148, 30, -148, -148, -148, -156, 59, + -156, 60, 60, 52, -119, -131, -130, -183, 131, 137, + 138, 133, 57, 124, 28, 130, 132, 151, 129, -183, + -114, -115, 126, 22, 124, 28, 151, -182, 53, 157, + 157, 126, -131, -107, 59, -39, 39, 112, -53, -40, + 11, 99, -120, -37, -35, 73, -63, -63, -190, -38, + -135, 108, 184, 145, 182, 178, 198, 189, 211, 180, + 212, -132, -135, -63, -63, -63, -63, -120, -63, -63, + -63, -63, 261, -84, 81, -39, 79, -63, -63, -94, + 52, -95, -72, -74, -73, -189, -2, -90, -119, -93, + -119, -57, 55, 82, -46, -45, 52, 53, -47, 52, + -45, 42, 42, 124, 124, 124, -93, -84, -39, -57, + 235, 239, 240, -167, -168, -171, -170, -119, -174, -161, + -161, 54, -146, 52, 59, 60, 61, 68, 242, 67, + 56, -148, -148, 57, 108, 56, 55, 56, 55, 56, + 55, -53, -130, -130, -53, -130, -119, -180, 264, -181, + 57, -119, -119, -53, -110, -57, -41, -190, -63, -190, + -143, -143, -143, -152, -143, 172, -143, 172, -190, -190, + -190, 55, 19, -190, 55, 19, -190, 55, 19, -190, + 55, 19, -189, -34, 257, -39, 55, 55, 27, -94, + 55, -190, -190, -190, 55, 112, -190, 55, -84, -99, + -39, -39, 54, -39, -189, -189, -189, -190, -88, 56, + 55, -143, -91, -119, -154, 209, 9, 54, -147, 59, + -147, 60, 60, -131, 26, -179, -178, -120, 54, -82, + 13, -147, 57, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -190, 59, -63, -63, 28, -74, 34, -2, + -189, -119, -119, -119, -88, -91, -91, -91, -91, -128, + -173, -172, 53, 134, 66, -170, 56, 55, -155, 130, + 28, 129, 242, 56, -148, -148, 56, 56, -189, 55, + 82, -91, -83, 14, 16, -190, -190, -190, -190, -190, + -190, -190, -190, -33, 92, 264, -190, -190, 9, -72, + -2, 112, 56, -190, -190, -190, -56, -172, 57, -162, + 82, 59, 140, -119, -145, 66, 28, 28, 54, -175, + -176, 151, -178, -168, 56, -39, -71, -190, 262, 49, + 265, -95, -190, -119, 60, -53, 59, 56, -190, 55, + -119, -182, 39, 263, 266, 54, -176, 34, -180, 39, + -91, 153, 264, 56, 154, 265, -185, -186, 52, -189, + 266, -186, 52, 10, 9, -63, 150, -184, 141, 136, + 139, 30, -184, -190, -190, 135, 29, 68, } var yyDef = [...]int{ 23, -2, 2, -2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 558, 0, 317, 317, 317, 317, 317, 317, - 0, 629, 612, 0, 0, 0, 0, -2, 304, 305, - 0, 307, 308, 852, 852, 852, 852, 852, 0, 0, - 852, 0, 35, 36, 850, 1, 3, 566, 0, 0, - 321, 324, 319, 0, 612, 612, 0, 0, 62, 63, - 0, 0, 0, 836, 0, 610, 610, 610, 630, 631, - 634, 635, 737, 738, 739, 740, 741, 742, 743, 744, - 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, - 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, - 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, - 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, - 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, - 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, - 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, - 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, - 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, - 835, 837, 838, 839, 840, 841, 842, 843, 844, 845, - 846, 847, 848, 849, 0, 0, 0, 613, 0, 608, - 0, 608, 608, 608, 0, 255, 389, 638, 639, 836, - 0, 0, 0, 853, 0, 853, 267, 853, 853, 270, - 853, 0, 853, 0, 277, 279, 280, 281, 282, 0, - 286, 853, 301, 302, 291, 303, 306, 309, 310, 311, - 312, 313, 852, 852, 316, 29, 570, 0, 0, 558, + 21, 22, 564, 0, 317, 317, 317, 317, 317, 317, + 0, 635, 618, 0, 0, 0, 0, -2, 304, 305, + 0, 307, 308, 858, 858, 858, 858, 858, 0, 0, + 858, 0, 35, 36, 856, 1, 3, 572, 0, 0, + 321, 324, 319, 0, 618, 618, 0, 0, 62, 63, + 0, 0, 0, 842, 0, 616, 616, 616, 636, 637, + 640, 641, 743, 744, 745, 746, 747, 748, 749, 750, + 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, + 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, + 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, + 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, + 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, + 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, + 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, + 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, + 841, 843, 844, 845, 846, 847, 848, 849, 850, 851, + 852, 853, 854, 855, 0, 0, 0, 619, 0, 614, + 0, 614, 614, 614, 0, 255, 389, 644, 645, 842, + 0, 0, 0, 859, 0, 859, 267, 859, 859, 270, + 859, 0, 859, 0, 277, 279, 280, 281, 282, 0, + 286, 859, 301, 302, 291, 303, 306, 309, 310, 311, + 312, 313, 858, 858, 316, 29, 576, 0, 0, 564, 31, 0, 317, 322, 323, 327, 325, 326, 318, 0, 335, 339, 0, 397, 0, 402, 404, -2, -2, 0, 439, 440, 441, 442, 443, 0, 0, 0, 0, 0, - 0, 0, 0, 467, 468, 469, 470, 543, 544, 545, - 546, 547, 548, 549, 550, 406, 407, 540, 590, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 531, 0, - 505, 505, 505, 505, 505, 505, 505, 505, 0, 0, + 0, 0, 0, 467, 468, 469, 470, 549, 550, 551, + 552, 553, 554, 555, 556, 406, 407, 546, 596, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 537, 0, + 511, 511, 511, 511, 511, 511, 511, 511, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 47, - 0, 827, 594, -2, -2, 0, 0, 636, 637, -2, - 746, -2, 642, 643, 644, 645, 646, 647, 648, 649, - 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, - 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, - 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, - 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, - 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, - 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, - 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, - 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, - 730, 731, 732, 733, 734, 735, 736, 0, 0, 81, - 0, 79, 0, 853, 0, 0, 0, 0, 0, 0, - 853, 0, 0, 0, 0, 246, 0, 0, 0, 0, - 0, 0, 0, 254, 0, 256, 853, 853, 259, 854, - 855, 853, 853, 853, 853, 853, 853, 266, 268, 269, - 271, 853, 853, 273, 0, 294, 292, 293, 288, 289, - 0, 283, 284, 287, 314, 315, 30, 851, 24, 0, - 0, 567, 0, 559, 560, 563, 566, 29, 324, 0, + 0, 833, 600, -2, -2, 0, 0, 642, 643, -2, + 752, -2, 648, 649, 650, 651, 652, 653, 654, 655, + 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, + 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, + 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, + 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, + 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, + 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, + 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, + 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, + 736, 737, 738, 739, 740, 741, 742, 0, 0, 81, + 0, 79, 0, 859, 0, 0, 0, 0, 0, 0, + 859, 0, 0, 0, 0, 246, 0, 0, 0, 0, + 0, 0, 0, 254, 0, 256, 859, 859, 259, 860, + 861, 859, 859, 859, 859, 859, 859, 266, 268, 269, + 271, 859, 859, 273, 0, 294, 292, 293, 288, 289, + 0, 283, 284, 287, 314, 315, 30, 857, 24, 0, + 0, 573, 0, 565, 566, 569, 572, 29, 324, 0, 329, 328, 320, 0, 336, 0, 0, 0, 340, 0, 342, 343, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 424, 425, 426, 427, 428, 429, 430, 403, 0, 417, 0, 0, 0, 459, 460, 461, 462, 463, 464, 465, 0, 331, 29, 0, 437, 0, 0, - 0, 0, 0, 0, 0, 0, 327, 0, 532, 0, - 495, 0, 496, 497, 498, 499, 500, 501, 502, 0, - 0, 0, 331, 0, 0, 45, 0, 388, 0, 346, - 348, 349, 350, -2, 0, 372, -2, 0, 0, 0, - 41, 42, 0, 48, 827, 50, 51, 0, 0, 0, - 164, 603, 604, 605, 601, 208, 0, 0, 145, 141, - 87, 88, 89, 134, 91, 134, 134, 134, 134, 161, - 161, 161, 161, 117, 118, 119, 120, 121, 0, 0, - 104, 134, 134, 134, 108, 124, 125, 126, 127, 128, - 129, 130, 131, 92, 93, 94, 95, 96, 97, 98, - 136, 136, 136, 138, 138, 632, 65, 0, 853, 0, - 853, 77, 0, 222, 0, 0, 0, 0, 0, 0, - 0, 249, 609, 0, 853, 252, 253, 390, 640, 641, - 257, 258, 260, 261, 262, 263, 264, 265, 272, 276, - 0, 297, 0, 0, 278, 0, 571, 0, 0, 0, - 0, 0, 562, 564, 565, 570, 32, 327, 0, 551, - 0, 0, 0, 330, 27, 398, 399, 401, 418, 0, - 420, 422, 341, 337, 0, 541, -2, 408, 409, 433, - 434, 435, 0, 0, 0, 0, 431, 413, 0, 444, - 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, - 455, 458, 516, 517, 0, 456, 457, 466, 0, 0, - 332, 333, 436, 0, 589, 29, 0, 0, 0, 0, - 0, 0, 540, 0, 0, 0, 0, 0, 538, 535, - 0, 0, 506, 0, 0, 0, 0, 0, 0, 0, - 0, 387, 0, 0, 0, 0, 0, 0, 377, 0, - 0, 380, 0, 0, 0, 0, 371, 0, 0, 391, - 796, 373, 0, 375, 376, 395, 0, 395, 44, 595, - 49, 0, 0, 54, 55, 596, 597, 598, 599, 0, - 78, 209, 211, 214, 215, 216, 82, 83, 84, 0, - 0, 196, 0, 0, 190, 190, 0, 188, 189, 80, - 148, 146, 0, 143, 142, 90, 0, 161, 161, 111, - 112, 164, 0, 164, 164, 164, 0, 0, 105, 106, - 107, 99, 0, 100, 101, 102, 0, 103, 0, 0, - 853, 67, 611, 68, 852, 0, 0, 624, 223, 614, - 615, 616, 617, 618, 619, 620, 621, 622, 623, 0, - 69, 225, 227, 226, 0, 0, 0, 247, 853, 251, - 294, 275, 0, 0, 295, 296, 285, 0, 568, 569, - 0, 561, 25, 0, 606, 607, 552, 553, 344, 419, - 421, 423, 0, 331, 410, 431, 414, 0, 411, 0, - 0, 405, 471, 0, 0, 438, -2, 474, 475, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 558, 0, 536, 0, 0, 494, 0, 0, - 507, 508, 509, 510, 583, 0, 0, -2, 0, 0, - 395, 591, 0, 347, 366, 368, 0, 363, 378, 379, - 381, 0, 383, 0, 385, 386, 351, 353, 354, 0, - 0, 0, 0, 374, 558, 0, 395, 40, 52, 53, - 0, 0, 59, 165, 166, 0, 212, 0, 0, 0, - 183, 190, 190, 186, 191, 187, 0, 156, 0, 147, - 86, 144, 0, 164, 164, 113, 0, 114, 115, 116, - 0, 132, 0, 0, 0, 0, 633, 66, 217, 852, - 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, - 240, 852, 0, 852, 625, 626, 627, 628, 0, 72, - 0, 0, 0, 0, 250, 297, 298, 299, 572, 0, - 26, 395, 0, 338, 542, 0, 412, 0, 432, 415, - 472, 334, 0, 134, 134, 521, 134, 138, 524, 134, - 526, 134, 529, 0, 0, 0, 0, 0, 0, 541, - 0, 0, 0, 0, 0, 533, 493, 539, 0, 0, - 0, 33, 0, 583, 573, 585, 587, 0, 29, 0, - 579, 0, 358, 558, 0, 0, 360, 367, 0, 0, - 361, 0, 362, 382, 384, 0, 0, 0, 0, 566, - 396, 39, 56, 57, 58, 210, 213, 0, 192, 134, - 195, 184, 185, 0, 159, 0, 149, 150, 151, 152, - 153, 155, 135, 109, 110, 162, 163, 161, 0, 161, - 0, 139, 0, 853, 218, 219, 220, 221, 0, 224, - 0, 70, 71, 0, 229, 248, 274, 554, 345, 473, - 416, 476, 518, 161, 522, 523, 525, 527, 528, 530, - 478, 477, 479, 0, 0, 485, 0, 0, 482, 0, - 0, 488, 0, 0, 0, 0, 0, 537, 0, 0, - 0, 34, 0, 588, -2, 0, 0, 0, 46, 0, - 566, 592, 593, 364, 0, 369, 0, 0, 0, 372, - 38, 175, 0, 194, 0, 356, 167, 160, 0, 0, - 164, 133, 164, 0, 0, 64, 0, 73, 74, 0, - 0, 556, 0, 519, 520, 0, 0, 0, 0, 0, - 0, 0, 0, 511, 492, 534, 0, 0, 0, 586, - 0, -2, 0, 581, 580, 359, 37, 0, 0, 0, - 0, 391, 174, 176, 0, 181, 0, 193, 0, 0, - 172, 0, 169, 171, 157, 154, 122, 123, 137, 140, - 0, 0, 0, 0, 28, 0, 0, 480, 481, 486, - 487, 483, 484, 489, 490, 0, 0, 0, 503, 504, - 0, 576, 29, 0, 365, 392, 393, 394, 355, 177, - 178, 0, 182, 180, 0, 357, 85, 0, 168, 170, - 0, 0, 242, 0, 75, 76, 69, 557, 555, 491, - 0, 0, 0, 584, -2, 582, 179, 0, 173, 158, - 241, 0, 0, 72, 512, 0, 515, 0, 243, 0, - 228, 513, 0, 0, 0, 197, 0, 0, 198, 199, - 0, 0, 514, 200, 0, 0, 0, 0, 0, 201, - 203, 204, 0, 0, 202, 244, 245, 205, 206, 207, + 0, 0, 0, 0, 0, 0, 327, 0, 538, 0, + 495, 0, 496, 0, 497, 0, 498, 0, 499, 0, + 500, 0, 501, 502, 0, 0, 0, 0, 331, 0, + 0, 45, 0, 388, 0, 346, 348, 349, 350, -2, + 0, 372, -2, 0, 0, 0, 41, 42, 0, 48, + 833, 50, 51, 0, 0, 0, 164, 609, 610, 611, + 607, 208, 0, 0, 145, 141, 87, 88, 89, 134, + 91, 134, 134, 134, 134, 161, 161, 161, 161, 117, + 118, 119, 120, 121, 0, 0, 104, 134, 134, 134, + 108, 124, 125, 126, 127, 128, 129, 130, 131, 92, + 93, 94, 95, 96, 97, 98, 136, 136, 136, 138, + 138, 638, 65, 0, 859, 0, 859, 77, 0, 222, + 0, 0, 0, 0, 0, 0, 0, 249, 615, 0, + 859, 252, 253, 390, 646, 647, 257, 258, 260, 261, + 262, 263, 264, 265, 272, 276, 0, 297, 0, 0, + 278, 0, 577, 0, 0, 0, 0, 0, 568, 570, + 571, 576, 32, 327, 0, 557, 0, 0, 0, 330, + 27, 398, 399, 401, 418, 0, 420, 422, 341, 337, + 0, 547, -2, 408, 409, 433, 434, 435, 0, 0, + 0, 0, 431, 413, 0, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 454, 455, 458, 522, 523, + 0, 456, 457, 466, 0, 0, 332, 333, 436, 0, + 595, 29, 0, 0, 0, 0, 0, 0, 546, 0, + 0, 0, 0, 0, 544, 541, 0, 0, 0, 512, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 387, 0, 0, 0, 0, 0, 0, + 377, 0, 0, 380, 0, 0, 0, 0, 371, 0, + 0, 391, 802, 373, 0, 375, 376, 395, 0, 395, + 44, 601, 49, 0, 0, 54, 55, 602, 603, 604, + 605, 0, 78, 209, 211, 214, 215, 216, 82, 83, + 84, 0, 0, 196, 0, 0, 190, 190, 0, 188, + 189, 80, 148, 146, 0, 143, 142, 90, 0, 161, + 161, 111, 112, 164, 0, 164, 164, 164, 0, 0, + 105, 106, 107, 99, 0, 100, 101, 102, 0, 103, + 0, 0, 859, 67, 617, 68, 858, 0, 0, 630, + 223, 620, 621, 622, 623, 624, 625, 626, 627, 628, + 629, 0, 69, 225, 227, 226, 0, 0, 0, 247, + 859, 251, 294, 275, 0, 0, 295, 296, 285, 0, + 574, 575, 0, 567, 25, 0, 612, 613, 558, 559, + 344, 419, 421, 423, 0, 331, 410, 431, 414, 0, + 411, 0, 0, 405, 471, 0, 0, 438, -2, 474, + 475, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 564, 0, 542, 0, 0, 494, + 503, 504, 505, 506, 507, 508, 0, 0, 513, 514, + 515, 516, 589, 0, 0, -2, 0, 0, 395, 597, + 0, 347, 366, 368, 0, 363, 378, 379, 381, 0, + 383, 0, 385, 386, 351, 353, 354, 0, 0, 0, + 0, 374, 564, 0, 395, 40, 52, 53, 0, 0, + 59, 165, 166, 0, 212, 0, 0, 0, 183, 190, + 190, 186, 191, 187, 0, 156, 0, 147, 86, 144, + 0, 164, 164, 113, 0, 114, 115, 116, 0, 132, + 0, 0, 0, 0, 639, 66, 217, 858, 230, 231, + 232, 233, 234, 235, 236, 237, 238, 239, 240, 858, + 0, 858, 631, 632, 633, 634, 0, 72, 0, 0, + 0, 0, 250, 297, 298, 299, 578, 0, 26, 395, + 0, 338, 548, 0, 412, 0, 432, 415, 472, 334, + 0, 134, 134, 527, 134, 138, 530, 134, 532, 134, + 535, 0, 0, 0, 0, 0, 0, 547, 0, 0, + 0, 0, 0, 539, 493, 545, 0, 0, 0, 33, + 0, 589, 579, 591, 593, 0, 29, 0, 585, 0, + 358, 564, 0, 0, 360, 367, 0, 0, 361, 0, + 362, 382, 384, 0, 0, 0, 0, 572, 396, 39, + 56, 57, 58, 210, 213, 0, 192, 134, 195, 184, + 185, 0, 159, 0, 149, 150, 151, 152, 153, 155, + 135, 109, 110, 162, 163, 161, 0, 161, 0, 139, + 0, 859, 218, 219, 220, 221, 0, 224, 0, 70, + 71, 0, 229, 248, 274, 560, 345, 473, 416, 476, + 524, 161, 528, 529, 531, 533, 534, 536, 478, 477, + 479, 0, 0, 485, 0, 0, 482, 0, 0, 488, + 0, 0, 0, 0, 0, 543, 0, 0, 0, 34, + 0, 594, -2, 0, 0, 0, 46, 0, 572, 598, + 599, 364, 0, 369, 0, 0, 0, 372, 38, 175, + 0, 194, 0, 356, 167, 160, 0, 0, 164, 133, + 164, 0, 0, 64, 0, 73, 74, 0, 0, 562, + 0, 525, 526, 0, 0, 0, 0, 0, 0, 0, + 0, 517, 492, 540, 0, 0, 0, 592, 0, -2, + 0, 587, 586, 359, 37, 0, 0, 0, 0, 391, + 174, 176, 0, 181, 0, 193, 0, 0, 172, 0, + 169, 171, 157, 154, 122, 123, 137, 140, 0, 0, + 0, 0, 28, 0, 0, 480, 481, 486, 487, 483, + 484, 489, 490, 0, 0, 0, 509, 510, 0, 582, + 29, 0, 365, 392, 393, 394, 355, 177, 178, 0, + 182, 180, 0, 357, 85, 0, 168, 170, 0, 0, + 242, 0, 75, 76, 69, 563, 561, 491, 0, 0, + 0, 590, -2, 588, 179, 0, 173, 158, 241, 0, + 0, 72, 518, 0, 521, 0, 243, 0, 228, 519, + 0, 0, 0, 197, 0, 0, 198, 199, 0, 0, + 520, 200, 0, 0, 0, 0, 0, 201, 203, 204, + 0, 0, 202, 244, 245, 205, 206, 207, } var yyTok1 = [...]int{ @@ -5842,315 +5891,351 @@ yydefault: } case 498: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2554 +//line sql.y:2555 { yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_date")} } case 499: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2559 +//line sql.y:2560 { yyVAL.expr = &FuncExpr{Name: NewColIdent("localtime")} } case 500: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2564 +//line sql.y:2565 { yyVAL.expr = &FuncExpr{Name: NewColIdent("localtimestamp")} } case 501: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2569 +//line sql.y:2571 { yyVAL.expr = &FuncExpr{Name: NewColIdent("current_date")} } case 502: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2574 +//line sql.y:2576 { yyVAL.expr = &FuncExpr{Name: NewColIdent("current_time")} } case 503: + yyDollar = yyS[yypt-4 : yypt+1] +//line sql.y:2581 + { + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_timestamp"), Fsp: yyDollar[3].expr} + } + case 504: + yyDollar = yyS[yypt-4 : yypt+1] +//line sql.y:2585 + { + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_timestamp"), Fsp: yyDollar[3].expr} + } + case 505: + yyDollar = yyS[yypt-4 : yypt+1] +//line sql.y:2589 + { + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_time"), Fsp: yyDollar[3].expr} + } + case 506: + yyDollar = yyS[yypt-4 : yypt+1] +//line sql.y:2594 + { + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtime"), Fsp: yyDollar[3].expr} + } + case 507: + yyDollar = yyS[yypt-4 : yypt+1] +//line sql.y:2599 + { + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtimestamp"), Fsp: yyDollar[3].expr} + } + case 508: + yyDollar = yyS[yypt-4 : yypt+1] +//line sql.y:2604 + { + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_time"), Fsp: yyDollar[3].expr} + } + case 509: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2578 +//line sql.y:2608 { yyVAL.expr = &TimestampFuncExpr{Name: string("timestampadd"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].expr, Expr2: yyDollar[7].expr} } - case 504: + case 510: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2582 +//line sql.y:2612 { yyVAL.expr = &TimestampFuncExpr{Name: string("timestampdiff"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].expr, Expr2: yyDollar[7].expr} } - case 507: + case 513: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2596 +//line sql.y:2626 { yyVAL.expr = &FuncExpr{Name: NewColIdent("if"), Exprs: yyDollar[3].selectExprs} } - case 508: + case 514: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2600 +//line sql.y:2630 { yyVAL.expr = &FuncExpr{Name: NewColIdent("database"), Exprs: yyDollar[3].selectExprs} } - case 509: + case 515: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2604 +//line sql.y:2634 { yyVAL.expr = &FuncExpr{Name: NewColIdent("mod"), Exprs: yyDollar[3].selectExprs} } - case 510: + case 516: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2608 +//line sql.y:2638 { yyVAL.expr = &FuncExpr{Name: NewColIdent("replace"), Exprs: yyDollar[3].selectExprs} } - case 511: + case 517: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2614 +//line sql.y:2644 { yyVAL.str = "" } - case 512: + case 518: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2618 +//line sql.y:2648 { yyVAL.str = BooleanModeStr } - case 513: + case 519: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2622 +//line sql.y:2652 { yyVAL.str = NaturalLanguageModeStr } - case 514: + case 520: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:2626 +//line sql.y:2656 { yyVAL.str = NaturalLanguageModeWithQueryExpansionStr } - case 515: + case 521: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2630 +//line sql.y:2660 { yyVAL.str = QueryExpansionStr } - case 516: + case 522: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2636 +//line sql.y:2666 { yyVAL.str = string(yyDollar[1].bytes) } - case 517: + case 523: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2640 +//line sql.y:2670 { yyVAL.str = string(yyDollar[1].bytes) } - case 518: + case 524: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2646 +//line sql.y:2676 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } - case 519: + case 525: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2650 +//line sql.y:2680 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Operator: CharacterSetStr} } - case 520: + case 526: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2654 +//line sql.y:2684 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: string(yyDollar[3].bytes)} } - case 521: + case 527: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2658 +//line sql.y:2688 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 522: + case 528: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2662 +//line sql.y:2692 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } - case 523: + case 529: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2666 +//line sql.y:2696 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} yyVAL.convertType.Length = yyDollar[2].LengthScaleOption.Length yyVAL.convertType.Scale = yyDollar[2].LengthScaleOption.Scale } - case 524: + case 530: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2672 +//line sql.y:2702 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 525: + case 531: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2676 +//line sql.y:2706 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } - case 526: + case 532: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2680 +//line sql.y:2710 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 527: + case 533: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2684 +//line sql.y:2714 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 528: + case 534: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2688 +//line sql.y:2718 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} } - case 529: + case 535: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2692 +//line sql.y:2722 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 530: + case 536: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2696 +//line sql.y:2726 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 531: + case 537: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2701 +//line sql.y:2731 { yyVAL.expr = nil } - case 532: + case 538: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2705 +//line sql.y:2735 { yyVAL.expr = yyDollar[1].expr } - case 533: + case 539: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2710 +//line sql.y:2740 { yyVAL.str = string("") } - case 534: + case 540: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2714 +//line sql.y:2744 { yyVAL.str = " separator '" + string(yyDollar[2].bytes) + "'" } - case 535: + case 541: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2720 +//line sql.y:2750 { yyVAL.whens = []*When{yyDollar[1].when} } - case 536: + case 542: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2724 +//line sql.y:2754 { yyVAL.whens = append(yyDollar[1].whens, yyDollar[2].when) } - case 537: + case 543: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2730 +//line sql.y:2760 { yyVAL.when = &When{Cond: yyDollar[2].expr, Val: yyDollar[4].expr} } - case 538: + case 544: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2735 +//line sql.y:2765 { yyVAL.expr = nil } - case 539: + case 545: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2739 +//line sql.y:2769 { yyVAL.expr = yyDollar[2].expr } - case 540: + case 546: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2745 +//line sql.y:2775 { yyVAL.colName = &ColName{Name: yyDollar[1].colIdent} } - case 541: + case 547: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2749 +//line sql.y:2779 { yyVAL.colName = &ColName{Qualifier: TableName{Name: yyDollar[1].tableIdent}, Name: yyDollar[3].colIdent} } - case 542: + case 548: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2753 +//line sql.y:2783 { yyVAL.colName = &ColName{Qualifier: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}, Name: yyDollar[5].colIdent} } - case 543: + case 549: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2759 +//line sql.y:2789 { yyVAL.expr = NewStrVal(yyDollar[1].bytes) } - case 544: + case 550: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2763 +//line sql.y:2793 { yyVAL.expr = NewHexVal(yyDollar[1].bytes) } - case 545: + case 551: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2767 +//line sql.y:2797 { yyVAL.expr = NewBitVal(yyDollar[1].bytes) } - case 546: + case 552: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2771 +//line sql.y:2801 { yyVAL.expr = NewIntVal(yyDollar[1].bytes) } - case 547: + case 553: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2775 +//line sql.y:2805 { yyVAL.expr = NewFloatVal(yyDollar[1].bytes) } - case 548: + case 554: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2779 +//line sql.y:2809 { yyVAL.expr = NewHexNum(yyDollar[1].bytes) } - case 549: + case 555: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2783 +//line sql.y:2813 { yyVAL.expr = NewValArg(yyDollar[1].bytes) } - case 550: + case 556: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2787 +//line sql.y:2817 { yyVAL.expr = &NullVal{} } - case 551: + case 557: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2793 +//line sql.y:2823 { // TODO(sougou): Deprecate this construct. if yyDollar[1].colIdent.Lowered() != "value" { @@ -6159,239 +6244,239 @@ yydefault: } yyVAL.expr = NewIntVal([]byte("1")) } - case 552: + case 558: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2802 +//line sql.y:2832 { yyVAL.expr = NewIntVal(yyDollar[1].bytes) } - case 553: + case 559: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2806 +//line sql.y:2836 { yyVAL.expr = NewValArg(yyDollar[1].bytes) } - case 554: + case 560: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2811 +//line sql.y:2841 { yyVAL.exprs = nil } - case 555: + case 561: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2815 +//line sql.y:2845 { yyVAL.exprs = yyDollar[3].exprs } - case 556: + case 562: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2820 +//line sql.y:2850 { yyVAL.expr = nil } - case 557: + case 563: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2824 +//line sql.y:2854 { yyVAL.expr = yyDollar[2].expr } - case 558: + case 564: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2829 +//line sql.y:2859 { yyVAL.orderBy = nil } - case 559: + case 565: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2833 +//line sql.y:2863 { yyVAL.orderBy = yyDollar[3].orderBy } - case 560: + case 566: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2839 +//line sql.y:2869 { yyVAL.orderBy = OrderBy{yyDollar[1].order} } - case 561: + case 567: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2843 +//line sql.y:2873 { yyVAL.orderBy = append(yyDollar[1].orderBy, yyDollar[3].order) } - case 562: + case 568: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2849 +//line sql.y:2879 { yyVAL.order = &Order{Expr: yyDollar[1].expr, Direction: yyDollar[2].str} } - case 563: + case 569: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2854 +//line sql.y:2884 { yyVAL.str = AscScr } - case 564: + case 570: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2858 +//line sql.y:2888 { yyVAL.str = AscScr } - case 565: + case 571: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2862 +//line sql.y:2892 { yyVAL.str = DescScr } - case 566: + case 572: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2867 +//line sql.y:2897 { yyVAL.limit = nil } - case 567: + case 573: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2871 +//line sql.y:2901 { yyVAL.limit = &Limit{Rowcount: yyDollar[2].expr} } - case 568: + case 574: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2875 +//line sql.y:2905 { yyVAL.limit = &Limit{Offset: yyDollar[2].expr, Rowcount: yyDollar[4].expr} } - case 569: + case 575: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2879 +//line sql.y:2909 { yyVAL.limit = &Limit{Offset: yyDollar[4].expr, Rowcount: yyDollar[2].expr} } - case 570: + case 576: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2884 +//line sql.y:2914 { yyVAL.str = "" } - case 571: + case 577: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2888 +//line sql.y:2918 { yyVAL.str = ForUpdateStr } - case 572: + case 578: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2892 +//line sql.y:2922 { yyVAL.str = ShareModeStr } - case 573: + case 579: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2905 +//line sql.y:2935 { yyVAL.ins = &Insert{Rows: yyDollar[2].values} } - case 574: + case 580: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2909 +//line sql.y:2939 { yyVAL.ins = &Insert{Rows: yyDollar[1].selStmt} } - case 575: + case 581: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2913 +//line sql.y:2943 { // Drop the redundant parenthesis. yyVAL.ins = &Insert{Rows: yyDollar[2].selStmt} } - case 576: + case 582: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2918 +//line sql.y:2948 { yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].values} } - case 577: + case 583: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2922 +//line sql.y:2952 { yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[4].selStmt} } - case 578: + case 584: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2926 +//line sql.y:2956 { // Drop the redundant parenthesis. yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].selStmt} } - case 579: + case 585: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2933 +//line sql.y:2963 { yyVAL.columns = Columns{yyDollar[1].colIdent} } - case 580: + case 586: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2937 +//line sql.y:2967 { yyVAL.columns = Columns{yyDollar[3].colIdent} } - case 581: + case 587: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2941 +//line sql.y:2971 { yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) } - case 582: + case 588: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2945 +//line sql.y:2975 { yyVAL.columns = append(yyVAL.columns, yyDollar[5].colIdent) } - case 583: + case 589: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2950 +//line sql.y:2980 { yyVAL.updateExprs = nil } - case 584: + case 590: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2954 +//line sql.y:2984 { yyVAL.updateExprs = yyDollar[5].updateExprs } - case 585: + case 591: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2960 +//line sql.y:2990 { yyVAL.values = Values{yyDollar[1].valTuple} } - case 586: + case 592: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2964 +//line sql.y:2994 { yyVAL.values = append(yyDollar[1].values, yyDollar[3].valTuple) } - case 587: + case 593: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2970 +//line sql.y:3000 { yyVAL.valTuple = yyDollar[1].valTuple } - case 588: + case 594: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2974 +//line sql.y:3004 { yyVAL.valTuple = ValTuple{} } - case 589: + case 595: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2980 +//line sql.y:3010 { yyVAL.valTuple = ValTuple(yyDollar[2].exprs) } - case 590: + case 596: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2986 +//line sql.y:3016 { if len(yyDollar[1].valTuple) == 1 { yyVAL.expr = &ParenExpr{yyDollar[1].valTuple[0]} @@ -6399,312 +6484,312 @@ yydefault: yyVAL.expr = yyDollar[1].valTuple } } - case 591: + case 597: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2996 +//line sql.y:3026 { yyVAL.updateExprs = UpdateExprs{yyDollar[1].updateExpr} } - case 592: + case 598: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3000 +//line sql.y:3030 { yyVAL.updateExprs = append(yyDollar[1].updateExprs, yyDollar[3].updateExpr) } - case 593: + case 599: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3006 +//line sql.y:3036 { yyVAL.updateExpr = &UpdateExpr{Name: yyDollar[1].colName, Expr: yyDollar[3].expr} } - case 594: + case 600: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3012 +//line sql.y:3042 { yyVAL.setExprs = SetExprs{yyDollar[1].setExpr} } - case 595: + case 601: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3016 +//line sql.y:3046 { yyVAL.setExprs = append(yyDollar[1].setExprs, yyDollar[3].setExpr) } - case 596: + case 602: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3022 +//line sql.y:3052 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: NewStrVal([]byte("on"))} } - case 597: + case 603: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3026 +//line sql.y:3056 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: NewStrVal([]byte("off"))} } - case 598: + case 604: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3030 +//line sql.y:3060 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: yyDollar[3].expr} } - case 599: + case 605: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3034 +//line sql.y:3064 { yyVAL.setExpr = &SetExpr{Name: NewColIdent(string(yyDollar[1].bytes)), Expr: yyDollar[2].expr} } - case 601: + case 607: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3041 +//line sql.y:3071 { yyVAL.bytes = []byte("charset") } - case 603: + case 609: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3048 +//line sql.y:3078 { yyVAL.expr = NewStrVal([]byte(yyDollar[1].colIdent.String())) } - case 604: + case 610: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3052 +//line sql.y:3082 { yyVAL.expr = NewStrVal(yyDollar[1].bytes) } - case 605: + case 611: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3056 +//line sql.y:3086 { yyVAL.expr = &Default{} } - case 608: + case 614: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3065 +//line sql.y:3095 { yyVAL.byt = 0 } - case 609: + case 615: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3067 +//line sql.y:3097 { yyVAL.byt = 1 } - case 610: + case 616: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3070 +//line sql.y:3100 { yyVAL.empty = struct{}{} } - case 611: + case 617: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3072 +//line sql.y:3102 { yyVAL.empty = struct{}{} } - case 612: + case 618: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3075 +//line sql.y:3105 { yyVAL.str = "" } - case 613: + case 619: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3077 +//line sql.y:3107 { yyVAL.str = IgnoreStr } - case 614: + case 620: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3081 +//line sql.y:3111 { yyVAL.empty = struct{}{} } - case 615: + case 621: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3083 +//line sql.y:3113 { yyVAL.empty = struct{}{} } - case 616: + case 622: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3085 +//line sql.y:3115 { yyVAL.empty = struct{}{} } - case 617: + case 623: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3087 +//line sql.y:3117 { yyVAL.empty = struct{}{} } - case 618: + case 624: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3089 +//line sql.y:3119 { yyVAL.empty = struct{}{} } - case 619: + case 625: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3091 +//line sql.y:3121 { yyVAL.empty = struct{}{} } - case 620: + case 626: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3093 +//line sql.y:3123 { yyVAL.empty = struct{}{} } - case 621: + case 627: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3095 +//line sql.y:3125 { yyVAL.empty = struct{}{} } - case 622: + case 628: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3097 +//line sql.y:3127 { yyVAL.empty = struct{}{} } - case 623: + case 629: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3099 +//line sql.y:3129 { yyVAL.empty = struct{}{} } - case 624: + case 630: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3102 +//line sql.y:3132 { yyVAL.empty = struct{}{} } - case 625: + case 631: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3104 +//line sql.y:3134 { yyVAL.empty = struct{}{} } - case 626: + case 632: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3106 +//line sql.y:3136 { yyVAL.empty = struct{}{} } - case 627: + case 633: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3110 +//line sql.y:3140 { yyVAL.empty = struct{}{} } - case 628: + case 634: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3112 +//line sql.y:3142 { yyVAL.empty = struct{}{} } - case 629: + case 635: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3115 +//line sql.y:3145 { yyVAL.empty = struct{}{} } - case 630: + case 636: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3117 +//line sql.y:3147 { yyVAL.empty = struct{}{} } - case 631: + case 637: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3119 +//line sql.y:3149 { yyVAL.empty = struct{}{} } - case 632: + case 638: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3122 +//line sql.y:3152 { yyVAL.colIdent = ColIdent{} } - case 633: + case 639: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3124 +//line sql.y:3154 { yyVAL.colIdent = yyDollar[2].colIdent } - case 634: + case 640: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3128 +//line sql.y:3158 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 635: + case 641: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3132 +//line sql.y:3162 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 637: + case 643: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3139 +//line sql.y:3169 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 638: + case 644: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3145 +//line sql.y:3175 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 639: + case 645: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3149 +//line sql.y:3179 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 641: + case 647: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3156 +//line sql.y:3186 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 850: + case 856: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3390 +//line sql.y:3420 { if incNesting(yylex) { yylex.Error("max nesting level reached") return 1 } } - case 851: + case 857: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3399 +//line sql.y:3429 { decNesting(yylex) } - case 852: + case 858: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3404 +//line sql.y:3434 { skipToEnd(yylex) } - case 853: + case 859: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3409 +//line sql.y:3439 { skipToEnd(yylex) } - case 854: + case 860: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3413 +//line sql.y:3443 { skipToEnd(yylex) } - case 855: + case 861: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3417 +//line sql.y:3447 { skipToEnd(yylex) } diff --git a/go/vt/sqlparser/sql.y b/go/vt/sqlparser/sql.y index b05d0421f04..264d832fded 100644 --- a/go/vt/sqlparser/sql.y +++ b/go/vt/sqlparser/sql.y @@ -2550,6 +2550,7 @@ function_call_nonkeyword: { $$ = &FuncExpr{Name:NewColIdent("utc_time")} } +/* doesn't support fsp */ | UTC_DATE func_datetime_precision_opt { $$ = &FuncExpr{Name:NewColIdent("utc_date")} @@ -2565,6 +2566,7 @@ function_call_nonkeyword: $$ = &FuncExpr{Name:NewColIdent("localtimestamp")} } // curdate +/* doesn't support fsp */ | CURRENT_DATE func_datetime_precision_opt { $$ = &FuncExpr{Name:NewColIdent("current_date")} @@ -2574,6 +2576,34 @@ function_call_nonkeyword: { $$ = &FuncExpr{Name:NewColIdent("current_time")} } +// these functions can also be called with an optional argument +| CURRENT_TIMESTAMP openb value_expression closeb + { + $$ = &CurTimeFuncExpr{Name:NewColIdent("current_timestamp"), Fsp:$3} + } +| UTC_TIMESTAMP openb value_expression closeb + { + $$ = &CurTimeFuncExpr{Name:NewColIdent("utc_timestamp"), Fsp:$3} + } +| UTC_TIME openb value_expression closeb + { + $$ = &CurTimeFuncExpr{Name:NewColIdent("utc_time"), Fsp:$3} + } + // now +| LOCALTIME openb value_expression closeb + { + $$ = &CurTimeFuncExpr{Name:NewColIdent("localtime"), Fsp:$3} + } + // now +| LOCALTIMESTAMP openb value_expression closeb + { + $$ = &CurTimeFuncExpr{Name:NewColIdent("localtimestamp"), Fsp:$3} + } + // curtime +| CURRENT_TIME openb value_expression closeb + { + $$ = &CurTimeFuncExpr{Name:NewColIdent("current_time"), Fsp:$3} + } | TIMESTAMPADD openb sql_id ',' value_expression ',' value_expression closeb { $$ = &TimestampFuncExpr{Name:string("timestampadd"), Unit:$3.String(), Expr1:$5, Expr2:$7} From a4d547e54126ccd5760a0f5cffcb070230cc5f48 Mon Sep 17 00:00:00 2001 From: Tom Krouper Date: Thu, 31 Jan 2019 13:23:22 -0800 Subject: [PATCH 006/196] Recommended fix for https://nvd.nist.gov/vuln/detail/CVE-2017-18342 Signed-off-by: Tom Krouper --- test/cluster/keytar/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/cluster/keytar/requirements.txt b/test/cluster/keytar/requirements.txt index 76649d9b728..694958b30d5 100644 --- a/test/cluster/keytar/requirements.txt +++ b/test/cluster/keytar/requirements.txt @@ -1,2 +1,2 @@ Flask==0.12.3 -pyyaml==3.10 +pyyaml==4.2b1 From 51cee3fdd8cbf4e7e389cd8936784be535da1521 Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Thu, 31 Jan 2019 16:33:06 -0500 Subject: [PATCH 007/196] update pull request Signed-off-by: xichengliudui --- doc/VindexAsTable.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/VindexAsTable.md b/doc/VindexAsTable.md index 5e633795088..55a9d529b23 100644 --- a/doc/VindexAsTable.md +++ b/doc/VindexAsTable.md @@ -37,7 +37,7 @@ For `select` statements, we can follow the V3 design principles, there will be a While analyzing the `WHERE` clause, if the primitive is a `vindexFunc`, we look for the three possible combinations listed above. Once they're matched, we can assign the corresponding opcode. -While analyizing the `SELECT` expression list, we verify that the user has specified expressions as required by each opcode. +While analyzing the `SELECT` expression list, we verify that the user has specified expressions as required by each opcode. Joins and subqueries will not be allowed, at least for now. From 704a247ebfd2f4a3580d2ff0e13b8be483429636 Mon Sep 17 00:00:00 2001 From: Tom Krouper Date: Thu, 31 Jan 2019 15:46:51 -0800 Subject: [PATCH 008/196] Recommended fix for https://nvd.nist.gov/vuln/detail/CVE-2018-14404 We've recently turned on [Security Alerts](https://github.blog/2017-11-16-introducing-security-alerts-on-github/) and found this alert marked as moderate severity. This change takes the recommendation to update to this version of nokogiri. Signed-off-by: Tom Krouper --- vitess.io/Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vitess.io/Gemfile.lock b/vitess.io/Gemfile.lock index 49a4a6e3af8..4c27d0fbfca 100644 --- a/vitess.io/Gemfile.lock +++ b/vitess.io/Gemfile.lock @@ -67,7 +67,7 @@ GEM neat (2.1.0) sass (~> 3.4) thor (~> 0.19) - nokogiri (1.8.2) + nokogiri (1.8.5) mini_portile2 (~> 2.3.0) pathutil (0.14.0) forwardable-extended (~> 2.6) From f8b53700b402d35259e279e2468845258d23b029 Mon Sep 17 00:00:00 2001 From: Tom Krouper Date: Thu, 31 Jan 2019 15:42:53 -0800 Subject: [PATCH 009/196] Recommended fix for https://nvd.nist.gov/vuln/detail/CVE-2018-17567 We've recently turned on [Security Alerts](https://github.blog/2017-11-16-introducing-security-alerts-on-github/) and found this alert marked as moderate severity. This change takes the recommendation to update to this verision of jekyll. Signed-off-by: Tom Krouper --- vitess.io/Gemfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vitess.io/Gemfile.lock b/vitess.io/Gemfile.lock index 49a4a6e3af8..66199fb6e9e 100644 --- a/vitess.io/Gemfile.lock +++ b/vitess.io/Gemfile.lock @@ -26,7 +26,7 @@ GEM activesupport (>= 2) nokogiri (~> 1.4) i18n (0.8.6) - jekyll (3.5.2) + jekyll (3.6.3) addressable (~> 2.4) colorator (~> 1.0) jekyll-sass-converter (~> 1.0) @@ -97,7 +97,7 @@ PLATFORMS DEPENDENCIES RedCloth (~> 4.3.2) bourbon - jekyll (= 3.5.2) + jekyll (= 3.6.3) jekyll-coffeescript (= 1.0.1) jekyll-feed (= 0.3.1) jekyll-redirect-from (= 0.11.0) From 9f9590bba28eacd84957f6acc69bc73829cb77d7 Mon Sep 17 00:00:00 2001 From: deepthi Date: Thu, 31 Jan 2019 16:02:37 -0800 Subject: [PATCH 010/196] implement date/time fsp for default and on update Signed-off-by: deepthi --- go/vt/sqlparser/ast.go | 4 +- go/vt/sqlparser/parse_test.go | 178 +- go/vt/sqlparser/sql.go | 5084 ++++++++++++++++----------------- go/vt/sqlparser/sql.y | 92 +- 4 files changed, 2718 insertions(+), 2640 deletions(-) diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index 3316e76cc51..fa33181cc06 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -1031,8 +1031,8 @@ type ColumnType struct { // Generic field options. NotNull BoolVal Autoincrement BoolVal - Default *SQLVal - OnUpdate *SQLVal + Default Expr + OnUpdate Expr Comment *SQLVal // Numeric field options diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 8dbc38d0e7d..4f4b29cbd88 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -1935,28 +1935,6 @@ func TestCreateTable(t *testing.T) { " col_multipolygon2 multipolygon not null\n" + ")", - // test defaults - "create table t (\n" + - " i1 int default 1,\n" + - " i2 int default null,\n" + - " f1 float default 1.23,\n" + - " s1 varchar default 'c',\n" + - " s2 varchar default 'this is a string',\n" + - " s3 varchar default null,\n" + - " s4 timestamp default current_timestamp,\n" + - " s5 bit(1) default B'0'\n" + - ")", - - // test key field options - "create table t (\n" + - " id int auto_increment primary key,\n" + - " username varchar unique key,\n" + - " email varchar unique,\n" + - " full_name varchar key,\n" + - " time1 timestamp on update current_timestamp,\n" + - " time2 timestamp default current_timestamp on update current_timestamp\n" + - ")", - // test defining indexes separately "create table t (\n" + " id int auto_increment,\n" + @@ -2107,6 +2085,46 @@ func TestCreateTable(t *testing.T) { " unique key by_username2 (username) key_block_size 8,\n" + " unique by_username3 (username) key_block_size 4\n" + ")", + }, { + // test defaults + input: "create table t (\n" + + " i1 int default 1,\n" + + " i2 int default null,\n" + + " f1 float default 1.23,\n" + + " s1 varchar default 'c',\n" + + " s2 varchar default 'this is a string',\n" + + " s3 varchar default null,\n" + + " s4 timestamp default current_timestamp,\n" + + " s5 bit(1) default B'0'\n" + + ")", + output: "create table t (\n" + + " i1 int default 1,\n" + + " i2 int default null,\n" + + " f1 float default 1.23,\n" + + " s1 varchar default 'c',\n" + + " s2 varchar default 'this is a string',\n" + + " s3 varchar default null,\n" + + " s4 timestamp default current_timestamp(),\n" + + " s5 bit(1) default B'0'\n" + + ")", + }, { + // test key field options + input: "create table t (\n" + + " id int auto_increment primary key,\n" + + " username varchar unique key,\n" + + " email varchar unique,\n" + + " full_name varchar key,\n" + + " time1 timestamp on update current_timestamp,\n" + + " time2 timestamp default current_timestamp on update current_timestamp\n" + + ")", + output: "create table t (\n" + + " id int auto_increment primary key,\n" + + " username varchar unique key,\n" + + " email varchar unique,\n" + + " full_name varchar key,\n" + + " time1 timestamp on update current_timestamp(),\n" + + " time2 timestamp default current_timestamp() on update current_timestamp()\n" + + ")", }, { // test current_timestamp with and without () input: "create table t (\n" + @@ -2117,12 +2135,120 @@ func TestCreateTable(t *testing.T) { " time5 timestamp(3) default current_timestamp(3) on update current_timestamp(3)\n" + ")", output: "create table t (\n" + - " time1 timestamp default current_timestamp,\n" + - " time2 timestamp default current_timestamp,\n" + - " time3 timestamp default current_timestamp on update current_timestamp,\n" + - " time4 timestamp default current_timestamp on update current_timestamp,\n" + + " time1 timestamp default current_timestamp(),\n" + + " time2 timestamp default current_timestamp(),\n" + + " time3 timestamp default current_timestamp() on update current_timestamp(),\n" + + " time4 timestamp default current_timestamp() on update current_timestamp(),\n" + " time5 timestamp(3) default current_timestamp(3) on update current_timestamp(3)\n" + ")", + }, { + // test utc_timestamp with and without () + input: "create table t (\n" + + " time1 timestamp default utc_timestamp,\n" + + " time2 timestamp default utc_timestamp(),\n" + + " time3 timestamp default utc_timestamp on update utc_timestamp,\n" + + " time4 timestamp default utc_timestamp() on update utc_timestamp(),\n" + + " time5 timestamp(4) default utc_timestamp(4) on update utc_timestamp(4)\n" + + ")", + output: "create table t (\n" + + " time1 timestamp default utc_timestamp(),\n" + + " time2 timestamp default utc_timestamp(),\n" + + " time3 timestamp default utc_timestamp() on update utc_timestamp(),\n" + + " time4 timestamp default utc_timestamp() on update utc_timestamp(),\n" + + " time5 timestamp(4) default utc_timestamp(4) on update utc_timestamp(4)\n" + + ")", + }, { + // test utc_time with and without () + input: "create table t (\n" + + " time1 timestamp default utc_time,\n" + + " time2 timestamp default utc_time(),\n" + + " time3 timestamp default utc_time on update utc_time,\n" + + " time4 timestamp default utc_time() on update utc_time(),\n" + + " time5 timestamp(5) default utc_time(5) on update utc_time(5)\n" + + ")", + output: "create table t (\n" + + " time1 timestamp default utc_time(),\n" + + " time2 timestamp default utc_time(),\n" + + " time3 timestamp default utc_time() on update utc_time(),\n" + + " time4 timestamp default utc_time() on update utc_time(),\n" + + " time5 timestamp(5) default utc_time(5) on update utc_time(5)\n" + + ")", + }, { + // test utc_date with and without () + input: "create table t (\n" + + " time1 timestamp default utc_date,\n" + + " time2 timestamp default utc_date(),\n" + + " time3 timestamp default utc_date on update utc_date,\n" + + " time4 timestamp default utc_date() on update utc_date()\n" + + ")", + output: "create table t (\n" + + " time1 timestamp default utc_date(),\n" + + " time2 timestamp default utc_date(),\n" + + " time3 timestamp default utc_date() on update utc_date(),\n" + + " time4 timestamp default utc_date() on update utc_date()\n" + + ")", + }, { + // test localtime with and without () + input: "create table t (\n" + + " time1 timestamp default localtime,\n" + + " time2 timestamp default localtime(),\n" + + " time3 timestamp default localtime on update localtime,\n" + + " time4 timestamp default localtime() on update localtime(),\n" + + " time5 timestamp(6) default localtime(6) on update localtime(6)\n" + + ")", + output: "create table t (\n" + + " time1 timestamp default localtime(),\n" + + " time2 timestamp default localtime(),\n" + + " time3 timestamp default localtime() on update localtime(),\n" + + " time4 timestamp default localtime() on update localtime(),\n" + + " time5 timestamp(6) default localtime(6) on update localtime(6)\n" + + ")", + }, { + // test localtimestamp with and without () + input: "create table t (\n" + + " time1 timestamp default localtimestamp,\n" + + " time2 timestamp default localtimestamp(),\n" + + " time3 timestamp default localtimestamp on update localtimestamp,\n" + + " time4 timestamp default localtimestamp() on update localtimestamp(),\n" + + " time5 timestamp(1) default localtimestamp(1) on update localtimestamp(1)\n" + + ")", + output: "create table t (\n" + + " time1 timestamp default localtimestamp(),\n" + + " time2 timestamp default localtimestamp(),\n" + + " time3 timestamp default localtimestamp() on update localtimestamp(),\n" + + " time4 timestamp default localtimestamp() on update localtimestamp(),\n" + + " time5 timestamp(1) default localtimestamp(1) on update localtimestamp(1)\n" + + ")", + }, { + // test current_date with and without () + input: "create table t (\n" + + " time1 timestamp default current_date,\n" + + " time2 timestamp default current_date(),\n" + + " time3 timestamp default current_date on update current_date,\n" + + " time4 timestamp default current_date() on update current_date()\n" + + ")", + output: "create table t (\n" + + " time1 timestamp default current_date(),\n" + + " time2 timestamp default current_date(),\n" + + " time3 timestamp default current_date() on update current_date(),\n" + + " time4 timestamp default current_date() on update current_date()\n" + + ")", + }, { + // test current_time with and without () + input: "create table t (\n" + + " time1 timestamp default current_time,\n" + + " time2 timestamp default current_time(),\n" + + " time3 timestamp default current_time on update current_time,\n" + + " time4 timestamp default current_time() on update current_time(),\n" + + " time5 timestamp(2) default current_time(2) on update current_time(2)\n" + + ")", + output: "create table t (\n" + + " time1 timestamp default current_time(),\n" + + " time2 timestamp default current_time(),\n" + + " time3 timestamp default current_time() on update current_time(),\n" + + " time4 timestamp default current_time() on update current_time(),\n" + + " time5 timestamp(2) default current_time(2) on update current_time(2)\n" + + ")", }, } for _, tcase := range testCases { diff --git a/go/vt/sqlparser/sql.go b/go/vt/sqlparser/sql.go index f9bd182cd27..b9de5232306 100644 --- a/go/vt/sqlparser/sql.go +++ b/go/vt/sqlparser/sql.go @@ -64,6 +64,7 @@ type yySymType struct { expr Expr exprs Exprs boolVal BoolVal + sqlVal *SQLVal colTuple ColTuple values Values valTuple ValTuple @@ -84,7 +85,7 @@ type yySymType struct { TableSpec *TableSpec columnType ColumnType colKeyOpt ColumnKeyOption - optVal *SQLVal + optVal Expr LengthScaleOption LengthScaleOption columnDefinition *ColumnDefinition indexDefinition *IndexDefinition @@ -638,384 +639,478 @@ var yyExca = [...]int{ 5, 29, -2, 4, -1, 37, - 159, 300, - 160, 300, - -2, 290, + 159, 293, + 160, 293, + -2, 283, -1, 267, - 112, 644, - -2, 640, + 112, 638, + -2, 634, -1, 268, - 112, 645, - -2, 641, + 112, 639, + -2, 635, -1, 333, - 82, 817, + 82, 811, -2, 60, -1, 334, - 82, 774, + 82, 768, -2, 61, -1, 339, - 82, 753, - -2, 606, + 82, 747, + -2, 600, -1, 341, - 82, 795, - -2, 608, - -1, 609, - 1, 352, - 5, 352, - 12, 352, - 13, 352, - 14, 352, - 15, 352, - 17, 352, - 19, 352, - 30, 352, - 31, 352, - 42, 352, - 43, 352, - 44, 352, - 45, 352, - 46, 352, - 48, 352, - 49, 352, - 52, 352, - 53, 352, - 55, 352, - 56, 352, - 268, 352, - -2, 370, - -1, 612, + 82, 789, + -2, 602, + -1, 610, + 1, 345, + 5, 345, + 12, 345, + 13, 345, + 14, 345, + 15, 345, + 17, 345, + 19, 345, + 30, 345, + 31, 345, + 42, 345, + 43, 345, + 44, 345, + 45, 345, + 46, 345, + 48, 345, + 49, 345, + 52, 345, + 53, 345, + 55, 345, + 56, 345, + 268, 345, + -2, 363, + -1, 613, 53, 43, 55, 43, -2, 45, - -1, 752, - 112, 647, - -2, 643, - -1, 978, + -1, 753, + 112, 641, + -2, 637, + -1, 974, 5, 30, - -2, 436, - -1, 1015, + -2, 429, + -1, 1006, 5, 29, - -2, 580, - -1, 1272, + -2, 574, + -1, 1258, 5, 30, - -2, 581, - -1, 1329, + -2, 575, + -1, 1314, 5, 29, - -2, 583, - -1, 1412, + -2, 577, + -1, 1395, 5, 30, - -2, 584, + -2, 578, } const yyPrivate = 57344 -const yyLast = 12774 +const yyLast = 12925 var yyAct = [...]int{ - 268, 1447, 1437, 1227, 1400, 1018, 272, 566, 1341, 1292, - 1306, 1036, 864, 1107, 1162, 1196, 57, 841, 1163, 246, - 860, 1159, 1019, 943, 907, 565, 3, 1061, 873, 893, - 887, 863, 81, 298, 1042, 1169, 208, 839, 1175, 208, - 777, 1130, 717, 1087, 338, 787, 970, 611, 1078, 784, - 622, 877, 843, 828, 805, 237, 754, 498, 504, 903, - 621, 606, 439, 332, 952, 518, 821, 208, 81, 605, - 255, 329, 208, 327, 208, 56, 510, 245, 1440, 1424, - 1435, 580, 1410, 205, 1432, 1228, 1423, 1152, 1264, 1409, - 444, 1352, 261, 472, 1191, 1192, 274, 61, 1190, 270, - 238, 239, 240, 241, 1049, 854, 244, 1048, 492, 259, - 1050, 855, 856, 243, 328, 203, 199, 200, 201, 441, - 242, 443, 218, 63, 64, 65, 66, 67, 926, 1374, + 268, 1419, 1213, 1429, 1098, 1383, 272, 1009, 1291, 1326, + 860, 1027, 566, 298, 1153, 470, 1187, 837, 1154, 57, + 285, 856, 1010, 246, 1150, 1052, 835, 903, 939, 1278, + 565, 3, 81, 1033, 859, 1160, 208, 869, 1166, 208, + 1121, 237, 778, 338, 788, 718, 1069, 1078, 623, 966, + 873, 839, 824, 806, 498, 504, 785, 755, 607, 622, + 332, 606, 439, 817, 510, 518, 899, 208, 81, 270, + 948, 327, 208, 255, 208, 329, 56, 581, 1422, 1406, + 1417, 1393, 245, 335, 1414, 1214, 238, 239, 240, 241, + 1405, 1143, 244, 1392, 1250, 444, 1182, 1183, 624, 580, + 625, 922, 472, 203, 199, 200, 201, 1040, 259, 1181, + 1039, 61, 850, 1041, 492, 921, 851, 852, 243, 242, + 889, 1358, 531, 530, 540, 541, 533, 534, 535, 536, + 537, 538, 539, 532, 1060, 882, 542, 63, 64, 65, + 66, 67, 310, 926, 316, 317, 314, 315, 313, 312, + 311, 1281, 920, 488, 457, 195, 1297, 197, 318, 319, + 890, 489, 486, 487, 1233, 1231, 236, 1101, 474, 1100, + 476, 1416, 491, 481, 482, 1122, 693, 691, 468, 1413, + 1376, 1433, 1384, 1097, 787, 218, 818, 874, 458, 1437, + 446, 197, 1102, 1028, 1030, 1335, 208, 697, 684, 208, + 473, 475, 917, 914, 915, 208, 913, 1085, 1176, 231, + 692, 208, 1124, 1327, 81, 1175, 81, 1174, 81, 81, + 442, 81, 876, 81, 202, 876, 1329, 694, 449, 210, + 198, 933, 81, 1365, 932, 1261, 1083, 924, 927, 876, + 1094, 554, 555, 1108, 984, 1126, 1096, 1130, 960, 1125, + 196, 1123, 727, 522, 1053, 857, 1128, 464, 883, 517, + 211, 532, 81, 1199, 542, 1127, 542, 214, 440, 506, + 1029, 730, 731, 919, 719, 222, 217, 724, 1129, 1131, + 1374, 1344, 507, 979, 494, 495, 890, 1431, 471, 1164, + 1432, 440, 1430, 1359, 1328, 918, 1336, 1334, 516, 515, + 454, 626, 1145, 1084, 274, 1147, 1391, 220, 1089, 1086, + 1079, 1087, 1082, 230, 1200, 517, 1080, 1081, 875, 516, + 515, 875, 941, 807, 438, 208, 208, 208, 686, 1399, + 1088, 81, 1058, 516, 515, 875, 517, 81, 923, 212, + 872, 870, 1095, 871, 1093, 762, 335, 1379, 868, 874, + 517, 70, 605, 925, 1397, 720, 460, 461, 462, 760, + 761, 759, 515, 451, 508, 452, 224, 215, 453, 225, + 226, 227, 229, 512, 228, 234, 445, 1287, 517, 216, + 219, 1286, 213, 233, 232, 516, 515, 71, 1073, 584, + 586, 1438, 590, 592, 477, 595, 478, 479, 614, 480, + 940, 483, 517, 879, 1072, 807, 620, 993, 1061, 880, + 493, 583, 585, 587, 589, 591, 593, 594, 531, 530, + 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, + 1439, 1375, 542, 535, 536, 537, 538, 539, 532, 208, + 779, 542, 780, 978, 81, 977, 745, 747, 748, 208, + 208, 81, 746, 447, 448, 208, 194, 1253, 208, 54, + 1308, 208, 516, 515, 1042, 208, 1043, 81, 81, 758, + 726, 967, 81, 81, 81, 81, 81, 81, 1284, 517, + 22, 1105, 81, 81, 533, 534, 535, 536, 537, 538, + 539, 532, 299, 51, 542, 531, 530, 540, 541, 533, + 534, 535, 536, 537, 538, 539, 532, 725, 706, 542, + 81, 957, 958, 959, 208, 1070, 1332, 1415, 497, 297, + 81, 324, 325, 1372, 516, 515, 1401, 497, 1341, 698, + 732, 1332, 1387, 1332, 497, 704, 1332, 1366, 752, 756, + 250, 517, 1332, 1331, 51, 1276, 1275, 1263, 497, 1260, + 497, 79, 251, 540, 541, 533, 534, 535, 536, 537, + 538, 539, 532, 1216, 81, 542, 753, 288, 287, 290, + 291, 292, 293, 1053, 552, 1048, 289, 294, 1206, 1205, + 797, 801, 734, 1202, 1203, 749, 808, 337, 1202, 1201, + 972, 497, 1340, 751, 821, 497, 1196, 81, 81, 792, + 790, 497, 1163, 781, 208, 703, 702, 687, 685, 682, + 24, 466, 208, 208, 633, 632, 208, 208, 459, 1034, + 81, 877, 683, 58, 782, 783, 1246, 497, 790, 690, + 610, 24, 1111, 81, 1004, 335, 1151, 1256, 1005, 1163, + 617, 804, 845, 1343, 1034, 707, 708, 988, 861, 821, + 709, 710, 711, 712, 713, 714, 814, 1204, 54, 1313, + 715, 716, 821, 972, 531, 530, 540, 541, 533, 534, + 535, 536, 537, 538, 539, 532, 972, 843, 542, 54, + 847, 848, 618, 986, 616, 208, 81, 1163, 81, 820, + 983, 987, 81, 81, 208, 208, 864, 208, 208, 1044, + 24, 208, 81, 981, 849, 844, 469, 616, 469, 905, + 469, 469, 998, 469, 821, 469, 997, 972, 208, 616, + 208, 208, 619, 208, 469, 728, 696, 985, 252, 54, + 1407, 1293, 884, 337, 982, 337, 1268, 337, 337, 904, + 337, 1192, 337, 752, 51, 901, 902, 980, 54, 1167, + 1168, 337, 1047, 900, 793, 794, 895, 894, 1099, 551, + 803, 907, 553, 1424, 1420, 1194, 1170, 1151, 891, 892, + 893, 753, 1074, 756, 1021, 722, 54, 700, 740, 1022, + 1173, 520, 1172, 813, 949, 815, 816, 950, 1018, 1017, + 564, 809, 568, 569, 570, 571, 572, 573, 574, 575, + 576, 1411, 579, 582, 582, 582, 588, 582, 582, 588, + 582, 596, 597, 598, 599, 600, 601, 962, 611, 256, + 257, 1404, 208, 208, 208, 208, 208, 1011, 1019, 1023, + 757, 830, 831, 1020, 208, 1107, 945, 208, 1409, 955, + 954, 208, 1065, 631, 467, 208, 1057, 1381, 1006, 1380, + 337, 826, 829, 830, 831, 827, 628, 828, 832, 992, + 81, 1167, 1168, 511, 909, 499, 911, 792, 1311, 1055, + 1045, 1035, 1049, 834, 1254, 861, 1289, 500, 509, 1036, + 937, 1013, 1014, 1012, 1016, 1024, 1015, 826, 829, 830, + 831, 827, 1032, 828, 832, 910, 699, 511, 1037, 1054, + 247, 885, 886, 887, 888, 253, 254, 1348, 81, 81, + 248, 1064, 58, 1066, 1067, 1068, 610, 896, 897, 898, + 610, 1347, 1050, 1051, 956, 530, 540, 541, 533, 534, + 535, 536, 537, 538, 539, 532, 469, 81, 542, 953, + 1295, 1034, 1071, 469, 490, 1426, 1425, 952, 717, 513, + 1426, 1362, 208, 1282, 1077, 723, 60, 62, 615, 469, + 469, 81, 1090, 337, 469, 469, 469, 469, 469, 469, + 337, 971, 55, 1, 469, 469, 1113, 1418, 1215, 1290, + 916, 1382, 1325, 1186, 1104, 867, 337, 337, 858, 990, + 69, 337, 337, 337, 337, 337, 337, 437, 68, 1373, + 1138, 337, 337, 866, 265, 865, 1062, 1063, 81, 81, + 1144, 1011, 1152, 1115, 1333, 1280, 878, 1120, 1114, 1155, + 1133, 1132, 1059, 881, 1193, 1056, 1378, 639, 753, 736, + 637, 638, 81, 636, 641, 640, 635, 496, 1157, 520, + 221, 330, 337, 1162, 833, 81, 51, 81, 81, 627, + 906, 514, 72, 1178, 1171, 1092, 1091, 1185, 912, 484, + 861, 568, 861, 485, 757, 223, 550, 1177, 951, 1180, + 1038, 336, 1158, 729, 503, 208, 1190, 1191, 1346, 1184, + 1294, 991, 577, 784, 1197, 1198, 1189, 1076, 805, 273, + 744, 286, 208, 799, 799, 283, 284, 735, 81, 799, + 1003, 81, 81, 208, 836, 524, 271, 263, 611, 81, + 609, 602, 208, 825, 823, 1103, 811, 812, 497, 822, + 1208, 1169, 1165, 608, 1113, 1110, 610, 610, 610, 610, + 610, 1249, 1209, 1220, 1211, 1357, 739, 26, 1222, 337, + 59, 610, 258, 19, 1221, 18, 17, 20, 16, 610, + 15, 14, 337, 455, 1229, 531, 530, 540, 541, 533, + 534, 535, 536, 537, 538, 539, 532, 30, 21, 542, + 1011, 13, 12, 11, 10, 1247, 9, 1255, 469, 8, + 469, 7, 1264, 6, 5, 81, 1265, 4, 249, 23, + 2, 0, 0, 81, 469, 1045, 0, 0, 0, 0, + 861, 0, 1274, 0, 0, 337, 0, 337, 81, 0, + 0, 928, 929, 0, 0, 81, 0, 0, 0, 0, + 0, 337, 0, 0, 0, 0, 0, 0, 0, 0, + 1292, 0, 531, 530, 540, 541, 533, 534, 535, 536, + 537, 538, 539, 532, 0, 961, 542, 337, 0, 531, + 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, + 532, 81, 81, 542, 81, 0, 0, 0, 0, 81, + 1155, 81, 81, 81, 208, 1312, 0, 81, 0, 0, + 556, 557, 558, 559, 560, 561, 562, 563, 1319, 0, + 1314, 1324, 0, 1330, 81, 0, 0, 0, 1320, 733, + 1321, 1322, 1323, 1337, 0, 1338, 0, 1339, 0, 0, + 1007, 1008, 0, 0, 611, 611, 611, 611, 611, 0, + 0, 0, 1283, 1345, 1285, 0, 0, 1155, 1363, 836, + 0, 1031, 0, 81, 0, 1371, 1370, 611, 0, 0, + 799, 0, 0, 0, 81, 81, 1364, 0, 1296, 0, + 0, 0, 1385, 0, 0, 1386, 0, 789, 791, 1292, + 861, 1389, 0, 0, 0, 0, 81, 0, 0, 1011, + 1394, 0, 0, 0, 0, 0, 0, 208, 0, 337, + 0, 1226, 1227, 0, 1228, 81, 1288, 1230, 0, 1232, + 0, 0, 1403, 0, 0, 0, 0, 0, 0, 0, + 0, 469, 0, 0, 0, 0, 1410, 1408, 81, 0, + 0, 0, 0, 0, 0, 0, 610, 0, 0, 0, + 1423, 0, 0, 0, 0, 0, 0, 1075, 337, 469, + 1434, 0, 0, 0, 0, 0, 0, 1412, 0, 0, + 0, 526, 0, 529, 1243, 497, 0, 1277, 0, 543, + 544, 545, 546, 547, 548, 549, 337, 527, 528, 525, 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 925, 623, 542, 624, 231, 1204, 1205, 1206, - 195, 886, 197, 1069, 488, 1209, 1207, 786, 1295, 474, - 1312, 476, 489, 486, 487, 457, 491, 894, 1247, 1245, - 930, 236, 481, 482, 692, 1110, 1109, 690, 1434, 924, - 1431, 1401, 1106, 822, 1392, 1451, 878, 1342, 1455, 458, - 446, 473, 475, 1037, 1039, 197, 208, 211, 1111, 208, - 1344, 696, 683, 1185, 214, 208, 1184, 1183, 691, 880, - 442, 208, 222, 217, 81, 693, 81, 880, 81, 81, - 454, 81, 449, 81, 210, 198, 861, 554, 555, 921, - 918, 919, 81, 917, 1350, 1381, 202, 937, 1062, 1275, - 936, 1103, 1117, 450, 220, 196, 456, 1105, 988, 964, - 230, 880, 463, 726, 522, 542, 464, 532, 465, 1213, - 542, 470, 81, 723, 928, 931, 506, 718, 1343, 517, - 1038, 945, 516, 515, 1390, 1360, 212, 507, 1173, 471, - 440, 440, 70, 451, 1154, 452, 625, 806, 453, 517, - 894, 1449, 685, 806, 1450, 997, 1448, 1067, 494, 495, - 923, 1375, 1408, 224, 215, 879, 225, 226, 227, 229, - 1214, 228, 234, 879, 438, 1094, 216, 219, 71, 213, - 233, 232, 922, 299, 51, 208, 208, 208, 883, 335, - 1208, 81, 1456, 1131, 884, 1351, 1349, 81, 515, 983, - 501, 505, 1395, 1104, 1092, 1102, 54, 879, 719, 944, - 508, 1414, 876, 874, 517, 875, 757, 523, 512, 1302, - 872, 878, 761, 604, 1301, 927, 552, 460, 461, 462, - 1133, 1457, 603, 1082, 612, 51, 759, 760, 758, 778, - 929, 779, 445, 251, 961, 962, 963, 1388, 1081, 516, - 515, 1070, 567, 582, 584, 586, 588, 590, 592, 593, - 613, 578, 619, 1135, 1416, 1139, 517, 1134, 1051, 1132, - 1052, 1093, 1391, 1323, 1137, 1299, 1098, 1095, 1088, 1096, - 1091, 22, 609, 1136, 1089, 1090, 535, 536, 537, 538, - 539, 532, 1114, 982, 542, 981, 1138, 1140, 1097, 208, - 516, 515, 1079, 1230, 81, 1347, 1433, 1156, 497, 208, - 208, 81, 516, 515, 1062, 208, 194, 517, 208, 447, - 448, 208, 725, 729, 730, 208, 1057, 81, 81, 517, - 1419, 497, 81, 81, 81, 81, 81, 81, 744, 746, - 747, 250, 81, 81, 745, 780, 633, 702, 533, 534, - 535, 536, 537, 538, 539, 532, 687, 688, 542, 724, - 1347, 1404, 694, 1347, 497, 328, 1347, 1382, 700, 705, - 81, 516, 515, 701, 208, 686, 516, 515, 1347, 1346, - 81, 324, 325, 1290, 1289, 1417, 731, 684, 517, 703, - 681, 697, 466, 517, 1277, 497, 1357, 469, 459, 469, - 616, 469, 469, 1356, 469, 1172, 469, 288, 287, 290, - 291, 292, 293, 1274, 497, 469, 289, 294, 1353, 755, - 1210, 740, 1220, 1219, 81, 1216, 1217, 752, 1216, 1215, - 976, 497, 825, 497, 1043, 51, 789, 497, 58, 733, - 796, 800, 617, 720, 615, 748, 807, 750, 632, 631, - 551, 881, 335, 553, 791, 1160, 81, 81, 1172, 848, - 789, 615, 1270, 208, 1359, 825, 1218, 1120, 741, 742, - 1053, 208, 208, 1043, 992, 208, 208, 825, 976, 81, - 24, 564, 756, 568, 569, 570, 571, 572, 573, 574, - 575, 576, 81, 579, 581, 583, 585, 587, 589, 591, - 587, 594, 595, 596, 597, 598, 599, 600, 818, 610, - 823, 976, 849, 803, 781, 782, 1172, 853, 991, 990, - 987, 567, 985, 850, 794, 795, 1007, 1006, 54, 1442, - 976, 615, 889, 890, 891, 892, 895, 896, 897, 847, - 618, 852, 851, 824, 208, 81, 24, 81, 900, 901, - 902, 81, 81, 208, 208, 868, 208, 208, 24, 727, - 208, 81, 695, 989, 986, 909, 984, 609, 825, 54, - 1013, 609, 1425, 1398, 1014, 1308, 1297, 208, 859, 208, - 208, 888, 208, 1282, 252, 908, 1328, 792, 793, 1201, - 1056, 912, 904, 802, 54, 809, 297, 905, 906, 899, - 934, 935, 898, 938, 939, 1438, 54, 940, 1176, 1177, - 1108, 911, 1203, 1179, 1160, 817, 1083, 819, 820, 830, - 833, 834, 835, 831, 942, 832, 836, 469, 79, 948, - 739, 752, 54, 721, 469, 699, 1030, 1028, 1182, 1181, - 1027, 1031, 1029, 1026, 751, 1032, 953, 834, 835, 954, - 469, 469, 755, 256, 257, 469, 469, 469, 469, 469, - 469, 1429, 1422, 1116, 337, 469, 469, 949, 511, 1427, - 959, 958, 499, 1074, 630, 966, 467, 950, 951, 1066, - 505, 1304, 1397, 509, 500, 1396, 208, 208, 208, 208, - 208, 1020, 1326, 830, 833, 834, 835, 831, 208, 832, - 836, 208, 1064, 1176, 1177, 208, 1058, 1015, 1268, 208, - 914, 698, 838, 253, 254, 756, 511, 957, 247, 996, - 1364, 248, 58, 1363, 81, 956, 791, 1310, 1043, 490, - 1444, 1443, 60, 716, 513, 1444, 1054, 51, 1378, 1296, - 335, 722, 977, 62, 1045, 614, 1044, 55, 1022, 1023, - 1033, 1025, 568, 865, 1, 1021, 960, 1041, 1024, 998, - 1436, 1229, 1305, 920, 1046, 1063, 1399, 1340, 1195, 871, - 862, 69, 81, 81, 1073, 437, 1075, 1076, 1077, 1071, - 1072, 68, 609, 609, 609, 609, 609, 1059, 1060, 1389, - 870, 869, 1348, 1294, 840, 882, 1068, 609, 610, 885, - 1202, 81, 1394, 975, 1065, 609, 638, 636, 1080, 637, - 337, 635, 337, 640, 337, 337, 208, 337, 639, 337, - 634, 994, 1099, 221, 330, 81, 837, 626, 337, 910, - 514, 72, 1086, 1101, 1100, 916, 484, 485, 223, 550, - 955, 496, 1047, 336, 1167, 1113, 728, 503, 751, 1362, - 1309, 995, 577, 804, 273, 743, 286, 283, 520, 285, - 284, 734, 1012, 1118, 524, 271, 263, 608, 469, 601, - 469, 1153, 829, 827, 1124, 1123, 826, 81, 81, 1161, - 1020, 468, 1129, 1141, 469, 1142, 1178, 1174, 607, 1119, - 1263, 1373, 738, 752, 26, 59, 258, 19, 1115, 18, - 17, 81, 1166, 20, 16, 15, 14, 455, 1164, 30, - 21, 13, 12, 1171, 81, 11, 81, 81, 10, 1187, - 9, 8, 7, 1180, 6, 5, 4, 337, 1194, 249, - 23, 2, 0, 627, 0, 965, 1186, 0, 0, 1189, - 0, 0, 0, 0, 208, 1193, 1198, 1199, 1200, 0, - 1155, 0, 1211, 1212, 0, 0, 0, 0, 0, 0, - 0, 208, 0, 0, 0, 0, 0, 81, 0, 0, - 81, 81, 208, 0, 0, 0, 0, 0, 81, 0, - 0, 208, 0, 0, 0, 865, 0, 0, 0, 0, - 0, 1221, 0, 0, 265, 0, 1188, 1234, 0, 0, - 0, 0, 0, 1222, 0, 1016, 1017, 0, 1224, 610, - 610, 610, 610, 610, 1235, 1223, 0, 1225, 1236, 1233, - 1243, 0, 1240, 1241, 840, 1242, 1040, 0, 1244, 0, - 1246, 0, 610, 0, 0, 0, 0, 0, 0, 1020, - 337, 0, 0, 1269, 0, 0, 0, 337, 1278, 0, - 0, 0, 0, 0, 81, 1279, 0, 0, 0, 0, - 0, 0, 81, 337, 337, 0, 1054, 1288, 337, 337, - 337, 337, 337, 337, 0, 0, 0, 609, 337, 337, - 0, 0, 81, 0, 0, 0, 1122, 0, 1291, 81, - 0, 0, 0, 0, 0, 0, 469, 477, 0, 478, - 479, 0, 480, 732, 483, 1298, 735, 1300, 0, 1265, - 1147, 0, 0, 493, 0, 0, 520, 0, 567, 337, - 0, 0, 0, 0, 469, 0, 1280, 0, 0, 1281, - 0, 1311, 1283, 0, 0, 81, 81, 0, 81, 0, - 0, 0, 0, 81, 0, 81, 81, 81, 208, 1327, - 0, 81, 1335, 0, 1336, 1337, 1338, 0, 1334, 1329, - 783, 788, 790, 0, 1164, 1339, 1345, 0, 0, 81, - 798, 798, 0, 0, 0, 865, 798, 865, 1361, 1354, - 0, 1355, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 815, 816, 542, 0, 0, 0, 1165, 0, - 51, 0, 0, 1379, 0, 0, 0, 0, 81, 1387, - 0, 1386, 0, 0, 0, 337, 1380, 0, 0, 0, - 81, 81, 1164, 0, 0, 0, 0, 0, 337, 0, - 1402, 0, 1406, 1403, 0, 0, 0, 0, 0, 1122, - 0, 0, 81, 0, 1411, 1020, 0, 0, 0, 0, - 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, - 0, 0, 81, 0, 0, 0, 0, 0, 0, 0, - 556, 557, 558, 559, 560, 561, 562, 563, 1421, 0, - 0, 337, 0, 337, 1426, 1428, 81, 932, 933, 0, - 0, 0, 0, 0, 0, 1430, 0, 337, 0, 1441, - 1415, 0, 0, 0, 610, 0, 1452, 0, 0, 0, - 0, 0, 0, 0, 0, 865, 1405, 567, 0, 0, - 0, 0, 0, 337, 0, 682, 0, 0, 0, 0, - 0, 0, 689, 0, 0, 0, 1262, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 706, 707, - 1307, 0, 0, 708, 709, 710, 711, 712, 713, 0, - 0, 0, 0, 714, 715, 0, 0, 1284, 1285, 1286, - 0, 0, 0, 0, 0, 0, 973, 0, 0, 0, - 974, 0, 0, 0, 0, 0, 0, 978, 979, 980, - 0, 0, 0, 0, 0, 0, 0, 0, 993, 1260, - 497, 0, 0, 999, 1000, 469, 1001, 1002, 1003, 1004, - 1005, 0, 0, 1008, 1009, 1010, 1011, 0, 0, 0, - 0, 798, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 0, 1035, 542, 531, 530, 540, - 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, - 0, 542, 1257, 497, 1165, 0, 0, 1330, 0, 0, + 539, 532, 0, 1252, 542, 0, 0, 0, 0, 0, 337, 0, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 0, 971, 542, 0, 0, 0, - 0, 1307, 865, 0, 0, 0, 0, 0, 1358, 0, - 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 1254, 497, 542, 0, 0, 0, 1084, 337, - 0, 0, 1165, 0, 51, 0, 0, 0, 0, 753, - 0, 0, 762, 763, 764, 765, 766, 767, 768, 769, - 770, 771, 772, 773, 774, 775, 776, 337, 0, 0, - 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 0, 0, 542, 0, 0, 0, 0, 0, - 0, 337, 0, 0, 0, 0, 913, 0, 915, 0, - 0, 1128, 0, 0, 0, 0, 808, 0, 810, 0, - 811, 0, 941, 497, 812, 337, 813, 0, 0, 814, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 502, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 798, 0, 0, 1168, 1170, 0, 0, 0, 1439, 0, - 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 0, 0, 542, 0, 206, 1170, 0, 235, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 337, 0, 337, 1197, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 262, 0, 0, 206, 526, 0, - 529, 0, 206, 0, 206, 0, 543, 544, 545, 546, - 547, 548, 549, 0, 527, 528, 525, 531, 530, 540, + 537, 538, 539, 532, 0, 0, 542, 0, 1156, 0, + 51, 0, 0, 0, 337, 0, 0, 0, 0, 0, + 0, 531, 530, 540, 541, 533, 534, 535, 536, 537, + 538, 539, 532, 0, 799, 542, 0, 1159, 1161, 754, + 0, 0, 763, 764, 765, 766, 767, 768, 769, 770, + 771, 772, 773, 774, 775, 776, 777, 0, 0, 0, + 0, 1161, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1244, 337, 0, 337, 1188, 0, 0, + 0, 0, 0, 969, 0, 0, 0, 970, 0, 0, + 0, 0, 0, 0, 974, 975, 976, 810, 0, 0, + 0, 0, 0, 0, 0, 989, 0, 0, 0, 0, + 995, 0, 996, 0, 611, 999, 1000, 1001, 1002, 0, + 0, 0, 0, 0, 0, 0, 0, 1212, 0, 612, + 1217, 1218, 0, 0, 0, 0, 0, 1026, 337, 0, + 0, 0, 1240, 497, 0, 0, 1248, 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, - 0, 542, 0, 1226, 0, 0, 1231, 1232, 0, 0, - 0, 0, 0, 0, 337, 0, 0, 0, 0, 1237, - 0, 0, 0, 0, 0, 0, 1239, 0, 0, 0, - 0, 0, 1251, 497, 0, 0, 0, 1248, 1249, 1250, - 0, 1253, 0, 0, 1256, 0, 1259, 0, 0, 0, - 0, 0, 0, 0, 967, 968, 969, 0, 0, 0, - 0, 1271, 1272, 1273, 0, 1276, 0, 0, 0, 798, + 0, 542, 0, 0, 0, 205, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1270, 1271, 1272, 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 1287, 0, 542, 0, 0, 0, 1267, 0, - 337, 0, 0, 0, 1085, 0, 206, 0, 1293, 206, - 0, 0, 0, 1266, 0, 206, 0, 0, 0, 0, - 0, 206, 0, 0, 1261, 0, 0, 0, 337, 0, - 0, 0, 1112, 0, 0, 337, 531, 530, 540, 541, - 533, 534, 535, 536, 537, 538, 539, 532, 0, 0, - 542, 531, 530, 540, 541, 533, 534, 535, 536, 537, - 538, 539, 532, 0, 0, 542, 0, 0, 0, 1322, - 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, - 532, 1331, 1332, 542, 1333, 0, 0, 0, 0, 1293, - 0, 1293, 1293, 1293, 0, 0, 0, 1197, 531, 530, - 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, - 0, 0, 542, 0, 0, 1293, 0, 0, 0, 1365, - 1366, 1367, 1368, 1369, 1370, 1371, 1372, 0, 0, 0, - 1376, 1377, 0, 0, 0, 206, 206, 206, 0, 0, - 0, 0, 1383, 1384, 1385, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1393, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 337, 337, 0, 0, - 0, 0, 0, 0, 0, 0, 1126, 1127, 0, 1407, - 0, 0, 0, 0, 0, 798, 1412, 0, 1413, 1143, - 1144, 1145, 1146, 0, 1148, 1149, 1150, 1151, 0, 24, - 25, 52, 27, 28, 1258, 1418, 0, 0, 1420, 0, - 0, 1157, 1158, 0, 0, 0, 0, 0, 43, 1255, - 0, 0, 0, 29, 48, 49, 0, 0, 0, 0, - 0, 0, 1293, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 38, 0, 0, 0, 54, 0, 206, - 0, 1453, 1454, 0, 0, 0, 0, 0, 0, 206, - 206, 0, 0, 0, 0, 206, 0, 0, 206, 1252, - 0, 206, 0, 0, 0, 704, 0, 0, 531, 530, - 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, - 0, 0, 542, 531, 530, 540, 541, 533, 534, 535, - 536, 537, 538, 539, 532, 0, 0, 542, 31, 32, - 34, 33, 36, 1303, 50, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, - 1238, 0, 0, 704, 0, 37, 44, 45, 0, 0, - 46, 47, 35, 531, 530, 540, 541, 533, 534, 535, - 536, 537, 538, 539, 532, 39, 40, 542, 41, 42, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1125, 0, 0, 262, 0, 0, 0, 0, - 262, 262, 0, 0, 799, 799, 262, 0, 0, 0, - 799, 0, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 0, 655, 542, 972, 262, 262, - 262, 262, 0, 206, 0, 0, 0, 0, 0, 0, - 0, 206, 845, 0, 0, 206, 206, 531, 530, 540, + 539, 532, 0, 799, 542, 0, 328, 0, 0, 0, + 502, 441, 0, 443, 1116, 0, 0, 0, 1237, 497, + 469, 0, 0, 0, 337, 0, 0, 0, 0, 261, + 0, 0, 1279, 0, 531, 530, 540, 541, 533, 534, + 535, 536, 537, 538, 539, 532, 206, 337, 542, 235, + 0, 0, 0, 0, 337, 0, 531, 530, 540, 541, + 533, 534, 535, 536, 537, 538, 539, 532, 0, 1156, + 542, 0, 1315, 0, 262, 0, 0, 206, 1241, 0, + 0, 0, 206, 1119, 206, 963, 964, 965, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1316, 1317, 1342, 1318, 0, 0, 0, 0, 1279, 0, + 1279, 1279, 1279, 1238, 0, 0, 1188, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1156, 0, 51, 0, + 0, 0, 0, 1279, 0, 450, 0, 0, 456, 0, + 0, 0, 0, 0, 463, 0, 0, 0, 0, 0, + 465, 0, 531, 530, 540, 541, 533, 534, 535, 536, + 537, 538, 539, 532, 0, 0, 542, 0, 0, 0, + 0, 0, 1377, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 337, 337, 0, 0, 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, - 0, 542, 0, 0, 53, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1313, 1314, 0, 1315, - 1316, 0, 1317, 1318, 0, 1319, 1320, 1321, 0, 0, - 0, 1324, 1325, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 643, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, - 0, 0, 0, 206, 206, 0, 206, 206, 0, 0, - 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 656, 0, 0, 0, 0, 0, 0, 206, 0, 946, - 947, 0, 206, 0, 0, 0, 0, 704, 0, 0, - 0, 0, 669, 670, 671, 672, 673, 674, 675, 262, - 676, 677, 678, 679, 680, 657, 658, 659, 660, 641, - 642, 0, 0, 644, 0, 645, 646, 647, 648, 649, - 650, 651, 652, 653, 654, 661, 662, 663, 664, 665, - 666, 667, 668, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 262, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 799, 206, 206, 206, 206, - 206, 0, 0, 0, 1445, 0, 0, 0, 1034, 0, - 0, 206, 0, 0, 0, 845, 0, 0, 0, 206, + 0, 542, 799, 0, 0, 1396, 206, 0, 0, 206, + 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, + 0, 206, 0, 0, 1402, 0, 1223, 0, 0, 1421, + 0, 0, 0, 1225, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1234, 1235, 1236, 1279, 1239, 0, + 0, 1242, 0, 1245, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 604, 0, 613, 0, 1257, 1258, + 1259, 0, 1262, 0, 0, 0, 0, 501, 505, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1273, + 0, 0, 1117, 1118, 523, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1134, 1135, 1136, 1137, 0, + 1139, 1140, 1141, 1142, 0, 0, 0, 0, 0, 968, + 0, 0, 1148, 1149, 0, 0, 0, 0, 0, 567, + 0, 0, 0, 0, 0, 206, 206, 206, 578, 531, + 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, + 532, 0, 0, 542, 0, 0, 0, 0, 0, 0, + 0, 1307, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 634, 0, + 0, 0, 1195, 0, 0, 0, 0, 0, 688, 689, + 0, 0, 0, 0, 695, 0, 0, 328, 0, 0, + 701, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 0, 0, + 0, 1360, 1361, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1367, 1368, 1369, 0, 0, 0, 0, + 0, 1224, 0, 0, 0, 0, 0, 0, 0, 206, + 0, 0, 0, 741, 0, 0, 0, 0, 0, 206, + 206, 0, 0, 0, 0, 206, 0, 0, 206, 1390, + 0, 206, 0, 0, 0, 705, 1395, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1400, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 721, 0, 0, 0, 206, 0, 0, 0, 0, 0, + 0, 0, 0, 705, 0, 0, 0, 0, 0, 1435, + 1436, 0, 0, 819, 0, 742, 743, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 846, 0, 0, 0, + 0, 0, 1298, 1299, 0, 1300, 1301, 0, 1302, 1303, + 0, 1304, 1305, 1306, 0, 262, 0, 1309, 1310, 0, + 262, 262, 0, 0, 800, 800, 262, 0, 0, 0, + 800, 0, 0, 0, 0, 0, 0, 0, 567, 0, + 0, 795, 796, 0, 0, 0, 0, 0, 0, 262, + 262, 262, 262, 0, 206, 0, 0, 0, 0, 0, + 0, 0, 206, 841, 908, 0, 206, 206, 0, 0, + 0, 0, 0, 930, 931, 0, 934, 935, 0, 0, + 936, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 25, 52, 27, 28, 0, 855, 938, 0, 0, + 0, 0, 944, 0, 0, 0, 0, 0, 0, 43, + 0, 0, 0, 0, 29, 48, 49, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 38, 206, 0, 0, 54, 0, + 0, 0, 0, 0, 206, 206, 0, 206, 206, 0, + 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 206, 0, + 942, 943, 0, 206, 0, 0, 0, 0, 705, 0, + 0, 0, 0, 0, 0, 0, 1427, 0, 0, 0, + 262, 0, 0, 0, 0, 946, 947, 0, 505, 31, + 32, 34, 33, 36, 656, 50, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 37, 44, 45, 0, + 0, 46, 47, 35, 0, 0, 0, 262, 0, 0, + 0, 0, 0, 0, 0, 0, 39, 40, 0, 41, + 42, 0, 0, 0, 0, 262, 0, 0, 0, 0, + 973, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 800, 206, 206, 206, 206, 206, 994, 0, 0, + 0, 0, 644, 0, 1025, 0, 0, 206, 0, 0, + 0, 841, 0, 0, 0, 206, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 657, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1109, 0, 0, 0, 53, 0, 0, 0, 0, + 0, 670, 671, 672, 673, 674, 675, 676, 0, 677, + 678, 679, 680, 681, 658, 659, 660, 661, 642, 643, + 0, 0, 645, 0, 646, 647, 648, 649, 650, 651, + 652, 653, 654, 655, 662, 663, 664, 665, 666, 667, + 668, 669, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, + 0, 1106, 262, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 705, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1207, 800, 0, 0, 0, 0, + 0, 0, 0, 1146, 0, 0, 0, 0, 0, 0, + 0, 1210, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 206, 0, 0, 0, 0, 0, 0, + 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 800, 0, 0, 1251, 0, 0, + 0, 0, 0, 0, 0, 0, 567, 0, 0, 0, + 0, 0, 0, 0, 1266, 0, 0, 1267, 0, 0, + 1269, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 262, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 262, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 704, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 799, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 841, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, - 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 799, 425, 414, 0, 385, 428, 363, + 0, 0, 0, 800, 0, 0, 0, 1388, 567, 0, + 0, 0, 0, 0, 0, 425, 414, 206, 385, 428, + 363, 377, 436, 378, 379, 407, 349, 393, 138, 375, + 0, 366, 344, 372, 345, 364, 387, 102, 390, 362, + 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, + 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, + 429, 376, 405, 430, 0, 0, 0, 80, 0, 862, + 863, 0, 0, 0, 0, 0, 95, 0, 403, 424, + 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, + 369, 370, 1046, 0, 0, 0, 0, 0, 0, 388, + 392, 409, 382, 0, 0, 0, 0, 0, 0, 0, + 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, + 0, 386, 0, 0, 0, 353, 0, 368, 410, 0, + 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, + 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, + 150, 154, 417, 365, 373, 98, 371, 152, 140, 174, + 398, 141, 151, 122, 166, 146, 173, 181, 182, 163, + 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, + 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, + 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, + 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, + 111, 143, 124, 144, 112, 132, 131, 133, 0, 346, + 0, 159, 176, 193, 93, 361, 164, 183, 184, 185, + 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, + 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, + 175, 157, 357, 360, 355, 356, 394, 395, 431, 432, + 433, 411, 352, 0, 358, 359, 0, 415, 421, 422, + 397, 82, 0, 120, 190, 147, 105, 177, 425, 414, + 0, 385, 428, 363, 377, 436, 378, 379, 407, 349, + 393, 138, 375, 0, 366, 344, 372, 345, 364, 387, + 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, + 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, + 408, 354, 400, 429, 376, 405, 430, 0, 0, 0, + 80, 0, 862, 863, 0, 0, 0, 0, 0, 95, + 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, + 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, + 0, 0, 388, 392, 409, 382, 0, 0, 0, 0, + 0, 0, 0, 0, 367, 0, 399, 0, 0, 0, + 351, 348, 0, 0, 386, 0, 0, 0, 353, 0, + 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, + 381, 380, 426, 145, 0, 161, 110, 118, 83, 89, + 0, 109, 136, 150, 154, 417, 365, 373, 98, 371, + 152, 140, 174, 398, 141, 151, 122, 166, 146, 173, + 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, + 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, + 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, + 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, + 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, + 133, 0, 346, 0, 159, 176, 193, 93, 361, 164, + 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, + 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, + 139, 153, 97, 175, 157, 357, 360, 355, 356, 394, + 395, 431, 432, 433, 411, 352, 0, 358, 359, 0, + 415, 421, 422, 397, 82, 0, 120, 190, 147, 105, + 177, 425, 414, 0, 385, 428, 363, 377, 436, 378, + 379, 407, 349, 393, 138, 375, 0, 366, 344, 372, + 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, + 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, + 391, 412, 384, 408, 354, 400, 429, 376, 405, 430, + 54, 0, 0, 80, 0, 0, 0, 0, 0, 0, + 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, + 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, + 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, + 0, 0, 0, 0, 0, 0, 0, 367, 0, 399, + 0, 0, 0, 351, 348, 0, 0, 386, 0, 0, + 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, + 383, 209, 423, 381, 380, 426, 145, 0, 161, 110, + 118, 83, 89, 0, 109, 136, 150, 154, 417, 365, + 373, 98, 371, 152, 140, 174, 398, 141, 151, 122, + 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, + 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, + 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, + 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, + 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, + 112, 132, 131, 133, 0, 346, 0, 159, 176, 193, + 93, 361, 164, 183, 184, 185, 186, 187, 188, 0, + 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, + 123, 148, 191, 139, 153, 97, 175, 157, 357, 360, + 355, 356, 394, 395, 431, 432, 433, 411, 352, 0, + 358, 359, 0, 415, 421, 422, 397, 82, 0, 120, + 190, 147, 105, 177, 425, 414, 0, 385, 428, 363, 377, 436, 378, 379, 407, 349, 393, 138, 375, 0, 366, 344, 372, 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, 429, - 376, 405, 430, 0, 0, 0, 80, 0, 866, 867, + 376, 405, 430, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, - 370, 1055, 0, 0, 0, 0, 0, 0, 388, 392, - 409, 382, 0, 0, 0, 0, 0, 0, 0, 0, + 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, + 409, 382, 0, 0, 0, 0, 0, 0, 1112, 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, - 386, 0, 0, 0, 353, 0, 368, 410, 845, 342, + 386, 0, 0, 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 417, 365, 373, 98, 371, 152, 140, 174, 398, @@ -1024,9 +1119,9 @@ var yyAct = [...]int{ 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 346, 799, + 143, 124, 144, 112, 132, 131, 133, 0, 346, 0, 159, 176, 193, 93, 361, 164, 183, 184, 185, 186, - 187, 188, 0, 206, 94, 107, 103, 142, 134, 92, + 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 357, 360, 355, 356, 394, 395, 431, 432, 433, 411, 352, 0, 358, 359, 0, 415, 421, 422, 397, @@ -1035,12 +1130,12 @@ var yyAct = [...]int{ 138, 375, 0, 366, 344, 372, 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, - 354, 400, 429, 376, 405, 430, 0, 0, 0, 80, - 0, 866, 867, 0, 0, 0, 0, 0, 95, 0, + 354, 400, 429, 376, 405, 430, 0, 0, 0, 267, + 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, 0, 0, 0, 0, - 0, 0, 0, 367, 0, 399, 0, 0, 0, 351, + 0, 750, 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, 386, 0, 0, 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, 0, 161, 110, 118, 83, 89, 0, @@ -1061,7 +1156,7 @@ var yyAct = [...]int{ 407, 349, 393, 138, 375, 0, 366, 344, 372, 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, - 412, 384, 408, 354, 400, 429, 376, 405, 430, 54, + 412, 384, 408, 354, 400, 429, 376, 405, 430, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, @@ -1088,11 +1183,11 @@ var yyAct = [...]int{ 344, 372, 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, 429, 376, - 405, 430, 0, 0, 0, 80, 0, 0, 0, 0, + 405, 430, 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, - 382, 0, 0, 0, 0, 0, 0, 1121, 0, 367, + 382, 0, 0, 0, 0, 0, 0, 0, 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, 386, 0, 0, 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, 0, @@ -1114,12 +1209,12 @@ var yyAct = [...]int{ 375, 0, 366, 344, 372, 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, 354, - 400, 429, 376, 405, 430, 0, 0, 0, 267, 0, + 400, 429, 376, 405, 430, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, 0, 0, 0, 0, 0, - 749, 0, 367, 0, 399, 0, 0, 0, 351, 348, + 0, 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, 386, 0, 0, 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, 0, 161, 110, 118, 83, 89, 0, 109, @@ -1127,12 +1222,12 @@ var yyAct = [...]int{ 174, 398, 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, - 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, + 137, 167, 168, 99, 192, 90, 179, 88, 340, 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, 346, 0, 159, 176, 193, 93, 361, 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, - 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, + 341, 339, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 357, 360, 355, 356, 394, 395, 431, 432, 433, 411, 352, 0, 358, 359, 0, 415, 421, 422, 397, 82, 0, 120, 190, 147, 105, 177, 425, @@ -1141,7 +1236,7 @@ var yyAct = [...]int{ 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, 429, 376, 405, 430, 0, 0, - 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, 0, 0, @@ -1167,7 +1262,7 @@ var yyAct = [...]int{ 372, 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, 429, 376, 405, - 430, 0, 0, 0, 267, 0, 0, 0, 0, 0, + 430, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, 382, @@ -1178,13 +1273,13 @@ var yyAct = [...]int{ 110, 118, 83, 89, 0, 109, 136, 150, 154, 417, 365, 373, 98, 371, 152, 140, 174, 398, 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, + 162, 621, 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, + 192, 90, 179, 88, 340, 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, 346, 0, 159, 176, 193, 93, 361, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, + 0, 0, 94, 107, 103, 142, 341, 339, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 357, 360, 355, 356, 394, 395, 431, 432, 433, 411, 352, 0, 358, 359, 0, 415, 421, 422, 397, 82, 0, @@ -1204,200 +1299,71 @@ var yyAct = [...]int{ 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 417, 365, 373, 98, 371, 152, 140, 174, 398, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, + 180, 189, 84, 162, 331, 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, 340, 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, 346, 0, 159, 176, 193, 93, 361, 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 341, - 339, 113, 156, 116, 123, 148, 191, 139, 153, 97, + 339, 334, 333, 116, 123, 148, 191, 139, 153, 97, 175, 157, 357, 360, 355, 356, 394, 395, 431, 432, 433, 411, 352, 0, 358, 359, 0, 415, 421, 422, - 397, 82, 0, 120, 190, 147, 105, 177, 425, 414, - 0, 385, 428, 363, 377, 436, 378, 379, 407, 349, - 393, 138, 375, 0, 366, 344, 372, 345, 364, 387, - 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, - 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, - 408, 354, 400, 429, 376, 405, 430, 0, 0, 0, - 207, 0, 0, 0, 0, 0, 0, 0, 0, 95, - 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, - 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, - 0, 0, 388, 392, 409, 382, 0, 0, 0, 0, - 0, 0, 0, 0, 367, 0, 399, 0, 0, 0, - 351, 348, 0, 0, 386, 0, 0, 0, 353, 0, - 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, - 381, 380, 426, 145, 0, 161, 110, 118, 83, 89, - 0, 109, 136, 150, 154, 417, 365, 373, 98, 371, - 152, 140, 174, 398, 141, 151, 122, 166, 146, 173, - 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, - 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, - 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, - 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, - 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, - 133, 0, 346, 0, 159, 176, 193, 93, 361, 164, - 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, - 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, - 139, 153, 97, 175, 157, 357, 360, 355, 356, 394, - 395, 431, 432, 433, 411, 352, 0, 358, 359, 0, - 415, 421, 422, 397, 82, 0, 120, 190, 147, 105, - 177, 425, 414, 0, 385, 428, 363, 377, 436, 378, - 379, 407, 349, 393, 138, 375, 0, 366, 344, 372, - 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, - 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, - 391, 412, 384, 408, 354, 400, 429, 376, 405, 430, - 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, - 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, - 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, - 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, - 0, 0, 0, 0, 0, 0, 0, 367, 0, 399, - 0, 0, 0, 351, 348, 0, 0, 386, 0, 0, - 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, - 383, 209, 423, 381, 380, 426, 145, 0, 161, 110, - 118, 83, 89, 0, 109, 136, 150, 154, 417, 365, - 373, 98, 371, 152, 140, 174, 398, 141, 151, 122, - 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, - 620, 96, 155, 86, 170, 160, 128, 114, 115, 85, - 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, - 90, 179, 88, 340, 178, 135, 165, 171, 129, 126, - 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, - 112, 132, 131, 133, 0, 346, 0, 159, 176, 193, - 93, 361, 164, 183, 184, 185, 186, 187, 188, 0, - 0, 94, 107, 103, 142, 341, 339, 113, 156, 116, - 123, 148, 191, 139, 153, 97, 175, 157, 357, 360, - 355, 356, 394, 395, 431, 432, 433, 411, 352, 0, - 358, 359, 0, 415, 421, 422, 397, 82, 0, 120, - 190, 147, 105, 177, 425, 414, 0, 385, 428, 363, - 377, 436, 378, 379, 407, 349, 393, 138, 375, 0, - 366, 344, 372, 345, 364, 387, 102, 390, 362, 416, - 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, - 0, 389, 418, 391, 412, 384, 408, 354, 400, 429, - 376, 405, 430, 0, 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, - 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, - 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, - 409, 382, 0, 0, 0, 0, 0, 0, 0, 0, - 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, - 386, 0, 0, 0, 353, 0, 368, 410, 0, 342, - 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 417, 365, 373, 98, 371, 152, 140, 174, 398, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 331, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 340, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 346, 0, - 159, 176, 193, 93, 361, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 341, 339, - 334, 333, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 357, 360, 355, 356, 394, 395, 431, 432, 433, - 411, 352, 0, 358, 359, 0, 415, 421, 422, 397, - 82, 0, 120, 190, 147, 105, 177, 138, 0, 0, - 0, 0, 269, 0, 0, 0, 102, 0, 266, 0, - 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, - 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, - 0, 857, 0, 54, 0, 0, 267, 288, 287, 290, - 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, - 858, 0, 0, 264, 281, 0, 308, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 278, 279, 0, 0, - 0, 0, 322, 0, 280, 0, 0, 275, 276, 277, - 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, - 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 310, 321, 316, 317, 314, 315, 313, 312, 311, - 323, 302, 303, 304, 305, 307, 0, 318, 319, 306, - 82, 0, 120, 190, 147, 105, 177, 138, 0, 0, - 785, 0, 269, 0, 0, 0, 102, 0, 266, 0, - 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, - 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 0, 267, 288, 287, 290, - 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, - 0, 0, 0, 264, 281, 0, 308, 0, 0, 0, + 397, 82, 0, 120, 190, 147, 105, 177, 138, 0, + 0, 0, 0, 269, 0, 0, 0, 102, 0, 266, + 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, + 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, + 0, 0, 853, 0, 54, 0, 0, 267, 288, 287, + 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, + 296, 854, 0, 0, 264, 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 278, 279, 260, 0, - 0, 0, 322, 0, 280, 0, 0, 275, 276, 277, - 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, - 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 310, 321, 316, 317, 314, 315, 313, 312, 311, - 323, 302, 303, 304, 305, 307, 0, 318, 319, 306, - 82, 0, 120, 190, 147, 105, 177, 138, 0, 0, - 0, 0, 269, 0, 0, 0, 102, 0, 266, 0, - 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, - 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 497, 267, 288, 287, 290, - 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, - 0, 0, 0, 264, 281, 0, 308, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 278, 279, 0, + 0, 0, 0, 322, 0, 280, 0, 0, 275, 276, + 277, 282, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, + 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, + 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, + 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, + 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, + 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, + 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, + 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, + 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, + 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, + 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, + 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, + 175, 157, 310, 321, 316, 317, 314, 315, 313, 312, + 311, 323, 302, 303, 304, 305, 307, 0, 318, 319, + 306, 82, 0, 120, 190, 147, 105, 177, 138, 0, + 0, 786, 0, 269, 0, 0, 0, 102, 0, 266, + 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, + 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, + 0, 0, 0, 0, 54, 0, 0, 267, 288, 287, + 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, + 296, 0, 0, 0, 264, 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 278, 279, 0, 0, - 0, 0, 322, 0, 280, 0, 0, 275, 276, 277, - 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, - 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 310, 321, 316, 317, 314, 315, 313, 312, 311, - 323, 302, 303, 304, 305, 307, 0, 318, 319, 306, - 82, 0, 120, 190, 147, 105, 177, 138, 0, 0, - 0, 0, 269, 0, 0, 0, 102, 0, 266, 0, - 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, - 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 0, 267, 288, 287, 290, - 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, - 0, 0, 0, 264, 281, 0, 308, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 278, 279, 260, 0, - 0, 0, 322, 0, 280, 0, 0, 275, 276, 277, - 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, - 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 310, 321, 316, 317, 314, 315, 313, 312, 311, - 323, 302, 303, 304, 305, 307, 24, 318, 319, 306, - 82, 0, 120, 190, 147, 105, 177, 0, 138, 0, + 0, 0, 0, 0, 0, 0, 0, 278, 279, 260, + 0, 0, 0, 322, 0, 280, 0, 0, 275, 276, + 277, 282, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, + 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, + 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, + 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, + 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, + 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, + 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, + 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, + 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, + 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, + 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, + 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, + 175, 157, 310, 321, 316, 317, 314, 315, 313, 312, + 311, 323, 302, 303, 304, 305, 307, 0, 318, 319, + 306, 82, 0, 120, 190, 147, 105, 177, 138, 0, 0, 0, 0, 269, 0, 0, 0, 102, 0, 266, 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 0, 267, 288, 287, + 0, 0, 0, 0, 54, 0, 497, 267, 288, 287, 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, 0, 0, 0, 264, 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1426,7 +1392,7 @@ var yyAct = [...]int{ 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, 0, 0, 0, 264, 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 278, 279, 0, + 0, 0, 0, 0, 0, 0, 0, 278, 279, 260, 0, 0, 0, 322, 0, 280, 0, 0, 275, 276, 277, 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, @@ -1442,115 +1408,19 @@ var yyAct = [...]int{ 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 310, 321, 316, 317, 314, 315, 313, 312, - 311, 323, 302, 303, 304, 305, 307, 0, 318, 319, - 306, 82, 138, 120, 190, 147, 105, 177, 0, 0, - 0, 102, 0, 0, 0, 0, 0, 119, 309, 121, - 0, 0, 158, 130, 0, 0, 0, 0, 300, 301, - 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, - 0, 267, 288, 287, 290, 291, 292, 293, 0, 0, - 95, 289, 294, 295, 296, 0, 0, 0, 0, 281, - 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 278, 279, 0, 0, 0, 0, 322, 0, 280, - 0, 0, 275, 276, 277, 282, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, - 0, 0, 320, 0, 145, 0, 161, 110, 118, 83, - 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, - 0, 152, 140, 174, 1446, 141, 151, 122, 166, 146, - 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, - 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, - 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, - 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, - 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, - 131, 133, 0, 0, 0, 159, 176, 193, 93, 0, - 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, - 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, - 191, 139, 153, 97, 175, 157, 310, 321, 316, 317, - 314, 315, 313, 312, 311, 323, 302, 303, 304, 305, - 307, 0, 318, 319, 306, 82, 138, 120, 190, 147, - 105, 177, 0, 0, 0, 102, 0, 0, 0, 0, - 0, 119, 309, 121, 0, 0, 158, 130, 0, 0, - 0, 0, 300, 301, 0, 0, 0, 0, 0, 0, - 0, 0, 54, 0, 497, 267, 288, 287, 290, 291, - 292, 293, 0, 0, 95, 289, 294, 295, 296, 0, - 0, 0, 0, 281, 0, 308, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 278, 279, 0, 0, 0, - 0, 322, 0, 280, 0, 0, 275, 276, 277, 282, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, - 0, 0, 0, 209, 0, 0, 320, 0, 145, 0, - 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, - 0, 0, 0, 98, 0, 152, 140, 174, 0, 141, - 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, - 84, 162, 172, 96, 155, 86, 170, 160, 128, 114, - 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, - 99, 192, 90, 179, 88, 91, 178, 135, 165, 171, - 129, 126, 87, 169, 127, 125, 117, 104, 111, 143, - 124, 144, 112, 132, 131, 133, 0, 0, 0, 159, - 176, 193, 93, 0, 164, 183, 184, 185, 186, 187, - 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, - 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, - 310, 321, 316, 317, 314, 315, 313, 312, 311, 323, - 302, 303, 304, 305, 307, 0, 318, 319, 306, 82, - 138, 120, 190, 147, 105, 177, 0, 0, 0, 102, - 0, 0, 0, 0, 0, 119, 309, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 300, 301, 0, 0, - 0, 0, 0, 0, 0, 0, 54, 0, 0, 267, - 288, 287, 290, 291, 292, 293, 0, 0, 95, 289, - 294, 295, 296, 0, 0, 0, 0, 281, 0, 308, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 278, - 279, 0, 0, 0, 0, 322, 0, 280, 0, 0, - 275, 276, 277, 282, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 320, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 310, 321, 316, 317, 314, 315, - 313, 312, 311, 323, 302, 303, 304, 305, 307, 0, - 318, 319, 306, 82, 138, 120, 190, 147, 105, 177, - 0, 0, 0, 102, 0, 0, 0, 0, 0, 119, - 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, - 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 531, - 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, - 532, 0, 0, 542, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, - 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, - 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, - 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, - 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, - 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, - 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, - 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, - 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, - 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, - 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, - 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, - 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, - 0, 0, 0, 519, 0, 0, 0, 82, 102, 120, - 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, - 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, - 521, 0, 0, 0, 0, 0, 0, 95, 0, 0, - 0, 0, 0, 516, 515, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 517, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, + 311, 323, 302, 303, 304, 305, 307, 24, 318, 319, + 306, 82, 0, 120, 190, 147, 105, 177, 0, 138, + 0, 0, 0, 0, 269, 0, 0, 0, 102, 0, + 266, 0, 0, 0, 119, 309, 121, 0, 0, 158, + 130, 0, 0, 0, 0, 300, 301, 0, 0, 0, + 0, 0, 0, 0, 0, 54, 0, 0, 267, 288, + 287, 290, 291, 292, 293, 0, 0, 95, 289, 294, + 295, 296, 0, 0, 0, 264, 281, 0, 308, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 278, 279, + 0, 0, 0, 0, 322, 0, 280, 0, 0, 275, + 276, 277, 282, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, @@ -1562,42 +1432,20 @@ var yyAct = [...]int{ 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, - 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, - 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, - 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, - 0, 0, 95, 0, 0, 0, 0, 0, 74, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 108, 76, 77, - 0, 73, 0, 0, 0, 78, 145, 0, 161, 110, - 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, - 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, - 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, - 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, - 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, - 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, - 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, - 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, - 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, - 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, - 123, 148, 191, 139, 153, 97, 175, 157, 0, 75, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, - 0, 0, 0, 844, 0, 0, 0, 82, 102, 120, - 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, - 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, - 846, 0, 0, 0, 0, 0, 0, 95, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, + 97, 175, 157, 310, 321, 316, 317, 314, 315, 313, + 312, 311, 323, 302, 303, 304, 305, 307, 0, 318, + 319, 306, 82, 0, 120, 190, 147, 105, 177, 138, + 0, 0, 0, 0, 269, 0, 0, 0, 102, 0, + 266, 0, 0, 0, 119, 309, 121, 0, 0, 158, + 130, 0, 0, 0, 0, 300, 301, 0, 0, 0, + 0, 0, 0, 0, 0, 54, 0, 0, 267, 288, + 287, 290, 291, 292, 293, 0, 0, 95, 289, 294, + 295, 296, 0, 0, 0, 264, 281, 0, 308, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 278, 279, + 0, 0, 0, 0, 322, 0, 280, 0, 0, 275, + 276, 277, 282, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, @@ -1609,16 +1457,113 @@ var yyAct = [...]int{ 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, - 97, 175, 157, 0, 0, 0, 0, 0, 24, 0, + 97, 175, 157, 310, 321, 316, 317, 314, 315, 313, + 312, 311, 323, 302, 303, 304, 305, 307, 0, 318, + 319, 306, 82, 138, 120, 190, 147, 105, 177, 0, + 0, 0, 102, 0, 0, 0, 0, 0, 119, 309, + 121, 0, 0, 158, 130, 0, 0, 0, 0, 300, + 301, 0, 0, 0, 0, 0, 0, 0, 0, 54, + 0, 0, 267, 288, 287, 290, 291, 292, 293, 0, + 0, 95, 289, 294, 295, 296, 0, 0, 0, 0, + 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 278, 279, 0, 0, 0, 0, 322, 0, + 280, 0, 0, 275, 276, 277, 282, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, + 209, 0, 0, 320, 0, 145, 0, 161, 110, 118, + 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, + 98, 0, 152, 140, 174, 1428, 141, 151, 122, 166, + 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, + 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, + 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, + 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, + 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, + 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, + 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, + 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, + 148, 191, 139, 153, 97, 175, 157, 310, 321, 316, + 317, 314, 315, 313, 312, 311, 323, 302, 303, 304, + 305, 307, 0, 318, 319, 306, 82, 138, 120, 190, + 147, 105, 177, 0, 0, 0, 102, 0, 0, 0, + 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, + 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, + 0, 0, 0, 54, 0, 497, 267, 288, 287, 290, + 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, + 0, 0, 0, 0, 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 0, 82, 0, 120, 190, 147, 105, 177, 102, - 0, 0, 0, 0, 0, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 54, 0, 0, 80, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, + 0, 0, 0, 0, 0, 0, 278, 279, 0, 0, + 0, 0, 322, 0, 280, 0, 0, 275, 276, 277, + 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, + 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, + 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, + 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, + 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, + 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, + 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, + 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, + 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, + 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, + 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, + 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, + 157, 310, 321, 316, 317, 314, 315, 313, 312, 311, + 323, 302, 303, 304, 305, 307, 0, 318, 319, 306, + 82, 138, 120, 190, 147, 105, 177, 0, 0, 0, + 102, 0, 0, 0, 0, 0, 119, 309, 121, 0, + 0, 158, 130, 0, 0, 0, 0, 300, 301, 0, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 267, 288, 287, 290, 291, 292, 293, 0, 0, 95, + 289, 294, 295, 296, 0, 0, 0, 0, 281, 0, + 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 278, 279, 0, 0, 0, 0, 322, 0, 280, 0, + 0, 275, 276, 277, 282, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, + 0, 320, 0, 145, 0, 161, 110, 118, 83, 89, + 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, + 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, + 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, + 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, + 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, + 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, + 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, + 133, 0, 0, 0, 159, 176, 193, 93, 0, 164, + 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, + 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, + 139, 153, 97, 175, 157, 310, 321, 316, 317, 314, + 315, 313, 312, 311, 323, 302, 303, 304, 305, 307, + 0, 318, 319, 306, 82, 138, 120, 190, 147, 105, + 177, 0, 0, 0, 102, 0, 0, 0, 0, 0, + 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, + 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, + 539, 532, 0, 0, 542, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, + 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, + 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, + 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, + 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, + 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, + 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, + 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, + 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, + 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, + 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, + 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, + 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 138, 0, 0, 0, 519, 0, 0, 0, 82, 102, + 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, + 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, + 0, 521, 0, 0, 0, 0, 0, 0, 95, 0, + 0, 0, 0, 0, 516, 515, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 517, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, @@ -1633,60 +1578,60 @@ var yyAct = [...]int{ 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 24, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 138, 0, 82, 0, 120, 190, 147, 105, 177, - 102, 0, 0, 0, 0, 0, 119, 0, 121, 0, - 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, - 207, 0, 0, 0, 0, 0, 0, 0, 0, 95, + 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, + 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, + 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, + 0, 0, 0, 95, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, - 0, 0, 0, 145, 0, 161, 110, 118, 83, 89, - 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, - 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, - 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, - 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, - 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, - 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, - 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, - 133, 0, 0, 0, 159, 176, 193, 93, 0, 164, - 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, - 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, - 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 138, 0, 0, 0, - 844, 0, 0, 0, 82, 102, 120, 190, 147, 105, - 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 108, 76, + 77, 0, 73, 0, 0, 0, 78, 145, 0, 161, + 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, + 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, + 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, + 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, + 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, + 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, + 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, + 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, + 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, + 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, + 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, + 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 138, 0, 0, 0, 840, 0, 0, 0, 82, 102, + 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, + 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, + 0, 842, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 207, 0, 846, 0, 0, - 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 108, - 0, 0, 0, 209, 0, 0, 0, 0, 145, 0, - 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, - 0, 0, 0, 98, 0, 152, 140, 174, 0, 842, - 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, - 84, 162, 172, 96, 155, 86, 170, 160, 128, 114, - 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, - 99, 192, 90, 179, 88, 91, 178, 135, 165, 171, - 129, 126, 87, 169, 127, 125, 117, 104, 111, 143, - 124, 144, 112, 132, 131, 133, 0, 0, 0, 159, - 176, 193, 93, 0, 164, 183, 184, 185, 186, 187, - 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, - 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, + 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, + 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, + 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, + 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, + 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, + 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, + 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, + 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, + 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, + 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, + 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, + 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, + 153, 97, 175, 157, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 138, 0, 0, 0, 0, 0, 0, 0, 82, - 102, 120, 190, 147, 105, 177, 119, 0, 121, 0, + 0, 138, 0, 82, 0, 120, 190, 147, 105, 177, + 102, 0, 0, 0, 0, 0, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 80, 0, 0, 736, 0, 0, 737, 0, 0, 95, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 80, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1705,12 +1650,12 @@ var yyAct = [...]int{ 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 82, 0, 120, 190, 147, 105, - 177, 102, 0, 629, 0, 0, 0, 119, 0, 121, + 177, 102, 0, 0, 0, 0, 0, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 80, 0, 628, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, + 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1730,10 +1675,10 @@ var yyAct = [...]int{ 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, - 0, 0, 0, 0, 0, 82, 102, 120, 190, 147, + 0, 840, 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 0, 207, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 207, 0, 842, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1743,7 +1688,7 @@ var yyAct = [...]int{ 108, 0, 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, + 838, 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, @@ -1757,7 +1702,7 @@ var yyAct = [...]int{ 82, 102, 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 207, 0, 846, 0, 0, 0, 0, 0, 0, + 0, 80, 0, 0, 737, 0, 0, 738, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1776,234 +1721,303 @@ var yyAct = [...]int{ 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, - 0, 0, 0, 0, 0, 82, 102, 120, 190, 147, - 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 267, 0, 801, 0, - 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, + 0, 0, 0, 138, 0, 82, 0, 120, 190, 147, + 105, 177, 102, 0, 630, 0, 0, 0, 119, 0, + 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 80, 0, 629, 0, 0, 0, 0, 0, + 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 108, 0, 0, 0, 209, 0, 0, 0, 0, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, - 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 138, 0, 0, 0, 0, 0, 0, 0, - 82, 102, 120, 190, 147, 105, 177, 119, 0, 121, - 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, + 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, + 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, + 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, + 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, + 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, + 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, + 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, + 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, + 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, + 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, + 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, + 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, + 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, + 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 267, 0, 797, 0, 0, 0, 0, 0, 0, - 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 54, 0, 0, 207, 0, 0, + 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, - 0, 0, 0, 0, 145, 0, 161, 110, 118, 83, - 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, - 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, - 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, - 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, - 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, - 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, - 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, - 131, 133, 0, 0, 0, 159, 176, 193, 93, 0, - 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, - 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, - 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, - 0, 0, 0, 0, 0, 82, 102, 120, 190, 147, - 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 80, 0, 521, 0, - 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, + 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, + 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, + 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, + 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, + 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, + 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, + 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, + 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, + 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, + 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, + 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, + 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, + 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, + 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, + 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 207, 0, 842, 0, 0, 0, 0, 0, + 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 108, 0, 0, 0, 209, 0, 0, 0, 0, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, - 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, - 82, 0, 120, 190, 147, 105, 177, 602, 102, 0, - 0, 0, 0, 0, 119, 0, 121, 0, 0, 158, - 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, - 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, + 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, + 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, + 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, + 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, + 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, + 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, + 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, + 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, + 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, + 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, + 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, + 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, + 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, + 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, + 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 267, 0, 802, + 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, - 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, - 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, - 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, - 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, - 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, - 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, - 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, - 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, - 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, - 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, - 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, - 97, 175, 157, 0, 0, 0, 0, 326, 0, 0, - 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, - 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, - 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 207, 0, 0, 0, 0, 0, 0, - 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, + 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, + 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, + 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, + 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, + 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, + 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, + 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, + 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, + 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, + 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, + 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, + 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, + 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, + 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, + 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 267, 0, 798, 0, 0, 0, 0, 0, + 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, + 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, + 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, + 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, + 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, + 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, + 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, + 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, + 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, + 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, + 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, + 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, + 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, + 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, + 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 80, 0, 521, + 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, + 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, + 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, + 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, + 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, + 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, + 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, + 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, + 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, + 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, + 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, + 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, + 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 138, 82, 0, 120, 190, 147, 105, 177, 603, 102, + 0, 0, 0, 0, 0, 119, 0, 121, 0, 0, + 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, + 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, + 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, + 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, + 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, + 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, + 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, + 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, + 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, + 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, + 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, + 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, + 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, + 153, 97, 175, 157, 0, 0, 0, 0, 326, 0, + 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, + 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, + 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, + 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, + 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, + 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, + 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, + 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, + 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, + 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, + 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, + 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, + 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, + 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, + 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, + 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, + 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, + 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, + 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, - 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, - 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, - 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, - 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, - 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, - 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, - 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, - 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, - 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, - 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, - 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, - 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, - 0, 0, 0, 0, 0, 0, 0, 82, 102, 120, - 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, - 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, - 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 204, 0, 209, 0, 0, + 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, + 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, + 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, + 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, + 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, + 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, + 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, + 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, + 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, + 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, + 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, + 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, + 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, + 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 108, 0, 204, 0, 209, 0, 0, 0, - 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, - 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, - 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, - 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, - 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, - 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, - 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, - 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, - 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, - 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, - 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, - 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, - 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, - 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, + 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, + 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, - 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, + 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, + 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, + 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, + 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, + 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, + 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, + 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, + 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, + 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, + 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, + 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, + 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, - 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, - 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, - 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, - 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, - 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, - 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, - 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, - 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, - 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, - 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, - 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, - 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, - 0, 0, 0, 0, 0, 0, 0, 82, 102, 120, - 190, 147, 105, 177, 119, 0, 121, 0, 0, 158, - 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, - 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, + 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, + 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, + 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, + 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 108, 0, 0, 0, 209, 0, 0, 0, - 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, - 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, - 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, - 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, - 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, - 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, - 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, - 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, - 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, - 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, - 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, - 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 138, 0, 0, 0, 0, 0, - 0, 0, 82, 102, 120, 190, 147, 105, 177, 119, - 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, + 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, + 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, + 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, + 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, + 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, + 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, + 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, + 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, + 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, + 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, + 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, + 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, + 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, + 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, + 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 267, 0, 0, 0, 0, 0, 0, - 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, + 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 108, 0, 0, - 0, 209, 0, 0, 0, 0, 145, 0, 161, 110, - 118, 83, 89, 0, 109, 136, 150, 154, 0, 0, - 0, 98, 0, 152, 140, 174, 0, 141, 151, 122, - 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, - 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, - 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, - 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, - 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, - 112, 132, 131, 133, 0, 0, 0, 159, 176, 193, - 93, 0, 164, 183, 184, 185, 186, 187, 188, 0, - 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, - 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, + 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, + 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, + 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, + 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, + 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, + 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, + 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, + 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, + 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, + 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, + 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, + 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 82, 0, 120, - 190, 147, 105, 177, + 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, + 120, 190, 147, 105, 177, } var yyPact = [...]int{ - 2123, -1000, -193, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 847, 867, -1000, -1000, -1000, -1000, -1000, -1000, - 228, 8486, 25, 102, -7, 11801, 101, 89, 12271, -1000, - 7, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -96, -103, - -1000, 614, -1000, -1000, -1000, -1000, -1000, 841, 845, 718, - 833, 753, -1000, 6539, 68, 68, 11566, 5539, -1000, -1000, - 224, 12271, 86, 12271, -161, 62, 62, 62, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 2324, -1000, -192, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 897, 951, -1000, -1000, -1000, -1000, -1000, -1000, + 297, 8637, 30, 107, -19, 11952, 106, 152, 12422, -1000, + 2, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -97, -98, + -1000, 694, -1000, -1000, -1000, -1000, -1000, 883, 894, 722, + 885, 779, -1000, 6690, 64, 64, 11717, 5690, -1000, -1000, + 234, 12422, 96, 12422, -156, 62, 62, 62, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -2013,236 +2027,224 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 99, 12271, 168, -1000, 12271, 61, - 481, 61, 61, 61, 12271, -1000, 144, -1000, -1000, -1000, - 12271, 475, 786, 3435, 36, 3435, -1000, 3435, 3435, -1000, - 3435, 13, 3435, -62, 857, -1000, -1000, -1000, -1000, -50, - -1000, 3435, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 392, 793, 7040, 7040, 847, - -1000, 614, -1000, -1000, -1000, 787, -1000, -1000, 293, 863, - -1000, 8251, 142, -1000, 7040, 1734, 655, -1000, -1000, 655, - -1000, -1000, 114, -1000, -1000, 7772, 7772, 7772, 7772, 7772, - 7772, 7772, 7772, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 655, -1000, 6790, - 655, 655, 655, 655, 655, 655, 655, 655, 7040, 655, - 655, 655, 655, 655, 655, 655, 655, 655, 655, 655, - 655, 655, 655, 655, 11331, 10149, 12271, 529, -1000, 625, - 5276, -90, -1000, -1000, -1000, 204, 9914, -1000, -1000, -1000, - 784, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 105, 12422, 248, -1000, 12422, 60, + 561, 60, 60, 60, 12422, -1000, 145, -1000, -1000, -1000, + 12422, 554, 814, 3586, 45, 3586, -1000, 3586, 3586, -1000, + 3586, 14, 3586, -63, 932, -1000, -1000, -1000, -1000, -44, + -1000, 3586, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 462, 846, 7191, 7191, 897, + -1000, 694, -1000, -1000, -1000, 842, -1000, -1000, 308, 938, + -1000, 8402, 141, -1000, 7191, 1367, 675, -1000, -1000, 675, + -1000, -1000, 128, -1000, -1000, 7923, 7923, 7923, 7923, 7923, + 7923, 7923, 7923, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 675, -1000, 6941, + 675, 675, 675, 675, 675, 675, 675, 675, 7191, 675, + 675, 675, 675, 675, 675, 675, 675, 675, 675, 675, + 675, 675, 675, 675, 11482, 10300, 12422, 629, -1000, 667, + 5427, -135, -1000, -1000, -1000, 219, 10065, -1000, -1000, -1000, + 813, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 533, 12271, -1000, - 2305, -1000, 473, 3435, 77, 470, 218, 458, 12271, 12271, - 3435, 20, 51, 92, 12271, 647, 75, 12271, 828, 723, - 12271, 456, 430, -1000, 5013, -1000, 3435, 3435, -1000, -1000, - -1000, 3435, 3435, 3435, 3435, 3435, 3435, -1000, -1000, -1000, - -1000, 3435, 3435, -1000, 862, 256, -1000, -1000, -1000, -1000, - 7040, -1000, 721, -1000, -1000, -1000, -1000, -1000, -1000, 872, - 171, 444, 141, 644, -1000, 439, 841, 392, 753, 9673, - 727, -1000, -1000, 12271, -1000, 7040, 7040, 410, -1000, 11089, - -1000, -1000, 3961, 180, 7772, 292, 286, 7772, 7772, 7772, - 7772, 7772, 7772, 7772, 7772, 7772, 7772, 7772, 7772, 7772, - 7772, 7772, 322, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 428, -1000, 614, 489, 489, 148, 148, 148, 148, - 148, 148, 148, 8016, 6039, 392, 521, 200, 6790, 6539, - 6539, 7040, 7040, 10854, 10619, 6539, 835, 209, 200, 12506, - -1000, 7528, -1000, 7528, -1000, 7528, -1000, 392, -1000, 7528, - -1000, 7528, -1000, -1000, 7528, 12036, 12036, 6539, 6539, 6539, - 6539, 32, 12271, -1000, 653, 717, -1000, -1000, -1000, 830, - 9203, 9438, 32, 546, 10149, 12271, -1000, -1000, 4750, 625, - -90, 602, -1000, -129, -125, 5789, 119, -1000, -1000, -1000, - -1000, 3172, 223, 535, 260, -61, -1000, -1000, -1000, 667, - -1000, 667, 667, 667, 667, -20, -20, -20, -20, -1000, - -1000, -1000, -1000, -1000, 688, 685, -1000, 667, 667, 667, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 678, 678, 678, 671, - 671, 698, -1000, 12271, 3435, 827, 3435, -1000, 113, -1000, - 12036, 12036, 12271, 12271, 120, 12271, 12271, 616, -1000, 12271, - 3435, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 12271, 259, 12271, 12271, - 200, 12271, -1000, 769, 7040, 7040, 4487, 7040, -1000, -1000, - -1000, 793, -1000, 835, 846, -1000, 777, 776, 6539, -1000, - -1000, 180, 265, -1000, -1000, 316, -1000, -1000, -1000, -1000, - 137, 655, -1000, 1509, -1000, -1000, -1000, -1000, 292, 7772, - 7772, 7772, 1469, 1509, 2264, 1227, 1906, 148, 327, 327, - 153, 153, 153, 153, 153, 391, 391, -1000, -1000, -1000, - 392, -1000, -1000, -1000, 392, 6539, 615, -1000, -1000, 7040, - -1000, 392, 515, 515, 380, 317, 651, 649, -1000, 136, - 648, 603, 515, 6539, 215, -1000, 7040, 392, 1667, -1000, - 1667, 1667, 1667, 1667, 1667, 612, 611, 515, 392, 515, - 515, 680, 655, -1000, 12506, 10149, 10149, 10149, 10149, 10149, - -1000, 741, 738, -1000, 735, 734, 743, 12271, -1000, 517, - 9203, 143, 655, -1000, 10384, -1000, -1000, 856, 10149, 562, - -1000, -1000, 602, -90, -131, -1000, -1000, -1000, -1000, 200, - -1000, 351, 555, 2909, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 676, 409, -1000, 818, 189, 181, 397, 814, -1000, - -1000, -1000, 790, -1000, 229, -60, -1000, -1000, 331, -20, - -20, -1000, -1000, 119, 783, 119, 119, 119, 383, 383, - -1000, -1000, -1000, -1000, 328, -1000, -1000, -1000, 313, -1000, - 704, 12036, 3435, -1000, -1000, -1000, -1000, 287, 287, 219, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 31, 697, -1000, -1000, -1000, 19, 18, 72, -1000, - 3435, -1000, 256, -1000, 373, 7040, -1000, -1000, -1000, 764, - 200, 200, 130, -1000, -1000, 12271, -1000, -1000, -1000, -1000, - 596, -1000, -1000, -1000, 3698, 6539, -1000, 1469, 1509, 2229, - -1000, 7772, 7772, -1000, -1000, 515, 6539, 200, -1000, -1000, - -1000, 225, 322, 225, 7772, 7772, 7772, 7772, 4487, 7772, - 7772, 7772, 7772, -174, 563, 203, -1000, 7040, 368, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 7772, 7772, -1000, -1000, - -1000, -1000, 702, 12506, 655, -1000, 8962, 12036, 601, -1000, - 196, 717, 696, 701, 791, -1000, -1000, -1000, -1000, 737, - -1000, 736, -1000, -1000, -1000, -1000, -1000, 83, 82, 79, - 12036, -1000, 847, 7040, 562, -1000, -1000, -1000, -137, -145, - -1000, -1000, -1000, 3172, -1000, 3172, 12036, 48, -1000, 397, - 397, -1000, -1000, -1000, 675, 700, 88, -1000, -1000, -1000, - 504, 119, 119, -1000, 202, -1000, -1000, -1000, 513, -1000, - 510, 551, 507, 12271, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 559, 12422, -1000, + 2414, -1000, 552, 3586, 73, 551, 254, 550, 12422, 12422, + 3586, 20, 53, 104, 12422, 671, 71, 12422, 873, 725, + 12422, 549, 548, -1000, 5164, -1000, 3586, 3586, -1000, -1000, + -1000, 3586, 3586, 3586, 3586, 3586, 3586, -1000, -1000, -1000, + -1000, 3586, 3586, -1000, 937, 263, -1000, -1000, -1000, -1000, + 7191, -1000, 723, -1000, -1000, -1000, -1000, -1000, -1000, 946, + 185, 452, 140, 670, -1000, 247, 883, 462, 779, 9824, + 735, -1000, -1000, 12422, -1000, 7191, 7191, 378, -1000, 11240, + -1000, -1000, 4112, 170, 7923, 405, 269, 7923, 7923, 7923, + 7923, 7923, 7923, 7923, 7923, 7923, 7923, 7923, 7923, 7923, + 7923, 7923, 383, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 546, -1000, 694, 509, 509, 159, 159, 159, 159, + 159, 159, 159, 8167, 6190, 462, 545, 313, 6941, 6690, + 6690, 7191, 7191, 11005, 10770, 6690, 876, 245, 313, 12657, + -1000, -1000, 7679, -1000, -1000, -1000, -1000, -1000, 462, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 12187, 12187, 6690, 6690, + 6690, 6690, 35, 12422, -1000, 659, 845, -1000, -1000, -1000, + 851, 9354, 9589, 35, 652, 10300, 12422, -1000, -1000, 4901, + 667, -135, 649, -1000, -122, -120, 5940, 148, -1000, -1000, + -1000, -1000, 3323, 211, 565, 335, -77, -1000, -1000, -1000, + 678, -1000, 678, 678, 678, 678, -27, -27, -27, -27, + -1000, -1000, -1000, -1000, -1000, 703, 702, -1000, 678, 678, + 678, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 699, 699, 699, + 685, 685, 708, -1000, 12422, 3586, 872, 3586, -1000, 86, + -1000, 12187, 12187, 12422, 12422, 114, 12422, 12422, 664, -1000, + 12422, 3586, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 12422, 310, 12422, + 12422, 313, 12422, -1000, 798, 7191, 7191, 4638, 7191, -1000, + -1000, -1000, 846, -1000, 876, 928, -1000, 806, 805, 6690, + -1000, -1000, 170, 289, -1000, -1000, 443, -1000, -1000, -1000, + -1000, 136, 675, -1000, 1139, -1000, -1000, -1000, -1000, 405, + 7923, 7923, 7923, 325, 1139, 1926, 458, 831, 159, 334, + 334, 157, 157, 157, 157, 157, 387, 387, -1000, -1000, + -1000, 462, -1000, -1000, -1000, 462, 6690, 662, -1000, -1000, + 7191, -1000, 462, 535, 535, 390, 261, 692, 679, -1000, + 132, 672, 636, 535, 6690, 327, -1000, 7191, 462, -1000, + 1062, 661, 657, 535, 462, 535, 535, 604, 675, -1000, + 12657, 10300, 10300, 10300, 10300, 10300, -1000, 747, 746, -1000, + 786, 732, 787, 12422, -1000, 539, 9354, 143, 675, -1000, + 10535, -1000, -1000, 929, 10300, 607, -1000, -1000, 649, -135, + -128, -1000, -1000, -1000, -1000, 313, -1000, 407, 644, 3060, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 698, 518, -1000, + 844, 194, 197, 516, 841, -1000, -1000, -1000, 817, -1000, + 264, -79, -1000, -1000, 348, -27, -27, -1000, -1000, 148, + 812, 148, 148, 148, 456, 456, -1000, -1000, -1000, -1000, + 344, -1000, -1000, -1000, 328, -1000, 720, 12187, 3586, -1000, + -1000, -1000, -1000, 179, 179, 218, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 32, 705, -1000, + -1000, -1000, 12, 10, 66, -1000, 3586, -1000, 263, -1000, + 422, 7191, -1000, -1000, -1000, 796, 313, 313, 131, -1000, + -1000, 12422, -1000, -1000, -1000, -1000, 621, -1000, -1000, -1000, + 3849, 6690, -1000, 325, 1139, 1621, -1000, 7923, 7923, -1000, + -1000, 535, 6690, 313, -1000, -1000, -1000, 67, 383, 67, + 7923, 7923, 7923, 7923, 4638, 7923, 7923, 7923, 7923, -170, + 608, 221, -1000, 7191, 226, -1000, -1000, 7923, 7923, -1000, + -1000, -1000, -1000, 715, 12657, 675, -1000, 9113, 12187, 632, + -1000, 207, 845, 697, 714, 809, -1000, -1000, -1000, -1000, + 740, -1000, 738, -1000, -1000, -1000, -1000, -1000, 93, 91, + 84, 12187, -1000, 897, 7191, 607, -1000, -1000, -1000, -126, + -143, -1000, -1000, -1000, 3323, -1000, 3323, 12187, 49, -1000, + 516, 516, -1000, -1000, -1000, 687, 713, 7923, -1000, -1000, + -1000, 540, 148, 148, -1000, 206, -1000, -1000, -1000, 533, + -1000, 528, 602, 523, 12422, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 12271, -1000, -1000, -1000, -1000, -1000, 12036, -179, 386, 12036, - 12036, 12271, -1000, 259, -1000, 200, -1000, 4224, -1000, 856, - 10149, -1000, -1000, 392, -1000, 7772, 1509, 1509, -1000, -1000, - 392, 667, 667, -1000, 667, 671, -1000, 667, -3, 667, - -4, 392, 392, 1817, 2180, 1587, 2130, -1000, 1537, 2115, - 1484, 1935, 655, -169, -1000, 200, 7040, 1888, 1873, -1000, - 821, 543, 547, -1000, -1000, 6289, 392, 498, 127, 479, - -1000, 847, 12506, 7040, -1000, -1000, 7040, 669, -1000, 7040, - -1000, -1000, -1000, 655, 655, 655, 479, 841, 200, -1000, - -1000, -1000, -1000, 2909, -1000, 468, -1000, 667, -1000, -1000, - -1000, 12036, -51, 870, -1000, -1000, -1000, -1000, 662, -1000, - -1000, -1000, -1000, -1000, -1000, -20, 356, -20, 304, -1000, - 299, 3435, -1000, -1000, -1000, -1000, 795, -1000, 4224, -1000, - -1000, 661, -1000, -1000, -1000, 854, 550, -1000, 1509, -1000, - -1000, 103, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 7772, 7772, -1000, 7772, 7772, -1000, 7772, 7772, -1000, - 7772, 7772, 7772, 392, 354, 200, 7772, 7772, 804, -1000, - 655, -1000, -1000, 692, 12036, 12036, -1000, 12036, 841, -1000, - 200, 200, 12036, 200, 12036, 12036, 12036, 8721, -1000, 134, - 12036, -1000, 463, -1000, 206, -1000, -151, 502, 119, -1000, - 119, 487, 480, -1000, 655, 549, -1000, 193, 12036, 849, - 844, -1000, -1000, 1667, 1667, 1667, 1667, 1667, 1667, 1667, - 1667, 37, -1000, -1000, 1667, 1667, 869, -1000, 655, -1000, - 614, 123, -1000, -1000, -1000, 451, 448, 448, 448, 143, - 134, -1000, 330, 192, 353, -1000, 44, 12036, 276, 797, - -1000, 794, 659, -1000, -1000, -1000, -1000, -1000, 30, 4224, - 3172, 445, -1000, 7040, 7040, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 392, 40, -183, -1000, -1000, 12506, 547, - 392, 12036, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 291, - -1000, -1000, 12271, -1000, -1000, 345, -1000, -1000, 469, 415, - -1000, 12036, -1000, -1000, 697, 200, 545, -1000, 763, -177, - -187, 490, -1000, -1000, -1000, 658, -1000, -1000, -1000, 30, - 775, -179, -1000, 762, -1000, 12036, -1000, 27, -1000, -180, - 390, 24, -185, 693, 655, -188, 617, -1000, 861, 7284, - -1000, -1000, 866, 155, 155, 1667, 392, -1000, -1000, -1000, - 53, 303, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, 12422, -1000, -1000, -1000, -1000, -1000, 12187, -179, 506, + 12187, 12187, 12422, -1000, 310, -1000, 313, -1000, 4375, -1000, + 929, 10300, -1000, -1000, 462, -1000, 7923, 1139, 1139, -1000, + -1000, 462, 678, 678, -1000, 678, 685, -1000, 678, -7, + 678, -8, 462, 462, 1643, 1774, 1577, 1739, -1000, 1389, + 1544, 571, 1156, 675, -163, -1000, 313, 7191, 1418, 402, + -1000, 847, 584, 582, -1000, -1000, 6440, 462, 494, 123, + 492, -1000, 897, 12657, 7191, -1000, -1000, 7191, 682, -1000, + 7191, -1000, -1000, -1000, 675, 675, 675, 492, 883, 313, + -1000, -1000, -1000, -1000, 3060, -1000, 490, -1000, 678, -1000, + -1000, -1000, 12187, -58, 944, 1139, -1000, -1000, -1000, -1000, + -1000, -27, 419, -27, 321, -1000, 317, 3586, -1000, -1000, + -1000, -1000, 850, -1000, 4375, -1000, -1000, 677, -1000, -1000, + -1000, 927, 594, -1000, 1139, -1000, -1000, 99, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 7923, 7923, -1000, + 7923, 7923, -1000, 7923, 7923, -1000, 7923, 7923, 7923, 462, + 401, 313, 7923, 7923, 840, -1000, 675, -1000, -1000, 625, + 12187, 12187, -1000, 12187, 883, -1000, 313, 313, 12187, 313, + 12187, 12187, 12187, 8872, -1000, 160, 12187, -1000, 487, -1000, + 167, -1000, -100, 148, -1000, 148, 536, 472, -1000, 675, + 588, -1000, 199, 12187, 907, 891, -1000, -1000, 1062, 1062, + 1062, 1062, 1062, 1062, 1062, 1062, 29, -1000, -1000, 1062, + 1062, 942, -1000, 675, -1000, 694, 121, -1000, -1000, -1000, + 481, 478, 478, 478, 143, 160, -1000, 466, 198, 372, + -1000, 40, 12187, 281, 821, -1000, 819, -1000, -1000, -1000, + -1000, -1000, 31, 4375, 3323, 476, -1000, 7191, 7191, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 462, 44, -184, + -1000, -1000, 12657, 582, 462, 12187, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, 294, -1000, -1000, 12422, -1000, -1000, 270, + -1000, -1000, 471, -1000, 12187, -1000, -1000, 705, 313, 573, + -1000, 782, -173, -187, 547, -1000, -1000, -1000, 676, -1000, + -1000, 31, 804, -179, -1000, 762, -1000, 12187, -1000, 26, + -1000, -180, 461, 17, -185, 712, 675, -188, 711, -1000, + 936, 7435, -1000, -1000, 941, 151, 151, 1062, 462, -1000, + -1000, -1000, 54, 362, -1000, -1000, -1000, -1000, -1000, -1000, } var yyPgo = [...]int{ - 0, 1071, 25, 421, 1070, 1069, 1066, 1065, 1064, 1062, - 1061, 1060, 1058, 1055, 1052, 1051, 1050, 1049, 1047, 1046, - 1045, 1044, 1043, 1040, 1039, 1037, 97, 1036, 1035, 1034, - 76, 1032, 70, 1031, 1030, 46, 157, 49, 45, 92, - 1029, 37, 69, 61, 1028, 38, 1027, 1026, 73, 1016, - 53, 1013, 1012, 47, 1009, 1007, 11, 34, 1006, 1005, - 1004, 1002, 99, 1134, 1001, 1000, 999, 997, 996, 995, - 56, 7, 14, 33, 18, 994, 96, 6, 993, 54, - 992, 991, 990, 989, 16, 987, 58, 986, 19, 57, - 984, 9, 66, 35, 21, 5, 71, 60, 983, 22, - 63, 50, 982, 980, 456, 979, 978, 42, 977, 976, - 23, 165, 382, 975, 974, 973, 971, 44, 0, 736, - 261, 65, 970, 969, 967, 1740, 64, 52, 17, 966, - 55, 1021, 40, 964, 963, 41, 960, 958, 953, 951, - 949, 947, 946, 30, 944, 942, 940, 29, 20, 939, - 936, 59, 24, 935, 933, 932, 48, 62, 931, 930, - 51, 27, 929, 921, 915, 911, 910, 31, 12, 909, - 15, 908, 8, 907, 28, 906, 4, 903, 10, 902, - 3, 901, 13, 43, 1, 900, 2, 894, 887, 323, - 735, 885, 883, 81, + 0, 1190, 30, 480, 1189, 1188, 1187, 1184, 1183, 1181, + 1179, 1176, 1174, 1173, 1172, 1171, 1168, 1167, 1153, 1151, + 1150, 1148, 1147, 1146, 1145, 1143, 111, 1142, 1140, 1137, + 64, 1136, 73, 1135, 1131, 49, 184, 56, 44, 1709, + 1125, 26, 61, 58, 1123, 38, 1122, 1121, 71, 1119, + 52, 1114, 1113, 1619, 1111, 1110, 11, 33, 1107, 1106, + 1105, 1100, 69, 1004, 1097, 1096, 20, 1095, 1091, 77, + 1090, 57, 12, 14, 13, 18, 1089, 304, 6, 1088, + 53, 1082, 1081, 1080, 1078, 19, 1074, 55, 1073, 23, + 54, 1072, 29, 63, 35, 24, 7, 75, 59, 1071, + 22, 60, 48, 1070, 1068, 456, 1066, 1065, 45, 1063, + 1059, 28, 154, 376, 1058, 1056, 1055, 1052, 43, 0, + 519, 15, 65, 1051, 1050, 1049, 1690, 70, 51, 17, + 1044, 41, 178, 42, 1041, 1040, 40, 1036, 1035, 1034, + 1033, 1031, 1030, 1027, 258, 1026, 1025, 1024, 120, 21, + 1023, 1022, 66, 27, 1016, 1015, 1014, 46, 62, 1005, + 1003, 50, 25, 999, 998, 997, 990, 988, 34, 10, + 985, 16, 983, 9, 982, 37, 981, 5, 980, 8, + 979, 2, 978, 4, 47, 3, 977, 1, 973, 972, + 492, 791, 958, 957, 99, } var yyR1 = [...]int{ - 0, 187, 188, 188, 1, 1, 1, 1, 1, 1, + 0, 188, 189, 189, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 6, 3, 4, 4, 5, 5, 7, 7, 29, 29, 8, 9, 9, - 9, 191, 191, 48, 48, 92, 92, 10, 10, 10, - 10, 97, 97, 101, 101, 101, 102, 102, 102, 102, - 133, 133, 11, 11, 11, 11, 11, 11, 11, 182, - 182, 181, 180, 180, 179, 179, 178, 17, 163, 165, - 165, 164, 164, 164, 164, 157, 136, 136, 136, 136, - 139, 139, 137, 137, 137, 137, 137, 137, 137, 138, - 138, 138, 138, 138, 140, 140, 140, 140, 140, 141, - 141, 141, 141, 141, 141, 141, 141, 141, 141, 141, - 141, 141, 141, 141, 142, 142, 142, 142, 142, 142, - 142, 142, 156, 156, 143, 143, 151, 151, 152, 152, - 152, 149, 149, 150, 150, 153, 153, 153, 144, 144, - 144, 144, 144, 144, 144, 144, 146, 146, 146, 154, - 154, 147, 147, 147, 148, 148, 148, 155, 155, 155, - 155, 155, 145, 145, 158, 158, 173, 173, 172, 172, - 172, 162, 162, 169, 169, 169, 169, 169, 160, 160, - 161, 161, 171, 171, 170, 159, 159, 174, 174, 174, - 174, 185, 186, 184, 184, 184, 184, 184, 166, 166, - 166, 167, 167, 167, 168, 168, 168, 12, 12, 12, + 9, 192, 192, 48, 48, 93, 93, 10, 10, 10, + 10, 98, 98, 102, 102, 102, 103, 103, 103, 103, + 134, 134, 11, 11, 11, 11, 11, 11, 11, 183, + 183, 182, 181, 181, 180, 180, 179, 17, 164, 166, + 166, 165, 165, 165, 165, 158, 137, 137, 137, 137, + 140, 140, 138, 138, 138, 138, 138, 138, 138, 139, + 139, 139, 139, 139, 141, 141, 141, 141, 141, 142, + 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 143, 143, 143, 143, 143, 143, + 143, 143, 157, 157, 144, 144, 152, 152, 153, 153, + 153, 150, 150, 151, 151, 154, 154, 154, 146, 146, + 147, 147, 155, 155, 148, 148, 148, 149, 149, 149, + 156, 156, 156, 156, 156, 145, 145, 159, 159, 174, + 174, 173, 173, 173, 163, 163, 170, 170, 170, 170, + 170, 161, 161, 162, 162, 172, 172, 171, 160, 160, + 175, 175, 175, 175, 186, 187, 185, 185, 185, 185, + 185, 167, 167, 167, 168, 168, 168, 169, 169, 169, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 183, 183, 183, 183, 183, 183, 183, 183, 183, 183, - 183, 177, 175, 175, 176, 176, 13, 18, 18, 14, - 14, 14, 14, 14, 15, 15, 19, 20, 20, 20, + 12, 12, 12, 184, 184, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 178, 176, 176, 177, 177, 13, + 18, 18, 14, 14, 14, 14, 14, 15, 15, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 108, 108, - 106, 106, 109, 109, 107, 107, 107, 110, 110, 110, - 134, 134, 134, 21, 21, 23, 23, 24, 25, 22, - 22, 22, 22, 22, 22, 22, 16, 192, 26, 27, - 27, 28, 28, 28, 32, 32, 32, 30, 30, 31, - 31, 37, 37, 36, 36, 38, 38, 38, 38, 122, - 122, 122, 121, 121, 40, 40, 41, 41, 42, 42, - 43, 43, 43, 43, 55, 55, 91, 91, 93, 93, - 44, 44, 44, 44, 45, 45, 46, 46, 47, 47, - 129, 129, 128, 128, 128, 127, 127, 49, 49, 49, - 51, 50, 50, 50, 50, 52, 52, 54, 54, 53, - 53, 56, 56, 56, 56, 57, 57, 39, 39, 39, - 39, 39, 39, 39, 105, 105, 59, 59, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 69, 69, - 69, 69, 69, 69, 60, 60, 60, 60, 60, 60, - 60, 35, 35, 70, 70, 70, 76, 71, 71, 63, - 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, + 20, 109, 109, 107, 107, 110, 110, 108, 108, 108, + 111, 111, 111, 135, 135, 135, 21, 21, 23, 23, + 24, 25, 22, 22, 22, 22, 22, 22, 22, 16, + 193, 26, 27, 27, 28, 28, 28, 32, 32, 32, + 30, 30, 31, 31, 37, 37, 36, 36, 38, 38, + 38, 38, 123, 123, 123, 122, 122, 40, 40, 41, + 41, 42, 42, 43, 43, 43, 43, 55, 55, 92, + 92, 94, 94, 44, 44, 44, 44, 45, 45, 46, + 46, 47, 47, 130, 130, 129, 129, 129, 128, 128, + 49, 49, 49, 51, 50, 50, 50, 50, 52, 52, + 54, 54, 53, 53, 56, 56, 56, 56, 57, 57, + 39, 39, 39, 39, 39, 39, 39, 106, 106, 59, + 59, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 70, 70, 70, 70, 70, 70, 60, 60, 60, + 60, 60, 60, 60, 35, 35, 71, 71, 71, 77, + 72, 72, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 63, 67, 67, 67, 65, 65, 65, 65, 65, 65, + 63, 63, 63, 63, 67, 67, 67, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, + 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 193, 193, 68, 68, 68, 68, 33, 33, 33, - 33, 33, 132, 132, 135, 135, 135, 135, 135, 135, - 135, 135, 135, 135, 135, 135, 135, 80, 80, 34, - 34, 78, 78, 79, 81, 81, 77, 77, 77, 62, - 62, 62, 62, 62, 62, 62, 62, 64, 64, 64, - 82, 82, 83, 83, 84, 84, 85, 85, 86, 87, - 87, 87, 88, 88, 88, 88, 89, 89, 89, 61, - 61, 61, 61, 61, 61, 90, 90, 90, 90, 94, - 94, 72, 72, 74, 74, 73, 75, 95, 95, 99, - 96, 96, 100, 100, 100, 100, 98, 98, 98, 124, - 124, 124, 103, 103, 111, 111, 112, 112, 104, 104, - 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, - 114, 114, 114, 115, 115, 116, 116, 116, 123, 123, - 119, 119, 120, 120, 125, 125, 126, 126, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 117, 117, 117, 117, 117, 117, 117, - 117, 117, 117, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, + 66, 66, 66, 66, 194, 194, 69, 68, 68, 68, + 68, 33, 33, 33, 33, 33, 133, 133, 136, 136, + 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, + 136, 81, 81, 34, 34, 79, 79, 80, 82, 82, + 78, 78, 78, 62, 62, 62, 62, 62, 62, 62, + 62, 64, 64, 64, 83, 83, 84, 84, 85, 85, + 86, 86, 87, 88, 88, 88, 89, 89, 89, 89, + 90, 90, 90, 61, 61, 61, 61, 61, 61, 91, + 91, 91, 91, 95, 95, 73, 73, 75, 75, 74, + 76, 96, 96, 100, 97, 97, 101, 101, 101, 101, + 99, 99, 99, 125, 125, 125, 104, 104, 112, 112, + 113, 113, 105, 105, 114, 114, 114, 114, 114, 114, + 114, 114, 114, 114, 115, 115, 115, 116, 116, 117, + 117, 117, 124, 124, 120, 120, 121, 121, 126, 126, + 127, 127, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, @@ -2251,8 +2253,19 @@ var yyR1 = [...]int{ 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 189, 190, 130, 131, - 131, 131, + 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, + 190, 191, 131, 132, 132, 132, } var yyR2 = [...]int{ @@ -2271,55 +2284,55 @@ var yyR2 = [...]int{ 1, 1, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 0, 3, 0, 5, 0, 3, 5, 0, 1, 0, 1, 0, 1, 2, 0, 2, - 2, 2, 2, 2, 4, 2, 0, 3, 5, 0, - 1, 0, 3, 3, 0, 2, 2, 0, 2, 1, - 2, 1, 0, 2, 5, 4, 1, 2, 2, 3, - 2, 0, 1, 2, 3, 3, 2, 2, 1, 1, - 0, 1, 1, 3, 2, 3, 1, 10, 11, 11, - 12, 3, 3, 1, 1, 2, 2, 2, 0, 1, - 3, 1, 2, 3, 1, 1, 1, 6, 7, 7, - 7, 7, 4, 5, 7, 5, 5, 5, 12, 7, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 7, 1, 3, 8, 8, 3, 3, 5, 4, - 6, 5, 4, 4, 3, 2, 3, 4, 4, 3, - 4, 4, 4, 4, 4, 4, 3, 2, 3, 3, - 2, 3, 4, 3, 7, 5, 4, 2, 4, 2, - 2, 2, 2, 3, 3, 5, 2, 3, 1, 1, - 0, 1, 1, 1, 0, 2, 2, 0, 2, 2, - 0, 1, 1, 2, 1, 1, 2, 1, 1, 2, - 2, 2, 2, 2, 3, 3, 2, 0, 2, 0, - 2, 1, 2, 2, 0, 1, 1, 0, 1, 0, - 1, 0, 1, 1, 3, 1, 2, 3, 5, 0, - 1, 2, 1, 1, 0, 2, 1, 3, 1, 1, - 1, 3, 1, 3, 3, 7, 1, 3, 1, 3, - 4, 4, 4, 3, 2, 4, 0, 1, 0, 2, - 0, 1, 0, 1, 2, 1, 1, 1, 2, 2, - 1, 2, 3, 2, 3, 2, 2, 2, 1, 1, - 3, 0, 5, 5, 5, 0, 2, 1, 3, 3, - 2, 3, 1, 2, 0, 3, 1, 1, 3, 3, - 4, 4, 5, 3, 4, 5, 6, 2, 1, 2, - 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, - 1, 0, 2, 1, 1, 1, 3, 1, 3, 1, - 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, - 2, 2, 2, 2, 2, 2, 3, 1, 1, 1, - 1, 4, 5, 6, 4, 4, 6, 6, 6, 6, - 8, 8, 6, 8, 8, 6, 8, 8, 6, 8, - 8, 9, 7, 5, 4, 2, 2, 2, 2, 2, - 2, 2, 2, 4, 4, 4, 4, 4, 4, 8, - 8, 0, 2, 4, 4, 4, 4, 0, 3, 4, - 7, 3, 1, 1, 2, 3, 3, 1, 2, 2, - 1, 2, 1, 2, 2, 1, 2, 0, 1, 0, - 2, 1, 2, 4, 0, 2, 1, 3, 5, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, - 0, 3, 0, 2, 0, 3, 1, 3, 2, 0, - 1, 1, 0, 2, 4, 4, 0, 2, 4, 2, - 1, 3, 5, 4, 6, 1, 3, 3, 5, 0, - 5, 1, 3, 1, 2, 3, 1, 1, 3, 3, - 1, 3, 3, 3, 3, 3, 1, 2, 1, 1, - 1, 1, 1, 1, 0, 2, 0, 3, 0, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 0, 1, 1, 0, 2, + 0, 3, 0, 1, 0, 3, 3, 0, 2, 2, + 0, 2, 1, 2, 1, 0, 2, 5, 4, 1, + 2, 2, 3, 2, 0, 1, 2, 3, 3, 2, + 2, 1, 1, 0, 1, 1, 3, 2, 3, 1, + 10, 11, 11, 12, 3, 3, 1, 1, 2, 2, + 2, 0, 1, 3, 1, 2, 3, 1, 1, 1, + 6, 7, 7, 7, 7, 4, 5, 7, 5, 5, + 5, 12, 7, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 7, 1, 3, 8, 8, 3, + 3, 5, 4, 6, 5, 4, 4, 3, 2, 3, + 4, 4, 3, 4, 4, 4, 4, 4, 4, 3, + 2, 3, 3, 2, 3, 4, 3, 7, 5, 4, + 2, 4, 2, 2, 2, 2, 3, 3, 5, 2, + 3, 1, 1, 0, 1, 1, 1, 0, 2, 2, + 0, 2, 2, 0, 1, 1, 2, 1, 1, 2, + 1, 1, 2, 2, 2, 2, 2, 3, 3, 2, + 0, 2, 0, 2, 1, 2, 2, 0, 1, 1, + 0, 1, 0, 1, 0, 1, 1, 3, 1, 2, + 3, 5, 0, 1, 2, 1, 1, 0, 2, 1, + 3, 1, 1, 1, 3, 1, 3, 3, 7, 1, + 3, 1, 3, 4, 4, 4, 3, 2, 4, 0, + 1, 0, 2, 0, 1, 0, 1, 2, 1, 1, + 1, 2, 2, 1, 2, 3, 2, 3, 2, 2, + 2, 1, 1, 3, 0, 5, 5, 5, 0, 2, + 1, 3, 3, 2, 3, 1, 2, 0, 3, 1, + 1, 3, 3, 4, 4, 5, 3, 4, 5, 6, + 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, + 1, 1, 1, 1, 0, 2, 1, 1, 1, 3, + 1, 3, 1, 1, 1, 1, 1, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, + 1, 1, 1, 1, 4, 5, 6, 4, 4, 6, + 6, 6, 6, 8, 8, 6, 8, 8, 6, 8, + 8, 6, 8, 8, 9, 7, 5, 4, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 8, 8, 0, 2, 3, 4, 4, 4, + 4, 0, 3, 4, 7, 3, 1, 1, 2, 3, + 3, 1, 2, 2, 1, 2, 1, 2, 2, 1, + 2, 0, 1, 0, 2, 1, 2, 4, 0, 2, + 1, 3, 5, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 2, 0, 3, 0, 2, 0, 3, + 1, 3, 2, 0, 1, 1, 0, 2, 4, 4, + 0, 2, 4, 2, 1, 3, 5, 4, 6, 1, + 3, 3, 5, 0, 5, 1, 3, 1, 2, 3, + 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, + 1, 2, 1, 1, 1, 1, 1, 1, 0, 2, + 0, 3, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, + 1, 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -2341,20 +2354,19 @@ var yyR2 = [...]int{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, - 1, 1, + 1, 1, 0, 0, 1, 1, } var yyChk = [...]int{ - -1000, -187, -1, -2, -6, -7, -8, -9, -10, -11, + -1000, -188, -1, -2, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -19, -20, -21, -23, -24, -25, -22, -16, -3, -4, 6, 7, -29, 9, 10, 30, -17, 115, 116, 118, 117, 149, 119, 142, 50, 162, 163, 165, 166, 25, 143, 144, 147, 148, 31, 32, - 121, -189, 8, 251, 54, -188, 268, -84, 15, -28, - 5, -26, -192, -26, -26, -26, -26, -26, -163, -165, - 54, 90, -116, 125, 72, 243, 122, 123, 129, -119, - 57, -118, 261, 135, 162, 173, 167, 194, 186, 136, + 121, -190, 8, 251, 54, -189, 268, -85, 15, -28, + 5, -26, -193, -26, -26, -26, -26, -26, -164, -166, + 54, 90, -117, 125, 72, 243, 122, 123, 129, -120, + 57, -119, 261, 135, 162, 173, 167, 194, 186, 136, 184, 187, 230, 214, 225, 66, 165, 239, 145, 182, 178, 176, 27, 227, 199, 266, 177, 226, 121, 138, 133, 200, 204, 231, 171, 172, 233, 198, 134, 33, @@ -2365,21 +2377,21 @@ var yyChk = [...]int{ 169, 132, 163, 159, 216, 190, 154, 180, 181, 195, 168, 191, 164, 156, 149, 240, 212, 267, 188, 185, 160, 157, 158, 217, 218, 219, 220, 221, 222, 161, - 264, 236, 183, 213, -104, 125, 220, 127, 123, 123, - 124, 125, 243, 122, 123, -53, -125, 57, -118, 125, + 264, 236, 183, 213, -105, 125, 220, 127, 123, 123, + 124, 125, 243, 122, 123, -53, -126, 57, -119, 125, 123, 108, 187, 230, 115, 215, 227, 124, 33, 228, - 155, -134, 123, -106, 214, 217, 218, 219, 222, 220, - 161, 57, 232, 231, 223, -125, 164, -130, -130, -130, - -130, -130, 216, 216, -130, -2, -88, 17, 16, -5, - -3, -189, 6, 20, 21, -32, 40, 41, -27, -38, - 99, -39, -125, -58, 74, -63, 29, 57, -118, 23, - -62, -59, -77, -75, -76, 108, 109, 110, 97, 98, + 155, -135, 123, -107, 214, 217, 218, 219, 222, 220, + 161, 57, 232, 231, 223, -126, 164, -131, -131, -131, + -131, -131, 216, 216, -131, -2, -89, 17, 16, -5, + -3, -190, 6, 20, 21, -32, 40, 41, -27, -38, + 99, -39, -126, -58, 74, -63, 29, 57, -119, 23, + -62, -59, -78, -76, -77, 108, 109, 110, 97, 98, 105, 75, 111, -67, -65, -66, -68, 59, 58, 67, - 60, 61, 62, 63, 68, 69, 70, -119, -73, -189, + 60, 61, 62, 63, 68, 69, 70, -120, -74, -190, 44, 45, 252, 253, 254, 255, 260, 256, 77, 34, 242, 250, 249, 248, 246, 247, 244, 245, 258, 259, - 128, 243, 103, 251, -104, -104, 11, -48, -53, -96, - -133, 164, -100, 232, 231, -120, -98, -119, -117, 230, + 128, 243, 103, 251, -105, -105, 11, -48, -53, -97, + -134, 164, -101, 232, 231, -121, -99, -120, -118, 230, 187, 229, 120, 73, 22, 24, 209, 76, 108, 16, 77, 107, 252, 115, 48, 244, 245, 242, 254, 255, 243, 215, 29, 10, 25, 143, 21, 101, 117, 80, @@ -2389,258 +2401,254 @@ var yyChk = [...]int{ 49, 36, 74, 68, 71, 52, 72, 15, 47, 91, 118, 251, 45, 122, 6, 257, 30, 142, 43, 123, 79, 258, 259, 126, 69, 5, 129, 32, 9, 50, - 53, 248, 249, 250, 34, 78, 12, -164, 90, -157, - 57, -53, 124, -53, 251, -112, 128, -112, -112, 123, - -53, 115, 117, 120, 52, -18, -53, -111, 128, 57, - -111, -111, -111, -53, 112, -53, 57, 30, -131, -189, - -120, 243, 57, 155, 123, 156, 125, -131, -131, -131, - -131, 159, 160, -131, -109, -108, 225, 226, 216, 224, - 12, 216, 158, -131, -130, -130, -190, 56, -89, 19, - 31, -39, -125, -85, -86, -39, -84, -2, -26, 36, - -30, 21, 65, 11, -122, 73, 72, 89, -121, 22, - -119, 59, 112, -39, -60, 92, 74, 90, 91, 76, + 53, 248, 249, 250, 34, 78, 12, -165, 90, -158, + 57, -53, 124, -53, 251, -113, 128, -113, -113, 123, + -53, 115, 117, 120, 52, -18, -53, -112, 128, 57, + -112, -112, -112, -53, 112, -53, 57, 30, -132, -190, + -121, 243, 57, 155, 123, 156, 125, -132, -132, -132, + -132, 159, 160, -132, -110, -109, 225, 226, 216, 224, + 12, 216, 158, -132, -131, -131, -191, 56, -90, 19, + 31, -39, -126, -86, -87, -39, -85, -2, -26, 36, + -30, 21, 65, 11, -123, 73, 72, 89, -122, 22, + -120, 59, 112, -39, -60, 92, 74, 90, 91, 76, 94, 93, 104, 97, 98, 99, 100, 101, 102, 103, 95, 96, 107, 82, 83, 84, 85, 86, 87, 88, - -105, -189, -76, -189, 113, 114, -63, -63, -63, -63, - -63, -63, -63, -63, -189, -2, -71, -39, -189, -189, - -189, -189, -189, -189, -189, -189, -189, -80, -39, -189, - -193, -189, -193, -189, -193, -189, -193, -189, -193, -189, - -193, -189, -193, -193, -189, -189, -189, -189, -189, -189, - -189, -54, 26, -53, -41, -42, -43, -44, -55, -76, - -189, -53, -53, -48, -191, 55, 11, 53, 55, -96, - 164, -97, -101, 233, 235, 82, -124, -119, 59, 29, - 30, 56, 55, -53, -136, -139, -141, -140, -142, -137, - -138, 184, 185, 108, 188, 190, 191, 192, 193, 194, - 195, 196, 197, 198, 199, 30, 145, 180, 181, 182, - 183, 200, 201, 202, 203, 204, 205, 206, 207, 167, - 168, 169, 170, 171, 172, 173, 175, 176, 177, 178, - 179, 57, -131, 125, 57, 74, 57, -53, -53, -131, - 157, 157, 123, 123, -53, 55, 126, -48, 23, 52, - -53, 57, 57, -126, -125, -117, -131, -131, -131, -131, - -131, -131, -131, -131, -131, -131, 11, -107, 11, 92, - -39, 52, 9, 92, 55, 18, 112, 55, -87, 24, - 25, -88, -190, -32, -64, -119, 60, 63, -31, 43, - -53, -39, -39, -69, 68, 74, 69, 70, -121, 99, - -126, -120, -117, -63, -70, -73, -76, 64, 92, 90, - 91, 76, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -132, 57, 59, - 57, -62, -62, -119, -37, 21, -36, -38, -190, 55, - -190, -2, -36, -36, -39, -39, -77, 59, -119, -125, - -77, 59, -36, -30, -78, -79, 78, -77, -63, -190, - -63, -63, -63, -63, -63, -119, -119, -36, -37, -36, - -36, -92, 151, -53, 30, 55, -49, -51, -50, -52, - 42, 46, 48, 43, 44, 45, 49, -129, 22, -41, - -189, -128, 151, -127, 22, -125, 59, -92, 53, -41, - -53, -100, -97, 55, 234, 236, 237, 52, 71, -39, - -148, 107, -166, -167, -168, -120, 59, 60, -157, -158, - -159, -169, 137, -174, 130, 132, 129, -160, 138, 124, - 28, 56, -153, 68, 74, -149, 212, -143, 54, -143, - -143, -143, -143, -147, 187, -147, -147, -147, 54, 54, - -143, -143, -143, -151, 54, -151, -151, -152, 54, -152, - -123, 53, -53, -131, 23, -131, -113, 120, 117, 118, - -177, 116, 209, 187, 66, 29, 15, 252, 151, 267, - 57, 152, -119, -119, -53, -53, 120, 117, -53, -53, - -53, -131, -53, -110, 90, 12, -125, -125, -53, 38, - -39, -39, -126, -86, -89, -103, 19, 11, 34, 34, - -36, 68, 69, 70, 112, -189, -70, -63, -63, -63, - -35, 146, 73, -190, -190, -36, 55, -39, -190, -190, - -190, 55, 53, 22, 55, 11, 55, 11, 112, 55, - 11, 55, 11, -190, -36, -81, -79, 80, -39, -190, - -190, -190, -190, -190, -190, -190, 55, 55, -190, -190, - -190, -190, -61, 30, 34, -2, -189, -189, -95, -99, - -77, -42, -43, -43, -42, -43, 42, 42, 42, 47, - 42, 47, 42, -50, -125, -190, -56, 50, 127, 51, - -189, -127, -57, 12, -41, -57, -101, -102, 238, 235, - 241, 57, 59, 55, -168, 82, 54, 57, 28, -160, - -160, -161, 57, -161, 28, -144, 29, 68, -150, 213, - 60, -147, -147, -148, 30, -148, -148, -148, -156, 59, - -156, 60, 60, 52, -119, -131, -130, -183, 131, 137, - 138, 133, 57, 124, 28, 130, 132, 151, 129, -183, - -114, -115, 126, 22, 124, 28, 151, -182, 53, 157, - 157, 126, -131, -107, 59, -39, 39, 112, -53, -40, - 11, 99, -120, -37, -35, 73, -63, -63, -190, -38, - -135, 108, 184, 145, 182, 178, 198, 189, 211, 180, - 212, -132, -135, -63, -63, -63, -63, -120, -63, -63, - -63, -63, 261, -84, 81, -39, 79, -63, -63, -94, - 52, -95, -72, -74, -73, -189, -2, -90, -119, -93, - -119, -57, 55, 82, -46, -45, 52, 53, -47, 52, - -45, 42, 42, 124, 124, 124, -93, -84, -39, -57, - 235, 239, 240, -167, -168, -171, -170, -119, -174, -161, - -161, 54, -146, 52, 59, 60, 61, 68, 242, 67, - 56, -148, -148, 57, 108, 56, 55, 56, 55, 56, - 55, -53, -130, -130, -53, -130, -119, -180, 264, -181, - 57, -119, -119, -53, -110, -57, -41, -190, -63, -190, - -143, -143, -143, -152, -143, 172, -143, 172, -190, -190, - -190, 55, 19, -190, 55, 19, -190, 55, 19, -190, - 55, 19, -189, -34, 257, -39, 55, 55, 27, -94, - 55, -190, -190, -190, 55, 112, -190, 55, -84, -99, - -39, -39, 54, -39, -189, -189, -189, -190, -88, 56, - 55, -143, -91, -119, -154, 209, 9, 54, -147, 59, - -147, 60, 60, -131, 26, -179, -178, -120, 54, -82, - 13, -147, 57, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -190, 59, -63, -63, 28, -74, 34, -2, - -189, -119, -119, -119, -88, -91, -91, -91, -91, -128, - -173, -172, 53, 134, 66, -170, 56, 55, -155, 130, - 28, 129, 242, 56, -148, -148, 56, 56, -189, 55, - 82, -91, -83, 14, 16, -190, -190, -190, -190, -190, - -190, -190, -190, -33, 92, 264, -190, -190, 9, -72, - -2, 112, 56, -190, -190, -190, -56, -172, 57, -162, - 82, 59, 140, -119, -145, 66, 28, 28, 54, -175, - -176, 151, -178, -168, 56, -39, -71, -190, 262, 49, - 265, -95, -190, -119, 60, -53, 59, 56, -190, 55, - -119, -182, 39, 263, 266, 54, -176, 34, -180, 39, - -91, 153, 264, 56, 154, 265, -185, -186, 52, -189, - 266, -186, 52, 10, 9, -63, 150, -184, 141, 136, - 139, 30, -184, -190, -190, 135, 29, 68, + -106, -190, -77, -190, 113, 114, -63, -63, -63, -63, + -63, -63, -63, -63, -190, -2, -72, -39, -190, -190, + -190, -190, -190, -190, -190, -190, -190, -81, -39, -190, + -194, -69, -190, -194, -69, -194, -69, -194, -190, -194, + -69, -194, -69, -194, -194, -69, -190, -190, -190, -190, + -190, -190, -54, 26, -53, -41, -42, -43, -44, -55, + -77, -190, -53, -53, -48, -192, 55, 11, 53, 55, + -97, 164, -98, -102, 233, 235, 82, -125, -120, 59, + 29, 30, 56, 55, -53, -137, -140, -142, -141, -143, + -138, -139, 184, 185, 108, 188, 190, 191, 192, 193, + 194, 195, 196, 197, 198, 199, 30, 145, 180, 181, + 182, 183, 200, 201, 202, 203, 204, 205, 206, 207, + 167, 168, 169, 170, 171, 172, 173, 175, 176, 177, + 178, 179, 57, -132, 125, 57, 74, 57, -53, -53, + -132, 157, 157, 123, 123, -53, 55, 126, -48, 23, + 52, -53, 57, 57, -127, -126, -118, -132, -132, -132, + -132, -132, -132, -132, -132, -132, -132, 11, -108, 11, + 92, -39, 52, 9, 92, 55, 18, 112, 55, -88, + 24, 25, -89, -191, -32, -64, -120, 60, 63, -31, + 43, -53, -39, -39, -70, 68, 74, 69, 70, -122, + 99, -127, -121, -118, -63, -71, -74, -77, 64, 92, + 90, 91, 76, -63, -63, -63, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -133, 57, + 59, 57, -62, -62, -120, -37, 21, -36, -38, -191, + 55, -191, -2, -36, -36, -39, -39, -78, 59, -120, + -126, -78, 59, -36, -30, -79, -80, 78, -78, -191, + -63, -120, -120, -36, -37, -36, -36, -93, 151, -53, + 30, 55, -49, -51, -50, -52, 42, 46, 48, 43, + 44, 45, 49, -130, 22, -41, -190, -129, 151, -128, + 22, -126, 59, -93, 53, -41, -53, -101, -98, 55, + 234, 236, 237, 52, 71, -39, -149, 107, -167, -168, + -169, -121, 59, 60, -158, -159, -160, -170, 137, -175, + 130, 132, 129, -161, 138, 124, 28, 56, -154, 68, + 74, -150, 212, -144, 54, -144, -144, -144, -144, -148, + 187, -148, -148, -148, 54, 54, -144, -144, -144, -152, + 54, -152, -152, -153, 54, -153, -124, 53, -53, -132, + 23, -132, -114, 120, 117, 118, -178, 116, 209, 187, + 66, 29, 15, 252, 151, 267, 57, 152, -120, -120, + -53, -53, 120, 117, -53, -53, -53, -132, -53, -111, + 90, 12, -126, -126, -53, 38, -39, -39, -127, -87, + -90, -104, 19, 11, 34, 34, -36, 68, 69, 70, + 112, -190, -71, -63, -63, -63, -35, 146, 73, -191, + -191, -36, 55, -39, -191, -191, -191, 55, 53, 22, + 55, 11, 55, 11, 112, 55, 11, 55, 11, -191, + -36, -82, -80, 80, -39, -191, -191, 55, 55, -191, + -191, -191, -191, -61, 30, 34, -2, -190, -190, -96, + -100, -78, -42, -43, -43, -42, -43, 42, 42, 42, + 47, 42, 47, 42, -50, -126, -191, -56, 50, 127, + 51, -190, -128, -57, 12, -41, -57, -102, -103, 238, + 235, 241, 57, 59, 55, -169, 82, 54, 57, 28, + -161, -161, -162, 57, -162, 28, -146, 29, 68, -151, + 213, 60, -148, -148, -149, 30, -149, -149, -149, -157, + 59, -157, 60, 60, 52, -120, -132, -131, -184, 131, + 137, 138, 133, 57, 124, 28, 130, 132, 151, 129, + -184, -115, -116, 126, 22, 124, 28, 151, -183, 53, + 157, 157, 126, -132, -108, 59, -39, 39, 112, -53, + -40, 11, 99, -121, -37, -35, 73, -63, -63, -191, + -38, -136, 108, 184, 145, 182, 178, 198, 189, 211, + 180, 212, -133, -136, -63, -63, -63, -63, -121, -63, + -63, -63, -63, 261, -85, 81, -39, 79, -63, -63, + -95, 52, -96, -73, -75, -74, -190, -2, -91, -120, + -94, -120, -57, 55, 82, -46, -45, 52, 53, -47, + 52, -45, 42, 42, 124, 124, 124, -94, -85, -39, + -57, 235, 239, 240, -168, -169, -172, -171, -120, -175, + -162, -162, 54, -147, 52, -63, 56, -149, -149, 57, + 108, 56, 55, 56, 55, 56, 55, -53, -131, -131, + -53, -131, -120, -181, 264, -182, 57, -120, -120, -53, + -111, -57, -41, -191, -63, -191, -144, -144, -144, -153, + -144, 172, -144, 172, -191, -191, -191, 55, 19, -191, + 55, 19, -191, 55, 19, -191, 55, 19, -190, -34, + 257, -39, 55, 55, 27, -95, 55, -191, -191, -191, + 55, 112, -191, 55, -85, -100, -39, -39, 54, -39, + -190, -190, -190, -191, -89, 56, 55, -144, -92, -120, + -155, 209, 9, -148, 59, -148, 60, 60, -132, 26, + -180, -179, -121, 54, -83, 13, -148, 57, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -191, 59, -63, + -63, 28, -75, 34, -2, -190, -120, -120, -120, -89, + -92, -92, -92, -92, -129, -174, -173, 53, 134, 66, + -171, 56, 55, -156, 130, 28, 129, -66, -149, -149, + 56, 56, -190, 55, 82, -92, -84, 14, 16, -191, + -191, -191, -191, -191, -191, -191, -191, -33, 92, 264, + -191, -191, 9, -73, -2, 112, 56, -191, -191, -191, + -56, -173, 57, -163, 82, 59, 140, -120, -145, 66, + 28, 28, -176, -177, 151, -179, -169, 56, -39, -72, + -191, 262, 49, 265, -96, -191, -120, 60, -53, 59, + -191, 55, -120, -183, 39, 263, 266, 54, -177, 34, + -181, 39, -92, 153, 264, 56, 154, 265, -186, -187, + 52, -190, 266, -187, 52, 10, 9, -63, 150, -185, + 141, 136, 139, 30, -185, -191, -191, 135, 29, 68, } var yyDef = [...]int{ 23, -2, 2, -2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 564, 0, 317, 317, 317, 317, 317, 317, - 0, 635, 618, 0, 0, 0, 0, -2, 304, 305, - 0, 307, 308, 858, 858, 858, 858, 858, 0, 0, - 858, 0, 35, 36, 856, 1, 3, 572, 0, 0, - 321, 324, 319, 0, 618, 618, 0, 0, 62, 63, - 0, 0, 0, 842, 0, 616, 616, 616, 636, 637, - 640, 641, 743, 744, 745, 746, 747, 748, 749, 750, - 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, - 761, 762, 763, 764, 765, 766, 767, 768, 769, 770, - 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, - 781, 782, 783, 784, 785, 786, 787, 788, 789, 790, - 791, 792, 793, 794, 795, 796, 797, 798, 799, 800, - 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, - 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, - 821, 822, 823, 824, 825, 826, 827, 828, 829, 830, - 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, - 841, 843, 844, 845, 846, 847, 848, 849, 850, 851, - 852, 853, 854, 855, 0, 0, 0, 619, 0, 614, - 0, 614, 614, 614, 0, 255, 389, 644, 645, 842, - 0, 0, 0, 859, 0, 859, 267, 859, 859, 270, - 859, 0, 859, 0, 277, 279, 280, 281, 282, 0, - 286, 859, 301, 302, 291, 303, 306, 309, 310, 311, - 312, 313, 858, 858, 316, 29, 576, 0, 0, 564, - 31, 0, 317, 322, 323, 327, 325, 326, 318, 0, - 335, 339, 0, 397, 0, 402, 404, -2, -2, 0, - 439, 440, 441, 442, 443, 0, 0, 0, 0, 0, - 0, 0, 0, 467, 468, 469, 470, 549, 550, 551, - 552, 553, 554, 555, 556, 406, 407, 546, 596, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 537, 0, - 511, 511, 511, 511, 511, 511, 511, 511, 0, 0, + 21, 22, 558, 0, 310, 310, 310, 310, 310, 310, + 0, 629, 612, 0, 0, 0, 0, -2, 297, 298, + 0, 300, 301, 852, 852, 852, 852, 852, 0, 0, + 852, 0, 35, 36, 850, 1, 3, 566, 0, 0, + 314, 317, 312, 0, 612, 612, 0, 0, 62, 63, + 0, 0, 0, 836, 0, 610, 610, 610, 630, 631, + 634, 635, 737, 738, 739, 740, 741, 742, 743, 744, + 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, + 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, + 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, + 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, + 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, + 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, + 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, + 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, + 835, 837, 838, 839, 840, 841, 842, 843, 844, 845, + 846, 847, 848, 849, 0, 0, 0, 613, 0, 608, + 0, 608, 608, 608, 0, 248, 382, 638, 639, 836, + 0, 0, 0, 853, 0, 853, 260, 853, 853, 263, + 853, 0, 853, 0, 270, 272, 273, 274, 275, 0, + 279, 853, 294, 295, 284, 296, 299, 302, 303, 304, + 305, 306, 852, 852, 309, 29, 570, 0, 0, 558, + 31, 0, 310, 315, 316, 320, 318, 319, 311, 0, + 328, 332, 0, 390, 0, 395, 397, -2, -2, 0, + 432, 433, 434, 435, 436, 0, 0, 0, 0, 0, + 0, 0, 0, 460, 461, 462, 463, 543, 544, 545, + 546, 547, 548, 549, 550, 399, 400, 540, 590, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 531, 0, + 504, 504, 504, 504, 504, 504, 504, 504, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 47, - 0, 833, 600, -2, -2, 0, 0, 642, 643, -2, - 752, -2, 648, 649, 650, 651, 652, 653, 654, 655, - 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, - 666, 667, 668, 669, 670, 671, 672, 673, 674, 675, - 676, 677, 678, 679, 680, 681, 682, 683, 684, 685, - 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, - 696, 697, 698, 699, 700, 701, 702, 703, 704, 705, - 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, - 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, - 726, 727, 728, 729, 730, 731, 732, 733, 734, 735, - 736, 737, 738, 739, 740, 741, 742, 0, 0, 81, - 0, 79, 0, 859, 0, 0, 0, 0, 0, 0, - 859, 0, 0, 0, 0, 246, 0, 0, 0, 0, - 0, 0, 0, 254, 0, 256, 859, 859, 259, 860, - 861, 859, 859, 859, 859, 859, 859, 266, 268, 269, - 271, 859, 859, 273, 0, 294, 292, 293, 288, 289, - 0, 283, 284, 287, 314, 315, 30, 857, 24, 0, - 0, 573, 0, 565, 566, 569, 572, 29, 324, 0, - 329, 328, 320, 0, 336, 0, 0, 0, 340, 0, - 342, 343, 0, 400, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 424, 425, 426, 427, 428, 429, 430, - 403, 0, 417, 0, 0, 0, 459, 460, 461, 462, - 463, 464, 465, 0, 331, 29, 0, 437, 0, 0, - 0, 0, 0, 0, 0, 0, 327, 0, 538, 0, - 495, 0, 496, 0, 497, 0, 498, 0, 499, 0, - 500, 0, 501, 502, 0, 0, 0, 0, 331, 0, - 0, 45, 0, 388, 0, 346, 348, 349, 350, -2, - 0, 372, -2, 0, 0, 0, 41, 42, 0, 48, - 833, 50, 51, 0, 0, 0, 164, 609, 610, 611, - 607, 208, 0, 0, 145, 141, 87, 88, 89, 134, - 91, 134, 134, 134, 134, 161, 161, 161, 161, 117, - 118, 119, 120, 121, 0, 0, 104, 134, 134, 134, - 108, 124, 125, 126, 127, 128, 129, 130, 131, 92, - 93, 94, 95, 96, 97, 98, 136, 136, 136, 138, - 138, 638, 65, 0, 859, 0, 859, 77, 0, 222, - 0, 0, 0, 0, 0, 0, 0, 249, 615, 0, - 859, 252, 253, 390, 646, 647, 257, 258, 260, 261, - 262, 263, 264, 265, 272, 276, 0, 297, 0, 0, - 278, 0, 577, 0, 0, 0, 0, 0, 568, 570, - 571, 576, 32, 327, 0, 557, 0, 0, 0, 330, - 27, 398, 399, 401, 418, 0, 420, 422, 341, 337, - 0, 547, -2, 408, 409, 433, 434, 435, 0, 0, - 0, 0, 431, 413, 0, 444, 445, 446, 447, 448, - 449, 450, 451, 452, 453, 454, 455, 458, 522, 523, - 0, 456, 457, 466, 0, 0, 332, 333, 436, 0, - 595, 29, 0, 0, 0, 0, 0, 0, 546, 0, - 0, 0, 0, 0, 544, 541, 0, 0, 0, 512, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 387, 0, 0, 0, 0, 0, 0, - 377, 0, 0, 380, 0, 0, 0, 0, 371, 0, - 0, 391, 802, 373, 0, 375, 376, 395, 0, 395, - 44, 601, 49, 0, 0, 54, 55, 602, 603, 604, - 605, 0, 78, 209, 211, 214, 215, 216, 82, 83, - 84, 0, 0, 196, 0, 0, 190, 190, 0, 188, - 189, 80, 148, 146, 0, 143, 142, 90, 0, 161, - 161, 111, 112, 164, 0, 164, 164, 164, 0, 0, - 105, 106, 107, 99, 0, 100, 101, 102, 0, 103, - 0, 0, 859, 67, 617, 68, 858, 0, 0, 630, - 223, 620, 621, 622, 623, 624, 625, 626, 627, 628, - 629, 0, 69, 225, 227, 226, 0, 0, 0, 247, - 859, 251, 294, 275, 0, 0, 295, 296, 285, 0, - 574, 575, 0, 567, 25, 0, 612, 613, 558, 559, - 344, 419, 421, 423, 0, 331, 410, 431, 414, 0, - 411, 0, 0, 405, 471, 0, 0, 438, -2, 474, - 475, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 564, 0, 542, 0, 0, 494, - 503, 504, 505, 506, 507, 508, 0, 0, 513, 514, - 515, 516, 589, 0, 0, -2, 0, 0, 395, 597, - 0, 347, 366, 368, 0, 363, 378, 379, 381, 0, - 383, 0, 385, 386, 351, 353, 354, 0, 0, 0, - 0, 374, 564, 0, 395, 40, 52, 53, 0, 0, - 59, 165, 166, 0, 212, 0, 0, 0, 183, 190, - 190, 186, 191, 187, 0, 156, 0, 147, 86, 144, - 0, 164, 164, 113, 0, 114, 115, 116, 0, 132, - 0, 0, 0, 0, 639, 66, 217, 858, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 240, 858, - 0, 858, 631, 632, 633, 634, 0, 72, 0, 0, - 0, 0, 250, 297, 298, 299, 578, 0, 26, 395, - 0, 338, 548, 0, 412, 0, 432, 415, 472, 334, - 0, 134, 134, 527, 134, 138, 530, 134, 532, 134, - 535, 0, 0, 0, 0, 0, 0, 547, 0, 0, - 0, 0, 0, 539, 493, 545, 0, 0, 0, 33, - 0, 589, 579, 591, 593, 0, 29, 0, 585, 0, - 358, 564, 0, 0, 360, 367, 0, 0, 361, 0, - 362, 382, 384, 0, 0, 0, 0, 572, 396, 39, - 56, 57, 58, 210, 213, 0, 192, 134, 195, 184, - 185, 0, 159, 0, 149, 150, 151, 152, 153, 155, - 135, 109, 110, 162, 163, 161, 0, 161, 0, 139, - 0, 859, 218, 219, 220, 221, 0, 224, 0, 70, - 71, 0, 229, 248, 274, 560, 345, 473, 416, 476, - 524, 161, 528, 529, 531, 533, 534, 536, 478, 477, - 479, 0, 0, 485, 0, 0, 482, 0, 0, 488, - 0, 0, 0, 0, 0, 543, 0, 0, 0, 34, - 0, 594, -2, 0, 0, 0, 46, 0, 572, 598, - 599, 364, 0, 369, 0, 0, 0, 372, 38, 175, - 0, 194, 0, 356, 167, 160, 0, 0, 164, 133, - 164, 0, 0, 64, 0, 73, 74, 0, 0, 562, - 0, 525, 526, 0, 0, 0, 0, 0, 0, 0, - 0, 517, 492, 540, 0, 0, 0, 592, 0, -2, - 0, 587, 586, 359, 37, 0, 0, 0, 0, 391, - 174, 176, 0, 181, 0, 193, 0, 0, 172, 0, - 169, 171, 157, 154, 122, 123, 137, 140, 0, 0, - 0, 0, 28, 0, 0, 480, 481, 486, 487, 483, - 484, 489, 490, 0, 0, 0, 509, 510, 0, 582, - 29, 0, 365, 392, 393, 394, 355, 177, 178, 0, - 182, 180, 0, 357, 85, 0, 168, 170, 0, 0, - 242, 0, 75, 76, 69, 563, 561, 491, 0, 0, - 0, 590, -2, 588, 179, 0, 173, 158, 241, 0, - 0, 72, 518, 0, 521, 0, 243, 0, 228, 519, - 0, 0, 0, 197, 0, 0, 198, 199, 0, 0, - 520, 200, 0, 0, 0, 0, 0, 201, 203, 204, - 0, 0, 202, 244, 245, 205, 206, 207, + 0, 827, 594, -2, -2, 0, 0, 636, 637, -2, + 746, -2, 642, 643, 644, 645, 646, 647, 648, 649, + 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, + 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, + 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, + 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, + 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, + 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, + 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, + 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, + 730, 731, 732, 733, 734, 735, 736, 0, 0, 81, + 0, 79, 0, 853, 0, 0, 0, 0, 0, 0, + 853, 0, 0, 0, 0, 239, 0, 0, 0, 0, + 0, 0, 0, 247, 0, 249, 853, 853, 252, 854, + 855, 853, 853, 853, 853, 853, 853, 259, 261, 262, + 264, 853, 853, 266, 0, 287, 285, 286, 281, 282, + 0, 276, 277, 280, 307, 308, 30, 851, 24, 0, + 0, 567, 0, 559, 560, 563, 566, 29, 317, 0, + 322, 321, 313, 0, 329, 0, 0, 0, 333, 0, + 335, 336, 0, 393, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 417, 418, 419, 420, 421, 422, 423, + 396, 0, 410, 0, 0, 0, 452, 453, 454, 455, + 456, 457, 458, 0, 324, 29, 0, 430, 0, 0, + 0, 0, 0, 0, 0, 0, 320, 0, 532, 0, + 488, 496, 0, 489, 497, 490, 498, 491, 0, 492, + 499, 493, 500, 494, 495, 501, 0, 0, 0, 324, + 0, 0, 45, 0, 381, 0, 339, 341, 342, 343, + -2, 0, 365, -2, 0, 0, 0, 41, 42, 0, + 48, 827, 50, 51, 0, 0, 0, 157, 603, 604, + 605, 601, 201, 0, 0, 145, 141, 87, 88, 89, + 134, 91, 134, 134, 134, 134, 154, 154, 154, 154, + 117, 118, 119, 120, 121, 0, 0, 104, 134, 134, + 134, 108, 124, 125, 126, 127, 128, 129, 130, 131, + 92, 93, 94, 95, 96, 97, 98, 136, 136, 136, + 138, 138, 632, 65, 0, 853, 0, 853, 77, 0, + 215, 0, 0, 0, 0, 0, 0, 0, 242, 609, + 0, 853, 245, 246, 383, 640, 641, 250, 251, 253, + 254, 255, 256, 257, 258, 265, 269, 0, 290, 0, + 0, 271, 0, 571, 0, 0, 0, 0, 0, 562, + 564, 565, 570, 32, 320, 0, 551, 0, 0, 0, + 323, 27, 391, 392, 394, 411, 0, 413, 415, 334, + 330, 0, 541, -2, 401, 402, 426, 427, 428, 0, + 0, 0, 0, 424, 406, 0, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, 451, 516, + 517, 0, 449, 450, 459, 0, 0, 325, 326, 429, + 0, 589, 29, 0, 0, 0, 0, 0, 0, 540, + 0, 0, 0, 0, 0, 538, 535, 0, 0, 505, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 380, + 0, 0, 0, 0, 0, 0, 370, 0, 0, 373, + 0, 0, 0, 0, 364, 0, 0, 384, 796, 366, + 0, 368, 369, 388, 0, 388, 44, 595, 49, 0, + 0, 54, 55, 596, 597, 598, 599, 0, 78, 202, + 204, 207, 208, 209, 82, 83, 84, 0, 0, 189, + 0, 0, 183, 183, 0, 181, 182, 80, 148, 146, + 0, 143, 142, 90, 0, 154, 154, 111, 112, 157, + 0, 157, 157, 157, 0, 0, 105, 106, 107, 99, + 0, 100, 101, 102, 0, 103, 0, 0, 853, 67, + 611, 68, 852, 0, 0, 624, 216, 614, 615, 616, + 617, 618, 619, 620, 621, 622, 623, 0, 69, 218, + 220, 219, 0, 0, 0, 240, 853, 244, 287, 268, + 0, 0, 288, 289, 278, 0, 568, 569, 0, 561, + 25, 0, 606, 607, 552, 553, 337, 412, 414, 416, + 0, 324, 403, 424, 407, 0, 404, 0, 0, 398, + 464, 0, 0, 431, -2, 467, 468, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 558, 0, 536, 0, 0, 487, 506, 0, 0, 507, + 508, 509, 510, 583, 0, 0, -2, 0, 0, 388, + 591, 0, 340, 359, 361, 0, 356, 371, 372, 374, + 0, 376, 0, 378, 379, 344, 346, 347, 0, 0, + 0, 0, 367, 558, 0, 388, 40, 52, 53, 0, + 0, 59, 158, 159, 0, 205, 0, 0, 0, 176, + 183, 183, 179, 184, 180, 0, 150, 0, 147, 86, + 144, 0, 157, 157, 113, 0, 114, 115, 116, 0, + 132, 0, 0, 0, 0, 633, 66, 210, 852, 223, + 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, + 852, 0, 852, 625, 626, 627, 628, 0, 72, 0, + 0, 0, 0, 243, 290, 291, 292, 572, 0, 26, + 388, 0, 331, 542, 0, 405, 0, 425, 408, 465, + 327, 0, 134, 134, 521, 134, 138, 524, 134, 526, + 134, 529, 0, 0, 0, 0, 0, 0, 541, 0, + 0, 0, 0, 0, 533, 486, 539, 0, 0, 0, + 33, 0, 583, 573, 585, 587, 0, 29, 0, 579, + 0, 351, 558, 0, 0, 353, 360, 0, 0, 354, + 0, 355, 375, 377, 0, 0, 0, 0, 566, 389, + 39, 56, 57, 58, 203, 206, 0, 185, 134, 188, + 177, 178, 0, 152, 0, 149, 135, 109, 110, 155, + 156, 154, 0, 154, 0, 139, 0, 853, 211, 212, + 213, 214, 0, 217, 0, 70, 71, 0, 222, 241, + 267, 554, 338, 466, 409, 469, 518, 154, 522, 523, + 525, 527, 528, 530, 471, 470, 472, 0, 0, 478, + 0, 0, 475, 0, 0, 481, 0, 0, 0, 0, + 0, 537, 0, 0, 0, 34, 0, 588, -2, 0, + 0, 0, 46, 0, 566, 592, 593, 357, 0, 362, + 0, 0, 0, 365, 38, 168, 0, 187, 0, 349, + 160, 153, 0, 157, 133, 157, 0, 0, 64, 0, + 73, 74, 0, 0, 556, 0, 519, 520, 0, 0, + 0, 0, 0, 0, 0, 0, 511, 485, 534, 0, + 0, 0, 586, 0, -2, 0, 581, 580, 352, 37, + 0, 0, 0, 0, 384, 167, 169, 0, 174, 0, + 186, 0, 0, 165, 0, 162, 164, 151, 122, 123, + 137, 140, 0, 0, 0, 0, 28, 0, 0, 473, + 474, 479, 480, 476, 477, 482, 483, 0, 0, 0, + 502, 503, 0, 576, 29, 0, 358, 385, 386, 387, + 348, 170, 171, 0, 175, 173, 0, 350, 85, 0, + 161, 163, 0, 235, 0, 75, 76, 69, 557, 555, + 484, 0, 0, 0, 584, -2, 582, 172, 0, 166, + 234, 0, 0, 72, 512, 0, 515, 0, 236, 0, + 221, 513, 0, 0, 0, 190, 0, 0, 191, 192, + 0, 0, 514, 193, 0, 0, 0, 0, 0, 194, + 196, 197, 0, 0, 195, 237, 238, 198, 199, 200, } var yyTok1 = [...]int{ @@ -3029,35 +3037,35 @@ yydefault: case 1: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:314 +//line sql.y:316 { setParseTree(yylex, yyDollar[1].statement) } case 2: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:319 +//line sql.y:321 { } case 3: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:320 +//line sql.y:322 { } case 4: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:324 +//line sql.y:326 { yyVAL.statement = yyDollar[1].selStmt } case 23: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:346 +//line sql.y:348 { setParseTree(yylex, nil) } case 24: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:352 +//line sql.y:354 { sel := yyDollar[1].selStmt.(*Select) sel.OrderBy = yyDollar[2].orderBy @@ -3067,55 +3075,55 @@ yydefault: } case 25: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:360 +//line sql.y:362 { yyVAL.selStmt = &Union{Type: yyDollar[2].str, Left: yyDollar[1].selStmt, Right: yyDollar[3].selStmt, OrderBy: yyDollar[4].orderBy, Limit: yyDollar[5].limit, Lock: yyDollar[6].str} } case 26: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:364 +//line sql.y:366 { yyVAL.selStmt = &Select{Comments: Comments(yyDollar[2].bytes2), Cache: yyDollar[3].str, SelectExprs: SelectExprs{Nextval{Expr: yyDollar[5].expr}}, From: TableExprs{&AliasedTableExpr{Expr: yyDollar[7].tableName}}} } case 27: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:370 +//line sql.y:372 { yyVAL.statement = &Stream{Comments: Comments(yyDollar[2].bytes2), SelectExpr: yyDollar[3].selectExpr, Table: yyDollar[5].tableName} } case 28: yyDollar = yyS[yypt-10 : yypt+1] -//line sql.y:377 +//line sql.y:379 { yyVAL.selStmt = &Select{Comments: Comments(yyDollar[2].bytes2), Cache: yyDollar[3].str, Distinct: yyDollar[4].str, Hints: yyDollar[5].str, SelectExprs: yyDollar[6].selectExprs, From: yyDollar[7].tableExprs, Where: NewWhere(WhereStr, yyDollar[8].expr), GroupBy: GroupBy(yyDollar[9].exprs), Having: NewWhere(HavingStr, yyDollar[10].expr)} } case 29: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:383 +//line sql.y:385 { yyVAL.selStmt = yyDollar[1].selStmt } case 30: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:387 +//line sql.y:389 { yyVAL.selStmt = &ParenSelect{Select: yyDollar[2].selStmt} } case 31: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:393 +//line sql.y:395 { yyVAL.selStmt = yyDollar[1].selStmt } case 32: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:397 +//line sql.y:399 { yyVAL.selStmt = &ParenSelect{Select: yyDollar[2].selStmt} } case 33: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:404 +//line sql.y:406 { // insert_data returns a *Insert pre-filled with Columns & Values ins := yyDollar[6].ins @@ -3129,7 +3137,7 @@ yydefault: } case 34: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:416 +//line sql.y:418 { cols := make(Columns, 0, len(yyDollar[7].updateExprs)) vals := make(ValTuple, 0, len(yyDollar[8].updateExprs)) @@ -3141,174 +3149,174 @@ yydefault: } case 35: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:428 +//line sql.y:430 { yyVAL.str = InsertStr } case 36: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:432 +//line sql.y:434 { yyVAL.str = ReplaceStr } case 37: yyDollar = yyS[yypt-9 : yypt+1] -//line sql.y:438 +//line sql.y:440 { yyVAL.statement = &Update{Comments: Comments(yyDollar[2].bytes2), Ignore: yyDollar[3].str, TableExprs: yyDollar[4].tableExprs, Exprs: yyDollar[6].updateExprs, Where: NewWhere(WhereStr, yyDollar[7].expr), OrderBy: yyDollar[8].orderBy, Limit: yyDollar[9].limit} } case 38: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:444 +//line sql.y:446 { yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), TableExprs: TableExprs{&AliasedTableExpr{Expr: yyDollar[4].tableName}}, Partitions: yyDollar[5].partitions, Where: NewWhere(WhereStr, yyDollar[6].expr), OrderBy: yyDollar[7].orderBy, Limit: yyDollar[8].limit} } case 39: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:448 +//line sql.y:450 { yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), Targets: yyDollar[4].tableNames, TableExprs: yyDollar[6].tableExprs, Where: NewWhere(WhereStr, yyDollar[7].expr)} } case 40: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:452 +//line sql.y:454 { yyVAL.statement = &Delete{Comments: Comments(yyDollar[2].bytes2), Targets: yyDollar[3].tableNames, TableExprs: yyDollar[5].tableExprs, Where: NewWhere(WhereStr, yyDollar[6].expr)} } case 41: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:457 +//line sql.y:459 { } case 42: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:458 +//line sql.y:460 { } case 43: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:462 +//line sql.y:464 { yyVAL.tableNames = TableNames{yyDollar[1].tableName} } case 44: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:466 +//line sql.y:468 { yyVAL.tableNames = append(yyVAL.tableNames, yyDollar[3].tableName) } case 45: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:471 +//line sql.y:473 { yyVAL.partitions = nil } case 46: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:475 +//line sql.y:477 { yyVAL.partitions = yyDollar[3].partitions } case 47: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:481 +//line sql.y:483 { yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Exprs: yyDollar[3].setExprs} } case 48: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:485 +//line sql.y:487 { yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Scope: yyDollar[3].str, Exprs: yyDollar[4].setExprs} } case 49: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:489 +//line sql.y:491 { yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Scope: yyDollar[3].str, Exprs: yyDollar[5].setExprs} } case 50: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:493 +//line sql.y:495 { yyVAL.statement = &Set{Comments: Comments(yyDollar[2].bytes2), Exprs: yyDollar[4].setExprs} } case 51: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:499 +//line sql.y:501 { yyVAL.setExprs = SetExprs{yyDollar[1].setExpr} } case 52: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:503 +//line sql.y:505 { yyVAL.setExprs = append(yyVAL.setExprs, yyDollar[3].setExpr) } case 53: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:509 +//line sql.y:511 { yyVAL.setExpr = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte(yyDollar[3].str))} } case 54: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:513 +//line sql.y:515 { yyVAL.setExpr = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte(TxReadWrite))} } case 55: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:517 +//line sql.y:519 { yyVAL.setExpr = &SetExpr{Name: NewColIdent(TransactionStr), Expr: NewStrVal([]byte(TxReadOnly))} } case 56: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:523 +//line sql.y:525 { yyVAL.str = IsolationLevelRepeatableRead } case 57: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:527 +//line sql.y:529 { yyVAL.str = IsolationLevelReadCommitted } case 58: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:531 +//line sql.y:533 { yyVAL.str = IsolationLevelReadUncommitted } case 59: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:535 +//line sql.y:537 { yyVAL.str = IsolationLevelSerializable } case 60: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:541 +//line sql.y:543 { yyVAL.str = SessionStr } case 61: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:545 +//line sql.y:547 { yyVAL.str = GlobalStr } case 62: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:551 +//line sql.y:553 { yyDollar[1].ddl.TableSpec = yyDollar[2].TableSpec yyVAL.statement = yyDollar[1].ddl } case 63: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:556 +//line sql.y:558 { // Create table [name] like [name] yyDollar[1].ddl.OptLike = yyDollar[2].optLike @@ -3316,151 +3324,151 @@ yydefault: } case 64: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:562 +//line sql.y:564 { // Change this to an alter statement yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[7].tableName} } case 65: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:567 +//line sql.y:569 { yyVAL.statement = &DDL{Action: CreateStr, Table: yyDollar[3].tableName.ToViewName()} } case 66: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:571 +//line sql.y:573 { yyVAL.statement = &DDL{Action: CreateStr, Table: yyDollar[5].tableName.ToViewName()} } case 67: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:575 +//line sql.y:577 { yyVAL.statement = &DBDDL{Action: CreateStr, DBName: string(yyDollar[4].bytes)} } case 68: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:579 +//line sql.y:581 { yyVAL.statement = &DBDDL{Action: CreateStr, DBName: string(yyDollar[4].bytes)} } case 69: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:584 +//line sql.y:586 { yyVAL.colIdent = NewColIdent("") } case 70: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:588 +//line sql.y:590 { yyVAL.colIdent = yyDollar[2].colIdent } case 71: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:594 +//line sql.y:596 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } case 72: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:599 +//line sql.y:601 { var v []VindexParam yyVAL.vindexParams = v } case 73: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:604 +//line sql.y:606 { yyVAL.vindexParams = yyDollar[2].vindexParams } case 74: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:610 +//line sql.y:612 { yyVAL.vindexParams = make([]VindexParam, 0, 4) yyVAL.vindexParams = append(yyVAL.vindexParams, yyDollar[1].vindexParam) } case 75: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:615 +//line sql.y:617 { yyVAL.vindexParams = append(yyVAL.vindexParams, yyDollar[3].vindexParam) } case 76: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:621 +//line sql.y:623 { yyVAL.vindexParam = VindexParam{Key: yyDollar[1].colIdent, Val: yyDollar[3].str} } case 77: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:627 +//line sql.y:629 { yyVAL.ddl = &DDL{Action: CreateStr, Table: yyDollar[4].tableName} setDDL(yylex, yyVAL.ddl) } case 78: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:634 +//line sql.y:636 { yyVAL.TableSpec = yyDollar[2].TableSpec yyVAL.TableSpec.Options = yyDollar[4].str } case 79: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:641 +//line sql.y:643 { yyVAL.optLike = &OptLike{LikeTable: yyDollar[2].tableName} } case 80: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:645 +//line sql.y:647 { yyVAL.optLike = &OptLike{LikeTable: yyDollar[3].tableName} } case 81: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:651 +//line sql.y:653 { yyVAL.TableSpec = &TableSpec{} yyVAL.TableSpec.AddColumn(yyDollar[1].columnDefinition) } case 82: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:656 +//line sql.y:658 { yyVAL.TableSpec.AddColumn(yyDollar[3].columnDefinition) } case 83: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:660 +//line sql.y:662 { yyVAL.TableSpec.AddIndex(yyDollar[3].indexDefinition) } case 84: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:664 +//line sql.y:666 { yyVAL.TableSpec.AddConstraint(yyDollar[3].constraintDefinition) } case 85: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:670 +//line sql.y:672 { yyDollar[2].columnType.NotNull = yyDollar[3].boolVal yyDollar[2].columnType.Default = yyDollar[4].optVal yyDollar[2].columnType.OnUpdate = yyDollar[5].optVal yyDollar[2].columnType.Autoincrement = yyDollar[6].boolVal yyDollar[2].columnType.KeyOpt = yyDollar[7].colKeyOpt - yyDollar[2].columnType.Comment = yyDollar[8].optVal + yyDollar[2].columnType.Comment = yyDollar[8].sqlVal yyVAL.columnDefinition = &ColumnDefinition{Name: NewColIdent(string(yyDollar[1].bytes)), Type: yyDollar[2].columnType} } case 86: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:681 +//line sql.y:683 { yyVAL.columnType = yyDollar[1].columnType yyVAL.columnType.Unsigned = yyDollar[2].boolVal @@ -3468,62 +3476,62 @@ yydefault: } case 90: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:692 +//line sql.y:694 { yyVAL.columnType = yyDollar[1].columnType - yyVAL.columnType.Length = yyDollar[2].optVal + yyVAL.columnType.Length = yyDollar[2].sqlVal } case 91: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:697 +//line sql.y:699 { yyVAL.columnType = yyDollar[1].columnType } case 92: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:703 +//line sql.y:705 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 93: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:707 +//line sql.y:709 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 94: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:711 +//line sql.y:713 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 95: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:715 +//line sql.y:717 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 96: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:719 +//line sql.y:721 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 97: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:723 +//line sql.y:725 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 98: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:727 +//line sql.y:729 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 99: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:733 +//line sql.y:735 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3531,7 +3539,7 @@ yydefault: } case 100: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:739 +//line sql.y:741 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3539,7 +3547,7 @@ yydefault: } case 101: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:745 +//line sql.y:747 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3547,7 +3555,7 @@ yydefault: } case 102: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:751 +//line sql.y:753 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3555,7 +3563,7 @@ yydefault: } case 103: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:757 +//line sql.y:759 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3563,206 +3571,206 @@ yydefault: } case 104: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:765 +//line sql.y:767 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 105: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:769 +//line sql.y:771 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 106: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:773 +//line sql.y:775 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 107: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:777 +//line sql.y:779 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 108: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:781 +//line sql.y:783 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 109: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:787 +//line sql.y:789 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} } case 110: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:791 +//line sql.y:793 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} } case 111: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:795 +//line sql.y:797 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 112: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:799 +//line sql.y:801 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 113: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:803 +//line sql.y:805 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 114: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:807 +//line sql.y:809 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 115: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:811 +//line sql.y:813 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 116: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:815 +//line sql.y:817 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 117: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:819 +//line sql.y:821 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 118: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:823 +//line sql.y:825 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 119: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:827 +//line sql.y:829 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 120: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:831 +//line sql.y:833 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 121: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:835 +//line sql.y:837 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 122: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:839 +//line sql.y:841 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} } case 123: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:844 +//line sql.y:846 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} } case 124: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:850 +//line sql.y:852 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 125: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:854 +//line sql.y:856 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 126: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:858 +//line sql.y:860 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 127: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:862 +//line sql.y:864 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 128: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:866 +//line sql.y:868 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 129: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:870 +//line sql.y:872 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 130: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:874 +//line sql.y:876 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 131: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:878 +//line sql.y:880 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 132: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:884 +//line sql.y:886 { yyVAL.strs = make([]string, 0, 4) yyVAL.strs = append(yyVAL.strs, "'"+string(yyDollar[1].bytes)+"'") } case 133: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:889 +//line sql.y:891 { yyVAL.strs = append(yyDollar[1].strs, "'"+string(yyDollar[3].bytes)+"'") } case 134: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:894 +//line sql.y:896 { - yyVAL.optVal = nil + yyVAL.sqlVal = nil } case 135: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:898 +//line sql.y:900 { - yyVAL.optVal = NewIntVal(yyDollar[2].bytes) + yyVAL.sqlVal = NewIntVal(yyDollar[2].bytes) } case 136: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:903 +//line sql.y:905 { yyVAL.LengthScaleOption = LengthScaleOption{} } case 137: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:907 +//line sql.y:909 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), @@ -3771,13 +3779,13 @@ yydefault: } case 138: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:915 +//line sql.y:917 { yyVAL.LengthScaleOption = LengthScaleOption{} } case 139: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:919 +//line sql.y:921 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), @@ -3785,7 +3793,7 @@ yydefault: } case 140: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:925 +//line sql.y:927 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), @@ -3794,508 +3802,466 @@ yydefault: } case 141: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:933 +//line sql.y:935 { yyVAL.boolVal = BoolVal(false) } case 142: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:937 +//line sql.y:939 { yyVAL.boolVal = BoolVal(true) } case 143: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:942 +//line sql.y:944 { yyVAL.boolVal = BoolVal(false) } case 144: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:946 +//line sql.y:948 { yyVAL.boolVal = BoolVal(true) } case 145: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:952 +//line sql.y:954 { yyVAL.boolVal = BoolVal(false) } case 146: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:956 +//line sql.y:958 { yyVAL.boolVal = BoolVal(false) } case 147: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:960 +//line sql.y:962 { yyVAL.boolVal = BoolVal(true) } case 148: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:965 +//line sql.y:967 { yyVAL.optVal = nil } case 149: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:969 +//line sql.y:971 { - yyVAL.optVal = NewStrVal(yyDollar[2].bytes) + yyVAL.optVal = yyDollar[2].expr } case 150: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:973 - { - yyVAL.optVal = NewIntVal(yyDollar[2].bytes) - } - case 151: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:977 - { - yyVAL.optVal = NewFloatVal(yyDollar[2].bytes) - } - case 152: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:981 - { - yyVAL.optVal = NewValArg(yyDollar[2].bytes) - } - case 153: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:985 - { - yyVAL.optVal = NewValArg(yyDollar[2].bytes) - } - case 154: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:989 - { - yyVAL.optVal = NewValArg(yyDollar[2].bytes) - } - case 155: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:993 - { - yyVAL.optVal = NewBitVal(yyDollar[2].bytes) - } - case 156: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:998 +//line sql.y:976 { yyVAL.optVal = nil } - case 157: + case 151: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1002 - { - yyVAL.optVal = NewValArg(yyDollar[3].bytes) - } - case 158: - yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1006 +//line sql.y:980 { - yyVAL.optVal = NewValArg(yyDollar[3].bytes) + yyVAL.optVal = yyDollar[3].expr } - case 159: + case 152: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1011 +//line sql.y:985 { yyVAL.boolVal = BoolVal(false) } - case 160: + case 153: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1015 +//line sql.y:989 { yyVAL.boolVal = BoolVal(true) } - case 161: + case 154: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1020 +//line sql.y:994 { yyVAL.str = "" } - case 162: + case 155: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1024 +//line sql.y:998 { yyVAL.str = string(yyDollar[3].bytes) } - case 163: + case 156: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1028 +//line sql.y:1002 { yyVAL.str = string(yyDollar[3].bytes) } - case 164: + case 157: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1033 +//line sql.y:1007 { yyVAL.str = "" } - case 165: + case 158: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1037 +//line sql.y:1011 { yyVAL.str = string(yyDollar[2].bytes) } - case 166: + case 159: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1041 +//line sql.y:1015 { yyVAL.str = string(yyDollar[2].bytes) } - case 167: + case 160: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1046 +//line sql.y:1020 { yyVAL.colKeyOpt = colKeyNone } - case 168: + case 161: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1050 +//line sql.y:1024 { yyVAL.colKeyOpt = colKeyPrimary } - case 169: + case 162: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1054 +//line sql.y:1028 { yyVAL.colKeyOpt = colKey } - case 170: + case 163: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1058 +//line sql.y:1032 { yyVAL.colKeyOpt = colKeyUniqueKey } - case 171: + case 164: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1062 +//line sql.y:1036 { yyVAL.colKeyOpt = colKeyUnique } - case 172: + case 165: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1067 +//line sql.y:1041 { - yyVAL.optVal = nil + yyVAL.sqlVal = nil } - case 173: + case 166: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1071 +//line sql.y:1045 { - yyVAL.optVal = NewStrVal(yyDollar[2].bytes) + yyVAL.sqlVal = NewStrVal(yyDollar[2].bytes) } - case 174: + case 167: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1077 +//line sql.y:1051 { yyVAL.indexDefinition = &IndexDefinition{Info: yyDollar[1].indexInfo, Columns: yyDollar[3].indexColumns, Options: yyDollar[5].indexOptions} } - case 175: + case 168: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1081 +//line sql.y:1055 { yyVAL.indexDefinition = &IndexDefinition{Info: yyDollar[1].indexInfo, Columns: yyDollar[3].indexColumns} } - case 176: + case 169: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1087 +//line sql.y:1061 { yyVAL.indexOptions = []*IndexOption{yyDollar[1].indexOption} } - case 177: + case 170: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1091 +//line sql.y:1065 { yyVAL.indexOptions = append(yyVAL.indexOptions, yyDollar[2].indexOption) } - case 178: + case 171: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1097 +//line sql.y:1071 { yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Using: string(yyDollar[2].bytes)} } - case 179: + case 172: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1101 +//line sql.y:1075 { // should not be string yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Value: NewIntVal(yyDollar[3].bytes)} } - case 180: + case 173: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1106 +//line sql.y:1080 { yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Value: NewStrVal(yyDollar[2].bytes)} } - case 181: + case 174: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1112 +//line sql.y:1086 { yyVAL.str = "" } - case 182: + case 175: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1116 +//line sql.y:1090 { yyVAL.str = string(yyDollar[1].bytes) } - case 183: + case 176: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1122 +//line sql.y:1096 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].bytes), Name: NewColIdent("PRIMARY"), Primary: true, Unique: true} } - case 184: + case 177: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1126 +//line sql.y:1100 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(yyDollar[3].str), Spatial: true, Unique: false} } - case 185: + case 178: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1130 +//line sql.y:1104 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(yyDollar[3].str), Unique: true} } - case 186: + case 179: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1134 +//line sql.y:1108 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes), Name: NewColIdent(yyDollar[2].str), Unique: true} } - case 187: + case 180: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1138 +//line sql.y:1112 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].str), Name: NewColIdent(yyDollar[2].str), Unique: false} } - case 188: + case 181: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1144 +//line sql.y:1118 { yyVAL.str = string(yyDollar[1].bytes) } - case 189: + case 182: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1148 +//line sql.y:1122 { yyVAL.str = string(yyDollar[1].bytes) } - case 190: + case 183: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1153 +//line sql.y:1127 { yyVAL.str = "" } - case 191: + case 184: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1157 +//line sql.y:1131 { yyVAL.str = string(yyDollar[1].bytes) } - case 192: + case 185: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1163 +//line sql.y:1137 { yyVAL.indexColumns = []*IndexColumn{yyDollar[1].indexColumn} } - case 193: + case 186: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1167 +//line sql.y:1141 { yyVAL.indexColumns = append(yyVAL.indexColumns, yyDollar[3].indexColumn) } - case 194: + case 187: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1173 +//line sql.y:1147 { - yyVAL.indexColumn = &IndexColumn{Column: yyDollar[1].colIdent, Length: yyDollar[2].optVal} + yyVAL.indexColumn = &IndexColumn{Column: yyDollar[1].colIdent, Length: yyDollar[2].sqlVal} } - case 195: + case 188: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1179 +//line sql.y:1153 { yyVAL.constraintDefinition = &ConstraintDefinition{Name: string(yyDollar[2].bytes), Details: yyDollar[3].constraintInfo} } - case 196: + case 189: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1183 +//line sql.y:1157 { yyVAL.constraintDefinition = &ConstraintDefinition{Details: yyDollar[1].constraintInfo} } - case 197: + case 190: yyDollar = yyS[yypt-10 : yypt+1] -//line sql.y:1190 +//line sql.y:1164 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns} } - case 198: + case 191: yyDollar = yyS[yypt-11 : yypt+1] -//line sql.y:1194 +//line sql.y:1168 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnDelete: yyDollar[11].ReferenceAction} } - case 199: + case 192: yyDollar = yyS[yypt-11 : yypt+1] -//line sql.y:1198 +//line sql.y:1172 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnUpdate: yyDollar[11].ReferenceAction} } - case 200: + case 193: yyDollar = yyS[yypt-12 : yypt+1] -//line sql.y:1202 +//line sql.y:1176 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnDelete: yyDollar[11].ReferenceAction, OnUpdate: yyDollar[12].ReferenceAction} } - case 201: + case 194: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1208 +//line sql.y:1182 { yyVAL.ReferenceAction = yyDollar[3].ReferenceAction } - case 202: + case 195: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1214 +//line sql.y:1188 { yyVAL.ReferenceAction = yyDollar[3].ReferenceAction } - case 203: + case 196: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1220 +//line sql.y:1194 { yyVAL.ReferenceAction = Restrict } - case 204: + case 197: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1224 +//line sql.y:1198 { yyVAL.ReferenceAction = Cascade } - case 205: + case 198: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1228 +//line sql.y:1202 { yyVAL.ReferenceAction = NoAction } - case 206: + case 199: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1232 +//line sql.y:1206 { yyVAL.ReferenceAction = SetDefault } - case 207: + case 200: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1236 +//line sql.y:1210 { yyVAL.ReferenceAction = SetNull } - case 208: + case 201: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1241 +//line sql.y:1215 { yyVAL.str = "" } - case 209: + case 202: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1245 +//line sql.y:1219 { yyVAL.str = " " + string(yyDollar[1].str) } - case 210: + case 203: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1249 +//line sql.y:1223 { yyVAL.str = string(yyDollar[1].str) + ", " + string(yyDollar[3].str) } - case 211: + case 204: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1257 +//line sql.y:1231 { yyVAL.str = yyDollar[1].str } - case 212: + case 205: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1261 +//line sql.y:1235 { yyVAL.str = yyDollar[1].str + " " + yyDollar[2].str } - case 213: + case 206: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1265 +//line sql.y:1239 { yyVAL.str = yyDollar[1].str + "=" + yyDollar[3].str } - case 214: + case 207: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1271 +//line sql.y:1245 { yyVAL.str = yyDollar[1].colIdent.String() } - case 215: + case 208: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1275 +//line sql.y:1249 { yyVAL.str = "'" + string(yyDollar[1].bytes) + "'" } - case 216: + case 209: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1279 +//line sql.y:1253 { yyVAL.str = string(yyDollar[1].bytes) } - case 217: + case 210: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:1285 +//line sql.y:1259 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName} } - case 218: + case 211: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1289 +//line sql.y:1263 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName} } - case 219: + case 212: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1293 +//line sql.y:1267 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName} } - case 220: + case 213: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1297 +//line sql.y:1271 { // Change this to a rename statement yyVAL.statement = &DDL{Action: RenameStr, FromTables: TableNames{yyDollar[4].tableName}, ToTables: TableNames{yyDollar[7].tableName}} } - case 221: + case 214: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1302 +//line sql.y:1276 { // Rename an index can just be an alter yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName} } - case 222: + case 215: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1307 +//line sql.y:1281 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[3].tableName.ToViewName()} } - case 223: + case 216: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1311 +//line sql.y:1285 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, PartitionSpec: yyDollar[5].partSpec} } - case 224: + case 217: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1315 +//line sql.y:1289 { yyVAL.statement = &DDL{Action: CreateVindexStr, VindexSpec: &VindexSpec{ Name: yyDollar[5].colIdent, @@ -4303,29 +4269,29 @@ yydefault: Params: yyDollar[7].vindexParams, }} } - case 225: + case 218: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1323 +//line sql.y:1297 { yyVAL.statement = &DDL{Action: DropVindexStr, VindexSpec: &VindexSpec{ Name: yyDollar[5].colIdent, }} } - case 226: + case 219: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1329 +//line sql.y:1303 { yyVAL.statement = &DDL{Action: AddVschemaTableStr, Table: yyDollar[5].tableName} } - case 227: + case 220: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1333 +//line sql.y:1307 { yyVAL.statement = &DDL{Action: DropVschemaTableStr, Table: yyDollar[5].tableName} } - case 228: + case 221: yyDollar = yyS[yypt-12 : yypt+1] -//line sql.y:1337 +//line sql.y:1311 { yyVAL.statement = &DDL{ Action: AddColVindexStr, @@ -4338,9 +4304,9 @@ yydefault: VindexCols: yyDollar[9].columns, } } - case 229: + case 222: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1350 +//line sql.y:1324 { yyVAL.statement = &DDL{ Action: DropColVindexStr, @@ -4350,59 +4316,59 @@ yydefault: }, } } - case 241: + case 234: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1375 +//line sql.y:1349 { yyVAL.partSpec = &PartitionSpec{Action: ReorganizeStr, Name: yyDollar[3].colIdent, Definitions: yyDollar[6].partDefs} } - case 242: + case 235: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1381 +//line sql.y:1355 { yyVAL.partDefs = []*PartitionDefinition{yyDollar[1].partDef} } - case 243: + case 236: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1385 +//line sql.y:1359 { yyVAL.partDefs = append(yyDollar[1].partDefs, yyDollar[3].partDef) } - case 244: + case 237: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:1391 +//line sql.y:1365 { yyVAL.partDef = &PartitionDefinition{Name: yyDollar[2].colIdent, Limit: yyDollar[7].expr} } - case 245: + case 238: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:1395 +//line sql.y:1369 { yyVAL.partDef = &PartitionDefinition{Name: yyDollar[2].colIdent, Maxvalue: true} } - case 246: + case 239: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1401 +//line sql.y:1375 { yyVAL.statement = yyDollar[3].ddl } - case 247: + case 240: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1407 +//line sql.y:1381 { yyVAL.ddl = &DDL{Action: RenameStr, FromTables: TableNames{yyDollar[1].tableName}, ToTables: TableNames{yyDollar[3].tableName}} } - case 248: + case 241: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1411 +//line sql.y:1385 { yyVAL.ddl = yyDollar[1].ddl yyVAL.ddl.FromTables = append(yyVAL.ddl.FromTables, yyDollar[3].tableName) yyVAL.ddl.ToTables = append(yyVAL.ddl.ToTables, yyDollar[5].tableName) } - case 249: + case 242: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1419 +//line sql.y:1393 { var exists bool if yyDollar[3].byt != 0 { @@ -4410,16 +4376,16 @@ yydefault: } yyVAL.statement = &DDL{Action: DropStr, FromTables: yyDollar[4].tableNames, IfExists: exists} } - case 250: + case 243: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:1427 +//line sql.y:1401 { // Change this to an alter statement yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[5].tableName} } - case 251: + case 244: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1432 +//line sql.y:1406 { var exists bool if yyDollar[3].byt != 0 { @@ -4427,148 +4393,148 @@ yydefault: } yyVAL.statement = &DDL{Action: DropStr, FromTables: TableNames{yyDollar[4].tableName.ToViewName()}, IfExists: exists} } - case 252: + case 245: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1440 +//line sql.y:1414 { yyVAL.statement = &DBDDL{Action: DropStr, DBName: string(yyDollar[4].bytes)} } - case 253: + case 246: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1444 +//line sql.y:1418 { yyVAL.statement = &DBDDL{Action: DropStr, DBName: string(yyDollar[4].bytes)} } - case 254: + case 247: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1450 +//line sql.y:1424 { yyVAL.statement = &DDL{Action: TruncateStr, Table: yyDollar[3].tableName} } - case 255: + case 248: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1454 +//line sql.y:1428 { yyVAL.statement = &DDL{Action: TruncateStr, Table: yyDollar[2].tableName} } - case 256: + case 249: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1459 +//line sql.y:1433 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[3].tableName} } - case 257: + case 250: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1465 +//line sql.y:1439 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 258: + case 251: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1470 +//line sql.y:1444 { yyVAL.statement = &Show{Type: CharsetStr} } - case 259: + case 252: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1474 +//line sql.y:1448 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 260: + case 253: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1478 +//line sql.y:1452 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 261: + case 254: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1483 +//line sql.y:1457 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 262: + case 255: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1487 +//line sql.y:1461 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 263: + case 256: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1491 +//line sql.y:1465 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 264: + case 257: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1495 +//line sql.y:1469 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 265: + case 258: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1499 +//line sql.y:1473 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 266: + case 259: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1503 +//line sql.y:1477 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 267: + case 260: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1507 +//line sql.y:1481 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 268: + case 261: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1511 +//line sql.y:1485 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 269: + case 262: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1515 +//line sql.y:1489 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 270: + case 263: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1519 +//line sql.y:1493 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 271: + case 264: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1523 +//line sql.y:1497 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 272: + case 265: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1527 +//line sql.y:1501 { yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} } - case 273: + case 266: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1531 +//line sql.y:1505 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 274: + case 267: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1535 +//line sql.y:1509 { showTablesOpt := &ShowTablesOpt{Full: yyDollar[2].str, DbName: yyDollar[6].str, Filter: yyDollar[7].showFilter} yyVAL.statement = &Show{Type: string(yyDollar[3].str), ShowTablesOpt: showTablesOpt, OnTable: yyDollar[5].tableName} } - case 275: + case 268: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1540 +//line sql.y:1514 { // this is ugly, but I couldn't find a better way for now if yyDollar[3].str == "processlist" { @@ -4578,650 +4544,650 @@ yydefault: yyVAL.statement = &Show{Type: yyDollar[3].str, ShowTablesOpt: showTablesOpt} } } - case 276: + case 269: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1550 +//line sql.y:1524 { yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} } - case 277: + case 270: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1554 +//line sql.y:1528 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 278: + case 271: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1558 +//line sql.y:1532 { // Cannot dereference $4 directly, or else the parser stackcannot be pooled. See yyParsePooled showCollationFilterOpt := yyDollar[4].expr yyVAL.statement = &Show{Type: string(yyDollar[2].bytes), ShowCollationFilterOpt: &showCollationFilterOpt} } - case 279: + case 272: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1564 +//line sql.y:1538 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 280: + case 273: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1568 +//line sql.y:1542 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 281: + case 274: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1572 +//line sql.y:1546 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 282: + case 275: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1576 +//line sql.y:1550 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 283: + case 276: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1580 +//line sql.y:1554 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 284: + case 277: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1584 +//line sql.y:1558 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 285: + case 278: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1588 +//line sql.y:1562 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes), OnTable: yyDollar[5].tableName} } - case 286: + case 279: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1592 +//line sql.y:1566 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 287: + case 280: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1602 +//line sql.y:1576 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 288: + case 281: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1608 +//line sql.y:1582 { yyVAL.str = string(yyDollar[1].bytes) } - case 289: + case 282: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1612 +//line sql.y:1586 { yyVAL.str = string(yyDollar[1].bytes) } - case 290: + case 283: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1618 +//line sql.y:1592 { yyVAL.str = "" } - case 291: + case 284: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1622 +//line sql.y:1596 { yyVAL.str = "full " } - case 292: + case 285: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1628 +//line sql.y:1602 { yyVAL.str = string(yyDollar[1].bytes) } - case 293: + case 286: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1632 +//line sql.y:1606 { yyVAL.str = string(yyDollar[1].bytes) } - case 294: + case 287: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1638 +//line sql.y:1612 { yyVAL.str = "" } - case 295: + case 288: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1642 +//line sql.y:1616 { yyVAL.str = yyDollar[2].tableIdent.v } - case 296: + case 289: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1646 +//line sql.y:1620 { yyVAL.str = yyDollar[2].tableIdent.v } - case 297: + case 290: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1652 +//line sql.y:1626 { yyVAL.showFilter = nil } - case 298: + case 291: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1656 +//line sql.y:1630 { yyVAL.showFilter = &ShowFilter{Like: string(yyDollar[2].bytes)} } - case 299: + case 292: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1660 +//line sql.y:1634 { yyVAL.showFilter = &ShowFilter{Filter: yyDollar[2].expr} } - case 300: + case 293: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1666 +//line sql.y:1640 { yyVAL.str = "" } - case 301: + case 294: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1670 +//line sql.y:1644 { yyVAL.str = SessionStr } - case 302: + case 295: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1674 +//line sql.y:1648 { yyVAL.str = GlobalStr } - case 303: + case 296: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1680 +//line sql.y:1654 { yyVAL.statement = &Use{DBName: yyDollar[2].tableIdent} } - case 304: + case 297: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1684 +//line sql.y:1658 { yyVAL.statement = &Use{DBName: TableIdent{v: ""}} } - case 305: + case 298: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1690 +//line sql.y:1664 { yyVAL.statement = &Begin{} } - case 306: + case 299: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1694 +//line sql.y:1668 { yyVAL.statement = &Begin{} } - case 307: + case 300: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1700 +//line sql.y:1674 { yyVAL.statement = &Commit{} } - case 308: + case 301: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1706 +//line sql.y:1680 { yyVAL.statement = &Rollback{} } - case 309: + case 302: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1712 +//line sql.y:1686 { yyVAL.statement = &OtherRead{} } - case 310: + case 303: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1716 +//line sql.y:1690 { yyVAL.statement = &OtherRead{} } - case 311: + case 304: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1720 +//line sql.y:1694 { yyVAL.statement = &OtherRead{} } - case 312: + case 305: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1724 +//line sql.y:1698 { yyVAL.statement = &OtherAdmin{} } - case 313: + case 306: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1728 +//line sql.y:1702 { yyVAL.statement = &OtherAdmin{} } - case 314: + case 307: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1732 +//line sql.y:1706 { yyVAL.statement = &OtherAdmin{} } - case 315: + case 308: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1736 +//line sql.y:1710 { yyVAL.statement = &OtherAdmin{} } - case 316: + case 309: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1742 +//line sql.y:1716 { yyVAL.statement = &DDL{Action: FlushStr} } - case 317: + case 310: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1746 +//line sql.y:1720 { setAllowComments(yylex, true) } - case 318: + case 311: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1750 +//line sql.y:1724 { yyVAL.bytes2 = yyDollar[2].bytes2 setAllowComments(yylex, false) } - case 319: + case 312: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1756 +//line sql.y:1730 { yyVAL.bytes2 = nil } - case 320: + case 313: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1760 +//line sql.y:1734 { yyVAL.bytes2 = append(yyDollar[1].bytes2, yyDollar[2].bytes) } - case 321: + case 314: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1766 +//line sql.y:1740 { yyVAL.str = UnionStr } - case 322: + case 315: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1770 +//line sql.y:1744 { yyVAL.str = UnionAllStr } - case 323: + case 316: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1774 +//line sql.y:1748 { yyVAL.str = UnionDistinctStr } - case 324: + case 317: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1779 +//line sql.y:1753 { yyVAL.str = "" } - case 325: + case 318: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1783 +//line sql.y:1757 { yyVAL.str = SQLNoCacheStr } - case 326: + case 319: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1787 +//line sql.y:1761 { yyVAL.str = SQLCacheStr } - case 327: + case 320: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1792 +//line sql.y:1766 { yyVAL.str = "" } - case 328: + case 321: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1796 +//line sql.y:1770 { yyVAL.str = DistinctStr } - case 329: + case 322: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1801 +//line sql.y:1775 { yyVAL.str = "" } - case 330: + case 323: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1805 +//line sql.y:1779 { yyVAL.str = StraightJoinHint } - case 331: + case 324: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1810 +//line sql.y:1784 { yyVAL.selectExprs = nil } - case 332: + case 325: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1814 +//line sql.y:1788 { yyVAL.selectExprs = yyDollar[1].selectExprs } - case 333: + case 326: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1820 +//line sql.y:1794 { yyVAL.selectExprs = SelectExprs{yyDollar[1].selectExpr} } - case 334: + case 327: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1824 +//line sql.y:1798 { yyVAL.selectExprs = append(yyVAL.selectExprs, yyDollar[3].selectExpr) } - case 335: + case 328: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1830 +//line sql.y:1804 { yyVAL.selectExpr = &StarExpr{} } - case 336: + case 329: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1834 +//line sql.y:1808 { yyVAL.selectExpr = &AliasedExpr{Expr: yyDollar[1].expr, As: yyDollar[2].colIdent} } - case 337: + case 330: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1838 +//line sql.y:1812 { yyVAL.selectExpr = &StarExpr{TableName: TableName{Name: yyDollar[1].tableIdent}} } - case 338: + case 331: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1842 +//line sql.y:1816 { yyVAL.selectExpr = &StarExpr{TableName: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}} } - case 339: + case 332: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1847 +//line sql.y:1821 { yyVAL.colIdent = ColIdent{} } - case 340: + case 333: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1851 +//line sql.y:1825 { yyVAL.colIdent = yyDollar[1].colIdent } - case 341: + case 334: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1855 +//line sql.y:1829 { yyVAL.colIdent = yyDollar[2].colIdent } - case 343: + case 336: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1862 +//line sql.y:1836 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 344: + case 337: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1867 +//line sql.y:1841 { yyVAL.tableExprs = TableExprs{&AliasedTableExpr{Expr: TableName{Name: NewTableIdent("dual")}}} } - case 345: + case 338: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1871 +//line sql.y:1845 { yyVAL.tableExprs = yyDollar[2].tableExprs } - case 346: + case 339: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1877 +//line sql.y:1851 { yyVAL.tableExprs = TableExprs{yyDollar[1].tableExpr} } - case 347: + case 340: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1881 +//line sql.y:1855 { yyVAL.tableExprs = append(yyVAL.tableExprs, yyDollar[3].tableExpr) } - case 350: + case 343: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1891 +//line sql.y:1865 { yyVAL.tableExpr = yyDollar[1].aliasedTableName } - case 351: + case 344: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1895 +//line sql.y:1869 { yyVAL.tableExpr = &AliasedTableExpr{Expr: yyDollar[1].subquery, As: yyDollar[3].tableIdent} } - case 352: + case 345: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1899 +//line sql.y:1873 { // missed alias for subquery yylex.Error("Every derived table must have its own alias") return 1 } - case 353: + case 346: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1905 +//line sql.y:1879 { yyVAL.tableExpr = &ParenTableExpr{Exprs: yyDollar[2].tableExprs} } - case 354: + case 347: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1911 +//line sql.y:1885 { yyVAL.aliasedTableName = &AliasedTableExpr{Expr: yyDollar[1].tableName, As: yyDollar[2].tableIdent, Hints: yyDollar[3].indexHints} } - case 355: + case 348: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1915 +//line sql.y:1889 { yyVAL.aliasedTableName = &AliasedTableExpr{Expr: yyDollar[1].tableName, Partitions: yyDollar[4].partitions, As: yyDollar[6].tableIdent, Hints: yyDollar[7].indexHints} } - case 356: + case 349: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1921 +//line sql.y:1895 { yyVAL.columns = Columns{yyDollar[1].colIdent} } - case 357: + case 350: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1925 +//line sql.y:1899 { yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) } - case 358: + case 351: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1931 +//line sql.y:1905 { yyVAL.partitions = Partitions{yyDollar[1].colIdent} } - case 359: + case 352: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1935 +//line sql.y:1909 { yyVAL.partitions = append(yyVAL.partitions, yyDollar[3].colIdent) } - case 360: + case 353: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1948 +//line sql.y:1922 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 361: + case 354: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1952 +//line sql.y:1926 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 362: + case 355: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1956 +//line sql.y:1930 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 363: + case 356: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1960 +//line sql.y:1934 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr} } - case 364: + case 357: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1966 +//line sql.y:1940 { yyVAL.joinCondition = JoinCondition{On: yyDollar[2].expr} } - case 365: + case 358: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1968 +//line sql.y:1942 { yyVAL.joinCondition = JoinCondition{Using: yyDollar[3].columns} } - case 366: + case 359: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1972 +//line sql.y:1946 { yyVAL.joinCondition = JoinCondition{} } - case 367: + case 360: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1974 +//line sql.y:1948 { yyVAL.joinCondition = yyDollar[1].joinCondition } - case 368: + case 361: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1978 +//line sql.y:1952 { yyVAL.joinCondition = JoinCondition{} } - case 369: + case 362: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1980 +//line sql.y:1954 { yyVAL.joinCondition = JoinCondition{On: yyDollar[2].expr} } - case 370: + case 363: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1983 +//line sql.y:1957 { yyVAL.empty = struct{}{} } - case 371: + case 364: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1985 +//line sql.y:1959 { yyVAL.empty = struct{}{} } - case 372: + case 365: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1988 +//line sql.y:1962 { yyVAL.tableIdent = NewTableIdent("") } - case 373: + case 366: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1992 +//line sql.y:1966 { yyVAL.tableIdent = yyDollar[1].tableIdent } - case 374: + case 367: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1996 +//line sql.y:1970 { yyVAL.tableIdent = yyDollar[2].tableIdent } - case 376: + case 369: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2003 +//line sql.y:1977 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 377: + case 370: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2009 +//line sql.y:1983 { yyVAL.str = JoinStr } - case 378: + case 371: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2013 +//line sql.y:1987 { yyVAL.str = JoinStr } - case 379: + case 372: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2017 +//line sql.y:1991 { yyVAL.str = JoinStr } - case 380: + case 373: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2023 +//line sql.y:1997 { yyVAL.str = StraightJoinStr } - case 381: + case 374: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2029 +//line sql.y:2003 { yyVAL.str = LeftJoinStr } - case 382: + case 375: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2033 +//line sql.y:2007 { yyVAL.str = LeftJoinStr } - case 383: + case 376: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2037 +//line sql.y:2011 { yyVAL.str = RightJoinStr } - case 384: + case 377: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2041 +//line sql.y:2015 { yyVAL.str = RightJoinStr } - case 385: + case 378: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2047 +//line sql.y:2021 { yyVAL.str = NaturalJoinStr } - case 386: + case 379: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2051 +//line sql.y:2025 { if yyDollar[2].str == LeftJoinStr { yyVAL.str = NaturalLeftJoinStr @@ -5229,459 +5195,459 @@ yydefault: yyVAL.str = NaturalRightJoinStr } } - case 387: + case 380: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2061 +//line sql.y:2035 { yyVAL.tableName = yyDollar[2].tableName } - case 388: + case 381: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2065 +//line sql.y:2039 { yyVAL.tableName = yyDollar[1].tableName } - case 389: + case 382: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2071 +//line sql.y:2045 { yyVAL.tableName = TableName{Name: yyDollar[1].tableIdent} } - case 390: + case 383: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2075 +//line sql.y:2049 { yyVAL.tableName = TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent} } - case 391: + case 384: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2080 +//line sql.y:2054 { yyVAL.indexHints = nil } - case 392: + case 385: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2084 +//line sql.y:2058 { yyVAL.indexHints = &IndexHints{Type: UseStr, Indexes: yyDollar[4].columns} } - case 393: + case 386: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2088 +//line sql.y:2062 { yyVAL.indexHints = &IndexHints{Type: IgnoreStr, Indexes: yyDollar[4].columns} } - case 394: + case 387: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2092 +//line sql.y:2066 { yyVAL.indexHints = &IndexHints{Type: ForceStr, Indexes: yyDollar[4].columns} } - case 395: + case 388: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2097 +//line sql.y:2071 { yyVAL.expr = nil } - case 396: + case 389: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2101 +//line sql.y:2075 { yyVAL.expr = yyDollar[2].expr } - case 397: + case 390: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2107 +//line sql.y:2081 { yyVAL.expr = yyDollar[1].expr } - case 398: + case 391: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2111 +//line sql.y:2085 { yyVAL.expr = &AndExpr{Left: yyDollar[1].expr, Right: yyDollar[3].expr} } - case 399: + case 392: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2115 +//line sql.y:2089 { yyVAL.expr = &OrExpr{Left: yyDollar[1].expr, Right: yyDollar[3].expr} } - case 400: + case 393: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2119 +//line sql.y:2093 { yyVAL.expr = &NotExpr{Expr: yyDollar[2].expr} } - case 401: + case 394: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2123 +//line sql.y:2097 { yyVAL.expr = &IsExpr{Operator: yyDollar[3].str, Expr: yyDollar[1].expr} } - case 402: + case 395: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2127 +//line sql.y:2101 { yyVAL.expr = yyDollar[1].expr } - case 403: + case 396: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2131 +//line sql.y:2105 { yyVAL.expr = &Default{ColName: yyDollar[2].str} } - case 404: + case 397: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2137 +//line sql.y:2111 { yyVAL.str = "" } - case 405: + case 398: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2141 +//line sql.y:2115 { yyVAL.str = string(yyDollar[2].bytes) } - case 406: + case 399: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2147 +//line sql.y:2121 { yyVAL.boolVal = BoolVal(true) } - case 407: + case 400: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2151 +//line sql.y:2125 { yyVAL.boolVal = BoolVal(false) } - case 408: + case 401: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2157 +//line sql.y:2131 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: yyDollar[2].str, Right: yyDollar[3].expr} } - case 409: + case 402: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2161 +//line sql.y:2135 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: InStr, Right: yyDollar[3].colTuple} } - case 410: + case 403: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2165 +//line sql.y:2139 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotInStr, Right: yyDollar[4].colTuple} } - case 411: + case 404: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2169 +//line sql.y:2143 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: LikeStr, Right: yyDollar[3].expr, Escape: yyDollar[4].expr} } - case 412: + case 405: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2173 +//line sql.y:2147 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotLikeStr, Right: yyDollar[4].expr, Escape: yyDollar[5].expr} } - case 413: + case 406: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2177 +//line sql.y:2151 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: RegexpStr, Right: yyDollar[3].expr} } - case 414: + case 407: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2181 +//line sql.y:2155 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotRegexpStr, Right: yyDollar[4].expr} } - case 415: + case 408: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2185 +//line sql.y:2159 { yyVAL.expr = &RangeCond{Left: yyDollar[1].expr, Operator: BetweenStr, From: yyDollar[3].expr, To: yyDollar[5].expr} } - case 416: + case 409: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2189 +//line sql.y:2163 { yyVAL.expr = &RangeCond{Left: yyDollar[1].expr, Operator: NotBetweenStr, From: yyDollar[4].expr, To: yyDollar[6].expr} } - case 417: + case 410: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2193 +//line sql.y:2167 { yyVAL.expr = &ExistsExpr{Subquery: yyDollar[2].subquery} } - case 418: + case 411: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2199 +//line sql.y:2173 { yyVAL.str = IsNullStr } - case 419: + case 412: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2203 +//line sql.y:2177 { yyVAL.str = IsNotNullStr } - case 420: + case 413: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2207 +//line sql.y:2181 { yyVAL.str = IsTrueStr } - case 421: + case 414: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2211 +//line sql.y:2185 { yyVAL.str = IsNotTrueStr } - case 422: + case 415: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2215 +//line sql.y:2189 { yyVAL.str = IsFalseStr } - case 423: + case 416: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2219 +//line sql.y:2193 { yyVAL.str = IsNotFalseStr } - case 424: + case 417: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2225 +//line sql.y:2199 { yyVAL.str = EqualStr } - case 425: + case 418: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2229 +//line sql.y:2203 { yyVAL.str = LessThanStr } - case 426: + case 419: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2233 +//line sql.y:2207 { yyVAL.str = GreaterThanStr } - case 427: + case 420: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2237 +//line sql.y:2211 { yyVAL.str = LessEqualStr } - case 428: + case 421: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2241 +//line sql.y:2215 { yyVAL.str = GreaterEqualStr } - case 429: + case 422: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2245 +//line sql.y:2219 { yyVAL.str = NotEqualStr } - case 430: + case 423: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2249 +//line sql.y:2223 { yyVAL.str = NullSafeEqualStr } - case 431: + case 424: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2254 +//line sql.y:2228 { yyVAL.expr = nil } - case 432: + case 425: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2258 +//line sql.y:2232 { yyVAL.expr = yyDollar[2].expr } - case 433: + case 426: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2264 +//line sql.y:2238 { yyVAL.colTuple = yyDollar[1].valTuple } - case 434: + case 427: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2268 +//line sql.y:2242 { yyVAL.colTuple = yyDollar[1].subquery } - case 435: + case 428: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2272 +//line sql.y:2246 { yyVAL.colTuple = ListArg(yyDollar[1].bytes) } - case 436: + case 429: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2278 +//line sql.y:2252 { yyVAL.subquery = &Subquery{yyDollar[2].selStmt} } - case 437: + case 430: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2284 +//line sql.y:2258 { yyVAL.exprs = Exprs{yyDollar[1].expr} } - case 438: + case 431: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2288 +//line sql.y:2262 { yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) } - case 439: + case 432: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2294 +//line sql.y:2268 { yyVAL.expr = yyDollar[1].expr } - case 440: + case 433: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2298 +//line sql.y:2272 { yyVAL.expr = yyDollar[1].boolVal } - case 441: + case 434: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2302 +//line sql.y:2276 { yyVAL.expr = yyDollar[1].colName } - case 442: + case 435: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2306 +//line sql.y:2280 { yyVAL.expr = yyDollar[1].expr } - case 443: + case 436: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2310 +//line sql.y:2284 { yyVAL.expr = yyDollar[1].subquery } - case 444: + case 437: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2314 +//line sql.y:2288 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitAndStr, Right: yyDollar[3].expr} } - case 445: + case 438: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2318 +//line sql.y:2292 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitOrStr, Right: yyDollar[3].expr} } - case 446: + case 439: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2322 +//line sql.y:2296 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitXorStr, Right: yyDollar[3].expr} } - case 447: + case 440: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2326 +//line sql.y:2300 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: PlusStr, Right: yyDollar[3].expr} } - case 448: + case 441: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2330 +//line sql.y:2304 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MinusStr, Right: yyDollar[3].expr} } - case 449: + case 442: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2334 +//line sql.y:2308 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MultStr, Right: yyDollar[3].expr} } - case 450: + case 443: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2338 +//line sql.y:2312 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: DivStr, Right: yyDollar[3].expr} } - case 451: + case 444: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2342 +//line sql.y:2316 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: IntDivStr, Right: yyDollar[3].expr} } - case 452: + case 445: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2346 +//line sql.y:2320 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} } - case 453: + case 446: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2350 +//line sql.y:2324 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} } - case 454: + case 447: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2354 +//line sql.y:2328 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftLeftStr, Right: yyDollar[3].expr} } - case 455: + case 448: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2358 +//line sql.y:2332 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftRightStr, Right: yyDollar[3].expr} } - case 456: + case 449: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2362 +//line sql.y:2336 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONExtractOp, Right: yyDollar[3].expr} } - case 457: + case 450: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2366 +//line sql.y:2340 { yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONUnquoteExtractOp, Right: yyDollar[3].expr} } - case 458: + case 451: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2370 +//line sql.y:2344 { yyVAL.expr = &CollateExpr{Expr: yyDollar[1].expr, Charset: yyDollar[3].str} } - case 459: + case 452: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2374 +//line sql.y:2348 { yyVAL.expr = &UnaryExpr{Operator: BinaryStr, Expr: yyDollar[2].expr} } - case 460: + case 453: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2378 +//line sql.y:2352 { yyVAL.expr = &UnaryExpr{Operator: UBinaryStr, Expr: yyDollar[2].expr} } - case 461: + case 454: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2382 +//line sql.y:2356 { yyVAL.expr = &UnaryExpr{Operator: Utf8mb4Str, Expr: yyDollar[2].expr} } - case 462: + case 455: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2386 +//line sql.y:2360 { if num, ok := yyDollar[2].expr.(*SQLVal); ok && num.Type == IntVal { yyVAL.expr = num @@ -5689,9 +5655,9 @@ yydefault: yyVAL.expr = &UnaryExpr{Operator: UPlusStr, Expr: yyDollar[2].expr} } } - case 463: + case 456: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2394 +//line sql.y:2368 { if num, ok := yyDollar[2].expr.(*SQLVal); ok && num.Type == IntVal { // Handle double negative @@ -5705,21 +5671,21 @@ yydefault: yyVAL.expr = &UnaryExpr{Operator: UMinusStr, Expr: yyDollar[2].expr} } } - case 464: + case 457: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2408 +//line sql.y:2382 { yyVAL.expr = &UnaryExpr{Operator: TildaStr, Expr: yyDollar[2].expr} } - case 465: + case 458: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2412 +//line sql.y:2386 { yyVAL.expr = &UnaryExpr{Operator: BangStr, Expr: yyDollar[2].expr} } - case 466: + case 459: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2416 +//line sql.y:2390 { // This rule prevents the usage of INTERVAL // as a function. If support is needed for that, @@ -5727,515 +5693,521 @@ yydefault: // will be non-trivial because of grammar conflicts. yyVAL.expr = &IntervalExpr{Expr: yyDollar[2].expr, Unit: yyDollar[3].colIdent.String()} } - case 471: + case 464: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2434 +//line sql.y:2408 { yyVAL.expr = &FuncExpr{Name: yyDollar[1].colIdent, Exprs: yyDollar[3].selectExprs} } - case 472: + case 465: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2438 +//line sql.y:2412 { yyVAL.expr = &FuncExpr{Name: yyDollar[1].colIdent, Distinct: true, Exprs: yyDollar[4].selectExprs} } - case 473: + case 466: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2442 +//line sql.y:2416 { yyVAL.expr = &FuncExpr{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].colIdent, Exprs: yyDollar[5].selectExprs} } - case 474: + case 467: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2452 +//line sql.y:2426 { yyVAL.expr = &FuncExpr{Name: NewColIdent("left"), Exprs: yyDollar[3].selectExprs} } - case 475: + case 468: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2456 +//line sql.y:2430 { yyVAL.expr = &FuncExpr{Name: NewColIdent("right"), Exprs: yyDollar[3].selectExprs} } - case 476: + case 469: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2460 +//line sql.y:2434 { yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} } - case 477: + case 470: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2464 +//line sql.y:2438 { yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} } - case 478: + case 471: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2468 +//line sql.y:2442 { yyVAL.expr = &ConvertUsingExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].str} } - case 479: + case 472: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2472 +//line sql.y:2446 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} } - case 480: + case 473: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2476 +//line sql.y:2450 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 481: + case 474: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2480 +//line sql.y:2454 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 482: + case 475: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2484 +//line sql.y:2458 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} } - case 483: + case 476: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2488 +//line sql.y:2462 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 484: + case 477: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2492 +//line sql.y:2466 { yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 485: + case 478: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2496 +//line sql.y:2470 { yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: nil} } - case 486: + case 479: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2500 +//line sql.y:2474 { yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 487: + case 480: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2504 +//line sql.y:2478 { yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 488: + case 481: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2508 +//line sql.y:2482 { yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: nil} } - case 489: + case 482: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2512 +//line sql.y:2486 { yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 490: + case 483: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2516 +//line sql.y:2490 { yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} } - case 491: + case 484: yyDollar = yyS[yypt-9 : yypt+1] -//line sql.y:2520 +//line sql.y:2494 { yyVAL.expr = &MatchExpr{Columns: yyDollar[3].selectExprs, Expr: yyDollar[7].expr, Option: yyDollar[8].str} } - case 492: + case 485: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:2524 +//line sql.y:2498 { yyVAL.expr = &GroupConcatExpr{Distinct: yyDollar[3].str, Exprs: yyDollar[4].selectExprs, OrderBy: yyDollar[5].orderBy, Separator: yyDollar[6].str} } - case 493: + case 486: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2528 +//line sql.y:2502 { yyVAL.expr = &CaseExpr{Expr: yyDollar[2].expr, Whens: yyDollar[3].whens, Else: yyDollar[4].expr} } - case 494: + case 487: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2532 +//line sql.y:2506 { yyVAL.expr = &ValuesFuncExpr{Name: yyDollar[3].colName} } - case 495: + case 488: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2542 +//line sql.y:2516 { yyVAL.expr = &FuncExpr{Name: NewColIdent("current_timestamp")} } - case 496: + case 489: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2546 +//line sql.y:2520 { yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_timestamp")} } - case 497: + case 490: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2550 +//line sql.y:2524 { yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_time")} } - case 498: + case 491: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2555 +//line sql.y:2529 { yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_date")} } - case 499: + case 492: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2560 +//line sql.y:2534 { yyVAL.expr = &FuncExpr{Name: NewColIdent("localtime")} } - case 500: + case 493: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2565 +//line sql.y:2539 { yyVAL.expr = &FuncExpr{Name: NewColIdent("localtimestamp")} } - case 501: + case 494: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2571 +//line sql.y:2545 { yyVAL.expr = &FuncExpr{Name: NewColIdent("current_date")} } - case 502: + case 495: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2576 +//line sql.y:2550 { yyVAL.expr = &FuncExpr{Name: NewColIdent("current_time")} } - case 503: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2581 + case 496: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2555 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_timestamp"), Fsp: yyDollar[3].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_timestamp"), Fsp: yyDollar[2].expr} } - case 504: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2585 + case 497: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2559 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_timestamp"), Fsp: yyDollar[3].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_timestamp"), Fsp: yyDollar[2].expr} } - case 505: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2589 + case 498: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2563 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_time"), Fsp: yyDollar[3].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_time"), Fsp: yyDollar[2].expr} } - case 506: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2594 + case 499: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2568 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtime"), Fsp: yyDollar[3].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtime"), Fsp: yyDollar[2].expr} } - case 507: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2599 + case 500: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2573 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtimestamp"), Fsp: yyDollar[3].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtimestamp"), Fsp: yyDollar[2].expr} } - case 508: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2604 + case 501: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2578 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_time"), Fsp: yyDollar[3].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_time"), Fsp: yyDollar[2].expr} } - case 509: + case 502: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2608 +//line sql.y:2582 { yyVAL.expr = &TimestampFuncExpr{Name: string("timestampadd"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].expr, Expr2: yyDollar[7].expr} } - case 510: + case 503: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2612 +//line sql.y:2586 { yyVAL.expr = &TimestampFuncExpr{Name: string("timestampdiff"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].expr, Expr2: yyDollar[7].expr} } - case 513: + case 506: + yyDollar = yyS[yypt-3 : yypt+1] +//line sql.y:2596 + { + yyVAL.expr = yyDollar[2].expr + } + case 507: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2626 +//line sql.y:2606 { yyVAL.expr = &FuncExpr{Name: NewColIdent("if"), Exprs: yyDollar[3].selectExprs} } - case 514: + case 508: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2630 +//line sql.y:2610 { yyVAL.expr = &FuncExpr{Name: NewColIdent("database"), Exprs: yyDollar[3].selectExprs} } - case 515: + case 509: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2634 +//line sql.y:2614 { yyVAL.expr = &FuncExpr{Name: NewColIdent("mod"), Exprs: yyDollar[3].selectExprs} } - case 516: + case 510: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2638 +//line sql.y:2618 { yyVAL.expr = &FuncExpr{Name: NewColIdent("replace"), Exprs: yyDollar[3].selectExprs} } - case 517: + case 511: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2644 +//line sql.y:2624 { yyVAL.str = "" } - case 518: + case 512: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2648 +//line sql.y:2628 { yyVAL.str = BooleanModeStr } - case 519: + case 513: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2652 +//line sql.y:2632 { yyVAL.str = NaturalLanguageModeStr } - case 520: + case 514: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:2656 +//line sql.y:2636 { yyVAL.str = NaturalLanguageModeWithQueryExpansionStr } - case 521: + case 515: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2660 +//line sql.y:2640 { yyVAL.str = QueryExpansionStr } - case 522: + case 516: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2666 +//line sql.y:2646 { yyVAL.str = string(yyDollar[1].bytes) } - case 523: + case 517: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2670 +//line sql.y:2650 { yyVAL.str = string(yyDollar[1].bytes) } - case 524: + case 518: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2676 +//line sql.y:2656 { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } - case 525: + case 519: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2680 +//line sql.y:2660 { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: yyDollar[3].str, Operator: CharacterSetStr} + yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: yyDollar[3].str, Operator: CharacterSetStr} } - case 526: + case 520: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2684 +//line sql.y:2664 { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal, Charset: string(yyDollar[3].bytes)} + yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: string(yyDollar[3].bytes)} } - case 527: + case 521: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2688 +//line sql.y:2668 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 528: + case 522: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2692 +//line sql.y:2672 { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } - case 529: + case 523: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2696 +//line sql.y:2676 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} yyVAL.convertType.Length = yyDollar[2].LengthScaleOption.Length yyVAL.convertType.Scale = yyDollar[2].LengthScaleOption.Scale } - case 530: + case 524: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2702 +//line sql.y:2682 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 531: + case 525: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2706 +//line sql.y:2686 { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } - case 532: + case 526: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2710 +//line sql.y:2690 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 533: + case 527: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2714 +//line sql.y:2694 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 534: + case 528: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2718 +//line sql.y:2698 { - yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].optVal} + yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } - case 535: + case 529: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2722 +//line sql.y:2702 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 536: + case 530: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2726 +//line sql.y:2706 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 537: + case 531: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2731 +//line sql.y:2711 { yyVAL.expr = nil } - case 538: + case 532: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2735 +//line sql.y:2715 { yyVAL.expr = yyDollar[1].expr } - case 539: + case 533: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2740 +//line sql.y:2720 { yyVAL.str = string("") } - case 540: + case 534: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2744 +//line sql.y:2724 { yyVAL.str = " separator '" + string(yyDollar[2].bytes) + "'" } - case 541: + case 535: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2750 +//line sql.y:2730 { yyVAL.whens = []*When{yyDollar[1].when} } - case 542: + case 536: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2754 +//line sql.y:2734 { yyVAL.whens = append(yyDollar[1].whens, yyDollar[2].when) } - case 543: + case 537: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2760 +//line sql.y:2740 { yyVAL.when = &When{Cond: yyDollar[2].expr, Val: yyDollar[4].expr} } - case 544: + case 538: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2765 +//line sql.y:2745 { yyVAL.expr = nil } - case 545: + case 539: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2769 +//line sql.y:2749 { yyVAL.expr = yyDollar[2].expr } - case 546: + case 540: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2775 +//line sql.y:2755 { yyVAL.colName = &ColName{Name: yyDollar[1].colIdent} } - case 547: + case 541: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2779 +//line sql.y:2759 { yyVAL.colName = &ColName{Qualifier: TableName{Name: yyDollar[1].tableIdent}, Name: yyDollar[3].colIdent} } - case 548: + case 542: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2783 +//line sql.y:2763 { yyVAL.colName = &ColName{Qualifier: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}, Name: yyDollar[5].colIdent} } - case 549: + case 543: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2789 +//line sql.y:2769 { yyVAL.expr = NewStrVal(yyDollar[1].bytes) } - case 550: + case 544: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2793 +//line sql.y:2773 { yyVAL.expr = NewHexVal(yyDollar[1].bytes) } - case 551: + case 545: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2797 +//line sql.y:2777 { yyVAL.expr = NewBitVal(yyDollar[1].bytes) } - case 552: + case 546: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2801 +//line sql.y:2781 { yyVAL.expr = NewIntVal(yyDollar[1].bytes) } - case 553: + case 547: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2805 +//line sql.y:2785 { yyVAL.expr = NewFloatVal(yyDollar[1].bytes) } - case 554: + case 548: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2809 +//line sql.y:2789 { yyVAL.expr = NewHexNum(yyDollar[1].bytes) } - case 555: + case 549: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2813 +//line sql.y:2793 { yyVAL.expr = NewValArg(yyDollar[1].bytes) } - case 556: + case 550: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2817 +//line sql.y:2797 { yyVAL.expr = &NullVal{} } - case 557: + case 551: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2823 +//line sql.y:2803 { // TODO(sougou): Deprecate this construct. if yyDollar[1].colIdent.Lowered() != "value" { @@ -6244,239 +6216,239 @@ yydefault: } yyVAL.expr = NewIntVal([]byte("1")) } - case 558: + case 552: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2832 +//line sql.y:2812 { yyVAL.expr = NewIntVal(yyDollar[1].bytes) } - case 559: + case 553: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2836 +//line sql.y:2816 { yyVAL.expr = NewValArg(yyDollar[1].bytes) } - case 560: + case 554: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2841 +//line sql.y:2821 { yyVAL.exprs = nil } - case 561: + case 555: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2845 +//line sql.y:2825 { yyVAL.exprs = yyDollar[3].exprs } - case 562: + case 556: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2850 +//line sql.y:2830 { yyVAL.expr = nil } - case 563: + case 557: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2854 +//line sql.y:2834 { yyVAL.expr = yyDollar[2].expr } - case 564: + case 558: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2859 +//line sql.y:2839 { yyVAL.orderBy = nil } - case 565: + case 559: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2863 +//line sql.y:2843 { yyVAL.orderBy = yyDollar[3].orderBy } - case 566: + case 560: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2869 +//line sql.y:2849 { yyVAL.orderBy = OrderBy{yyDollar[1].order} } - case 567: + case 561: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2873 +//line sql.y:2853 { yyVAL.orderBy = append(yyDollar[1].orderBy, yyDollar[3].order) } - case 568: + case 562: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2879 +//line sql.y:2859 { yyVAL.order = &Order{Expr: yyDollar[1].expr, Direction: yyDollar[2].str} } - case 569: + case 563: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2884 +//line sql.y:2864 { yyVAL.str = AscScr } - case 570: + case 564: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2888 +//line sql.y:2868 { yyVAL.str = AscScr } - case 571: + case 565: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2892 +//line sql.y:2872 { yyVAL.str = DescScr } - case 572: + case 566: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2897 +//line sql.y:2877 { yyVAL.limit = nil } - case 573: + case 567: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2901 +//line sql.y:2881 { yyVAL.limit = &Limit{Rowcount: yyDollar[2].expr} } - case 574: + case 568: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2905 +//line sql.y:2885 { yyVAL.limit = &Limit{Offset: yyDollar[2].expr, Rowcount: yyDollar[4].expr} } - case 575: + case 569: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2909 +//line sql.y:2889 { yyVAL.limit = &Limit{Offset: yyDollar[4].expr, Rowcount: yyDollar[2].expr} } - case 576: + case 570: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2914 +//line sql.y:2894 { yyVAL.str = "" } - case 577: + case 571: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2918 +//line sql.y:2898 { yyVAL.str = ForUpdateStr } - case 578: + case 572: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2922 +//line sql.y:2902 { yyVAL.str = ShareModeStr } - case 579: + case 573: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2935 +//line sql.y:2915 { yyVAL.ins = &Insert{Rows: yyDollar[2].values} } - case 580: + case 574: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2939 +//line sql.y:2919 { yyVAL.ins = &Insert{Rows: yyDollar[1].selStmt} } - case 581: + case 575: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2943 +//line sql.y:2923 { // Drop the redundant parenthesis. yyVAL.ins = &Insert{Rows: yyDollar[2].selStmt} } - case 582: + case 576: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2948 +//line sql.y:2928 { yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].values} } - case 583: + case 577: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2952 +//line sql.y:2932 { yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[4].selStmt} } - case 584: + case 578: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2956 +//line sql.y:2936 { // Drop the redundant parenthesis. yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].selStmt} } - case 585: + case 579: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2963 +//line sql.y:2943 { yyVAL.columns = Columns{yyDollar[1].colIdent} } - case 586: + case 580: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2967 +//line sql.y:2947 { yyVAL.columns = Columns{yyDollar[3].colIdent} } - case 587: + case 581: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2971 +//line sql.y:2951 { yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) } - case 588: + case 582: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2975 +//line sql.y:2955 { yyVAL.columns = append(yyVAL.columns, yyDollar[5].colIdent) } - case 589: + case 583: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2980 +//line sql.y:2960 { yyVAL.updateExprs = nil } - case 590: + case 584: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2984 +//line sql.y:2964 { yyVAL.updateExprs = yyDollar[5].updateExprs } - case 591: + case 585: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2990 +//line sql.y:2970 { yyVAL.values = Values{yyDollar[1].valTuple} } - case 592: + case 586: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2994 +//line sql.y:2974 { yyVAL.values = append(yyDollar[1].values, yyDollar[3].valTuple) } - case 593: + case 587: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3000 +//line sql.y:2980 { yyVAL.valTuple = yyDollar[1].valTuple } - case 594: + case 588: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3004 +//line sql.y:2984 { yyVAL.valTuple = ValTuple{} } - case 595: + case 589: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3010 +//line sql.y:2990 { yyVAL.valTuple = ValTuple(yyDollar[2].exprs) } - case 596: + case 590: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3016 +//line sql.y:2996 { if len(yyDollar[1].valTuple) == 1 { yyVAL.expr = &ParenExpr{yyDollar[1].valTuple[0]} @@ -6484,312 +6456,312 @@ yydefault: yyVAL.expr = yyDollar[1].valTuple } } - case 597: + case 591: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3026 +//line sql.y:3006 { yyVAL.updateExprs = UpdateExprs{yyDollar[1].updateExpr} } - case 598: + case 592: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3030 +//line sql.y:3010 { yyVAL.updateExprs = append(yyDollar[1].updateExprs, yyDollar[3].updateExpr) } - case 599: + case 593: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3036 +//line sql.y:3016 { yyVAL.updateExpr = &UpdateExpr{Name: yyDollar[1].colName, Expr: yyDollar[3].expr} } - case 600: + case 594: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3042 +//line sql.y:3022 { yyVAL.setExprs = SetExprs{yyDollar[1].setExpr} } - case 601: + case 595: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3046 +//line sql.y:3026 { yyVAL.setExprs = append(yyDollar[1].setExprs, yyDollar[3].setExpr) } - case 602: + case 596: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3052 +//line sql.y:3032 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: NewStrVal([]byte("on"))} } - case 603: + case 597: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3056 +//line sql.y:3036 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: NewStrVal([]byte("off"))} } - case 604: + case 598: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3060 +//line sql.y:3040 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: yyDollar[3].expr} } - case 605: + case 599: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3064 +//line sql.y:3044 { yyVAL.setExpr = &SetExpr{Name: NewColIdent(string(yyDollar[1].bytes)), Expr: yyDollar[2].expr} } - case 607: + case 601: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3071 +//line sql.y:3051 { yyVAL.bytes = []byte("charset") } - case 609: + case 603: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3078 +//line sql.y:3058 { yyVAL.expr = NewStrVal([]byte(yyDollar[1].colIdent.String())) } - case 610: + case 604: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3082 +//line sql.y:3062 { yyVAL.expr = NewStrVal(yyDollar[1].bytes) } - case 611: + case 605: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3086 +//line sql.y:3066 { yyVAL.expr = &Default{} } - case 614: + case 608: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3095 +//line sql.y:3075 { yyVAL.byt = 0 } - case 615: + case 609: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3097 +//line sql.y:3077 { yyVAL.byt = 1 } - case 616: + case 610: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3100 +//line sql.y:3080 { yyVAL.empty = struct{}{} } - case 617: + case 611: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3102 +//line sql.y:3082 { yyVAL.empty = struct{}{} } - case 618: + case 612: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3105 +//line sql.y:3085 { yyVAL.str = "" } - case 619: + case 613: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3107 +//line sql.y:3087 { yyVAL.str = IgnoreStr } - case 620: + case 614: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3111 +//line sql.y:3091 { yyVAL.empty = struct{}{} } - case 621: + case 615: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3113 +//line sql.y:3093 { yyVAL.empty = struct{}{} } - case 622: + case 616: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3115 +//line sql.y:3095 { yyVAL.empty = struct{}{} } - case 623: + case 617: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3117 +//line sql.y:3097 { yyVAL.empty = struct{}{} } - case 624: + case 618: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3119 +//line sql.y:3099 { yyVAL.empty = struct{}{} } - case 625: + case 619: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3121 +//line sql.y:3101 { yyVAL.empty = struct{}{} } - case 626: + case 620: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3123 +//line sql.y:3103 { yyVAL.empty = struct{}{} } - case 627: + case 621: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3125 +//line sql.y:3105 { yyVAL.empty = struct{}{} } - case 628: + case 622: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3127 +//line sql.y:3107 { yyVAL.empty = struct{}{} } - case 629: + case 623: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3129 +//line sql.y:3109 { yyVAL.empty = struct{}{} } - case 630: + case 624: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3132 +//line sql.y:3112 { yyVAL.empty = struct{}{} } - case 631: + case 625: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3134 +//line sql.y:3114 { yyVAL.empty = struct{}{} } - case 632: + case 626: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3136 +//line sql.y:3116 { yyVAL.empty = struct{}{} } - case 633: + case 627: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3140 +//line sql.y:3120 { yyVAL.empty = struct{}{} } - case 634: + case 628: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3142 +//line sql.y:3122 { yyVAL.empty = struct{}{} } - case 635: + case 629: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3145 +//line sql.y:3125 { yyVAL.empty = struct{}{} } - case 636: + case 630: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3147 +//line sql.y:3127 { yyVAL.empty = struct{}{} } - case 637: + case 631: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3149 +//line sql.y:3129 { yyVAL.empty = struct{}{} } - case 638: + case 632: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3152 +//line sql.y:3132 { yyVAL.colIdent = ColIdent{} } - case 639: + case 633: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3154 +//line sql.y:3134 { yyVAL.colIdent = yyDollar[2].colIdent } - case 640: + case 634: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3158 +//line sql.y:3138 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 641: + case 635: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3162 +//line sql.y:3142 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 643: + case 637: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3169 +//line sql.y:3149 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 644: + case 638: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3175 +//line sql.y:3155 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 645: + case 639: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3179 +//line sql.y:3159 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 647: + case 641: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3186 +//line sql.y:3166 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 856: + case 850: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3420 +//line sql.y:3400 { if incNesting(yylex) { yylex.Error("max nesting level reached") return 1 } } - case 857: + case 851: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3429 +//line sql.y:3409 { decNesting(yylex) } - case 858: + case 852: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3434 +//line sql.y:3414 { skipToEnd(yylex) } - case 859: + case 853: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3439 +//line sql.y:3419 { skipToEnd(yylex) } - case 860: + case 854: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3443 +//line sql.y:3423 { skipToEnd(yylex) } - case 861: + case 855: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3447 +//line sql.y:3427 { skipToEnd(yylex) } diff --git a/go/vt/sqlparser/sql.y b/go/vt/sqlparser/sql.y index 264d832fded..33816225ed7 100644 --- a/go/vt/sqlparser/sql.y +++ b/go/vt/sqlparser/sql.y @@ -75,6 +75,7 @@ func skipToEnd(yylex interface{}) { expr Expr exprs Exprs boolVal BoolVal + sqlVal *SQLVal colTuple ColTuple values Values valTuple ValTuple @@ -95,7 +96,7 @@ func skipToEnd(yylex interface{}) { TableSpec *TableSpec columnType ColumnType colKeyOpt ColumnKeyOption - optVal *SQLVal + optVal Expr LengthScaleOption LengthScaleOption columnDefinition *ColumnDefinition indexDefinition *IndexDefinition @@ -229,7 +230,7 @@ func skipToEnd(yylex interface{}) { %type compare %type insert_data %type value value_expression num_val -%type function_call_keyword function_call_nonkeyword function_call_generic function_call_conflict +%type function_call_keyword function_call_nonkeyword function_call_generic function_call_conflict func_datetime_precision %type is_suffix %type col_tuple %type expression_list @@ -274,7 +275,8 @@ func skipToEnd(yylex interface{}) { %type convert_type %type column_type %type int_type decimal_type numeric_type time_type char_type spatial_type -%type length_opt column_default_opt column_comment_opt on_update_opt +%type length_opt column_comment_opt +%type column_default_opt on_update_opt %type charset_opt collate_opt %type unsigned_opt zero_fill_opt %type float_length_opt decimal_length_opt @@ -965,46 +967,18 @@ column_default_opt: { $$ = nil } -| DEFAULT STRING +| DEFAULT value_expression { - $$ = NewStrVal($2) - } -| DEFAULT INTEGRAL - { - $$ = NewIntVal($2) - } -| DEFAULT FLOAT - { - $$ = NewFloatVal($2) - } -| DEFAULT NULL - { - $$ = NewValArg($2) - } -| DEFAULT CURRENT_TIMESTAMP - { - $$ = NewValArg($2) - } -| DEFAULT CURRENT_TIMESTAMP '(' ')' - { - $$ = NewValArg($2) - } -| DEFAULT BIT_LITERAL - { - $$ = NewBitVal($2) + $$ = $2 } on_update_opt: { $$ = nil } -| ON UPDATE CURRENT_TIMESTAMP -{ - $$ = NewValArg($3) -} -| ON UPDATE CURRENT_TIMESTAMP '(' ')' +| ON UPDATE function_call_nonkeyword { - $$ = NewValArg($3) + $$ = $3 } auto_increment_opt: @@ -2538,71 +2512,71 @@ function_call_keyword: Dedicated grammar rules are needed because of the special syntax */ function_call_nonkeyword: - CURRENT_TIMESTAMP func_datetime_precision_opt + CURRENT_TIMESTAMP func_datetime_opt { $$ = &FuncExpr{Name:NewColIdent("current_timestamp")} } -| UTC_TIMESTAMP func_datetime_precision_opt +| UTC_TIMESTAMP func_datetime_opt { $$ = &FuncExpr{Name:NewColIdent("utc_timestamp")} } -| UTC_TIME func_datetime_precision_opt +| UTC_TIME func_datetime_opt { $$ = &FuncExpr{Name:NewColIdent("utc_time")} } /* doesn't support fsp */ -| UTC_DATE func_datetime_precision_opt +| UTC_DATE func_datetime_opt { $$ = &FuncExpr{Name:NewColIdent("utc_date")} } // now -| LOCALTIME func_datetime_precision_opt +| LOCALTIME func_datetime_opt { $$ = &FuncExpr{Name:NewColIdent("localtime")} } // now -| LOCALTIMESTAMP func_datetime_precision_opt +| LOCALTIMESTAMP func_datetime_opt { $$ = &FuncExpr{Name:NewColIdent("localtimestamp")} } // curdate /* doesn't support fsp */ -| CURRENT_DATE func_datetime_precision_opt +| CURRENT_DATE func_datetime_opt { $$ = &FuncExpr{Name:NewColIdent("current_date")} } // curtime -| CURRENT_TIME func_datetime_precision_opt +| CURRENT_TIME func_datetime_opt { $$ = &FuncExpr{Name:NewColIdent("current_time")} } // these functions can also be called with an optional argument -| CURRENT_TIMESTAMP openb value_expression closeb +| CURRENT_TIMESTAMP func_datetime_precision { - $$ = &CurTimeFuncExpr{Name:NewColIdent("current_timestamp"), Fsp:$3} + $$ = &CurTimeFuncExpr{Name:NewColIdent("current_timestamp"), Fsp:$2} } -| UTC_TIMESTAMP openb value_expression closeb +| UTC_TIMESTAMP func_datetime_precision { - $$ = &CurTimeFuncExpr{Name:NewColIdent("utc_timestamp"), Fsp:$3} + $$ = &CurTimeFuncExpr{Name:NewColIdent("utc_timestamp"), Fsp:$2} } -| UTC_TIME openb value_expression closeb +| UTC_TIME func_datetime_precision { - $$ = &CurTimeFuncExpr{Name:NewColIdent("utc_time"), Fsp:$3} + $$ = &CurTimeFuncExpr{Name:NewColIdent("utc_time"), Fsp:$2} } // now -| LOCALTIME openb value_expression closeb +| LOCALTIME func_datetime_precision { - $$ = &CurTimeFuncExpr{Name:NewColIdent("localtime"), Fsp:$3} + $$ = &CurTimeFuncExpr{Name:NewColIdent("localtime"), Fsp:$2} } // now -| LOCALTIMESTAMP openb value_expression closeb +| LOCALTIMESTAMP func_datetime_precision { - $$ = &CurTimeFuncExpr{Name:NewColIdent("localtimestamp"), Fsp:$3} + $$ = &CurTimeFuncExpr{Name:NewColIdent("localtimestamp"), Fsp:$2} } // curtime -| CURRENT_TIME openb value_expression closeb +| CURRENT_TIME func_datetime_precision { - $$ = &CurTimeFuncExpr{Name:NewColIdent("current_time"), Fsp:$3} + $$ = &CurTimeFuncExpr{Name:NewColIdent("current_time"), Fsp:$2} } | TIMESTAMPADD openb sql_id ',' value_expression ',' value_expression closeb { @@ -2613,10 +2587,16 @@ function_call_nonkeyword: $$ = &TimestampFuncExpr{Name:string("timestampdiff"), Unit:$3.String(), Expr1:$5, Expr2:$7} } -func_datetime_precision_opt: +func_datetime_opt: /* empty */ | openb closeb +func_datetime_precision: + openb value_expression closeb + { + $$ = $2 + } + /* Function calls using non reserved keywords with *normal* syntax forms. Because the names are non-reserved, they need a dedicated rule so as not to conflict From e66f2850354c4d19fef3eced95b80a81fded24c8 Mon Sep 17 00:00:00 2001 From: deepthi Date: Thu, 31 Jan 2019 16:55:07 -0800 Subject: [PATCH 011/196] update goyacc and regen sql.go Signed-off-by: deepthi --- go/vt/sqlparser/sql.go | 1 + 1 file changed, 1 insertion(+) diff --git a/go/vt/sqlparser/sql.go b/go/vt/sqlparser/sql.go index b9de5232306..c21cae51832 100644 --- a/go/vt/sqlparser/sql.go +++ b/go/vt/sqlparser/sql.go @@ -6,6 +6,7 @@ package sqlparser import __yyfmt__ "fmt" //line sql.y:18 + func setParseTree(yylex interface{}, stmt Statement) { yylex.(*Tokenizer).ParseTree = stmt } From 3739931453f15a465b3eb9cee4ba70da1086f92f Mon Sep 17 00:00:00 2001 From: sanket_5001211 Date: Fri, 1 Feb 2019 13:40:01 +0530 Subject: [PATCH 012/196] Updating url to https as it causing trouble in unzip in mac Signed-off-by: sanket_5001211 --- bootstrap.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bootstrap.sh b/bootstrap.sh index 2317c0c786d..971034fd7c7 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -264,7 +264,7 @@ function install_chromedriver() { local version="$1" local dist="$2" - curl -sL "http://chromedriver.storage.googleapis.com/$version/chromedriver_linux64.zip" > chromedriver_linux64.zip + curl -sL "https://chromedriver.storage.googleapis.com/$version/chromedriver_linux64.zip" > chromedriver_linux64.zip unzip -o -q chromedriver_linux64.zip -d "$dist" rm chromedriver_linux64.zip } From c77fca3b8de856acdea8f0185a2087a74e56a102 Mon Sep 17 00:00:00 2001 From: Aaron Young Date: Wed, 14 Nov 2018 18:09:14 -0500 Subject: [PATCH 013/196] Fix connection leak in vtworker Signed-off-by: Michael Pawliszyn --- go/vt/worker/result_merger.go | 13 ++++++------- go/vt/worker/split_clone.go | 30 ++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 11 deletions(-) diff --git a/go/vt/worker/result_merger.go b/go/vt/worker/result_merger.go index 87213242b94..c0ae2ec7190 100644 --- a/go/vt/worker/result_merger.go +++ b/go/vt/worker/result_merger.go @@ -21,11 +21,10 @@ import ( "fmt" "io" + "github.com/golang/protobuf/proto" "golang.org/x/net/context" "vitess.io/vitess/go/vt/vterrors" - "github.com/golang/protobuf/proto" - "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" @@ -42,8 +41,9 @@ const ResultSizeRows = 64 // The output stream will be sorted by ascending primary key order. // It implements the ResultReader interface. type ResultMerger struct { - inputs []ResultReader - fields []*querypb.Field + inputs []ResultReader + allInputs []ResultReader + fields []*querypb.Field // output is the buffer of merged rows. Once it's full, we'll return it in // Next() (wrapped in a sqltypes.Result). output [][]sqltypes.Value @@ -92,6 +92,7 @@ func NewResultMerger(inputs []ResultReader, pkFieldCount int) (*ResultMerger, er rm := &ResultMerger{ inputs: activeInputs, + allInputs: inputs, fields: fields, nextRowHeap: nextRowHeap, } @@ -180,13 +181,11 @@ func (rm *ResultMerger) Next() (*sqltypes.Result, error) { // Close closes all inputs func (rm *ResultMerger) Close(ctx context.Context) { - for _, i := range rm.inputs { + for _, i := range rm.allInputs { i.Close(ctx) } } - - func (rm *ResultMerger) deleteInput(deleteMe ResultReader) { for i, input := range rm.inputs { if input == deleteMe { diff --git a/go/vt/worker/split_clone.go b/go/vt/worker/split_clone.go index 8537be596e2..3f4369eb976 100644 --- a/go/vt/worker/split_clone.go +++ b/go/vt/worker/split_clone.go @@ -914,6 +914,13 @@ func mergeOrSingle(readers []ResultReader, td *tabletmanagerdatapb.TableDefiniti func (scw *SplitCloneWorker) getSourceResultReader(ctx context.Context, td *tabletmanagerdatapb.TableDefinition, state StatusWorkerState, chunk chunk, txID int64) (ResultReader, error) { sourceReaders := make([]ResultReader, len(scw.sourceShards)) + var readers []ResultReader + defer func() { + for _, i := range readers { + i.Close(ctx) + } + }() + for shardIndex, si := range scw.sourceShards { var sourceResultReader ResultReader var err error @@ -941,15 +948,26 @@ func (scw *SplitCloneWorker) getSourceResultReader(ctx context.Context, td *tabl if err != nil { return nil, fmt.Errorf("NewRestartableResultReader for source: %v failed: %v", tp.description(), err) } + readers = append(readers, sourceResultReader) } - // TODO: We could end up in a situation where some readers have been created but not all. In this situation, we would not close up all readers sourceReaders[shardIndex] = sourceResultReader } - return mergeOrSingle(sourceReaders, td) + resultReader, err := mergeOrSingle(sourceReaders, td) + if err == nil { + readers = readers[:0] + } + return resultReader, err } func (scw *SplitCloneWorker) getDestinationResultReader(ctx context.Context, td *tabletmanagerdatapb.TableDefinition, state StatusWorkerState, chunk chunk) (ResultReader, error) { destReaders := make([]ResultReader, len(scw.destinationShards)) + var readers []ResultReader + defer func() { + for _, i := range readers { + i.Close(ctx) + } + }() + for shardIndex, si := range scw.destinationShards { tp := newShardTabletProvider(scw.tsc, scw.tabletTracker, si.Keyspace(), si.ShardName(), topodatapb.TabletType_MASTER) destResultReader, err := NewRestartableResultReader(ctx, scw.wr.Logger(), tp, td, chunk, true /* allowMultipleRetries */) @@ -958,7 +976,11 @@ func (scw *SplitCloneWorker) getDestinationResultReader(ctx context.Context, td } destReaders[shardIndex] = destResultReader } - return mergeOrSingle(destReaders, td) + resultReader, err := mergeOrSingle(destReaders, td) + if err == nil { + readers = readers[:0] + } + return resultReader, err } func (scw *SplitCloneWorker) cloneAChunk(ctx context.Context, td *tabletmanagerdatapb.TableDefinition, tableIndex int, chunk chunk, processError func(string, ...interface{}), state StatusWorkerState, tableStatusList *tableStatusList, keyResolver keyspaceIDResolver, start time.Time, insertChannels []chan string, txID int64, statsCounters []*stats.CountersWithSingleLabel) { @@ -1354,4 +1376,4 @@ func (scw *SplitCloneWorker) closeThrottlers() { t.Close() delete(scw.throttlers, keyspaceAndShard) } -} \ No newline at end of file +} From 5b1c31a6be9eb478762e1fd1fc42220ca75210c8 Mon Sep 17 00:00:00 2001 From: Tanmoy Krishna Das Date: Mon, 4 Feb 2019 18:53:50 +0600 Subject: [PATCH 014/196] fixed typo in the command to install unused Signed-off-by: Tanmoy Krishna Das --- misc/git/hooks/unused | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/git/hooks/unused b/misc/git/hooks/unused index a02b40c34bc..935740d2958 100755 --- a/misc/git/hooks/unused +++ b/misc/git/hooks/unused @@ -8,7 +8,7 @@ if [ -z "$GOPATH" ]; then fi if [ -z "$(which unused)" ]; then - echo "unused not found, please run: go get honnef.co/go/unused/cmd/unused" + echo "unused not found, please run: go get honnef.co/go/tools/cmd/unused" exit 1 fi From d717cc7794346a7f906fe5872f909c2eda803ae7 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Mon, 4 Feb 2019 10:51:09 -0800 Subject: [PATCH 015/196] Use sub tests Signed-off-by: Andres Taylor --- go/vt/worker/result_merger_test.go | 83 ++++++++++++++++-------------- 1 file changed, 44 insertions(+), 39 deletions(-) diff --git a/go/vt/worker/result_merger_test.go b/go/vt/worker/result_merger_test.go index 66bfa65eddf..b5ebb3c63d1 100644 --- a/go/vt/worker/result_merger_test.go +++ b/go/vt/worker/result_merger_test.go @@ -54,6 +54,7 @@ type fakeResultReader struct { // currentIndex is the current index within the current range. currentIndex int rowsReturned int + closed bool } // newFakeResultReader returns a new FakeResultReader. @@ -113,6 +114,7 @@ func (f *fakeResultReader) Fields() []*querypb.Field { // Close closes nothing func (f *fakeResultReader) Close(ctx context.Context) { + f.closed = true } // Next returns the next fake result. It is part of the ResultReader interface. @@ -303,53 +305,56 @@ func TestResultMerger(t *testing.T) { } for _, tc := range testcases { - t.Logf("checking testcase: %v", tc.desc) - pkFieldCount := 1 - if tc.multiPk { - pkFieldCount = 2 - } - rm, err := NewResultMerger(tc.inputs, pkFieldCount) - if err != nil { - t.Fatal(err) - } - - // Consume all merged Results. - var got []*sqltypes.Result - for { - result, err := rm.Next() + t.Run(fmt.Sprintf("checking testcase: %v", tc.desc), func(inner *testing.T) { + pkFieldCount := 1 + if tc.multiPk { + pkFieldCount = 2 + } + rm, err := NewResultMerger(tc.inputs, pkFieldCount) if err != nil { - if err == io.EOF { - break - } else { - t.Fatal(err) - } + inner.Fatal(err) } - got = append(got, result) - } - if !reflect.DeepEqual(got, tc.want) { - for i := range got { - if i == len(tc.want) { - // got has more Results than want. Avoid index out of range errors. - break - } - if got[i].RowsAffected != tc.want[i].RowsAffected { - t.Logf("deviating RowsAffected value for Result at index: %v got = %v, want = %v", i, got[i].RowsAffected, tc.want[i].RowsAffected) + // Consume all merged Results. + var got []*sqltypes.Result + for { + result, err := rm.Next() + if err != nil { + if err == io.EOF { + break + } else { + inner.Fatal(err) + } } - t.Logf("deviating Rows for Result at index: %v got = %v, want = %v", i, got[i].Rows, tc.want[i].Rows) + got = append(got, result) } - if len(tc.want)-len(got) > 0 { - for i := len(got); i < len(tc.want); i++ { - t.Logf("missing Result in got: %v", tc.want[i].Rows) + + rm.Close(context.Background()) + + if !reflect.DeepEqual(got, tc.want) { + for i := range got { + if i == len(tc.want) { + // got has more Results than want. Avoid index out of range errors. + break + } + if got[i].RowsAffected != tc.want[i].RowsAffected { + inner.Logf("deviating RowsAffected value for Result at index: %v got = %v, want = %v", i, got[i].RowsAffected, tc.want[i].RowsAffected) + } + inner.Logf("deviating Rows for Result at index: %v got = %v, want = %v", i, got[i].Rows, tc.want[i].Rows) } - } - if len(got)-len(tc.want) > 0 { - for i := len(tc.want); i < len(got); i++ { - t.Logf("unnecessary extra Result in got: %v", got[i].Rows) + if len(tc.want)-len(got) > 0 { + for i := len(got); i < len(tc.want); i++ { + inner.Logf("missing Result in got: %v", tc.want[i].Rows) + } + } + if len(got)-len(tc.want) > 0 { + for i := len(tc.want); i < len(got); i++ { + inner.Logf("unnecessary extra Result in got: %v", got[i].Rows) + } } + inner.Fatalf("ResultMerger testcase '%v' failed. See output above for different rows.", tc.desc) } - t.Fatalf("ResultMerger testcase '%v' failed. See output above for different rows.", tc.desc) - } + }) } } From a0daf9feace0c71b37af6eb28fbd9043c2a9587e Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Mon, 4 Feb 2019 10:54:19 -0800 Subject: [PATCH 016/196] Assert that inputs have been closed Signed-off-by: Andres Taylor --- go/vt/worker/result_merger_test.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/go/vt/worker/result_merger_test.go b/go/vt/worker/result_merger_test.go index b5ebb3c63d1..4fe9dd19c66 100644 --- a/go/vt/worker/result_merger_test.go +++ b/go/vt/worker/result_merger_test.go @@ -354,6 +354,13 @@ func TestResultMerger(t *testing.T) { } inner.Fatalf("ResultMerger testcase '%v' failed. See output above for different rows.", tc.desc) } + + for _, x := range tc.inputs { + fake := x.(*fakeResultReader) + if !fake.closed { + inner.Fatal("expected inputs to be closed by now") + } + } }) } } From fe6ab9c59bd234868729aa22d1b4305e83c79873 Mon Sep 17 00:00:00 2001 From: Toliver Jue Date: Mon, 4 Feb 2019 17:30:20 -0800 Subject: [PATCH 017/196] Change CRC32 usage from zlib -> native go hash/crc32 Signed-off-by: Toliver Jue --- go/cgzip/adler32.go | 79 ---------- go/cgzip/cgzip_test.go | 276 --------------------------------- go/cgzip/crc32.go | 79 ---------- go/cgzip/doc.go | 18 --- go/cgzip/eof_read_test.go | 90 ----------- go/cgzip/pure.go | 22 --- go/cgzip/reader.go | 119 -------------- go/cgzip/testdata/cgzip_eof.gz | Bin 55787 -> 0 bytes go/cgzip/writer.go | 158 ------------------- go/cgzip/zstream.go | 177 --------------------- go/vt/mysqlctl/fileutil.go | 37 +---- 11 files changed, 4 insertions(+), 1051 deletions(-) delete mode 100644 go/cgzip/adler32.go delete mode 100644 go/cgzip/cgzip_test.go delete mode 100644 go/cgzip/crc32.go delete mode 100644 go/cgzip/doc.go delete mode 100644 go/cgzip/eof_read_test.go delete mode 100644 go/cgzip/pure.go delete mode 100644 go/cgzip/reader.go delete mode 100644 go/cgzip/testdata/cgzip_eof.gz delete mode 100644 go/cgzip/writer.go delete mode 100644 go/cgzip/zstream.go diff --git a/go/cgzip/adler32.go b/go/cgzip/adler32.go deleted file mode 100644 index 87ca8e17588..00000000000 --- a/go/cgzip/adler32.go +++ /dev/null @@ -1,79 +0,0 @@ -// +build cgo - -/* -Copyright 2017 Google Inc. - -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 cgzip - -/* -#cgo CFLAGS: -Werror=implicit -#cgo pkg-config: zlib - -#include "zlib.h" -*/ -import "C" - -import ( - "hash" - "unsafe" -) - -type adler32Hash struct { - adler C.uLong -} - -// NewAdler32 creates an empty buffer which has an adler32 of '1'. The go -// hash/adler32 does the same. -func NewAdler32() hash.Hash32 { - a := &adler32Hash{} - a.Reset() - return a -} - -// io.Writer interface -func (a *adler32Hash) Write(p []byte) (n int, err error) { - if len(p) > 0 { - a.adler = C.adler32(a.adler, (*C.Bytef)(unsafe.Pointer(&p[0])), (C.uInt)(len(p))) - } - return len(p), nil -} - -// hash.Hash interface -func (a *adler32Hash) Sum(b []byte) []byte { - s := a.Sum32() - b = append(b, byte(s>>24)) - b = append(b, byte(s>>16)) - b = append(b, byte(s>>8)) - b = append(b, byte(s)) - return b -} - -func (a *adler32Hash) Reset() { - a.adler = C.adler32(0, (*C.Bytef)(unsafe.Pointer(nil)), 0) -} - -func (a *adler32Hash) Size() int { - return 4 -} - -func (a *adler32Hash) BlockSize() int { - return 1 -} - -// hash.Hash32 interface -func (a *adler32Hash) Sum32() uint32 { - return uint32(a.adler) -} diff --git a/go/cgzip/cgzip_test.go b/go/cgzip/cgzip_test.go deleted file mode 100644 index b3e4e621842..00000000000 --- a/go/cgzip/cgzip_test.go +++ /dev/null @@ -1,276 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 agreedto 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 cgzip - -import ( - "bytes" - "compress/gzip" - "fmt" - "hash/adler32" - "hash/crc32" - "hash/crc64" - "io" - "math/rand" - "os/exec" - "sync" - "testing" - "time" -) - -type prettyTimer struct { - name string - before time.Time -} - -func newPrettyTimer(name string) *prettyTimer { - return &prettyTimer{name, time.Now()} -} - -func (pt *prettyTimer) stopAndPrintCompress(t *testing.T, size, processed int) { - duration := time.Since(pt.before) - t.Log(pt.name + ":") - t.Log(" size :", size) - t.Log(" time :", duration.String()) - if duration != 0 { - t.Logf(" speed: %.0f KB/s", float64(processed)/duration.Seconds()/1024.0) - } else { - t.Log(" processed:", processed, "B") - } -} - -func (pt *prettyTimer) stopAndPrintUncompress(t *testing.T, processed int) { - duration := time.Since(pt.before) - t.Log(" " + pt.name + ":") - t.Log(" time :", duration.String()) - if duration != 0 { - t.Logf(" speed: %.0f KB/s", float64(processed)/duration.Seconds()/1024.0) - } else { - t.Log(" processed:", processed, "B") - } -} - -func compareCompressedBuffer(t *testing.T, source []byte, compressed *bytes.Buffer) { - // compare using go's gunzip - toGunzip := bytes.NewBuffer(compressed.Bytes()) - gunzip, err := gzip.NewReader(toGunzip) - if err != nil { - t.Errorf("gzip.NewReader failed: %v", err) - } - uncompressed := &bytes.Buffer{} - pt := newPrettyTimer("go unzip") - _, err = io.Copy(uncompressed, gunzip) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - pt.stopAndPrintUncompress(t, uncompressed.Len()) - if !bytes.Equal(source, uncompressed.Bytes()) { - t.Errorf("Bytes are not equal") - } - - // compare using cgzip gunzip - toGunzip = bytes.NewBuffer(compressed.Bytes()) - cgunzip, err := NewReader(toGunzip) - if err != nil { - t.Errorf("cgzip.NewReader failed: %v", err) - } - uncompressed = &bytes.Buffer{} - pt = newPrettyTimer("cgzip unzip") - _, err = io.Copy(uncompressed, cgunzip) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - pt.stopAndPrintUncompress(t, uncompressed.Len()) - if !bytes.Equal(source, uncompressed.Bytes()) { - t.Errorf("Bytes are not equal") - } -} - -func testChecksums(t *testing.T, data []byte) { - t.Log("Checksums:") - - // crc64 with go library - goCrc64 := crc64.New(crc64.MakeTable(crc64.ECMA)) - toChecksum := bytes.NewBuffer(data) - pt := newPrettyTimer("go crc64") - _, err := io.Copy(goCrc64, toChecksum) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - pt.stopAndPrintUncompress(t, len(data)) - - // adler32 with go library - goAdler32 := adler32.New() - toChecksum = bytes.NewBuffer(data) - pt = newPrettyTimer("go adler32") - _, err = io.Copy(goAdler32, toChecksum) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - goResult := goAdler32.Sum32() - pt.stopAndPrintUncompress(t, len(data)) - t.Log(" sum :", goResult) - - // adler32 with cgzip library - cgzipAdler32 := NewAdler32() - toChecksum = bytes.NewBuffer(data) - pt = newPrettyTimer("cgzip adler32") - _, err = io.Copy(cgzipAdler32, toChecksum) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - cgzipResult := cgzipAdler32.Sum32() - pt.stopAndPrintUncompress(t, len(data)) - t.Log(" sum :", cgzipResult) - - // test both results are the same - if goResult != cgzipResult { - t.Errorf("go and cgzip adler32 mismatch") - } - - // crc32 with go library - goCrc32 := crc32.New(crc32.MakeTable(crc32.IEEE)) - toChecksum = bytes.NewBuffer(data) - pt = newPrettyTimer("go crc32") - _, err = io.Copy(goCrc32, toChecksum) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - goResult = goCrc32.Sum32() - pt.stopAndPrintUncompress(t, len(data)) - t.Log(" sum :", goResult) - - // crc32 with cgzip library - cgzipCrc32 := NewCrc32() - toChecksum = bytes.NewBuffer(data) - pt = newPrettyTimer("cgzip crc32") - _, err = io.Copy(cgzipCrc32, toChecksum) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - cgzipResult = cgzipCrc32.Sum32() - pt.stopAndPrintUncompress(t, len(data)) - t.Log(" sum :", cgzipResult) - - // test both results are the same - if goResult != cgzipResult { - t.Errorf("go and cgzip crc32 mismatch") - } -} - -func runCompare(t *testing.T, testSize int, level int) { - - // create a test chunk, put semi-random bytes in there - // (so compression actually will compress some) - toEncode := make([]byte, testSize) - where := 0 - for where < testSize { - toFill := rand.Intn(16) - filler := 0x61 + rand.Intn(24) - for i := 0; i < toFill && where < testSize; i++ { - toEncode[where] = byte(filler) - where++ - } - } - t.Log("Original size:", len(toEncode)) - - // now time a regular gzip writer to a Buffer - compressed := &bytes.Buffer{} - reader := bytes.NewBuffer(toEncode) - pt := newPrettyTimer("Go gzip") - gz, err := gzip.NewWriterLevel(compressed, level) - _, err = io.Copy(gz, reader) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - gz.Close() - pt.stopAndPrintCompress(t, compressed.Len(), len(toEncode)) - compareCompressedBuffer(t, toEncode, compressed) - - // now time a forked gzip - compressed2 := &bytes.Buffer{} - reader = bytes.NewBuffer(toEncode) - cmd := exec.Command("gzip", fmt.Sprintf("-%v", level), "-c") - stdout, err := cmd.StdoutPipe() - if err != nil { - t.Errorf("StdoutPipe failed: %v", err) - } - stdin, err := cmd.StdinPipe() - if err != nil { - t.Errorf("StdinPipe failed: %v", err) - } - wg := sync.WaitGroup{} - wg.Add(1) - go func() { - io.Copy(compressed2, stdout) - wg.Done() - }() - if err = cmd.Start(); err != nil { - t.Errorf("Start failed: %v", err) - } - pt = newPrettyTimer("Forked gzip") - _, err = io.Copy(stdin, reader) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - stdin.Close() - wg.Wait() - if err := cmd.Wait(); err != nil { - t.Errorf("Wait failed: %v", err) - } - pt.stopAndPrintCompress(t, compressed2.Len(), len(toEncode)) - compareCompressedBuffer(t, toEncode, compressed2) - - // and time the cgo version - compressed3 := &bytes.Buffer{} - reader = bytes.NewBuffer(toEncode) - pt = newPrettyTimer("cgzip") - cgz, err := NewWriterLevel(compressed3, level) - if err != nil { - t.Errorf("NewWriterLevel failed: %v", err) - } - _, err = io.Copy(cgz, reader) - if err != nil { - t.Errorf("Copy failed: %v", err) - } - if err := cgz.Flush(); err != nil { - t.Errorf("Flush failed: %v", err) - } - if err := cgz.Close(); err != nil { - t.Errorf("Close failed: %v", err) - } - pt.stopAndPrintCompress(t, compressed3.Len(), len(toEncode)) - compareCompressedBuffer(t, toEncode, compressed3) - - testChecksums(t, toEncode) -} - -// use 'go test -v' and bigger sizes to show meaningful rates -func TestCompare(t *testing.T) { - testSize := 1 * 1024 * 1024 - if testing.Short() { - testSize /= 10 - } - runCompare(t, testSize, 1) -} - -func TestCompareBest(t *testing.T) { - testSize := 1 * 1024 * 1024 - if testing.Short() { - testSize /= 10 - } - runCompare(t, testSize, 9) -} diff --git a/go/cgzip/crc32.go b/go/cgzip/crc32.go deleted file mode 100644 index 182e2eec7b7..00000000000 --- a/go/cgzip/crc32.go +++ /dev/null @@ -1,79 +0,0 @@ -// +build cgo - -/* -Copyright 2017 Google Inc. - -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 cgzip - -/* -#cgo CFLAGS: -Werror=implicit -#cgo pkg-config: zlib - -#include "zlib.h" -*/ -import "C" - -import ( - "hash" - "unsafe" -) - -type crc32Hash struct { - crc C.uLong -} - -// NewCrc32 creates an empty buffer which has an crc32 of '1'. The go -// hash/crc32 does the same. -func NewCrc32() hash.Hash32 { - c := &crc32Hash{} - c.Reset() - return c -} - -// io.Writer interface -func (a *crc32Hash) Write(p []byte) (n int, err error) { - if len(p) > 0 { - a.crc = C.crc32(a.crc, (*C.Bytef)(unsafe.Pointer(&p[0])), (C.uInt)(len(p))) - } - return len(p), nil -} - -// hash.Hash interface -func (a *crc32Hash) Sum(b []byte) []byte { - s := a.Sum32() - b = append(b, byte(s>>24)) - b = append(b, byte(s>>16)) - b = append(b, byte(s>>8)) - b = append(b, byte(s)) - return b -} - -func (a *crc32Hash) Reset() { - a.crc = C.crc32(0, (*C.Bytef)(unsafe.Pointer(nil)), 0) -} - -func (a *crc32Hash) Size() int { - return 4 -} - -func (a *crc32Hash) BlockSize() int { - return 1 -} - -// hash.Hash32 interface -func (a *crc32Hash) Sum32() uint32 { - return uint32(a.crc) -} diff --git a/go/cgzip/doc.go b/go/cgzip/doc.go deleted file mode 100644 index 2f501d6c3a0..00000000000 --- a/go/cgzip/doc.go +++ /dev/null @@ -1,18 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 cgzip wraps the C library for gzip. -package cgzip diff --git a/go/cgzip/eof_read_test.go b/go/cgzip/eof_read_test.go deleted file mode 100644 index e884b324527..00000000000 --- a/go/cgzip/eof_read_test.go +++ /dev/null @@ -1,90 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 agreedto 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 cgzip - -import ( - "io" - "io/ioutil" - "testing" -) - -// specialReader is a test class that will return bytes it reads from a file, -// returning EOF and data in the last chunk. -type specialReader struct { - t *testing.T - contents []byte - sent int -} - -func newSpecialReader(t *testing.T, filename string) *specialReader { - b, err := ioutil.ReadFile(filename) - if err != nil { - t.Fatalf("Cannot read file %v: %v", filename, err) - } - return &specialReader{t, b, 0} -} - -// Read is the implementation of Reader -func (sr *specialReader) Read(p []byte) (int, error) { - if len(p) > len(sr.contents)-sr.sent { - toCopy := len(sr.contents) - sr.sent - sr.t.Logf("Sending %v bytes and EOF", toCopy) - sr.sent += copy(p, sr.contents[sr.sent:]) - return toCopy, io.EOF - } - toCopy := len(p) - sr.sent += copy(p, sr.contents[sr.sent:sr.sent+toCopy]) - sr.t.Logf("Sending %v bytes", toCopy) - return toCopy, nil -} - -// TestEofAndData is the main test here: if we return data and EOF, -// it needs to be fully processed. -// The file is a 55k file, that uncompresses into a 10 MB file. -// So it will be read as 32k + 22k, and decompressed into 2MB + 2MB + 1M and -// then 2MB + 2MB + 1M again. So it's a great test for corner cases. -func TestEofAndData(t *testing.T) { - r := newSpecialReader(t, "testdata/cgzip_eof.gz") - gz, err := NewReader(r) - if err != nil { - t.Fatalf("NewReader failed: %v", err) - } - - n := 0 - dst := make([]byte, 2*1024*1024) - for { - nRead, err := gz.Read(dst) - t.Logf("Got: %v %v", nRead, err) - n += nRead - switch err { - case nil: - case io.EOF: - if n != 10485760 { - t.Fatalf("Read wrong number of bytes: got %v expected 10485760", n) - } - - // test we also get 0 / EOF if we read again - nRead, err = gz.Read(dst) - if nRead != 0 || err != io.EOF { - t.Fatalf("After-EOF read got %v %v", nRead, err) - } - return - default: - t.Fatalf("Unexpected error: %v", err) - } - } -} diff --git a/go/cgzip/pure.go b/go/cgzip/pure.go deleted file mode 100644 index 55221f786a8..00000000000 --- a/go/cgzip/pure.go +++ /dev/null @@ -1,22 +0,0 @@ -// +build !cgo - -// A slower, pure go alternative to cgzip to allow for cross compilation. - -package cgzip - -import ( - "compress/gzip" - "hash/adler32" - "hash/crc32" -) - -// Writer is an io.WriteCloser. Writes to a Writer are compressed. -type Writer = gzip.Writer - -var ( - Z_BEST_SPEED = gzip.BestSpeed - NewWriterLevel = gzip.NewWriterLevel - NewReader = gzip.NewReader - NewCrc32 = crc32.NewIEEE - NewAdler32 = adler32.New -) diff --git a/go/cgzip/reader.go b/go/cgzip/reader.go deleted file mode 100644 index 4766976c5b4..00000000000 --- a/go/cgzip/reader.go +++ /dev/null @@ -1,119 +0,0 @@ -// +build cgo - -/* -Copyright 2017 Google Inc. - -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 cgzip - -import "io" - -// err starts out as nil -// we will call inflateEnd when we set err to a value: -// - whatever error is returned by the underlying reader -// - io.EOF if Close was called -type reader struct { - r io.Reader - in []byte - strm zstream - err error - skipIn bool -} - -// NewReader returns a new cgzip.reader for reading gzip files with the C gzip -// library. -func NewReader(r io.Reader) (io.ReadCloser, error) { - return NewReaderBuffer(r, DEFAULT_COMPRESSED_BUFFER_SIZE) -} - -// NewReaderBuffer returns a new cgzip.reader with a given buffer size for -// reading gzip files with the C gzip library. -func NewReaderBuffer(r io.Reader, bufferSize int) (io.ReadCloser, error) { - z := &reader{r: r, in: make([]byte, bufferSize)} - if err := z.strm.inflateInit(); err != nil { - return nil, err - } - return z, nil -} - -// Read reads from the gz stream. -func (z *reader) Read(p []byte) (int, error) { - if z.err != nil { - return 0, z.err - } - - if len(p) == 0 { - return 0, nil - } - - // read and deflate until the output buffer is full - z.strm.setOutBuf(p, len(p)) - - for { - // if we have no data to inflate, read more - if !z.skipIn && z.strm.availIn() == 0 { - var n int - n, z.err = z.r.Read(z.in) - // If we got data and EOF, pretend we didn't get the - // EOF. That way we will return the right values - // upstream. Note this will trigger another read - // later on, that should return (0, EOF). - if n > 0 && z.err == io.EOF { - z.err = nil - } - - // FIXME(alainjobart) this code is not compliant with - // the Reader interface. We should process all the - // data we got from the reader, and then return the - // error, whatever it is. - if (z.err != nil && z.err != io.EOF) || (n == 0 && z.err == io.EOF) { - z.strm.inflateEnd() - return 0, z.err - } - - z.strm.setInBuf(z.in, n) - } else { - z.skipIn = false - } - - // inflate some - ret, err := z.strm.inflate(zNoFlush) - if err != nil { - z.err = err - z.strm.inflateEnd() - return 0, z.err - } - - // if we read something, we're good - have := len(p) - z.strm.availOut() - if have > 0 { - z.skipIn = ret == Z_OK && z.strm.availOut() == 0 - return have, z.err - } - } -} - -// Close closes the Reader. It does not close the underlying io.Reader. -func (z *reader) Close() error { - if z.err != nil { - if z.err != io.EOF { - return z.err - } - return nil - } - z.strm.inflateEnd() - z.err = io.EOF - return nil -} diff --git a/go/cgzip/testdata/cgzip_eof.gz b/go/cgzip/testdata/cgzip_eof.gz deleted file mode 100644 index 019e9f190b971eb560644486d229932efd4e4c48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 55787 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 0 { - var n int - n, z.err = z.w.Write(z.out[from:have]) - if z.err != nil { - z.strm.deflateEnd() - return 0 - } - from += n - have -= n - } - - // we stop trying if we get a partial response - if z.strm.availOut() != 0 { - break - } - } - // the library guarantees this - if z.strm.availIn() != 0 { - panic(fmt.Errorf("cgzip: Unexpected error (2)")) - } - return len(p) -} - -func (z *Writer) Write(p []byte) (n int, err error) { - if z.err != nil { - return 0, z.err - } - n = z.write(p, Z_NO_FLUSH) - return n, z.err -} - -func (z *Writer) Flush() error { - if z.err != nil { - return z.err - } - z.write(nil, Z_SYNC_FLUSH) - return z.err -} - -// Calling Close does not close the wrapped io.Writer originally -// passed to NewWriterX. -func (z *Writer) Close() error { - if z.err != nil { - return z.err - } - z.write(nil, Z_FINISH) - if z.err != nil { - return z.err - } - z.strm.deflateEnd() - z.err = io.EOF - return nil -} diff --git a/go/cgzip/zstream.go b/go/cgzip/zstream.go deleted file mode 100644 index a336b54959b..00000000000 --- a/go/cgzip/zstream.go +++ /dev/null @@ -1,177 +0,0 @@ -// +build cgo - -/* -Copyright 2017 Google Inc. - -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 cgzip - -// See http://www.zlib.net/zlib_how.html for more information on this - -/* -#cgo CFLAGS: -Werror=implicit -#cgo pkg-config: zlib - -#include "zlib.h" - -// inflateInit2 is a macro, so using a wrapper function -int zstream_inflate_init(char *strm) { - ((z_stream*)strm)->zalloc = Z_NULL; - ((z_stream*)strm)->zfree = Z_NULL; - ((z_stream*)strm)->opaque = Z_NULL; - ((z_stream*)strm)->avail_in = 0; - ((z_stream*)strm)->next_in = Z_NULL; - return inflateInit2((z_stream*)strm, - 16+15); // 16 makes it understand only gzip files -} - -// deflateInit2 is a macro, so using a wrapper function -// using deflateInit2 instead of deflateInit to be able to specify gzip format -int zstream_deflate_init(char *strm, int level) { - ((z_stream*)strm)->zalloc = Z_NULL; - ((z_stream*)strm)->zfree = Z_NULL; - ((z_stream*)strm)->opaque = Z_NULL; - return deflateInit2((z_stream*)strm, level, Z_DEFLATED, - 16+15, // 16 makes it a gzip file, 15 is default - 8, Z_DEFAULT_STRATEGY); // default values -} - -unsigned int zstream_avail_in(char *strm) { - return ((z_stream*)strm)->avail_in; -} - -unsigned int zstream_avail_out(char *strm) { - return ((z_stream*)strm)->avail_out; -} - -char* zstream_msg(char *strm) { - return ((z_stream*)strm)->msg; -} - -void zstream_set_in_buf(char *strm, void *buf, unsigned int len) { - ((z_stream*)strm)->next_in = (Bytef*)buf; - ((z_stream*)strm)->avail_in = len; -} - -void zstream_set_out_buf(char *strm, void *buf, unsigned int len) { - ((z_stream*)strm)->next_out = (Bytef*)buf; - ((z_stream*)strm)->avail_out = len; -} - -int zstream_inflate(char *strm, int flag) { - return inflate((z_stream*)strm, flag); -} - -int zstream_deflate(char *strm, int flag) { - return deflate((z_stream*)strm, flag); -} - -void zstream_inflate_end(char *strm) { - inflateEnd((z_stream*)strm); -} - -void zstream_deflate_end(char *strm) { - deflateEnd((z_stream*)strm); -} -*/ -import "C" - -import ( - "fmt" - "unsafe" -) - -const ( - zNoFlush = C.Z_NO_FLUSH -) - -// z_stream is a buffer that's big enough to fit a C.z_stream. -// This lets us allocate a C.z_stream within Go, while keeping the contents -// opaque to the Go GC. Otherwise, the GC would look inside and complain that -// the pointers are invalid, since they point to objects allocated by C code. -type zstream [unsafe.Sizeof(C.z_stream{})]C.char - -func (strm *zstream) inflateInit() error { - result := C.zstream_inflate_init(&strm[0]) - if result != Z_OK { - return fmt.Errorf("cgzip: failed to initialize inflate (%v): %v", result, strm.msg()) - } - return nil -} - -func (strm *zstream) deflateInit(level int) error { - result := C.zstream_deflate_init(&strm[0], C.int(level)) - if result != Z_OK { - return fmt.Errorf("cgzip: failed to initialize deflate (%v): %v", result, strm.msg()) - } - return nil -} - -func (strm *zstream) inflateEnd() { - C.zstream_inflate_end(&strm[0]) -} - -func (strm *zstream) deflateEnd() { - C.zstream_deflate_end(&strm[0]) -} - -func (strm *zstream) availIn() int { - return int(C.zstream_avail_in(&strm[0])) -} - -func (strm *zstream) availOut() int { - return int(C.zstream_avail_out(&strm[0])) -} - -func (strm *zstream) msg() string { - return C.GoString(C.zstream_msg(&strm[0])) -} - -func (strm *zstream) setInBuf(buf []byte, size int) { - if buf == nil { - C.zstream_set_in_buf(&strm[0], nil, C.uint(size)) - } else { - C.zstream_set_in_buf(&strm[0], unsafe.Pointer(&buf[0]), C.uint(size)) - } -} - -func (strm *zstream) setOutBuf(buf []byte, size int) { - if buf == nil { - C.zstream_set_out_buf(&strm[0], nil, C.uint(size)) - } else { - C.zstream_set_out_buf(&strm[0], unsafe.Pointer(&buf[0]), C.uint(size)) - } -} - -func (strm *zstream) inflate(flag int) (int, error) { - ret := C.zstream_inflate(&strm[0], C.int(flag)) - switch ret { - case Z_NEED_DICT: - ret = Z_DATA_ERROR - fallthrough - case Z_DATA_ERROR, Z_MEM_ERROR: - return int(ret), fmt.Errorf("cgzip: failed to inflate (%v): %v", ret, strm.msg()) - } - return int(ret), nil -} - -func (strm *zstream) deflate(flag int) { - ret := C.zstream_deflate(&strm[0], C.int(flag)) - if ret == Z_STREAM_ERROR { - // all the other error cases are normal, - // and this should never happen - panic(fmt.Errorf("cgzip: Unexpected error (1)")) - } -} diff --git a/go/vt/mysqlctl/fileutil.go b/go/vt/mysqlctl/fileutil.go index b5aee7f1000..331b6378785 100644 --- a/go/vt/mysqlctl/fileutil.go +++ b/go/vt/mysqlctl/fileutil.go @@ -1,5 +1,5 @@ /* -Copyright 2017 Google Inc. +Copyright 2018 The Vitess Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -17,13 +17,10 @@ limitations under the License. package mysqlctl import ( - // "crypto/md5" "encoding/hex" "hash" - // "hash/crc64" + "hash/crc32" "os" - - "vitess.io/vitess/go/cgzip" ) // Use this to simulate failures in tests @@ -36,39 +33,13 @@ func init() { simulateFailures = statErr == nil } -// our hasher, implemented using md5 -// type hasher struct { -// hash.Hash -// } - -// func newHasher() *hasher { -// return &hasher{md5.New()} -// } - -// func (h *hasher) HashString() string { -// return hex.EncodeToString(h.Sum(nil)) -// } - -// our hasher, implemented using crc64 -//type hasher struct { -// hash.Hash64 -//} - -//func newHasher() *hasher { -// return &hasher{crc64.New(crc64.MakeTable(crc64.ECMA))} -//} - -//func (h *hasher) HashString() string { -// return hex.EncodeToString(h.Sum(nil)) -//} - -// our hasher, implemented using cgzip crc32 +// our hasher, implemented using crc32 type hasher struct { hash.Hash32 } func newHasher() *hasher { - return &hasher{cgzip.NewCrc32()} + return &hasher{crc32.NewIEEE()} } func (h *hasher) HashString() string { From 4085cceeb6224725ba623c98b72633ba13673934 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Tue, 5 Feb 2019 12:12:39 -0500 Subject: [PATCH 018/196] shutdown channel cleanly Signed-off-by: Ze'ev Klapow --- .../io/vitess/client/grpc/GrpcClient.java | 26 +++++++++++++++++-- .../vitess/client/grpc/GrpcClientFactory.java | 4 +-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java index feb50bcdeca..61485b38b3b 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java @@ -81,23 +81,36 @@ * GrpcClient is a gRPC-based implementation of Vitess RpcClient. */ public class GrpcClient implements RpcClient { + private static final Duration DEFAULT_TIMEOUT = Duration.standardSeconds(30); + private final ManagedChannel channel; private final String channelId; private final VitessStub asyncStub; private final VitessFutureStub futureStub; + private final Duration timeout; public GrpcClient(ManagedChannel channel) { this.channel = channel; channelId = toChannelId(channel); asyncStub = VitessGrpc.newStub(channel); futureStub = VitessGrpc.newFutureStub(channel); + timeout = DEFAULT_TIMEOUT; + } + + public GrpcClient(ManagedChannel channel, Context context) { + this.channel = channel; + channelId = toChannelId(channel); + asyncStub = VitessGrpc.newStub(channel); + futureStub = VitessGrpc.newFutureStub(channel); + timeout = context.getTimeout() != null ? context.getTimeout() : DEFAULT_TIMEOUT; } - public GrpcClient(ManagedChannel channel, CallCredentials credentials) { + public GrpcClient(ManagedChannel channel, CallCredentials credentials, Context context) { this.channel = channel; channelId = toChannelId(channel); asyncStub = VitessGrpc.newStub(channel).withCallCredentials(credentials); futureStub = VitessGrpc.newFutureStub(channel).withCallCredentials(credentials); + timeout = context.getTimeout() != null ? context.getTimeout() : DEFAULT_TIMEOUT; } private String toChannelId(ManagedChannel channel) { @@ -107,7 +120,16 @@ private String toChannelId(ManagedChannel channel) { @Override public void close() throws IOException { - channel.shutdown(); + try { + if (!channel.shutdown().awaitTermination(timeout.getStandardSeconds(), TimeUnit.SECONDS)) { + // The channel failed to shut down cleanly within the specified window + // Now we try hard shutdown + channel.shutdownNow(); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } @Override diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 928c29334ee..61e30711c75 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -98,7 +98,7 @@ public RpcClient create(Context ctx, String target) { channel.nameResolverFactory(nameResolverFactory); } return callCredentials != null ? - new GrpcClient(channel.build(), callCredentials) : new GrpcClient(channel.build()); + new GrpcClient(channel.build(), callCredentials, ctx) : new GrpcClient(channel.build(), ctx); } /** @@ -174,7 +174,7 @@ public RpcClient createTls(Context ctx, String target, TlsOptions tlsOptions) { } return new GrpcClient( - channelBuilder(target).negotiationType(NegotiationType.TLS).sslContext(sslContext).intercept(new RetryingInterceptor(config)).build()); + channelBuilder(target).negotiationType(NegotiationType.TLS).sslContext(sslContext).intercept(new RetryingInterceptor(config)).build(), ctx); } /** From add6111f4382bbf63b6bbfcbf229de58cab36805 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Tue, 5 Feb 2019 12:06:30 -0800 Subject: [PATCH 019/196] Close result readers correctly Signed-off-by: Andres Taylor --- go/vt/worker/split_clone.go | 40 ++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/go/vt/worker/split_clone.go b/go/vt/worker/split_clone.go index 3f4369eb976..bead11591cf 100644 --- a/go/vt/worker/split_clone.go +++ b/go/vt/worker/split_clone.go @@ -912,25 +912,32 @@ func mergeOrSingle(readers []ResultReader, td *tabletmanagerdatapb.TableDefiniti return sourceReader, nil } +func closeReaders(ctx context.Context, readers []ResultReader) { + for _, reader := range readers { + if reader != nil { + reader.Close(ctx) + } + } +} + func (scw *SplitCloneWorker) getSourceResultReader(ctx context.Context, td *tabletmanagerdatapb.TableDefinition, state StatusWorkerState, chunk chunk, txID int64) (ResultReader, error) { sourceReaders := make([]ResultReader, len(scw.sourceShards)) - var readers []ResultReader - defer func() { - for _, i := range readers { - i.Close(ctx) - } - }() for shardIndex, si := range scw.sourceShards { var sourceResultReader ResultReader - var err error if state == WorkerStateCloneOffline && scw.useConsistentSnapshot { + var err error if txID < 1 { return nil, fmt.Errorf("tried using consistent snapshot without a valid transaction") } tp := newShardTabletProvider(scw.tsc, scw.tabletTracker, si.Keyspace(), si.ShardName(), scw.tabletType) sourceResultReader, err = NewTransactionalRestartableResultReader(ctx, scw.wr.Logger(), tp, td, chunk, false, txID) + if err != nil { + closeReaders(ctx, sourceReaders) + return nil, fmt.Errorf("NewTransactionalRestartableResultReader for source: %v failed: %v", tp.description(), err) + } } else { + var err error var tp tabletProvider allowMultipleRetries := true if state == WorkerStateCloneOffline { @@ -946,39 +953,36 @@ func (scw *SplitCloneWorker) getSourceResultReader(ctx context.Context, td *tabl } sourceResultReader, err = NewRestartableResultReader(ctx, scw.wr.Logger(), tp, td, chunk, allowMultipleRetries) if err != nil { + closeReaders(ctx, sourceReaders) return nil, fmt.Errorf("NewRestartableResultReader for source: %v failed: %v", tp.description(), err) } - readers = append(readers, sourceResultReader) } sourceReaders[shardIndex] = sourceResultReader } resultReader, err := mergeOrSingle(sourceReaders, td) - if err == nil { - readers = readers[:0] + if err != nil { + closeReaders(ctx, sourceReaders) + return nil, err } return resultReader, err } func (scw *SplitCloneWorker) getDestinationResultReader(ctx context.Context, td *tabletmanagerdatapb.TableDefinition, state StatusWorkerState, chunk chunk) (ResultReader, error) { destReaders := make([]ResultReader, len(scw.destinationShards)) - var readers []ResultReader - defer func() { - for _, i := range readers { - i.Close(ctx) - } - }() for shardIndex, si := range scw.destinationShards { tp := newShardTabletProvider(scw.tsc, scw.tabletTracker, si.Keyspace(), si.ShardName(), topodatapb.TabletType_MASTER) destResultReader, err := NewRestartableResultReader(ctx, scw.wr.Logger(), tp, td, chunk, true /* allowMultipleRetries */) if err != nil { + closeReaders(ctx, destReaders) return nil, fmt.Errorf("NewRestartableResultReader for destination: %v failed: %v", tp.description(), err) } destReaders[shardIndex] = destResultReader } resultReader, err := mergeOrSingle(destReaders, td) - if err == nil { - readers = readers[:0] + if err != nil { + closeReaders(ctx, destReaders) + return nil, err } return resultReader, err } From 196cf77dd0dd9392932f0d311cca6cf8596bcd35 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Mon, 7 Jan 2019 13:15:48 -0800 Subject: [PATCH 020/196] Move serving state from global topo to srv keyspace Initial stab at: https://github.com/vitessio/vitess/issues/4496 Signed-off-by: Rafael Chacon --- go/vt/proto/topodata/topodata.pb.go | 358 ++++++------- go/vt/topo/cell_info.go | 20 +- go/vt/topo/helpers/compare.go | 13 +- go/vt/topo/helpers/copy.go | 14 +- go/vt/topo/shard.go | 241 ++++----- go/vt/topo/srv_keyspace.go | 312 ++++++++++++ go/vt/topo/topoproto/shard.go | 10 - go/vt/topotools/rebuild_keyspace.go | 96 +--- go/vt/vtctl/vtctl.go | 5 +- go/vt/vttablet/tabletmanager/init_tablet.go | 16 - go/vt/vttablet/tabletmanager/state_change.go | 21 +- go/vt/worker/legacy_split_clone.go | 27 +- go/vt/worker/split_clone.go | 44 +- .../reshardingworkflowgen/workflow.go | 6 +- go/vt/wrangler/keyspace.go | 70 ++- go/vt/wrangler/shard.go | 90 ++-- go/vt/wrangler/tablet.go | 2 +- proto/topodata.proto | 39 +- py/vtproto/topodata_pb2.py | 198 +++---- py/vtproto/vtgate_pb2.py | 481 +++++++++--------- 20 files changed, 1164 insertions(+), 899 deletions(-) diff --git a/go/vt/proto/topodata/topodata.pb.go b/go/vt/proto/topodata/topodata.pb.go index 504f39b0eaf..15392dced19 100644 --- a/go/vt/proto/topodata/topodata.pb.go +++ b/go/vt/proto/topodata/topodata.pb.go @@ -48,7 +48,7 @@ func (x KeyspaceIdType) String() string { return proto.EnumName(KeyspaceIdType_name, int32(x)) } func (KeyspaceIdType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{0} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{0} } // TabletType represents the type of a given tablet. @@ -117,7 +117,7 @@ func (x TabletType) String() string { return proto.EnumName(TabletType_name, int32(x)) } func (TabletType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{1} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{1} } // KeyRange describes a range of sharding keys, when range-based @@ -134,7 +134,7 @@ func (m *KeyRange) Reset() { *m = KeyRange{} } func (m *KeyRange) String() string { return proto.CompactTextString(m) } func (*KeyRange) ProtoMessage() {} func (*KeyRange) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{0} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{0} } func (m *KeyRange) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyRange.Unmarshal(m, b) @@ -184,7 +184,7 @@ func (m *TabletAlias) Reset() { *m = TabletAlias{} } func (m *TabletAlias) String() string { return proto.CompactTextString(m) } func (*TabletAlias) ProtoMessage() {} func (*TabletAlias) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{1} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{1} } func (m *TabletAlias) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletAlias.Unmarshal(m, b) @@ -260,7 +260,7 @@ func (m *Tablet) Reset() { *m = Tablet{} } func (m *Tablet) String() string { return proto.CompactTextString(m) } func (*Tablet) ProtoMessage() {} func (*Tablet) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{2} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{2} } func (m *Tablet) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Tablet.Unmarshal(m, b) @@ -372,29 +372,26 @@ type Shard struct { // helpful to have it decomposed here. // Once set at creation time, it is never changed. KeyRange *KeyRange `protobuf:"bytes,2,opt,name=key_range,json=keyRange,proto3" json:"key_range,omitempty"` - // served_types has at most one entry per TabletType - // The keyspace lock is always taken when changing this. - ServedTypes []*Shard_ServedType `protobuf:"bytes,3,rep,name=served_types,json=servedTypes,proto3" json:"served_types,omitempty"` // SourceShards is the list of shards we're replicating from, // using filtered replication. // The keyspace lock is always taken when changing this. SourceShards []*Shard_SourceShard `protobuf:"bytes,4,rep,name=source_shards,json=sourceShards,proto3" json:"source_shards,omitempty"` - // Cells is the list of cells that contain tablets for this shard. - // No lock is necessary to update this field. - Cells []string `protobuf:"bytes,5,rep,name=cells,proto3" json:"cells,omitempty"` // tablet_controls has at most one entry per TabletType. // The keyspace lock is always taken when changing this. - TabletControls []*Shard_TabletControl `protobuf:"bytes,6,rep,name=tablet_controls,json=tabletControls,proto3" json:"tablet_controls,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + TabletControls []*Shard_TabletControl `protobuf:"bytes,6,rep,name=tablet_controls,json=tabletControls,proto3" json:"tablet_controls,omitempty"` + // is_master_serving sets whether this shard master is serving traffic or not. + // The keyspace lock is always taken when changing this. + IsMasterServing bool `protobuf:"varint,7,opt,name=is_master_serving,json=isMasterServing,proto3" json:"is_master_serving,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Shard) Reset() { *m = Shard{} } func (m *Shard) String() string { return proto.CompactTextString(m) } func (*Shard) ProtoMessage() {} func (*Shard) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{3} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{3} } func (m *Shard) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Shard.Unmarshal(m, b) @@ -428,13 +425,6 @@ func (m *Shard) GetKeyRange() *KeyRange { return nil } -func (m *Shard) GetServedTypes() []*Shard_ServedType { - if m != nil { - return m.ServedTypes - } - return nil -} - func (m *Shard) GetSourceShards() []*Shard_SourceShard { if m != nil { return m.SourceShards @@ -442,13 +432,6 @@ func (m *Shard) GetSourceShards() []*Shard_SourceShard { return nil } -func (m *Shard) GetCells() []string { - if m != nil { - return m.Cells - } - return nil -} - func (m *Shard) GetTabletControls() []*Shard_TabletControl { if m != nil { return m.TabletControls @@ -456,51 +439,11 @@ func (m *Shard) GetTabletControls() []*Shard_TabletControl { return nil } -// ServedType is an entry in the served_types -type Shard_ServedType struct { - TabletType TabletType `protobuf:"varint,1,opt,name=tablet_type,json=tabletType,proto3,enum=topodata.TabletType" json:"tablet_type,omitempty"` - Cells []string `protobuf:"bytes,2,rep,name=cells,proto3" json:"cells,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *Shard_ServedType) Reset() { *m = Shard_ServedType{} } -func (m *Shard_ServedType) String() string { return proto.CompactTextString(m) } -func (*Shard_ServedType) ProtoMessage() {} -func (*Shard_ServedType) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{3, 0} -} -func (m *Shard_ServedType) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Shard_ServedType.Unmarshal(m, b) -} -func (m *Shard_ServedType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Shard_ServedType.Marshal(b, m, deterministic) -} -func (dst *Shard_ServedType) XXX_Merge(src proto.Message) { - xxx_messageInfo_Shard_ServedType.Merge(dst, src) -} -func (m *Shard_ServedType) XXX_Size() int { - return xxx_messageInfo_Shard_ServedType.Size(m) -} -func (m *Shard_ServedType) XXX_DiscardUnknown() { - xxx_messageInfo_Shard_ServedType.DiscardUnknown(m) -} - -var xxx_messageInfo_Shard_ServedType proto.InternalMessageInfo - -func (m *Shard_ServedType) GetTabletType() TabletType { - if m != nil { - return m.TabletType - } - return TabletType_UNKNOWN -} - -func (m *Shard_ServedType) GetCells() []string { +func (m *Shard) GetIsMasterServing() bool { if m != nil { - return m.Cells + return m.IsMasterServing } - return nil + return false } // SourceShard represents a data source for filtered replication @@ -526,7 +469,7 @@ func (m *Shard_SourceShard) Reset() { *m = Shard_SourceShard{} } func (m *Shard_SourceShard) String() string { return proto.CompactTextString(m) } func (*Shard_SourceShard) ProtoMessage() {} func (*Shard_SourceShard) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{3, 1} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{3, 0} } func (m *Shard_SourceShard) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Shard_SourceShard.Unmarshal(m, b) @@ -584,11 +527,9 @@ func (m *Shard_SourceShard) GetTables() []string { // TabletControl controls tablet's behavior type Shard_TabletControl struct { // which tablet type is affected - TabletType TabletType `protobuf:"varint,1,opt,name=tablet_type,json=tabletType,proto3,enum=topodata.TabletType" json:"tablet_type,omitempty"` - Cells []string `protobuf:"bytes,2,rep,name=cells,proto3" json:"cells,omitempty"` - // what to do - DisableQueryService bool `protobuf:"varint,3,opt,name=disable_query_service,json=disableQueryService,proto3" json:"disable_query_service,omitempty"` - BlacklistedTables []string `protobuf:"bytes,4,rep,name=blacklisted_tables,json=blacklistedTables,proto3" json:"blacklisted_tables,omitempty"` + TabletType TabletType `protobuf:"varint,1,opt,name=tablet_type,json=tabletType,proto3,enum=topodata.TabletType" json:"tablet_type,omitempty"` + Cells []string `protobuf:"bytes,2,rep,name=cells,proto3" json:"cells,omitempty"` + BlacklistedTables []string `protobuf:"bytes,4,rep,name=blacklisted_tables,json=blacklistedTables,proto3" json:"blacklisted_tables,omitempty"` // frozen is set if we've started failing over traffic for // the master. If set, this record should not be removed. Frozen bool `protobuf:"varint,5,opt,name=frozen,proto3" json:"frozen,omitempty"` @@ -601,7 +542,7 @@ func (m *Shard_TabletControl) Reset() { *m = Shard_TabletControl{} } func (m *Shard_TabletControl) String() string { return proto.CompactTextString(m) } func (*Shard_TabletControl) ProtoMessage() {} func (*Shard_TabletControl) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{3, 2} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{3, 1} } func (m *Shard_TabletControl) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Shard_TabletControl.Unmarshal(m, b) @@ -635,13 +576,6 @@ func (m *Shard_TabletControl) GetCells() []string { return nil } -func (m *Shard_TabletControl) GetDisableQueryService() bool { - if m != nil { - return m.DisableQueryService - } - return false -} - func (m *Shard_TabletControl) GetBlacklistedTables() []string { if m != nil { return m.BlacklistedTables @@ -676,7 +610,7 @@ func (m *Keyspace) Reset() { *m = Keyspace{} } func (m *Keyspace) String() string { return proto.CompactTextString(m) } func (*Keyspace) ProtoMessage() {} func (*Keyspace) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{4} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{4} } func (m *Keyspace) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Keyspace.Unmarshal(m, b) @@ -735,7 +669,7 @@ func (m *Keyspace_ServedFrom) Reset() { *m = Keyspace_ServedFrom{} } func (m *Keyspace_ServedFrom) String() string { return proto.CompactTextString(m) } func (*Keyspace_ServedFrom) ProtoMessage() {} func (*Keyspace_ServedFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{4, 0} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{4, 0} } func (m *Keyspace_ServedFrom) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Keyspace_ServedFrom.Unmarshal(m, b) @@ -791,7 +725,7 @@ func (m *ShardReplication) Reset() { *m = ShardReplication{} } func (m *ShardReplication) String() string { return proto.CompactTextString(m) } func (*ShardReplication) ProtoMessage() {} func (*ShardReplication) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{5} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{5} } func (m *ShardReplication) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShardReplication.Unmarshal(m, b) @@ -830,7 +764,7 @@ func (m *ShardReplication_Node) Reset() { *m = ShardReplication_Node{} } func (m *ShardReplication_Node) String() string { return proto.CompactTextString(m) } func (*ShardReplication_Node) ProtoMessage() {} func (*ShardReplication_Node) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{5, 0} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{5, 0} } func (m *ShardReplication_Node) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShardReplication_Node.Unmarshal(m, b) @@ -871,7 +805,7 @@ func (m *ShardReference) Reset() { *m = ShardReference{} } func (m *ShardReference) String() string { return proto.CompactTextString(m) } func (*ShardReference) ProtoMessage() {} func (*ShardReference) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{6} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{6} } func (m *ShardReference) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShardReference.Unmarshal(m, b) @@ -905,6 +839,63 @@ func (m *ShardReference) GetKeyRange() *KeyRange { return nil } +// ShardTabletControl is used as a pointer from a SrvKeyspace to a Shard +type ShardTabletControl struct { + // Copied from Shard. + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + KeyRange *KeyRange `protobuf:"bytes,2,opt,name=key_range,json=keyRange,proto3" json:"key_range,omitempty"` + // Disable query serving in this shard + QueryServiceDisabled bool `protobuf:"varint,3,opt,name=query_service_disabled,json=queryServiceDisabled,proto3" json:"query_service_disabled,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *ShardTabletControl) Reset() { *m = ShardTabletControl{} } +func (m *ShardTabletControl) String() string { return proto.CompactTextString(m) } +func (*ShardTabletControl) ProtoMessage() {} +func (*ShardTabletControl) Descriptor() ([]byte, []int) { + return fileDescriptor_topodata_42e6e5b7e6808654, []int{7} +} +func (m *ShardTabletControl) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_ShardTabletControl.Unmarshal(m, b) +} +func (m *ShardTabletControl) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_ShardTabletControl.Marshal(b, m, deterministic) +} +func (dst *ShardTabletControl) XXX_Merge(src proto.Message) { + xxx_messageInfo_ShardTabletControl.Merge(dst, src) +} +func (m *ShardTabletControl) XXX_Size() int { + return xxx_messageInfo_ShardTabletControl.Size(m) +} +func (m *ShardTabletControl) XXX_DiscardUnknown() { + xxx_messageInfo_ShardTabletControl.DiscardUnknown(m) +} + +var xxx_messageInfo_ShardTabletControl proto.InternalMessageInfo + +func (m *ShardTabletControl) GetName() string { + if m != nil { + return m.Name + } + return "" +} + +func (m *ShardTabletControl) GetKeyRange() *KeyRange { + if m != nil { + return m.KeyRange + } + return nil +} + +func (m *ShardTabletControl) GetQueryServiceDisabled() bool { + if m != nil { + return m.QueryServiceDisabled + } + return false +} + // SrvKeyspace is a rollup node for the keyspace itself. type SrvKeyspace struct { // The partitions this keyspace is serving, per tablet type. @@ -922,7 +913,7 @@ func (m *SrvKeyspace) Reset() { *m = SrvKeyspace{} } func (m *SrvKeyspace) String() string { return proto.CompactTextString(m) } func (*SrvKeyspace) ProtoMessage() {} func (*SrvKeyspace) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{7} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{8} } func (m *SrvKeyspace) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SrvKeyspace.Unmarshal(m, b) @@ -974,17 +965,19 @@ type SrvKeyspace_KeyspacePartition struct { // The type this partition applies to. ServedType TabletType `protobuf:"varint,1,opt,name=served_type,json=servedType,proto3,enum=topodata.TabletType" json:"served_type,omitempty"` // List of non-overlapping continuous shards sorted by range. - ShardReferences []*ShardReference `protobuf:"bytes,2,rep,name=shard_references,json=shardReferences,proto3" json:"shard_references,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + ShardReferences []*ShardReference `protobuf:"bytes,2,rep,name=shard_references,json=shardReferences,proto3" json:"shard_references,omitempty"` + // List of shard tablet controls + ShardTabletControls []*ShardTabletControl `protobuf:"bytes,3,rep,name=shard_tablet_controls,json=shardTabletControls,proto3" json:"shard_tablet_controls,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *SrvKeyspace_KeyspacePartition) Reset() { *m = SrvKeyspace_KeyspacePartition{} } func (m *SrvKeyspace_KeyspacePartition) String() string { return proto.CompactTextString(m) } func (*SrvKeyspace_KeyspacePartition) ProtoMessage() {} func (*SrvKeyspace_KeyspacePartition) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{7, 0} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{8, 0} } func (m *SrvKeyspace_KeyspacePartition) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SrvKeyspace_KeyspacePartition.Unmarshal(m, b) @@ -1018,6 +1011,13 @@ func (m *SrvKeyspace_KeyspacePartition) GetShardReferences() []*ShardReference { return nil } +func (m *SrvKeyspace_KeyspacePartition) GetShardTabletControls() []*ShardTabletControl { + if m != nil { + return m.ShardTabletControls + } + return nil +} + // ServedFrom indicates a relationship between a TabletType and the // keyspace name that's serving it. type SrvKeyspace_ServedFrom struct { @@ -1034,7 +1034,7 @@ func (m *SrvKeyspace_ServedFrom) Reset() { *m = SrvKeyspace_ServedFrom{} func (m *SrvKeyspace_ServedFrom) String() string { return proto.CompactTextString(m) } func (*SrvKeyspace_ServedFrom) ProtoMessage() {} func (*SrvKeyspace_ServedFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{7, 1} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{8, 1} } func (m *SrvKeyspace_ServedFrom) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SrvKeyspace_ServedFrom.Unmarshal(m, b) @@ -1092,7 +1092,7 @@ func (m *CellInfo) Reset() { *m = CellInfo{} } func (m *CellInfo) String() string { return proto.CompactTextString(m) } func (*CellInfo) ProtoMessage() {} func (*CellInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_693bf5422a92a7f4, []int{8} + return fileDescriptor_topodata_42e6e5b7e6808654, []int{9} } func (m *CellInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CellInfo.Unmarshal(m, b) @@ -1140,7 +1140,6 @@ func init() { proto.RegisterMapType((map[string]int32)(nil), "topodata.Tablet.PortMapEntry") proto.RegisterMapType((map[string]string)(nil), "topodata.Tablet.TagsEntry") proto.RegisterType((*Shard)(nil), "topodata.Shard") - proto.RegisterType((*Shard_ServedType)(nil), "topodata.Shard.ServedType") proto.RegisterType((*Shard_SourceShard)(nil), "topodata.Shard.SourceShard") proto.RegisterType((*Shard_TabletControl)(nil), "topodata.Shard.TabletControl") proto.RegisterType((*Keyspace)(nil), "topodata.Keyspace") @@ -1148,6 +1147,7 @@ func init() { proto.RegisterType((*ShardReplication)(nil), "topodata.ShardReplication") proto.RegisterType((*ShardReplication_Node)(nil), "topodata.ShardReplication.Node") proto.RegisterType((*ShardReference)(nil), "topodata.ShardReference") + proto.RegisterType((*ShardTabletControl)(nil), "topodata.ShardTabletControl") proto.RegisterType((*SrvKeyspace)(nil), "topodata.SrvKeyspace") proto.RegisterType((*SrvKeyspace_KeyspacePartition)(nil), "topodata.SrvKeyspace.KeyspacePartition") proto.RegisterType((*SrvKeyspace_ServedFrom)(nil), "topodata.SrvKeyspace.ServedFrom") @@ -1156,81 +1156,83 @@ func init() { proto.RegisterEnum("topodata.TabletType", TabletType_name, TabletType_value) } -func init() { proto.RegisterFile("topodata.proto", fileDescriptor_topodata_693bf5422a92a7f4) } - -var fileDescriptor_topodata_693bf5422a92a7f4 = []byte{ - // 1162 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0x6f, 0x8f, 0xda, 0x46, - 0x13, 0x7f, 0x0c, 0x86, 0x33, 0x63, 0x8e, 0x38, 0xfb, 0x24, 0x95, 0xe5, 0x2a, 0x2a, 0x42, 0x8a, - 0x8a, 0x52, 0x15, 0x2a, 0xd2, 0xb4, 0xa7, 0x48, 0x95, 0x42, 0x08, 0x69, 0xb8, 0x24, 0x1c, 0x5d, - 0x38, 0xb5, 0xa9, 0x54, 0x59, 0x3e, 0xbc, 0x47, 0xac, 0x33, 0x5e, 0xb2, 0xbb, 0x20, 0xd1, 0xaf, - 0xd0, 0x17, 0xcd, 0xeb, 0xbe, 0xed, 0xa7, 0xe8, 0x27, 0xe8, 0x47, 0xe8, 0xd7, 0xa9, 0x76, 0xd7, - 0x06, 0xc3, 0x35, 0xe9, 0xa5, 0xba, 0x77, 0x33, 0x3b, 0x7f, 0x3c, 0xf3, 0x9b, 0xdf, 0x0c, 0x40, - 0x4d, 0xd0, 0x05, 0x0d, 0x03, 0x11, 0xb4, 0x16, 0x8c, 0x0a, 0x8a, 0xac, 0x4c, 0x6f, 0x74, 0xc0, - 0x7a, 0x4e, 0xd6, 0x38, 0x48, 0x66, 0x04, 0xdd, 0x82, 0x12, 0x17, 0x01, 0x13, 0xae, 0x51, 0x37, - 0x9a, 0x55, 0xac, 0x15, 0xe4, 0x40, 0x91, 0x24, 0xa1, 0x5b, 0x50, 0x6f, 0x52, 0x6c, 0xdc, 0x07, - 0x7b, 0x12, 0x9c, 0xc5, 0x44, 0x74, 0xe3, 0x28, 0xe0, 0x08, 0x81, 0x39, 0x25, 0x71, 0xac, 0xa2, - 0x2a, 0x58, 0xc9, 0x32, 0x68, 0x19, 0xe9, 0xa0, 0x43, 0x2c, 0xc5, 0xc6, 0x1f, 0x26, 0x94, 0x75, - 0x14, 0xfa, 0x0c, 0x4a, 0x81, 0x8c, 0x54, 0x11, 0x76, 0xe7, 0x76, 0x6b, 0x53, 0x5d, 0x2e, 0x2d, - 0xd6, 0x3e, 0xc8, 0x03, 0xeb, 0x35, 0xe5, 0x22, 0x09, 0xe6, 0x44, 0xa5, 0xab, 0xe0, 0x8d, 0x8e, - 0x8e, 0xc0, 0x5a, 0x50, 0x26, 0xfc, 0x79, 0xb0, 0x70, 0xcd, 0x7a, 0xb1, 0x69, 0x77, 0xee, 0xec, - 0xe7, 0x6a, 0x8d, 0x28, 0x13, 0x2f, 0x83, 0x45, 0x3f, 0x11, 0x6c, 0x8d, 0x0f, 0x16, 0x5a, 0x93, - 0x59, 0x2f, 0xc8, 0x9a, 0x2f, 0x82, 0x29, 0x71, 0x4b, 0x3a, 0x6b, 0xa6, 0x2b, 0x18, 0x5e, 0x07, - 0x2c, 0x74, 0xcb, 0xca, 0xa0, 0x15, 0xd4, 0x86, 0xca, 0x05, 0x59, 0xfb, 0x4c, 0x22, 0xe5, 0x1e, - 0xa8, 0xc2, 0xd1, 0xf6, 0x63, 0x19, 0x86, 0x2a, 0x8d, 0x46, 0xb3, 0x09, 0xa6, 0x58, 0x2f, 0x88, - 0x6b, 0xd5, 0x8d, 0x66, 0xad, 0x73, 0x6b, 0xbf, 0xb0, 0xc9, 0x7a, 0x41, 0xb0, 0xf2, 0x40, 0x4d, - 0x70, 0xc2, 0x33, 0x5f, 0x76, 0xe4, 0xd3, 0x15, 0x61, 0x2c, 0x0a, 0x89, 0x5b, 0x51, 0xdf, 0xae, - 0x85, 0x67, 0xc3, 0x60, 0x4e, 0x4e, 0xd2, 0x57, 0xd4, 0x02, 0x53, 0x04, 0x33, 0xee, 0x82, 0x6a, - 0xd6, 0xbb, 0xd4, 0xec, 0x24, 0x98, 0x71, 0xdd, 0xa9, 0xf2, 0x43, 0x77, 0xa1, 0x36, 0x5f, 0xf3, - 0x37, 0xb1, 0xbf, 0x81, 0xb0, 0xaa, 0xf2, 0x1e, 0xaa, 0xd7, 0x67, 0x19, 0x8e, 0x77, 0x00, 0xb4, - 0x9b, 0x84, 0xc7, 0x3d, 0xac, 0x1b, 0xcd, 0x12, 0xae, 0xa8, 0x17, 0x89, 0x9e, 0xf7, 0x10, 0xaa, - 0x79, 0x14, 0xe5, 0x70, 0x2f, 0xc8, 0x3a, 0x9d, 0xb7, 0x14, 0x25, 0x64, 0xab, 0x20, 0x5e, 0xea, - 0x09, 0x95, 0xb0, 0x56, 0x1e, 0x16, 0x8e, 0x0c, 0xef, 0x6b, 0xa8, 0x6c, 0x8a, 0xfa, 0xb7, 0xc0, - 0x4a, 0x2e, 0xf0, 0xd8, 0xb4, 0x8a, 0x8e, 0x79, 0x6c, 0x5a, 0xb6, 0x53, 0x6d, 0xfc, 0x5e, 0x86, - 0xd2, 0x58, 0x4d, 0xe1, 0x08, 0xaa, 0xf3, 0x80, 0x0b, 0xc2, 0xfc, 0x2b, 0x30, 0xc8, 0xd6, 0xae, - 0x9a, 0xa5, 0x3b, 0xf3, 0x2b, 0x5c, 0x61, 0x7e, 0xdf, 0x40, 0x95, 0x13, 0xb6, 0x22, 0xa1, 0x2f, - 0x87, 0xc4, 0xdd, 0xe2, 0x3e, 0xe6, 0xaa, 0xa2, 0xd6, 0x58, 0xf9, 0xa8, 0x69, 0xda, 0x7c, 0x23, - 0x73, 0xf4, 0x08, 0x0e, 0x39, 0x5d, 0xb2, 0x29, 0xf1, 0x15, 0x7f, 0x78, 0x4a, 0xd0, 0x8f, 0x2f, - 0xc5, 0x2b, 0x27, 0x25, 0xe3, 0x2a, 0xdf, 0x2a, 0x5c, 0x62, 0x23, 0x77, 0x89, 0xbb, 0xa5, 0x7a, - 0x51, 0x62, 0xa3, 0x14, 0xf4, 0x14, 0x6e, 0x08, 0xd5, 0xa3, 0x3f, 0xa5, 0x89, 0x60, 0x34, 0xe6, - 0x6e, 0x79, 0x9f, 0xfa, 0x3a, 0xb3, 0x86, 0xa2, 0xa7, 0xbd, 0x70, 0x4d, 0xe4, 0x55, 0xee, 0xbd, - 0x02, 0xd8, 0x96, 0x8e, 0x1e, 0x80, 0x9d, 0x66, 0x55, 0x9c, 0x35, 0xde, 0xc3, 0x59, 0x10, 0x1b, - 0x79, 0x5b, 0x62, 0x21, 0x57, 0xa2, 0xf7, 0x9b, 0x01, 0x76, 0xae, 0xad, 0xec, 0x18, 0x18, 0x9b, - 0x63, 0xb0, 0xb3, 0x7e, 0x85, 0x77, 0xad, 0x5f, 0xf1, 0x9d, 0xeb, 0x67, 0x5e, 0x61, 0x7c, 0x1f, - 0x41, 0x59, 0x15, 0x9a, 0xc1, 0x97, 0x6a, 0xde, 0x5f, 0x06, 0x1c, 0xee, 0x20, 0x73, 0xad, 0xbd, - 0xa3, 0x0e, 0xdc, 0x0e, 0x23, 0x2e, 0xbd, 0xfc, 0x37, 0x4b, 0xc2, 0xd6, 0xbe, 0xe4, 0x44, 0x34, - 0x25, 0xaa, 0x1b, 0x0b, 0xff, 0x3f, 0x35, 0x7e, 0x27, 0x6d, 0x63, 0x6d, 0x42, 0x9f, 0x03, 0x3a, - 0x8b, 0x83, 0xe9, 0x45, 0x1c, 0x71, 0x21, 0xe9, 0xa6, 0xcb, 0x36, 0x55, 0xda, 0x9b, 0x39, 0x8b, - 0x2a, 0x84, 0xcb, 0xce, 0xce, 0x19, 0xfd, 0x99, 0x24, 0xea, 0x72, 0x59, 0x38, 0xd5, 0x1a, 0x7f, - 0x16, 0xd4, 0x2d, 0xd7, 0x28, 0x7e, 0x01, 0xb7, 0x14, 0x70, 0x51, 0x32, 0xf3, 0xa7, 0x34, 0x5e, - 0xce, 0x13, 0x75, 0x60, 0xd2, 0xdd, 0x43, 0x99, 0xad, 0xa7, 0x4c, 0xf2, 0xc6, 0xa0, 0xe3, 0xcb, - 0x11, 0x0a, 0x8f, 0x82, 0xc2, 0xc3, 0xdd, 0x01, 0x5b, 0x7d, 0x63, 0xa0, 0x59, 0xbf, 0x97, 0x4b, - 0x61, 0xf3, 0x68, 0xb3, 0x3b, 0xe7, 0x8c, 0xce, 0xf9, 0xe5, 0xe3, 0x9c, 0xe5, 0x48, 0xd7, 0xe7, - 0x29, 0xa3, 0xf3, 0x6c, 0x7d, 0xa4, 0xcc, 0xbd, 0x65, 0x46, 0x4f, 0xa9, 0x5e, 0xef, 0x88, 0xf2, - 0xe4, 0x2b, 0xee, 0x92, 0x4f, 0x5f, 0x9d, 0xc6, 0x2f, 0x06, 0x38, 0x7a, 0x23, 0xc9, 0x22, 0x8e, - 0xa6, 0x81, 0x88, 0x68, 0x82, 0x1e, 0x40, 0x29, 0xa1, 0x21, 0x91, 0x37, 0x47, 0x36, 0xf3, 0xc9, - 0xde, 0xba, 0xe5, 0x5c, 0x5b, 0x43, 0x1a, 0x12, 0xac, 0xbd, 0xbd, 0x47, 0x60, 0x4a, 0x55, 0x5e, - 0xae, 0xb4, 0x85, 0xab, 0x5c, 0x2e, 0xb1, 0x55, 0x1a, 0xa7, 0x50, 0x4b, 0xbf, 0x70, 0x4e, 0x18, - 0x49, 0xa6, 0x44, 0xfe, 0xe2, 0xe6, 0x86, 0xa9, 0xe4, 0x0f, 0xbe, 0x6f, 0x8d, 0xb7, 0x26, 0xd8, - 0x63, 0xb6, 0xda, 0x30, 0xe6, 0x5b, 0x80, 0x45, 0xc0, 0x44, 0x24, 0x3b, 0xc8, 0x9a, 0xfc, 0x34, - 0xd7, 0xe4, 0xd6, 0x75, 0x33, 0xbd, 0x51, 0xe6, 0x8f, 0x73, 0xa1, 0xef, 0xa4, 0x5e, 0xe1, 0x83, - 0xa9, 0x57, 0xfc, 0x0f, 0xd4, 0xeb, 0x82, 0x9d, 0xa3, 0x5e, 0xca, 0xbc, 0xfa, 0x3f, 0xf7, 0x91, - 0x23, 0x1f, 0x6c, 0xc9, 0xe7, 0xfd, 0x6a, 0xc0, 0xcd, 0x4b, 0x2d, 0x4a, 0x0e, 0xe6, 0x7e, 0x0f, - 0xde, 0xcf, 0xc1, 0xed, 0x0f, 0x01, 0xea, 0x81, 0xa3, 0xaa, 0xf4, 0x59, 0x36, 0x3e, 0x4d, 0x47, - 0x3b, 0xdf, 0xd7, 0xee, 0x7c, 0xf1, 0x0d, 0xbe, 0xa3, 0x73, 0xcf, 0xbf, 0x8e, 0x6d, 0x78, 0xcf, - 0xd1, 0x3d, 0x36, 0xad, 0x92, 0x53, 0x6e, 0xfc, 0x04, 0x56, 0x8f, 0xc4, 0xf1, 0x20, 0x39, 0xa7, - 0xf2, 0xaf, 0x83, 0xea, 0x82, 0xf9, 0x41, 0x18, 0x32, 0xc2, 0x79, 0xca, 0xb6, 0x43, 0xfd, 0xda, - 0xd5, 0x8f, 0x92, 0x8a, 0x8c, 0x52, 0x91, 0x26, 0x54, 0xb2, 0x3c, 0x50, 0x8c, 0xcc, 0x22, 0x9a, - 0xa4, 0xeb, 0x95, 0x6a, 0xf7, 0x3a, 0x50, 0xdb, 0x1d, 0x20, 0xaa, 0x40, 0xe9, 0x74, 0x38, 0xee, - 0x4f, 0x9c, 0xff, 0x21, 0x80, 0xf2, 0xe9, 0x60, 0x38, 0xf9, 0xea, 0x4b, 0xc7, 0x90, 0xcf, 0x8f, - 0x5f, 0x4d, 0xfa, 0x63, 0xa7, 0x70, 0xef, 0xad, 0x01, 0xb0, 0xed, 0x07, 0xd9, 0x70, 0x70, 0x3a, - 0x7c, 0x3e, 0x3c, 0xf9, 0x7e, 0xa8, 0x43, 0x5e, 0x76, 0xc7, 0x93, 0x3e, 0x76, 0x0c, 0x69, 0xc0, - 0xfd, 0xd1, 0x8b, 0x41, 0xaf, 0xeb, 0x14, 0xa4, 0x01, 0x3f, 0x39, 0x19, 0xbe, 0x78, 0xe5, 0x14, - 0x55, 0xae, 0xee, 0xa4, 0xf7, 0x4c, 0x8b, 0xe3, 0x51, 0x17, 0xf7, 0x1d, 0x13, 0x39, 0x50, 0xed, - 0xff, 0x30, 0xea, 0xe3, 0xc1, 0xcb, 0xfe, 0x70, 0xd2, 0x7d, 0xe1, 0x94, 0x64, 0xcc, 0xe3, 0x6e, - 0xef, 0xf9, 0xe9, 0xc8, 0x29, 0xeb, 0x64, 0xe3, 0xc9, 0x09, 0xee, 0x3b, 0x07, 0x52, 0x79, 0x82, - 0xbb, 0x83, 0x61, 0xff, 0x89, 0x63, 0x79, 0x05, 0xc7, 0x78, 0x7c, 0x04, 0x37, 0x22, 0xda, 0x5a, - 0x45, 0x82, 0x70, 0xae, 0xff, 0x4f, 0xff, 0x78, 0x37, 0xd5, 0x22, 0xda, 0xd6, 0x52, 0x7b, 0x46, - 0xdb, 0x2b, 0xd1, 0x56, 0xd6, 0x76, 0x36, 0x98, 0xb3, 0xb2, 0xd2, 0xef, 0xff, 0x1d, 0x00, 0x00, - 0xff, 0xff, 0x74, 0x1e, 0xdb, 0x99, 0x8f, 0x0b, 0x00, 0x00, +func init() { proto.RegisterFile("topodata.proto", fileDescriptor_topodata_42e6e5b7e6808654) } + +var fileDescriptor_topodata_42e6e5b7e6808654 = []byte{ + // 1192 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xef, 0x6e, 0x1b, 0x45, + 0x10, 0xe7, 0xec, 0xb3, 0x73, 0x9e, 0x73, 0x9c, 0xeb, 0x92, 0x56, 0x27, 0x43, 0x45, 0x64, 0xa9, + 0xc2, 0x2a, 0xc2, 0x41, 0x69, 0x0b, 0x51, 0x3f, 0xd5, 0x75, 0x5c, 0x9a, 0xb6, 0x71, 0xac, 0xb5, + 0x23, 0x28, 0x12, 0x3a, 0x5d, 0x7c, 0x1b, 0xf7, 0x94, 0xf3, 0xad, 0xbb, 0xbb, 0x89, 0x64, 0x5e, + 0x81, 0x0f, 0xf0, 0x99, 0x37, 0xe0, 0x11, 0x78, 0x02, 0x9e, 0x03, 0xde, 0x03, 0x09, 0xed, 0xec, + 0xd9, 0x3e, 0x3b, 0xb4, 0x4d, 0x51, 0xbf, 0x58, 0x33, 0x3b, 0x7f, 0x76, 0x66, 0xf6, 0xf7, 0x9b, + 0x33, 0xd4, 0x14, 0x9f, 0xf2, 0x28, 0x54, 0x61, 0x6b, 0x2a, 0xb8, 0xe2, 0xc4, 0x99, 0xeb, 0x8d, + 0x3d, 0x70, 0x9e, 0xb3, 0x19, 0x0d, 0xd3, 0x31, 0x23, 0xdb, 0x50, 0x92, 0x2a, 0x14, 0xca, 0xb7, + 0x76, 0xac, 0x66, 0x95, 0x1a, 0x85, 0x78, 0x50, 0x64, 0x69, 0xe4, 0x17, 0xf0, 0x4c, 0x8b, 0x8d, + 0x7b, 0xe0, 0x0e, 0xc3, 0xd3, 0x84, 0xa9, 0x76, 0x12, 0x87, 0x92, 0x10, 0xb0, 0x47, 0x2c, 0x49, + 0x30, 0xaa, 0x42, 0x51, 0xd6, 0x41, 0x17, 0xb1, 0x09, 0xda, 0xa4, 0x5a, 0x6c, 0xfc, 0x61, 0x43, + 0xd9, 0x44, 0x91, 0x2f, 0xa0, 0x14, 0xea, 0x48, 0x8c, 0x70, 0xf7, 0x6e, 0xb6, 0x16, 0xd5, 0xe5, + 0xd2, 0x52, 0xe3, 0x43, 0xea, 0xe0, 0xbc, 0xe2, 0x52, 0xa5, 0xe1, 0x84, 0x61, 0xba, 0x0a, 0x5d, + 0xe8, 0x64, 0x1f, 0x9c, 0x29, 0x17, 0x2a, 0x98, 0x84, 0x53, 0xdf, 0xde, 0x29, 0x36, 0xdd, 0xbd, + 0xdb, 0xeb, 0xb9, 0x5a, 0x7d, 0x2e, 0xd4, 0x51, 0x38, 0xed, 0xa6, 0x4a, 0xcc, 0xe8, 0xc6, 0xd4, + 0x68, 0x3a, 0xeb, 0x39, 0x9b, 0xc9, 0x69, 0x38, 0x62, 0x7e, 0xc9, 0x64, 0x9d, 0xeb, 0x38, 0x86, + 0x57, 0xa1, 0x88, 0xfc, 0x32, 0x1a, 0x8c, 0x42, 0x76, 0xa1, 0x72, 0xce, 0x66, 0x81, 0xd0, 0x93, + 0xf2, 0x37, 0xb0, 0x70, 0xb2, 0xbc, 0x6c, 0x3e, 0x43, 0x4c, 0x63, 0xa6, 0xd9, 0x04, 0x5b, 0xcd, + 0xa6, 0xcc, 0x77, 0x76, 0xac, 0x66, 0x6d, 0x6f, 0x7b, 0xbd, 0xb0, 0xe1, 0x6c, 0xca, 0x28, 0x7a, + 0x90, 0x26, 0x78, 0xd1, 0x69, 0xa0, 0x3b, 0x0a, 0xf8, 0x25, 0x13, 0x22, 0x8e, 0x98, 0x5f, 0xc1, + 0xbb, 0x6b, 0xd1, 0x69, 0x2f, 0x9c, 0xb0, 0xe3, 0xec, 0x94, 0xb4, 0xc0, 0x56, 0xe1, 0x58, 0xfa, + 0x80, 0xcd, 0xd6, 0xaf, 0x34, 0x3b, 0x0c, 0xc7, 0xd2, 0x74, 0x8a, 0x7e, 0xe4, 0x0e, 0xd4, 0x26, + 0x33, 0xf9, 0x3a, 0x09, 0x16, 0x23, 0xac, 0x62, 0xde, 0x4d, 0x3c, 0x7d, 0x3a, 0x9f, 0xe3, 0x6d, + 0x00, 0xe3, 0xa6, 0xc7, 0xe3, 0x6f, 0xee, 0x58, 0xcd, 0x12, 0xad, 0xe0, 0x89, 0x9e, 0x5e, 0xfd, + 0x21, 0x54, 0xf3, 0x53, 0xd4, 0x8f, 0x7b, 0xce, 0x66, 0xd9, 0x7b, 0x6b, 0x51, 0x8f, 0xec, 0x32, + 0x4c, 0x2e, 0xcc, 0x0b, 0x95, 0xa8, 0x51, 0x1e, 0x16, 0xf6, 0xad, 0xfa, 0x37, 0x50, 0x59, 0x14, + 0xf5, 0xae, 0xc0, 0x4a, 0x2e, 0xf0, 0x99, 0xed, 0x14, 0x3d, 0xfb, 0x99, 0xed, 0xb8, 0x5e, 0xb5, + 0xf1, 0x8f, 0x0d, 0xa5, 0x01, 0xbe, 0xc2, 0x3e, 0x54, 0x27, 0xa1, 0x54, 0x4c, 0x04, 0xd7, 0x40, + 0x90, 0x6b, 0x5c, 0x0d, 0x4a, 0x57, 0xde, 0xaf, 0x70, 0x8d, 0xf7, 0x7b, 0x04, 0x9b, 0x92, 0x5f, + 0x88, 0x11, 0x0b, 0x10, 0x00, 0x32, 0x43, 0xd8, 0x27, 0xcb, 0x20, 0x2c, 0xa9, 0x35, 0x40, 0x27, + 0x94, 0x69, 0x55, 0x2e, 0x15, 0x49, 0x9e, 0xc0, 0x96, 0xc2, 0x72, 0x82, 0x11, 0x4f, 0x95, 0xe0, + 0x89, 0xf4, 0xcb, 0xeb, 0x28, 0x35, 0x39, 0x4c, 0xd5, 0x1d, 0xe3, 0x45, 0x6b, 0x2a, 0xaf, 0x4a, + 0x72, 0x17, 0x6e, 0xc4, 0x32, 0xc8, 0xfa, 0x96, 0x4c, 0x5c, 0xc6, 0xe9, 0x18, 0x21, 0xe8, 0xd0, + 0xad, 0x58, 0x1e, 0xe1, 0xf9, 0xc0, 0x1c, 0xd7, 0x7f, 0xb3, 0xc0, 0xcd, 0x55, 0x34, 0x27, 0xa2, + 0xb5, 0x20, 0xe2, 0x0a, 0xf4, 0x0b, 0x6f, 0x82, 0x7e, 0xf1, 0x8d, 0xd0, 0xb7, 0xaf, 0x31, 0xba, + 0x5b, 0x50, 0xc6, 0x16, 0xa4, 0x5f, 0xda, 0x29, 0x36, 0x2b, 0x34, 0xd3, 0xea, 0xbf, 0x5b, 0xb0, + 0xb9, 0xd2, 0x2a, 0x79, 0x00, 0x6e, 0x36, 0x22, 0xe4, 0x8a, 0xf5, 0x16, 0xae, 0x80, 0x5a, 0xc8, + 0xba, 0x4e, 0xbd, 0x66, 0xa4, 0x5f, 0xc0, 0xfc, 0x46, 0x21, 0x5f, 0x02, 0x39, 0x4d, 0xc2, 0xd1, + 0x79, 0x12, 0x4b, 0xc5, 0xa2, 0x20, 0x2b, 0xc1, 0x46, 0x97, 0x1b, 0x39, 0x0b, 0x26, 0x95, 0xba, + 0xca, 0x33, 0xc1, 0x7f, 0x62, 0x29, 0x6e, 0x00, 0x87, 0x66, 0xda, 0x02, 0x79, 0xe6, 0xb7, 0xe4, + 0x95, 0x1b, 0x7f, 0x16, 0x70, 0x4b, 0x9a, 0x19, 0x7d, 0x05, 0xdb, 0x38, 0x96, 0x38, 0x1d, 0x07, + 0x23, 0x9e, 0x5c, 0x4c, 0x52, 0xa4, 0x6e, 0x86, 0x6a, 0x32, 0xb7, 0x75, 0xd0, 0xa4, 0xd9, 0x4b, + 0x9e, 0x5d, 0x8d, 0xc0, 0x6e, 0x0b, 0xd8, 0xad, 0xbf, 0x32, 0x4a, 0xbc, 0xe3, 0x30, 0xc2, 0x8e, + 0xd7, 0x72, 0x61, 0xe7, 0x8f, 0xa0, 0xaa, 0x11, 0xc0, 0xa2, 0xe0, 0x4c, 0xf0, 0x89, 0xbc, 0xba, + 0xf6, 0xe6, 0x39, 0x5a, 0x03, 0x74, 0x7b, 0x22, 0xf8, 0x84, 0xba, 0x72, 0x21, 0xcb, 0xfa, 0x05, + 0xc0, 0xd2, 0xf4, 0x61, 0x1f, 0x20, 0x0f, 0xad, 0xe2, 0x2a, 0xb4, 0xcc, 0x3c, 0x1b, 0x3f, 0x5b, + 0xe0, 0x19, 0xaa, 0xb0, 0x69, 0x12, 0x8f, 0x42, 0x15, 0xf3, 0x94, 0x3c, 0x80, 0x52, 0xca, 0x23, + 0xa6, 0xd9, 0xac, 0x9b, 0xf9, 0x6c, 0x8d, 0x1d, 0x39, 0xd7, 0x56, 0x8f, 0x47, 0x8c, 0x1a, 0xef, + 0xfa, 0x23, 0xb0, 0xb5, 0xaa, 0x77, 0x42, 0xd6, 0xc2, 0x75, 0x76, 0x82, 0x5a, 0x2a, 0x8d, 0x13, + 0xa8, 0x65, 0x37, 0x9c, 0x31, 0xc1, 0xd2, 0x11, 0xd3, 0xdf, 0xb2, 0xdc, 0x63, 0xa2, 0xfc, 0xde, + 0x9b, 0xa3, 0xf1, 0x8b, 0x05, 0x04, 0xf3, 0xae, 0x62, 0xfd, 0x43, 0xe4, 0x26, 0xf7, 0xe1, 0xd6, + 0xeb, 0x0b, 0x26, 0x66, 0x66, 0x0f, 0x8c, 0x58, 0x10, 0xc5, 0x52, 0xdf, 0x62, 0x28, 0xeb, 0xd0, + 0x6d, 0xb4, 0x0e, 0x8c, 0xf1, 0x20, 0xb3, 0x35, 0xfe, 0xb6, 0xc1, 0x1d, 0x88, 0xcb, 0x05, 0x86, + 0xbf, 0x05, 0x98, 0x86, 0x42, 0xc5, 0x7a, 0xa6, 0xf3, 0xb1, 0x7f, 0x9e, 0x1b, 0xfb, 0xd2, 0x75, + 0x81, 0xa7, 0xfe, 0xdc, 0x9f, 0xe6, 0x42, 0xdf, 0x48, 0x86, 0xc2, 0x7b, 0x93, 0xa1, 0xf8, 0x3f, + 0xc8, 0xd0, 0x06, 0x37, 0x47, 0x86, 0x8c, 0x0b, 0x3b, 0xff, 0xdd, 0x47, 0x8e, 0x0e, 0xb0, 0xa4, + 0x43, 0xfd, 0x2f, 0x0b, 0x6e, 0x5c, 0x69, 0x51, 0xb3, 0x22, 0x4b, 0xfc, 0x6e, 0x56, 0x18, 0x47, + 0xac, 0xa7, 0x03, 0x1e, 0x56, 0x19, 0x88, 0x39, 0xa0, 0x0c, 0x41, 0xdc, 0x7c, 0x5f, 0xab, 0x88, + 0xa3, 0x5b, 0x72, 0x45, 0x97, 0xa4, 0x0f, 0x37, 0x4d, 0x92, 0xf5, 0x6f, 0x47, 0x11, 0x33, 0x7d, + 0xba, 0x96, 0x69, 0xf5, 0xd3, 0xf1, 0xb1, 0xbc, 0x72, 0x26, 0xeb, 0xc1, 0x87, 0x60, 0xfc, 0x5b, + 0x3e, 0x1b, 0xd9, 0x96, 0xfc, 0x11, 0x9c, 0x0e, 0x4b, 0x92, 0xc3, 0xf4, 0x8c, 0xeb, 0x3f, 0x1e, + 0x38, 0x17, 0x11, 0x84, 0x51, 0x24, 0x98, 0x94, 0x19, 0xea, 0x37, 0xcd, 0x69, 0xdb, 0x1c, 0x6a, + 0x4a, 0x08, 0xce, 0x55, 0x96, 0x10, 0x65, 0xbd, 0x96, 0x05, 0x1b, 0xc7, 0x3c, 0xcd, 0x56, 0x48, + 0xa6, 0xdd, 0xdd, 0x83, 0xda, 0x2a, 0x24, 0x48, 0x05, 0x4a, 0x27, 0xbd, 0x41, 0x77, 0xe8, 0x7d, + 0x44, 0x00, 0xca, 0x27, 0x87, 0xbd, 0xe1, 0xd7, 0xf7, 0x3d, 0x4b, 0x1f, 0x3f, 0x7e, 0x39, 0xec, + 0x0e, 0xbc, 0xc2, 0xdd, 0x5f, 0x2d, 0x80, 0x65, 0x3f, 0xc4, 0x85, 0x8d, 0x93, 0xde, 0xf3, 0xde, + 0xf1, 0x77, 0x3d, 0x13, 0x72, 0xd4, 0x1e, 0x0c, 0xbb, 0xd4, 0xb3, 0xb4, 0x81, 0x76, 0xfb, 0x2f, + 0x0e, 0x3b, 0x6d, 0xaf, 0xa0, 0x0d, 0xf4, 0xe0, 0xb8, 0xf7, 0xe2, 0xa5, 0x57, 0xc4, 0x5c, 0xed, + 0x61, 0xe7, 0xa9, 0x11, 0x07, 0xfd, 0x36, 0xed, 0x7a, 0x36, 0xf1, 0xa0, 0xda, 0xfd, 0xbe, 0xdf, + 0xa5, 0x87, 0x47, 0xdd, 0xde, 0xb0, 0xfd, 0xc2, 0x2b, 0xe9, 0x98, 0xc7, 0xed, 0xce, 0xf3, 0x93, + 0xbe, 0x57, 0x36, 0xc9, 0x06, 0xc3, 0x63, 0xda, 0xf5, 0x36, 0xb4, 0x72, 0x40, 0xdb, 0x87, 0xbd, + 0xee, 0x81, 0xe7, 0xd4, 0x0b, 0x9e, 0xf5, 0x78, 0x1f, 0xb6, 0x62, 0xde, 0xba, 0x8c, 0x15, 0x93, + 0xd2, 0xfc, 0x1b, 0xff, 0xe1, 0x4e, 0xa6, 0xc5, 0x7c, 0xd7, 0x48, 0xbb, 0x63, 0xbe, 0x7b, 0xa9, + 0x76, 0xd1, 0xba, 0x3b, 0x7f, 0x98, 0xd3, 0x32, 0xea, 0xf7, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, + 0xed, 0x99, 0x0d, 0x60, 0xcd, 0x0b, 0x00, 0x00, } diff --git a/go/vt/topo/cell_info.go b/go/vt/topo/cell_info.go index 25523f4aa14..946e0c8b4d5 100644 --- a/go/vt/topo/cell_info.go +++ b/go/vt/topo/cell_info.go @@ -136,24 +136,14 @@ func (ts *Server) UpdateCellInfoFields(ctx context.Context, cell string, update // DeleteCellInfo deletes the specified CellInfo. // We first make sure no Shard record points to the cell. func (ts *Server) DeleteCellInfo(ctx context.Context, cell string) error { - // Get all keyspaces. - keyspaces, err := ts.GetKeyspaces(ctx) + srvKeyspaces, err := ts.GetSrvKeyspaceNames(ctx, cell) if err != nil { - return fmt.Errorf("GetKeyspaces() failed: %v", err) + return fmt.Errorf("GetSrvKeyspaceNames() failed: %v", err) } - // For each keyspace, make sure no shard points at the cell. - for _, keyspace := range keyspaces { - shards, err := ts.FindAllShardsInKeyspace(ctx, keyspace) - if err != nil { - return fmt.Errorf("FindAllShardsInKeyspace(%v) failed: %v", keyspace, err) - } - - for shard, si := range shards { - if si.HasCell(cell) { - return fmt.Errorf("cell %v is used by shard %v/%v, cannot remove it. Use 'vtctl RemoveShardCell' to remove unused cells in a Shard", cell, keyspace, shard) - } - } + if len(srvKeyspaces) != 0 { + // TODO @rafael - implement this function and expose it via a vtctld command + return fmt.Errorf("cell %v has serving keyspaces. Before deleting, delete serving keyspace with: DeleteSrvKeyspaces", cell) } filePath := pathForCellInfo(cell) diff --git a/go/vt/topo/helpers/compare.go b/go/vt/topo/helpers/compare.go index a14f3f83a03..d89826b72cb 100644 --- a/go/vt/topo/helpers/compare.go +++ b/go/vt/topo/helpers/compare.go @@ -145,6 +145,10 @@ func CompareShardReplications(ctx context.Context, fromTS, toTS *topo.Server) er if err != nil { return fmt.Errorf("fromTS.GetKeyspaces: %v", err) } + cells, err := fromTS.GetCellInfoNames(ctx) + if err != nil { + return fmt.Errorf("GetCellInfoNames(): %v", err) + } for _, keyspace := range keyspaces { shards, err := fromTS.GetShardNames(ctx, keyspace) @@ -153,14 +157,7 @@ func CompareShardReplications(ctx context.Context, fromTS, toTS *topo.Server) er } for _, shard := range shards { - - // read the source shard to get the cells - si, err := fromTS.GetShard(ctx, keyspace, shard) - if err != nil { - return fmt.Errorf("GetShard(%v, %v): %v", keyspace, shard, err) - } - - for _, cell := range si.Shard.Cells { + for _, cell := range cells { fromSRi, err := fromTS.GetShardReplication(ctx, cell, keyspace, shard) if err != nil { return fmt.Errorf("GetShardReplication(%v, %v, %v): %v", cell, keyspace, shard, err) diff --git a/go/vt/topo/helpers/copy.go b/go/vt/topo/helpers/copy.go index 4b19870b9e1..0e6f2825f24 100644 --- a/go/vt/topo/helpers/copy.go +++ b/go/vt/topo/helpers/copy.go @@ -146,6 +146,11 @@ func CopyShardReplications(ctx context.Context, fromTS, toTS *topo.Server) { log.Fatalf("fromTS.GetKeyspaces: %v", err) } + cells, err := fromTS.GetCellInfoNames(ctx) + if err != nil { + log.Fatalf("GetCellInfoNames(): %v", err) + } + for _, keyspace := range keyspaces { shards, err := fromTS.GetShardNames(ctx, keyspace) if err != nil { @@ -153,14 +158,7 @@ func CopyShardReplications(ctx context.Context, fromTS, toTS *topo.Server) { } for _, shard := range shards { - - // read the source shard to get the cells - si, err := fromTS.GetShard(ctx, keyspace, shard) - if err != nil { - log.Fatalf("GetShard(%v, %v): %v", keyspace, shard, err) - } - - for _, cell := range si.Shard.Cells { + for _, cell := range cells { sri, err := fromTS.GetShardReplication(ctx, cell, keyspace, shard) if err != nil { log.Fatalf("GetShardReplication(%v, %v, %v): %v", cell, keyspace, shard, err) diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index eff52454207..2ffe984e720 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -56,6 +56,18 @@ func addCells(left, right []string) []string { return left } +// removeCellsFromList will remove the cells from the provided list. It returns +// the new list, and a boolean that indicates the returned list is empty. +func removeCellsFromList(cells, toRemove []string) []string { + leftoverCells := make([]string, 0, len(cells)) + for _, cell := range cells { + if !InCellList(cell, toRemove) { + leftoverCells = append(leftoverCells, cell) + } + } + return leftoverCells +} + // removeCells will remove the cells from the provided list. It returns // the new list, and a boolean that indicates the returned list is empty. func removeCells(cells, toRemove, fullList []string) ([]string, bool) { @@ -160,11 +172,6 @@ func (si *ShardInfo) HasMaster() bool { return !topoproto.TabletAliasIsZero(si.Shard.MasterAlias) } -// HasCell returns true if the cell is listed in the Cells for the shard. -func (si *ShardInfo) HasCell(cell string) bool { - return topoproto.ShardHasCell(si.Shard, cell) -} - // GetShard is a high level function to read shard data. // It generates trace spans. func (ts *Server) GetShard(ctx context.Context, keyspace, shard string) (*ShardInfo, error) { @@ -265,17 +272,15 @@ func (ts *Server) CreateShard(ctx context.Context, keyspace, shard string) (err return err } - // start the shard with all serving types. If it overlaps with - // other shards for some serving types, remove them. - servedTypes := map[topodatapb.TabletType]bool{ - topodatapb.TabletType_MASTER: true, - topodatapb.TabletType_REPLICA: true, - topodatapb.TabletType_RDONLY: true, - } value := &topodatapb.Shard{ KeyRange: keyRange, } + isMasterServing := true + + // start the shard IsMasterServing. If it overlaps with + // other shards for some serving types, remove them. + if IsShardUsingRangeBasedSharding(name) { // if we are using range-based sharding, we don't want // overlapping shards to all serve and confuse the clients. @@ -285,18 +290,12 @@ func (ts *Server) CreateShard(ctx context.Context, keyspace, shard string) (err } for _, si := range sis { if si.KeyRange == nil || key.KeyRangesIntersect(si.KeyRange, keyRange) { - for _, st := range si.ServedTypes { - delete(servedTypes, st.TabletType) - } + isMasterServing = false } } } - for st := range servedTypes { - value.ServedTypes = append(value.ServedTypes, &topodatapb.Shard_ServedType{ - TabletType: st, - }) - } + value.IsMasterServing = isMasterServing // Marshal and save. data, err := proto.Marshal(value) @@ -394,20 +393,14 @@ func (si *ShardInfo) UpdateSourceBlacklistedTables(ctx context.Context, tabletTy // trying to add more constraints with no existing record si.TabletControls = append(si.TabletControls, &topodatapb.Shard_TabletControl{ - TabletType: tabletType, - Cells: cells, - DisableQueryService: false, - BlacklistedTables: tables, + TabletType: tabletType, + Cells: cells, + BlacklistedTables: tables, }) return nil } // we have an existing record, check table lists matches and - // DisableQueryService is not set - if tc.DisableQueryService { - return fmt.Errorf("cannot safely alter BlacklistedTables as DisableQueryService is set for shard %v/%v", si.keyspace, si.shardName) - } - if remove { si.removeCellsFromTabletControl(tc, tabletType, cells) } else { @@ -420,54 +413,9 @@ func (si *ShardInfo) UpdateSourceBlacklistedTables(ctx context.Context, tabletTy return nil } -// UpdateDisableQueryService will make sure the disableQueryService is -// set appropriately in the shard record. Note we don't support a lot -// of the corner cases: -// - we don't support DisableQueryService at the same time as BlacklistedTables, -// because it's not used in the same context (vertical vs horizontal sharding) -// This function should be called while holding the keyspace lock. -func (si *ShardInfo) UpdateDisableQueryService(ctx context.Context, tabletType topodatapb.TabletType, cells []string, disableQueryService bool) error { - if err := CheckKeyspaceLocked(ctx, si.keyspace); err != nil { - return err - } - tc := si.GetTabletControl(tabletType) - if tc == nil { - // handle the case where the TabletControl object is new - if disableQueryService { - si.TabletControls = append(si.TabletControls, &topodatapb.Shard_TabletControl{ - TabletType: tabletType, - Cells: cells, - DisableQueryService: true, - BlacklistedTables: nil, - }) - } - return nil - } - - // we have an existing record, check table list is empty and - // DisableQueryService is set - if len(tc.BlacklistedTables) > 0 { - return fmt.Errorf("cannot safely alter DisableQueryService as BlacklistedTables is set") - } - if !tc.DisableQueryService { - // This code is unreachable because we always delete the control record when we enable QueryService. - return fmt.Errorf("cannot safely alter DisableQueryService as DisableQueryService is not set, this record should not be there for shard %v/%v", si.keyspace, si.shardName) - } - - if disableQueryService { - tc.Cells = addCells(tc.Cells, cells) - } else { - if tc.Frozen { - return fmt.Errorf("migrate has gone past the point of no return, cannot re-enable serving for %v/%v", si.keyspace, si.shardName) - } - si.removeCellsFromTabletControl(tc, tabletType, cells) - } - return nil -} - func (si *ShardInfo) removeCellsFromTabletControl(tc *topodatapb.Shard_TabletControl, tabletType topodatapb.TabletType, cells []string) { - result, emptyList := removeCells(tc.Cells, cells, si.Cells) - if emptyList { + result := removeCellsFromList(tc.Cells, cells) + if len(result) == 0 { // we don't have any cell left, we need to clear this record var tabletControls []*topodatapb.Shard_TabletControl for _, tc := range si.TabletControls { @@ -481,64 +429,42 @@ func (si *ShardInfo) removeCellsFromTabletControl(tc *topodatapb.Shard_TabletCon } } -// GetServedType returns the Shard_ServedType for a TabletType, or nil -func (si *ShardInfo) GetServedType(tabletType topodatapb.TabletType) *topodatapb.Shard_ServedType { - for _, st := range si.ServedTypes { - if st.TabletType == tabletType { - return st - } - } - return nil -} - -// GetServedTypesPerCell returns the list of types this shard is serving -// in the provided cell. -func (si *ShardInfo) GetServedTypesPerCell(cell string) []topodatapb.TabletType { - result := make([]topodatapb.TabletType, 0, len(si.ServedTypes)) - for _, st := range si.ServedTypes { - if InCellList(cell, st.Cells) { - result = append(result, st.TabletType) - } - } - return result -} - // UpdateServedTypesMap handles ServedTypesMap. It can add or remove cells. -func (si *ShardInfo) UpdateServedTypesMap(tabletType topodatapb.TabletType, cells []string, remove bool) error { - sst := si.GetServedType(tabletType) - - if remove { - if sst == nil { - // nothing to remove - return nil - } - result, emptyList := removeCells(sst.Cells, cells, si.Cells) - if emptyList { - // we don't have any cell left, we need to clear this record - var servedTypes []*topodatapb.Shard_ServedType - for _, st := range si.ServedTypes { - if st.TabletType != tabletType { - servedTypes = append(servedTypes, st) - } - } - si.ServedTypes = servedTypes - return nil - } - sst.Cells = result - return nil - } - - // add - if sst == nil { - si.ServedTypes = append(si.ServedTypes, &topodatapb.Shard_ServedType{ - TabletType: tabletType, - Cells: cells, - }) - return nil - } - sst.Cells = addCells(sst.Cells, cells) - return nil -} +// func (si *ShardInfo) UpdateServedTypesMap(tabletType topodatapb.TabletType, cells []string, remove bool) error { +// sst := si.GetServedType(tabletType) + +// if remove { +// if sst == nil { +// // nothing to remove +// return nil +// } +// result, emptyList := removeCells(sst.Cells, cells, si.Cells) +// if emptyList { +// // we don't have any cell left, we need to clear this record +// var servedTypes []*topodatapb.Shard_ServedType +// for _, st := range si.ServedTypes { +// if st.TabletType != tabletType { +// servedTypes = append(servedTypes, st) +// } +// } +// si.ServedTypes = servedTypes +// return nil +// } +// sst.Cells = result +// return nil +// } + +// // add +// if sst == nil { +// si.ServedTypes = append(si.ServedTypes, &topodatapb.Shard_ServedType{ +// TabletType: tabletType, +// Cells: cells, +// }) +// return nil +// } +// sst.Cells = addCells(sst.Cells, cells) +// return nil +// } // // Utility functions for shards @@ -602,25 +528,41 @@ func (ts *Server) FindAllTabletAliasesInShardByCell(ctx context.Context, keyspac wg := sync.WaitGroup{} mutex := sync.Mutex{} rec := concurrency.AllErrorRecorder{} - for _, cell := range si.Cells { - if !InCellList(cell, cells) { - continue + result := make([]*topodatapb.TabletAlias, 0, len(resultAsMap)) + for _, cell := range cells { + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + return result, err } - wg.Add(1) - go func(cell string) { - defer wg.Done() - sri, err := ts.GetShardReplication(ctx, cell, keyspace, shard) - if err != nil { - rec.RecordError(fmt.Errorf("GetShardReplication(%v, %v, %v) failed: %v", cell, keyspace, shard, err)) - return - } - mutex.Lock() - for _, node := range sri.Nodes { - resultAsMap[topoproto.TabletAliasString(node.TabletAlias)] = node.TabletAlias + shardInCell := func() bool { + for _, partition := range srvKeyspace.GetPartitions() { + for _, shardReference := range partition.ShardReferences { + if shardReference.GetName() == shard { + return true + } + } } - mutex.Unlock() - }(cell) + return false + }() + + if shardInCell { + wg.Add(1) + go func(cell string) { + defer wg.Done() + sri, err := ts.GetShardReplication(ctx, cell, keyspace, shard) + if err != nil { + rec.RecordError(fmt.Errorf("GetShardReplication(%v, %v, %v) failed: %v", cell, keyspace, shard, err)) + return + } + + mutex.Lock() + for _, node := range sri.Nodes { + resultAsMap[topoproto.TabletAliasString(node.TabletAlias)] = node.TabletAlias + } + mutex.Unlock() + }(cell) + } } wg.Wait() err = nil @@ -629,7 +571,6 @@ func (ts *Server) FindAllTabletAliasesInShardByCell(ctx context.Context, keyspac err = NewError(PartialResult, shard) } - result := make([]*topodatapb.TabletAlias, 0, len(resultAsMap)) for _, a := range resultAsMap { v := *a result = append(result, &v) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index c5d0a6ceb31..c9068269059 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -17,12 +17,19 @@ limitations under the License. package topo import ( + "bytes" + "encoding/hex" "fmt" "path" + "sync" "github.com/golang/protobuf/proto" + "golang.org/x/net/context" + "vitess.io/vitess/go/vt/concurrency" + "vitess.io/vitess/go/vt/topo/topoproto" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -115,6 +122,238 @@ func (ts *Server) GetSrvKeyspaceNames(ctx context.Context, cell string) ([]strin } } +// GetShardServingCells returns cells where this shard is serving +func (ts *Server) GetShardServingCells(ctx context.Context, si *ShardInfo) (servingCells []string, err error) { + cells, err := ts.GetCellInfoNames(ctx) + if err != nil { + return nil, err + } + + wg := sync.WaitGroup{} + rec := concurrency.AllErrorRecorder{} + servingCells = make([]string, len(cells)) + var mu sync.Mutex + for _, cell := range cells { + wg.Add(1) + go func(cell, keyspace string) { + defer wg.Done() + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) + switch { + case err != nil: + for _, partition := range srvKeyspace.GetPartitions() { + for _, shardReference := range partition.ShardReferences { + if shardReference.GetName() == si.ShardName() { + mu.Lock() + defer mu.Unlock() + servingCells = append(servingCells, cell) + } + } + } + case IsErrType(err, NoNode): + // NOOP + return + default: + rec.RecordError(err) + return + } + }(cell, si.Keyspace()) + } + wg.Wait() + if rec.HasErrors() { + return nil, NewError(PartialResult, rec.Error().Error()) + } + return servingCells, nil +} + +// GetShardServingTypes returns served types for given shard across all cells +func (ts *Server) GetShardServingTypes(ctx context.Context, si *ShardInfo) (servingTypes []topodatapb.TabletType, err error) { + cells, err := ts.GetCellInfoNames(ctx) + if err != nil { + return nil, err + } + + wg := sync.WaitGroup{} + rec := concurrency.AllErrorRecorder{} + servingTypes = make([]topodatapb.TabletType, len(cells)) + var mu sync.Mutex + for _, cell := range cells { + wg.Add(1) + go func(cell, keyspace string) { + defer wg.Done() + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) + switch { + case err != nil: + for _, partition := range srvKeyspace.GetPartitions() { + for _, shardReference := range partition.ShardReferences { + if shardReference.GetName() == si.ShardName() { + mu.Lock() + defer mu.Unlock() + found := false + for _, servingType := range servingTypes { + if servingType == partition.ServedType { + found = true + } + } + if !found { + servingTypes = append(servingTypes, partition.ServedType) + } + } + } + } + case IsErrType(err, NoNode): + // NOOP + return + default: + rec.RecordError(err) + return + } + }(cell, si.Keyspace()) + } + wg.Wait() + if rec.HasErrors() { + return nil, NewError(PartialResult, rec.Error().Error()) + } + return servingTypes, nil +} + +// RemoveShardServingKeyspace ... +func (ts *Server) RemoveShardServingKeyspace(ctx context.Context, si *ShardInfo, cells []string) (err error) { + if err = CheckKeyspaceLocked(ctx, si.keyspace); err != nil { + return err + } + + // The caller intents to update all cells in this case + if len(cells) == 0 { + cells, err = ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + } + + wg := sync.WaitGroup{} + rec := concurrency.AllErrorRecorder{} + for _, cell := range cells { + wg.Add(1) + go func(cell, keyspace string) { + defer wg.Done() + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) + switch { + case err == nil: + shardReferences := make([]*topodatapb.ShardReference, 0) + for _, partition := range srvKeyspace.GetPartitions() { + + for _, shardReference := range partition.ShardReferences { + if shardReference.GetName() != si.ShardName() { + shardReferences = append(shardReferences, shardReference) + } + } + if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { + rec.RecordError(err) + return + } + + } + + if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { + rec.RecordError(err) + return + } + err = ts.UpdateSrvKeyspace(ctx, cell, si.keyspace, srvKeyspace) + if err != nil { + rec.RecordError(err) + return + } + case IsErrType(err, NoNode): + // NOOP + default: + rec.RecordError(err) + return + } + if err != nil { + rec.RecordError(err) + return + } + }(cell, si.Keyspace()) + } + wg.Wait() + if rec.HasErrors() { + return NewError(PartialResult, rec.Error().Error()) + } + return nil +} + +// UpdateDisableQueryService will make sure the disableQueryService is +// set appropriately in the shard record. Note we don't support a lot +// of the corner cases: +// - we don't support DisableQueryService at the same time as BlacklistedTables, +// because it's not used in the same context (vertical vs horizontal sharding) +// This function should be called while holding the keyspace lock. +func (ts *Server) UpdateDisableQueryService(ctx context.Context, si *ShardInfo, tabletType topodatapb.TabletType, cells []string, disableQueryService bool) (err error) { + if err = CheckKeyspaceLocked(ctx, si.keyspace); err != nil { + return err + } + tc := si.GetTabletControl(tabletType) + // we have an existing record, check table list is empty and + // DisableQueryService is set + if tc != nil && len(tc.BlacklistedTables) > 0 { + return fmt.Errorf("cannot safely alter DisableQueryService as BlacklistedTables is set") + } + + // The caller intents to update all cells in this case + if len(cells) == 0 { + cells, err = ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + } + + wg := sync.WaitGroup{} + rec := concurrency.AllErrorRecorder{} + for _, cell := range cells { + wg.Add(1) + go func(cell, keyspace string) { + defer wg.Done() + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) + if err != nil { + rec.RecordError(err) + return + } + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } + found := false + for _, tabletControl := range partition.GetShardTabletControls() { + if tabletControl.GetName() == si.ShardName() { + found = true + tabletControl.QueryServiceDisabled = disableQueryService + } + } + + if !found { + shardTabletControl := &topodatapb.ShardTabletControl{ + Name: si.ShardName(), + KeyRange: si.KeyRange, + QueryServiceDisabled: true, + } + partition.ShardTabletControls = append(partition.GetShardTabletControls(), shardTabletControl) + } + } + err = ts.UpdateSrvKeyspace(ctx, cell, si.keyspace, srvKeyspace) + if err != nil { + rec.RecordError(err) + return + } + + }(cell, si.Keyspace()) + } + wg.Wait() + if rec.HasErrors() { + return NewError(PartialResult, rec.Error().Error()) + } + return nil +} + // UpdateSrvKeyspace saves a new SrvKeyspace. It is a blind write. func (ts *Server) UpdateSrvKeyspace(ctx context.Context, cell, keyspace string, srvKeyspace *topodatapb.SrvKeyspace) error { conn, err := ts.ConnForCell(ctx, cell) @@ -142,6 +381,28 @@ func (ts *Server) DeleteSrvKeyspace(ctx context.Context, cell, keyspace string) return conn.Delete(ctx, nodePath, nil) } +// GetSrvKeyspaceAllCells returns the SrvKeyspace for all cells +func (ts *Server) GetSrvKeyspaceAllCells(ctx context.Context, keyspace string) ([]*topodatapb.SrvKeyspace, error) { + cells, err := ts.GetCellInfoNames(ctx) + if err != nil { + return nil, err + } + + srvKeyspaces := make([]*topodatapb.SrvKeyspace, len(cells)) + for _, cell := range cells { + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + switch { + case err == nil: + srvKeyspaces = append(srvKeyspaces, srvKeyspace) + case IsErrType(err, NoNode): + // NOOP + default: + return srvKeyspaces, err + } + } + return srvKeyspaces, nil +} + // GetSrvKeyspace returns the SrvKeyspace for a cell/keyspace. func (ts *Server) GetSrvKeyspace(ctx context.Context, cell, keyspace string) (*topodatapb.SrvKeyspace, error) { conn, err := ts.ConnForCell(ctx, cell) @@ -160,3 +421,54 @@ func (ts *Server) GetSrvKeyspace(ctx context.Context, cell, keyspace string) (*t } return srvKeyspace, nil } + +// OrderAndCheckPartitions will re-order the partition list, and check +// it's correct. +func OrderAndCheckPartitions(cell string, srvKeyspace *topodatapb.SrvKeyspace) error { + // now check them all + for _, partition := range srvKeyspace.Partitions { + tabletType := partition.ServedType + topoproto.ShardReferenceArray(partition.ShardReferences).Sort() + + // check the first Start is MinKey, the last End is MaxKey, + // and the values in between match: End[i] == Start[i+1] + first := partition.ShardReferences[0] + if first.KeyRange != nil && len(first.KeyRange.Start) != 0 { + return fmt.Errorf("keyspace partition for %v in cell %v does not start with min key", tabletType, cell) + } + last := partition.ShardReferences[len(partition.ShardReferences)-1] + if last.KeyRange != nil && len(last.KeyRange.End) != 0 { + return fmt.Errorf("keyspace partition for %v in cell %v does not end with max key", tabletType, cell) + } + for i := range partition.ShardReferences[0 : len(partition.ShardReferences)-1] { + currShard := partition.ShardReferences[i] + nextShard := partition.ShardReferences[i+1] + currHasKeyRange := currShard.KeyRange != nil + nextHasKeyRange := nextShard.KeyRange != nil + if currHasKeyRange != nextHasKeyRange { + return fmt.Errorf("shards with inconsistent KeyRanges for %v in cell %v. shards: %v, %v", tabletType, cell, currShard, nextShard) + } + if !currHasKeyRange { + // this is the custom sharding case, all KeyRanges must be nil + continue + } + if bytes.Compare(currShard.KeyRange.End, nextShard.KeyRange.Start) != 0 { + return fmt.Errorf("non-contiguous KeyRange values for %v in cell %v at shard %v to %v: %v != %v", tabletType, cell, i, i+1, hex.EncodeToString(currShard.KeyRange.End), hex.EncodeToString(nextShard.KeyRange.Start)) + } + } + } + + return nil +} + +// ShardIsServing returns true if this shard is found in any of the partitions in the srvKeyspace +func ShardIsServing(srvKeyspace *topodatapb.SrvKeyspace, shard *topodatapb.Shard) bool { + for _, partition := range srvKeyspace.GetPartitions() { + for _, shardReference := range partition.GetShardReferences() { + if shardReference.GetKeyRange() == shard.KeyRange { + return true + } + } + } + return false +} diff --git a/go/vt/topo/topoproto/shard.go b/go/vt/topo/topoproto/shard.go index 9db710f6f9d..d7d837019be 100644 --- a/go/vt/topo/topoproto/shard.go +++ b/go/vt/topo/topoproto/shard.go @@ -61,13 +61,3 @@ func SourceShardAsHTML(source *topodatapb.Shard_SourceShard) template.HTML { } return template.HTML(result) } - -// ShardHasCell returns true if the cell is listed in the Cells for the shard. -func ShardHasCell(shard *topodatapb.Shard, cell string) bool { - for _, c := range shard.Cells { - if c == cell { - return true - } - } - return false -} diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index 8a29f1e6231..c55e58dae91 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -17,8 +17,6 @@ limitations under the License. package topotools import ( - "bytes" - "encoding/hex" "fmt" "sync" @@ -42,25 +40,6 @@ func RebuildKeyspace(ctx context.Context, log logutil.Logger, ts *topo.Server, k return RebuildKeyspaceLocked(ctx, log, ts, keyspace, cells) } -// findCellsForRebuild will find all the cells in the given keyspace -// and create an entry if the map for them -func findCellsForRebuild(ki *topo.KeyspaceInfo, shardMap map[string]*topo.ShardInfo, cells []string, srvKeyspaceMap map[string]*topodatapb.SrvKeyspace) { - for _, si := range shardMap { - for _, cell := range si.Cells { - if !topo.InCellList(cell, cells) { - continue - } - if _, ok := srvKeyspaceMap[cell]; !ok { - srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ - ShardingColumnName: ki.ShardingColumnName, - ShardingColumnType: ki.ShardingColumnType, - ServedFrom: ki.ComputeCellServedFrom(cell), - } - } - } - } -} - // RebuildKeyspaceLocked should only be used with an action lock on the keyspace // - otherwise the consistency of the serving graph data can't be // guaranteed. @@ -90,15 +69,24 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser // key: cell // value: topo.SrvKeyspace object being built srvKeyspaceMap := make(map[string]*topodatapb.SrvKeyspace) - findCellsForRebuild(ki, shards, cells, srvKeyspaceMap) - - // Then we add the cells from the keyspaces we might be 'ServedFrom'. - for _, ksf := range ki.ServedFroms { - servedFromShards, err := ts.FindAllShardsInKeyspace(ctx, ksf.Keyspace) - if err != nil { - return err + for _, cell := range cells { + _, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + switch { + case err == nil: + // NOOP + case topo.IsErrType(err, topo.NoNode): + if _, ok := srvKeyspaceMap[cell]; !ok { + srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ + ShardingColumnName: ki.ShardingColumnName, + ShardingColumnType: ki.ShardingColumnType, + ServedFrom: ki.ComputeCellServedFrom(cell), + } + } + default: + // Couldn't get srvKeyspace, not + log.Warningf("Couldn't get srvKeyspace for cell %v, skip rebuilding", cell) } - findCellsForRebuild(ki, servedFromShards, cells, srvKeyspaceMap) + } // for each entry in the srvKeyspaceMap map, we do the following: @@ -108,9 +96,12 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser // - sort the shards in the list by range // - check the ranges are compatible (no hole, covers everything) for cell, srvKeyspace := range srvKeyspaceMap { + // this is not an error for _, si := range shards { - servedTypes := si.GetServedTypesPerCell(cell) - + if !si.IsMasterServing { + continue + } + servedTypes := []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY} // for each type this shard is supposed to serve, // add it to srvKeyspace.Partitions for _, tabletType := range servedTypes { @@ -128,11 +119,11 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser } } - if err := orderAndCheckPartitions(cell, srvKeyspace); err != nil { + if err := topo.OrderAndCheckPartitions(cell, srvKeyspace); err != nil { return err } - } + } // And then finally save the keyspace objects, in parallel. rec := concurrency.AllErrorRecorder{} wg := sync.WaitGroup{} @@ -149,42 +140,3 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser wg.Wait() return rec.Error() } - -// orderAndCheckPartitions will re-order the partition list, and check -// it's correct. -func orderAndCheckPartitions(cell string, srvKeyspace *topodatapb.SrvKeyspace) error { - // now check them all - for _, partition := range srvKeyspace.Partitions { - tabletType := partition.ServedType - topoproto.ShardReferenceArray(partition.ShardReferences).Sort() - - // check the first Start is MinKey, the last End is MaxKey, - // and the values in between match: End[i] == Start[i+1] - first := partition.ShardReferences[0] - if first.KeyRange != nil && len(first.KeyRange.Start) != 0 { - return fmt.Errorf("keyspace partition for %v in cell %v does not start with min key", tabletType, cell) - } - last := partition.ShardReferences[len(partition.ShardReferences)-1] - if last.KeyRange != nil && len(last.KeyRange.End) != 0 { - return fmt.Errorf("keyspace partition for %v in cell %v does not end with max key", tabletType, cell) - } - for i := range partition.ShardReferences[0 : len(partition.ShardReferences)-1] { - currShard := partition.ShardReferences[i] - nextShard := partition.ShardReferences[i+1] - currHasKeyRange := currShard.KeyRange != nil - nextHasKeyRange := nextShard.KeyRange != nil - if currHasKeyRange != nextHasKeyRange { - return fmt.Errorf("shards with inconsistent KeyRanges for %v in cell %v. shards: %v, %v", tabletType, cell, currShard, nextShard) - } - if !currHasKeyRange { - // this is the custom sharding case, all KeyRanges must be nil - continue - } - if bytes.Compare(currShard.KeyRange.End, nextShard.KeyRange.Start) != 0 { - return fmt.Errorf("non-contiguous KeyRange values for %v in cell %v at shard %v to %v: %v != %v", tabletType, cell, i, i+1, hex.EncodeToString(currShard.KeyRange.End), hex.EncodeToString(nextShard.KeyRange.Start)) - } - } - } - - return nil -} diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index 50b106ca977..eda5a4ed114 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -1319,7 +1319,10 @@ func commandSetShardTabletControl(ctx context.Context, wr *wrangler.Wrangler, su cells = strings.Split(*cellsStr, ",") } - return wr.SetShardTabletControl(ctx, keyspace, shard, tabletType, cells, *remove, *disableQueryService, blacklistedTables) + if len(blacklistedTables) > 0 { + return wr.SetShardTabletControl(ctx, keyspace, shard, tabletType, cells, *remove, blacklistedTables) + } + return wr.UpdateDisableQueryService(ctx, keyspace, shard, tabletType, cells, *disableQueryService) } func commandSourceShardDelete(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { diff --git a/go/vt/vttablet/tabletmanager/init_tablet.go b/go/vt/vttablet/tabletmanager/init_tablet.go index 804590d2d82..1e418cfa6f9 100644 --- a/go/vt/vttablet/tabletmanager/init_tablet.go +++ b/go/vt/vttablet/tabletmanager/init_tablet.go @@ -122,22 +122,6 @@ func (agent *ActionAgent) InitTablet(port, gRPCPort int32) error { } } - // See if we need to add the tablet's cell to the shard's cell list. - if !si.HasCell(agent.TabletAlias.Cell) { - if err := agent.withRetry(ctx, "updating Cells list in Shard if necessary", func() error { - si, err = agent.TopoServer.UpdateShardFields(ctx, *initKeyspace, shard, func(si *topo.ShardInfo) error { - if si.HasCell(agent.TabletAlias.Cell) { - // Someone else already did it. - return topo.NewError(topo.NoUpdateNeeded, agent.TabletAlias.String()) - } - si.Cells = append(si.Cells, agent.TabletAlias.Cell) - return nil - }) - return err - }); err != nil { - return vterrors.Wrap(err, "couldn't add tablet's cell to shard record") - } - } log.Infof("Initializing the tablet for type %v", tabletType) // figure out the hostname diff --git a/go/vt/vttablet/tabletmanager/state_change.go b/go/vt/vttablet/tabletmanager/state_change.go index 8dafe948279..0b815ac22da 100644 --- a/go/vt/vttablet/tabletmanager/state_change.go +++ b/go/vt/vttablet/tabletmanager/state_change.go @@ -217,12 +217,25 @@ func (agent *ActionAgent) changeCallback(ctx context.Context, oldTablet, newTabl disallowQueryReason = "master tablet with filtered replication on" } } + srvKeyspace, err := agent.TopoServer.GetSrvKeyspace(ctx, newTablet.Alias.Cell, newTablet.Keyspace) + if err != nil { + log.Error("Fail to get SrvKeyspace") + } else { + + for _, partition := range srvKeyspace.GetPartitions() { + for _, tabletControl := range partition.GetShardTabletControls() { + if tabletControl.Name == newTablet.Shard { + if tabletControl.QueryServiceDisabled { + allowQuery = false + disallowQueryReason = "SrvKeyspace.QueryServiceEnabled set to false" + } + } + } + } + } if tc := shardInfo.GetTabletControl(newTablet.Type); tc != nil { if topo.InCellList(newTablet.Alias.Cell, tc.Cells) { - if tc.DisableQueryService { - allowQuery = false - disallowQueryReason = "TabletControl.DisableQueryService set" - } + blacklistedTables = tc.BlacklistedTables } } diff --git a/go/vt/worker/legacy_split_clone.go b/go/vt/worker/legacy_split_clone.go index 3a870245688..a510ee57728 100644 --- a/go/vt/worker/legacy_split_clone.go +++ b/go/vt/worker/legacy_split_clone.go @@ -290,7 +290,12 @@ func (scw *LegacySplitCloneWorker) init(ctx context.Context) error { // one side should have served types, the other one none, // figure out wich is which, then double check them all - if len(os.Left[0].ServedTypes) > 0 { + + leftServingTypes, err := scw.wr.TopoServer().GetShardServingTypes(ctx, os.Left[0]) + if err != nil { + return fmt.Errorf("cannot get shard serving cells for: %v", os.Left[0]) + } + if len(leftServingTypes) > 0 { scw.sourceShards = os.Left scw.destinationShards = os.Right } else { @@ -311,13 +316,29 @@ func (scw *LegacySplitCloneWorker) init(ctx context.Context) error { servingTypes := []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY} for _, st := range servingTypes { for _, si := range scw.sourceShards { - if si.GetServedType(st) == nil { + shardServingTypes, err := scw.wr.TopoServer().GetShardServingTypes(ctx, si) + if err != nil { + return fmt.Errorf("failed to get ServingTypes for source shard %v/%v", si.Keyspace(), si.ShardName()) + + } + found := false + for _, shardServingType := range shardServingTypes { + if shardServingType == st { + found = true + } + } + if !found { return fmt.Errorf("source shard %v/%v is not serving type %v", si.Keyspace(), si.ShardName(), st) } } } for _, si := range scw.destinationShards { - if len(si.ServedTypes) > 0 { + shardServingTypes, err := scw.wr.TopoServer().GetShardServingTypes(ctx, si) + if err != nil { + return fmt.Errorf("failed to get ServingTypes for destination shard %v/%v", si.Keyspace(), si.ShardName()) + + } + if len(shardServingTypes) > 0 { return fmt.Errorf("destination shard %v/%v is serving some types", si.Keyspace(), si.ShardName()) } } diff --git a/go/vt/worker/split_clone.go b/go/vt/worker/split_clone.go index 3f4369eb976..34f09a3cccb 100644 --- a/go/vt/worker/split_clone.go +++ b/go/vt/worker/split_clone.go @@ -550,7 +550,7 @@ func (scw *SplitCloneWorker) init(ctx context.Context) error { } } - if err := scw.sanityCheckShardInfos(); err != nil { + if err := scw.sanityCheckShardInfos(ctx); err != nil { return vterrors.Wrap(err, "failed sanityCheckShardInfos") } @@ -596,7 +596,11 @@ func (scw *SplitCloneWorker) initShardsForHorizontalResharding(ctx context.Conte // one side should have served types, the other one none, // figure out wich is which, then double check them all - if len(os.Left[0].ServedTypes) > 0 { + leftServingTypes, err := scw.wr.TopoServer().GetShardServingTypes(ctx, os.Left[0]) + if err != nil { + return fmt.Errorf("cannot get shard serving cells for: %v", os.Left[0]) + } + if len(leftServingTypes) > 0 { scw.sourceShards = os.Left scw.destinationShards = os.Right } else { @@ -662,7 +666,7 @@ func (scw *SplitCloneWorker) initShardsForVerticalSplit(ctx context.Context) err return nil } -func (scw *SplitCloneWorker) sanityCheckShardInfos() error { +func (scw *SplitCloneWorker) sanityCheckShardInfos(ctx context.Context) error { // Verify that filtered replication is not already enabled. for _, si := range scw.destinationShards { if len(si.SourceShards) > 0 { @@ -674,7 +678,18 @@ func (scw *SplitCloneWorker) sanityCheckShardInfos() error { // Verify that the source is serving all serving types. for _, st := range servingTypes { for _, si := range scw.sourceShards { - if si.GetServedType(st) == nil { + shardServingTypes, err := scw.wr.TopoServer().GetShardServingTypes(ctx, si) + if err != nil { + return fmt.Errorf("failed to get ServingTypes for source shard %v/%v", si.Keyspace(), si.ShardName()) + + } + found := false + for _, shardServingType := range shardServingTypes { + if shardServingType == st { + found = true + } + } + if !found { return fmt.Errorf("source shard %v/%v is not serving type %v", si.Keyspace(), si.ShardName(), st) } } @@ -684,15 +699,32 @@ func (scw *SplitCloneWorker) sanityCheckShardInfos() error { case horizontalResharding: // Verify that the destination is not serving yet. for _, si := range scw.destinationShards { - if len(si.ServedTypes) > 0 { + shardServingTypes, err := scw.wr.TopoServer().GetShardServingTypes(ctx, si) + if err != nil { + return fmt.Errorf("failed to get ServingTypes for destination shard %v/%v", si.Keyspace(), si.ShardName()) + + } + if len(shardServingTypes) > 0 { return fmt.Errorf("destination shard %v/%v is serving some types", si.Keyspace(), si.ShardName()) } } + case verticalSplit: // Verify that the destination is serving all types. for _, st := range servingTypes { for _, si := range scw.destinationShards { - if si.GetServedType(st) == nil { + shardServingTypes, err := scw.wr.TopoServer().GetShardServingTypes(ctx, si) + if err != nil { + return fmt.Errorf("failed to get ServingTypes for source shard %v/%v", si.Keyspace(), si.ShardName()) + + } + found := false + for _, shardServingType := range shardServingTypes { + if shardServingType == st { + found = true + } + } + if !found { return fmt.Errorf("source shard %v/%v is not serving type %v", si.Keyspace(), si.ShardName(), st) } } diff --git a/go/vt/workflow/reshardingworkflowgen/workflow.go b/go/vt/workflow/reshardingworkflowgen/workflow.go index d3d655bf98d..50bd4de9ece 100644 --- a/go/vt/workflow/reshardingworkflowgen/workflow.go +++ b/go/vt/workflow/reshardingworkflowgen/workflow.go @@ -167,7 +167,11 @@ func findSourceAndDestinationShards(ts *topo.Server, keyspace string) ([][][]str var sourceShardInfo *topo.ShardInfo var destinationShardInfos []*topo.ShardInfo // Judge which side is source shard by checking the number of servedTypes. - if len(os.Left[0].ServedTypes) > 0 { + leftServingTypes, err := ts.GetShardServingTypes(context.Background(), os.Left[0]) + if err != nil { + return nil, err + } + if len(leftServingTypes) > 0 { sourceShardInfo = os.Left[0] destinationShardInfos = os.Right } else { diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index a98a467feef..a0341bf357d 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -145,9 +145,7 @@ func (wr *Wrangler) printShards(ctx context.Context, si []*topo.ShardInfo) error wr.Logger().Printf(" %v\n", row) } } - if len(si.ServedTypes) != 0 { - wr.Logger().Printf(" Served Types: %v\n", si.ServedTypes) - } + wr.Logger().Printf(" Served Types: %v\n", si.IsMasterServing) if len(si.TabletControls) != 0 { wr.Logger().Printf(" Tablet Controls: %v\n", si.TabletControls) } @@ -191,9 +189,18 @@ func (wr *Wrangler) cancelHorizontalResharding(ctx context.Context, keyspace, sh if err != nil { return err } + + // get srvKeyspaces in all cells to check if they are already serving this shard + srvKeyspaces, err := wr.ts.GetSrvKeyspaceAllCells(ctx, keyspace) + if err != nil { + return err + } + for _, si := range destinationShards { - if len(si.ServedTypes) != 0 { - return fmt.Errorf("some served types have migrated for %v/%v, please undo them before canceling", keyspace, shard) + for _, srvKeyspace := range srvKeyspaces { + if topo.ShardIsServing(srvKeyspace, si.Shard) { + return fmt.Errorf("some served types have migrated for %v/%v, please undo them before canceling", keyspace, shard) + } } } for i, si := range destinationShards { @@ -491,14 +498,26 @@ func (wr *Wrangler) replicaMigrateServedType(ctx context.Context, keyspace strin // masterMigrateServedType operates with the keyspace locked func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string, sourceShards, destinationShards []*topo.ShardInfo, filteredReplicationWaitTime time.Duration, reverseReplication bool) (err error) { // Ensure other served types have migrated. - if si := sourceShards[0]; len(si.ServedTypes) > 1 { + srvKeyspaces, err := wr.ts.GetSrvKeyspaceAllCells(ctx, keyspace) + if err != nil { + return err + } + + si := sourceShards[0] + for _, srvKeyspace := range srvKeyspaces { var types []string - for _, servedType := range si.ServedTypes { - if servedType.TabletType != topodatapb.TabletType_MASTER { - types = append(types, servedType.TabletType.String()) + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != topodatapb.TabletType_MASTER { + for _, shardReference := range partition.GetShardReferences() { + if shardReference.GetKeyRange() == si.GetKeyRange() { + types = append(types, partition.GetServedType().String()) + } + } } } - return fmt.Errorf("cannot migrate MASTER away from %v/%v until everything else is migrated. Make sure that the following types are migrated first: %v", si.Keyspace(), si.ShardName(), strings.Join(types, ", ")) + if len(types) > 0 { + return fmt.Errorf("cannot migrate MASTER away from %v/%v until everything else is migrated. Make sure that the following types are migrated first: %v", si.Keyspace(), si.ShardName(), strings.Join(types, ", ")) + } } ev := &events.MigrateServedTypes{ @@ -577,19 +596,14 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string } // Similar to updateShardRecords, but we also remove SourceShards. destinationShards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { - if err := si.UpdateServedTypesMap(topodatapb.TabletType_MASTER, nil, false); err != nil { - return err - } - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_MASTER, nil, false); err != nil { - return err - } - si.SourceShards = nil return nil }) if err != nil { return err } + wr.ts.UpdateDisableQueryService(ctx, si, topodatapb.TabletType_MASTER, nil, false) + } event.DispatchUpdate(ev, "setting destination masters read-write") @@ -700,15 +714,20 @@ func (wr *Wrangler) startReverseReplication(ctx context.Context, sourceShards [] // updateShardRecords updates the shard records based on 'from' or 'to' direction. func (wr *Wrangler) updateShardRecords(ctx context.Context, shards []*topo.ShardInfo, cells []string, servedType topodatapb.TabletType, isFrom bool, clearSourceShards bool) (err error) { for i, si := range shards { + + err := wr.ts.UpdateDisableQueryService(ctx, si, servedType, cells, isFrom /* disable */) + + if err != nil { + return err + } + shards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { if clearSourceShards { si.SourceShards = nil } - if err := si.UpdateServedTypesMap(servedType, cells, isFrom /* remove */); err != nil { - return err - } - return si.UpdateDisableQueryService(ctx, servedType, cells, isFrom /* disable */) + return nil }) + if err != nil { return err } @@ -747,13 +766,13 @@ func (wr *Wrangler) updateFrozenFlag(ctx context.Context, shards []*topo.ShardIn // be observed. func (wr *Wrangler) WaitForDrain(ctx context.Context, cells []string, keyspace, shard string, servedType topodatapb.TabletType, retryDelay, healthCheckTopologyRefresh, healthcheckRetryDelay, healthCheckTimeout, initialWait time.Duration) error { + var err error if len(cells) == 0 { // Retrieve list of cells for the shard from the topology. - shardInfo, err := wr.ts.GetShard(ctx, keyspace, shard) + cells, err = wr.ts.GetCellInfoNames(ctx) if err != nil { - return fmt.Errorf("failed to retrieve list of all cells. GetShard() failed: %v", err) + return fmt.Errorf("failed to retrieve list of all cells. GetCellInfoNames() failed: %v", err) } - cells = shardInfo.Cells } // Check all cells in parallel. @@ -976,7 +995,8 @@ func (wr *Wrangler) migrateServedFromLocked(ctx context.Context, ki *topo.Keyspa if reverse { ki.UpdateServedFromMap(servedType, cells, destinationShard.SourceShards[0].Keyspace, false, nil) } else { - ki.UpdateServedFromMap(servedType, cells, destinationShard.SourceShards[0].Keyspace, true, destinationShard.Cells) + // Check with Sugi, I think in this world, there is no longer the concept of a destinationShard.Cells, so it must be think as all cells all the time. + ki.UpdateServedFromMap(servedType, cells, destinationShard.SourceShards[0].Keyspace, true, nil) } // re-read and check the destination shard diff --git a/go/vt/wrangler/shard.go b/go/vt/wrangler/shard.go index 9719cf3b10d..2e9de76856c 100644 --- a/go/vt/wrangler/shard.go +++ b/go/vt/wrangler/shard.go @@ -30,14 +30,11 @@ import ( // updateShardCellsAndMaster will update the 'Cells' and possibly // MasterAlias records for the shard, if needed. -func (wr *Wrangler) updateShardCellsAndMaster(ctx context.Context, si *topo.ShardInfo, tabletAlias *topodatapb.TabletAlias, tabletType topodatapb.TabletType, allowMasterOverride bool) error { +func (wr *Wrangler) updateShardMaster(ctx context.Context, si *topo.ShardInfo, tabletAlias *topodatapb.TabletAlias, tabletType topodatapb.TabletType, allowMasterOverride bool) error { // See if we need to update the Shard: // - add the tablet's cell to the shard's Cells if needed // - change the master if needed shardUpdateRequired := false - if !si.HasCell(tabletAlias.Cell) { - shardUpdateRequired = true - } if tabletType == topodatapb.TabletType_MASTER && !topoproto.TabletAliasEqual(si.MasterAlias, tabletAlias) { shardUpdateRequired = true } @@ -48,10 +45,6 @@ func (wr *Wrangler) updateShardCellsAndMaster(ctx context.Context, si *topo.Shar // run the update _, err := wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(s *topo.ShardInfo) error { wasUpdated := false - if !s.HasCell(tabletAlias.Cell) { - s.Cells = append(s.Cells, tabletAlias.Cell) - wasUpdated = true - } if tabletType == topodatapb.TabletType_MASTER && !topoproto.TabletAliasEqual(s.MasterAlias, tabletAlias) { if !topoproto.TabletAliasIsZero(s.MasterAlias) && !allowMasterOverride { @@ -81,26 +74,20 @@ func (wr *Wrangler) SetShardServedTypes(ctx context.Context, keyspace, shard str defer unlock(&err) // and update the shard - _, err = wr.ts.UpdateShardFields(ctx, keyspace, shard, func(si *topo.ShardInfo) error { - return si.UpdateServedTypesMap(servedType, cells, remove) - }) + // TODO: What should we do with this method? + //_, err = wr.ts.UpdateShardFields(ctx, keyspace, shard, func(si *topo.ShardInfo) error { + //return si.UpdateServedTypesMap(servedType, cells, remove) + //}) return err } // SetShardTabletControl changes the TabletControl records // for a shard. It does not rebuild any serving graph or do // cross-shard consistency check. -// - if disableQueryService is set, tables has to be empty -// - if disableQueryService is not set, and tables is empty, we remove -// the TabletControl record for the cells +// - sets black listed tables in tablet control record // // This takes the keyspace lock as to not interfere with resharding operations. -func (wr *Wrangler) SetShardTabletControl(ctx context.Context, keyspace, shard string, tabletType topodatapb.TabletType, cells []string, remove, disableQueryService bool, blacklistedTables []string) (err error) { - // check input - if disableQueryService && len(blacklistedTables) > 0 { - return fmt.Errorf("SetShardTabletControl cannot have both DisableQueryService and BlacklistedTables set") - } - +func (wr *Wrangler) SetShardTabletControl(ctx context.Context, keyspace, shard string, tabletType topodatapb.TabletType, cells []string, remove bool, blacklistedTables []string) (err error) { // lock the keyspace ctx, unlock, lockErr := wr.ts.LockKeyspace(ctx, keyspace, "SetShardTabletControl") if lockErr != nil { @@ -110,17 +97,32 @@ func (wr *Wrangler) SetShardTabletControl(ctx context.Context, keyspace, shard s // update the shard _, err = wr.ts.UpdateShardFields(ctx, keyspace, shard, func(si *topo.ShardInfo) error { - if len(blacklistedTables) == 0 && !remove { - // we are setting the DisableQueryService flag only - return si.UpdateDisableQueryService(ctx, tabletType, cells, disableQueryService) - } - // we are setting / removing the blacklisted tables only return si.UpdateSourceBlacklistedTables(ctx, tabletType, cells, remove, blacklistedTables) }) return err } +// UpdateDisableQueryService changes the TabletControl records +// for a shard. It updates serving graph +// +// This takes the keyspace lock as to not interfere with resharding operations. +func (wr *Wrangler) UpdateDisableQueryService(ctx context.Context, keyspace, shard string, tabletType topodatapb.TabletType, cells []string, disableQueryService bool) (err error) { + // lock the keyspace + ctx, unlock, lockErr := wr.ts.LockKeyspace(ctx, keyspace, "SetShardTabletControl") + if lockErr != nil { + return lockErr + } + defer unlock(&err) + + si, err := wr.ts.GetShard(ctx, keyspace, shard) + if err != nil { + return err + } + // disable query service for shard + return wr.ts.UpdateDisableQueryService(ctx, si, tabletType, cells, disableQueryService) +} + // DeleteShard will do all the necessary changes in the topology server // to entirely remove a shard. func (wr *Wrangler) DeleteShard(ctx context.Context, keyspace, shard string, recursive, evenIfServing bool) error { @@ -135,14 +137,23 @@ func (wr *Wrangler) DeleteShard(ctx context.Context, keyspace, shard string, rec return err } + servingCells, err := wr.ts.GetShardServingCells(ctx, shardInfo) + if err != nil { + return err + } // Check the Serving map for the shard, we don't want to // remove a serving shard if not absolutely sure. - if !evenIfServing && len(shardInfo.ServedTypes) > 0 { + if !evenIfServing && len(servingCells) > 0 { return fmt.Errorf("shard %v/%v is still serving, cannot delete it, use even_if_serving flag if needed", keyspace, shard) } + cells, err := wr.ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + // Go through all the cells. - for _, cell := range shardInfo.Cells { + for _, cell := range cells { var aliases []*topodatapb.TabletAlias // Get the ShardReplication object for that cell. Try @@ -216,7 +227,7 @@ func (wr *Wrangler) DeleteShard(ctx context.Context, keyspace, shard string, rec // Try to remove the replication graph and serving graph in each cell, // regardless of its existence. - for _, cell := range shardInfo.Cells { + for _, cell := range cells { if err := wr.ts.DeleteShardReplication(ctx, cell, keyspace, shard); err != nil && !topo.IsErrType(err, topo.NoNode) { wr.Logger().Warningf("Cannot delete ShardReplication in cell %v for %v/%v: %v", cell, keyspace, shard, err) } @@ -240,8 +251,10 @@ func (wr *Wrangler) RemoveShardCell(ctx context.Context, keyspace, shard, cell s return err } + shardServingCells, err := wr.ts.GetShardServingCells(ctx, shardInfo) + // check the cell is in the list already - if !topo.InCellList(cell, shardInfo.Cells) { + if !topo.InCellList(cell, shardServingCells) { return fmt.Errorf("cell %v in not in shard info", cell) } @@ -286,22 +299,9 @@ func (wr *Wrangler) RemoveShardCell(ctx context.Context, keyspace, shard, cell s } // now we can update the shard - wr.Logger().Infof("Removing cell %v from shard %v/%v", cell, keyspace, shard) - _, err = wr.ts.UpdateShardFields(ctx, keyspace, shard, func(si *topo.ShardInfo) error { - // since no lock is taken, protect against corner cases. - if len(si.Cells) == 0 { - return topo.NewError(topo.NoUpdateNeeded, si.Keyspace()+"/"+si.ShardName()) - } - var newCells []string - for _, c := range si.Cells { - if c != cell { - newCells = append(newCells, c) - } - } - si.Cells = newCells - return nil - }) - return err + wr.Logger().Infof("Removing cell %v from SrvKeyspace %v/%v", cell, keyspace, shard) + + return wr.ts.RemoveShardServingKeyspace(ctx, shardInfo, shardServingCells) } // SourceShardDelete will delete a SourceShard inside a shard, by index. diff --git a/go/vt/wrangler/tablet.go b/go/vt/wrangler/tablet.go index 36a57f48ee1..3f22a67081b 100644 --- a/go/vt/wrangler/tablet.go +++ b/go/vt/wrangler/tablet.go @@ -71,7 +71,7 @@ func (wr *Wrangler) InitTablet(ctx context.Context, tablet *topodatapb.Tablet, a } // update the shard record if needed - if err := wr.updateShardCellsAndMaster(ctx, si, tablet.Alias, tablet.Type, allowMasterOverride); err != nil { + if err := wr.updateShardMaster(ctx, si, tablet.Alias, tablet.Type, allowMasterOverride); err != nil { return err } diff --git a/proto/topodata.proto b/proto/topodata.proto index 4fe5584f57f..06c7b3d2683 100644 --- a/proto/topodata.proto +++ b/proto/topodata.proto @@ -173,16 +173,6 @@ message Shard { // Once set at creation time, it is never changed. KeyRange key_range = 2; - // ServedType is an entry in the served_types - message ServedType { - TabletType tablet_type = 1; - repeated string cells = 2; - } - - // served_types has at most one entry per TabletType - // The keyspace lock is always taken when changing this. - repeated ServedType served_types = 3; - // SourceShard represents a data source for filtered replication // accross shards. When this is used in a destination shard, the master // of that shard will run filtered replication. @@ -208,18 +198,15 @@ message Shard { // The keyspace lock is always taken when changing this. repeated SourceShard source_shards = 4; - // Cells is the list of cells that contain tablets for this shard. - // No lock is necessary to update this field. - repeated string cells = 5; - // TabletControl controls tablet's behavior message TabletControl { // which tablet type is affected TabletType tablet_type = 1; repeated string cells = 2; - // what to do - bool disable_query_service = 3; + // OBSOLETE: disable_query_service 3 + reserved 3; + repeated string blacklisted_tables = 4; // frozen is set if we've started failing over traffic for @@ -230,6 +217,13 @@ message Shard { // tablet_controls has at most one entry per TabletType. // The keyspace lock is always taken when changing this. repeated TabletControl tablet_controls = 6; + + // is_master_serving sets whether this shard master is serving traffic or not. + // The keyspace lock is always taken when changing this. + bool is_master_serving = 7; + + // OBSOLETE fields: served_types (3), cells (5) + reserved 3, 5; } // A Keyspace contains data about a keyspace. @@ -282,6 +276,16 @@ message ShardReference { // Copied from Shard. string name = 1; KeyRange key_range = 2; + // Disable query serving in this shard +} + +// ShardTabletControl is used as a pointer from a SrvKeyspace to a Shard +message ShardTabletControl { + // Copied from Shard. + string name = 1; + KeyRange key_range = 2; + // Disable query serving in this shard + bool query_service_disabled = 3; } // SrvKeyspace is a rollup node for the keyspace itself. @@ -292,6 +296,9 @@ message SrvKeyspace { // List of non-overlapping continuous shards sorted by range. repeated ShardReference shard_references = 2; + + // List of shard tablet controls + repeated ShardTabletControl shard_tablet_controls = 3; } // The partitions this keyspace is serving, per tablet type. diff --git a/py/vtproto/topodata_pb2.py b/py/vtproto/topodata_pb2.py index b048124834d..8616429f0fe 100644 --- a/py/vtproto/topodata_pb2.py +++ b/py/vtproto/topodata_pb2.py @@ -20,7 +20,7 @@ package='topodata', syntax='proto3', serialized_options=_b('\n\017io.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodata'), - serialized_pb=_b('\n\x0etopodata.proto\x12\x08topodata\"&\n\x08KeyRange\x12\r\n\x05start\x18\x01 \x01(\x0c\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x0c\"(\n\x0bTabletAlias\x12\x0c\n\x04\x63\x65ll\x18\x01 \x01(\t\x12\x0b\n\x03uid\x18\x02 \x01(\r\"\xb6\x03\n\x06Tablet\x12$\n\x05\x61lias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x10\n\x08hostname\x18\x02 \x01(\t\x12/\n\x08port_map\x18\x04 \x03(\x0b\x32\x1d.topodata.Tablet.PortMapEntry\x12\x10\n\x08keyspace\x18\x05 \x01(\t\x12\r\n\x05shard\x18\x06 \x01(\t\x12%\n\tkey_range\x18\x07 \x01(\x0b\x32\x12.topodata.KeyRange\x12\"\n\x04type\x18\x08 \x01(\x0e\x32\x14.topodata.TabletType\x12\x18\n\x10\x64\x62_name_override\x18\t \x01(\t\x12(\n\x04tags\x18\n \x03(\x0b\x32\x1a.topodata.Tablet.TagsEntry\x12\x16\n\x0emysql_hostname\x18\x0c \x01(\t\x12\x12\n\nmysql_port\x18\r \x01(\x05\x1a.\n\x0cPortMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01J\x04\x08\x03\x10\x04J\x04\x08\x0b\x10\x0c\"\xdb\x04\n\x05Shard\x12+\n\x0cmaster_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x30\n\x0cserved_types\x18\x03 \x03(\x0b\x32\x1a.topodata.Shard.ServedType\x12\x32\n\rsource_shards\x18\x04 \x03(\x0b\x32\x1b.topodata.Shard.SourceShard\x12\r\n\x05\x63\x65lls\x18\x05 \x03(\t\x12\x36\n\x0ftablet_controls\x18\x06 \x03(\x0b\x32\x1d.topodata.Shard.TabletControl\x1a\x46\n\nServedType\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x1ar\n\x0bSourceShard\x12\x0b\n\x03uid\x18\x01 \x01(\r\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\r\n\x05shard\x18\x03 \x01(\t\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\t\x1a\x94\x01\n\rTabletControl\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x1d\n\x15\x64isable_query_service\x18\x03 \x01(\x08\x12\x1a\n\x12\x62lacklisted_tables\x18\x04 \x03(\t\x12\x0e\n\x06\x66rozen\x18\x05 \x01(\x08\"\xf5\x01\n\x08Keyspace\x12\x1c\n\x14sharding_column_name\x18\x01 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x02 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x33\n\x0cserved_froms\x18\x04 \x03(\x0b\x32\x1d.topodata.Keyspace.ServedFrom\x1aX\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x10\n\x08keyspace\x18\x03 \x01(\tJ\x04\x08\x03\x10\x04\"w\n\x10ShardReplication\x12.\n\x05nodes\x18\x01 \x03(\x0b\x32\x1f.topodata.ShardReplication.Node\x1a\x33\n\x04Node\x12+\n\x0ctablet_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"E\n\x0eShardReference\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\"\x9c\x03\n\x0bSrvKeyspace\x12;\n\npartitions\x18\x01 \x03(\x0b\x32\'.topodata.SrvKeyspace.KeyspacePartition\x12\x1c\n\x14sharding_column_name\x18\x02 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x03 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x35\n\x0bserved_from\x18\x04 \x03(\x0b\x32 .topodata.SrvKeyspace.ServedFrom\x1ar\n\x11KeyspacePartition\x12)\n\x0bserved_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x32\n\x10shard_references\x18\x02 \x03(\x0b\x32\x18.topodata.ShardReference\x1aI\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x10\n\x08keyspace\x18\x02 \x01(\tJ\x04\x08\x05\x10\x06\"@\n\x08\x43\x65llInfo\x12\x16\n\x0eserver_address\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\t\x12\x0e\n\x06region\x18\x03 \x01(\t*2\n\x0eKeyspaceIdType\x12\t\n\x05UNSET\x10\x00\x12\n\n\x06UINT64\x10\x01\x12\t\n\x05\x42YTES\x10\x02*\x90\x01\n\nTabletType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06MASTER\x10\x01\x12\x0b\n\x07REPLICA\x10\x02\x12\n\n\x06RDONLY\x10\x03\x12\t\n\x05\x42\x41TCH\x10\x03\x12\t\n\x05SPARE\x10\x04\x12\x10\n\x0c\x45XPERIMENTAL\x10\x05\x12\n\n\x06\x42\x41\x43KUP\x10\x06\x12\x0b\n\x07RESTORE\x10\x07\x12\x0b\n\x07\x44RAINED\x10\x08\x1a\x02\x10\x01\x42\x38\n\x0fio.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodatab\x06proto3') + serialized_pb=_b('\n\x0etopodata.proto\x12\x08topodata\"&\n\x08KeyRange\x12\r\n\x05start\x18\x01 \x01(\x0c\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x0c\"(\n\x0bTabletAlias\x12\x0c\n\x04\x63\x65ll\x18\x01 \x01(\t\x12\x0b\n\x03uid\x18\x02 \x01(\r\"\xb6\x03\n\x06Tablet\x12$\n\x05\x61lias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x10\n\x08hostname\x18\x02 \x01(\t\x12/\n\x08port_map\x18\x04 \x03(\x0b\x32\x1d.topodata.Tablet.PortMapEntry\x12\x10\n\x08keyspace\x18\x05 \x01(\t\x12\r\n\x05shard\x18\x06 \x01(\t\x12%\n\tkey_range\x18\x07 \x01(\x0b\x32\x12.topodata.KeyRange\x12\"\n\x04type\x18\x08 \x01(\x0e\x32\x14.topodata.TabletType\x12\x18\n\x10\x64\x62_name_override\x18\t \x01(\t\x12(\n\x04tags\x18\n \x03(\x0b\x32\x1a.topodata.Tablet.TagsEntry\x12\x16\n\x0emysql_hostname\x18\x0c \x01(\t\x12\x12\n\nmysql_port\x18\r \x01(\x05\x1a.\n\x0cPortMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01J\x04\x08\x03\x10\x04J\x04\x08\x0b\x10\x0c\"\xdf\x03\n\x05Shard\x12+\n\x0cmaster_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x32\n\rsource_shards\x18\x04 \x03(\x0b\x32\x1b.topodata.Shard.SourceShard\x12\x36\n\x0ftablet_controls\x18\x06 \x03(\x0b\x32\x1d.topodata.Shard.TabletControl\x12\x19\n\x11is_master_serving\x18\x07 \x01(\x08\x1ar\n\x0bSourceShard\x12\x0b\n\x03uid\x18\x01 \x01(\r\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\r\n\x05shard\x18\x03 \x01(\t\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\t\x1a{\n\rTabletControl\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x1a\n\x12\x62lacklisted_tables\x18\x04 \x03(\t\x12\x0e\n\x06\x66rozen\x18\x05 \x01(\x08J\x04\x08\x03\x10\x04J\x04\x08\x03\x10\x04J\x04\x08\x05\x10\x06\"\xf5\x01\n\x08Keyspace\x12\x1c\n\x14sharding_column_name\x18\x01 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x02 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x33\n\x0cserved_froms\x18\x04 \x03(\x0b\x32\x1d.topodata.Keyspace.ServedFrom\x1aX\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x10\n\x08keyspace\x18\x03 \x01(\tJ\x04\x08\x03\x10\x04\"w\n\x10ShardReplication\x12.\n\x05nodes\x18\x01 \x03(\x0b\x32\x1f.topodata.ShardReplication.Node\x1a\x33\n\x04Node\x12+\n\x0ctablet_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"E\n\x0eShardReference\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\"i\n\x12ShardTabletControl\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x1e\n\x16query_service_disabled\x18\x03 \x01(\x08\"\xda\x03\n\x0bSrvKeyspace\x12;\n\npartitions\x18\x01 \x03(\x0b\x32\'.topodata.SrvKeyspace.KeyspacePartition\x12\x1c\n\x14sharding_column_name\x18\x02 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x03 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x35\n\x0bserved_from\x18\x04 \x03(\x0b\x32 .topodata.SrvKeyspace.ServedFrom\x1a\xaf\x01\n\x11KeyspacePartition\x12)\n\x0bserved_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x32\n\x10shard_references\x18\x02 \x03(\x0b\x32\x18.topodata.ShardReference\x12;\n\x15shard_tablet_controls\x18\x03 \x03(\x0b\x32\x1c.topodata.ShardTabletControl\x1aI\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x10\n\x08keyspace\x18\x02 \x01(\tJ\x04\x08\x05\x10\x06\"@\n\x08\x43\x65llInfo\x12\x16\n\x0eserver_address\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\t\x12\x0e\n\x06region\x18\x03 \x01(\t*2\n\x0eKeyspaceIdType\x12\t\n\x05UNSET\x10\x00\x12\n\n\x06UINT64\x10\x01\x12\t\n\x05\x42YTES\x10\x02*\x90\x01\n\nTabletType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06MASTER\x10\x01\x12\x0b\n\x07REPLICA\x10\x02\x12\n\n\x06RDONLY\x10\x03\x12\t\n\x05\x42\x41TCH\x10\x03\x12\t\n\x05SPARE\x10\x04\x12\x10\n\x0c\x45XPERIMENTAL\x10\x05\x12\n\n\x06\x42\x41\x43KUP\x10\x06\x12\x0b\n\x07RESTORE\x10\x07\x12\x0b\n\x07\x44RAINED\x10\x08\x1a\x02\x10\x01\x42\x38\n\x0fio.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodatab\x06proto3') ) _KEYSPACEIDTYPE = _descriptor.EnumDescriptor( @@ -44,8 +44,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=2078, - serialized_end=2128, + serialized_start=2123, + serialized_end=2173, ) _sym_db.RegisterEnumDescriptor(_KEYSPACEIDTYPE) @@ -99,8 +99,8 @@ ], containing_type=None, serialized_options=_b('\020\001'), - serialized_start=2131, - serialized_end=2275, + serialized_start=2176, + serialized_end=2320, ) _sym_db.RegisterEnumDescriptor(_TABLETTYPE) @@ -372,43 +372,6 @@ ) -_SHARD_SERVEDTYPE = _descriptor.Descriptor( - name='ServedType', - full_name='topodata.Shard.ServedType', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='tablet_type', full_name='topodata.Shard.ServedType.tablet_type', index=0, - number=1, type=14, cpp_type=8, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='cells', full_name='topodata.Shard.ServedType.cells', index=1, - number=2, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - serialized_options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=818, - serialized_end=888, -) - _SHARD_SOURCESHARD = _descriptor.Descriptor( name='SourceShard', full_name='topodata.Shard.SourceShard', @@ -463,8 +426,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=890, - serialized_end=1004, + serialized_start=780, + serialized_end=894, ) _SHARD_TABLETCONTROL = _descriptor.Descriptor( @@ -489,21 +452,14 @@ is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='disable_query_service', full_name='topodata.Shard.TabletControl.disable_query_service', index=2, - number=3, type=8, cpp_type=7, label=1, - has_default_value=False, default_value=False, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='blacklisted_tables', full_name='topodata.Shard.TabletControl.blacklisted_tables', index=3, + name='blacklisted_tables', full_name='topodata.Shard.TabletControl.blacklisted_tables', index=2, number=4, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='frozen', full_name='topodata.Shard.TabletControl.frozen', index=4, + name='frozen', full_name='topodata.Shard.TabletControl.frozen', index=3, number=5, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, @@ -521,8 +477,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1007, - serialized_end=1155, + serialized_start=896, + serialized_end=1019, ) _SHARD = _descriptor.Descriptor( @@ -547,37 +503,30 @@ is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='served_types', full_name='topodata.Shard.served_types', index=2, - number=3, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR), - _descriptor.FieldDescriptor( - name='source_shards', full_name='topodata.Shard.source_shards', index=3, + name='source_shards', full_name='topodata.Shard.source_shards', index=2, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='cells', full_name='topodata.Shard.cells', index=4, - number=5, type=9, cpp_type=9, label=3, + name='tablet_controls', full_name='topodata.Shard.tablet_controls', index=3, + number=6, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='tablet_controls', full_name='topodata.Shard.tablet_controls', index=5, - number=6, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], + name='is_master_serving', full_name='topodata.Shard.is_master_serving', index=4, + number=7, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], - nested_types=[_SHARD_SERVEDTYPE, _SHARD_SOURCESHARD, _SHARD_TABLETCONTROL, ], + nested_types=[_SHARD_SOURCESHARD, _SHARD_TABLETCONTROL, ], enum_types=[ ], serialized_options=None, @@ -587,7 +536,7 @@ oneofs=[ ], serialized_start=552, - serialized_end=1155, + serialized_end=1031, ) @@ -631,8 +580,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1309, - serialized_end=1397, + serialized_start=1185, + serialized_end=1273, ) _KEYSPACE = _descriptor.Descriptor( @@ -675,8 +624,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1158, - serialized_end=1403, + serialized_start=1034, + serialized_end=1279, ) @@ -706,8 +655,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1473, - serialized_end=1524, + serialized_start=1349, + serialized_end=1400, ) _SHARDREPLICATION = _descriptor.Descriptor( @@ -736,8 +685,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1405, - serialized_end=1524, + serialized_start=1281, + serialized_end=1400, ) @@ -774,8 +723,53 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1526, - serialized_end=1595, + serialized_start=1402, + serialized_end=1471, +) + + +_SHARDTABLETCONTROL = _descriptor.Descriptor( + name='ShardTabletControl', + full_name='topodata.ShardTabletControl', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='name', full_name='topodata.ShardTabletControl.name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=_b("").decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='key_range', full_name='topodata.ShardTabletControl.key_range', index=1, + number=2, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='query_service_disabled', full_name='topodata.ShardTabletControl.query_service_disabled', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1473, + serialized_end=1578, ) @@ -800,6 +794,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='shard_tablet_controls', full_name='topodata.SrvKeyspace.KeyspacePartition.shard_tablet_controls', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -812,8 +813,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1815, - serialized_end=1929, + serialized_start=1799, + serialized_end=1974, ) _SRVKEYSPACE_SERVEDFROM = _descriptor.Descriptor( @@ -849,8 +850,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1931, - serialized_end=2004, + serialized_start=1976, + serialized_end=2049, ) _SRVKEYSPACE = _descriptor.Descriptor( @@ -900,8 +901,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1598, - serialized_end=2010, + serialized_start=1581, + serialized_end=2055, ) @@ -945,8 +946,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2012, - serialized_end=2076, + serialized_start=2057, + serialized_end=2121, ) _TABLET_PORTMAPENTRY.containing_type = _TABLET @@ -956,15 +957,12 @@ _TABLET.fields_by_name['key_range'].message_type = _KEYRANGE _TABLET.fields_by_name['type'].enum_type = _TABLETTYPE _TABLET.fields_by_name['tags'].message_type = _TABLET_TAGSENTRY -_SHARD_SERVEDTYPE.fields_by_name['tablet_type'].enum_type = _TABLETTYPE -_SHARD_SERVEDTYPE.containing_type = _SHARD _SHARD_SOURCESHARD.fields_by_name['key_range'].message_type = _KEYRANGE _SHARD_SOURCESHARD.containing_type = _SHARD _SHARD_TABLETCONTROL.fields_by_name['tablet_type'].enum_type = _TABLETTYPE _SHARD_TABLETCONTROL.containing_type = _SHARD _SHARD.fields_by_name['master_alias'].message_type = _TABLETALIAS _SHARD.fields_by_name['key_range'].message_type = _KEYRANGE -_SHARD.fields_by_name['served_types'].message_type = _SHARD_SERVEDTYPE _SHARD.fields_by_name['source_shards'].message_type = _SHARD_SOURCESHARD _SHARD.fields_by_name['tablet_controls'].message_type = _SHARD_TABLETCONTROL _KEYSPACE_SERVEDFROM.fields_by_name['tablet_type'].enum_type = _TABLETTYPE @@ -975,8 +973,10 @@ _SHARDREPLICATION_NODE.containing_type = _SHARDREPLICATION _SHARDREPLICATION.fields_by_name['nodes'].message_type = _SHARDREPLICATION_NODE _SHARDREFERENCE.fields_by_name['key_range'].message_type = _KEYRANGE +_SHARDTABLETCONTROL.fields_by_name['key_range'].message_type = _KEYRANGE _SRVKEYSPACE_KEYSPACEPARTITION.fields_by_name['served_type'].enum_type = _TABLETTYPE _SRVKEYSPACE_KEYSPACEPARTITION.fields_by_name['shard_references'].message_type = _SHARDREFERENCE +_SRVKEYSPACE_KEYSPACEPARTITION.fields_by_name['shard_tablet_controls'].message_type = _SHARDTABLETCONTROL _SRVKEYSPACE_KEYSPACEPARTITION.containing_type = _SRVKEYSPACE _SRVKEYSPACE_SERVEDFROM.fields_by_name['tablet_type'].enum_type = _TABLETTYPE _SRVKEYSPACE_SERVEDFROM.containing_type = _SRVKEYSPACE @@ -990,6 +990,7 @@ DESCRIPTOR.message_types_by_name['Keyspace'] = _KEYSPACE DESCRIPTOR.message_types_by_name['ShardReplication'] = _SHARDREPLICATION DESCRIPTOR.message_types_by_name['ShardReference'] = _SHARDREFERENCE +DESCRIPTOR.message_types_by_name['ShardTabletControl'] = _SHARDTABLETCONTROL DESCRIPTOR.message_types_by_name['SrvKeyspace'] = _SRVKEYSPACE DESCRIPTOR.message_types_by_name['CellInfo'] = _CELLINFO DESCRIPTOR.enum_types_by_name['KeyspaceIdType'] = _KEYSPACEIDTYPE @@ -1035,13 +1036,6 @@ Shard = _reflection.GeneratedProtocolMessageType('Shard', (_message.Message,), dict( - ServedType = _reflection.GeneratedProtocolMessageType('ServedType', (_message.Message,), dict( - DESCRIPTOR = _SHARD_SERVEDTYPE, - __module__ = 'topodata_pb2' - # @@protoc_insertion_point(class_scope:topodata.Shard.ServedType) - )) - , - SourceShard = _reflection.GeneratedProtocolMessageType('SourceShard', (_message.Message,), dict( DESCRIPTOR = _SHARD_SOURCESHARD, __module__ = 'topodata_pb2' @@ -1060,7 +1054,6 @@ # @@protoc_insertion_point(class_scope:topodata.Shard) )) _sym_db.RegisterMessage(Shard) -_sym_db.RegisterMessage(Shard.ServedType) _sym_db.RegisterMessage(Shard.SourceShard) _sym_db.RegisterMessage(Shard.TabletControl) @@ -1101,6 +1094,13 @@ )) _sym_db.RegisterMessage(ShardReference) +ShardTabletControl = _reflection.GeneratedProtocolMessageType('ShardTabletControl', (_message.Message,), dict( + DESCRIPTOR = _SHARDTABLETCONTROL, + __module__ = 'topodata_pb2' + # @@protoc_insertion_point(class_scope:topodata.ShardTabletControl) + )) +_sym_db.RegisterMessage(ShardTabletControl) + SrvKeyspace = _reflection.GeneratedProtocolMessageType('SrvKeyspace', (_message.Message,), dict( KeyspacePartition = _reflection.GeneratedProtocolMessageType('KeyspacePartition', (_message.Message,), dict( diff --git a/py/vtproto/vtgate_pb2.py b/py/vtproto/vtgate_pb2.py index aeba2d1fb31..ecf7e927956 100644 --- a/py/vtproto/vtgate_pb2.py +++ b/py/vtproto/vtgate_pb2.py @@ -8,7 +8,6 @@ from google.protobuf import message as _message from google.protobuf import reflection as _reflection from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -23,6 +22,7 @@ name='vtgate.proto', package='vtgate', syntax='proto3', + serialized_options=_b('\n\017io.vitess.protoZ#vitess.io/vitess/go/vt/proto/vtgate'), serialized_pb=_b('\n\x0cvtgate.proto\x12\x06vtgate\x1a\x0bquery.proto\x1a\x0etopodata.proto\x1a\x0bvtrpc.proto\"\xde\x02\n\x07Session\x12\x16\n\x0ein_transaction\x18\x01 \x01(\x08\x12\x34\n\x0eshard_sessions\x18\x02 \x03(\x0b\x32\x1c.vtgate.Session.ShardSession\x12\x11\n\tsingle_db\x18\x03 \x01(\x08\x12\x12\n\nautocommit\x18\x04 \x01(\x08\x12\x15\n\rtarget_string\x18\x05 \x01(\t\x12&\n\x07options\x18\x06 \x01(\x0b\x32\x15.query.ExecuteOptions\x12\x31\n\x10transaction_mode\x18\x07 \x01(\x0e\x32\x17.vtgate.TransactionMode\x12%\n\x08warnings\x18\x08 \x03(\x0b\x32\x13.query.QueryWarning\x1a\x45\n\x0cShardSession\x12\x1d\n\x06target\x18\x01 \x01(\x0b\x32\r.query.Target\x12\x16\n\x0etransaction_id\x18\x02 \x01(\x03\"\xff\x01\n\x0e\x45xecuteRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12 \n\x05query\x18\x03 \x01(\x0b\x32\x11.query.BoundQuery\x12)\n\x0btablet_type\x18\x04 \x01(\x0e\x32\x14.topodata.TabletType\x12\x1a\n\x12not_in_transaction\x18\x05 \x01(\x08\x12\x16\n\x0ekeyspace_shard\x18\x06 \x01(\t\x12&\n\x07options\x18\x07 \x01(\x0b\x32\x15.query.ExecuteOptions\"w\n\x0f\x45xecuteResponse\x12\x1e\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x0f.vtrpc.RPCError\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12\"\n\x06result\x18\x03 \x01(\x0b\x32\x12.query.QueryResult\"\x8f\x02\n\x14\x45xecuteShardsRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12 \n\x05query\x18\x03 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x04 \x01(\t\x12\x0e\n\x06shards\x18\x05 \x03(\t\x12)\n\x0btablet_type\x18\x06 \x01(\x0e\x32\x14.topodata.TabletType\x12\x1a\n\x12not_in_transaction\x18\x07 \x01(\x08\x12&\n\x07options\x18\x08 \x01(\x0b\x32\x15.query.ExecuteOptions\"}\n\x15\x45xecuteShardsResponse\x12\x1e\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x0f.vtrpc.RPCError\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12\"\n\x06result\x18\x03 \x01(\x0b\x32\x12.query.QueryResult\"\x9a\x02\n\x19\x45xecuteKeyspaceIdsRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12 \n\x05query\x18\x03 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x04 \x01(\t\x12\x14\n\x0ckeyspace_ids\x18\x05 \x03(\x0c\x12)\n\x0btablet_type\x18\x06 \x01(\x0e\x32\x14.topodata.TabletType\x12\x1a\n\x12not_in_transaction\x18\x07 \x01(\x08\x12&\n\x07options\x18\x08 \x01(\x0b\x32\x15.query.ExecuteOptions\"\x82\x01\n\x1a\x45xecuteKeyspaceIdsResponse\x12\x1e\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x0f.vtrpc.RPCError\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12\"\n\x06result\x18\x03 \x01(\x0b\x32\x12.query.QueryResult\"\xaa\x02\n\x17\x45xecuteKeyRangesRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12 \n\x05query\x18\x03 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x04 \x01(\t\x12&\n\nkey_ranges\x18\x05 \x03(\x0b\x32\x12.topodata.KeyRange\x12)\n\x0btablet_type\x18\x06 \x01(\x0e\x32\x14.topodata.TabletType\x12\x1a\n\x12not_in_transaction\x18\x07 \x01(\x08\x12&\n\x07options\x18\x08 \x01(\x0b\x32\x15.query.ExecuteOptions\"\x80\x01\n\x18\x45xecuteKeyRangesResponse\x12\x1e\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x0f.vtrpc.RPCError\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12\"\n\x06result\x18\x03 \x01(\x0b\x32\x12.query.QueryResult\"\xb0\x03\n\x17\x45xecuteEntityIdsRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12 \n\x05query\x18\x03 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x04 \x01(\t\x12\x1a\n\x12\x65ntity_column_name\x18\x05 \x01(\t\x12\x45\n\x13\x65ntity_keyspace_ids\x18\x06 \x03(\x0b\x32(.vtgate.ExecuteEntityIdsRequest.EntityId\x12)\n\x0btablet_type\x18\x07 \x01(\x0e\x32\x14.topodata.TabletType\x12\x1a\n\x12not_in_transaction\x18\x08 \x01(\x08\x12&\n\x07options\x18\t \x01(\x0b\x32\x15.query.ExecuteOptions\x1aI\n\x08\x45ntityId\x12\x19\n\x04type\x18\x01 \x01(\x0e\x32\x0b.query.Type\x12\r\n\x05value\x18\x02 \x01(\x0c\x12\x13\n\x0bkeyspace_id\x18\x03 \x01(\x0c\"\x80\x01\n\x18\x45xecuteEntityIdsResponse\x12\x1e\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x0f.vtrpc.RPCError\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12\"\n\x06result\x18\x03 \x01(\x0b\x32\x12.query.QueryResult\"\x82\x02\n\x13\x45xecuteBatchRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12\"\n\x07queries\x18\x03 \x03(\x0b\x32\x11.query.BoundQuery\x12)\n\x0btablet_type\x18\x04 \x01(\x0e\x32\x14.topodata.TabletType\x12\x16\n\x0e\x61s_transaction\x18\x05 \x01(\x08\x12\x16\n\x0ekeyspace_shard\x18\x06 \x01(\t\x12&\n\x07options\x18\x07 \x01(\x0b\x32\x15.query.ExecuteOptions\"\x81\x01\n\x14\x45xecuteBatchResponse\x12\x1e\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x0f.vtrpc.RPCError\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12\'\n\x07results\x18\x03 \x03(\x0b\x32\x16.query.ResultWithError\"U\n\x0f\x42oundShardQuery\x12 \n\x05query\x18\x01 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\x0e\n\x06shards\x18\x03 \x03(\t\"\xf6\x01\n\x19\x45xecuteBatchShardsRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12(\n\x07queries\x18\x03 \x03(\x0b\x32\x17.vtgate.BoundShardQuery\x12)\n\x0btablet_type\x18\x04 \x01(\x0e\x32\x14.topodata.TabletType\x12\x16\n\x0e\x61s_transaction\x18\x05 \x01(\x08\x12&\n\x07options\x18\x06 \x01(\x0b\x32\x15.query.ExecuteOptions\"\x83\x01\n\x1a\x45xecuteBatchShardsResponse\x12\x1e\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x0f.vtrpc.RPCError\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12#\n\x07results\x18\x03 \x03(\x0b\x32\x12.query.QueryResult\"`\n\x14\x42oundKeyspaceIdQuery\x12 \n\x05query\x18\x01 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\x14\n\x0ckeyspace_ids\x18\x03 \x03(\x0c\"\x80\x02\n\x1e\x45xecuteBatchKeyspaceIdsRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12-\n\x07queries\x18\x03 \x03(\x0b\x32\x1c.vtgate.BoundKeyspaceIdQuery\x12)\n\x0btablet_type\x18\x04 \x01(\x0e\x32\x14.topodata.TabletType\x12\x16\n\x0e\x61s_transaction\x18\x05 \x01(\x08\x12&\n\x07options\x18\x06 \x01(\x0b\x32\x15.query.ExecuteOptions\"\x88\x01\n\x1f\x45xecuteBatchKeyspaceIdsResponse\x12\x1e\n\x05\x65rror\x18\x01 \x01(\x0b\x32\x0f.vtrpc.RPCError\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12#\n\x07results\x18\x03 \x03(\x0b\x32\x12.query.QueryResult\"\xe9\x01\n\x14StreamExecuteRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x05query\x18\x02 \x01(\x0b\x32\x11.query.BoundQuery\x12)\n\x0btablet_type\x18\x03 \x01(\x0e\x32\x14.topodata.TabletType\x12\x16\n\x0ekeyspace_shard\x18\x04 \x01(\t\x12&\n\x07options\x18\x05 \x01(\x0b\x32\x15.query.ExecuteOptions\x12 \n\x07session\x18\x06 \x01(\x0b\x32\x0f.vtgate.Session\";\n\x15StreamExecuteResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\xd7\x01\n\x1aStreamExecuteShardsRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x05query\x18\x02 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x03 \x01(\t\x12\x0e\n\x06shards\x18\x04 \x03(\t\x12)\n\x0btablet_type\x18\x05 \x01(\x0e\x32\x14.topodata.TabletType\x12&\n\x07options\x18\x06 \x01(\x0b\x32\x15.query.ExecuteOptions\"A\n\x1bStreamExecuteShardsResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\xe2\x01\n\x1fStreamExecuteKeyspaceIdsRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x05query\x18\x02 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x03 \x01(\t\x12\x14\n\x0ckeyspace_ids\x18\x04 \x03(\x0c\x12)\n\x0btablet_type\x18\x05 \x01(\x0e\x32\x14.topodata.TabletType\x12&\n\x07options\x18\x06 \x01(\x0b\x32\x15.query.ExecuteOptions\"F\n StreamExecuteKeyspaceIdsResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\xf2\x01\n\x1dStreamExecuteKeyRangesRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x05query\x18\x02 \x01(\x0b\x32\x11.query.BoundQuery\x12\x10\n\x08keyspace\x18\x03 \x01(\t\x12&\n\nkey_ranges\x18\x04 \x03(\x0b\x32\x12.topodata.KeyRange\x12)\n\x0btablet_type\x18\x05 \x01(\x0e\x32\x14.topodata.TabletType\x12&\n\x07options\x18\x06 \x01(\x0b\x32\x15.query.ExecuteOptions\"D\n\x1eStreamExecuteKeyRangesResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"E\n\x0c\x42\x65ginRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x11\n\tsingle_db\x18\x02 \x01(\x08\"1\n\rBeginResponse\x12 \n\x07session\x18\x01 \x01(\x0b\x32\x0f.vtgate.Session\"e\n\rCommitRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\x12\x0e\n\x06\x61tomic\x18\x03 \x01(\x08\"\x10\n\x0e\x43ommitResponse\"W\n\x0fRollbackRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12 \n\x07session\x18\x02 \x01(\x0b\x32\x0f.vtgate.Session\"\x12\n\x10RollbackResponse\"M\n\x19ResolveTransactionRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x0c\n\x04\x64tid\x18\x02 \x01(\t\"\x90\x01\n\x14MessageStreamRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\r\n\x05shard\x18\x03 \x01(\t\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0c\n\x04name\x18\x05 \x01(\t\"r\n\x11MessageAckRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12\x19\n\x03ids\x18\x04 \x03(\x0b\x32\x0c.query.Value\"=\n\x0cIdKeyspaceId\x12\x18\n\x02id\x18\x01 \x01(\x0b\x32\x0c.query.Value\x12\x13\n\x0bkeyspace_id\x18\x02 \x01(\x0c\"\x91\x01\n\x1cMessageAckKeyspaceIdsRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\x0c\n\x04name\x18\x03 \x01(\t\x12-\n\x0fid_keyspace_ids\x18\x04 \x03(\x0b\x32\x14.vtgate.IdKeyspaceId\"\x1c\n\x1aResolveTransactionResponse\"\x8a\x02\n\x11SplitQueryRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12 \n\x05query\x18\x03 \x01(\x0b\x32\x11.query.BoundQuery\x12\x14\n\x0csplit_column\x18\x04 \x03(\t\x12\x13\n\x0bsplit_count\x18\x05 \x01(\x03\x12\x1f\n\x17num_rows_per_query_part\x18\x06 \x01(\x03\x12\x35\n\talgorithm\x18\x07 \x01(\x0e\x32\".query.SplitQueryRequest.Algorithm\x12\x1a\n\x12use_split_query_v2\x18\x08 \x01(\x08\"\xf2\x02\n\x12SplitQueryResponse\x12/\n\x06splits\x18\x01 \x03(\x0b\x32\x1f.vtgate.SplitQueryResponse.Part\x1aH\n\x0cKeyRangePart\x12\x10\n\x08keyspace\x18\x01 \x01(\t\x12&\n\nkey_ranges\x18\x02 \x03(\x0b\x32\x12.topodata.KeyRange\x1a-\n\tShardPart\x12\x10\n\x08keyspace\x18\x01 \x01(\t\x12\x0e\n\x06shards\x18\x02 \x03(\t\x1a\xb1\x01\n\x04Part\x12 \n\x05query\x18\x01 \x01(\x0b\x32\x11.query.BoundQuery\x12?\n\x0ekey_range_part\x18\x02 \x01(\x0b\x32\'.vtgate.SplitQueryResponse.KeyRangePart\x12\x38\n\nshard_part\x18\x03 \x01(\x0b\x32$.vtgate.SplitQueryResponse.ShardPart\x12\x0c\n\x04size\x18\x04 \x01(\x03\")\n\x15GetSrvKeyspaceRequest\x12\x10\n\x08keyspace\x18\x01 \x01(\t\"E\n\x16GetSrvKeyspaceResponse\x12+\n\x0csrv_keyspace\x18\x01 \x01(\x0b\x32\x15.topodata.SrvKeyspace\"\xe1\x01\n\x13UpdateStreamRequest\x12\"\n\tcaller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\r\n\x05shard\x18\x03 \x01(\t\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12)\n\x0btablet_type\x18\x05 \x01(\x0e\x32\x14.topodata.TabletType\x12\x11\n\ttimestamp\x18\x06 \x01(\x03\x12 \n\x05\x65vent\x18\x07 \x01(\x0b\x32\x11.query.EventToken\"S\n\x14UpdateStreamResponse\x12!\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x12.query.StreamEvent\x12\x18\n\x10resume_timestamp\x18\x02 \x01(\x03*D\n\x0fTransactionMode\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\n\n\x06SINGLE\x10\x01\x12\t\n\x05MULTI\x10\x02\x12\t\n\x05TWOPC\x10\x03\x42\x36\n\x0fio.vitess.protoZ#vitess.io/vitess/go/vt/proto/vtgateb\x06proto3') , dependencies=[query__pb2.DESCRIPTOR,topodata__pb2.DESCRIPTOR,vtrpc__pb2.DESCRIPTOR,]) @@ -35,23 +35,23 @@ values=[ _descriptor.EnumValueDescriptor( name='UNSPECIFIED', index=0, number=0, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='SINGLE', index=1, number=1, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='MULTI', index=2, number=2, - options=None, + serialized_options=None, type=None), _descriptor.EnumValueDescriptor( name='TWOPC', index=3, number=3, - options=None, + serialized_options=None, type=None), ], containing_type=None, - options=None, + serialized_options=None, serialized_start=7176, serialized_end=7244, ) @@ -78,21 +78,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='transaction_id', full_name='vtgate.Session.ShardSession.transaction_id', index=1, number=2, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -115,63 +115,63 @@ has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='shard_sessions', full_name='vtgate.Session.shard_sessions', index=1, number=2, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='single_db', full_name='vtgate.Session.single_db', index=2, number=3, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='autocommit', full_name='vtgate.Session.autocommit', index=3, number=4, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='target_string', full_name='vtgate.Session.target_string', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.Session.options', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='transaction_mode', full_name='vtgate.Session.transaction_mode', index=6, number=7, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='warnings', full_name='vtgate.Session.warnings', index=7, number=8, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[_SESSION_SHARDSESSION, ], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -195,56 +195,56 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.ExecuteRequest.query', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.ExecuteRequest.tablet_type', index=3, number=4, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='not_in_transaction', full_name='vtgate.ExecuteRequest.not_in_transaction', index=4, number=5, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace_shard', full_name='vtgate.ExecuteRequest.keyspace_shard', index=5, number=6, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.ExecuteRequest.options', index=6, number=7, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -268,28 +268,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteResponse.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='result', full_name='vtgate.ExecuteResponse.result', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -313,63 +313,63 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteShardsRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.ExecuteShardsRequest.query', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.ExecuteShardsRequest.keyspace', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='shards', full_name='vtgate.ExecuteShardsRequest.shards', index=4, number=5, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.ExecuteShardsRequest.tablet_type', index=5, number=6, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='not_in_transaction', full_name='vtgate.ExecuteShardsRequest.not_in_transaction', index=6, number=7, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.ExecuteShardsRequest.options', index=7, number=8, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -393,28 +393,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteShardsResponse.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='result', full_name='vtgate.ExecuteShardsResponse.result', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -438,63 +438,63 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteKeyspaceIdsRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.ExecuteKeyspaceIdsRequest.query', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.ExecuteKeyspaceIdsRequest.keyspace', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace_ids', full_name='vtgate.ExecuteKeyspaceIdsRequest.keyspace_ids', index=4, number=5, type=12, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.ExecuteKeyspaceIdsRequest.tablet_type', index=5, number=6, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='not_in_transaction', full_name='vtgate.ExecuteKeyspaceIdsRequest.not_in_transaction', index=6, number=7, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.ExecuteKeyspaceIdsRequest.options', index=7, number=8, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -518,28 +518,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteKeyspaceIdsResponse.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='result', full_name='vtgate.ExecuteKeyspaceIdsResponse.result', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -563,63 +563,63 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteKeyRangesRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.ExecuteKeyRangesRequest.query', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.ExecuteKeyRangesRequest.keyspace', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='key_ranges', full_name='vtgate.ExecuteKeyRangesRequest.key_ranges', index=4, number=5, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.ExecuteKeyRangesRequest.tablet_type', index=5, number=6, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='not_in_transaction', full_name='vtgate.ExecuteKeyRangesRequest.not_in_transaction', index=6, number=7, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.ExecuteKeyRangesRequest.options', index=7, number=8, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -643,28 +643,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteKeyRangesResponse.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='result', full_name='vtgate.ExecuteKeyRangesResponse.result', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -688,28 +688,28 @@ has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='value', full_name='vtgate.ExecuteEntityIdsRequest.EntityId.value', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace_id', full_name='vtgate.ExecuteEntityIdsRequest.EntityId.keyspace_id', index=2, number=3, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -732,70 +732,70 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteEntityIdsRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.ExecuteEntityIdsRequest.query', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.ExecuteEntityIdsRequest.keyspace', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='entity_column_name', full_name='vtgate.ExecuteEntityIdsRequest.entity_column_name', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='entity_keyspace_ids', full_name='vtgate.ExecuteEntityIdsRequest.entity_keyspace_ids', index=5, number=6, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.ExecuteEntityIdsRequest.tablet_type', index=6, number=7, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='not_in_transaction', full_name='vtgate.ExecuteEntityIdsRequest.not_in_transaction', index=7, number=8, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.ExecuteEntityIdsRequest.options', index=8, number=9, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[_EXECUTEENTITYIDSREQUEST_ENTITYID, ], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -819,28 +819,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteEntityIdsResponse.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='result', full_name='vtgate.ExecuteEntityIdsResponse.result', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -864,56 +864,56 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteBatchRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='queries', full_name='vtgate.ExecuteBatchRequest.queries', index=2, number=3, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.ExecuteBatchRequest.tablet_type', index=3, number=4, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='as_transaction', full_name='vtgate.ExecuteBatchRequest.as_transaction', index=4, number=5, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace_shard', full_name='vtgate.ExecuteBatchRequest.keyspace_shard', index=5, number=6, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.ExecuteBatchRequest.options', index=6, number=7, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -937,28 +937,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteBatchResponse.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='results', full_name='vtgate.ExecuteBatchResponse.results', index=2, number=3, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -982,28 +982,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.BoundShardQuery.keyspace', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='shards', full_name='vtgate.BoundShardQuery.shards', index=2, number=3, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1027,49 +1027,49 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteBatchShardsRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='queries', full_name='vtgate.ExecuteBatchShardsRequest.queries', index=2, number=3, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.ExecuteBatchShardsRequest.tablet_type', index=3, number=4, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='as_transaction', full_name='vtgate.ExecuteBatchShardsRequest.as_transaction', index=4, number=5, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.ExecuteBatchShardsRequest.options', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1093,28 +1093,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteBatchShardsResponse.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='results', full_name='vtgate.ExecuteBatchShardsResponse.results', index=2, number=3, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1138,28 +1138,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.BoundKeyspaceIdQuery.keyspace', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace_ids', full_name='vtgate.BoundKeyspaceIdQuery.keyspace_ids', index=2, number=3, type=12, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1183,49 +1183,49 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteBatchKeyspaceIdsRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='queries', full_name='vtgate.ExecuteBatchKeyspaceIdsRequest.queries', index=2, number=3, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.ExecuteBatchKeyspaceIdsRequest.tablet_type', index=3, number=4, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='as_transaction', full_name='vtgate.ExecuteBatchKeyspaceIdsRequest.as_transaction', index=4, number=5, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.ExecuteBatchKeyspaceIdsRequest.options', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1249,28 +1249,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.ExecuteBatchKeyspaceIdsResponse.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='results', full_name='vtgate.ExecuteBatchKeyspaceIdsResponse.results', index=2, number=3, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1294,49 +1294,49 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.StreamExecuteRequest.query', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.StreamExecuteRequest.tablet_type', index=2, number=3, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace_shard', full_name='vtgate.StreamExecuteRequest.keyspace_shard', index=3, number=4, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.StreamExecuteRequest.options', index=4, number=5, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.StreamExecuteRequest.session', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1360,14 +1360,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1391,49 +1391,49 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.StreamExecuteShardsRequest.query', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.StreamExecuteShardsRequest.keyspace', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='shards', full_name='vtgate.StreamExecuteShardsRequest.shards', index=3, number=4, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.StreamExecuteShardsRequest.tablet_type', index=4, number=5, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.StreamExecuteShardsRequest.options', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1457,14 +1457,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1488,49 +1488,49 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.StreamExecuteKeyspaceIdsRequest.query', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.StreamExecuteKeyspaceIdsRequest.keyspace', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace_ids', full_name='vtgate.StreamExecuteKeyspaceIdsRequest.keyspace_ids', index=3, number=4, type=12, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.StreamExecuteKeyspaceIdsRequest.tablet_type', index=4, number=5, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.StreamExecuteKeyspaceIdsRequest.options', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1554,14 +1554,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1585,49 +1585,49 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.StreamExecuteKeyRangesRequest.query', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.StreamExecuteKeyRangesRequest.keyspace', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='key_ranges', full_name='vtgate.StreamExecuteKeyRangesRequest.key_ranges', index=3, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.StreamExecuteKeyRangesRequest.tablet_type', index=4, number=5, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='options', full_name='vtgate.StreamExecuteKeyRangesRequest.options', index=5, number=6, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1651,14 +1651,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1682,21 +1682,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='single_db', full_name='vtgate.BeginRequest.single_db', index=1, number=2, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1720,14 +1720,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1751,28 +1751,28 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.CommitRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='atomic', full_name='vtgate.CommitRequest.atomic', index=2, number=3, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1796,7 +1796,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1820,21 +1820,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='session', full_name='vtgate.RollbackRequest.session', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1858,7 +1858,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1882,21 +1882,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='dtid', full_name='vtgate.ResolveTransactionRequest.dtid', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1920,42 +1920,42 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.MessageStreamRequest.keyspace', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='shard', full_name='vtgate.MessageStreamRequest.shard', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='key_range', full_name='vtgate.MessageStreamRequest.key_range', index=3, number=4, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='name', full_name='vtgate.MessageStreamRequest.name', index=4, number=5, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -1979,35 +1979,35 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.MessageAckRequest.keyspace', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='name', full_name='vtgate.MessageAckRequest.name', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='ids', full_name='vtgate.MessageAckRequest.ids', index=3, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2031,21 +2031,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace_id', full_name='vtgate.IdKeyspaceId.keyspace_id', index=1, number=2, type=12, cpp_type=9, label=1, has_default_value=False, default_value=_b(""), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2069,35 +2069,35 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.MessageAckKeyspaceIdsRequest.keyspace', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='name', full_name='vtgate.MessageAckKeyspaceIdsRequest.name', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='id_keyspace_ids', full_name='vtgate.MessageAckKeyspaceIdsRequest.id_keyspace_ids', index=3, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2121,7 +2121,7 @@ nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2145,63 +2145,63 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.SplitQueryRequest.keyspace', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='query', full_name='vtgate.SplitQueryRequest.query', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='split_column', full_name='vtgate.SplitQueryRequest.split_column', index=3, number=4, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='split_count', full_name='vtgate.SplitQueryRequest.split_count', index=4, number=5, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='num_rows_per_query_part', full_name='vtgate.SplitQueryRequest.num_rows_per_query_part', index=5, number=6, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='algorithm', full_name='vtgate.SplitQueryRequest.algorithm', index=6, number=7, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='use_split_query_v2', full_name='vtgate.SplitQueryRequest.use_split_query_v2', index=7, number=8, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2225,21 +2225,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='key_ranges', full_name='vtgate.SplitQueryResponse.KeyRangePart.key_ranges', index=1, number=2, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2262,21 +2262,21 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='shards', full_name='vtgate.SplitQueryResponse.ShardPart.shards', index=1, number=2, type=9, cpp_type=9, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2299,35 +2299,35 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='key_range_part', full_name='vtgate.SplitQueryResponse.Part.key_range_part', index=1, number=2, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='shard_part', full_name='vtgate.SplitQueryResponse.Part.shard_part', index=2, number=3, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='size', full_name='vtgate.SplitQueryResponse.Part.size', index=3, number=4, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2350,14 +2350,14 @@ has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[_SPLITQUERYRESPONSE_KEYRANGEPART, _SPLITQUERYRESPONSE_SHARDPART, _SPLITQUERYRESPONSE_PART, ], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2381,14 +2381,14 @@ has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2412,14 +2412,14 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2443,56 +2443,56 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='keyspace', full_name='vtgate.UpdateStreamRequest.keyspace', index=1, number=2, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='shard', full_name='vtgate.UpdateStreamRequest.shard', index=2, number=3, type=9, cpp_type=9, label=1, has_default_value=False, default_value=_b("").decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='key_range', full_name='vtgate.UpdateStreamRequest.key_range', index=3, number=4, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='tablet_type', full_name='vtgate.UpdateStreamRequest.tablet_type', index=4, number=5, type=14, cpp_type=8, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='timestamp', full_name='vtgate.UpdateStreamRequest.timestamp', index=5, number=6, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='event', full_name='vtgate.UpdateStreamRequest.event', index=6, number=7, type=11, cpp_type=10, label=1, has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -2516,21 +2516,21 @@ has_default_value=False, default_value=None, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( name='resume_timestamp', full_name='vtgate.UpdateStreamResponse.resume_timestamp', index=1, number=2, type=3, cpp_type=2, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - options=None, file=DESCRIPTOR), + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], nested_types=[], enum_types=[ ], - options=None, + serialized_options=None, is_extendable=False, syntax='proto3', extension_ranges=[], @@ -3073,6 +3073,5 @@ _sym_db.RegisterMessage(UpdateStreamResponse) -DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('\n\017io.vitess.protoZ#vitess.io/vitess/go/vt/proto/vtgate')) +DESCRIPTOR._options = None # @@protoc_insertion_point(module_scope) From 8128ffe91795f8171abaf8cde2ef0345e243d086 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Tue, 5 Feb 2019 15:54:08 -0800 Subject: [PATCH 021/196] Update disable query service to be more efficient Instead of updating the serving keyspace one time per shard, just do it a single time with all the shards that we need to update. Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 51 ++++++++++++++++++-------------------- go/vt/wrangler/keyspace.go | 43 +++++++++++++++----------------- go/vt/wrangler/shard.go | 2 +- 3 files changed, 45 insertions(+), 51 deletions(-) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index c9068269059..8ee811baf34 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -288,16 +288,10 @@ func (ts *Server) RemoveShardServingKeyspace(ctx context.Context, si *ShardInfo, // - we don't support DisableQueryService at the same time as BlacklistedTables, // because it's not used in the same context (vertical vs horizontal sharding) // This function should be called while holding the keyspace lock. -func (ts *Server) UpdateDisableQueryService(ctx context.Context, si *ShardInfo, tabletType topodatapb.TabletType, cells []string, disableQueryService bool) (err error) { - if err = CheckKeyspaceLocked(ctx, si.keyspace); err != nil { +func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string, disableQueryService bool) (err error) { + if err = CheckKeyspaceLocked(ctx, keyspace); err != nil { return err } - tc := si.GetTabletControl(tabletType) - // we have an existing record, check table list is empty and - // DisableQueryService is set - if tc != nil && len(tc.BlacklistedTables) > 0 { - return fmt.Errorf("cannot safely alter DisableQueryService as BlacklistedTables is set") - } // The caller intents to update all cells in this case if len(cells) == 0 { @@ -313,39 +307,42 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, si *ShardInfo, wg.Add(1) go func(cell, keyspace string) { defer wg.Done() - srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) if err != nil { rec.RecordError(err) return } - for _, partition := range srvKeyspace.GetPartitions() { - if partition.GetServedType() != tabletType { - continue - } - found := false - for _, tabletControl := range partition.GetShardTabletControls() { - if tabletControl.GetName() == si.ShardName() { - found = true - tabletControl.QueryServiceDisabled = disableQueryService + for _, si := range shards { + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } + found := false + for _, tabletControl := range partition.GetShardTabletControls() { + if tabletControl.GetName() == si.ShardName() { + found = true + tabletControl.QueryServiceDisabled = disableQueryService + } } - } - if !found { - shardTabletControl := &topodatapb.ShardTabletControl{ - Name: si.ShardName(), - KeyRange: si.KeyRange, - QueryServiceDisabled: true, + if !found { + shardTabletControl := &topodatapb.ShardTabletControl{ + Name: si.ShardName(), + KeyRange: si.KeyRange, + QueryServiceDisabled: true, + } + partition.ShardTabletControls = append(partition.GetShardTabletControls(), shardTabletControl) } - partition.ShardTabletControls = append(partition.GetShardTabletControls(), shardTabletControl) } } - err = ts.UpdateSrvKeyspace(ctx, cell, si.keyspace, srvKeyspace) + + err = ts.UpdateSrvKeyspace(ctx, cell, keyspace, srvKeyspace) if err != nil { rec.RecordError(err) return } - }(cell, si.Keyspace()) + }(cell, keyspace) } wg.Wait() if rec.HasErrors() { diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index a0341bf357d..1a17a3252c0 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -283,11 +283,6 @@ func (wr *Wrangler) MigrateServedTypes(ctx context.Context, keyspace, shard stri } } - // rebuild the keyspace serving graph now that there is no error - if err = topotools.RebuildKeyspaceLocked(ctx, wr.logger, wr.ts, keyspace, cells); err != nil { - return err - } - // Master migrate performs its own refresh. // Otherwise, honor skipRefreshState if requested. if servedType == topodatapb.TabletType_MASTER || skipReFreshState { @@ -481,13 +476,13 @@ func (wr *Wrangler) replicaMigrateServedType(ctx context.Context, keyspace strin // Check and update all source shard records. // Enable query service if needed event.DispatchUpdate(ev, "updating shards to migrate from") - if err = wr.updateShardRecords(ctx, fromShards, cells, servedType, true, false); err != nil { + if err = wr.updateShardRecords(ctx, keyspace, fromShards, cells, servedType, true, false); err != nil { return err } // Do the same for destination shards event.DispatchUpdate(ev, "updating shards to migrate to") - if err = wr.updateShardRecords(ctx, toShards, cells, servedType, false, false); err != nil { + if err = wr.updateShardRecords(ctx, keyspace, toShards, cells, servedType, false, false); err != nil { return err } @@ -539,31 +534,31 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string // - wait for filtered replication to catch up // - mark source shards as frozen event.DispatchUpdate(ev, "disabling query service on all source masters") - if err := wr.updateShardRecords(ctx, sourceShards, nil, topodatapb.TabletType_MASTER, true, false); err != nil { - wr.cancelMasterMigrateServedTypes(ctx, sourceShards) + if err := wr.updateShardRecords(ctx, keyspace, sourceShards, nil, topodatapb.TabletType_MASTER, true, false); err != nil { + wr.cancelMasterMigrateServedTypes(ctx, keyspace, sourceShards) return err } if err := wr.refreshMasters(ctx, sourceShards); err != nil { - wr.cancelMasterMigrateServedTypes(ctx, sourceShards) + wr.cancelMasterMigrateServedTypes(ctx, keyspace, sourceShards) return err } event.DispatchUpdate(ev, "getting positions of source masters") masterPositions, err := wr.getMastersPosition(ctx, sourceShards) if err != nil { - wr.cancelMasterMigrateServedTypes(ctx, sourceShards) + wr.cancelMasterMigrateServedTypes(ctx, keyspace, sourceShards) return err } event.DispatchUpdate(ev, "waiting for destination masters to catch up") if err := wr.waitForFilteredReplication(ctx, masterPositions, destinationShards, filteredReplicationWaitTime); err != nil { - wr.cancelMasterMigrateServedTypes(ctx, sourceShards) + wr.cancelMasterMigrateServedTypes(ctx, keyspace, sourceShards) return err } // We've reached the point of no return. Freeze the tablet control records in the source masters. if err := wr.updateFrozenFlag(ctx, sourceShards, true); err != nil { - wr.cancelMasterMigrateServedTypes(ctx, sourceShards) + wr.cancelMasterMigrateServedTypes(ctx, keyspace, sourceShards) return err } @@ -572,7 +567,7 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string // This will allow someone to reverse the replication later if they change their mind. if err := wr.setupReverseReplication(ctx, sourceShards, destinationShards); err != nil { // It's safe to unfreeze if reverse replication setup fails. - wr.cancelMasterMigrateServedTypes(ctx, sourceShards) + wr.cancelMasterMigrateServedTypes(ctx, keyspace, sourceShards) unfreezeErr := wr.updateFrozenFlag(ctx, sourceShards, false) if unfreezeErr != nil { wr.Logger().Errorf("Problem recovering for failed reverse replication: %v", unfreezeErr) @@ -602,10 +597,12 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string if err != nil { return err } - wr.ts.UpdateDisableQueryService(ctx, si, topodatapb.TabletType_MASTER, nil, false) } + // Enable query service + wr.ts.UpdateDisableQueryService(ctx, keyspace, destinationShards, topodatapb.TabletType_MASTER, nil, false) + event.DispatchUpdate(ev, "setting destination masters read-write") if err := wr.refreshMasters(ctx, destinationShards); err != nil { return err @@ -625,8 +622,8 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string return nil } -func (wr *Wrangler) cancelMasterMigrateServedTypes(ctx context.Context, sourceShards []*topo.ShardInfo) { - if err := wr.updateShardRecords(ctx, sourceShards, nil, topodatapb.TabletType_MASTER, false, true); err != nil { +func (wr *Wrangler) cancelMasterMigrateServedTypes(ctx context.Context, keyspace string, sourceShards []*topo.ShardInfo) { + if err := wr.updateShardRecords(ctx, keyspace, sourceShards, nil, topodatapb.TabletType_MASTER, false, true); err != nil { wr.Logger().Errorf2(err, "failed to re-enable source masters") return } @@ -712,14 +709,14 @@ func (wr *Wrangler) startReverseReplication(ctx context.Context, sourceShards [] } // updateShardRecords updates the shard records based on 'from' or 'to' direction. -func (wr *Wrangler) updateShardRecords(ctx context.Context, shards []*topo.ShardInfo, cells []string, servedType topodatapb.TabletType, isFrom bool, clearSourceShards bool) (err error) { - for i, si := range shards { +func (wr *Wrangler) updateShardRecords(ctx context.Context, keyspace string, shards []*topo.ShardInfo, cells []string, servedType topodatapb.TabletType, isFrom bool, clearSourceShards bool) (err error) { + err = wr.ts.UpdateDisableQueryService(ctx, keyspace, shards, servedType, cells, isFrom /* disable */) - err := wr.ts.UpdateDisableQueryService(ctx, si, servedType, cells, isFrom /* disable */) + if err != nil { + return err + } - if err != nil { - return err - } + for i, si := range shards { shards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { if clearSourceShards { diff --git a/go/vt/wrangler/shard.go b/go/vt/wrangler/shard.go index 2e9de76856c..9b6601cef95 100644 --- a/go/vt/wrangler/shard.go +++ b/go/vt/wrangler/shard.go @@ -120,7 +120,7 @@ func (wr *Wrangler) UpdateDisableQueryService(ctx context.Context, keyspace, sha return err } // disable query service for shard - return wr.ts.UpdateDisableQueryService(ctx, si, tabletType, cells, disableQueryService) + return wr.ts.UpdateDisableQueryService(ctx, keyspace, []*topo.ShardInfo{si}, tabletType, cells, disableQueryService) } // DeleteShard will do all the necessary changes in the topology server From c0996cd1e917dd8291345ff568e57141fc1c8c20 Mon Sep 17 00:00:00 2001 From: Scott Lanning Date: Wed, 6 Feb 2019 18:23:46 +0100 Subject: [PATCH 022/196] make FindSlaves keys be addresses fixes #4532 I didn't see a good way to test it (other than manually running the command). Signed-off-by: Scott Lanning --- go/vt/mysqlctl/replication.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 12aef08d9ab..9a0c9632004 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -23,6 +23,7 @@ package mysqlctl import ( "errors" "fmt" + "net" "strings" "time" @@ -306,7 +307,14 @@ func FindSlaves(mysqld MysqlDaemon) ([]string, error) { if err != nil { return nil, fmt.Errorf("FindSlaves: malformed addr %v", err) } - addrs = append(addrs, host) + var ips []string + ips, err = net.LookupHost(host) + if err != nil { + return nil, fmt.Errorf("FindSlaves: LookupHost failed %v", err) + } + for _, ip := range ips { + addrs = append(addrs, ip) + } } } From ef7a24dbb75b5b0c42d1bcda0f6c033c0a793ad1 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Wed, 6 Feb 2019 14:48:21 -0800 Subject: [PATCH 023/196] Bug fixes * Make sure that we get all cells when non is provided in FindAllTablets * Add function to migrate served types in srv vschema Signed-off-by: Rafael Chacon --- go/vt/topo/shard.go | 9 +++ go/vt/topo/srv_keyspace.go | 89 ++++++++++++++++++++- go/vt/vtctld/api.go | 1 + go/vt/vttablet/tabletmanager/init_tablet.go | 20 ++++- go/vt/wrangler/keyspace.go | 6 ++ 5 files changed, 118 insertions(+), 7 deletions(-) diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index 2ffe984e720..86d4c44b978 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -510,6 +510,15 @@ func (ts *Server) FindAllTabletAliasesInShardByCell(ctx context.Context, keyspac span.Annotate("num_cells", len(cells)) defer span.Finish() ctx = trace.NewContext(ctx, span) + var err error + + // The caller intents to update all cells in this case + if len(cells) == 0 { + cells, err = ts.GetCellInfoNames(ctx) + if err != nil { + return nil, err + } + } // read the shard information to find the cells si, err := ts.GetShard(ctx, keyspace, shard) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index 8ee811baf34..5e6472fd6fc 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -247,11 +247,11 @@ func (ts *Server) RemoveShardServingKeyspace(ctx context.Context, si *ShardInfo, shardReferences = append(shardReferences, shardReference) } } - if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { - rec.RecordError(err) - return - } + } + if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { + rec.RecordError(err) + return } if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { @@ -351,6 +351,87 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string return nil } +// MigrateServedType will make sure the disableQueryService is +func (ts *Server) MigrateServedType(ctx context.Context, keyspace string, shardsToAdd, shardsToRemove []*ShardInfo, tabletType topodatapb.TabletType, cells []string) (err error) { + if err = CheckKeyspaceLocked(ctx, keyspace); err != nil { + return err + } + + // The caller intents to update all cells in this case + if len(cells) == 0 { + cells, err = ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + } + + wg := sync.WaitGroup{} + rec := concurrency.AllErrorRecorder{} + for _, cell := range cells { + wg.Add(1) + go func(cell, keyspace string) { + defer wg.Done() + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + rec.RecordError(err) + return + } + for _, si := range shardsToAdd { + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } + found := false + for _, shardReference := range partition.GetShardReferences() { + if shardReference.GetName() == si.ShardName() { + found = true + } + } + + if !found { + shardReference := &topodatapb.ShardReference{ + Name: si.ShardName(), + KeyRange: si.KeyRange, + } + partition.ShardReferences = append(partition.GetShardReferences(), shardReference) + } + } + } + + for _, si := range shardsToRemove { + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } + shardReferences := make([]*topodatapb.ShardReference, 0) + for _, shardReference := range partition.GetShardReferences() { + if shardReference.GetName() != si.ShardName() { + partition.ShardReferences = append(shardReferences, shardReference) + } + } + } + } + + if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { + rec.RecordError(err) + return + } + + err = ts.UpdateSrvKeyspace(ctx, cell, keyspace, srvKeyspace) + if err != nil { + rec.RecordError(err) + return + } + + }(cell, keyspace) + } + wg.Wait() + if rec.HasErrors() { + return NewError(PartialResult, rec.Error().Error()) + } + return nil +} + // UpdateSrvKeyspace saves a new SrvKeyspace. It is a blind write. func (ts *Server) UpdateSrvKeyspace(ctx context.Context, cell, keyspace string, srvKeyspace *topodatapb.SrvKeyspace) error { conn, err := ts.ConnForCell(ctx, cell) diff --git a/go/vt/vtctld/api.go b/go/vt/vtctld/api.go index 54da31b7653..d5522e06beb 100644 --- a/go/vt/vtctld/api.go +++ b/go/vt/vtctld/api.go @@ -327,6 +327,7 @@ func initAPI(ctx context.Context, ts *topo.Server, actions *ActionRepository, re } return result, nil } + log.Infof("Using findAllTablets with nil cells") result, err := ts.FindAllTabletAliasesInShard(ctx, keyspace, shard) if err != nil && !topo.IsErrType(err, topo.PartialResult) { return result, err diff --git a/go/vt/vttablet/tabletmanager/init_tablet.go b/go/vt/vttablet/tabletmanager/init_tablet.go index 1e418cfa6f9..715b8744953 100644 --- a/go/vt/vttablet/tabletmanager/init_tablet.go +++ b/go/vt/vttablet/tabletmanager/init_tablet.go @@ -24,16 +24,19 @@ import ( "fmt" "time" - "vitess.io/vitess/go/vt/vterrors" - "golang.org/x/net/context" + "vitess.io/vitess/go/flagutil" "vitess.io/vitess/go/netutil" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl" - topodatapb "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" + "vitess.io/vitess/go/vt/topotools" + "vitess.io/vitess/go/vt/vterrors" + + topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) var ( @@ -122,6 +125,17 @@ func (agent *ActionAgent) InitTablet(port, gRPCPort int32) error { } } + // Rebuild keyspace graph if this the first tablet in this keyspace/cell + _, err = agent.TopoServer.GetSrvKeyspace(ctx, agent.TabletAlias.Cell, *initKeyspace) + switch { + case err == nil: + // NOOP + case topo.IsErrType(err, topo.NoNode): + err = topotools.RebuildKeyspaceLocked(ctx, logutil.NewConsoleLogger(), agent.TopoServer, *initKeyspace, []string{agent.TabletAlias.Cell}) + default: + return vterrors.Wrap(err, "InitTablet failed to read srvKeyspace") + } + log.Infof("Initializing the tablet for type %v", tabletType) // figure out the hostname diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index 1a17a3252c0..ee0b57e8a89 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -486,6 +486,12 @@ func (wr *Wrangler) replicaMigrateServedType(ctx context.Context, keyspace strin return err } + // Now update serving keyspace + + if err = wr.ts.MigrateServedType(ctx, keyspace, fromShards, toShards, servedType, cells); err != nil { + return err + } + event.DispatchUpdate(ev, "finished") return nil } From a938468a28cad4b8b6be77b48617d45bc8c93f8e Mon Sep 17 00:00:00 2001 From: deepthi Date: Wed, 6 Feb 2019 20:37:37 -0800 Subject: [PATCH 024/196] update minio-go version to 6.0.16 Signed-off-by: deepthi --- go/vt/mysqlctl/cephbackupstorage/ceph.go | 13 ++-- vendor/vendor.json | 80 ++++++++++++++++++++++-- 2 files changed, 84 insertions(+), 9 deletions(-) diff --git a/go/vt/mysqlctl/cephbackupstorage/ceph.go b/go/vt/mysqlctl/cephbackupstorage/ceph.go index 7d5f3c64670..683a5af9b0b 100644 --- a/go/vt/mysqlctl/cephbackupstorage/ceph.go +++ b/go/vt/mysqlctl/cephbackupstorage/ceph.go @@ -88,7 +88,7 @@ func (bh *CephBackupHandle) AddFile(ctx context.Context, filename string, filesi // Give PutObject() the read end of the pipe. object := objName(bh.dir, bh.name, filename) - _, err := bh.client.PutObject(bucket, object, reader, "application/octet-stream") + _, err := bh.client.PutObject(bucket, object, reader, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"}) if err != nil { // Signal the writer that an error occurred, in case it's not done writing yet. reader.CloseWithError(err) @@ -126,7 +126,7 @@ func (bh *CephBackupHandle) ReadFile(ctx context.Context, filename string) (io.R // ceph bucket name bucket := alterBucketName(bh.dir) object := objName(bh.dir, bh.name, filename) - return bh.client.GetObject(bucket, object) + return bh.client.GetObject(bucket, object, minio.GetObjectOptions{}) } // CephBackupStorage implements BackupStorage for Ceph Cloud Storage. @@ -154,7 +154,7 @@ func (bs *CephBackupStorage) ListBackups(ctx context.Context, dir string) ([]bac doneCh := make(chan struct{}) for object := range c.ListObjects(bucket, searchPrefix, false, doneCh) { if object.Err != nil { - err := c.BucketExists(bucket) + _, err := c.BucketExists(bucket) if err != nil { return nil, nil } @@ -190,8 +190,13 @@ func (bs *CephBackupStorage) StartBackup(ctx context.Context, dir, name string) // ceph bucket name bucket := alterBucketName(dir) - err = c.BucketExists(bucket) + found, err := c.BucketExists(bucket) + if err != nil { + log.Info("Error from BucketExists: %v, quitting", bucket) + return nil, errors.New("Error checking whether bucket exists: " + bucket) + } + if !found { log.Info("Bucket: %v doesn't exist, creating new bucket with the required name", bucket) err = c.MakeBucket(bucket, "") if err != nil { diff --git a/vendor/vendor.json b/vendor/vendor.json index cd595fc3943..8fbf87b2dda 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -673,12 +673,52 @@ "revisionTime": "2016-04-24T11:30:07Z" }, { - "checksumSHA1": "Oi8lZYAVzy67goiwBWBDot28s6k=", + "checksumSHA1": "Yi/mSgnMkG30eC61vcQWVwmxQQ8=", "path": "github.com/minio/minio-go", - "revision": "9f282f76643244430e3d0b69dc7285628a8db8a7", - "revisionTime": "2016-07-19T21:19:03Z", - "version": "v2.0.1", - "versionExact": "v2.0.1" + "revision": "c8a261de75c1a9a9ece4dcc0c81ff6db525bcf27", + "revisionTime": "2019-01-31T01:53:50Z", + "version": "v6.0.16", + "versionExact": "v6.0.16" + }, + { + "checksumSHA1": "pw8e6bgWfeEZUIMnD0Zge4d/KPo=", + "path": "github.com/minio/minio-go/pkg/credentials", + "revision": "c8a261de75c1a9a9ece4dcc0c81ff6db525bcf27", + "revisionTime": "2019-01-31T01:53:50Z", + "version": "v6.0.16", + "versionExact": "v6.0.16" + }, + { + "checksumSHA1": "Md5pOKYfoKtrG7xNvs2FtiDPfDc=", + "path": "github.com/minio/minio-go/pkg/encrypt", + "revision": "c8a261de75c1a9a9ece4dcc0c81ff6db525bcf27", + "revisionTime": "2019-01-31T01:53:50Z", + "version": "v6.0.16", + "versionExact": "v6.0.16" + }, + { + "checksumSHA1": "1KcTZxPRRQ0BWLt1zDVG1bSjm/4=", + "path": "github.com/minio/minio-go/pkg/s3signer", + "revision": "c8a261de75c1a9a9ece4dcc0c81ff6db525bcf27", + "revisionTime": "2019-01-31T01:53:50Z", + "version": "v6.0.16", + "versionExact": "v6.0.16" + }, + { + "checksumSHA1": "7iUaZkEJdhkyAu3F07vrX8pyavI=", + "path": "github.com/minio/minio-go/pkg/s3utils", + "revision": "c8a261de75c1a9a9ece4dcc0c81ff6db525bcf27", + "revisionTime": "2019-01-31T01:53:50Z", + "version": "v6.0.16", + "versionExact": "v6.0.16" + }, + { + "checksumSHA1": "Wt8ej+rZXTdNBR9Xyw1eGo3Iq5o=", + "path": "github.com/minio/minio-go/pkg/set", + "revision": "c8a261de75c1a9a9ece4dcc0c81ff6db525bcf27", + "revisionTime": "2019-01-31T01:53:50Z", + "version": "v6.0.16", + "versionExact": "v6.0.16" }, { "checksumSHA1": "V/quM7+em2ByJbWBLOsEwnY3j/Q=", @@ -872,6 +912,18 @@ "revision": "ecda9a501e8220fae3b4b600c3db4b0ba22cfc68", "revisionTime": "2017-03-16T03:48:04Z" }, + { + "checksumSHA1": "FwW3Vv4jW0Nv7V2SZC7x/Huj5M4=", + "path": "golang.org/x/crypto/argon2", + "revision": "b8fe1690c61389d7d2a8074a507d1d40c5d30448", + "revisionTime": "2019-01-30T22:18:58Z" + }, + { + "checksumSHA1": "eaK7NuGdfEVypOnqYniZSuF2S6s=", + "path": "golang.org/x/crypto/blake2b", + "revision": "b8fe1690c61389d7d2a8074a507d1d40c5d30448", + "revisionTime": "2019-01-30T22:18:58Z" + }, { "checksumSHA1": "N5fb5y92DFIP+wUhi1rSwPp9vyk=", "path": "golang.org/x/crypto/ssh/terminal", @@ -926,6 +978,12 @@ "revision": "5f8847ae0d0e90b6a9dc8148e7ad616874625171", "revisionTime": "2017-06-23T17:10:45Z" }, + { + "checksumSHA1": "j6leSoJatxWHJGLjRxIjZ8GbaDQ=", + "path": "golang.org/x/net/publicsuffix", + "revision": "65e2d4e15006aab9813ff8769e768bbf4bb667a0", + "revisionTime": "2019-02-01T23:59:58Z" + }, { "checksumSHA1": "4vGl3N46SAJwQl/uSlQvZQvc734=", "path": "golang.org/x/net/trace", @@ -962,6 +1020,12 @@ "revision": "04e1573abc896e70388bd387a69753c378d46466", "revisionTime": "2016-07-30T22:43:56Z" }, + { + "checksumSHA1": "1CmUDjhZlyKZcbLYlWI7cRzK3fI=", + "path": "golang.org/x/sys/cpu", + "revision": "41f3e6584952bb034a481797859f6ab34b6803bd", + "revisionTime": "2019-02-04T12:38:20Z" + }, { "checksumSHA1": "QmmEQv1jLvjlVGPsWewqeNYNoyk=", "path": "golang.org/x/sys/unix", @@ -1370,6 +1434,12 @@ "revision": "4e86f4367175e39f69d9358a5f17b4dda270378d", "revisionTime": "2015-09-24T05:17:56Z" }, + { + "checksumSHA1": "8yg3QdSXVEmuHm2CgWXEMFN3K6Q=", + "path": "gopkg.in/ini.v1", + "revision": "6ed8d5f64cd79a498d1f3fab5880cc376ce41bbe", + "revisionTime": "2019-01-03T01:53:35Z" + }, { "checksumSHA1": "itYnRitfdzJjy2mZlvJ+hCJZvtY=", "path": "gopkg.in/ldap.v2", From 4a36888bf576f72d0be8bb2208ce2ef0cf4ea378 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Wed, 6 Feb 2019 12:54:55 -0500 Subject: [PATCH 025/196] java: checkstyle for client module Signed-off-by: Ze'ev Klapow --- java/.gitignore | 1 + java/checkstyle-suppression.xml | 15 + .../main/java/io/vitess/client/Context.java | 54 +-- .../src/main/java/io/vitess/client/Proto.java | 70 +-- .../client/RefreshableVTGateConnection.java | 53 +-- .../main/java/io/vitess/client/RpcClient.java | 39 +- .../io/vitess/client/RpcClientFactory.java | 6 +- .../main/java/io/vitess/client/SQLFuture.java | 63 ++- .../java/io/vitess/client/StreamIterator.java | 35 +- .../io/vitess/client/VTGateBlockingConn.java | 78 ++-- .../client/VTGateBlockingConnection.java | 239 ++++++----- .../io/vitess/client/VTGateBlockingTx.java | 31 +- .../java/io/vitess/client/VTGateConn.java | 135 +++--- .../io/vitess/client/VTGateConnection.java | 398 +++++++++--------- .../main/java/io/vitess/client/VTGateTx.java | 93 ++-- .../main/java/io/vitess/client/VTSession.java | 205 ++++----- .../java/io/vitess/client/cursor/Cursor.java | 30 +- .../vitess/client/cursor/CursorWithError.java | 40 +- .../io/vitess/client/cursor/FieldMap.java | 7 +- .../java/io/vitess/client/cursor/Row.java | 308 +++++++------- .../io/vitess/client/cursor/SimpleCursor.java | 16 +- .../io/vitess/client/cursor/StreamCursor.java | 26 +- .../io/vitess/client/grpc/tls/TlsOptions.java | 11 +- .../main/java/io/vitess/mysql/DateTime.java | 24 +- .../java/io/vitess/client/BindVarTest.java | 25 +- .../java/io/vitess/client/EntityIdTest.java | 148 +++---- .../test/java/io/vitess/client/ProtoTest.java | 9 +- .../java/io/vitess/client/RpcClientTest.java | 103 +++-- .../test/java/io/vitess/client/TestEnv.java | 8 +- .../test/java/io/vitess/client/TestUtil.java | 26 +- .../io/vitess/client/cursor/CursorTest.java | 55 ++- .../java/io/vitess/mysql/DateTimeTest.java | 9 +- java/pom.xml | 23 + 33 files changed, 1282 insertions(+), 1101 deletions(-) create mode 100644 java/.gitignore create mode 100644 java/checkstyle-suppression.xml diff --git a/java/.gitignore b/java/.gitignore new file mode 100644 index 00000000000..2f7896d1d13 --- /dev/null +++ b/java/.gitignore @@ -0,0 +1 @@ +target/ diff --git a/java/checkstyle-suppression.xml b/java/checkstyle-suppression.xml new file mode 100644 index 00000000000..77906f6572a --- /dev/null +++ b/java/checkstyle-suppression.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/client/src/main/java/io/vitess/client/Context.java b/java/client/src/main/java/io/vitess/client/Context.java index b701820f635..c2a2bffcd98 100644 --- a/java/client/src/main/java/io/vitess/client/Context.java +++ b/java/client/src/main/java/io/vitess/client/Context.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,31 +16,41 @@ package io.vitess.client; -import javax.annotation.Nullable; +import io.vitess.proto.Vtrpc.CallerID; + import org.joda.time.Duration; import org.joda.time.Instant; -import io.vitess.proto.Vtrpc.CallerID; +import javax.annotation.Nullable; /** * Context is an immutable object that carries per-request info. * *

RPC frameworks like gRPC have their own Context implementations that - * allow propagation of deadlines, cancellation, and end-user credentials - * across RPC boundaries (between client and server). Since these - * framework-specific Context implementations are not compatible with one - * another, we provide our own Context class that wraps common features. + * allow propagation of deadlines, cancellation, and end-user credentials across RPC boundaries + * (between client and server). Since these framework-specific Context implementations are not + * compatible with one another, we provide our own Context class that wraps common features. * *

In gRPC and other frameworks, the current Context is maintained in - * thread-local storage, so it's implicitly available to any method that - * needs it. In this Vitess client library, we pass Context as an explicit - * parameter to methods that need it. This allows us to defer enforcement - * of the specified request constraints until the request reaches the - * underlying framework-specific Vitess client implementation, at which point - * the native Context class can be used. + * thread-local storage, so it's implicitly available to any method that needs it. In this Vitess + * client library, we pass Context as an explicit parameter to methods that need it. This allows us + * to defer enforcement of the specified request constraints until the request reaches the + * underlying framework-specific Vitess client implementation, at which point the native Context + * class can be used. */ public class Context { + private static final Context DEFAULT_CONTEXT = new Context(); + private Instant deadline; + private CallerID callerId; + + private Context() { + } + + private Context(Instant deadline, CallerID callerId) { + this.deadline = deadline; + this.callerId = callerId; + } // getDefault returns an empty context. public static Context getDefault() { @@ -57,8 +67,8 @@ public Context withDeadline(Instant deadline) { } /** - * withDeadlineAfter returns a derived context with a maximum deadline - * specified relative to the current time. + * withDeadlineAfter returns a derived context with a maximum deadline specified relative to the + * current time. */ public Context withDeadlineAfter(Duration duration) { return withDeadline(Instant.now().plus(duration)); @@ -90,14 +100,4 @@ public Duration getTimeout() { public CallerID getCallerId() { return callerId; } - - private Instant deadline; - private CallerID callerId; - - private Context() {} - - private Context(Instant deadline, CallerID callerId) { - this.deadline = deadline; - this.callerId = callerId; - } } diff --git a/java/client/src/main/java/io/vitess/client/Proto.java b/java/client/src/main/java/io/vitess/client/Proto.java index 2f15ccb4baa..2706a06fda4 100644 --- a/java/client/src/main/java/io/vitess/client/Proto.java +++ b/java/client/src/main/java/io/vitess/client/Proto.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -21,6 +21,19 @@ import com.google.common.collect.Iterables; import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; + +import io.vitess.client.cursor.Cursor; +import io.vitess.client.cursor.CursorWithError; +import io.vitess.client.cursor.SimpleCursor; +import io.vitess.proto.Query; +import io.vitess.proto.Query.BindVariable; +import io.vitess.proto.Query.BoundQuery; +import io.vitess.proto.Query.QueryResult; +import io.vitess.proto.Vtgate.BoundKeyspaceIdQuery; +import io.vitess.proto.Vtgate.BoundShardQuery; +import io.vitess.proto.Vtgate.ExecuteEntityIdsRequest.EntityId; +import io.vitess.proto.Vtrpc.RPCError; + import java.math.BigDecimal; import java.math.BigInteger; import java.sql.SQLException; @@ -34,25 +47,28 @@ import java.util.Iterator; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; -import io.vitess.client.cursor.Cursor; -import io.vitess.client.cursor.CursorWithError; -import io.vitess.client.cursor.SimpleCursor; -import io.vitess.proto.Query; -import io.vitess.proto.Query.BindVariable; -import io.vitess.proto.Query.BoundQuery; -import io.vitess.proto.Query.QueryResult; -import io.vitess.proto.Vtgate.BoundKeyspaceIdQuery; -import io.vitess.proto.Vtgate.BoundShardQuery; -import io.vitess.proto.Vtgate.ExecuteEntityIdsRequest.EntityId; -import io.vitess.proto.Vtrpc.RPCError; +import javax.annotation.Nullable; /** * Proto contains methods for working with Vitess protobuf messages. */ public class Proto { + public static final Function BYTE_ARRAY_TO_BYTE_STRING = + new Function() { + @Override + public ByteString apply(byte[] from) { + return ByteString.copyFrom(from); + } + }; + public static final Function, EntityId> MAP_ENTRY_TO_ENTITY_KEYSPACE_ID = + new Function, EntityId>() { + @Override + public EntityId apply(Map.Entry entry) { + return buildEntityId(entry.getKey(), entry.getValue()); + } + }; private static final int MAX_DECIMAL_UNIT = 30; /** @@ -133,7 +149,7 @@ public static int getErrno(@Nullable String errorMessage) { } try { return Integer.parseInt(errorMessage.substring(start, end)); - } catch (NumberFormatException e) { + } catch (NumberFormatException exc) { return 0; } } @@ -256,7 +272,8 @@ public static List toCursorList(List queryResults) { return builder.build(); } - public static List fromQueryResponsesToCursorList(List resultWithErrorList) { + public static List fromQueryResponsesToCursorList( + List resultWithErrorList) { ImmutableList.Builder builder = new ImmutableList.Builder(); for (Query.ResultWithError resultWithError : resultWithErrorList) { builder.add(new CursorWithError(resultWithError)); @@ -264,26 +281,11 @@ public static List fromQueryResponsesToCursorList(List BYTE_ARRAY_TO_BYTE_STRING = - new Function() { - @Override - public ByteString apply(byte[] from) { - return ByteString.copyFrom(from); - } - }; - - public static final Function, EntityId> MAP_ENTRY_TO_ENTITY_KEYSPACE_ID = - new Function, EntityId>() { - @Override - public EntityId apply(Map.Entry entry) { - return buildEntityId(entry.getKey(), entry.getValue()); - } - }; - /** * Represents a type and value in the type system used in query.proto. */ protected static class TypedValue { + Query.Type type; ByteString value; @@ -300,7 +302,7 @@ protected static class TypedValue { this.type = Query.Type.VARBINARY; this.value = ByteString.copyFrom((byte[]) value); } else if (value instanceof Integer || value instanceof Long || value instanceof Short - || value instanceof Byte ) { + || value instanceof Byte) { // Int32, Int64, Short, Byte this.type = Query.Type.INT64; this.value = ByteString.copyFromUtf8(value.toString()); diff --git a/java/client/src/main/java/io/vitess/client/RefreshableVTGateConnection.java b/java/client/src/main/java/io/vitess/client/RefreshableVTGateConnection.java index 030062f6641..d1fb6d0621b 100644 --- a/java/client/src/main/java/io/vitess/client/RefreshableVTGateConnection.java +++ b/java/client/src/main/java/io/vitess/client/RefreshableVTGateConnection.java @@ -3,33 +3,34 @@ import java.io.File; public class RefreshableVTGateConnection extends VTGateConnection { - private final File keystoreFile; - private final File truststoreFile; - private volatile long keystoreMtime; - private volatile long truststoreMtime; - public RefreshableVTGateConnection(RpcClient client, - String keystorePath, - String truststorePath) { - super(client); - this.keystoreFile = new File(keystorePath); - this.truststoreFile = new File(truststorePath); - this.keystoreMtime = this.keystoreFile.exists() ? this.keystoreFile.lastModified() : 0; - this.truststoreMtime = this.truststoreFile.exists() ? this.truststoreFile.lastModified() : 0; - } + private final File keystoreFile; + private final File truststoreFile; + private volatile long keystoreMtime; + private volatile long truststoreMtime; + + public RefreshableVTGateConnection(RpcClient client, + String keystorePath, + String truststorePath) { + super(client); + this.keystoreFile = new File(keystorePath); + this.truststoreFile = new File(truststorePath); + this.keystoreMtime = this.keystoreFile.exists() ? this.keystoreFile.lastModified() : 0; + this.truststoreMtime = this.truststoreFile.exists() ? this.truststoreFile.lastModified() : 0; + } - public boolean checkKeystoreUpdates() { - long keystoreMtime = keystoreFile.exists() ? keystoreFile.lastModified() : 0; - long truststoreMtime = truststoreFile.exists() ? truststoreFile.lastModified() : 0; - boolean modified = false; - if (keystoreMtime > this.keystoreMtime) { - modified = true; - this.keystoreMtime = keystoreMtime; - } - if (truststoreMtime > this.truststoreMtime) { - modified = true; - this.truststoreMtime = truststoreMtime; - } - return modified; + public boolean checkKeystoreUpdates() { + long keystoreMtime = keystoreFile.exists() ? keystoreFile.lastModified() : 0; + long truststoreMtime = truststoreFile.exists() ? truststoreFile.lastModified() : 0; + boolean modified = false; + if (keystoreMtime > this.keystoreMtime) { + modified = true; + this.keystoreMtime = keystoreMtime; + } + if (truststoreMtime > this.truststoreMtime) { + modified = true; + this.truststoreMtime = truststoreMtime; } + return modified; + } } diff --git a/java/client/src/main/java/io/vitess/client/RpcClient.java b/java/client/src/main/java/io/vitess/client/RpcClient.java index 68015380044..31bd7e51689 100644 --- a/java/client/src/main/java/io/vitess/client/RpcClient.java +++ b/java/client/src/main/java/io/vitess/client/RpcClient.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,8 +17,6 @@ package io.vitess.client; import com.google.common.util.concurrent.ListenableFuture; -import java.io.Closeable; -import java.sql.SQLException; import io.vitess.proto.Query.QueryResult; import io.vitess.proto.Vtgate; @@ -51,10 +49,14 @@ import io.vitess.proto.Vtgate.StreamExecuteRequest; import io.vitess.proto.Vtgate.StreamExecuteShardsRequest; +import java.io.Closeable; +import java.sql.SQLException; + /** * RpcClient defines a set of methods to communicate with VTGates. */ public interface RpcClient extends Closeable { + /** * Sends a single query using the VTGate V3 API. * @@ -112,7 +114,8 @@ ListenableFuture executeEntityIds( * proto * definition for canonical documentation on this VTGate API. */ - ListenableFuture executeBatch(Context ctx, Vtgate.ExecuteBatchRequest request) + ListenableFuture executeBatch(Context ctx, + Vtgate.ExecuteBatchRequest request) throws SQLException; /** @@ -139,9 +142,9 @@ ListenableFuture executeBatchKeyspaceIds( * Starts stream queries with the VTGate V3 API. * *

Note: Streaming queries are not asynchronous, because they typically shouldn't - * be used from a latency-critical serving path anyway. This method will return as - * soon as the request is initiated, but StreamIterator methods will block until the - * next chunk of results is received from the server. + * be used from a latency-critical serving path anyway. This method will return as soon as the + * request is initiated, but StreamIterator methods will block until the next chunk of results is + * received from the server. * *

See the * proto @@ -154,9 +157,9 @@ StreamIterator streamExecute(Context ctx, StreamExecuteRequest requ * Starts stream queries with multiple shards. * *

Note: Streaming queries are not asynchronous, because they typically shouldn't - * be used from a latency-critical serving path anyway. This method will return as - * soon as the request is initiated, but StreamIterator methods will block until the - * next chunk of results is received from the server. + * be used from a latency-critical serving path anyway. This method will return as soon as the + * request is initiated, but StreamIterator methods will block until the next chunk of results is + * received from the server. * *

See the * proto @@ -169,9 +172,9 @@ StreamIterator streamExecuteShards(Context ctx, StreamExecuteShards * Starts a list of stream queries with keyspace ids as bind variables. * *

Note: Streaming queries are not asynchronous, because they typically shouldn't - * be used from a latency-critical serving path anyway. This method will return as - * soon as the request is initiated, but StreamIterator methods will block until the - * next chunk of results is received from the server. + * be used from a latency-critical serving path anyway. This method will return as soon as the + * request is initiated, but StreamIterator methods will block until the next chunk of results is + * received from the server. * *

See the * proto @@ -184,9 +187,9 @@ StreamIterator streamExecuteKeyspaceIds( * Starts stream query with a set of key ranges. * *

Note: Streaming queries are not asynchronous, because they typically shouldn't - * be used from a latency-critical serving path anyway. This method will return as - * soon as the request is initiated, but StreamIterator methods will block until the - * next chunk of results is received from the server. + * be used from a latency-critical serving path anyway. This method will return as soon as the + * request is initiated, but StreamIterator methods will block until the next chunk of results is + * received from the server. * *

See the * proto diff --git a/java/client/src/main/java/io/vitess/client/RpcClientFactory.java b/java/client/src/main/java/io/vitess/client/RpcClientFactory.java index 67e72d60aee..762f7105395 100644 --- a/java/client/src/main/java/io/vitess/client/RpcClientFactory.java +++ b/java/client/src/main/java/io/vitess/client/RpcClientFactory.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. diff --git a/java/client/src/main/java/io/vitess/client/SQLFuture.java b/java/client/src/main/java/io/vitess/client/SQLFuture.java index 9c43c2c8bbb..0afef6fd0ed 100644 --- a/java/client/src/main/java/io/vitess/client/SQLFuture.java +++ b/java/client/src/main/java/io/vitess/client/SQLFuture.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -18,6 +18,7 @@ import com.google.common.util.concurrent.ForwardingListenableFuture.SimpleForwardingListenableFuture; import com.google.common.util.concurrent.ListenableFuture; + import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.sql.SQLException; @@ -31,22 +32,22 @@ * *

* When used as a {@link ListenableFuture}, the {@link SQLException} thrown by Vitess will be - * wrapped in {@link ExecutionException}. You can retrieve it by calling - * {@link ExecutionException#getCause()}. + * wrapped in {@link ExecutionException}. You can retrieve it by calling {@link + * ExecutionException#getCause()}. * *

* For users who want to get results synchronously, we provide {@link #checkedGet()} as a - * convenience method. Unlike {@link #get()}, it throws only {@code SQLException}, so e.g. - * {@code vtgateConn.execute(...).checkedGet()} behaves the same as our old synchronous API. + * convenience method. Unlike {@link #get()}, it throws only {@code SQLException}, so e.g. {@code + * vtgateConn.execute(...).checkedGet()} behaves the same as our old synchronous API. * *

* The additional methods are similar to the {@code CheckedFuture} interface (marked as beta), but * this class does not declare that it implements {@code CheckedFuture} because that interface is - * not recommended for new projects. See the + * not recommended for new projects. See the * CheckedFuture docs for more information. */ public class SQLFuture extends SimpleForwardingListenableFuture { + /** * Creates a SQLFuture that wraps the given ListenableFuture. */ @@ -64,13 +65,11 @@ public SQLFuture(ListenableFuture delegate) { public V checkedGet() throws SQLException { try { return get(); - } catch (InterruptedException e) { + } catch (InterruptedException exc) { Thread.currentThread().interrupt(); - throw mapException(e); - } catch (CancellationException e) { - throw mapException(e); - } catch (ExecutionException e) { - throw mapException(e); + throw mapException(exc); + } catch (CancellationException | ExecutionException exc) { + throw mapException(exc); } } @@ -84,33 +83,31 @@ public V checkedGet() throws SQLException { public V checkedGet(long timeout, TimeUnit unit) throws TimeoutException, SQLException { try { return get(timeout, unit); - } catch (InterruptedException e) { + } catch (InterruptedException exc) { Thread.currentThread().interrupt(); - throw mapException(e); - } catch (CancellationException e) { - throw mapException(e); - } catch (ExecutionException e) { - throw mapException(e); + throw mapException(exc); + } catch (CancellationException | ExecutionException exc) { + throw mapException(exc); } } /** - * Translates from an {@link InterruptedException}, {@link CancellationException} or - * {@link ExecutionException} thrown by {@code get} to an exception of type {@code SQLException} - * to be thrown by {@code checkedGet}. + * Translates from an {@link InterruptedException}, {@link CancellationException} or {@link + * ExecutionException} thrown by {@code get} to an exception of type {@code SQLException} to be + * thrown by {@code checkedGet}. * *

- * If {@code e} is an {@code InterruptedException}, the calling {@code checkedGet} method has - * already restored the interrupt after catching the exception. If an implementation of - * {@link #mapException(Exception)} wishes to swallow the interrupt, it can do so by calling - * {@link Thread#interrupted()}. + * If {@code exc} is an {@code InterruptedException}, the calling {@code checkedGet} method has + * already restored the interrupt after catching the exception. If an implementation of {@link + * #mapException(Exception)} wishes to swallow the interrupt, it can do so by calling {@link + * Thread#interrupted()}. */ - protected SQLException mapException(Exception e) { - if (e instanceof ExecutionException) { + protected SQLException mapException(Exception exc) { + if (exc instanceof ExecutionException) { // To preserve both the stack trace and SQLException subclass type of the error // being wrapped, we use reflection to create a new instance of the particular // subclass of the original exception. - Throwable cause = e.getCause(); + Throwable cause = exc.getCause(); if (cause instanceof SQLException) { SQLException se = (SQLException) cause; try { @@ -119,7 +116,7 @@ protected SQLException mapException(Exception e) { .getClass() .getConstructor(String.class, String.class, int.class, Throwable.class); return (SQLException) - constructor.newInstance(se.getMessage(), se.getSQLState(), se.getErrorCode(), e); + constructor.newInstance(se.getMessage(), se.getSQLState(), se.getErrorCode(), exc); } catch (NoSuchMethodException | InstantiationException | IllegalAccessException @@ -131,6 +128,6 @@ protected SQLException mapException(Exception e) { } } - return new SQLException(e); + return new SQLException(exc); } } diff --git a/java/client/src/main/java/io/vitess/client/StreamIterator.java b/java/client/src/main/java/io/vitess/client/StreamIterator.java index 6550952329b..7d97da0779a 100644 --- a/java/client/src/main/java/io/vitess/client/StreamIterator.java +++ b/java/client/src/main/java/io/vitess/client/StreamIterator.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -20,29 +20,30 @@ import java.util.NoSuchElementException; /** - * An {@link java.util.Iterator Iterator}-like interface for accessing the results of a - * Vitess streaming call. + * An {@link java.util.Iterator Iterator}-like interface for accessing the results of a Vitess + * streaming call. * *

It is similar to {@link java.util.Iterator}, but the hasNext() method is - * understood to block until either a result is ready, an error occurs, - * or there are no more results. Also, unlike Iterator, these methods - * can throw SQLException. + * understood to block until either a result is ready, an error occurs, or there are no more + * results. Also, unlike Iterator, these methods can throw SQLException. * - *

The {@link #close()} method should be called when done to free up threads that may be blocking + *

The {@link #close()} method should be called when done to free up threads that may be + * blocking * on the streaming connection. * - * @param the type of result returned by the iterator, - * e.g. {@link io.vitess.proto.Query.QueryResult QueryResult} + * @param the type of result returned by the iterator, e.g. {@link + * io.vitess.proto.Query.QueryResult QueryResult} */ public interface StreamIterator extends AutoCloseable { + /** * hasNext returns true if next() would return a value. * *

If no value is available, hasNext() will block until either: *

    - *
  • A value becomes available (returns true), - *
  • The stream completes successfully (returns false), - *
  • An error occurs (throws exception). + *
  • A value becomes available (returns true), + *
  • The stream completes successfully (returns false), + *
  • An error occurs (throws exception). *
*/ boolean hasNext() throws SQLException; @@ -52,9 +53,9 @@ public interface StreamIterator extends AutoCloseable { * *

If no value is available, next() will block until either: *

    - *
  • A value becomes available (returns the value), - *
  • The stream completes successfully (throws NoSuchElementException), - *
  • An error occurs (throws other exception). + *
  • A value becomes available (returns the value), + *
  • The stream completes successfully (throws NoSuchElementException), + *
  • An error occurs (throws other exception). *
*/ E next() throws NoSuchElementException, SQLException; diff --git a/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java b/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java index 03ca209bc0d..d2aee89e0a0 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java +++ b/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,14 +16,6 @@ package io.vitess.client; -import java.io.Closeable; -import java.io.IOException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; - import io.vitess.client.cursor.Cursor; import io.vitess.client.cursor.CursorWithError; import io.vitess.proto.Query; @@ -35,6 +27,15 @@ import io.vitess.proto.Vtgate.BoundShardQuery; import io.vitess.proto.Vtgate.SplitQueryResponse; +import java.io.Closeable; +import java.io.IOException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + /** * A synchronous wrapper around a VTGate connection. * @@ -44,6 +45,7 @@ */ @Deprecated public class VTGateBlockingConn implements Closeable { + private final VTGateConn conn; /** @@ -76,15 +78,18 @@ public Cursor execute(Context ctx, String query, Map bindVars, Tablet } public Cursor executeShards(Context ctx, String query, String keyspace, Iterable shards, - Map bindVars, TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields).checkedGet(); + Map bindVars, TabletType tabletType, + Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + return conn.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields) + .checkedGet(); } public Cursor executeKeyspaceIds(Context ctx, String query, String keyspace, Iterable keyspaceIds, Map bindVars, TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.executeKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields) + return conn + .executeKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields) .checkedGet(); } @@ -92,13 +97,15 @@ public Cursor executeKeyRanges(Context ctx, String query, String keyspace, Iterable keyRanges, Map bindVars, TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.executeKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields) + return conn + .executeKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields) .checkedGet(); } public Cursor executeEntityIds(Context ctx, String query, String keyspace, String entityColumnName, Map entityKeyspaceIds, Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { return conn.executeEntityIds(ctx, query, keyspace, entityColumnName, entityKeyspaceIds, bindVars, tabletType, includedFields).checkedGet(); } @@ -111,36 +118,44 @@ public List executeBatch(Context ctx, ArrayList queryLi public List executeBatch(Context ctx, ArrayList queryList, @Nullable ArrayList> bindVarsList, TabletType tabletType, - boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.executeBatch(ctx, queryList, bindVarsList, tabletType, asTransaction, includedFields).checkedGet(); + boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { + return conn + .executeBatch(ctx, queryList, bindVarsList, tabletType, asTransaction, includedFields) + .checkedGet(); } /** * Execute multiple keyspace ID queries as a batch. * - * @param asTransaction If true, automatically create a transaction (per shard) that encloses all - * the batch queries. + * @param asTransaction If true, automatically create a transaction (per shard) that encloses + * all the batch queries. */ public List executeBatchShards(Context ctx, Iterable queries, - TabletType tabletType, boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) + TabletType tabletType, boolean asTransaction, + Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.executeBatchShards(ctx, queries, tabletType, asTransaction, includedFields).checkedGet(); + return conn.executeBatchShards(ctx, queries, tabletType, asTransaction, includedFields) + .checkedGet(); } /** * Execute multiple keyspace ID queries as a batch. * - * @param asTransaction If true, automatically create a transaction (per shard) that encloses all - * the batch queries. + * @param asTransaction If true, automatically create a transaction (per shard) that encloses + * all the batch queries. */ public List executeBatchKeyspaceIds(Context ctx, Iterable queries, TabletType tabletType, - boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.executeBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, includedFields).checkedGet(); + boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { + return conn.executeBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, includedFields) + .checkedGet(); } public Cursor streamExecute(Context ctx, String query, Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { return conn.streamExecute(ctx, query, bindVars, tabletType, includedFields); } @@ -148,21 +163,24 @@ public Cursor streamExecuteShards(Context ctx, String query, String keyspace, Iterable shards, Map bindVars, TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.streamExecuteShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields); + return conn + .streamExecuteShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields); } public Cursor streamExecuteKeyspaceIds(Context ctx, String query, String keyspace, Iterable keyspaceIds, Map bindVars, TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.streamExecuteKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields); + return conn.streamExecuteKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, + includedFields); } public Cursor streamExecuteKeyRanges(Context ctx, String query, String keyspace, Iterable keyRanges, Map bindVars, TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return conn.streamExecuteKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields); + return conn.streamExecuteKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, + includedFields); } public VTGateBlockingTx begin(Context ctx) throws SQLException { diff --git a/java/client/src/main/java/io/vitess/client/VTGateBlockingConnection.java b/java/client/src/main/java/io/vitess/client/VTGateBlockingConnection.java index 183f17ac2a3..1d29492333c 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateBlockingConnection.java +++ b/java/client/src/main/java/io/vitess/client/VTGateBlockingConnection.java @@ -16,135 +16,162 @@ package io.vitess.client; +import io.vitess.client.cursor.Cursor; +import io.vitess.client.cursor.CursorWithError; +import io.vitess.proto.Query.SplitQueryRequest.Algorithm; +import io.vitess.proto.Vtgate.SplitQueryResponse; + import java.io.Closeable; import java.io.IOException; import java.sql.SQLException; import java.util.List; import java.util.Map; -import javax.annotation.Nullable; -import io.vitess.client.cursor.Cursor; -import io.vitess.client.cursor.CursorWithError; -import io.vitess.proto.Query.SplitQueryRequest.Algorithm; -import io.vitess.proto.Vtgate.SplitQueryResponse; +import javax.annotation.Nullable; /** * An asynchronous VTGate connection. *

*

All the information regarding this connection is maintained by {@code Session}, - * only one operation can be in flight at a time on a given instance. - * The methods are {@code synchronized} only because the session cookie is updated asynchronously - * when the RPC response comes back.

+ * only one operation can be in flight at a time on a given instance. The methods are {@code + * synchronized} only because the session cookie is updated asynchronously when the RPC response + * comes back.

*

*

After calling any method that returns a {@link SQLFuture}, you must wait for that future to - * complete before calling any other methods on that {@code VTGateConnection} instance. - * An {@link IllegalStateException} will be thrown if this constraint is violated.

+ * complete before calling any other methods on that {@code VTGateConnection} instance. An {@link + * IllegalStateException} will be thrown if this constraint is violated.

*

- *

All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link VTGateBlockingConnection} if + *

All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link + * VTGateBlockingConnection} if * you want synchronous calls.

*/ public final class VTGateBlockingConnection implements Closeable { - private final VTGateConnection vtGateConnection; - /** - * Creates a VTGate connection with no specific parameters. - *

- *

In this mode, VTGate will use VSchema to resolve the keyspace for any unprefixed - * table names. Note that this only works if the table name is unique across all keyspaces.

- * - * @param client RPC connection - */ - public VTGateBlockingConnection(RpcClient client) { - vtGateConnection = new VTGateConnection(client); - } + private final VTGateConnection vtGateConnection; + + /** + * Creates a VTGate connection with no specific parameters. + *

+ *

In this mode, VTGate will use VSchema to resolve the keyspace for any unprefixed + * table names. Note that this only works if the table name is unique across all keyspaces.

+ * + * @param client RPC connection + */ + public VTGateBlockingConnection(RpcClient client) { + vtGateConnection = new VTGateConnection(client); + } - /** - * This method calls the VTGate to execute the query. - * - * @param ctx Context on user and execution deadline if any. - * @param query Sql Query to be executed. - * @param bindVars Parameters to bind with sql. - * @param vtSession Session to be used with the call. - * @return Cursor - * @throws SQLException If anything fails on query execution. - */ - public Cursor execute(Context ctx, String query, @Nullable Map bindVars, final VTSession vtSession) throws SQLException { - return vtGateConnection.execute(ctx, query, bindVars, vtSession).checkedGet(); - } + /** + * This method calls the VTGate to execute the query. + * + * @param ctx Context on user and execution deadline if any. + * @param query Sql Query to be executed. + * @param bindVars Parameters to bind with sql. + * @param vtSession Session to be used with the call. + * @return Cursor + * @throws SQLException If anything fails on query execution. + */ + public Cursor execute(Context ctx, + String query, + @Nullable Map bindVars, + final VTSession vtSession) throws SQLException { + return vtGateConnection.execute(ctx, query, bindVars, vtSession).checkedGet(); + } - /** - * This method calls the VTGate to execute list of queries as a batch. - * - * @param ctx Context on user and execution deadline if any. - * @param queryList List of sql queries to be executed. - * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. - * If provided, should match the number of sql queries.

- * @param vtSession Session to be used with the call. - * @return List of Cursors - * @throws SQLException If anything fails on query execution. - */ - public List executeBatch(Context ctx, List queryList, @Nullable List> bindVarsList, final VTSession vtSession) throws SQLException { - return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, vtSession).checkedGet(); - } + /** + * This method calls the VTGate to execute list of queries as a batch. + * + * @param ctx Context on user and execution deadline if any. + * @param queryList List of sql queries to be executed. + * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. If + * provided, should match the number of sql queries.

+ * @param vtSession Session to be used with the call. + * @return List of Cursors + * @throws SQLException If anything fails on query execution. + */ + public List executeBatch(Context ctx, + List queryList, + @Nullable List> bindVarsList, + final VTSession vtSession) throws SQLException { + return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, vtSession).checkedGet(); + } - /** - * This method calls the VTGate to execute list of queries as a batch. - *

- *

If asTransaction is set to true then query execution will not change the session cookie. - * Otherwise, query execution will become part of the session.

- * - * @param ctx Context on user and execution deadline if any. - * @param queryList List of sql queries to be executed. - * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. - * If provided, should match the number of sql queries.

- * @param asTransaction To execute query without impacting session cookie. - * @param vtSession Session to be used with the call. - * @return List of Cursors - * @throws SQLException If anything fails on query execution. - */ - public List executeBatch(Context ctx, List queryList, @Nullable List> bindVarsList, boolean asTransaction, final VTSession vtSession) throws SQLException { - return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, asTransaction, vtSession).checkedGet(); - } + /** + * This method calls the VTGate to execute list of queries as a batch. + *

+ *

If asTransaction is set to true then query execution will not change the + * session cookie. + * Otherwise, query execution will become part of the session.

+ * + * @param ctx Context on user and execution deadline if any. + * @param queryList List of sql queries to be executed. + * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. If + * provided, should match the number of sql queries.

+ * @param asTransaction To execute query without impacting session cookie. + * @param vtSession Session to be used with the call. + * @return List of Cursors + * @throws SQLException If anything fails on query execution. + */ + public List executeBatch(Context ctx, + List queryList, + @Nullable List> bindVarsList, + boolean asTransaction, + final VTSession vtSession) throws SQLException { + return vtGateConnection.executeBatch(ctx, queryList, bindVarsList, asTransaction, vtSession) + .checkedGet(); + } - /** - * This method should be used execute select query to return response as a stream. - * - * @param ctx Context on user and execution deadline if any. - * @param query Sql Query to be executed. - * @param bindVars Parameters to bind with sql. - * @param vtSession Session to be used with the call. - * @return Cursor - * @throws SQLException Returns SQLException if there is any failure on VTGate. - */ - public Cursor streamExecute(Context ctx, String query, @Nullable Map bindVars, VTSession vtSession) throws SQLException { - return vtGateConnection.streamExecute(ctx, query, bindVars, vtSession); - } + /** + * This method should be used execute select query to return response as a stream. + * + * @param ctx Context on user and execution deadline if any. + * @param query Sql Query to be executed. + * @param bindVars Parameters to bind with sql. + * @param vtSession Session to be used with the call. + * @return Cursor + * @throws SQLException Returns SQLException if there is any failure on VTGate. + */ + public Cursor streamExecute(Context ctx, + String query, + @Nullable Map bindVars, + VTSession vtSession) throws SQLException { + return vtGateConnection.streamExecute(ctx, query, bindVars, vtSession); + } - /** - * This method splits the query into small parts based on the splitColumn and Algorithm type provided. - * - * @param ctx Context on user and execution deadline if any. - * @param keyspace Keyspace to execute the query on. - * @param query Sql Query to be executed. - * @param bindVars Parameters to bind with sql. - * @param splitColumns Column to be used to split the data. - * @param splitCount Number of Partitions - * @param numRowsPerQueryPart Limit the number of records per query part. - * @param algorithm EQUAL_SPLITS or FULL_SCAN - * @return Query Parts - * @throws SQLException If anything fails on query execution. - */ - public List splitQuery(Context ctx, String keyspace, String query, @Nullable Map bindVars, Iterable splitColumns, - int splitCount, int numRowsPerQueryPart, Algorithm algorithm) throws SQLException { - return vtGateConnection.splitQuery(ctx, keyspace, query, bindVars, splitColumns, splitCount, numRowsPerQueryPart, algorithm).checkedGet(); - } + /** + * This method splits the query into small parts based on the splitColumn and Algorithm type + * provided. + * + * @param ctx Context on user and execution deadline if any. + * @param keyspace Keyspace to execute the query on. + * @param query Sql Query to be executed. + * @param bindVars Parameters to bind with sql. + * @param splitColumns Column to be used to split the data. + * @param splitCount Number of Partitions + * @param numRowsPerQueryPart Limit the number of records per query part. + * @param algorithm EQUAL_SPLITS or FULL_SCAN + * @return Query Parts + * @throws SQLException If anything fails on query execution. + */ + public List splitQuery(Context ctx, + String keyspace, + String query, + @Nullable Map bindVars, + Iterable splitColumns, + int splitCount, + int numRowsPerQueryPart, + Algorithm algorithm) throws SQLException { + return vtGateConnection + .splitQuery(ctx, keyspace, query, bindVars, splitColumns, splitCount, numRowsPerQueryPart, + algorithm).checkedGet(); + } - /** - * @inheritDoc - */ - @Override - public void close() throws IOException { - vtGateConnection.close(); - } + /** + * @inheritDoc + */ + @Override + public void close() throws IOException { + vtGateConnection.close(); + } } diff --git a/java/client/src/main/java/io/vitess/client/VTGateBlockingTx.java b/java/client/src/main/java/io/vitess/client/VTGateBlockingTx.java index 18361bbcb6d..a44597e465c 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateBlockingTx.java +++ b/java/client/src/main/java/io/vitess/client/VTGateBlockingTx.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,11 +16,6 @@ package io.vitess.client; -import java.sql.SQLException; -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; - import io.vitess.client.cursor.Cursor; import io.vitess.client.cursor.CursorWithError; import io.vitess.proto.Query; @@ -29,6 +24,12 @@ import io.vitess.proto.Vtgate.BoundKeyspaceIdQuery; import io.vitess.proto.Vtgate.BoundShardQuery; +import java.sql.SQLException; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + /** * A synchronous wrapper around a VTGate transaction. * @@ -37,6 +38,7 @@ */ @Deprecated public class VTGateBlockingTx { + private final VTGateTx tx; /** @@ -61,7 +63,8 @@ public Cursor executeShards( TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return tx.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields).checkedGet(); + return tx.executeShards(ctx, query, keyspace, shards, bindVars, tabletType, includedFields) + .checkedGet(); } public Cursor executeKeyspaceIds( @@ -73,7 +76,8 @@ public Cursor executeKeyspaceIds( TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return tx.executeKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields) + return tx + .executeKeyspaceIds(ctx, query, keyspace, keyspaceIds, bindVars, tabletType, includedFields) .checkedGet(); } @@ -86,7 +90,9 @@ public Cursor executeKeyRanges( TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return tx.executeKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields).checkedGet(); + return tx + .executeKeyRanges(ctx, query, keyspace, keyRanges, bindVars, tabletType, includedFields) + .checkedGet(); } public Cursor executeEntityIds( @@ -100,7 +106,8 @@ public Cursor executeEntityIds( Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { return tx.executeEntityIds( - ctx, query, keyspace, entityColumnName, entityKeyspaceIds, bindVars, tabletType, includedFields) + ctx, query, keyspace, entityColumnName, entityKeyspaceIds, bindVars, tabletType, + includedFields) .checkedGet(); } diff --git a/java/client/src/main/java/io/vitess/client/VTGateConn.java b/java/client/src/main/java/io/vitess/client/VTGateConn.java index 34f077944d5..6a810327701 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateConn.java +++ b/java/client/src/main/java/io/vitess/client/VTGateConn.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -24,14 +24,6 @@ import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import java.io.Closeable; -import java.io.IOException; -import java.sql.SQLDataException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; import io.vitess.client.cursor.Cursor; import io.vitess.client.cursor.CursorWithError; @@ -70,12 +62,21 @@ import io.vitess.proto.Vtgate.StreamExecuteRequest; import io.vitess.proto.Vtgate.StreamExecuteShardsRequest; +import java.io.Closeable; +import java.io.IOException; +import java.sql.SQLDataException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + /** * An asynchronous VTGate connection. * *

- * See the VitessClientExample + * See the VitessClientExample * for a usage example. * *

@@ -84,6 +85,7 @@ */ @Deprecated public final class VTGateConn implements Closeable { + private final RpcClient client; private final String keyspace; @@ -107,8 +109,8 @@ public VTGateConn(RpcClient client) { * The given {@code keyspace} will be used as the connection-wide default for {@code execute()} * and {@code streamExecute()} calls, since those do not specify the keyspace for each call. Like * the connection-wide default database of a MySQL connection, individual queries can still refer - * to other keyspaces by prefixing table names. For example: - * {@code "SELECT ... FROM keyspace.table ..."} + * to other keyspaces by prefixing table names. For example: {@code "SELECT ... FROM + * keyspace.table ..."} */ public VTGateConn(RpcClient client, String keyspace) { this.client = checkNotNull(client); @@ -116,13 +118,14 @@ public VTGateConn(RpcClient client, String keyspace) { } public SQLFuture execute(Context ctx, String query, @Nullable Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { ExecuteRequest.Builder requestBuilder = ExecuteRequest.newBuilder() - .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) - .setKeyspaceShard(keyspace) - .setTabletType(checkNotNull(tabletType)) - .setOptions(Query.ExecuteOptions.newBuilder() - .setIncludedFields(includedFields)); + .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) + .setKeyspaceShard(keyspace) + .setTabletType(checkNotNull(tabletType)) + .setOptions(Query.ExecuteOptions.newBuilder() + .setIncludedFields(includedFields)); if (ctx.getCallerId() != null) { requestBuilder.setCallerId(ctx.getCallerId()); @@ -205,7 +208,8 @@ public ListenableFuture apply(ExecuteKeyspaceIdsResponse response) public SQLFuture executeKeyRanges(Context ctx, String query, String keyspace, Iterable keyRanges, @Nullable Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { ExecuteKeyRangesRequest.Builder requestBuilder = ExecuteKeyRangesRequest.newBuilder() .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) .setKeyspace(checkNotNull(keyspace)) @@ -234,7 +238,8 @@ public ListenableFuture apply(ExecuteKeyRangesResponse response) public SQLFuture executeEntityIds(Context ctx, String query, String keyspace, String entityColumnName, Map entityKeyspaceIds, @Nullable Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { ExecuteEntityIdsRequest.Builder requestBuilder = ExecuteEntityIdsRequest.newBuilder() .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) .setKeyspace(checkNotNull(keyspace)) @@ -263,39 +268,40 @@ public ListenableFuture apply(ExecuteEntityIdsResponse response) directExecutor())); } - public SQLFuture> executeBatch(Context ctx, List queryList, - @Nullable List> bindVarsList, TabletType tabletType, - Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - return executeBatch(ctx, queryList, bindVarsList, tabletType, false, includedFields); + public SQLFuture> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, TabletType tabletType, + Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + return executeBatch(ctx, queryList, bindVarsList, tabletType, false, includedFields); + } + + public SQLFuture> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, TabletType tabletType, + boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { + List queries = new ArrayList<>(); + + if (null != bindVarsList && bindVarsList.size() != queryList.size()) { + throw new SQLDataException( + "Size of SQL Query list does not match the bind variables list"); } - public SQLFuture> executeBatch(Context ctx, List queryList, - @Nullable List> bindVarsList, TabletType tabletType, - boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { - List queries = new ArrayList<>(); - - if (null != bindVarsList && bindVarsList.size() != queryList.size()) { - throw new SQLDataException( - "Size of SQL Query list does not match the bind variables list"); - } - - for (int i = 0; i < queryList.size(); ++i) { - queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)), - bindVarsList == null ? null : bindVarsList.get(i))); - } - - Vtgate.ExecuteBatchRequest.Builder requestBuilder = - Vtgate.ExecuteBatchRequest.newBuilder() - .addAllQueries(checkNotNull(queries)) - .setKeyspaceShard(keyspace) - .setTabletType(checkNotNull(tabletType)) - .setAsTransaction(asTransaction) - .setOptions(Query.ExecuteOptions.newBuilder() - .setIncludedFields(includedFields)); - - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + for (int i = 0; i < queryList.size(); ++i) { + queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)), + bindVarsList == null ? null : bindVarsList.get(i))); + } + + Vtgate.ExecuteBatchRequest.Builder requestBuilder = + Vtgate.ExecuteBatchRequest.newBuilder() + .addAllQueries(checkNotNull(queries)) + .setKeyspaceShard(keyspace) + .setTabletType(checkNotNull(tabletType)) + .setAsTransaction(asTransaction) + .setOptions(Query.ExecuteOptions.newBuilder() + .setIncludedFields(includedFields)); + + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); + } return new SQLFuture<>( transformAsync( @@ -310,13 +316,13 @@ public ListenableFuture> apply( } }, directExecutor())); - } + } - /** + /** * Execute multiple keyspace ID queries as a batch. * - * @param asTransaction If true, automatically create a transaction (per shard) that encloses all - * the batch queries. + * @param asTransaction If true, automatically create a transaction (per shard) that encloses + * all the batch queries. */ public SQLFuture> executeBatchShards(Context ctx, Iterable queries, TabletType tabletType, boolean asTransaction, @@ -352,12 +358,13 @@ public ListenableFuture> apply(ExecuteBatchShardsResponse response) /** * Execute multiple keyspace ID queries as a batch. * - * @param asTransaction If true, automatically create a transaction (per shard) that encloses all - * the batch queries. + * @param asTransaction If true, automatically create a transaction (per shard) that encloses + * all the batch queries. */ public SQLFuture> executeBatchKeyspaceIds(Context ctx, Iterable queries, TabletType tabletType, - boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + boolean asTransaction, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { ExecuteBatchKeyspaceIdsRequest.Builder requestBuilder = ExecuteBatchKeyspaceIdsRequest.newBuilder() .addAllQueries(checkNotNull(queries)) @@ -386,7 +393,8 @@ public ListenableFuture> apply(ExecuteBatchKeyspaceIdsResponse resp } public Cursor streamExecute(Context ctx, String query, @Nullable Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { StreamExecuteRequest.Builder requestBuilder = StreamExecuteRequest.newBuilder() .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) @@ -444,7 +452,8 @@ public Cursor streamExecuteKeyspaceIds(Context ctx, String query, String keyspac public Cursor streamExecuteKeyRanges(Context ctx, String query, String keyspace, Iterable keyRanges, @Nullable Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { StreamExecuteKeyRangesRequest.Builder requestBuilder = StreamExecuteKeyRangesRequest .newBuilder() .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) diff --git a/java/client/src/main/java/io/vitess/client/VTGateConnection.java b/java/client/src/main/java/io/vitess/client/VTGateConnection.java index 485897f0da5..d22f01f5dc2 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateConnection.java +++ b/java/client/src/main/java/io/vitess/client/VTGateConnection.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -20,16 +20,6 @@ import static com.google.common.util.concurrent.Futures.transformAsync; import static com.google.common.util.concurrent.MoreExecutors.directExecutor; -import java.io.Closeable; -import java.io.IOException; -import java.sql.SQLDataException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import javax.annotation.Nullable; - import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; @@ -47,216 +37,234 @@ import io.vitess.proto.Vtgate.SplitQueryResponse; import io.vitess.proto.Vtgate.StreamExecuteRequest; +import java.io.Closeable; +import java.io.IOException; +import java.sql.SQLDataException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + /** * An asynchronous VTGate connection. *

*

All the information regarding this connection is maintained by {@code Session}, - * only one operation can be in flight at a time on a given instance. - * The methods are {@code synchronized} only because the session cookie is updated asynchronously - * when the RPC response comes back.

+ * only one operation can be in flight at a time on a given instance. The methods are {@code + * synchronized} only because the session cookie is updated asynchronously when the RPC response + * comes back.

*

*

After calling any method that returns a {@link SQLFuture}, you must wait for that future to - * complete before calling any other methods on that {@code VTGateConnection} instance. - * An {@link IllegalStateException} will be thrown if this constraint is violated.

+ * complete before calling any other methods on that {@code VTGateConnection} instance. An {@link + * IllegalStateException} will be thrown if this constraint is violated.

*

- *

All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link VTGateBlockingConnection} if - * you want synchronous calls.

+ *

All non-streaming calls on {@code VTGateConnection} are asynchronous. Use {@link + * VTGateBlockingConnection} if you want synchronous calls.

*/ public class VTGateConnection implements Closeable { - private final RpcClient client; - /** - * Creates a VTGate connection with no specific parameters. - *

- *

In this mode, VTGate will use VSchema to resolve the keyspace for any unprefixed - * table names. Note that this only works if the table name is unique across all keyspaces.

- * - * @param client RPC connection - */ - public VTGateConnection(RpcClient client) { - this.client = checkNotNull(client); - } + private final RpcClient client; - /** - * This method calls the VTGate to execute the query. - * - * @param ctx Context on user and execution deadline if any. - * @param query Sql Query to be executed. - * @param bindVars Parameters to bind with sql. - * @param vtSession Session to be used with the call. - * @return SQL Future Cursor - * @throws SQLException If anything fails on query execution. - */ - public SQLFuture execute(Context ctx, String query, @Nullable Map bindVars, final VTSession vtSession) throws SQLException { - synchronized (this) { - vtSession.checkCallIsAllowed("execute"); - ExecuteRequest.Builder requestBuilder = ExecuteRequest.newBuilder() - .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) - .setSession(vtSession.getSession()); + /** + * Creates a VTGate connection with no specific parameters. + *

+ *

In this mode, VTGate will use VSchema to resolve the keyspace for any unprefixed + * table names. Note that this only works if the table name is unique across all keyspaces.

+ * + * @param client RPC connection + */ + public VTGateConnection(RpcClient client) { + this.client = checkNotNull(client); + } - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + /** + * This method calls the VTGate to execute the query. + * + * @param ctx Context on user and execution deadline if any. + * @param query Sql Query to be executed. + * @param bindVars Parameters to bind with sql. + * @param vtSession Session to be used with the call. + * @return SQL Future Cursor + * @throws SQLException If anything fails on query execution. + */ + public SQLFuture execute(Context ctx, String query, @Nullable Map bindVars, + final VTSession vtSession) throws SQLException { + synchronized (this) { + vtSession.checkCallIsAllowed("execute"); + ExecuteRequest.Builder requestBuilder = ExecuteRequest.newBuilder() + .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) + .setSession(vtSession.getSession()); - SQLFuture call = new SQLFuture<>( - transformAsync(client.execute(ctx, requestBuilder.build()), - new AsyncFunction() { - @Override - public ListenableFuture apply(ExecuteResponse response) throws Exception { - vtSession.setSession(response.getSession()); - Proto.checkError(response.getError()); - return Futures.immediateFuture(new SimpleCursor(response.getResult())); - } - }, directExecutor())); - vtSession.setLastCall(call); - return call; - } - } + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); + } - /** - * This method calls the VTGate to execute list of queries as a batch. - * - * @param ctx Context on user and execution deadline if any. - * @param queryList List of sql queries to be executed. - * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. - * If provided, should match the number of sql queries.

- * @param vtSession Session to be used with the call. - * @return SQL Future with List of Cursors - * @throws SQLException If anything fails on query execution. - */ - public SQLFuture> executeBatch(Context ctx, List queryList, @Nullable List> bindVarsList, final VTSession vtSession) throws SQLException { - return executeBatch(ctx, queryList, bindVarsList, false, vtSession); + SQLFuture call = new SQLFuture<>( + transformAsync(client.execute(ctx, requestBuilder.build()), + new AsyncFunction() { + @Override + public ListenableFuture apply(ExecuteResponse response) throws Exception { + vtSession.setSession(response.getSession()); + Proto.checkError(response.getError()); + return Futures.immediateFuture(new SimpleCursor(response.getResult())); + } + }, directExecutor())); + vtSession.setLastCall(call); + return call; } + } - /** - * This method calls the VTGate to execute list of queries as a batch. - *

- *

If asTransaction is set to true then query execution will not change the session cookie. - * Otherwise, query execution will become part of the session.

- * - * @param ctx Context on user and execution deadline if any. - * @param queryList List of sql queries to be executed. - * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. - * If provided, should match the number of sql queries.

- * @param asTransaction To execute query without impacting session cookie. - * @param vtSession Session to be used with the call. - * @return SQL Future with List of Cursors - * @throws SQLException If anything fails on query execution. - */ - public SQLFuture> executeBatch(Context ctx, List queryList, @Nullable List> bindVarsList, boolean asTransaction, final VTSession vtSession) throws SQLException { - synchronized (this) { - vtSession.checkCallIsAllowed("executeBatch"); - List queries = new ArrayList<>(); + /** + * This method calls the VTGate to execute list of queries as a batch. + * + * @param ctx Context on user and execution deadline if any. + * @param queryList List of sql queries to be executed. + * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. If + * provided, should match the number of sql queries.

+ * @param vtSession Session to be used with the call. + * @return SQL Future with List of Cursors + * @throws SQLException If anything fails on query execution. + */ + public SQLFuture> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, final VTSession vtSession) throws SQLException { + return executeBatch(ctx, queryList, bindVarsList, false, vtSession); + } - if (null != bindVarsList && bindVarsList.size() != queryList.size()) { - throw new SQLDataException( - "Size of SQL Query list does not match the bind variables list"); - } + /** + * This method calls the VTGate to execute list of queries as a batch. + *

+ *

If asTransaction is set to true then query execution will not change the + * session cookie. Otherwise, query execution will become part of the session.

+ * + * @param ctx Context on user and execution deadline if any. + * @param queryList List of sql queries to be executed. + * @param bindVarsList

For each sql query it will provide a list of parameters to bind with. If + * provided, should match the number of sql queries.

+ * @param asTransaction To execute query without impacting session cookie. + * @param vtSession Session to be used with the call. + * @return SQL Future with List of Cursors + * @throws SQLException If anything fails on query execution. + */ + public SQLFuture> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, boolean asTransaction, final VTSession vtSession) + throws SQLException { + synchronized (this) { + vtSession.checkCallIsAllowed("executeBatch"); + List queries = new ArrayList<>(); - for (int i = 0; i < queryList.size(); ++i) { - queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)), - bindVarsList == null ? null : bindVarsList.get(i))); - } + if (null != bindVarsList && bindVarsList.size() != queryList.size()) { + throw new SQLDataException( + "Size of SQL Query list does not match the bind variables list"); + } - Vtgate.ExecuteBatchRequest.Builder requestBuilder = - Vtgate.ExecuteBatchRequest.newBuilder() - .addAllQueries(checkNotNull(queries)) - .setSession(vtSession.getSession()) - .setAsTransaction(asTransaction); + for (int i = 0; i < queryList.size(); ++i) { + queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)), + bindVarsList == null ? null : bindVarsList.get(i))); + } - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + Vtgate.ExecuteBatchRequest.Builder requestBuilder = + Vtgate.ExecuteBatchRequest.newBuilder() + .addAllQueries(checkNotNull(queries)) + .setSession(vtSession.getSession()) + .setAsTransaction(asTransaction); - SQLFuture> call = new SQLFuture<>( - transformAsync(client.executeBatch(ctx, requestBuilder.build()), - new AsyncFunction>() { - @Override - public ListenableFuture> apply(Vtgate.ExecuteBatchResponse response) throws Exception { - vtSession.setSession(response.getSession()); - Proto.checkError(response.getError()); - return Futures.immediateFuture( - Proto.fromQueryResponsesToCursorList(response.getResultsList())); - } - }, directExecutor())); - vtSession.setLastCall(call); - return call; - } - } + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); + } - /** - * - * @param ctx Context on user and execution deadline if any. - * @param query Sql Query to be executed. - * @param bindVars Parameters to bind with sql. - * @param vtSession Session to be used with the call. - * @return - * @throws SQLException - */ - public Cursor streamExecute(Context ctx, String query, @Nullable Map bindVars, VTSession vtSession) throws SQLException { - StreamExecuteRequest.Builder requestBuilder = - StreamExecuteRequest.newBuilder() - .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) - .setSession(vtSession.getSession()); + SQLFuture> call = new SQLFuture<>( + transformAsync(client.executeBatch(ctx, requestBuilder.build()), + new AsyncFunction>() { + @Override + public ListenableFuture> apply( + Vtgate.ExecuteBatchResponse response) throws Exception { + vtSession.setSession(response.getSession()); + Proto.checkError(response.getError()); + return Futures.immediateFuture( + Proto.fromQueryResponsesToCursorList(response.getResultsList())); + } + }, directExecutor())); + vtSession.setLastCall(call); + return call; + } + } - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + /** + * @param ctx Context on user and execution deadline if any. + * @param query Sql Query to be executed. + * @param bindVars Parameters to bind with sql. + * @param vtSession Session to be used with the call. + */ + public Cursor streamExecute(Context ctx, String query, @Nullable Map bindVars, + VTSession vtSession) throws SQLException { + StreamExecuteRequest.Builder requestBuilder = + StreamExecuteRequest.newBuilder() + .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) + .setSession(vtSession.getSession()); - return new StreamCursor(client.streamExecute(ctx, requestBuilder.build())); + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); } - /** - * This method splits the query into small parts based on the splitColumn and Algorithm type provided. - * - * @param ctx Context on user and execution deadline if any. - * @param keyspace Keyspace to execute the query on. - * @param query Sql Query to be executed. - * @param bindVars Parameters to bind with sql. - * @param splitColumns Column to be used to split the data. - * @param splitCount Number of Partitions - * @param numRowsPerQueryPart Limit the number of records per query part. - * @param algorithm EQUAL_SPLITS or FULL_SCAN - * @return SQL Future with Query Parts - * @throws SQLException If anything fails on query execution. - */ - public SQLFuture> splitQuery(Context ctx, String keyspace, String query, @Nullable Map bindVars, Iterable splitColumns, - int splitCount, int numRowsPerQueryPart, Algorithm algorithm) throws SQLException { - SplitQueryRequest.Builder requestBuilder = - SplitQueryRequest.newBuilder() - .setKeyspace(checkNotNull(keyspace)) - .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) - .addAllSplitColumn(splitColumns) - .setSplitCount(splitCount) - .setNumRowsPerQueryPart(numRowsPerQueryPart) - .setAlgorithm(algorithm); - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + return new StreamCursor(client.streamExecute(ctx, requestBuilder.build())); + } - return new SQLFuture<>( - transformAsync(client.splitQuery(ctx, requestBuilder.build()), - new AsyncFunction>() { - @Override - public ListenableFuture> apply(SplitQueryResponse response) throws Exception { - return Futures.immediateFuture(response.getSplitsList()); - } - }, directExecutor())); - } + /** + * This method splits the query into small parts based on the splitColumn and Algorithm type + * provided. + * + * @param ctx Context on user and execution deadline if any. + * @param keyspace Keyspace to execute the query on. + * @param query Sql Query to be executed. + * @param bindVars Parameters to bind with sql. + * @param splitColumns Column to be used to split the data. + * @param splitCount Number of Partitions + * @param numRowsPerQueryPart Limit the number of records per query part. + * @param algorithm EQUAL_SPLITS or FULL_SCAN + * @return SQL Future with Query Parts + * @throws SQLException If anything fails on query execution. + */ + public SQLFuture> splitQuery(Context ctx, String keyspace, + String query, @Nullable Map bindVars, Iterable splitColumns, + int splitCount, int numRowsPerQueryPart, Algorithm algorithm) throws SQLException { + SplitQueryRequest.Builder requestBuilder = + SplitQueryRequest.newBuilder() + .setKeyspace(checkNotNull(keyspace)) + .setQuery(Proto.bindQuery(checkNotNull(query), bindVars)) + .addAllSplitColumn(splitColumns) + .setSplitCount(splitCount) + .setNumRowsPerQueryPart(numRowsPerQueryPart) + .setAlgorithm(algorithm); - /** - * @inheritDoc - */ - @Override - public void close() throws IOException { - client.close(); + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); } - @Override - public String toString() { - return String.format("[VTGateConnection-%s client=%s]", - Integer.toHexString(this.hashCode()), - client.toString() - ); - } + return new SQLFuture<>( + transformAsync(client.splitQuery(ctx, requestBuilder.build()), + new AsyncFunction>() { + @Override + public ListenableFuture> apply( + SplitQueryResponse response) throws Exception { + return Futures.immediateFuture(response.getSplitsList()); + } + }, directExecutor())); + } + + /** + * @inheritDoc + */ + @Override + public void close() throws IOException { + client.close(); + } + + @Override + public String toString() { + return String.format("[VTGateConnection-%s client=%s]", + Integer.toHexString(this.hashCode()), + client.toString() + ); + } } diff --git a/java/client/src/main/java/io/vitess/client/VTGateTx.java b/java/client/src/main/java/io/vitess/client/VTGateTx.java index 4e330790383..4028bde21fa 100644 --- a/java/client/src/main/java/io/vitess/client/VTGateTx.java +++ b/java/client/src/main/java/io/vitess/client/VTGateTx.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -24,12 +24,6 @@ import com.google.common.util.concurrent.AsyncFunction; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; -import java.sql.SQLDataException; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import javax.annotation.Nullable; import io.vitess.client.cursor.Cursor; import io.vitess.client.cursor.CursorWithError; @@ -60,6 +54,14 @@ import io.vitess.proto.Vtgate.RollbackResponse; import io.vitess.proto.Vtgate.Session; +import java.sql.SQLDataException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; + /** * An asynchronous VTGate transaction session. * @@ -82,6 +84,7 @@ */ @Deprecated public class VTGateTx { + private final RpcClient client; private final String keyspace; private Session session; @@ -94,7 +97,8 @@ public class VTGateTx { } public synchronized SQLFuture execute(Context ctx, String query, Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { checkCallIsAllowed("execute"); ExecuteRequest.Builder requestBuilder = ExecuteRequest.newBuilder() @@ -235,7 +239,8 @@ public ListenableFuture apply(ExecuteKeyRangesResponse response) public synchronized SQLFuture executeEntityIds(Context ctx, String query, String keyspace, String entityColumnName, Map entityKeyspaceIds, Map bindVars, - TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) throws SQLException { + TabletType tabletType, Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { checkCallIsAllowed("executeEntityIds"); ExecuteEntityIdsRequest.Builder requestBuilder = ExecuteEntityIdsRequest.newBuilder() .setQuery(Proto.bindQuery(query, bindVars)) @@ -270,34 +275,34 @@ public ListenableFuture apply(ExecuteEntityIdsResponse response) return call; } - public SQLFuture> executeBatch(Context ctx, List queryList, - @Nullable List> bindVarsList, TabletType tabletType, - Query.ExecuteOptions.IncludedFields includedFields) - throws SQLException { - List queries = new ArrayList<>(); - - if (null != bindVarsList && bindVarsList.size() != queryList.size()) { - throw new SQLDataException( - "Size of SQL Query list does not match the bind variables list"); - } - - for (int i = 0; i < queryList.size(); ++i) { - queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)), - bindVarsList == null ? null : bindVarsList.get(i))); - } - - Vtgate.ExecuteBatchRequest.Builder requestBuilder = - Vtgate.ExecuteBatchRequest.newBuilder() - .addAllQueries(checkNotNull(queries)) - .setKeyspaceShard(keyspace) - .setTabletType(checkNotNull(tabletType)) - .setSession(session) - .setOptions(Query.ExecuteOptions.newBuilder() - .setIncludedFields(includedFields)); - - if (ctx.getCallerId() != null) { - requestBuilder.setCallerId(ctx.getCallerId()); - } + public SQLFuture> executeBatch(Context ctx, List queryList, + @Nullable List> bindVarsList, TabletType tabletType, + Query.ExecuteOptions.IncludedFields includedFields) + throws SQLException { + List queries = new ArrayList<>(); + + if (null != bindVarsList && bindVarsList.size() != queryList.size()) { + throw new SQLDataException( + "Size of SQL Query list does not match the bind variables list"); + } + + for (int i = 0; i < queryList.size(); ++i) { + queries.add(i, Proto.bindQuery(checkNotNull(queryList.get(i)), + bindVarsList == null ? null : bindVarsList.get(i))); + } + + Vtgate.ExecuteBatchRequest.Builder requestBuilder = + Vtgate.ExecuteBatchRequest.newBuilder() + .addAllQueries(checkNotNull(queries)) + .setKeyspaceShard(keyspace) + .setTabletType(checkNotNull(tabletType)) + .setSession(session) + .setOptions(Query.ExecuteOptions.newBuilder() + .setIncludedFields(includedFields)); + + if (ctx.getCallerId() != null) { + requestBuilder.setCallerId(ctx.getCallerId()); + } return new SQLFuture<>( transformAsync( @@ -313,7 +318,7 @@ public ListenableFuture> apply( } }, directExecutor())); - } + } public synchronized SQLFuture> executeBatchShards(Context ctx, Iterable queries, TabletType tabletType, @@ -384,14 +389,14 @@ public ListenableFuture> apply( return call; } - public synchronized SQLFuture commit(Context ctx) throws SQLException { - return commit(ctx, false); - } + public synchronized SQLFuture commit(Context ctx) throws SQLException { + return commit(ctx, false); + } public synchronized SQLFuture commit(Context ctx, boolean atomic) throws SQLException { checkCallIsAllowed("commit"); CommitRequest.Builder requestBuilder = CommitRequest.newBuilder().setSession(session) - .setAtomic(atomic); + .setAtomic(atomic); if (ctx.getCallerId() != null) { requestBuilder.setCallerId(ctx.getCallerId()); } diff --git a/java/client/src/main/java/io/vitess/client/VTSession.java b/java/client/src/main/java/io/vitess/client/VTSession.java index d4d724cae16..69978a12db5 100644 --- a/java/client/src/main/java/io/vitess/client/VTSession.java +++ b/java/client/src/main/java/io/vitess/client/VTSession.java @@ -21,119 +21,122 @@ /** * A persistence session state for each connection. - * */ public class VTSession { - private Vtgate.Session session; - private SQLFuture lastCall; - /** - * Create session cookie. - * - * @param target In the format keyspace@shard:tabletType. Only provide the part what needs to be set. - * @param options Additional parameters to be passed along the query to the underlying database engine. - */ - public VTSession(String target, Query.ExecuteOptions options) { - this.session = Vtgate.Session.newBuilder() - .setTargetString(null == target ? "" : target) - .setOptions(null == options ? Query.ExecuteOptions.newBuilder().build() : options) - .setAutocommit(true) - .setInTransaction(false) - .build(); - } + private Vtgate.Session session; + private SQLFuture lastCall; - /** - * Returns the persistent session cookie. - * - * @return Session - */ - public Vtgate.Session getSession() { - return this.session; - } + /** + * Create session cookie. + * + * @param target In the format keyspace@shard:tabletType. Only provide the part what needs to + * be set. + * @param options Additional parameters to be passed along the query to the underlying + * database engine. + */ + public VTSession(String target, Query.ExecuteOptions options) { + this.session = Vtgate.Session.newBuilder() + .setTargetString(null == target ? "" : target) + .setOptions(null == options ? Query.ExecuteOptions.newBuilder().build() : options) + .setAutocommit(true) + .setInTransaction(false) + .build(); + } - /** - * This method set the session cookie returned from VTGate. - *

- *

This method is not synchronized as the callee function is synchronized.

- * - * @param session Updated globalSession to be set. - */ - public void setSession(Vtgate.Session session) { - this.session = session; - } + /** + * Returns the persistent session cookie. + * + * @return Session + */ + public Vtgate.Session getSession() { + return this.session; + } - /** - * Returns the current state of commit mode. - * - * @return autocommit state - */ - public boolean isAutoCommit() { - return this.session.getAutocommit(); - } + /** + * This method set the session cookie returned from VTGate. + *

+ *

This method is not synchronized as the callee function is synchronized.

+ * + * @param session Updated globalSession to be set. + */ + public void setSession(Vtgate.Session session) { + this.session = session; + } - /** - * Set the auto commit state. - * - * @param autoCommit true or false - */ - public void setAutoCommit(boolean autoCommit) { - this.session = this.session.toBuilder().setAutocommit(autoCommit).build(); - } + /** + * Returns the current state of commit mode. + * + * @return autocommit state + */ + public boolean isAutoCommit() { + return this.session.getAutocommit(); + } - /** - * Returns whether session is maintaining any transaction or not. - * - * @return true or false based on if session cookie is maintaining any transaction. - */ - public boolean isInTransaction() { - return this.session.getShardSessionsCount() > 0; - } + /** + * Set the auto commit state. + * + * @param autoCommit true or false + */ + public void setAutoCommit(boolean autoCommit) { + this.session = this.session.toBuilder().setAutocommit(autoCommit).build(); + } - /** - * Returns this session's transaction isolation level. - * - * @return Transaction Isolation Level of the Session - */ - public Query.ExecuteOptions.TransactionIsolation getTransactionIsolation() { - return this.session.getOptions().getTransactionIsolation(); - } + /** + * Returns whether session is maintaining any transaction or not. + * + * @return true or false based on if session cookie is maintaining any transaction. + */ + public boolean isInTransaction() { + return this.session.getShardSessionsCount() > 0; + } - /** - * Sets this session's transaction isolation level. - * - * @param Transaction Isolation Level of the Session - */ - public void setTransactionIsolation(Query.ExecuteOptions.TransactionIsolation isolation) { - this.session = this.session.toBuilder() - .setOptions(this.session.getOptions().toBuilder() - .setTransactionIsolation(isolation)).build(); - } + /** + * Returns this session's transaction isolation level. + * + * @return Transaction Isolation Level of the Session + */ + public Query.ExecuteOptions.TransactionIsolation getTransactionIsolation() { + return this.session.getOptions().getTransactionIsolation(); + } - /** - * Set the last SQLFuture call made on this session. - * - * @param call - SQLFuture - */ - public void setLastCall(SQLFuture call) { - this.lastCall = call; - } + /** + * Sets this session's transaction isolation level. + * + * @param Transaction Isolation Level of the Session + */ + public void setTransactionIsolation(Query.ExecuteOptions.TransactionIsolation isolation) { + this.session = this.session.toBuilder() + .setOptions(this.session.getOptions().toBuilder() + .setTransactionIsolation(isolation)).build(); + } + + /** + * Set the last SQLFuture call made on this session. + * + * @param call - SQLFuture + */ + public void setLastCall(SQLFuture call) { + this.lastCall = call; + } - /** - * This method checks if the last SQLFuture call is complete or not. - *

- *

This should be called only in the start of the function - * where we modify the session cookie after the response from VTGate. - * This is to protect any possible loss of session modification like shard transaction.

- * - * @param call - The represents the callee function name. - * @throws IllegalStateException - Throws IllegalStateException if lastCall has not completed. - */ - public void checkCallIsAllowed(String call) throws IllegalStateException { - // Calls are not allowed to overlap. - if (lastCall != null && !lastCall.isDone()) { - throw new IllegalStateException("Can't call " + call - + "() until the last asynchronous call is done on this transaction."); - } + /** + * This method checks if the last SQLFuture call is complete or not. + *

+ *

This should be called only in the start of the function + * where we modify the session cookie after the response from VTGate. This is to protect any + * possible loss of session modification like shard transaction.

+ * + * @param call - The represents the callee function name. + * @throws IllegalStateException - Throws IllegalStateException if lastCall has not + * completed. + */ + public void checkCallIsAllowed(String call) throws IllegalStateException { + // Calls are not allowed to overlap. + if (lastCall != null && !lastCall.isDone()) { + throw new IllegalStateException("Can't call " + call + + "() until the last asynchronous call is done on this transaction."); } + } } diff --git a/java/client/src/main/java/io/vitess/client/cursor/Cursor.java b/java/client/src/main/java/io/vitess/client/cursor/Cursor.java index d7f479bb21c..f810bf99fd6 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/Cursor.java +++ b/java/client/src/main/java/io/vitess/client/cursor/Cursor.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -18,23 +18,23 @@ import static com.google.common.base.Preconditions.checkNotNull; +import io.vitess.proto.Query.Field; +import io.vitess.proto.Query.QueryResult; + import java.sql.SQLDataException; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.List; + import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.QueryResult; - /** * Provides access to the result rows of a query. * *

{@code Cursor} wraps an underlying Vitess {@link QueryResult} object, converting column - * values from the raw result values to Java types. In the case of streaming queries, the - * {@link StreamCursor} implementation will also fetch more {@code QueryResult} objects as - * necessary. + * values from the raw result values to Java types. In the case of streaming queries, the {@link + * StreamCursor} implementation will also fetch more {@code QueryResult} objects as necessary. * *

Similar to {@link java.sql.ResultSet}, a {@code Cursor} is initially positioned before the * first row, and the first call to {@link #next()} moves to the first row. The getter methods @@ -42,19 +42,19 @@ * should be called to free resources when done, regardless of whether all the rows were processed. * *

Each individual {@code Cursor} is not thread-safe; it must be protected if used concurrently. - * However, two cursors from the same {@link io.vitess.client.VTGateConn VTGateConn} can be - * accessed concurrently without additional synchronization. + * However, two cursors from the same {@link io.vitess.client.VTGateConn VTGateConn} can be accessed + * concurrently without additional synchronization. */ @NotThreadSafe public abstract class Cursor implements AutoCloseable { + /** * A pre-built {@link FieldMap}, shared by each {@link Row}. * *

Although {@link Cursor} is not supposed to be used by multiple threads, - * the asynchronous API makes it unavoidable that a {@code Cursor} may be created - * in one thread and then sent to another. We therefore declare {@code fieldMap} - * as {@code volatile} to guarantee the value set by the constructor is seen by - * all threads. + * the asynchronous API makes it unavoidable that a {@code Cursor} may be created in one thread + * and then sent to another. We therefore declare {@code fieldMap} as {@code volatile} to + * guarantee the value set by the constructor is seen by all threads. */ private volatile FieldMap fieldMap; diff --git a/java/client/src/main/java/io/vitess/client/cursor/CursorWithError.java b/java/client/src/main/java/io/vitess/client/cursor/CursorWithError.java index 3fe52c451c6..4051a0f7a79 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/CursorWithError.java +++ b/java/client/src/main/java/io/vitess/client/cursor/CursorWithError.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -24,25 +24,25 @@ */ public class CursorWithError { - private final Cursor cursor; - private final Vtrpc.RPCError error; + private final Cursor cursor; + private final Vtrpc.RPCError error; - public CursorWithError(Query.ResultWithError resultWithError) { - if (!resultWithError.hasError() || - Vtrpc.Code.OK == resultWithError.getError().getCode()) { - this.cursor = new SimpleCursor(resultWithError.getResult()); - this.error = null; - } else { - this.cursor = null; - this.error = resultWithError.getError(); - } + public CursorWithError(Query.ResultWithError resultWithError) { + if (!resultWithError.hasError() + || Vtrpc.Code.OK == resultWithError.getError().getCode()) { + this.cursor = new SimpleCursor(resultWithError.getResult()); + this.error = null; + } else { + this.cursor = null; + this.error = resultWithError.getError(); } + } - public Cursor getCursor() { - return cursor; - } + public Cursor getCursor() { + return cursor; + } - public Vtrpc.RPCError getError() { - return error; - } + public Vtrpc.RPCError getError() { + return error; + } } diff --git a/java/client/src/main/java/io/vitess/client/cursor/FieldMap.java b/java/client/src/main/java/io/vitess/client/cursor/FieldMap.java index 3826d0782a7..d34c13ab623 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/FieldMap.java +++ b/java/client/src/main/java/io/vitess/client/cursor/FieldMap.java @@ -20,11 +20,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableList; + import io.vitess.proto.Query.Field; + +import org.apache.commons.collections4.map.CaseInsensitiveMap; + import java.util.List; import java.util.Map; + import javax.annotation.Nullable; -import org.apache.commons.collections4.map.CaseInsensitiveMap; /** @@ -37,6 +41,7 @@ * index is also used to find the value in a separate list. */ public class FieldMap { + private final List fields; private final Map labelMap; private final Map nameMap; diff --git a/java/client/src/main/java/io/vitess/client/cursor/Row.java b/java/client/src/main/java/io/vitess/client/cursor/Row.java index 20c079cbefc..b232fb6d8aa 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/Row.java +++ b/java/client/src/main/java/io/vitess/client/cursor/Row.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -21,6 +21,12 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; + +import io.vitess.mysql.DateTime; +import io.vitess.proto.Query; +import io.vitess.proto.Query.Field; +import io.vitess.proto.Query.Type; + import java.io.InputStream; import java.math.BigDecimal; import java.math.BigInteger; @@ -33,29 +39,26 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.List; -import javax.annotation.concurrent.NotThreadSafe; -import io.vitess.mysql.DateTime; -import io.vitess.proto.Query; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.Type; +import javax.annotation.concurrent.NotThreadSafe; /** * Type-converting wrapper around raw {@link io.vitess.proto.Query.Row} proto. * *

- * Usually you get Row objects from a {@link Cursor}, which builds them by combining - * {@link io.vitess.proto.Query.Row} with the list of {@link Field}s from the corresponding - * {@link io.vitess.proto.Query.QueryResult}. + * Usually you get Row objects from a {@link Cursor}, which builds them by combining {@link + * io.vitess.proto.Query.Row} with the list of {@link Field}s from the corresponding {@link + * io.vitess.proto.Query.QueryResult}. * *

* Methods on {@code Row} are intended to be compatible with those on {@link java.sql.ResultSet} - * where possible. This means {@code columnIndex} values start at 1 for the first column, and - * {@code columnLabel} values are case-insensitive. If multiple columns have the same - * case-insensitive {@code columnLabel}, the earliest one will be returned. + * where possible. This means {@code columnIndex} values start at 1 for the first column, and {@code + * columnLabel} values are case-insensitive. If multiple columns have the same case-insensitive + * {@code columnLabel}, the earliest one will be returned. */ @NotThreadSafe public class Row { + private final FieldMap fieldMap; private final List values; private final Query.Row rawRow; @@ -70,8 +73,8 @@ public class Row { private volatile boolean lastGetWasNull; /** - * Construct a Row from {@link io.vitess.proto.Query.Row} proto with a pre-built - * {@link FieldMap}. + * Construct a Row from {@link io.vitess.proto.Query.Row} proto with a pre-built {@link + * FieldMap}. * *

* {@link Cursor} uses this to share a {@link FieldMap} among multiple rows. @@ -95,9 +98,9 @@ public Row(List fields, Query.Row rawRow) { * Construct a Row manually (not from proto). * *

- * The primary purpose of this Row class is to wrap the {@link io.vitess.proto.Query.Row} - * proto, which stores values in a packed format. However, when writing tests you may want to - * create a Row from unpacked data. + * The primary purpose of this Row class is to wrap the {@link io.vitess.proto.Query.Row} proto, + * which stores values in a packed format. However, when writing tests you may want to create a + * Row from unpacked data. * *

* Note that {@link #getRowProto()} will return null in this case, so a Row created in this way @@ -110,6 +113,102 @@ public Row(List fields, List values) { this.values = values; } + private static Object convertFieldValue(Field field, ByteString value) throws SQLException { + // Note: We don't actually know the charset in which the value is encoded. + // For dates and numeric values, we just assume UTF-8 because they (hopefully) don't contain + // anything outside 7-bit ASCII, which (hopefully) is a subset of the actual charset. + // For strings, we return byte[] and the application is responsible for using the right charset. + switch (field.getType()) { + case DECIMAL: + return new BigDecimal(value.toStringUtf8()); + case INT8: // fall through + case UINT8: // fall through + case INT16: // fall through + case UINT16: // fall through + case INT24: // fall through + case UINT24: // fall through + case INT32: + return Integer.valueOf(value.toStringUtf8()); + case UINT32: // fall through + case INT64: + return Long.valueOf(value.toStringUtf8()); + case UINT64: + return new BigInteger(value.toStringUtf8()); + case FLOAT32: + return Float.valueOf(value.toStringUtf8()); + case FLOAT64: + return Double.valueOf(value.toStringUtf8()); + case NULL_TYPE: + return null; + case DATE: + // We don't get time zone information from the server, + // so we use the default time zone. + try { + return DateTime.parseDate(value.toStringUtf8()); + } catch (ParseException exc) { + throw new SQLDataException("Can't parse DATE: " + value.toStringUtf8(), exc); + } + case TIME: + // We don't get time zone information from the server, + // so we use the default time zone. + try { + return DateTime.parseTime(value.toStringUtf8()); + } catch (ParseException exc) { + throw new SQLDataException("Can't parse TIME: " + value.toStringUtf8(), exc); + } + case DATETIME: // fall through + case TIMESTAMP: + // We don't get time zone information from the server, + // so we use the default time zone. + try { + return DateTime.parseTimestamp(value.toStringUtf8()); + } catch (ParseException exc) { + throw new SQLDataException("Can't parse TIMESTAMP: " + value.toStringUtf8(), exc); + } + case YEAR: + return Short.valueOf(value.toStringUtf8()); + case ENUM: // fall through + case SET: + return value.toStringUtf8(); + case BIT: // fall through + case TEXT: // fall through + case BLOB: // fall through + case VARCHAR: // fall through + case VARBINARY: // fall through + case CHAR: // fall through + case BINARY: + case GEOMETRY: + case JSON: + return value.toByteArray(); + default: + throw new SQLDataException("unknown field type: " + field.getType()); + } + } + + /** + * Extract cell values from the single-buffer wire format. + * + *

+ * See the docs for the {@code Row} message in {@code query.proto}. + */ + private static List extractValues(List lengths, ByteString buf) { + List list = new ArrayList(lengths.size()); + + int start = 0; + for (long len : lengths) { + if (len < 0) { + // This indicates a MySQL NULL value, to distinguish it from a zero-length string. + list.add((ByteString) null); + } else { + // Lengths are returned as long, but ByteString.substring() only supports int. + list.add(buf.substring(start, start + (int) len)); + start += len; + } + } + + return list; + } + /** * Returns the number of columns. */ @@ -212,8 +311,8 @@ public InputStream getBinaryInputStream(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(String,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link + * #getObject(String, Class)}. * * @param columnLabel case-insensitive column label */ @@ -225,8 +324,8 @@ public int getInt(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(int,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int, + * Class)}. * * @param columnIndex 1-based column number (0 is invalid) */ @@ -246,8 +345,8 @@ public UnsignedLong getULong(String columnLabel) throws SQLException { * @param columnIndex 1-based column number (0 is invalid) */ public UnsignedLong getULong(int columnIndex) throws SQLException { - BigInteger l = getObject(columnIndex, BigInteger.class); - return l == null ? null : UnsignedLong.fromLongBits(l.longValue()); + BigInteger longValue = getObject(columnIndex, BigInteger.class); + return longValue == null ? null : UnsignedLong.fromLongBits(longValue.longValue()); } /** @@ -268,8 +367,8 @@ public String getString(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(String,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link + * #getObject(String, Class)}. * * @param columnLabel case-insensitive column label */ @@ -281,8 +380,8 @@ public long getLong(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(int,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int, + * Class)}. * * @param columnIndex 1-based column number (0 is invalid) */ @@ -295,8 +394,8 @@ public long getLong(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(String,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link + * #getObject(String, Class)}. * * @param columnLabel case-insensitive column label */ @@ -308,8 +407,8 @@ public double getDouble(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(int,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int, + * Class)}. * * @param columnIndex 1-based column number (0 is invalid) */ @@ -322,8 +421,8 @@ public double getDouble(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(String,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link + * #getObject(String, Class)}. * * @param columnLabel case-insensitive column label */ @@ -335,8 +434,8 @@ public float getFloat(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(int,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int, + * Class)}. * * @param columnIndex 1-based column number (0 is invalid) */ @@ -389,8 +488,8 @@ public Date getDate(int columnIndex, Calendar cal) throws SQLException { } try { return DateTime.parseDate(rawValue.toStringUtf8(), cal); - } catch (ParseException e) { - throw new SQLDataException("Can't parse DATE: " + rawValue.toStringUtf8(), e); + } catch (ParseException exc) { + throw new SQLDataException("Can't parse DATE: " + rawValue.toStringUtf8(), exc); } } @@ -438,8 +537,8 @@ public Time getTime(int columnIndex, Calendar cal) throws SQLException { } try { return DateTime.parseTime(rawValue.toStringUtf8(), cal); - } catch (ParseException e) { - throw new SQLDataException("Can't parse TIME: " + rawValue.toStringUtf8(), e); + } catch (ParseException exc) { + throw new SQLDataException("Can't parse TIME: " + rawValue.toStringUtf8(), exc); } } @@ -487,8 +586,8 @@ public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException } try { return DateTime.parseTimestamp(rawValue.toStringUtf8(), cal); - } catch (ParseException e) { - throw new SQLDataException("Can't parse TIMESTAMP: " + rawValue.toStringUtf8(), e); + } catch (ParseException exc) { + throw new SQLDataException("Can't parse TIMESTAMP: " + rawValue.toStringUtf8(), exc); } } @@ -524,8 +623,8 @@ public BigDecimal getBigDecimal(int columnIndex) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(String,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link + * #getObject(String, Class)}. * * @param columnLabel case-insensitive column label */ @@ -537,8 +636,8 @@ public short getShort(String columnLabel) throws SQLException { * Returns the column value, or 0 if the value is SQL NULL. * *

- * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or - * {@link #getObject(int,Class)}. + * To distinguish between 0 and SQL NULL, use either {@link #wasNull()} or {@link #getObject(int, + * Class)}. * * @param columnIndex 1-based column number (0 is invalid) */ @@ -570,12 +669,15 @@ public short getShort(int columnIndex) throws SQLException { */ @SuppressWarnings("unchecked") // by runtime check public T getObject(int columnIndex, Class type) throws SQLException { - Object o = getObject(columnIndex); - if (o != null && !type.isInstance(o)) { + Object object = getObject(columnIndex); + if (object != null && !type.isInstance(object)) { throw new SQLDataException( - "type mismatch, expected: " + type.getName() + ", actual: " + o.getClass().getName()); + "type mismatch, expected: " + + type.getName() + + ", actual: " + + object.getClass().getName()); } - return (T) o; + return (T) object; } /** @@ -617,11 +719,9 @@ public T getObject(String columnLabel, Class type) throws SQLException { * {@code wasNull()}. * *

- * As an alternative to {@code wasNull()}, you can use {@link #getObject(int,Class)} (e.g. - * {@code getObject(0, Long.class)} instead of {@code getLong(0)}) to get a wrapped {@code Long} - * value that will be {@code null} if the column value was SQL NULL. - * - * @throws SQLException + * As an alternative to {@code wasNull()}, you can use {@link #getObject(int, Class)} (e.g. {@code + * getObject(0, Long.class)} instead of {@code getLong(0)}) to get a wrapped {@code Long} value + * that will be {@code null} if the column value was SQL NULL. */ public boolean wasNull() throws SQLException { // Note: lastGetWasNull is currently set only in getRawValue(), @@ -630,100 +730,4 @@ public boolean wasNull() throws SQLException { // checking wasNull() after each get*(). return lastGetWasNull; } - - private static Object convertFieldValue(Field field, ByteString value) throws SQLException { - // Note: We don't actually know the charset in which the value is encoded. - // For dates and numeric values, we just assume UTF-8 because they (hopefully) don't contain - // anything outside 7-bit ASCII, which (hopefully) is a subset of the actual charset. - // For strings, we return byte[] and the application is responsible for using the right charset. - switch (field.getType()) { - case DECIMAL: - return new BigDecimal(value.toStringUtf8()); - case INT8: // fall through - case UINT8: // fall through - case INT16: // fall through - case UINT16: // fall through - case INT24: // fall through - case UINT24: // fall through - case INT32: - return Integer.valueOf(value.toStringUtf8()); - case UINT32: // fall through - case INT64: - return Long.valueOf(value.toStringUtf8()); - case UINT64: - return new BigInteger(value.toStringUtf8()); - case FLOAT32: - return Float.valueOf(value.toStringUtf8()); - case FLOAT64: - return Double.valueOf(value.toStringUtf8()); - case NULL_TYPE: - return null; - case DATE: - // We don't get time zone information from the server, - // so we use the default time zone. - try { - return DateTime.parseDate(value.toStringUtf8()); - } catch (ParseException e) { - throw new SQLDataException("Can't parse DATE: " + value.toStringUtf8(), e); - } - case TIME: - // We don't get time zone information from the server, - // so we use the default time zone. - try { - return DateTime.parseTime(value.toStringUtf8()); - } catch (ParseException e) { - throw new SQLDataException("Can't parse TIME: " + value.toStringUtf8(), e); - } - case DATETIME: // fall through - case TIMESTAMP: - // We don't get time zone information from the server, - // so we use the default time zone. - try { - return DateTime.parseTimestamp(value.toStringUtf8()); - } catch (ParseException e) { - throw new SQLDataException("Can't parse TIMESTAMP: " + value.toStringUtf8(), e); - } - case YEAR: - return Short.valueOf(value.toStringUtf8()); - case ENUM: // fall through - case SET: - return value.toStringUtf8(); - case BIT: // fall through - case TEXT: // fall through - case BLOB: // fall through - case VARCHAR: // fall through - case VARBINARY: // fall through - case CHAR: // fall through - case BINARY: - case GEOMETRY: - case JSON: - return value.toByteArray(); - default: - throw new SQLDataException("unknown field type: " + field.getType()); - } - } - - /** - * Extract cell values from the single-buffer wire format. - * - *

- * See the docs for the {@code Row} message in {@code query.proto}. - */ - private static List extractValues(List lengths, ByteString buf) { - List list = new ArrayList(lengths.size()); - - int start = 0; - for (long len : lengths) { - if (len < 0) { - // This indicates a MySQL NULL value, to distinguish it from a zero-length string. - list.add((ByteString) null); - } else { - // Lengths are returned as long, but ByteString.substring() only supports int. - list.add(buf.substring(start, start + (int) len)); - start += len; - } - } - - return list; - } } diff --git a/java/client/src/main/java/io/vitess/client/cursor/SimpleCursor.java b/java/client/src/main/java/io/vitess/client/cursor/SimpleCursor.java index bc1c447ac63..69fe26d14e9 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/SimpleCursor.java +++ b/java/client/src/main/java/io/vitess/client/cursor/SimpleCursor.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,20 +16,22 @@ package io.vitess.client.cursor; +import io.vitess.proto.Query; +import io.vitess.proto.Query.Field; +import io.vitess.proto.Query.QueryResult; + import java.sql.SQLException; import java.util.Iterator; import java.util.List; -import javax.annotation.concurrent.NotThreadSafe; -import io.vitess.proto.Query; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.QueryResult; +import javax.annotation.concurrent.NotThreadSafe; /** * A {@link Cursor} that serves records from a single {@link QueryResult} object. */ @NotThreadSafe public class SimpleCursor extends Cursor { + private final QueryResult queryResult; private final Iterator rowIterator; diff --git a/java/client/src/main/java/io/vitess/client/cursor/StreamCursor.java b/java/client/src/main/java/io/vitess/client/cursor/StreamCursor.java index 4ab56eea654..1ef5971ad73 100644 --- a/java/client/src/main/java/io/vitess/client/cursor/StreamCursor.java +++ b/java/client/src/main/java/io/vitess/client/cursor/StreamCursor.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,24 +16,26 @@ package io.vitess.client.cursor; +import io.vitess.client.StreamIterator; +import io.vitess.proto.Query; +import io.vitess.proto.Query.Field; +import io.vitess.proto.Query.QueryResult; + import java.sql.SQLDataException; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.Iterator; import java.util.List; -import javax.annotation.concurrent.NotThreadSafe; -import io.vitess.client.StreamIterator; -import io.vitess.proto.Query; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.QueryResult; +import javax.annotation.concurrent.NotThreadSafe; /** - * A {@link Cursor} that serves records from the sequence of {@link QueryResult} objects - * represented by a {@link StreamIterator}. + * A {@link Cursor} that serves records from the sequence of {@link QueryResult} objects represented + * by a {@link StreamIterator}. */ @NotThreadSafe public class StreamCursor extends Cursor { + private StreamIterator streamIterator; private Iterator rowIterator; @@ -103,8 +105,8 @@ public Row next() throws SQLException { * *

Whereas the public {@link #next()} method advances the {@link Cursor} state to the next * {@link Row}, this method advances the internal state to the next {@link QueryResult}, which - * contains a batch of rows. Specifically, we get the next {@link QueryResult} from - * {@link #streamIterator}, and then set {@link #rowIterator} accordingly. + * contains a batch of rows. Specifically, we get the next {@link QueryResult} from {@link + * #streamIterator}, and then set {@link #rowIterator} accordingly. * *

If {@link #fields} is null, we assume the next {@link QueryResult} must contain the fields, * and set {@link #fields} from it. diff --git a/java/client/src/main/java/io/vitess/client/grpc/tls/TlsOptions.java b/java/client/src/main/java/io/vitess/client/grpc/tls/TlsOptions.java index e56dcce8329..a97fa3151ec 100644 --- a/java/client/src/main/java/io/vitess/client/grpc/tls/TlsOptions.java +++ b/java/client/src/main/java/io/vitess/client/grpc/tls/TlsOptions.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -21,8 +21,8 @@ /** *

A wrapper type holding TLS-related fields for the - * {@link io.vitess.client.RpcClientFactory#createTls(InetSocketAddress, TlsOptions)} method, so that - * this method won't have an unwieldy number of direct parameters.

+ * {@link io.vitess.client.RpcClientFactory#createTls(InetSocketAddress, TlsOptions)} method, so + * that this method won't have an unwieldy number of direct parameters.

* *

This path uses a builder pattern style:

* @@ -39,6 +39,7 @@ * */ public class TlsOptions { + private File keyStore; private String keyStorePassword; private String keyAlias; diff --git a/java/client/src/main/java/io/vitess/mysql/DateTime.java b/java/client/src/main/java/io/vitess/mysql/DateTime.java index 1d2d9ae9cd7..e5f9ef13e4d 100644 --- a/java/client/src/main/java/io/vitess/mysql/DateTime.java +++ b/java/client/src/main/java/io/vitess/mysql/DateTime.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,6 +17,7 @@ package io.vitess.mysql; import com.google.common.math.IntMath; + import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; @@ -29,10 +30,11 @@ * Utility methods for processing MySQL TIME, DATE, DATETIME, and TIMESTAMP. * *

These provide functionality similar to {@code valueOf()} and {@code toString()} - * in {@link java.sql.Date} et al. The difference is that these support MySQL-specific - * syntax like fractional seconds, negative times, and hours > 24 for elapsed time. + * in {@link java.sql.Date} et al. The difference is that these support MySQL-specific syntax like + * fractional seconds, negative times, and hours > 24 for elapsed time. */ public class DateTime { + private static final String DATE_FORMAT = "yyyy-MM-dd"; private static final String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss"; @@ -139,7 +141,7 @@ public static Time parseTime(String value, Calendar cal) throws ParseException { } } } - } catch (NumberFormatException e) { + } catch (NumberFormatException exc) { throw new ParseException("Invalid MYSQL TIME format: " + value, 0); } @@ -165,8 +167,8 @@ public static Time parseTime(String value, Calendar cal) throws ParseException { * Format a {@link Time} as a MySQL TIME with the default time zone. * *

This should match {@link Time#toString()} for the values it supports. - * For MySQL-specific syntax (like fractional seconds, negative times, - * and hours > 24) the results will differ. + * For MySQL-specific syntax (like fractional seconds, negative times, and hours > 24) the results + * will differ. */ public static String formatTime(Time value) { return formatTime(value, Calendar.getInstance()); @@ -177,8 +179,8 @@ public static String formatTime(Time value) { * *

The range for TIME values is '-838:59:59.000000' to '838:59:59.000000' * [1]. - * We don't enforce that range, but we do print >24 hours rather than - * wrapping around to the next day. + * We don't enforce that range, but we do print >24 hours rather than wrapping around to the next + * day. */ public static String formatTime(Time value, Calendar cal) { long millis = value.getTime(); @@ -243,7 +245,7 @@ public static Timestamp parseTimestamp(String value, Calendar cal) throws ParseE } try { nanos = Integer.parseInt(fraction) * IntMath.pow(10, 9 - fraction.length()); - } catch (NumberFormatException e) { + } catch (NumberFormatException exc) { throw new ParseException("Invalid MySQL TIMESTAMP format: " + value, dotIndex + 1); } } diff --git a/java/client/src/test/java/io/vitess/client/BindVarTest.java b/java/client/src/test/java/io/vitess/client/BindVarTest.java index 28bcee59f23..dee81b8ea66 100644 --- a/java/client/src/test/java/io/vitess/client/BindVarTest.java +++ b/java/client/src/test/java/io/vitess/client/BindVarTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -20,20 +20,23 @@ import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; + +import io.vitess.proto.Query; +import io.vitess.proto.Query.BindVariable; + import java.math.BigDecimal; import java.math.BigInteger; import java.util.Arrays; import java.util.Collection; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import io.vitess.proto.Query; -import io.vitess.proto.Query.BindVariable; - @RunWith(value = Parameterized.class) public class BindVarTest { + private Object input; private BindVariable expected; @@ -50,9 +53,9 @@ public static Collection testParams() { BindVariable.newBuilder().setType(Query.Type.VARCHAR) .setValue(ByteString.copyFromUtf8("hello world")).build()}, // Bytes - {new byte[] {1, 2, 3}, + {new byte[]{1, 2, 3}, BindVariable.newBuilder().setType(Query.Type.VARBINARY) - .setValue(ByteString.copyFrom(new byte[] {1, 2, 3})).build()}, + .setValue(ByteString.copyFrom(new byte[]{1, 2, 3})).build()}, // Int {123, BindVariable.newBuilder().setType(Query.Type.INT64) @@ -78,12 +81,12 @@ public static Collection testParams() { BindVariable.newBuilder().setType(Query.Type.FLOAT64) .setValue(ByteString.copyFromUtf8("1.23")).build()}, // List of Bytes - {Arrays.asList(new byte[] {1, 2, 3}, new byte[] {4, 5, 6}), + {Arrays.asList(new byte[]{1, 2, 3}, new byte[]{4, 5, 6}), BindVariable.newBuilder().setType(Query.Type.TUPLE) .addValues(Query.Value.newBuilder().setType(Query.Type.VARBINARY) - .setValue(ByteString.copyFrom(new byte[] {1, 2, 3})).build()) + .setValue(ByteString.copyFrom(new byte[]{1, 2, 3})).build()) .addValues(Query.Value.newBuilder().setType(Query.Type.VARBINARY) - .setValue(ByteString.copyFrom(new byte[] {4, 5, 6})).build()) + .setValue(ByteString.copyFrom(new byte[]{4, 5, 6})).build()) .build()}, // Boolean {true, diff --git a/java/client/src/test/java/io/vitess/client/EntityIdTest.java b/java/client/src/test/java/io/vitess/client/EntityIdTest.java index 82a5064dc49..1359d487904 100644 --- a/java/client/src/test/java/io/vitess/client/EntityIdTest.java +++ b/java/client/src/test/java/io/vitess/client/EntityIdTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -20,91 +20,95 @@ import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; + +import io.vitess.proto.Query; +import io.vitess.proto.Vtgate.ExecuteEntityIdsRequest.EntityId; + import java.util.Arrays; import java.util.Collection; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; -import io.vitess.proto.Query; -import io.vitess.proto.Vtgate.ExecuteEntityIdsRequest.EntityId; - @RunWith(value = Parameterized.class) public class EntityIdTest { + private Object input; private EntityId expected; - private static final ByteString KEYSPACE_ID = ByteString.copyFrom(new byte[] {1, 2, 3}); + private static final ByteString KEYSPACE_ID = ByteString.copyFrom(new byte[]{1, 2, 3}); @Parameters public static Collection testParams() { Object[][] params = { - // SQL NULL - { - null, EntityId.newBuilder().setKeyspaceId(KEYSPACE_ID).setType(Query.Type.NULL_TYPE).build() - }, - // String - { - "hello world", - EntityId.newBuilder() - .setKeyspaceId(KEYSPACE_ID) - .setType(Query.Type.VARCHAR) - .setValue(ByteString.copyFromUtf8("hello world")) - .build() - }, - // Bytes - { - new byte[] {1, 2, 3}, - EntityId.newBuilder() - .setKeyspaceId(KEYSPACE_ID) - .setType(Query.Type.VARBINARY) - .setValue(ByteString.copyFrom(new byte[] {1, 2, 3})) - .build() - }, - // Int - { - 123, - EntityId.newBuilder() - .setKeyspaceId(KEYSPACE_ID) - .setType(Query.Type.INT64) - .setValue(ByteString.copyFromUtf8("123")) - .build() - }, - { - 123L, - EntityId.newBuilder() - .setKeyspaceId(KEYSPACE_ID) - .setType(Query.Type.INT64) - .setValue(ByteString.copyFromUtf8("123")) - .build() - }, - // Uint - { - UnsignedLong.fromLongBits(-1), - EntityId.newBuilder() - .setKeyspaceId(KEYSPACE_ID) - .setType(Query.Type.UINT64) - .setValue(ByteString.copyFromUtf8("18446744073709551615")) - .build() - }, - // Float - { - 1.23f, - EntityId.newBuilder() - .setKeyspaceId(KEYSPACE_ID) - .setType(Query.Type.FLOAT64) - .setValue(ByteString.copyFromUtf8("1.23")) - .build() - }, - { - 1.23, - EntityId.newBuilder() - .setKeyspaceId(KEYSPACE_ID) - .setType(Query.Type.FLOAT64) - .setValue(ByteString.copyFromUtf8("1.23")) - .build() - }, + // SQL NULL + { + null, + EntityId.newBuilder().setKeyspaceId(KEYSPACE_ID).setType(Query.Type.NULL_TYPE).build() + }, + // String + { + "hello world", + EntityId.newBuilder() + .setKeyspaceId(KEYSPACE_ID) + .setType(Query.Type.VARCHAR) + .setValue(ByteString.copyFromUtf8("hello world")) + .build() + }, + // Bytes + { + new byte[]{1, 2, 3}, + EntityId.newBuilder() + .setKeyspaceId(KEYSPACE_ID) + .setType(Query.Type.VARBINARY) + .setValue(ByteString.copyFrom(new byte[]{1, 2, 3})) + .build() + }, + // Int + { + 123, + EntityId.newBuilder() + .setKeyspaceId(KEYSPACE_ID) + .setType(Query.Type.INT64) + .setValue(ByteString.copyFromUtf8("123")) + .build() + }, + { + 123L, + EntityId.newBuilder() + .setKeyspaceId(KEYSPACE_ID) + .setType(Query.Type.INT64) + .setValue(ByteString.copyFromUtf8("123")) + .build() + }, + // Uint + { + UnsignedLong.fromLongBits(-1), + EntityId.newBuilder() + .setKeyspaceId(KEYSPACE_ID) + .setType(Query.Type.UINT64) + .setValue(ByteString.copyFromUtf8("18446744073709551615")) + .build() + }, + // Float + { + 1.23f, + EntityId.newBuilder() + .setKeyspaceId(KEYSPACE_ID) + .setType(Query.Type.FLOAT64) + .setValue(ByteString.copyFromUtf8("1.23")) + .build() + }, + { + 1.23, + EntityId.newBuilder() + .setKeyspaceId(KEYSPACE_ID) + .setType(Query.Type.FLOAT64) + .setValue(ByteString.copyFromUtf8("1.23")) + .build() + }, }; return Arrays.asList(params); } diff --git a/java/client/src/test/java/io/vitess/client/ProtoTest.java b/java/client/src/test/java/io/vitess/client/ProtoTest.java index 27f6ab1142b..d52d6551971 100644 --- a/java/client/src/test/java/io/vitess/client/ProtoTest.java +++ b/java/client/src/test/java/io/vitess/client/ProtoTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,7 +17,9 @@ package io.vitess.client; import com.google.common.collect.ImmutableMap; + import java.util.Map; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,6 +27,7 @@ @RunWith(JUnit4.class) public class ProtoTest { + @Test public void testGetErrno() { final Map testValues = diff --git a/java/client/src/test/java/io/vitess/client/RpcClientTest.java b/java/client/src/test/java/io/vitess/client/RpcClientTest.java index 97301296a3d..67e69c93552 100644 --- a/java/client/src/test/java/io/vitess/client/RpcClientTest.java +++ b/java/client/src/test/java/io/vitess/client/RpcClientTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -20,6 +20,21 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.protobuf.ByteString; + +import io.vitess.client.cursor.Cursor; +import io.vitess.client.cursor.Row; +import io.vitess.proto.Query; +import io.vitess.proto.Query.Field; +import io.vitess.proto.Query.SplitQueryRequest.Algorithm; +import io.vitess.proto.Topodata.KeyRange; +import io.vitess.proto.Topodata.KeyspaceIdType; +import io.vitess.proto.Topodata.ShardReference; +import io.vitess.proto.Topodata.SrvKeyspace; +import io.vitess.proto.Topodata.SrvKeyspace.KeyspacePartition; +import io.vitess.proto.Topodata.TabletType; +import io.vitess.proto.Vtgate.SplitQueryResponse; +import io.vitess.proto.Vtrpc.CallerID; + import java.nio.charset.StandardCharsets; import java.sql.SQLDataException; import java.sql.SQLException; @@ -34,7 +49,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.TimeUnit; + import org.joda.time.DateTime; import org.joda.time.Duration; import org.junit.Assert; @@ -42,20 +57,6 @@ import org.junit.BeforeClass; import org.junit.Test; -import io.vitess.client.cursor.Cursor; -import io.vitess.client.cursor.Row; -import io.vitess.proto.Query; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.SplitQueryRequest.Algorithm; -import io.vitess.proto.Topodata.KeyRange; -import io.vitess.proto.Topodata.KeyspaceIdType; -import io.vitess.proto.Topodata.ShardReference; -import io.vitess.proto.Topodata.SrvKeyspace; -import io.vitess.proto.Topodata.SrvKeyspace.KeyspacePartition; -import io.vitess.proto.Topodata.TabletType; -import io.vitess.proto.Vtgate.SplitQueryResponse; -import io.vitess.proto.Vtrpc.CallerID; - /** * RpcClientTest tests a given implementation of RpcClient against a mock vtgate server * (go/cmd/vtgateclienttest). @@ -64,6 +65,7 @@ * vtgateclienttest server with the necessary parameters and then set 'client'. */ public abstract class RpcClientTest { + protected static RpcClient client; // ready is true when "vtgateclienttest" can accept RPCs. It is set by "waitForVtgateclienttest" // and reset to "false" at the start of each test class by "resetReady". @@ -86,7 +88,8 @@ public void setUp() throws SQLException, InterruptedException { // ctx is used by all RPCs within one test method. A deadline is set to cap test execution. // (RPCs will fail with DEADLINE_EXCEEDED if they keep using "ctx" 5 seconds from now.) - ctx = Context.getDefault().withDeadlineAfter(Duration.standardSeconds(5)).withCallerId(CALLER_ID); + ctx = Context.getDefault().withDeadlineAfter(Duration.standardSeconds(5)) + .withCallerId(CALLER_ID); } private static final String ECHO_PREFIX = "echo://"; @@ -111,20 +114,20 @@ public void setUp() throws SQLException, InterruptedException { private static final String SHARDS_ECHO = "[-80 80-]"; private static final List KEYSPACE_IDS = - Arrays.asList(new byte[] {1, 2, 3, 4}, new byte[] {5, 6, 7, 8}); + Arrays.asList(new byte[]{1, 2, 3, 4}, new byte[]{5, 6, 7, 8}); private static final String KEYSPACE_IDS_ECHO = "[[1 2 3 4] [5 6 7 8]]"; private static final List KEY_RANGES = - Arrays.asList(KeyRange.newBuilder().setStart(ByteString.copyFrom(new byte[] {1, 2, 3, 4})) - .setEnd(ByteString.copyFrom(new byte[] {5, 6, 7, 8})).build()); + Arrays.asList(KeyRange.newBuilder().setStart(ByteString.copyFrom(new byte[]{1, 2, 3, 4})) + .setEnd(ByteString.copyFrom(new byte[]{5, 6, 7, 8})).build()); private static final String KEY_RANGES_ECHO = "[start:\"\\001\\002\\003\\004\" end:\"\\005\\006\\007\\010\" ]"; private static final ImmutableMap ENTITY_KEYSPACE_IDS = new ImmutableMap.Builder() - .put(new byte[] {1, 2, 3}, 123) - .put(new byte[] {4, 5, 6}, 2.5) - .put(new byte[] {7, 8, 9}, new byte[] {1, 2, 3}) + .put(new byte[]{1, 2, 3}, 123) + .put(new byte[]{4, 5, 6}, 2.5) + .put(new byte[]{7, 8, 9}, new byte[]{1, 2, 3}) .build(); private static final String ENTITY_KEYSPACE_IDS_ECHO = "[type:INT64 value:\"123\" keyspace_id:\"\\001\\002\\003\" type:FLOAT64 value:\"2.5\" keyspace_id:\"\\004\\005\\006\" type:VARBINARY value:\"\\001\\002\\003\" keyspace_id:\"\\007\\010\\t\" ]"; @@ -132,12 +135,13 @@ public void setUp() throws SQLException, InterruptedException { private static final TabletType TABLET_TYPE = TabletType.REPLICA; private static final String TABLET_TYPE_ECHO = TABLET_TYPE.toString(); private static final Query.ExecuteOptions.IncludedFields ALL_FIELDS = Query.ExecuteOptions.IncludedFields.ALL; - private static final String OPTIONS_ALL_FIELDS_ECHO = "included_fields:" + ALL_FIELDS.toString() + " "; + private static final String OPTIONS_ALL_FIELDS_ECHO = + "included_fields:" + ALL_FIELDS.toString() + " "; private static final ImmutableMap BIND_VARS = new ImmutableMap.Builder() .put("int", 123) .put("float", 2.5) - .put("bytes", new byte[] {1, 2, 3}) + .put("bytes", new byte[]{1, 2, 3}) .build(); private static final String BIND_VARS_ECHO = "map[bytes:type:VARBINARY value:\"\\001\\002\\003\" float:type:FLOAT64 value:\"2.5\" int:type:INT64 value:\"123\" ]"; @@ -187,9 +191,6 @@ private static Map getEcho(Cursor cursor) throws Exception { * * We will constantly execute the "GetSrvKeyspace" RPC and return when the binary responded * successfully. - * - * @throws SQLException - * @throws InterruptedException */ private void waitForVtgateclienttest() throws SQLException, InterruptedException { if (ready) { @@ -213,7 +214,9 @@ private void waitForVtgateclienttest() throws SQLException, InterruptedException throw e; } - System.out.format("Waiting until vtgateclienttest is ready and responds (got exception: %s)\n", rootCause); + System.out + .format("Waiting until vtgateclienttest is ready and responds (got exception: %s)\n", + rootCause); Thread.sleep(100 /* milliseconds */); waited = true; } @@ -221,7 +224,8 @@ private void waitForVtgateclienttest() throws SQLException, InterruptedException if (waited) { double waitTimeSeconds = (DateTime.now().getMillis() - start.getMillis()) / 1000.0; - System.out.format("Had to wait %.1f second(s) until vtgateclienttest was ready.\n", waitTimeSeconds); + System.out.format("Had to wait %.1f second(s) until vtgateclienttest was ready.\n", + waitTimeSeconds); } ready = true; } @@ -237,7 +241,8 @@ public void testEchoExecute() throws Exception { Assert.assertEquals(NONTX_V3_SESSION_ECHO, echo.get("session")); echo = getEcho( - conn.executeShards(ctx, ECHO_PREFIX + QUERY, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS)); + conn.executeShards(ctx, ECHO_PREFIX + QUERY, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, + ALL_FIELDS)); Assert.assertEquals(CALLER_ID_ECHO, echo.get("callerId")); Assert.assertEquals(ECHO_PREFIX + QUERY, echo.get("query")); Assert.assertEquals(KEYSPACE, echo.get("keyspace")); @@ -307,7 +312,8 @@ public void testEchoExecute() throws Exception { public void testEchoStreamExecute() throws Exception { Map echo; - echo = getEcho(conn.streamExecute(ctx, ECHO_PREFIX + QUERY, BIND_VARS, TABLET_TYPE, ALL_FIELDS)); + echo = getEcho( + conn.streamExecute(ctx, ECHO_PREFIX + QUERY, BIND_VARS, TABLET_TYPE, ALL_FIELDS)); Assert.assertEquals(CALLER_ID_ECHO, echo.get("callerId")); Assert.assertEquals(ECHO_PREFIX + QUERY, echo.get("query")); Assert.assertEquals(BIND_VARS_ECHO, echo.get("bindVars")); @@ -363,7 +369,8 @@ public void testEchoTransactionExecute() throws Exception { tx = conn.begin(ctx); echo = getEcho( - tx.executeShards(ctx, ECHO_PREFIX + QUERY, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS)); + tx.executeShards(ctx, ECHO_PREFIX + QUERY, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, + ALL_FIELDS)); Assert.assertEquals(CALLER_ID_ECHO, echo.get("callerId")); Assert.assertEquals(ECHO_PREFIX + QUERY, echo.get("query")); Assert.assertEquals(KEYSPACE, echo.get("keyspace")); @@ -462,7 +469,7 @@ public void testEchoSplitQuery() throws Exception { 123, 1000, Algorithm.FULL_SCAN) - .get(0); + .get(0); Assert.assertEquals(expected, actual); } @@ -471,8 +478,8 @@ public void testGetSrvKeyspace() throws Exception { SrvKeyspace expected = SrvKeyspace.newBuilder() .addPartitions(KeyspacePartition.newBuilder().setServedType(TabletType.REPLICA) .addShardReferences(ShardReference.newBuilder().setName("shard0").setKeyRange(KeyRange - .newBuilder().setStart(ByteString.copyFrom(new byte[] {0x40, 0, 0, 0, 0, 0, 0, 0})) - .setEnd(ByteString.copyFrom(new byte[] {(byte) 0x80, 0, 0, 0, 0, 0, 0, 0})).build()) + .newBuilder().setStart(ByteString.copyFrom(new byte[]{0x40, 0, 0, 0, 0, 0, 0, 0})) + .setEnd(ByteString.copyFrom(new byte[]{(byte) 0x80, 0, 0, 0, 0, 0, 0, 0})).build()) .build()) .build()) .setShardingColumnName("sharding_column_name") @@ -484,6 +491,7 @@ public void testGetSrvKeyspace() throws Exception { } abstract static class Executable { + abstract void execute(String query) throws Exception; } @@ -521,6 +529,7 @@ void checkStreamExecuteErrors(Executable exe) { } abstract static class TransactionExecutable { + abstract void execute(VTGateBlockingTx tx, String query) throws Exception; } @@ -602,7 +611,8 @@ void execute(String query) throws Exception { checkExecuteErrors(new Executable() { @Override void execute(String query) throws Exception { - conn.executeKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS); + conn.executeKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, + ALL_FIELDS); } }); checkExecuteErrors(new Executable() { @@ -647,20 +657,23 @@ void execute(String query) throws Exception { checkStreamExecuteErrors(new Executable() { @Override void execute(String query) throws Exception { - conn.streamExecuteShards(ctx, query, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS).next(); + conn.streamExecuteShards(ctx, query, KEYSPACE, SHARDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS) + .next(); } }); checkStreamExecuteErrors(new Executable() { @Override void execute(String query) throws Exception { - conn.streamExecuteKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS) + conn.streamExecuteKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, + ALL_FIELDS) .next(); } }); checkStreamExecuteErrors(new Executable() { @Override void execute(String query) throws Exception { - conn.streamExecuteKeyRanges(ctx, query, KEYSPACE, KEY_RANGES, BIND_VARS, TABLET_TYPE, ALL_FIELDS) + conn.streamExecuteKeyRanges(ctx, query, KEYSPACE, KEY_RANGES, BIND_VARS, TABLET_TYPE, + ALL_FIELDS) .next(); } }); @@ -683,7 +696,8 @@ void execute(VTGateBlockingTx tx, String query) throws Exception { checkTransactionExecuteErrors(new TransactionExecutable() { @Override void execute(VTGateBlockingTx tx, String query) throws Exception { - tx.executeKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, ALL_FIELDS); + tx.executeKeyspaceIds(ctx, query, KEYSPACE, KEYSPACE_IDS, BIND_VARS, TABLET_TYPE, + ALL_FIELDS); } }); checkTransactionExecuteErrors(new TransactionExecutable() { @@ -703,7 +717,8 @@ void execute(VTGateBlockingTx tx, String query) throws Exception { @Override void execute(VTGateBlockingTx tx, String query) throws Exception { tx.executeBatchShards(ctx, - Arrays.asList(Proto.bindShardQuery(KEYSPACE, SHARDS, query, BIND_VARS)), TABLET_TYPE, ALL_FIELDS); + Arrays.asList(Proto.bindShardQuery(KEYSPACE, SHARDS, query, BIND_VARS)), TABLET_TYPE, + ALL_FIELDS); } }); checkTransactionExecuteErrors(new TransactionExecutable() { diff --git a/java/client/src/test/java/io/vitess/client/TestEnv.java b/java/client/src/test/java/io/vitess/client/TestEnv.java index 1c5012eab9b..f9b9d0dabd3 100644 --- a/java/client/src/test/java/io/vitess/client/TestEnv.java +++ b/java/client/src/test/java/io/vitess/client/TestEnv.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -21,6 +21,7 @@ import java.nio.file.Files; import java.util.ArrayList; import java.util.List; + import org.apache.commons.io.FileUtils; import vttest.Vttest.VTTestTopology; @@ -28,6 +29,7 @@ * Helper class to hold the configurations for VtGate setup used in integration tests */ public class TestEnv { + private VTTestTopology topology; private String keyspace; private String outputPath; diff --git a/java/client/src/test/java/io/vitess/client/TestUtil.java b/java/client/src/test/java/io/vitess/client/TestUtil.java index 395abc4817f..563874f47b4 100644 --- a/java/client/src/test/java/io/vitess/client/TestUtil.java +++ b/java/client/src/test/java/io/vitess/client/TestUtil.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -19,22 +19,25 @@ import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; + +import io.vitess.proto.Query; +import io.vitess.proto.Topodata.TabletType; + import java.io.BufferedReader; import java.io.InputStreamReader; import java.lang.reflect.Type; import java.util.HashMap; import java.util.List; import java.util.Map; + import org.apache.log4j.LogManager; import org.apache.log4j.Logger; import org.joda.time.Duration; import org.junit.Assert; import vttest.Vttest.VTTestTopology; -import io.vitess.proto.Query; -import io.vitess.proto.Topodata.TabletType; - public class TestUtil { + static final Logger logger = LogManager.getLogger(TestUtil.class.getName()); public static final String PROPERTY_KEY_CLIENT_TEST_ENV = "vitess.client.testEnv"; public static final String PROPERTY_KEY_CLIENT_TEST_PORT = "vitess.client.testEnv.portName"; @@ -60,10 +63,12 @@ public static void setupTestEnv(TestEnv testEnv) throws Exception { continue; } try { - Type mapType = new TypeToken>() {}.getType(); + Type mapType = new TypeToken>() { + }.getType(); Map map = new Gson().fromJson(line, mapType); testEnv.setPythonScriptProcess(p); - testEnv.setPort(((Double)map.get(System.getProperty(PROPERTY_KEY_CLIENT_TEST_PORT))).intValue()); + testEnv.setPort( + ((Double) map.get(System.getProperty(PROPERTY_KEY_CLIENT_TEST_PORT))).intValue()); return; } catch (JsonSyntaxException e) { logger.error("JsonSyntaxException parsing setup command output: " + line, e); @@ -114,7 +119,7 @@ public static VTGateBlockingConn getBlockingConn(TestEnv testEnv) { // Dial timeout Context ctx = Context.getDefault().withDeadlineAfter(Duration.millis(5000)); return new VTGateBlockingConn( - getRpcClientFactory().create(ctx, "localhost:" + testEnv.getPort()), + getRpcClientFactory().create(ctx, "localhost:" + testEnv.getPort()), testEnv.getKeyspace()); } @@ -132,7 +137,8 @@ public static void insertRows(TestEnv testEnv, int startId, int count) throws Ex bindVars.put("name", "name_" + id); bindVars.put("age", id % 10); bindVars.put("percent", id / 100.0); - tx.execute(ctx, insertSql, bindVars, TabletType.MASTER, Query.ExecuteOptions.IncludedFields.ALL); + tx.execute(ctx, insertSql, bindVars, TabletType.MASTER, + Query.ExecuteOptions.IncludedFields.ALL); } tx.commit(ctx); } diff --git a/java/client/src/test/java/io/vitess/client/cursor/CursorTest.java b/java/client/src/test/java/io/vitess/client/cursor/CursorTest.java index 0534cf72b4c..809607e00a9 100644 --- a/java/client/src/test/java/io/vitess/client/cursor/CursorTest.java +++ b/java/client/src/test/java/io/vitess/client/cursor/CursorTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -18,6 +18,11 @@ import com.google.common.primitives.UnsignedLong; import com.google.protobuf.ByteString; + +import io.vitess.proto.Query; +import io.vitess.proto.Query.Field; +import io.vitess.proto.Query.QueryResult; + import java.math.BigDecimal; import java.math.BigInteger; import java.sql.Date; @@ -28,17 +33,15 @@ import java.util.Calendar; import java.util.List; import java.util.TimeZone; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import io.vitess.proto.Query; -import io.vitess.proto.Query.Field; -import io.vitess.proto.Query.QueryResult; - @RunWith(JUnit4.class) public class CursorTest { + private static final Calendar GMT = Calendar.getInstance(TimeZone.getTimeZone("GMT")); @Test @@ -58,16 +61,20 @@ public void testFindColumn() throws Exception { @Test public void testFindColumnAlternateIndexes() throws Exception { try (Cursor cursor = new SimpleCursor( - QueryResult.newBuilder().addFields(Field.newBuilder().setName("col1").setTable("Table1").build()) - .addFields(Field.newBuilder().setName("myAlias").setOrgName("boringColName").setTable("Table2").build()) - .build())) { + QueryResult.newBuilder() + .addFields(Field.newBuilder().setName("col1").setTable("Table1").build()) + .addFields( + Field.newBuilder().setName("myAlias").setOrgName("boringColName").setTable("Table2") + .build()) + .build())) { Assert.assertEquals(1, cursor.findColumn("Table1.col1")); Assert.assertEquals(1, cursor.findColumn("Table1.Col1")); Assert.assertEquals(2, cursor.findColumn("myAlias")); Assert.assertEquals(2, cursor.findColumn("Table2.myAlias")); Assert.assertEquals(2, cursor.findColumn("boringColName")); try { - int idx = cursor.findColumn("Table2.boringColName"); // don't do what mysql-connector-j doesn't do + int idx = cursor + .findColumn("Table2.boringColName"); // don't do what mysql-connector-j doesn't do Assert.fail("no exception thrown for findColumn(\"Table2.boringColName\")"); } catch (Exception ex) { Assert.assertEquals(SQLDataException.class, ex.getClass()); @@ -103,9 +110,10 @@ public void testGetULong() throws Exception { try (Cursor cursor = new SimpleCursor(QueryResult.newBuilder() .addFields(Field.newBuilder().setName("col1").setType(Query.Type.UINT64).build()) .addFields(Field.newBuilder().setName("null").setType(Query.Type.UINT64).build()) - .addRows(Query.Row.newBuilder().addLengths("18446744073709551615".length()).addLengths(-1) // SQL - // NULL - .setValues(ByteString.copyFromUtf8("18446744073709551615"))) + .addRows( + Query.Row.newBuilder().addLengths("18446744073709551615".length()).addLengths(-1) // SQL + // NULL + .setValues(ByteString.copyFromUtf8("18446744073709551615"))) .build())) { Row row = cursor.next(); Assert.assertNotNull(row); @@ -121,9 +129,10 @@ public void testGetBigInteger() throws Exception { try (Cursor cursor = new SimpleCursor(QueryResult.newBuilder() .addFields(Field.newBuilder().setName("col1").setType(Query.Type.UINT64).build()) .addFields(Field.newBuilder().setName("null").setType(Query.Type.UINT64).build()) - .addRows(Query.Row.newBuilder().addLengths("18446744073709551615".length()).addLengths(-1) // SQL - // NULL - .setValues(ByteString.copyFromUtf8("18446744073709551615"))) + .addRows( + Query.Row.newBuilder().addLengths("18446744073709551615".length()).addLengths(-1) // SQL + // NULL + .setValues(ByteString.copyFromUtf8("18446744073709551615"))) .build())) { Row row = cursor.next(); Assert.assertNotNull(row); @@ -222,7 +231,7 @@ public void testGetDate() throws Exception { .addFields(Field.newBuilder().setName("col1").setType(type).build()) .addFields(Field.newBuilder().setName("null").setType(type).build()) .addRows(Query.Row.newBuilder().addLengths("2008-01-02".length()).addLengths(-1) // SQL - // NULL + // NULL .setValues(ByteString.copyFromUtf8("2008-01-02"))) .build())) { Row row = cursor.next(); @@ -291,7 +300,7 @@ public void testGetBytes() throws Exception { .addFields(Field.newBuilder().setName("col1").setType(type).build()) .addFields(Field.newBuilder().setName("null").setType(type).build()) .addRows(Query.Row.newBuilder().addLengths("hello world".length()).addLengths(-1) // SQL - // NULL + // NULL .setValues(ByteString.copyFromUtf8("hello world"))) .build())) { Row row = cursor.next(); @@ -312,7 +321,7 @@ public void testGetBigDecimal() throws Exception { .addFields(Field.newBuilder().setName("col1").setType(type).build()) .addFields(Field.newBuilder().setName("null").setType(type).build()) .addRows(Query.Row.newBuilder().addLengths("1234.56789".length()).addLengths(-1) // SQL - // NULL + // NULL .setValues(ByteString.copyFromUtf8("1234.56789"))) .build())) { Row row = cursor.next(); @@ -376,9 +385,9 @@ public void testNull() throws Exception { public void testGetBinaryInputStream() throws Exception { ByteString travel = ByteString.copyFromUtf8("მოგზაურობა"); try (Cursor cursor = new SimpleCursor(QueryResult.newBuilder() - .addFields(Field.newBuilder().setName("col1").setType(Query.Type.INT32).build()) - .addRows(Query.Row.newBuilder().addLengths(travel.size()).setValues(travel)) - .build())) { + .addFields(Field.newBuilder().setName("col1").setType(Query.Type.INT32).build()) + .addRows(Query.Row.newBuilder().addLengths(travel.size()).setValues(travel)) + .build())) { Row row = cursor.next(); Assert.assertNotNull(row); diff --git a/java/client/src/test/java/io/vitess/mysql/DateTimeTest.java b/java/client/src/test/java/io/vitess/mysql/DateTimeTest.java index 9a544f1001b..59bd0c7ea19 100644 --- a/java/client/src/test/java/io/vitess/mysql/DateTimeTest.java +++ b/java/client/src/test/java/io/vitess/mysql/DateTimeTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; + import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; @@ -27,12 +28,14 @@ import java.util.List; import java.util.Map; import java.util.TimeZone; + import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class DateTimeTest { + private static final Calendar GMT = Calendar.getInstance(TimeZone.getTimeZone("GMT")); private static final Calendar PST = Calendar.getInstance(TimeZone.getTimeZone("GMT-8")); private static final Calendar IST = Calendar.getInstance(TimeZone.getTimeZone("GMT+0530")); diff --git a/java/pom.xml b/java/pom.xml index e5b2fbd7b45..ac05378c605 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -70,6 +70,7 @@ 1.16.0 3.6.1 3.6.1 + 3.0.0 @@ -253,6 +254,28 @@ + + org.apache.maven.plugins + maven-checkstyle-plugin + ${checkstyle.plugin.version} + + google_checks.xml + checkstyle-suppression.xml + true + false + true + warning + + + + validate + validate + + check + + + + From 4e1d20a3b40660e365dd75a982e0b122af006bc0 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Wed, 6 Feb 2019 13:19:10 -0500 Subject: [PATCH 026/196] grpc-client: checkstyle Signed-off-by: Ze'ev Klapow --- .../java/io/vitess/client/grpc/Constants.java | 12 +- .../io/vitess/client/grpc/GrpcClient.java | 43 ++- .../vitess/client/grpc/GrpcClientFactory.java | 252 +++++++------- .../vitess/client/grpc/GrpcStreamAdapter.java | 36 +- .../client/grpc/RetryingInterceptor.java | 39 ++- .../grpc/RetryingInterceptorConfig.java | 24 +- .../client/grpc/StaticAuthCredentials.java | 5 +- .../client/grpc/GrpcClientStaticAuthTest.java | 10 +- .../java/io/client/grpc/GrpcClientTest.java | 32 +- .../grpc/GrpcClientTlsClientAuthTest.java | 313 +++++++++--------- .../io/client/grpc/GrpcClientTlsTest.java | 256 +++++++------- .../grpc/GrpcClientWithRetriesTest.java | 15 +- .../client/grpc/RetryingInterceptorTest.java | 49 ++- 13 files changed, 577 insertions(+), 509 deletions(-) diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/Constants.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/Constants.java index e8dd4319421..950c9d351ad 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/Constants.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/Constants.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -21,9 +21,9 @@ */ public class Constants { - public static final String KEYSTORE_TYPE = "JKS"; + public static final String KEYSTORE_TYPE = "JKS"; - private Constants() { + private Constants() { - } + } } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java index feb50bcdeca..a25784df223 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java @@ -20,10 +20,11 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; + import io.grpc.CallCredentials; +import io.grpc.InternalWithLogId; import io.grpc.ManagedChannel; import io.grpc.StatusRuntimeException; -import io.grpc.InternalWithLogId; import io.vitess.client.Context; import io.vitess.client.Proto; import io.vitess.client.RpcClient; @@ -65,6 +66,9 @@ import io.vitess.proto.grpc.VitessGrpc; import io.vitess.proto.grpc.VitessGrpc.VitessFutureStub; import io.vitess.proto.grpc.VitessGrpc.VitessStub; + +import org.joda.time.Duration; + import java.io.IOException; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; @@ -75,12 +79,12 @@ import java.sql.SQLTimeoutException; import java.sql.SQLTransientException; import java.util.concurrent.TimeUnit; -import org.joda.time.Duration; /** * GrpcClient is a gRPC-based implementation of Vitess RpcClient. */ public class GrpcClient implements RpcClient { + private final ManagedChannel channel; private final String channelId; private final VitessStub asyncStub; @@ -101,8 +105,8 @@ public GrpcClient(ManagedChannel channel, CallCredentials credentials) { } private String toChannelId(ManagedChannel channel) { - return channel instanceof InternalWithLogId ? - ((InternalWithLogId) channel).getLogId().toString() : channel.toString(); + return channel instanceof InternalWithLogId + ? ((InternalWithLogId) channel).getLogId().toString() : channel.toString(); } @Override @@ -145,7 +149,8 @@ public ListenableFuture executeEntityIds(Context ctx, new ExceptionConverter(), MoreExecutors.directExecutor()); } - @Override public ListenableFuture executeBatch(Context ctx, + @Override + public ListenableFuture executeBatch(Context ctx, Vtgate.ExecuteBatchRequest request) throws SQLException { return Futures.catchingAsync(getFutureStub(ctx).executeBatch(request), Exception.class, new ExceptionConverter(), MoreExecutors.directExecutor()); @@ -260,9 +265,9 @@ public ListenableFuture getSrvKeyspace(Context ctx, /** * Converts an exception from the gRPC framework into the appropriate {@link SQLException}. */ - static SQLException convertGrpcError(Throwable e) { - if (e instanceof StatusRuntimeException) { - StatusRuntimeException sre = (StatusRuntimeException) e; + static SQLException convertGrpcError(Throwable exc) { + if (exc instanceof StatusRuntimeException) { + StatusRuntimeException sre = (StatusRuntimeException) exc; int errno = Proto.getErrno(sre.getMessage()); String sqlState = Proto.getSQLState(sre.getMessage()); @@ -282,21 +287,23 @@ static SQLException convertGrpcError(Throwable e) { return new SQLRecoverableException(sre.toString(), sqlState, errno, sre); default: // Covers e.g. UNKNOWN. String advice = ""; - if (e.getCause() instanceof java.nio.channels.ClosedChannelException) { + if (exc.getCause() instanceof java.nio.channels.ClosedChannelException) { advice = - "Failed to connect to vtgate. Make sure that vtgate is running and you are using the correct address. Details: "; + "Failed to connect to vtgate. Make sure that vtgate is running and you are using " + + "the correct address. Details: "; } return new SQLNonTransientException( - "gRPC StatusRuntimeException: " + advice + e.toString(), sqlState, errno, e); + "gRPC StatusRuntimeException: " + advice + exc.toString(), sqlState, errno, exc); } } - return new SQLNonTransientException("gRPC error: " + e.toString(), e); + return new SQLNonTransientException("gRPC error: " + exc.toString(), exc); } static class ExceptionConverter implements AsyncFunction { + @Override - public ListenableFuture apply(Exception e) throws Exception { - throw convertGrpcError(e); + public ListenableFuture apply(Exception exc) throws Exception { + throw convertGrpcError(exc); } } @@ -318,9 +325,9 @@ private VitessFutureStub getFutureStub(Context ctx) { @Override public String toString() { - return String.format("[GrpcClient-%s channel=%s]", - Integer.toHexString(this.hashCode()), - channelId - ); + return String.format("[GrpcClient-%s channel=%s]", + Integer.toHexString(this.hashCode()), + channelId + ); } } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 928c29334ee..19524061faa 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -19,6 +19,16 @@ import io.grpc.CallCredentials; import io.grpc.LoadBalancer; import io.grpc.NameResolver; +import io.grpc.netty.GrpcSslContexts; +import io.grpc.netty.NegotiationType; +import io.grpc.netty.NettyChannelBuilder; +import io.netty.handler.ssl.SslContext; +import io.netty.handler.ssl.SslContextBuilder; +import io.vitess.client.Context; +import io.vitess.client.RpcClient; +import io.vitess.client.RpcClientFactory; +import io.vitess.client.grpc.tls.TlsOptions; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -35,16 +45,6 @@ import javax.net.ssl.SSLException; -import io.grpc.netty.GrpcSslContexts; -import io.grpc.netty.NegotiationType; -import io.grpc.netty.NettyChannelBuilder; -import io.netty.handler.ssl.SslContext; -import io.netty.handler.ssl.SslContextBuilder; -import io.vitess.client.Context; -import io.vitess.client.RpcClient; -import io.vitess.client.RpcClientFactory; -import io.vitess.client.grpc.tls.TlsOptions; - /** * GrpcClientFactory creates RpcClients with the gRPC implementation. */ @@ -81,30 +81,32 @@ public GrpcClientFactory setNameResolverFactory(NameResolver.Factory value) { /** * Factory method to construct a gRPC client connection with no transport-layer security. * - * @param ctx TODO: This parameter is not actually used, but probably SHOULD be so that timeout duration and caller ID settings aren't discarded - * @param target - * target is passed to NettyChannelBuilder which will resolve based on scheme, by default dns. - * @return + * @param ctx TODO: This parameter is not actually used, but probably SHOULD be so that + * timeout duration and caller ID settings aren't discarded + * @param target target is passed to NettyChannelBuilder which will resolve based on scheme, + * by default dns. */ @Override public RpcClient create(Context ctx, String target) { NettyChannelBuilder channel = channelBuilder(target) - .negotiationType(NegotiationType.PLAINTEXT) - .intercept(new RetryingInterceptor(config)); + .negotiationType(NegotiationType.PLAINTEXT) + .intercept(new RetryingInterceptor(config)); if (loadBalancerFactory != null) { channel.loadBalancerFactory(loadBalancerFactory); } if (nameResolverFactory != null) { channel.nameResolverFactory(nameResolverFactory); } - return callCredentials != null ? - new GrpcClient(channel.build(), callCredentials) : new GrpcClient(channel.build()); + return callCredentials != null + ? new GrpcClient(channel.build(), callCredentials) : new GrpcClient(channel.build()); } /** - *

This method constructs NettyChannelBuilder object that will be used to create RpcClient.

- *

Subclasses may override this method to make adjustments to the builder

+ *

This method constructs NettyChannelBuilder object that will be used to create + * RpcClient.

+ *

Subclasses may override this method to make adjustments to the builder

* for example: + * * * @Override * protected NettyChannelBuilder channelBuilder(String target) { @@ -112,83 +114,81 @@ public RpcClient create(Context ctx, String target) { * .eventLoopGroup(new EpollEventLoopGroup()) * .withOption(EpollChannelOption.TCP_USER_TIMEOUT,30); * } - * * * - * @param target - * target is passed to NettyChannelBuilder which will resolve based on scheme, by default dns. - * @return + * @param target target is passed to NettyChannelBuilder which will resolve based on scheme, + * by default dns. */ - protected NettyChannelBuilder channelBuilder(String target){ + protected NettyChannelBuilder channelBuilder(String target) { return NettyChannelBuilder.forTarget(target); } /** *

Factory method to construct a gRPC client connection with transport-layer security.

* - *

Within the tlsOptions parameter value, the trustStore field should + *

Within the tlsOptions parameter value, the trustStore field + * should * always be populated. All other fields are optional.

* - * @param ctx TODO: This parameter is not actually used, but probably SHOULD be so that timeout duration and caller ID settings aren't discarded - * @param target - * target is passed to NettyChannelBuilder which will resolve based on scheme, by default dns. - * @param tlsOptions - * @return + * @param ctx TODO: This parameter is not actually used, but probably SHOULD be so that + * timeout duration and caller ID settings aren't discarded + * @param target target is passed to NettyChannelBuilder which will resolve based on scheme, + * by default dns. */ @Override public RpcClient createTls(Context ctx, String target, TlsOptions tlsOptions) { final SslContextBuilder sslContextBuilder = GrpcSslContexts.forClient(); // trustManager should always be set - final KeyStore trustStore = loadKeyStore(tlsOptions.getTrustStore(), tlsOptions.getTrustStorePassword()); + final KeyStore trustStore = loadKeyStore(tlsOptions.getTrustStore(), + tlsOptions.getTrustStorePassword()); if (trustStore == null) { throw new RuntimeException("Could not load trustStore"); } final X509Certificate[] trustCertCollection = tlsOptions.getTrustAlias() == null - ? loadCertCollection(trustStore) - : loadCertCollectionForAlias(trustStore, tlsOptions.getTrustAlias()); + ? loadCertCollection(trustStore) + : loadCertCollectionForAlias(trustStore, tlsOptions.getTrustAlias()); sslContextBuilder.trustManager(trustCertCollection); - // keyManager should only be set if a keyStore is specified (meaning that client authentication is enabled) - final KeyStore keyStore = loadKeyStore(tlsOptions.getKeyStore(), tlsOptions.getKeyStorePassword()); + // keyManager should only be set if a keyStore is specified (meaning that client authentication + // is enabled) + final KeyStore keyStore = loadKeyStore(tlsOptions.getKeyStore(), + tlsOptions.getKeyStorePassword()); if (keyStore != null) { final PrivateKeyWrapper privateKeyWrapper = tlsOptions.getKeyAlias() == null - ? loadPrivateKeyEntry(keyStore, tlsOptions.getKeyStorePassword(), tlsOptions.getKeyPassword()) - : loadPrivateKeyEntryForAlias(keyStore, tlsOptions.getKeyAlias(), tlsOptions.getKeyStorePassword(), tlsOptions.getKeyPassword()); + ? loadPrivateKeyEntry(keyStore, tlsOptions.getKeyStorePassword(), + tlsOptions.getKeyPassword()) + : loadPrivateKeyEntryForAlias(keyStore, tlsOptions.getKeyAlias(), + tlsOptions.getKeyStorePassword(), tlsOptions.getKeyPassword()); if (privateKeyWrapper == null) { - throw new RuntimeException("Could not retrieve private key and certificate chain from keyStore"); + throw new RuntimeException( + "Could not retrieve private key and certificate chain from keyStore"); } sslContextBuilder.keyManager( - privateKeyWrapper.getPrivateKey(), - privateKeyWrapper.getPassword(), - privateKeyWrapper.getCertificateChain() + privateKeyWrapper.getPrivateKey(), + privateKeyWrapper.getPassword(), + privateKeyWrapper.getCertificateChain() ); } final SslContext sslContext; try { sslContext = sslContextBuilder.build(); - } catch (SSLException e) { - throw new RuntimeException(e); + } catch (SSLException exc) { + throw new RuntimeException(exc); } return new GrpcClient( - channelBuilder(target).negotiationType(NegotiationType.TLS).sslContext(sslContext).intercept(new RetryingInterceptor(config)).build()); + channelBuilder(target).negotiationType(NegotiationType.TLS).sslContext(sslContext) + .intercept(new RetryingInterceptor(config)).build()); } /** *

Opens a JKS keystore file from the filesystem.

* - *

Returns null if the file is inaccessible for any reason, or if the password fails to unlock it.

- * - * @param keyStoreFile - * @param keyStorePassword - * @return - * @throws KeyStoreException - * @throws IOException - * @throws CertificateException - * @throws NoSuchAlgorithmException + *

Returns null if the file is inaccessible for any reason, or if the password + * fails to unlock it.

*/ private KeyStore loadKeyStore(final File keyStoreFile, String keyStorePassword) { if (keyStoreFile == null) { @@ -202,45 +202,46 @@ private KeyStore loadKeyStore(final File keyStoreFile, String keyStorePassword) keyStore.load(fis, password); } return keyStore; - } catch (KeyStoreException | CertificateException | NoSuchAlgorithmException | IOException e) { + } catch (KeyStoreException + | CertificateException + | NoSuchAlgorithmException + | IOException exc) { return null; } } /** - *

Loads an X509 certificate from a keystore using a given alias, and returns it as a one-element + *

Loads an X509 certificate from a keystore using a given alias, and returns it as a + * one-element * array so that it can be passed to {@link SslContextBuilder#trustManager(File)}.

* - *

Returns null if there is any problem accessing the keystore, or if the alias does + *

Returns null if there is any problem accessing the keystore, or if the alias + * does * not match an X509 certificate.

- * - * @param keyStore - * @param alias - * @return */ - private X509Certificate[] loadCertCollectionForAlias(final KeyStore keyStore, final String alias) { + private X509Certificate[] loadCertCollectionForAlias(final KeyStore keyStore, + final String alias) { if (keyStore == null) { return null; } try { - return new X509Certificate[] { - (X509Certificate) keyStore.getCertificate(alias) + return new X509Certificate[]{ + (X509Certificate) keyStore.getCertificate(alias) }; - } catch (KeyStoreException | ClassCastException e) { + } catch (KeyStoreException | ClassCastException exc) { return null; } } /** - *

Loads the first valid X509 certificate found in the keystore, and returns it as a one-element + *

Loads the first valid X509 certificate found in the keystore, and returns it as a + * one-element * array so that it can be passed to {@link SslContextBuilder#trustManager(File)}.

* - *

Returns null if there is any problem accessing the keystore, or if no X509 certificates + *

Returns null if there is any problem accessing the keystore, or if no X509 + * certificates * are found at all.

- * - * @param keyStore - * @return */ private X509Certificate[] loadCertCollection(final KeyStore keyStore) { if (keyStore == null) { @@ -250,7 +251,7 @@ private X509Certificate[] loadCertCollection(final KeyStore keyStore) { final Enumeration aliases; try { aliases = keyStore.aliases(); - } catch (KeyStoreException e) { + } catch (KeyStoreException exc) { return null; } @@ -266,29 +267,25 @@ private X509Certificate[] loadCertCollection(final KeyStore keyStore) { } /** - *

Loads from a keystore the private key entry matching a given alias, and returns it parsed and - * ready to be passed to {@link SslContextBuilder#keyManager(PrivateKey, String, X509Certificate...)}.

+ *

Loads from a keystore the private key entry matching a given alias, and returns it parsed + * and + * ready to be passed to {@link SslContextBuilder#keyManager(PrivateKey, String, + * X509Certificate...)}.

* - *

To access the private key, this method will first try using the keyPassword parameter - * value (this parameter can be set to null to explicitly indicate that there is no password). - * If that fails, then this method will then try using the keyStorePassword parameter value - * as the key value too.

+ *

To access the private key, this method will first try using the keyPassword + * parameter + * value (this parameter can be set to null to explicitly indicate that there is no + * password). If that fails, then this method will then try using the + * keyStorePassword parameter value as the key value too.

* - *

Returns null if there is any problem accessing the keystore, if neither keyPassword - * or keyStorePassword can unlock the private key, or if no private key entry matches + *

Returns null if there is any problem accessing the keystore, if neither + * keyPassword + * or keyStorePassword can unlock the private key, or if no private key entry + * matches * alias.

- * - * @param keyStore - * @param alias - * @param keyStorePassword - * @param keyPassword - * @return - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws UnrecoverableEntryException */ private PrivateKeyWrapper loadPrivateKeyEntryForAlias(final KeyStore keyStore, final String alias, - final String keyStorePassword, final String keyPassword) { + final String keyStorePassword, final String keyPassword) { if (keyStore == null || alias == null) { return null; } @@ -298,52 +295,53 @@ private PrivateKeyWrapper loadPrivateKeyEntryForAlias(final KeyStore keyStore, f // There is no private key matching this alias return null; } - } catch (KeyStoreException e) { + } catch (KeyStoreException exc) { return null; } // Try loading the private key with the key password (which can be null) try { final char[] pass = keyPassword == null ? null : keyPassword.toCharArray(); - final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(pass)); + final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore + .getEntry(alias, new KeyStore.PasswordProtection(pass)); return new PrivateKeyWrapper(entry.getPrivateKey(), keyPassword, entry.getCertificateChain()); - } catch (KeyStoreException | NoSuchAlgorithmException e) { - return null; - } catch (UnrecoverableEntryException e) { + } catch (KeyStoreException | NoSuchAlgorithmException exc) { + return null; + } catch (UnrecoverableEntryException exc) { // The key password didn't work (or just wasn't set). Try using the keystore password. final char[] pass = keyStorePassword == null ? null : keyStorePassword.toCharArray(); try { - final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore.getEntry(alias, new KeyStore.PasswordProtection(pass)); - return new PrivateKeyWrapper(entry.getPrivateKey(), keyPassword, entry.getCertificateChain()); + final KeyStore.PrivateKeyEntry entry = (KeyStore.PrivateKeyEntry) keyStore + .getEntry(alias, new KeyStore.PasswordProtection(pass)); + return new PrivateKeyWrapper(entry.getPrivateKey(), keyPassword, + entry.getCertificateChain()); } catch (KeyStoreException | NoSuchAlgorithmException | UnrecoverableEntryException e1) { - // Neither password worked. - return null; + // Neither password worked. + return null; } } } /** - *

Loads from a keystore the first valid private key entry found, and returns it parsed and ready to be + *

Loads from a keystore the first valid private key entry found, and returns it parsed and + * ready to be * passed to {@link SslContextBuilder#keyManager(PrivateKey, String, X509Certificate...)}.

* - *

To access the private key, this method will first try using the keyPassword parameter - * value (this parameter can be set to null to explicitly indicate that there is no password). - * If that fails, then this method will then try using the keyStorePassword parameter value - * as the key value too.

+ *

To access the private key, this method will first try using the keyPassword + * parameter + * value (this parameter can be set to null to explicitly indicate that there is no + * password). If that fails, then this method will then try using the + * keyStorePassword parameter value as the key value too.

* - *

Returns null if there is any problem accessing the keystore, if neither keyPassword - * or keyStorePassword can unlock the private key, or if no private key entry matches + *

Returns null if there is any problem accessing the keystore, if neither + * keyPassword + * or keyStorePassword can unlock the private key, or if no private key entry + * matches * alias.

- * - * @param keyStore - * @param keyStorePassword - * @param keyPassword - * @return - * @throws KeyStoreException - * @throws NoSuchAlgorithmException */ - private PrivateKeyWrapper loadPrivateKeyEntry(final KeyStore keyStore, final String keyStorePassword, - final String keyPassword) { + private PrivateKeyWrapper loadPrivateKeyEntry(final KeyStore keyStore, + final String keyStorePassword, + final String keyPassword) { if (keyStore == null) { return null; } @@ -351,13 +349,14 @@ private PrivateKeyWrapper loadPrivateKeyEntry(final KeyStore keyStore, final Str final Enumeration aliases; try { aliases = keyStore.aliases(); - } catch (KeyStoreException e) { + } catch (KeyStoreException exc) { return null; } while (aliases.hasMoreElements()) { final String alias = aliases.nextElement(); - final PrivateKeyWrapper privateKeyWrapper = loadPrivateKeyEntryForAlias(keyStore, alias, keyStorePassword, keyPassword); + final PrivateKeyWrapper privateKeyWrapper = loadPrivateKeyEntryForAlias(keyStore, alias, + keyStorePassword, keyPassword); if (privateKeyWrapper != null) { return privateKeyWrapper; } @@ -366,20 +365,23 @@ private PrivateKeyWrapper loadPrivateKeyEntry(final KeyStore keyStore, final Str } /** - * A container for the values returned by {@link this#loadPrivateKeyEntry(KeyStore, String, String)} and - * {@link this#loadPrivateKeyEntryForAlias(KeyStore, String, String, String)}, and passed in turn - * to {@link SslContextBuilder#keyManager(PrivateKey, String, X509Certificate...)}. Helpful since Java - * methods cannot return multiple values. + * A container for the values returned by {@link this#loadPrivateKeyEntry(KeyStore, String, + * String)} and {@link this#loadPrivateKeyEntryForAlias(KeyStore, String, String, String)}, and + * passed in turn to {@link SslContextBuilder#keyManager(PrivateKey, String, X509Certificate...)}. + * Helpful since Java methods cannot return multiple values. */ private class PrivateKeyWrapper { + private PrivateKey privateKey; private String password; private X509Certificate[] certificateChain; - public PrivateKeyWrapper(final PrivateKey privateKey, final String password, final Certificate[] certificateChain) { + public PrivateKeyWrapper(final PrivateKey privateKey, final String password, + final Certificate[] certificateChain) { this.privateKey = privateKey; this.password = password; - this.certificateChain = Arrays.copyOf(certificateChain, certificateChain.length, X509Certificate[].class); + this.certificateChain = Arrays + .copyOf(certificateChain, certificateChain.length, X509Certificate[].class); } public PrivateKey getPrivateKey() { diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcStreamAdapter.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcStreamAdapter.java index fe2b68b119c..d8b6b12aff7 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcStreamAdapter.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcStreamAdapter.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -18,6 +18,7 @@ import io.grpc.stub.StreamObserver; import io.vitess.client.StreamIterator; + import java.sql.SQLDataException; import java.sql.SQLException; import java.util.NoSuchElementException; @@ -29,9 +30,9 @@ * gRPC {@code StreamObserver} interface. * *

This class is abstract because it needs to be told how to extract the result - * (e.g. {@link io.vitess.proto.Query.QueryResult QueryResult}) from a given RPC response - * (e.g. {@link io.vitess.proto.Vtgate.StreamExecuteResponse StreamExecuteResponse}). - * Callers must therefore implement {@link #getResult(Object)} when instantiating this class. + * (e.g. {@link io.vitess.proto.Query.QueryResult QueryResult}) from a given RPC response (e.g. + * {@link io.vitess.proto.Vtgate.StreamExecuteResponse StreamExecuteResponse}). Callers must + * therefore implement {@link #getResult(Object)} when instantiating this class. * *

The {@code StreamObserver} side will block until the result has been returned to the consumer * by the {@code StreamIterator} side. Therefore, the {@link #close()} method must be called when @@ -42,11 +43,12 @@ */ abstract class GrpcStreamAdapter implements StreamObserver, StreamIterator, AutoCloseable { + /** - * getResult must be implemented to tell the adapter how to convert from - * the StreamObserver value type (V) to the StreamIterator value type (E). - * Before converting, getResult() should check for application-level errors - * in the RPC response and throw the appropriate SQLException. + * getResult must be implemented to tell the adapter how to convert from the StreamObserver value + * type (V) to the StreamIterator value type (E). Before converting, getResult() should check for + * application-level errors in the RPC response and throw the appropriate SQLException. + * * @param value The RPC response object. * @return The result object to pass to the iterator consumer. * @throws SQLException For errors originating within the Vitess server. @@ -75,10 +77,10 @@ public void onNext(V value) { nextValue = getResult(value); notifyAll(); - } catch (InterruptedException e) { - onError(e); - } catch (SQLException e) { - onError(e); + } catch (InterruptedException exc) { + onError(exc); + } catch (SQLException exc) { + onError(exc); } } } @@ -117,9 +119,9 @@ public boolean hasNext() throws SQLException { } return true; - } catch (InterruptedException e) { - onError(e); - throw new SQLDataException("gRPC StreamIterator interrupted while waiting for value", e); + } catch (InterruptedException exc) { + onError(exc); + throw new SQLDataException("gRPC StreamIterator interrupted while waiting for value", exc); } } } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptor.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptor.java index 0127e876a66..1991772df35 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptor.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptor.java @@ -3,15 +3,6 @@ import static com.google.common.base.Preconditions.checkState; import static io.grpc.internal.GrpcUtil.TIMER_SERVICE; -import java.util.Queue; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; - -import javax.annotation.Nullable; - import io.grpc.CallOptions; import io.grpc.Channel; import io.grpc.ClientCall; @@ -22,14 +13,24 @@ import io.grpc.Status; import io.grpc.internal.SharedResourceHolder; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + /** - * RetryingInterceptor is used for retrying certain classes of failed requests in the underlying gRPC connection. - * At this time it handles {@link MethodDescriptor.MethodType.UNARY} requests with status {@link Status.Code.UNAVAILABLE}, which is - * according to the spec meant to be a transient error. This class can be configured with {@link RetryingInterceptorConfig} to - * determine what level of exponential backoff to apply to the handled types of failing requests. + * RetryingInterceptor is used for retrying certain classes of failed requests in the underlying + * gRPC connection. At this time it handles {@link MethodDescriptor.MethodType.UNARY} requests with + * status {@link Status.Code.UNAVAILABLE}, which is according to the spec meant to be a transient + * error. This class can be configured with {@link RetryingInterceptorConfig} to determine what + * level of exponential backoff to apply to the handled types of failing requests. * - * When enabled, this interceptor will retry valid requests with an exponentially increasing backoff time up to the maximum - * time defined by the {@link io.grpc.Deadline} in the call's {@link CallOptions}. + * When enabled, this interceptor will retry valid requests with an exponentially increasing backoff + * time up to the maximum time defined by the {@link io.grpc.Deadline} in the call's {@link + * CallOptions}. */ public class RetryingInterceptor implements ClientInterceptor { @@ -52,6 +53,7 @@ public ClientCall interceptCall( } private class RetryingCall extends ClientCall { + private final MethodDescriptor method; private final CallOptions callOptions; private final Channel channel; @@ -71,8 +73,8 @@ private class RetryingCall extends ClientCall { private final double backoffMultiplier; RetryingCall(MethodDescriptor method, - CallOptions callOptions, Channel channel, Context context, - RetryingInterceptorConfig config) { + CallOptions callOptions, Channel channel, Context context, + RetryingInterceptorConfig config) { this.method = method; this.callOptions = callOptions; this.channel = channel; @@ -136,7 +138,7 @@ public void setMessageCompression(boolean enabled) { private long computeSleepTime() { long currentBackoff = nextBackoffMillis; - nextBackoffMillis = Math.min((long) ( currentBackoff * backoffMultiplier), maxBackoffMillis); + nextBackoffMillis = Math.min((long) (currentBackoff * backoffMultiplier), maxBackoffMillis); return currentBackoff; } @@ -194,6 +196,7 @@ private ClientCall lastCall() { } private class AttemptListener extends ClientCall.Listener { + final ClientCall call; Metadata responseHeaders; RespT responseMessage; diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptorConfig.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptorConfig.java index 4e75c2ba60d..f3d3f0eeb76 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptorConfig.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/RetryingInterceptorConfig.java @@ -1,8 +1,8 @@ package io.vitess.client.grpc; /** - * This class defines what level of exponential backoff to apply in the {@link RetryingInterceptor}. It can be - * disabled with the {@link #noOpConfig()}. + * This class defines what level of exponential backoff to apply in the {@link RetryingInterceptor}. + * It can be disabled with the {@link #noOpConfig()}. */ public class RetryingInterceptorConfig { @@ -12,7 +12,8 @@ public class RetryingInterceptorConfig { private final long maxBackoffMillis; private final double backoffMultiplier; - private RetryingInterceptorConfig(long initialBackoffMillis, long maxBackoffMillis, double backoffMultiplier) { + private RetryingInterceptorConfig(long initialBackoffMillis, long maxBackoffMillis, + double backoffMultiplier) { this.initialBackoffMillis = initialBackoffMillis; this.maxBackoffMillis = maxBackoffMillis; this.backoffMultiplier = backoffMultiplier; @@ -26,15 +27,16 @@ public static RetryingInterceptorConfig noOpConfig() { } /** - * Returns an exponential config with the given values to determine how aggressive of a backoff is needed - * @param initialBackoffMillis - * how long in millis to backoff off for the first attempt - * @param maxBackoffMillis - * the maximum value the backoff time can grow to, at which point all future retries will backoff at this amount - * @param backoffMultiplier - * how quickly the backoff time should grow + * Returns an exponential config with the given values to determine how aggressive of a backoff is + * needed + * + * @param initialBackoffMillis how long in millis to backoff off for the first attempt + * @param maxBackoffMillis the maximum value the backoff time can grow to, at which point all + * future retries will backoff at this amount + * @param backoffMultiplier how quickly the backoff time should grow */ - public static RetryingInterceptorConfig exponentialConfig(long initialBackoffMillis, long maxBackoffMillis, double backoffMultiplier) { + public static RetryingInterceptorConfig exponentialConfig(long initialBackoffMillis, + long maxBackoffMillis, double backoffMultiplier) { return new RetryingInterceptorConfig(initialBackoffMillis, maxBackoffMillis, backoffMultiplier); } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/StaticAuthCredentials.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/StaticAuthCredentials.java index fbf5694b8c9..d04754ee5d8 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/StaticAuthCredentials.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/StaticAuthCredentials.java @@ -5,6 +5,7 @@ import io.grpc.Metadata; import io.grpc.MethodDescriptor; import io.grpc.Status; + import java.util.Objects; import java.util.concurrent.Executor; @@ -35,8 +36,8 @@ public void applyRequestMetadata(MethodDescriptor method, Attributes attrs headers.put(USERNAME, username); headers.put(PASSWORD, password); applier.apply(headers); - } catch (Throwable e) { - applier.fail(Status.UNAUTHENTICATED.withCause(e)); + } catch (Throwable exc) { + applier.fail(Status.UNAUTHENTICATED.withCause(exc)); } }); } diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientStaticAuthTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientStaticAuthTest.java index 8be2567535c..1148406412e 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientStaticAuthTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientStaticAuthTest.java @@ -1,6 +1,7 @@ package io.client.grpc; import com.google.common.base.Throwables; + import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.vitess.client.Context; @@ -9,11 +10,14 @@ import io.vitess.client.grpc.GrpcClientFactory; import io.vitess.client.grpc.StaticAuthCredentials; import io.vitess.proto.Vtgate.GetSrvKeyspaceRequest; + +import org.joda.time.Duration; + import java.net.ServerSocket; import java.net.URI; import java.util.Arrays; import java.util.concurrent.ExecutionException; -import org.joda.time.Duration; + import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -23,6 +27,7 @@ @RunWith(JUnit4.class) public class GrpcClientStaticAuthTest extends RpcClientTest { + private static Process vtgateclienttest; private static int port; @@ -32,7 +37,8 @@ public static void setUpBeforeClass() throws Exception { if (vtRoot == null) { throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); } - URI staticAuthFile = GrpcClientStaticAuthTest.class.getResource("grpc_static_auth.json").toURI(); + URI staticAuthFile = GrpcClientStaticAuthTest.class.getResource("grpc_static_auth.json") + .toURI(); ServerSocket socket = new ServerSocket(0); port = socket.getLocalPort(); diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTest.java index 00425e84a3e..18e69eaba21 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,24 +16,26 @@ package io.client.grpc; +import io.vitess.client.Context; +import io.vitess.client.RpcClientTest; +import io.vitess.client.grpc.GrpcClientFactory; + +import org.joda.time.Duration; + import java.net.ServerSocket; import java.util.Arrays; -import org.joda.time.Duration; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import io.vitess.client.Context; -import io.vitess.client.RpcClientTest; -import io.vitess.client.grpc.GrpcClientFactory; - /** * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest). */ @RunWith(JUnit4.class) public class GrpcClientTest extends RpcClientTest { + private static Process vtgateclienttest; private static int port; @@ -50,13 +52,13 @@ public static void setUpBeforeClass() throws Exception { vtgateclienttest = new ProcessBuilder( - Arrays.asList( - vtRoot + "/bin/vtgateclienttest", - "-logtostderr", - "-grpc_port", - Integer.toString(port), - "-service_map", - "grpc-vtgateservice")) + Arrays.asList( + vtRoot + "/bin/vtgateclienttest", + "-logtostderr", + "-grpc_port", + Integer.toString(port), + "-service_map", + "grpc-vtgateservice")) .inheritIO() .start(); diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsClientAuthTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsClientAuthTest.java index f37ed7467a2..19f2d4de91a 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsClientAuthTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsClientAuthTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,169 +16,186 @@ package io.client.grpc; +import com.google.common.io.Files; + +import io.vitess.client.Context; +import io.vitess.client.RpcClientTest; +import io.vitess.client.grpc.GrpcClientFactory; +import io.vitess.client.grpc.tls.TlsOptions; + +import org.joda.time.Duration; + import java.io.File; import java.io.IOException; import java.net.ServerSocket; import java.nio.file.Paths; -import org.joda.time.Duration; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import com.google.common.io.Files; - -import io.vitess.client.Context; -import io.vitess.client.RpcClientTest; -import io.vitess.client.grpc.GrpcClientFactory; -import io.vitess.client.grpc.tls.TlsOptions; - /** - * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest), over an SSL connection with client - * authentication enabled. + * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest), over an SSL connection + * with client authentication enabled. */ @RunWith(JUnit4.class) public class GrpcClientTlsClientAuthTest extends RpcClientTest { - private static Process vtgateclienttest; - private static int port; - private static File certDirectory; - - private static String caConfig; - private static String caKey; - private static String caCert; - private static String caCertDer; - private static String trustStore; - - @BeforeClass - public static void setUpBeforeClass() throws Exception { - certDirectory = Files.createTempDir(); - System.out.println("Using cert directory: " + certDirectory.getCanonicalPath()); - - caConfig = certDirectory.getCanonicalPath() + File.separatorChar + "ca.config"; - caKey = certDirectory.getCanonicalPath() + File.separatorChar + "ca-key.pem"; - caCert = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.pem"; - caCertDer = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.der"; - trustStore = certDirectory.getCanonicalPath() + File.separatorChar + "ca-trustStore.jks"; - - createCA(); - createTrustStore(); - createSignedCert("01", "server"); - createSignedCert("02", "client"); - createKeyStore("client"); - - startVtgate(); - createClientConnection(); + private static Process vtgateclienttest; + private static int port; + private static File certDirectory; + + private static String caConfig; + private static String caKey; + private static String caCert; + private static String caCertDer; + private static String trustStore; + + @BeforeClass + public static void setUpBeforeClass() throws Exception { + certDirectory = Files.createTempDir(); + System.out.println("Using cert directory: " + certDirectory.getCanonicalPath()); + + caConfig = certDirectory.getCanonicalPath() + File.separatorChar + "ca.config"; + caKey = certDirectory.getCanonicalPath() + File.separatorChar + "ca-key.pem"; + caCert = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.pem"; + caCertDer = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.der"; + trustStore = certDirectory.getCanonicalPath() + File.separatorChar + "ca-trustStore.jks"; + + createCA(); + createTrustStore(); + createSignedCert("01", "server"); + createSignedCert("02", "client"); + createKeyStore("client"); + + startVtgate(); + createClientConnection(); + } + + @AfterClass + public static void tearDownAfterClass() throws Exception { + if (client != null) { + client.close(); } - - @AfterClass - public static void tearDownAfterClass() throws Exception { - if (client != null) { - client.close(); - } - if (vtgateclienttest != null) { - vtgateclienttest.destroy(); - vtgateclienttest.waitFor(); - } + if (vtgateclienttest != null) { + vtgateclienttest.destroy(); + vtgateclienttest.waitFor(); } - - private static void runProcess(final String command) throws IOException, InterruptedException { - System.out.println("\nExecuting: " + command); - int exitCode = new ProcessBuilder().inheritIO().command(command.split(" ")).start().waitFor(); - System.out.println("Exit code: " + exitCode + "\n"); + } + + private static void runProcess(final String command) throws IOException, InterruptedException { + System.out.println("\nExecuting: " + command); + int exitCode = new ProcessBuilder().inheritIO().command(command.split(" ")).start().waitFor(); + System.out.println("Exit code: " + exitCode + "\n"); + } + + private static void createCA() throws Exception { + java.nio.file.Files.copy( + GrpcClientTlsTest.class.getResourceAsStream("/ca.config"), + Paths.get(caConfig) + ); + + final String createKey = String.format("openssl genrsa -out %s 2048", caKey); + runProcess(createKey); + + final String createCert = String + .format("openssl req -new -x509 -nodes -days 3600 -batch -config %s -key %s -out %s", + caConfig, caKey, caCert); + runProcess(createCert); + } + + private static void createTrustStore() throws Exception { + final String convertCaCert = String + .format("openssl x509 -outform der -in %s -out %s", caCert, caCertDer); + runProcess(convertCaCert); + + final String createTrustStore = String.format( + "keytool -import -alias cacert -keystore %s -file %s -storepass passwd -trustcacerts -noprompt", + trustStore, caCertDer); + runProcess(createTrustStore); + } + + private static void createSignedCert(final String serial, final String name) throws Exception { + final String certConfig = certDirectory.getCanonicalPath() + File.separatorChar + "cert.config"; + if (!(new File(certConfig)).exists()) { + java.nio.file.Files.copy( + GrpcClientTlsTest.class.getResourceAsStream("/cert.config"), + Paths.get(certConfig) + ); } - - private static void createCA() throws Exception { - java.nio.file.Files.copy( - GrpcClientTlsTest.class.getResourceAsStream("/ca.config"), - Paths.get(caConfig) - ); - - final String createKey = String.format("openssl genrsa -out %s 2048", caKey); - runProcess(createKey); - - final String createCert = String.format("openssl req -new -x509 -nodes -days 3600 -batch -config %s -key %s -out %s", caConfig, caKey, caCert); - runProcess(createCert); - } - - private static void createTrustStore() throws Exception { - final String convertCaCert = String.format("openssl x509 -outform der -in %s -out %s", caCert, caCertDer); - runProcess(convertCaCert); - - final String createTrustStore = String.format("keytool -import -alias cacert -keystore %s -file %s -storepass passwd -trustcacerts -noprompt", trustStore, caCertDer); - runProcess(createTrustStore); - } - - private static void createSignedCert(final String serial, final String name) throws Exception { - final String certConfig = certDirectory.getCanonicalPath() + File.separatorChar + "cert.config"; - if (!(new File(certConfig)).exists()) { - java.nio.file.Files.copy( - GrpcClientTlsTest.class.getResourceAsStream("/cert.config"), - Paths.get(certConfig) - ); - } - final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; - final String req = certDirectory.getCanonicalPath() + File.separatorChar + name + "-req.pem"; - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; - - final String createKeyAndCSR = String.format("openssl req -newkey rsa:2048 -days 3600 -nodes -batch -config %s -keyout %s -out %s", certConfig, key, req); - runProcess(createKeyAndCSR); - - final String signKey = String.format("openssl x509 -req -in %s -days 3600 -CA %s -CAkey %s -set_serial %s -out %s", req, caCert, caKey, serial, cert); - runProcess(signKey); + final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; + final String req = certDirectory.getCanonicalPath() + File.separatorChar + name + "-req.pem"; + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; + + final String createKeyAndCSR = String.format( + "openssl req -newkey rsa:2048 -days 3600 -nodes -batch -config %s -keyout %s -out %s", + certConfig, key, req); + runProcess(createKeyAndCSR); + + final String signKey = String + .format("openssl x509 -req -in %s -days 3600 -CA %s -CAkey %s -set_serial %s -out %s", req, + caCert, caKey, serial, cert); + runProcess(signKey); + } + + private static void createKeyStore(final String name) throws Exception { + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; + final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; + final String p12 = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.p12"; + final String keyStore = + certDirectory.getCanonicalPath() + File.separatorChar + name + "-keyStore.jks"; + + final String convertCert = String.format( + "openssl pkcs12 -export -in %s -inkey %s -out %s -name cert -CAfile %s -caname root -passout pass:passwd", + cert, key, p12, caCert); + System.out.println(convertCert); + new ProcessBuilder(convertCert.split(" ")).start().waitFor(); + + final String createKeyStore = String.format( + "keytool -importkeystore -deststorepass passwd -destkeystore %s -srckeystore %s -srcstoretype PKCS12 -alias cert -srcstorepass passwd", + keyStore, p12); + System.out.println(createKeyStore); + new ProcessBuilder(createKeyStore.split(" ")).start().waitFor(); + } + + private static void startVtgate() throws Exception { + final String vtRoot = System.getenv("VTROOT"); + if (vtRoot == null) { + throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); } - private static void createKeyStore(final String name) throws Exception { - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; - final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; - final String p12 = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.p12"; - final String keyStore = certDirectory.getCanonicalPath() + File.separatorChar + name + "-keyStore.jks"; - - final String convertCert = String.format("openssl pkcs12 -export -in %s -inkey %s -out %s -name cert -CAfile %s -caname root -passout pass:passwd", cert, key, p12, caCert); - System.out.println(convertCert); - new ProcessBuilder(convertCert.split(" ")).start().waitFor(); - - final String createKeyStore = String.format("keytool -importkeystore -deststorepass passwd -destkeystore %s -srckeystore %s -srcstoretype PKCS12 -alias cert -srcstorepass passwd", keyStore, p12); - System.out.println(createKeyStore); - new ProcessBuilder(createKeyStore.split(" ")).start().waitFor(); - } - - private static void startVtgate() throws Exception { - final String vtRoot = System.getenv("VTROOT"); - if (vtRoot == null) { - throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); - } - - final ServerSocket socket = new ServerSocket(0); - port = socket.getLocalPort(); - socket.close(); - - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + "server-cert.pem"; - final String key = certDirectory.getCanonicalPath() + File.separatorChar + "server-key.pem"; - - final String vtgateCommand = String.format("%s -grpc_cert %s -grpc_key %s -grpc_ca %s -logtostderr -grpc_port %s -service_map grpc-vtgateservice", - vtRoot + "/bin/vtgateclienttest", cert, key, caCert, Integer.toString(port)); - System.out.println(vtgateCommand); - vtgateclienttest = new ProcessBuilder(vtgateCommand.split(" ")).inheritIO().start(); - } - - private static void createClientConnection() throws Exception { - final String keyStore = certDirectory.getCanonicalPath() + File.separatorChar + "client-keyStore.jks"; - - final TlsOptions tlsOptions = new TlsOptions() - .keyStorePath(keyStore) - .keyStorePassword("passwd") - .keyAlias("cert") - .trustStorePath(trustStore) - .trustStorePassword("passwd") - .trustAlias("cacert"); - - client = new GrpcClientFactory() - .createTls( - Context.getDefault().withDeadlineAfter(Duration.millis(5000)), - "localhost:" + port, - tlsOptions - ); - } + final ServerSocket socket = new ServerSocket(0); + port = socket.getLocalPort(); + socket.close(); + + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + "server-cert.pem"; + final String key = certDirectory.getCanonicalPath() + File.separatorChar + "server-key.pem"; + + final String vtgateCommand = String.format( + "%s -grpc_cert %s -grpc_key %s -grpc_ca %s -logtostderr -grpc_port %s -service_map grpc-vtgateservice", + vtRoot + "/bin/vtgateclienttest", cert, key, caCert, Integer.toString(port)); + System.out.println(vtgateCommand); + vtgateclienttest = new ProcessBuilder(vtgateCommand.split(" ")).inheritIO().start(); + } + + private static void createClientConnection() throws Exception { + final String keyStore = + certDirectory.getCanonicalPath() + File.separatorChar + "client-keyStore.jks"; + + final TlsOptions tlsOptions = new TlsOptions() + .keyStorePath(keyStore) + .keyStorePassword("passwd") + .keyAlias("cert") + .trustStorePath(trustStore) + .trustStorePassword("passwd") + .trustAlias("cacert"); + + client = new GrpcClientFactory() + .createTls( + Context.getDefault().withDeadlineAfter(Duration.millis(5000)), + "localhost:" + port, + tlsOptions + ); + } } diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsTest.java index e326ea8f00f..f0c44616de4 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientTlsTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,153 +16,165 @@ package io.client.grpc; +import com.google.common.io.Files; + +import io.vitess.client.Context; +import io.vitess.client.RpcClientTest; +import io.vitess.client.grpc.GrpcClientFactory; +import io.vitess.client.grpc.tls.TlsOptions; + +import org.joda.time.Duration; + import java.io.File; import java.io.IOException; import java.net.ServerSocket; import java.nio.file.Paths; -import org.joda.time.Duration; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -import com.google.common.io.Files; - -import io.vitess.client.Context; -import io.vitess.client.RpcClientTest; -import io.vitess.client.grpc.GrpcClientFactory; -import io.vitess.client.grpc.tls.TlsOptions; - /** - * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest), over an SSL connection. + * This tests GrpcClient with a mock vtgate server (go/cmd/vtgateclienttest), over an SSL + * connection. * * The SSL setup is adapted from "test/encrypted_transport.py" */ @RunWith(JUnit4.class) public class GrpcClientTlsTest extends RpcClientTest { - private static Process vtgateclienttest; - private static int port; - private static File certDirectory; + private static Process vtgateclienttest; + private static int port; + private static File certDirectory; - private static String caConfig; - private static String caKey; - private static String caCert; - private static String caCertDer; - private static String trustStore; + private static String caConfig; + private static String caKey; + private static String caCert; + private static String caCertDer; + private static String trustStore; - @BeforeClass - public static void setUpBeforeClass() throws Exception { - certDirectory = Files.createTempDir(); - System.out.println("Using cert directory: " + certDirectory.getCanonicalPath()); + @BeforeClass + public static void setUpBeforeClass() throws Exception { + certDirectory = Files.createTempDir(); + System.out.println("Using cert directory: " + certDirectory.getCanonicalPath()); - caConfig = certDirectory.getCanonicalPath() + File.separatorChar + "ca.config"; - caKey = certDirectory.getCanonicalPath() + File.separatorChar + "ca-key.pem"; - caCert = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.pem"; - caCertDer = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.der"; - trustStore = certDirectory.getCanonicalPath() + File.separatorChar + "ca-trustStore.jks"; + caConfig = certDirectory.getCanonicalPath() + File.separatorChar + "ca.config"; + caKey = certDirectory.getCanonicalPath() + File.separatorChar + "ca-key.pem"; + caCert = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.pem"; + caCertDer = certDirectory.getCanonicalPath() + File.separatorChar + "ca-cert.der"; + trustStore = certDirectory.getCanonicalPath() + File.separatorChar + "ca-trustStore.jks"; - createCA(); - createTrustStore(); + createCA(); + createTrustStore(); - createSignedCert("01", "server"); + createSignedCert("01", "server"); - startVtgate(); - createClientConnection(); - } + startVtgate(); + createClientConnection(); + } - @AfterClass - public static void tearDownAfterClass() throws Exception { - if (client != null) { - client.close(); - } - if (vtgateclienttest != null) { - vtgateclienttest.destroy(); - vtgateclienttest.waitFor(); - } + @AfterClass + public static void tearDownAfterClass() throws Exception { + if (client != null) { + client.close(); } - - private static void runProcess(final String command) throws IOException, InterruptedException { - System.out.println("\nExecuting: " + command); - int exitCode = new ProcessBuilder().inheritIO().command(command.split(" ")).start().waitFor(); - System.out.println("Exit code: " + exitCode + "\n"); + if (vtgateclienttest != null) { + vtgateclienttest.destroy(); + vtgateclienttest.waitFor(); } - - private static void createCA() throws Exception { - java.nio.file.Files.copy( - GrpcClientTlsTest.class.getResourceAsStream("/ca.config"), - Paths.get(caConfig) - ); - - final String createKey = String.format("openssl genrsa -out %s 2048", caKey); - runProcess(createKey); - - final String createCert = String.format("openssl req -new -x509 -nodes -days 3600 -batch -config %s -key %s -out %s", caConfig, caKey, caCert); - runProcess(createCert); + } + + private static void runProcess(final String command) throws IOException, InterruptedException { + System.out.println("\nExecuting: " + command); + int exitCode = new ProcessBuilder().inheritIO().command(command.split(" ")).start().waitFor(); + System.out.println("Exit code: " + exitCode + "\n"); + } + + private static void createCA() throws Exception { + java.nio.file.Files.copy( + GrpcClientTlsTest.class.getResourceAsStream("/ca.config"), + Paths.get(caConfig) + ); + + final String createKey = String.format("openssl genrsa -out %s 2048", caKey); + runProcess(createKey); + + final String createCert = String + .format("openssl req -new -x509 -nodes -days 3600 -batch -config %s -key %s -out %s", + caConfig, caKey, caCert); + runProcess(createCert); + } + + private static void createTrustStore() throws Exception { + final String convertCaCert = String + .format("openssl x509 -outform der -in %s -out %s", caCert, caCertDer); + runProcess(convertCaCert); + + final String createTrustStore = String.format( + "keytool -import -alias cacert -keystore %s -file %s -storepass passwd -trustcacerts -noprompt", + trustStore, caCertDer); + runProcess(createTrustStore); + } + + private static void createSignedCert(final String serial, final String name) throws Exception { + final String certConfig = certDirectory.getCanonicalPath() + File.separatorChar + "cert.config"; + if (!(new File(certConfig)).exists()) { + java.nio.file.Files.copy( + GrpcClientTlsTest.class.getResourceAsStream("/cert.config"), + Paths.get(certConfig) + ); } - - private static void createTrustStore() throws Exception { - final String convertCaCert = String.format("openssl x509 -outform der -in %s -out %s", caCert, caCertDer); - runProcess(convertCaCert); - - final String createTrustStore = String.format("keytool -import -alias cacert -keystore %s -file %s -storepass passwd -trustcacerts -noprompt", trustStore, caCertDer); - runProcess(createTrustStore); - } - - private static void createSignedCert(final String serial, final String name) throws Exception { - final String certConfig = certDirectory.getCanonicalPath() + File.separatorChar + "cert.config"; - if (!(new File(certConfig)).exists()) { - java.nio.file.Files.copy( - GrpcClientTlsTest.class.getResourceAsStream("/cert.config"), - Paths.get(certConfig) - ); - } - final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; - final String req = certDirectory.getCanonicalPath() + File.separatorChar + name + "-req.pem"; - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; - - final String createKeyAndCSR = String.format("openssl req -newkey rsa:2048 -days 3600 -nodes -batch -config %s -keyout %s -out %s", certConfig, key, req); - runProcess(createKeyAndCSR); - - final String signKey = String.format("openssl x509 -req -in %s -days 3600 -CA %s -CAkey %s -set_serial %s -out %s", req, caCert, caKey, serial, cert); - runProcess(signKey); + final String key = certDirectory.getCanonicalPath() + File.separatorChar + name + "-key.pem"; + final String req = certDirectory.getCanonicalPath() + File.separatorChar + name + "-req.pem"; + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + name + "-cert.pem"; + + final String createKeyAndCSR = String.format( + "openssl req -newkey rsa:2048 -days 3600 -nodes -batch -config %s -keyout %s -out %s", + certConfig, key, req); + runProcess(createKeyAndCSR); + + final String signKey = String + .format("openssl x509 -req -in %s -days 3600 -CA %s -CAkey %s -set_serial %s -out %s", req, + caCert, caKey, serial, cert); + runProcess(signKey); + } + + private static void startVtgate() throws Exception { + final String vtRoot = System.getenv("VTROOT"); + if (vtRoot == null) { + throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); } - - private static void startVtgate() throws Exception { - final String vtRoot = System.getenv("VTROOT"); - if (vtRoot == null) { - throw new RuntimeException("cannot find env variable VTROOT; make sure to source dev.env"); - } - final ServerSocket socket = new ServerSocket(0); - port = socket.getLocalPort(); - socket.close(); - - final String cert = certDirectory.getCanonicalPath() + File.separatorChar + "server-cert.pem"; - final String key = certDirectory.getCanonicalPath() + File.separatorChar + "server-key.pem"; - - final String vtgate = String.format("%s -grpc_cert %s -grpc_key %s -logtostderr -grpc_port %s -service_map grpc-vtgateservice", - vtRoot + "/bin/vtgateclienttest", - cert, - key, - Integer.toString(port) + final ServerSocket socket = new ServerSocket(0); + port = socket.getLocalPort(); + socket.close(); + + final String cert = certDirectory.getCanonicalPath() + File.separatorChar + "server-cert.pem"; + final String key = certDirectory.getCanonicalPath() + File.separatorChar + "server-key.pem"; + + final String vtgate = String.format( + "%s -grpc_cert %s -grpc_key %s -logtostderr -grpc_port %s -service_map grpc-vtgateservice", + vtRoot + "/bin/vtgateclienttest", + cert, + key, + Integer.toString(port) + ); + System.out.println(vtgate); + vtgateclienttest = new ProcessBuilder().inheritIO().command(vtgate.split(" ")).start(); + } + + private static void createClientConnection() throws Exception { + final TlsOptions tlsOptions = new TlsOptions() + .trustStorePath(trustStore) + .trustStorePassword("passwd") + .trustAlias("cacert"); + + client = new GrpcClientFactory() + .createTls( + Context.getDefault().withDeadlineAfter(Duration.millis(5000)), + "localhost:" + port, + tlsOptions ); - System.out.println(vtgate); - vtgateclienttest = new ProcessBuilder().inheritIO().command(vtgate.split(" ")).start(); - } - - private static void createClientConnection() throws Exception { - final TlsOptions tlsOptions = new TlsOptions() - .trustStorePath(trustStore) - .trustStorePassword("passwd") - .trustAlias("cacert"); - - client = new GrpcClientFactory() - .createTls( - Context.getDefault().withDeadlineAfter(Duration.millis(5000)), - "localhost:" + port, - tlsOptions - ); - } + } } diff --git a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientWithRetriesTest.java b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientWithRetriesTest.java index ab66d6f9bdf..92164de28ac 100644 --- a/java/grpc-client/src/test/java/io/client/grpc/GrpcClientWithRetriesTest.java +++ b/java/grpc-client/src/test/java/io/client/grpc/GrpcClientWithRetriesTest.java @@ -1,18 +1,20 @@ package io.client.grpc; +import io.vitess.client.Context; +import io.vitess.client.RpcClientTest; +import io.vitess.client.grpc.GrpcClientFactory; +import io.vitess.client.grpc.RetryingInterceptorConfig; + +import org.joda.time.Duration; + import java.net.ServerSocket; import java.util.Arrays; -import org.joda.time.Duration; import org.junit.AfterClass; import org.junit.BeforeClass; -import io.vitess.client.Context; -import io.vitess.client.RpcClientTest; -import io.vitess.client.grpc.GrpcClientFactory; -import io.vitess.client.grpc.RetryingInterceptorConfig; - public class GrpcClientWithRetriesTest extends RpcClientTest { + private static Process vtgateclienttest; private static int port; @@ -39,7 +41,6 @@ public static void setUpBeforeClass() throws Exception { .inheritIO() .start(); - client = new GrpcClientFactory(RetryingInterceptorConfig.exponentialConfig(5, 60, 2)) .create( diff --git a/java/grpc-client/src/test/java/io/vitess/client/grpc/RetryingInterceptorTest.java b/java/grpc-client/src/test/java/io/vitess/client/grpc/RetryingInterceptorTest.java index 757e77b1926..9e325c7de68 100644 --- a/java/grpc-client/src/test/java/io/vitess/client/grpc/RetryingInterceptorTest.java +++ b/java/grpc-client/src/test/java/io/vitess/client/grpc/RetryingInterceptorTest.java @@ -1,13 +1,5 @@ package io.vitess.client.grpc; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.TimeUnit; - -import javax.annotation.Nullable; - -import org.junit.Assert; -import org.junit.Test; - import com.google.common.util.concurrent.ListenableFuture; import io.grpc.CallOptions; @@ -22,15 +14,26 @@ import io.vitess.proto.Vtgate; import io.vitess.proto.grpc.VitessGrpc; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import javax.annotation.Nullable; + +import org.junit.Assert; +import org.junit.Test; + public class RetryingInterceptorTest { @Test public void testNoopConfigPassesThrough() throws ExecutionException, InterruptedException { ForceRetryNTimesInterceptor forceRetryNTimesInterceptor = new ForceRetryNTimesInterceptor(3); - ManagedChannel channel = InProcessChannelBuilder.forName("foo").intercept(new RetryingInterceptor(RetryingInterceptorConfig.noOpConfig()), forceRetryNTimesInterceptor).build(); + ManagedChannel channel = InProcessChannelBuilder.forName("foo") + .intercept(new RetryingInterceptor(RetryingInterceptorConfig.noOpConfig()), + forceRetryNTimesInterceptor).build(); VitessGrpc.VitessFutureStub stub = VitessGrpc.newFutureStub(channel); - ListenableFuture resp = stub.execute(Vtgate.ExecuteRequest.getDefaultInstance()); + ListenableFuture resp = stub + .execute(Vtgate.ExecuteRequest.getDefaultInstance()); try { resp.get(); Assert.fail("Should have failed after 1 attempt"); @@ -42,10 +45,14 @@ public void testNoopConfigPassesThrough() throws ExecutionException, Interrupted @Test public void testRetryAfterBackoff() throws ExecutionException, InterruptedException { ForceRetryNTimesInterceptor forceRetryNTimesInterceptor = new ForceRetryNTimesInterceptor(3); - RetryingInterceptorConfig retryingInterceptorConfig = RetryingInterceptorConfig.exponentialConfig(5, 60, 2); - ManagedChannel channel = InProcessChannelBuilder.forName("foo").intercept(forceRetryNTimesInterceptor, new RetryingInterceptor(retryingInterceptorConfig)).build(); + RetryingInterceptorConfig retryingInterceptorConfig = RetryingInterceptorConfig + .exponentialConfig(5, 60, 2); + ManagedChannel channel = InProcessChannelBuilder.forName("foo") + .intercept(forceRetryNTimesInterceptor, new RetryingInterceptor(retryingInterceptorConfig)) + .build(); VitessGrpc.VitessFutureStub stub = VitessGrpc.newFutureStub(channel); - ListenableFuture resp = stub.execute(Vtgate.ExecuteRequest.getDefaultInstance()); + ListenableFuture resp = stub + .execute(Vtgate.ExecuteRequest.getDefaultInstance()); try { resp.get(); Assert.fail("Should have failed after 3 attempt"); @@ -58,10 +65,15 @@ public void testRetryAfterBackoff() throws ExecutionException, InterruptedExcept @Test public void testRetryDeadlineExceeded() throws ExecutionException, InterruptedException { ForceRetryNTimesInterceptor forceRetryNTimesInterceptor = new ForceRetryNTimesInterceptor(3); - RetryingInterceptorConfig retryingInterceptorConfig = RetryingInterceptorConfig.exponentialConfig(5, 60, 2); - ManagedChannel channel = InProcessChannelBuilder.forName("foo").intercept(forceRetryNTimesInterceptor, new RetryingInterceptor(retryingInterceptorConfig)).build(); - VitessGrpc.VitessFutureStub stub = VitessGrpc.newFutureStub(channel).withDeadlineAfter(1, TimeUnit.MILLISECONDS); - ListenableFuture resp = stub.execute(Vtgate.ExecuteRequest.getDefaultInstance()); + RetryingInterceptorConfig retryingInterceptorConfig = RetryingInterceptorConfig + .exponentialConfig(5, 60, 2); + ManagedChannel channel = InProcessChannelBuilder.forName("foo") + .intercept(forceRetryNTimesInterceptor, new RetryingInterceptor(retryingInterceptorConfig)) + .build(); + VitessGrpc.VitessFutureStub stub = VitessGrpc.newFutureStub(channel) + .withDeadlineAfter(1, TimeUnit.MILLISECONDS); + ListenableFuture resp = stub + .execute(Vtgate.ExecuteRequest.getDefaultInstance()); try { resp.get(); Assert.fail("Should have failed"); @@ -85,7 +97,8 @@ int getNumRetryableFailures() { } @Override - public ClientCall interceptCall(MethodDescriptor method, CallOptions callOptions, Channel next) { + public ClientCall interceptCall(MethodDescriptor method, + CallOptions callOptions, Channel next) { System.out.println("Num failures: " + numRetryableFailures); if (numRetryableFailures < timesToForceRetry) { From 5ee78a5c0c27d655c30a9687916c2e1d79a8e8cf Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Wed, 6 Feb 2019 13:25:45 -0500 Subject: [PATCH 027/196] vitess-hadoop: checkstyle Signed-off-by: Ze'ev Klapow --- .../vitess/client/grpc/GrpcClientFactory.java | 6 +-- .../java/io/vitess/hadoop/RowWritable.java | 19 +++++--- .../java/io/vitess/hadoop/VitessConf.java | 15 ++++--- .../io/vitess/hadoop/VitessInputFormat.java | 39 ++++++++-------- .../io/vitess/hadoop/VitessInputSplit.java | 14 +++--- .../io/vitess/hadoop/VitessRecordReader.java | 44 ++++++++++--------- .../java/io/vitess/hadoop/MapReduceIT.java | 35 ++++++++------- 7 files changed, 97 insertions(+), 75 deletions(-) diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 19524061faa..92847bde42f 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -102,9 +102,9 @@ public RpcClient create(Context ctx, String target) { } /** - *

This method constructs NettyChannelBuilder object that will be used to create - * RpcClient.

- *

Subclasses may override this method to make adjustments to the builder

+ * This method constructs NettyChannelBuilder object that will be used to create + * RpcClient. + * Subclasses may override this method to make adjustments to the builder * for example: * * diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java b/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java index d8377fcb3d2..d349d8ae550 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -19,9 +19,13 @@ import com.google.common.collect.Lists; import com.google.common.io.BaseEncoding; import com.google.gson.Gson; + import io.vitess.client.cursor.Row; import io.vitess.proto.Query; import io.vitess.proto.Query.Field; + +import org.apache.hadoop.io.Writable; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; @@ -29,12 +33,13 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.apache.hadoop.io.Writable; public class RowWritable implements Writable { + private Row row; - public RowWritable() {} + public RowWritable() { + } public RowWritable(Row row) { this.row = row; @@ -76,8 +81,8 @@ public String toString() { if (!map.containsKey(key)) { try { map.put(key, row.getRawValue(i + 1).toStringUtf8()); - } catch (SQLException e) { - map.put(key, e.toString()); + } catch (SQLException exc) { + map.put(key, exc.toString()); } } } diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/VitessConf.java b/java/hadoop/src/main/java/io/vitess/hadoop/VitessConf.java index 19cf26e81e4..c70c4b22f01 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/VitessConf.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/VitessConf.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -19,13 +19,16 @@ import io.vitess.client.RpcClientFactory; import io.vitess.proto.Query; import io.vitess.proto.Query.SplitQueryRequest; -import java.util.Collection; + import org.apache.hadoop.conf.Configuration; +import java.util.Collection; + /** * Collection of configuration properties used for {@link VitessInputFormat} */ public class VitessConf { + public static final String HOSTS = "vitess.client.hosts"; public static final String CONN_TIMEOUT_MS = "vitess.client.conn_timeout_ms"; public static final String INPUT_KEYSPACE = "vitess.client.keyspace"; @@ -108,7 +111,9 @@ public void setAlgorithm(SplitQueryRequest.Algorithm algorithm) { conf.setEnum(ALGORITHM, algorithm); } - public String getRpcFactoryClass() { return conf.get(RPC_FACTORY_CLASS); } + public String getRpcFactoryClass() { + return conf.get(RPC_FACTORY_CLASS); + } public void setRpcFactoryClass(Class clz) { conf.set(RPC_FACTORY_CLASS, clz.getName()); diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java b/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java index 62cd1ca4b12..97d06b845a1 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -18,12 +18,14 @@ import static com.google.common.base.Preconditions.checkNotNull; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Random; +import com.google.common.collect.Lists; + +import io.vitess.client.Context; +import io.vitess.client.RpcClient; +import io.vitess.client.RpcClientFactory; +import io.vitess.client.VTGateBlockingConn; +import io.vitess.proto.Query.SplitQueryRequest.Algorithm; +import io.vitess.proto.Vtgate.SplitQueryResponse; import org.apache.hadoop.io.NullWritable; import org.apache.hadoop.mapreduce.InputFormat; @@ -32,16 +34,15 @@ import org.apache.hadoop.mapreduce.JobContext; import org.apache.hadoop.mapreduce.RecordReader; import org.apache.hadoop.mapreduce.TaskAttemptContext; -import org.joda.time.Duration; -import com.google.common.collect.Lists; +import org.joda.time.Duration; -import io.vitess.client.Context; -import io.vitess.client.RpcClient; -import io.vitess.client.RpcClientFactory; -import io.vitess.client.VTGateBlockingConn; -import io.vitess.proto.Query.SplitQueryRequest.Algorithm; -import io.vitess.proto.Vtgate.SplitQueryResponse; +import java.io.IOException; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Random; /** * {@link VitessInputFormat} is the {@link org.apache.hadoop.mapreduce.InputFormat} for tables in @@ -77,8 +78,8 @@ public List getSplits(JobContext context) { conf.getAlgorithm()); } } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | SQLException - | IOException e) { - throw new RuntimeException(e); + | IOException exc) { + throw new RuntimeException(exc); } List splits = Lists.newArrayList(); diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputSplit.java b/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputSplit.java index 1dbf0d40caa..e32edf4c9fc 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputSplit.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputSplit.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,14 +17,18 @@ package io.vitess.hadoop; import com.google.common.io.BaseEncoding; + import io.vitess.proto.Vtgate.SplitQueryResponse; + +import org.apache.hadoop.io.Writable; +import org.apache.hadoop.mapreduce.InputSplit; + import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; -import org.apache.hadoop.io.Writable; -import org.apache.hadoop.mapreduce.InputSplit; public class VitessInputSplit extends InputSplit implements Writable { + private String[] locations; private SplitQueryResponse.Part split; diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/VitessRecordReader.java b/java/hadoop/src/main/java/io/vitess/hadoop/VitessRecordReader.java index 221f7f1e14d..e8b83d9d6ce 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/VitessRecordReader.java +++ b/java/hadoop/src/main/java/io/vitess/hadoop/VitessRecordReader.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,18 +16,6 @@ package io.vitess.hadoop; -import java.io.IOException; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.List; -import java.util.Random; - -import org.apache.hadoop.io.NullWritable; -import org.apache.hadoop.mapreduce.InputSplit; -import org.apache.hadoop.mapreduce.RecordReader; -import org.apache.hadoop.mapreduce.TaskAttemptContext; -import org.joda.time.Duration; - import io.vitess.client.Context; import io.vitess.client.RpcClient; import io.vitess.client.RpcClientFactory; @@ -39,7 +27,21 @@ import io.vitess.proto.Topodata.TabletType; import io.vitess.proto.Vtgate.SplitQueryResponse; +import org.apache.hadoop.io.NullWritable; +import org.apache.hadoop.mapreduce.InputSplit; +import org.apache.hadoop.mapreduce.RecordReader; +import org.apache.hadoop.mapreduce.TaskAttemptContext; + +import org.joda.time.Duration; + +import java.io.IOException; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + public class VitessRecordReader extends RecordReader { + private VitessInputSplit split; private VTGateBlockingConn vtgate; private VitessConf conf; @@ -68,8 +70,8 @@ public void initialize(InputSplit split, TaskAttemptContext context) addressList.get(index)); vtgate = new VTGateBlockingConn(rpcClient); includedFields = conf.getIncludedFields(); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { - throw new RuntimeException(e); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException exc) { + throw new RuntimeException(exc); } } @@ -79,8 +81,8 @@ public void close() throws IOException { try { vtgate.close(); vtgate = null; - } catch (IOException e) { - throw new RuntimeException(e); + } catch (IOException exc) { + throw new RuntimeException(exc); } } } @@ -134,8 +136,8 @@ public boolean nextKeyValue() throws IOException, InterruptedException { } else { currentRow = new RowWritable(row); } - } catch (SQLException e) { - throw new RuntimeException(e); + } catch (SQLException exc) { + throw new RuntimeException(exc); } if (currentRow == null) { diff --git a/java/hadoop/src/test/java/io/vitess/hadoop/MapReduceIT.java b/java/hadoop/src/test/java/io/vitess/hadoop/MapReduceIT.java index 36ebe85c69b..5ee19911543 100644 --- a/java/hadoop/src/test/java/io/vitess/hadoop/MapReduceIT.java +++ b/java/hadoop/src/test/java/io/vitess/hadoop/MapReduceIT.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -19,18 +19,11 @@ import com.google.common.collect.ImmutableList; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; + import io.vitess.client.TestEnv; import io.vitess.client.TestUtil; import io.vitess.proto.Query.SplitQueryRequest.Algorithm; -import java.io.IOException; -import java.lang.reflect.Type; -import java.sql.SQLException; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import junit.extensions.TestSetup; -import junit.framework.TestSuite; + import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileSystem; import org.apache.hadoop.fs.Path; @@ -43,17 +36,26 @@ import org.apache.hadoop.mapreduce.Reducer; import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat; import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import junit.extensions.TestSetup; +import junit.framework.TestSuite; import vttest.Vttest.Keyspace; import vttest.Vttest.Shard; import vttest.Vttest.VTTestTopology; - /** * Integration tests for MapReductions in Vitess. These tests use an in-process Hadoop cluster via * {@link HadoopTestCase}. These tests are JUnit3 style because of this dependency. Vitess setup for * these tests require at least one rdonly instance per shard. - * */ public class MapReduceIT extends HadoopTestCase { @@ -114,7 +116,8 @@ public void testDumpTableToHDFS() throws Exception { // Rows are written as JSON since this is TextOutputFormat. String rowJson = parts[1]; - Type mapType = new TypeToken>() {}.getType(); + Type mapType = new TypeToken>() { + }.getType(); @SuppressWarnings("unchecked") Map map = (Map) gson.fromJson(rowJson, mapType); actualNames.add(map.get("name")); @@ -185,6 +188,7 @@ public void testReducerAggregateRows() throws Exception { public static class TableMapper extends Mapper { + @Override public void map(NullWritable key, RowWritable value, Context context) throws IOException, InterruptedException { @@ -199,6 +203,7 @@ public void map(NullWritable key, RowWritable value, Context context) public static class CountReducer extends Reducer { + @Override public void reduce(IntWritable key, Iterable values, Context context) throws IOException, InterruptedException { From fb4a797e61c61002725bb32a69f6773e7f1a44b8 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Wed, 6 Feb 2019 17:20:47 -0500 Subject: [PATCH 028/196] jdbc: parial checkstyle conversion Signed-off-by: Ze'ev Klapow --- java/checkstyle-suppression.xml | 6 +- .../vitess/client/grpc/GrpcClientFactory.java | 10 +- .../io/vitess/jdbc/ConnectionProperties.java | 1421 ++++---- .../java/io/vitess/jdbc/DBProperties.java | 74 +- .../io/vitess/jdbc/FieldWithMetadata.java | 1086 +++--- .../java/io/vitess/jdbc/VitessConnection.java | 1541 ++++---- .../vitess/jdbc/VitessDatabaseMetaData.java | 1044 +++--- .../java/io/vitess/jdbc/VitessDriver.java | 174 +- .../java/io/vitess/jdbc/VitessJDBCUrl.java | 396 +- .../jdbc/VitessMariaDBDatabaseMetadata.java | 986 +++-- .../jdbc/VitessMySQLDatabaseMetadata.java | 3233 ++++++++--------- .../vitess/jdbc/VitessParameterMetaData.java | 159 +- .../vitess/jdbc/VitessPreparedStatement.java | 1610 ++++---- .../java/io/vitess/jdbc/VitessResultSet.java | 2760 +++++++------- .../vitess/jdbc/VitessResultSetMetaData.java | 619 ++-- .../java/io/vitess/jdbc/VitessStatement.java | 1330 ++++--- .../io/vitess/jdbc/VitessVTGateManager.java | 358 +- .../main/java/io/vitess/util/CommonUtils.java | 50 +- .../main/java/io/vitess/util/Constants.java | 305 +- .../main/java/io/vitess/util/MysqlDefs.java | 894 ++--- .../main/java/io/vitess/util/StringUtils.java | 1653 +++++---- .../vitess/util/charset/CharsetMapping.java | 1068 +++--- .../io/vitess/util/charset/Collation.java | 50 +- .../io/vitess/util/charset/MysqlCharset.java | 193 +- .../test/java/io/vitess/jdbc/BaseTest.java | 43 +- .../vitess/jdbc/ConnectionPropertiesTest.java | 537 +-- .../io/vitess/jdbc/FieldWithMetadataTest.java | 1291 +++---- .../io/vitess/jdbc/VitessConnectionTest.java | 462 +-- .../jdbc/VitessDatabaseMetadataTest.java | 2804 +++++++------- .../java/io/vitess/jdbc/VitessDriverTest.java | 157 +- .../io/vitess/jdbc/VitessJDBCUrlTest.java | 461 +-- .../jdbc/VitessParameterMetaDataTest.java | 113 +- .../jdbc/VitessPreparedStatementTest.java | 1368 ++++--- .../jdbc/VitessResultSetMetadataTest.java | 1112 +++--- .../io/vitess/jdbc/VitessResultSetTest.java | 1348 +++---- .../io/vitess/jdbc/VitessStatementTest.java | 1286 ++++--- .../vitess/jdbc/VitessVTGateManagerTest.java | 125 +- .../java/io/vitess/util/StringUtilsTest.java | 88 +- 38 files changed, 16157 insertions(+), 16058 deletions(-) diff --git a/java/checkstyle-suppression.xml b/java/checkstyle-suppression.xml index 77906f6572a..ac41584523c 100644 --- a/java/checkstyle-suppression.xml +++ b/java/checkstyle-suppression.xml @@ -6,10 +6,14 @@ - + + + + + \ No newline at end of file diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 92847bde42f..25427c1b977 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -102,13 +102,13 @@ public RpcClient create(Context ctx, String target) { } /** - * This method constructs NettyChannelBuilder object that will be used to create - * RpcClient. - * Subclasses may override this method to make adjustments to the builder - * for example: + *

This method constructs NettyChannelBuilder object that will be used to create + * RpcClient.

+ *

Subclasses may override this method to make adjustments to the builder + * for example:

* * - * @Override + * {@literal @}Override * protected NettyChannelBuilder channelBuilder(String target) { * return super.channelBuilder(target) * .eventLoopGroup(new EpollEventLoopGroup()) diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java index f978311831e..5d172808395 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -34,797 +34,800 @@ public class ConnectionProperties { - private static final ArrayList PROPERTY_LIST = new ArrayList<>(); - - static { - try { - // Generate property list for use in dynamically filling out values from Properties objects in - // #initializeProperties below - java.lang.reflect.Field[] declaredFields = ConnectionProperties.class.getDeclaredFields(); - for (Field declaredField : declaredFields) { - if (ConnectionProperty.class.isAssignableFrom(declaredField.getType())) { - PROPERTY_LIST.add(declaredField); - } - } - Collections.sort(PROPERTY_LIST, new Comparator() { - @Override public int compare(Field o1, Field o2) { - return o1.getName().compareTo(o2.getName()); - } - }); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - // Configs for handling deserialization of blobs - private BooleanConnectionProperty blobsAreStrings = new BooleanConnectionProperty( - "blobsAreStrings", - "Should the driver always treat BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?", - false); - private BooleanConnectionProperty functionsNeverReturnBlobs = new BooleanConnectionProperty( - "functionsNeverReturnBlobs", - "Should the driver always treat data from functions returning BLOBs as Strings - specifically to work around dubious metadata returned by the server for GROUP BY clauses?", - false); - - // Configs for handing tinyint(1) - private BooleanConnectionProperty tinyInt1isBit = new BooleanConnectionProperty( - "tinyInt1isBit", - "Should the driver treat the datatype TINYINT(1) as the BIT type (because the server silently converts BIT -> TINYINT(1) when creating tables)?", - true); - private BooleanConnectionProperty yearIsDateType = new BooleanConnectionProperty( - "yearIsDateType", - "Should the JDBC driver treat the MySQL type \"YEAR\" as a java.sql.Date, or as a SHORT?", - true); - - private EnumConnectionProperty zeroDateTimeBehavior = new EnumConnectionProperty<>( - "zeroDateTimeBehavior", - "How should timestamps with format \"0000-00-00 00:00:00.0000\" be treated", - Constants.ZeroDateTimeBehavior.GARBLE); - - // Configs for handling irregular blobs, those with characters outside the typical 4-byte encodings - private BooleanConnectionProperty useBlobToStoreUTF8OutsideBMP = new BooleanConnectionProperty( - "useBlobToStoreUTF8OutsideBMP", - "Tells the driver to treat [MEDIUM/LONG]BLOB columns as [LONG]VARCHAR columns holding text encoded in UTF-8 that has characters outside the BMP (4-byte encodings), which MySQL server can't handle natively.", - false); - private StringConnectionProperty utf8OutsideBmpIncludedColumnNamePattern = new StringConnectionProperty( - "utf8OutsideBmpIncludedColumnNamePattern", - "Used to specify exclusion rules to \"utf8OutsideBmpExcludedColumnNamePattern\". The regex must follow the patterns used for the java.util.regex package.", - null, - null); - private StringConnectionProperty utf8OutsideBmpExcludedColumnNamePattern = new StringConnectionProperty( - "utf8OutsideBmpExcludedColumnNamePattern", - "When \"useBlobToStoreUTF8OutsideBMP\" is set to \"true\", column names matching the given regex will still be treated as BLOBs unless they match the regex specified for \"utf8OutsideBmpIncludedColumnNamePattern\". The regex must follow the patterns used for the java.util.regex package.", - null, - null); - - // Default encodings, for when one cannot be determined from field metadata - private StringConnectionProperty characterEncoding = new StringConnectionProperty( - "characterEncoding", - "If a character encoding cannot be detected, which fallback should be used when dealing with strings? (defaults is to 'autodetect')", - null, - null); - - // Vitess-specific configs - private StringConnectionProperty userName = new StringConnectionProperty( - Constants.Property.USERNAME, - "query will be executed via this user", - Constants.DEFAULT_USERNAME, - null); - private StringConnectionProperty target = new StringConnectionProperty( - Constants.Property.TARGET, - "Represents keyspace:shard@tabletType to be used to VTGates. keyspace, keyspace:shard, @tabletType all are optional.", - Constants.DEFAULT_TARGET, - null); - private StringConnectionProperty keyspace = new StringConnectionProperty( - Constants.Property.KEYSPACE, - "Targeted keyspace to execute queries on", - Constants.DEFAULT_KEYSPACE, - null); - private StringConnectionProperty catalog = new StringConnectionProperty( - Constants.Property.DBNAME, - "Database name in the keyspace", - Constants.DEFAULT_CATALOG, - null); - private StringConnectionProperty shard = new StringConnectionProperty( - Constants.Property.SHARD, - "Targeted shard in a given keyspace", - Constants.DEFAULT_SHARD, - null); - private EnumConnectionProperty tabletType = new EnumConnectionProperty<>( - Constants.Property.TABLET_TYPE, - "Tablet Type to which Vitess will connect(master, replica, rdonly)", - Constants.DEFAULT_TABLET_TYPE); - private EnumConnectionProperty oldTabletType = new EnumConnectionProperty<>( - Constants.Property.OLD_TABLET_TYPE, - "Deprecated Tablet Type to which Vitess will connect(master, replica, rdonly)", - Constants.DEFAULT_TABLET_TYPE); - private EnumConnectionProperty executeType = new EnumConnectionProperty<>( - Constants.Property.EXECUTE_TYPE, - "Query execution type: simple or stream", - Constants.DEFAULT_EXECUTE_TYPE); - private BooleanConnectionProperty twopcEnabled = new BooleanConnectionProperty( - Constants.Property.TWOPC_ENABLED, - "Whether to enable two-phased commit, for atomic distributed commits. See http://vitess.io/user-guide/twopc/", - false); - private EnumConnectionProperty includedFields = new EnumConnectionProperty<>( - Constants.Property.INCLUDED_FIELDS, - "What fields to return from MySQL to the Driver. Limiting the fields returned can improve performance, but ALL is required for maximum JDBC API support", - Constants.DEFAULT_INCLUDED_FIELDS); - private EnumConnectionProperty workload = new EnumConnectionProperty<>( - "workload", - "The workload type to use when executing queries", - Query.ExecuteOptions.Workload.UNSPECIFIED - ); - private BooleanConnectionProperty useAffectedRows = new BooleanConnectionProperty( - "useAffectedRows", - "Don't set the CLIENT_FOUND_ROWS flag when connecting to the server. The vitess default (useAffectedRows=true) is the opposite of mysql-connector-j.", - true); - - private BooleanConnectionProperty grpcRetriesEnabled = new BooleanConnectionProperty( - "grpcRetriesEnabled", - "If enabled, a gRPC interceptor will ensure retries happen in the case of TRANSIENT gRPC errors.", - true - ); - private LongConnectionProperty grpcRetryInitialBackoffMillis = new LongConnectionProperty( - "grpcRetriesInitialBackoffMillis", - "If grpcRetriesEnabled is set, what is the initial backoff time in milliseconds for exponential retry backoff.", - 10 - ); - private LongConnectionProperty grpcRetryMaxBackoffMillis = new LongConnectionProperty( - "grpcRetriesMaxBackoffMillis", - "If grpcRetriesEnabled is set, what is the maximum backoff time in milliseconds for exponential retry backoff. After this threshold, failures will propagate.", - TimeUnit.MINUTES.toMillis(2) - ); - private DoubleConnectionProperty grpcRetryBackoffMultiplier = new DoubleConnectionProperty( - "grpcRetriesBackoffMultiplier", - "If grpcRetriesEnabled is set, what multiplier should be used to increase exponential backoff on each retry.", - 1.6 - ); - // TLS-related configs - private BooleanConnectionProperty useSSL = new BooleanConnectionProperty( - Constants.Property.USE_SSL, - "Whether this connection should use transport-layer security", - false); - private BooleanConnectionProperty refreshConnection = new BooleanConnectionProperty( - "refreshConnection", - "When enabled, the driver will monitor for changes to the keystore and truststore files. If any are detected, SSL-enabled connections will be recreated.", - false); - private LongConnectionProperty refreshSeconds = new LongConnectionProperty( - "refreshSeconds", - "How often in seconds the driver will monitor for changes to the keystore and truststore files, when refreshConnection is enabled.", - 60); - private BooleanConnectionProperty refreshClosureDelayed = new BooleanConnectionProperty( - "refreshClosureDelayed", - "When enabled, the closing of the old connections will be delayed instead of happening instantly.", - false); - private LongConnectionProperty refreshClosureDelaySeconds = new LongConnectionProperty( - "refreshClosureDelaySeconds", - "How often in seconds the grace period before closing the old connections that had been recreated.", - 300); - private StringConnectionProperty keyStore = new StringConnectionProperty( - Constants.Property.KEYSTORE, - "The Java .JKS keystore file to use when TLS is enabled", - null, - null); - private StringConnectionProperty keyStorePassword = new StringConnectionProperty( - Constants.Property.KEYSTORE_PASSWORD, - "The password protecting the keystore file (if a password is set)", - null, - null); - private StringConnectionProperty keyAlias = new StringConnectionProperty( - Constants.Property.KEY_ALIAS, - "Alias under which the private key is stored in the keystore file (if not specified, then the " - + "first valid `PrivateKeyEntry` will be used)", - null, - null); - private StringConnectionProperty keyPassword = new StringConnectionProperty( - Constants.Property.KEY_PASSWORD, - "The additional password protecting the private key entry within the keystore file (if not " - + "specified, then the logic will fallback to the keystore password and then to no password at all)", - null, - null); - private StringConnectionProperty trustStore = new StringConnectionProperty( - Constants.Property.TRUSTSTORE, - "The Java .JKS truststore file to use when TLS is enabled", - null, - null); - private StringConnectionProperty trustStorePassword = new StringConnectionProperty( - Constants.Property.TRUSTSTORE_PASSWORD, - "The password protecting the truststore file (if a password is set)", - null, - null); - private StringConnectionProperty trustAlias = new StringConnectionProperty( - Constants.Property.TRUST_ALIAS, - "Alias under which the certficate chain is stored in the truststore file (if not specified, then " - + "the first valid `X509Certificate` will be used)", - null, - null); - - private BooleanConnectionProperty treatUtilDateAsTimestamp = new BooleanConnectionProperty( - "treatUtilDateAsTimestamp", - "Should the driver treat java.util.Date as a TIMESTAMP for the purposes of PreparedStatement.setObject()", - true); - - private LongConnectionProperty timeout = new LongConnectionProperty( - "timeout", - "The default timeout, in millis, to use for queries, connections, and transaction commit/rollback. Query timeout can be overridden by explicitly calling setQueryTimeout", - Constants.DEFAULT_TIMEOUT - ); - - // Caching of some hot properties to avoid casting over and over - private Topodata.TabletType tabletTypeCache; - private Query.ExecuteOptions.IncludedFields includedFieldsCache; - private Query.ExecuteOptions executeOptionsCache; - private boolean includeAllFieldsCache = true; - private boolean twopcEnabledCache = false; - private boolean simpleExecuteTypeCache = true; - private String characterEncodingAsString = null; - private String userNameCache; - - void initializeProperties(Properties props) throws SQLException { - Properties propsCopy = (Properties) props.clone(); - for (Field propertyField : PROPERTY_LIST) { - try { - ConnectionProperty propToSet = (ConnectionProperty) propertyField.get(this); - propToSet.initializeFrom(propsCopy); - } catch (IllegalAccessException iae) { - throw new SQLException("Unable to initialize driver properties due to " + iae.toString()); - } - } - postInitialization(); - checkConfiguredEncodingSupport(); - } - - private void postInitialization() { - this.tabletTypeCache = this.tabletType.getValueAsEnum(); - this.includedFieldsCache = this.includedFields.getValueAsEnum(); - this.includeAllFieldsCache = this.includedFieldsCache == Query.ExecuteOptions.IncludedFields.ALL; - this.twopcEnabledCache = this.twopcEnabled.getValueAsBoolean(); - this.simpleExecuteTypeCache = this.executeType.getValueAsEnum() == Constants.QueryExecuteType.SIMPLE; - this.characterEncodingAsString = this.characterEncoding.getValueAsString(); - this.userNameCache = this.userName.getValueAsString(); - - setExecuteOptions(); - } - - /** - * Attempt to use the encoding, and bail out if it can't be used - * @throws SQLException if exception occurs while attempting to use the encoding - */ - private void checkConfiguredEncodingSupport() throws SQLException { - if (characterEncodingAsString != null) { - try { - String testString = "abc"; - StringUtils.getBytes(testString, characterEncodingAsString); - } catch (UnsupportedEncodingException UE) { - throw new SQLException("Unsupported character encoding: " + characterEncodingAsString); - } - } - } - - static DriverPropertyInfo[] exposeAsDriverPropertyInfo(Properties info, int slotsToReserve) throws SQLException { - return new ConnectionProperties().exposeAsDriverPropertyInfoInternal(info, slotsToReserve); - } + private static final ArrayList PROPERTY_LIST = new ArrayList<>(); - private DriverPropertyInfo[] exposeAsDriverPropertyInfoInternal(Properties info, int slotsToReserve) throws SQLException { - initializeProperties(info); - int numProperties = PROPERTY_LIST.size(); - int listSize = numProperties + slotsToReserve; - DriverPropertyInfo[] driverProperties = new DriverPropertyInfo[listSize]; - - for (int i = slotsToReserve; i < listSize; i++) { - java.lang.reflect.Field propertyField = PROPERTY_LIST.get(i - slotsToReserve); - try { - ConnectionProperty propToExpose = (ConnectionProperty) propertyField.get(this); - if (info != null) { - propToExpose.initializeFrom(info); - } - driverProperties[i] = propToExpose.getAsDriverPropertyInfo(); - } catch (IllegalAccessException iae) { - throw new SQLException("Internal properties failure", iae); - } + static { + try { + // Generate property list for use in dynamically filling out values from Properties objects in + // #initializeProperties below + java.lang.reflect.Field[] declaredFields = ConnectionProperties.class.getDeclaredFields(); + for (Field declaredField : declaredFields) { + if (ConnectionProperty.class.isAssignableFrom(declaredField.getType())) { + PROPERTY_LIST.add(declaredField); } - return driverProperties; - } - - public boolean getBlobsAreStrings() { - return blobsAreStrings.getValueAsBoolean(); - } - - public void setBlobsAreStrings(boolean blobsAreStrings) { - this.blobsAreStrings.setValue(blobsAreStrings); - } - - public boolean getUseBlobToStoreUTF8OutsideBMP() { - return useBlobToStoreUTF8OutsideBMP.getValueAsBoolean(); - } - - public void setUseBlobToStoreUTF8OutsideBMP(boolean useBlobToStoreUTF8OutsideBMP) { - this.useBlobToStoreUTF8OutsideBMP.setValue(useBlobToStoreUTF8OutsideBMP); - } - - public boolean getTinyInt1isBit() { - return tinyInt1isBit.getValueAsBoolean(); - } - - public void setTinyInt1isBit(boolean tinyInt1isBit) { - this.tinyInt1isBit.setValue(tinyInt1isBit); - } - - public boolean getFunctionsNeverReturnBlobs() { - return functionsNeverReturnBlobs.getValueAsBoolean(); - } - - public void setFunctionsNeverReturnBlobs(boolean functionsNeverReturnBlobs) { - this.functionsNeverReturnBlobs.setValue(functionsNeverReturnBlobs); - } - - public String getUtf8OutsideBmpIncludedColumnNamePattern() { - return utf8OutsideBmpIncludedColumnNamePattern.getValueAsString(); - } - - public void setUtf8OutsideBmpIncludedColumnNamePattern(String pattern) { - this.utf8OutsideBmpIncludedColumnNamePattern.setValue(pattern); - } - - public String getUtf8OutsideBmpExcludedColumnNamePattern() { - return utf8OutsideBmpExcludedColumnNamePattern.getValueAsString(); - } - - public void setUtf8OutsideBmpExcludedColumnNamePattern(String pattern) { - this.utf8OutsideBmpExcludedColumnNamePattern.setValue(pattern); - } - - public Constants.ZeroDateTimeBehavior getZeroDateTimeBehavior() { - return zeroDateTimeBehavior.getValueAsEnum(); - } - - public boolean getYearIsDateType() { - return yearIsDateType.getValueAsBoolean(); - } + } + Collections.sort(PROPERTY_LIST, new Comparator() { + @Override + public int compare(Field o1, Field o2) { + return o1.getName().compareTo(o2.getName()); + } + }); + } catch (Exception ex) { + throw new RuntimeException(ex); + } + } + + // Configs for handling deserialization of blobs + private BooleanConnectionProperty blobsAreStrings = new BooleanConnectionProperty( + "blobsAreStrings", + "Should the driver always treat BLOBs as Strings - specifically to work around dubious " + + "metadata returned by the server for GROUP BY clauses?", + false); + private BooleanConnectionProperty functionsNeverReturnBlobs = new BooleanConnectionProperty( + "functionsNeverReturnBlobs", + "Should the driver always treat data from functions returning BLOBs as Strings - " + + "specifically to work around dubious metadata returned by the server for GROUP BY " + + "clauses?", + false); + + // Configs for handing tinyint(1) + private BooleanConnectionProperty tinyInt1isBit = new BooleanConnectionProperty("tinyInt1isBit", + "Should the driver treat the datatype TINYINT(1) as the BIT type (because the server " + + "silently converts BIT -> TINYINT(1) when creating tables)?", + true); + private BooleanConnectionProperty yearIsDateType = new BooleanConnectionProperty("yearIsDateType", + "Should the JDBC driver treat the MySQL type \"YEAR\" as a java.sql.Date, or as a SHORT?", + true); + + private EnumConnectionProperty zeroDateTimeBehavior = + new EnumConnectionProperty<>( + "zeroDateTimeBehavior", + "How should timestamps with format \"0000-00-00 00:00:00.0000\" be treated", + Constants.ZeroDateTimeBehavior.GARBLE); + + // Configs for handling irregular blobs, those with characters outside the typical 4-byte + // encodings + private BooleanConnectionProperty useBlobToStoreUTF8OutsideBMP = new BooleanConnectionProperty( + "useBlobToStoreUTF8OutsideBMP", + "Tells the driver to treat [MEDIUM/LONG]BLOB columns as [LONG]VARCHAR columns holding text " + + "encoded in UTF-8 that has characters outside the BMP (4-byte encodings), which MySQL" + + " server can't handle natively.", + false); + private StringConnectionProperty utf8OutsideBmpIncludedColumnNamePattern = + new StringConnectionProperty( + "utf8OutsideBmpIncludedColumnNamePattern", + "Used to specify exclusion rules to \"utf8OutsideBmpExcludedColumnNamePattern\". The regex " + + "must follow the patterns used for the java.util.regex package.", + null, null); + private StringConnectionProperty utf8OutsideBmpExcludedColumnNamePattern = + new StringConnectionProperty( + "utf8OutsideBmpExcludedColumnNamePattern", + "When \"useBlobToStoreUTF8OutsideBMP\" is set to \"true\", column names matching the given " + + "regex will still be treated as BLOBs unless they match the regex specified for " + + "\"utf8OutsideBmpIncludedColumnNamePattern\". The regex must follow the patterns used" + + " for the java.util.regex package.", + null, null); + + // Default encodings, for when one cannot be determined from field metadata + private StringConnectionProperty characterEncoding = new StringConnectionProperty( + "characterEncoding", + "If a character encoding cannot be detected, which fallback should be used when dealing " + + "with strings? (defaults is to 'autodetect')", + null, null); + + // Vitess-specific configs + private StringConnectionProperty userName = new StringConnectionProperty( + Constants.Property.USERNAME, "query will be executed via this user", + Constants.DEFAULT_USERNAME, null); + private StringConnectionProperty target = new StringConnectionProperty(Constants.Property.TARGET, + "Represents keyspace:shard@tabletType to be used to VTGates. keyspace, keyspace:shard, " + + "@tabletType all are optional.", + Constants.DEFAULT_TARGET, null); + private StringConnectionProperty keyspace = new StringConnectionProperty( + Constants.Property.KEYSPACE, "Targeted keyspace to execute queries on", + Constants.DEFAULT_KEYSPACE, null); + private StringConnectionProperty catalog = new StringConnectionProperty(Constants.Property.DBNAME, + "Database name in the keyspace", Constants.DEFAULT_CATALOG, null); + private StringConnectionProperty shard = new StringConnectionProperty(Constants.Property.SHARD, + "Targeted shard in a given keyspace", Constants.DEFAULT_SHARD, null); + private EnumConnectionProperty tabletType = new EnumConnectionProperty<>( + Constants.Property.TABLET_TYPE, + "Tablet Type to which Vitess will connect(master, replica, rdonly)", + Constants.DEFAULT_TABLET_TYPE); + private EnumConnectionProperty oldTabletType = new EnumConnectionProperty<>( + Constants.Property.OLD_TABLET_TYPE, + "Deprecated Tablet Type to which Vitess will connect(master, replica, rdonly)", + Constants.DEFAULT_TABLET_TYPE); + private EnumConnectionProperty executeType = + new EnumConnectionProperty<>( + Constants.Property.EXECUTE_TYPE, "Query execution type: simple or stream", + Constants.DEFAULT_EXECUTE_TYPE); + private BooleanConnectionProperty twopcEnabled = new BooleanConnectionProperty( + Constants.Property.TWOPC_ENABLED, + "Whether to enable two-phased commit, for atomic distributed commits. See http://vitess" + + ".io/user-guide/twopc/", + false); + private EnumConnectionProperty includedFields = + new EnumConnectionProperty<>( + Constants.Property.INCLUDED_FIELDS, + "What fields to return from MySQL to the Driver. Limiting the fields returned can improve " + + "performance, but ALL is required for maximum JDBC API support", + Constants.DEFAULT_INCLUDED_FIELDS); + private EnumConnectionProperty workload = + new EnumConnectionProperty<>( + "workload", "The workload type to use when executing queries", + Query.ExecuteOptions.Workload.UNSPECIFIED); + private BooleanConnectionProperty useAffectedRows = new BooleanConnectionProperty( + "useAffectedRows", + "Don't set the CLIENT_FOUND_ROWS flag when connecting to the server. The vitess default " + + "(useAffectedRows=true) is the opposite of mysql-connector-j.", + true); + + private BooleanConnectionProperty grpcRetriesEnabled = new BooleanConnectionProperty( + "grpcRetriesEnabled", + "If enabled, a gRPC interceptor will ensure retries happen in the case of TRANSIENT gRPC " + + "errors.", + true); + private LongConnectionProperty grpcRetryInitialBackoffMillis = new LongConnectionProperty( + "grpcRetriesInitialBackoffMillis", + "If grpcRetriesEnabled is set, what is the initial backoff time in milliseconds for " + + "exponential retry backoff.", + 10); + private LongConnectionProperty grpcRetryMaxBackoffMillis = new LongConnectionProperty( + "grpcRetriesMaxBackoffMillis", + "If grpcRetriesEnabled is set, what is the maximum backoff time in milliseconds for " + + "exponential retry backoff. After this threshold, failures will propagate.", + TimeUnit.MINUTES.toMillis(2)); + private DoubleConnectionProperty grpcRetryBackoffMultiplier = new DoubleConnectionProperty( + "grpcRetriesBackoffMultiplier", + "If grpcRetriesEnabled is set, what multiplier should be used to increase exponential " + + "backoff on each retry.", + 1.6); + // TLS-related configs + private BooleanConnectionProperty useSSL = new BooleanConnectionProperty( + Constants.Property.USE_SSL, "Whether this connection should use transport-layer security", + false); + private BooleanConnectionProperty refreshConnection = new BooleanConnectionProperty( + "refreshConnection", + "When enabled, the driver will monitor for changes to the keystore and truststore files. If" + + " any are detected, SSL-enabled connections will be recreated.", + false); + private LongConnectionProperty refreshSeconds = new LongConnectionProperty("refreshSeconds", + "How often in seconds the driver will monitor for changes to the keystore and truststore " + + "files, when refreshConnection is enabled.", + 60); + private BooleanConnectionProperty refreshClosureDelayed = new BooleanConnectionProperty( + "refreshClosureDelayed", + "When enabled, the closing of the old connections will be delayed instead of happening " + + "instantly.", + false); + private LongConnectionProperty refreshClosureDelaySeconds = new LongConnectionProperty( + "refreshClosureDelaySeconds", + "How often in seconds the grace period before closing the old connections that had been " + + "recreated.", + 300); + private StringConnectionProperty keyStore = new StringConnectionProperty( + Constants.Property.KEYSTORE, "The Java .JKS keystore file to use when TLS is enabled", null, + null); + private StringConnectionProperty keyStorePassword = new StringConnectionProperty( + Constants.Property.KEYSTORE_PASSWORD, + "The password protecting the keystore file (if a password is set)", null, null); + private StringConnectionProperty keyAlias = new StringConnectionProperty( + Constants.Property.KEY_ALIAS, + "Alias under which the private key is stored in the keystore file (if not specified, then " + + "the " + + "first valid `PrivateKeyEntry` will be used)", null, null); + private StringConnectionProperty keyPassword = new StringConnectionProperty( + Constants.Property.KEY_PASSWORD, + "The additional password protecting the private key entry within the keystore file (if not " + + "specified, then the logic will fallback to the keystore password and then to no " + + "password at all)", + null, null); + private StringConnectionProperty trustStore = new StringConnectionProperty( + Constants.Property.TRUSTSTORE, "The Java .JKS truststore file to use when TLS is enabled", + null, null); + private StringConnectionProperty trustStorePassword = new StringConnectionProperty( + Constants.Property.TRUSTSTORE_PASSWORD, + "The password protecting the truststore file (if a password is set)", null, null); + private StringConnectionProperty trustAlias = new StringConnectionProperty( + Constants.Property.TRUST_ALIAS, + "Alias under which the certficate chain is stored in the truststore file (if not specified," + + " then " + + "the first valid `X509Certificate` will be used)", null, null); + + private BooleanConnectionProperty treatUtilDateAsTimestamp = new BooleanConnectionProperty( + "treatUtilDateAsTimestamp", + "Should the driver treat java.util.Date as a TIMESTAMP for the purposes of " + + "PreparedStatement.setObject()", + true); + + private LongConnectionProperty timeout = new LongConnectionProperty("timeout", + "The default timeout, in millis, to use for queries, connections, and transaction " + + "commit/rollback. Query timeout can be overridden by explicitly calling " + + "setQueryTimeout", + Constants.DEFAULT_TIMEOUT); + + // Caching of some hot properties to avoid casting over and over + private Topodata.TabletType tabletTypeCache; + private Query.ExecuteOptions.IncludedFields includedFieldsCache; + private Query.ExecuteOptions executeOptionsCache; + private boolean includeAllFieldsCache = true; + private boolean twopcEnabledCache = false; + private boolean simpleExecuteTypeCache = true; + private String characterEncodingAsString = null; + private String userNameCache; + + void initializeProperties(Properties props) throws SQLException { + Properties propsCopy = (Properties) props.clone(); + for (Field propertyField : PROPERTY_LIST) { + try { + ConnectionProperty propToSet = (ConnectionProperty) propertyField.get(this); + propToSet.initializeFrom(propsCopy); + } catch (IllegalAccessException iae) { + throw new SQLException("Unable to initialize driver properties due to " + iae.toString()); + } + } + postInitialization(); + checkConfiguredEncodingSupport(); + } + + private void postInitialization() { + this.tabletTypeCache = this.tabletType.getValueAsEnum(); + this.includedFieldsCache = this.includedFields.getValueAsEnum(); + this.includeAllFieldsCache = + this.includedFieldsCache == Query.ExecuteOptions.IncludedFields.ALL; + this.twopcEnabledCache = this.twopcEnabled.getValueAsBoolean(); + this.simpleExecuteTypeCache = + this.executeType.getValueAsEnum() == Constants.QueryExecuteType.SIMPLE; + this.characterEncodingAsString = this.characterEncoding.getValueAsString(); + this.userNameCache = this.userName.getValueAsString(); + + setExecuteOptions(); + } + + /** + * Attempt to use the encoding, and bail out if it can't be used + * + * @throws SQLException if exception occurs while attempting to use the encoding + */ + private void checkConfiguredEncodingSupport() throws SQLException { + if (characterEncodingAsString != null) { + try { + String testString = "abc"; + StringUtils.getBytes(testString, characterEncodingAsString); + } catch (UnsupportedEncodingException UE) { + throw new SQLException("Unsupported character encoding: " + characterEncodingAsString); + } + } + } + + static DriverPropertyInfo[] exposeAsDriverPropertyInfo(Properties info, int slotsToReserve) + throws SQLException { + return new ConnectionProperties().exposeAsDriverPropertyInfoInternal(info, slotsToReserve); + } + + private DriverPropertyInfo[] exposeAsDriverPropertyInfoInternal(Properties info, + int slotsToReserve) throws SQLException { + initializeProperties(info); + int numProperties = PROPERTY_LIST.size(); + int listSize = numProperties + slotsToReserve; + DriverPropertyInfo[] driverProperties = new DriverPropertyInfo[listSize]; + + for (int i = slotsToReserve; i < listSize; i++) { + java.lang.reflect.Field propertyField = PROPERTY_LIST.get(i - slotsToReserve); + try { + ConnectionProperty propToExpose = (ConnectionProperty) propertyField.get(this); + if (info != null) { + propToExpose.initializeFrom(info); + } + driverProperties[i] = propToExpose.getAsDriverPropertyInfo(); + } catch (IllegalAccessException iae) { + throw new SQLException("Internal properties failure", iae); + } + } + return driverProperties; + } + + public boolean getBlobsAreStrings() { + return blobsAreStrings.getValueAsBoolean(); + } + + public void setBlobsAreStrings(boolean blobsAreStrings) { + this.blobsAreStrings.setValue(blobsAreStrings); + } + + public boolean getUseBlobToStoreUTF8OutsideBMP() { + return useBlobToStoreUTF8OutsideBMP.getValueAsBoolean(); + } + + public void setUseBlobToStoreUTF8OutsideBMP(boolean useBlobToStoreUTF8OutsideBMP) { + this.useBlobToStoreUTF8OutsideBMP.setValue(useBlobToStoreUTF8OutsideBMP); + } + + public boolean getTinyInt1isBit() { + return tinyInt1isBit.getValueAsBoolean(); + } + + public void setTinyInt1isBit(boolean tinyInt1isBit) { + this.tinyInt1isBit.setValue(tinyInt1isBit); + } + + public boolean getFunctionsNeverReturnBlobs() { + return functionsNeverReturnBlobs.getValueAsBoolean(); + } + + public void setFunctionsNeverReturnBlobs(boolean functionsNeverReturnBlobs) { + this.functionsNeverReturnBlobs.setValue(functionsNeverReturnBlobs); + } + + public String getUtf8OutsideBmpIncludedColumnNamePattern() { + return utf8OutsideBmpIncludedColumnNamePattern.getValueAsString(); + } + + public void setUtf8OutsideBmpIncludedColumnNamePattern(String pattern) { + this.utf8OutsideBmpIncludedColumnNamePattern.setValue(pattern); + } + + public String getUtf8OutsideBmpExcludedColumnNamePattern() { + return utf8OutsideBmpExcludedColumnNamePattern.getValueAsString(); + } + + public void setUtf8OutsideBmpExcludedColumnNamePattern(String pattern) { + this.utf8OutsideBmpExcludedColumnNamePattern.setValue(pattern); + } + + public Constants.ZeroDateTimeBehavior getZeroDateTimeBehavior() { + return zeroDateTimeBehavior.getValueAsEnum(); + } + + public boolean getYearIsDateType() { + return yearIsDateType.getValueAsBoolean(); + } + + public void setYearIsDateType(boolean yearIsDateType) { + this.yearIsDateType.setValue(yearIsDateType); + } + + public String getEncoding() { + return characterEncodingAsString; + } + + public void setEncoding(String encoding) { + this.characterEncoding.setValue(encoding); + this.characterEncodingAsString = this.characterEncoding.getValueAsString(); + } + + public Query.ExecuteOptions.IncludedFields getIncludedFields() { + return this.includedFieldsCache; + } + + public boolean isIncludeAllFields() { + return this.includeAllFieldsCache; + } + + public void setIncludedFields(Query.ExecuteOptions.IncludedFields includedFields) { + this.includedFields.setValue(includedFields); + this.includedFieldsCache = includedFields; + this.includeAllFieldsCache = includedFields == Query.ExecuteOptions.IncludedFields.ALL; + this.setExecuteOptions(); + } + + public Query.ExecuteOptions.Workload getWorkload() { + return this.workload.getValueAsEnum(); + } + + public void setWorkload(Query.ExecuteOptions.Workload workload) { + this.workload.setValue(workload); + setExecuteOptions(); + } + + public boolean getUseAffectedRows() { + return useAffectedRows.getValueAsBoolean(); + } + + public void setUseAffectedRows(boolean useAffectedRows) { + this.useAffectedRows.setValue(useAffectedRows); + setExecuteOptions(); + } + + private void setExecuteOptions() { + this.executeOptionsCache = Query.ExecuteOptions.newBuilder() + .setIncludedFields(getIncludedFields()).setWorkload(getWorkload()) + .setClientFoundRows(!getUseAffectedRows()).build(); + } + + public Query.ExecuteOptions getExecuteOptions() { + return this.executeOptionsCache; + } + + public boolean getTwopcEnabled() { + return twopcEnabledCache; + } + + public void setTwopcEnabled(boolean twopcEnabled) { + this.twopcEnabled.setValue(twopcEnabled); + this.twopcEnabledCache = this.twopcEnabled.getValueAsBoolean(); + } + + public Constants.QueryExecuteType getExecuteType() { + return executeType.getValueAsEnum(); + } + + public boolean isSimpleExecute() { + return simpleExecuteTypeCache; + } + + public void setExecuteType(Constants.QueryExecuteType executeType) { + this.executeType.setValue(executeType); + this.simpleExecuteTypeCache = + this.executeType.getValueAsEnum() == Constants.QueryExecuteType.SIMPLE; + } + + public Topodata.TabletType getTabletType() { + return tabletTypeCache; + } + + public void setTabletType(Topodata.TabletType tabletType) { + this.tabletType.setValue(tabletType); + this.tabletTypeCache = this.tabletType.getValueAsEnum(); + } + + public Boolean getGrpcRetriesEnabled() { + return grpcRetriesEnabled.getValueAsBoolean(); + } + + public void setGrpcRetriesEnabled(Boolean grpcRetriesEnabled) { + this.grpcRetriesEnabled.setValue(grpcRetriesEnabled); + } + + public Long getGrpcRetryInitialBackoffMillis() { + return grpcRetryInitialBackoffMillis.getValueAsLong(); + } + + public void setGrpcRetryInitialBackoffMillis(Long grpcRetryInitialBackoffMillis) { + this.grpcRetryInitialBackoffMillis.setValue(grpcRetryInitialBackoffMillis); + } + + public Long getGrpcRetryMaxBackoffMillis() { + return grpcRetryMaxBackoffMillis.getValueAsLong(); + } + + public void setGrpcRetryMaxBackoffMillis(Long grpcRetryMaxBackoffMillis) { + this.grpcRetryMaxBackoffMillis.setValue(grpcRetryMaxBackoffMillis); + } + + public Double getGrpcRetryBackoffMultiplier() { + return grpcRetryBackoffMultiplier.getValueAsDouble(); + } + + public void setGrpcRetryBackoffMultiplier(DoubleConnectionProperty grpcRetryBackoffMultiplier) { + this.grpcRetryBackoffMultiplier = grpcRetryBackoffMultiplier; + } + + public boolean getUseSSL() { + return useSSL.getValueAsBoolean(); + } + + public boolean getRefreshConnection() { + return refreshConnection.getValueAsBoolean(); + } + + public void setRefreshConnection(boolean refreshConnection) { + this.refreshConnection.setValue(refreshConnection); + } + + public long getRefreshSeconds() { + return refreshSeconds.getValueAsLong(); + } + + public void setRefreshSeconds(long refreshSeconds) { + this.refreshSeconds.setValue(refreshSeconds); + } + + public boolean getRefreshClosureDelayed() { + return refreshClosureDelayed.getValueAsBoolean(); + } + + public void setRefreshClosureDelayed(boolean refreshClosureDelayed) { + this.refreshClosureDelayed.setValue(refreshClosureDelayed); + } + + public long getRefreshClosureDelaySeconds() { + return refreshClosureDelaySeconds.getValueAsLong(); + } + + public void setRefreshClosureDelaySeconds(long refreshClosureDelaySeconds) { + this.refreshClosureDelaySeconds.setValue(refreshClosureDelaySeconds); + } + + public String getKeyStore() { + return keyStore.getValueAsString(); + } + + public String getKeyStorePassword() { + return keyStorePassword.getValueAsString(); + } + + public String getKeyAlias() { + return keyAlias.getValueAsString(); + } + + public String getKeyPassword() { + return keyPassword.getValueAsString(); + } - public void setYearIsDateType(boolean yearIsDateType) { - this.yearIsDateType.setValue(yearIsDateType); - } + public String getTrustStore() { + return trustStore.getValueAsString(); + } - public String getEncoding() { - return characterEncodingAsString; - } + public String getTrustStorePassword() { + return trustStorePassword.getValueAsString(); + } - public void setEncoding(String encoding) { - this.characterEncoding.setValue(encoding); - this.characterEncodingAsString = this.characterEncoding.getValueAsString(); - } + public String getTrustAlias() { + return trustAlias.getValueAsString(); + } - public Query.ExecuteOptions.IncludedFields getIncludedFields() { - return this.includedFieldsCache; - } + public boolean getTreatUtilDateAsTimestamp() { + return treatUtilDateAsTimestamp.getValueAsBoolean(); + } - public boolean isIncludeAllFields() { - return this.includeAllFieldsCache; - } + public void setTreatUtilDateAsTimestamp(boolean treatUtilDateAsTimestamp) { + this.treatUtilDateAsTimestamp.setValue(treatUtilDateAsTimestamp); + } - public void setIncludedFields(Query.ExecuteOptions.IncludedFields includedFields) { - this.includedFields.setValue(includedFields); - this.includedFieldsCache = includedFields; - this.includeAllFieldsCache = includedFields == Query.ExecuteOptions.IncludedFields.ALL; - this.setExecuteOptions(); - } + public long getTimeout() { + return timeout.getValueAsLong(); + } - public Query.ExecuteOptions.Workload getWorkload() { - return this.workload.getValueAsEnum(); - } + public void setTimeout(long timeout) { + this.timeout.setValue(timeout); + } - public void setWorkload(Query.ExecuteOptions.Workload workload) { - this.workload.setValue(workload); - setExecuteOptions(); + public String getTarget() { + if (!StringUtils.isNullOrEmptyWithoutWS(target.getValueAsString())) { + return target.getValueAsString(); } - - public boolean getUseAffectedRows() { - return useAffectedRows.getValueAsBoolean(); + String targetString = ""; + String keyspace = this.keyspace.getValueAsString(); + if (!StringUtils.isNullOrEmptyWithoutWS(keyspace)) { + targetString += keyspace; + String shard = this.shard.getValueAsString(); + if (!StringUtils.isNullOrEmptyWithoutWS(shard)) { + targetString += ":" + shard; + } } - - public void setUseAffectedRows(boolean useAffectedRows) { - this.useAffectedRows.setValue(useAffectedRows); - setExecuteOptions(); + String tabletType = this.tabletType.getValueAsEnum().name(); + if (!StringUtils.isNullOrEmptyWithoutWS(tabletType)) { + targetString += "@" + tabletType.toLowerCase(); } + return targetString; + } - private void setExecuteOptions() { - this.executeOptionsCache = Query.ExecuteOptions.newBuilder() - .setIncludedFields(getIncludedFields()) - .setWorkload(getWorkload()) - .setClientFoundRows(!getUseAffectedRows()) - .build(); - } + @Deprecated + protected String getKeyspace() { + return this.keyspace.getValueAsString(); + } - public Query.ExecuteOptions getExecuteOptions() { - return this.executeOptionsCache; - } + protected void setCatalog(String catalog) throws SQLException { + this.catalog.setValue(catalog); + } - public boolean getTwopcEnabled() { - return twopcEnabledCache; - } + protected String getCatalog() throws SQLException { + return this.catalog.getValueAsString(); + } - public void setTwopcEnabled(boolean twopcEnabled) { - this.twopcEnabled.setValue(twopcEnabled); - this.twopcEnabledCache = this.twopcEnabled.getValueAsBoolean(); - } + protected String getUsername() { + return this.userNameCache; + } - public Constants.QueryExecuteType getExecuteType() { - return executeType.getValueAsEnum(); - } - - public boolean isSimpleExecute() { - return simpleExecuteTypeCache; - } + abstract static class ConnectionProperty { - public void setExecuteType(Constants.QueryExecuteType executeType) { - this.executeType.setValue(executeType); - this.simpleExecuteTypeCache = this.executeType.getValueAsEnum() == Constants.QueryExecuteType.SIMPLE; - } + private final String name; + private final boolean required = false; + private final String description; + final Object defaultValue; + Object valueAsObject; - public Topodata.TabletType getTabletType() { - return tabletTypeCache; + private ConnectionProperty(String name, String description, Object defaultValue) { + this.name = name; + this.description = description; + this.defaultValue = defaultValue; } - public void setTabletType(Topodata.TabletType tabletType) { - this.tabletType.setValue(tabletType); - this.tabletTypeCache = this.tabletType.getValueAsEnum(); - } - - public Boolean getGrpcRetriesEnabled() { - return grpcRetriesEnabled.getValueAsBoolean(); - } - - public void setGrpcRetriesEnabled(Boolean grpcRetriesEnabled) { - this.grpcRetriesEnabled.setValue(grpcRetriesEnabled); - } - - public Long getGrpcRetryInitialBackoffMillis() { - return grpcRetryInitialBackoffMillis.getValueAsLong(); - } - - public void setGrpcRetryInitialBackoffMillis(Long grpcRetryInitialBackoffMillis) { - this.grpcRetryInitialBackoffMillis.setValue(grpcRetryInitialBackoffMillis); + void initializeFrom(Properties extractFrom) { + String extractedValue = extractFrom.getProperty(getPropertyName()); + String[] allowable = getAllowableValues(); + if (allowable != null && extractedValue != null) { + boolean found = false; + for (String value : allowable) { + found |= value.equalsIgnoreCase(extractedValue); + } + if (!found) { + throw new IllegalArgumentException("Property '" + name + "' Value '" + extractedValue + + "' not in the list of allowable values: " + Arrays.toString(allowable)); + } + } + extractFrom.remove(getPropertyName()); + initializeFrom(extractedValue); } - public Long getGrpcRetryMaxBackoffMillis() { - return grpcRetryMaxBackoffMillis.getValueAsLong(); - } + abstract void initializeFrom(String extractedValue); - public void setGrpcRetryMaxBackoffMillis(Long grpcRetryMaxBackoffMillis) { - this.grpcRetryMaxBackoffMillis.setValue(grpcRetryMaxBackoffMillis); - } + abstract String[] getAllowableValues(); - public Double getGrpcRetryBackoffMultiplier() { - return grpcRetryBackoffMultiplier.getValueAsDouble(); + public String getPropertyName() { + return name; } - public void setGrpcRetryBackoffMultiplier(DoubleConnectionProperty grpcRetryBackoffMultiplier) { - this.grpcRetryBackoffMultiplier = grpcRetryBackoffMultiplier; + DriverPropertyInfo getAsDriverPropertyInfo() { + DriverPropertyInfo dpi = new DriverPropertyInfo(this.name, null); + dpi.choices = getAllowableValues(); + dpi.value = (this.valueAsObject != null) ? this.valueAsObject.toString() : null; + dpi.required = this.required; + dpi.description = this.description; + return dpi; } + } - public boolean getUseSSL() { - return useSSL.getValueAsBoolean(); - } + private static class BooleanConnectionProperty extends ConnectionProperty { - public boolean getRefreshConnection() { - return refreshConnection.getValueAsBoolean(); + private BooleanConnectionProperty(String name, String description, Boolean defaultValue) { + super(name, description, defaultValue); } - public void setRefreshConnection(boolean refreshConnection) { - this.refreshConnection.setValue(refreshConnection); + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(extractedValue.equalsIgnoreCase("TRUE") || extractedValue.equalsIgnoreCase("YES")); + } else { + this.valueAsObject = this.defaultValue; + } } - public long getRefreshSeconds() { - return refreshSeconds.getValueAsLong(); + public void setValue(boolean value) { + this.valueAsObject = value; } - public void setRefreshSeconds(long refreshSeconds) { - this.refreshSeconds.setValue(refreshSeconds); + @Override + String[] getAllowableValues() { + return new String[]{Boolean.toString(true), Boolean.toString(false), "yes", "no"}; } - public boolean getRefreshClosureDelayed() { - return refreshClosureDelayed.getValueAsBoolean(); + boolean getValueAsBoolean() { + return (boolean) valueAsObject; } + } - public void setRefreshClosureDelayed(boolean refreshClosureDelayed) { - this.refreshClosureDelayed.setValue(refreshClosureDelayed); - } + private static class StringConnectionProperty extends ConnectionProperty { - public long getRefreshClosureDelaySeconds() { - return refreshClosureDelaySeconds.getValueAsLong(); - } + private final String[] allowableValues; - public void setRefreshClosureDelaySeconds(long refreshClosureDelaySeconds) { - this.refreshClosureDelaySeconds.setValue(refreshClosureDelaySeconds); + private StringConnectionProperty(String name, String description, String defaultValue, + String[] allowableValuesToSet) { + super(name, description, defaultValue); + allowableValues = allowableValuesToSet; } - public String getKeyStore() { - return keyStore.getValueAsString(); + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(extractedValue); + } else { + this.valueAsObject = this.defaultValue; + } } - public String getKeyStorePassword() { - return keyStorePassword.getValueAsString(); + @Override + String[] getAllowableValues() { + return allowableValues; } - public String getKeyAlias() { - return keyAlias.getValueAsString(); + public void setValue(String value) { + this.valueAsObject = value; } - public String getKeyPassword() { - return keyPassword.getValueAsString(); + String getValueAsString() { + return valueAsObject == null ? null : valueAsObject.toString(); } + } - public String getTrustStore() { - return trustStore.getValueAsString(); - } + private static class LongConnectionProperty extends ConnectionProperty { - public String getTrustStorePassword() { - return trustStorePassword.getValueAsString(); + private LongConnectionProperty(String name, String description, long defaultValue) { + super(name, description, defaultValue); } - public String getTrustAlias() { - return trustAlias.getValueAsString(); + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(Long.parseLong(extractedValue)); + } else { + this.valueAsObject = this.defaultValue; + } } - public boolean getTreatUtilDateAsTimestamp() { - return treatUtilDateAsTimestamp.getValueAsBoolean(); + @Override + String[] getAllowableValues() { + return null; } - public void setTreatUtilDateAsTimestamp(boolean treatUtilDateAsTimestamp) { - this.treatUtilDateAsTimestamp.setValue(treatUtilDateAsTimestamp); + public void setValue(Long value) { + this.valueAsObject = value; } - public long getTimeout() { - return timeout.getValueAsLong(); + Long getValueAsLong() { + return valueAsObject == null ? null : (Long) valueAsObject; } + } - public void setTimeout(long timeout) { - this.timeout.setValue(timeout); - } + private static class DoubleConnectionProperty extends ConnectionProperty { - public String getTarget() { - if(!StringUtils.isNullOrEmptyWithoutWS(target.getValueAsString())) { - return target.getValueAsString(); - } - String targetString = ""; - String keyspace = this.keyspace.getValueAsString(); - if(!StringUtils.isNullOrEmptyWithoutWS(keyspace)) { - targetString += keyspace; - String shard = this.shard.getValueAsString(); - if(!StringUtils.isNullOrEmptyWithoutWS(shard)) { - targetString += ":" + shard; - } - } - String tabletType = this.tabletType.getValueAsEnum().name(); - if(!StringUtils.isNullOrEmptyWithoutWS(tabletType)) { - targetString += "@" + tabletType.toLowerCase(); - } - return targetString; + private DoubleConnectionProperty(String name, String description, double defaultValue) { + super(name, description, defaultValue); } - @Deprecated - protected String getKeyspace() { - return this.keyspace.getValueAsString(); - } - protected void setCatalog(String catalog) throws SQLException { - this.catalog.setValue(catalog); + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(Double.parseDouble(extractedValue)); + } else { + this.valueAsObject = this.defaultValue; + } } - protected String getCatalog() throws SQLException{ - return this.catalog.getValueAsString(); + @Override + String[] getAllowableValues() { + return null; } - protected String getUsername() { - return this.userNameCache; + public void setValue(Double value) { + this.valueAsObject = value; } - abstract static class ConnectionProperty { - - private final String name; - private final boolean required = false; - private final String description; - final Object defaultValue; - Object valueAsObject; - - private ConnectionProperty(String name, String description, Object defaultValue) { - this.name = name; - this.description = description; - this.defaultValue = defaultValue; - } - - void initializeFrom(Properties extractFrom) { - String extractedValue = extractFrom.getProperty(getPropertyName()); - String[] allowable = getAllowableValues(); - if (allowable != null && extractedValue != null) { - boolean found = false; - for (String value : allowable) { - found |= value.equalsIgnoreCase(extractedValue); - } - if (!found) { - throw new IllegalArgumentException("Property '" + name + "' Value '" + extractedValue + "' not in the list of allowable values: " + Arrays.toString(allowable)); - } - } - extractFrom.remove(getPropertyName()); - initializeFrom(extractedValue); - } - - abstract void initializeFrom(String extractedValue); - - abstract String[] getAllowableValues(); - - public String getPropertyName() { - return name; - } - - DriverPropertyInfo getAsDriverPropertyInfo() { - DriverPropertyInfo dpi = new DriverPropertyInfo(this.name, null); - dpi.choices = getAllowableValues(); - dpi.value = (this.valueAsObject != null) ? this.valueAsObject.toString() : null; - dpi.required = this.required; - dpi.description = this.description; - return dpi; - } + Double getValueAsDouble() { + return valueAsObject == null ? null : (Double) valueAsObject; } + } - private static class BooleanConnectionProperty extends ConnectionProperty { + private static class EnumConnectionProperty> extends ConnectionProperty { - private BooleanConnectionProperty(String name, String description, Boolean defaultValue) { - super(name, description, defaultValue); - } + private final Class clazz; - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(extractedValue.equalsIgnoreCase("TRUE") || extractedValue.equalsIgnoreCase("YES")); - } else { - this.valueAsObject = this.defaultValue; - } - } - - public void setValue(boolean value) { - this.valueAsObject = value; - } - - @Override - String[] getAllowableValues() { - return new String[]{Boolean.toString(true), Boolean.toString(false), "yes", "no"}; - } - - boolean getValueAsBoolean() { - return (boolean) valueAsObject; - } + private EnumConnectionProperty(String name, String description, Enum defaultValue) { + super(name, description, defaultValue); + this.clazz = defaultValue.getDeclaringClass(); + if (!clazz.isEnum()) { + throw new IllegalArgumentException("EnumConnectionProperty types should be enums"); + } } - private static class StringConnectionProperty extends ConnectionProperty { - - private final String[] allowableValues; - - private StringConnectionProperty(String name, String description, String defaultValue, String[] allowableValuesToSet) { - super(name, description, defaultValue); - allowableValues = allowableValuesToSet; - } - - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(extractedValue); - } else { - this.valueAsObject = this.defaultValue; - } - } - - @Override - String[] getAllowableValues() { - return allowableValues; - } - - public void setValue(String value) { - this.valueAsObject = value; - } - - String getValueAsString() { - return valueAsObject == null ? null : valueAsObject.toString(); - } + @Override + void initializeFrom(String extractedValue) { + if (extractedValue != null) { + setValue(Enum.valueOf(clazz, extractedValue.toUpperCase())); + } else { + this.valueAsObject = this.defaultValue; + } } - private static class LongConnectionProperty extends ConnectionProperty { - - private LongConnectionProperty(String name, String description, long defaultValue) { - super(name, description, defaultValue); - } - - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(Long.parseLong(extractedValue)); - } else { - this.valueAsObject = this.defaultValue; - } - } - - @Override - String[] getAllowableValues() { - return null; - } - - public void setValue(Long value) { - this.valueAsObject = value; - } - - Long getValueAsLong() { - return valueAsObject == null ? null : (Long) valueAsObject; - } + public void setValue(T value) { + this.valueAsObject = value; } - private static class DoubleConnectionProperty extends ConnectionProperty { - - private DoubleConnectionProperty(String name, String description, double defaultValue) { - super(name, description, defaultValue); - } - - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(Double.parseDouble(extractedValue)); - } else { - this.valueAsObject = this.defaultValue; - } - } - - @Override - String[] getAllowableValues() { - return null; - } - - public void setValue(Double value) { - this.valueAsObject = value; - } - - Double getValueAsDouble() { - return valueAsObject == null ? null : (Double) valueAsObject; - } + @Override + String[] getAllowableValues() { + T[] enumConstants = clazz.getEnumConstants(); + String[] allowed = new String[enumConstants.length]; + for (int i = 0; i < enumConstants.length; i++) { + allowed[i] = enumConstants[i].toString(); + } + return allowed; } - private static class EnumConnectionProperty> extends ConnectionProperty { - - private final Class clazz; - - private EnumConnectionProperty(String name, String description, Enum defaultValue) { - super(name, description, defaultValue); - this.clazz = defaultValue.getDeclaringClass(); - if (!clazz.isEnum()) { - throw new IllegalArgumentException("EnumConnectionProperty types should be enums"); - } - } - - @Override - void initializeFrom(String extractedValue) { - if (extractedValue != null) { - setValue(Enum.valueOf(clazz, extractedValue.toUpperCase())); - } else { - this.valueAsObject = this.defaultValue; - } - } - - public void setValue(T value) { - this.valueAsObject = value; - } - - @Override - String[] getAllowableValues() { - T[] enumConstants = clazz.getEnumConstants(); - String[] allowed = new String[enumConstants.length]; - for (int i = 0; i < enumConstants.length; i++) { - allowed[i] = enumConstants[i].toString(); - } - return allowed; - } - - T getValueAsEnum() { - return (T) valueAsObject; - } + T getValueAsEnum() { + return (T) valueAsObject; } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/DBProperties.java b/java/jdbc/src/main/java/io/vitess/jdbc/DBProperties.java index 6c64ebb5be3..e510df6bd65 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/DBProperties.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/DBProperties.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -20,45 +20,47 @@ * Created by ashudeep.sharma on 10/03/16. */ public class DBProperties { - private final String productVersion; - private final String majorVersion; - private final String minorVersion; - private final int isolationLevel; - private final boolean caseInsensitiveComparison; - private final boolean storesLowerCaseTableName; - public DBProperties(String productVersion, String majorVersion, String minorVersion, - int isolationLevel, String lowerCaseTableNames) { + private final String productVersion; + private final String majorVersion; + private final String minorVersion; + private final int isolationLevel; + private final boolean caseInsensitiveComparison; + private final boolean storesLowerCaseTableName; - this.productVersion = productVersion; - this.majorVersion = majorVersion; - this.minorVersion = minorVersion; - this.isolationLevel = isolationLevel; - this.caseInsensitiveComparison = "1".equalsIgnoreCase(lowerCaseTableNames) || "2".equalsIgnoreCase(lowerCaseTableNames); - this.storesLowerCaseTableName = "1".equalsIgnoreCase(lowerCaseTableNames); - } + public DBProperties(String productVersion, String majorVersion, String minorVersion, + int isolationLevel, String lowerCaseTableNames) { - public String getProductVersion() { - return this.productVersion; - } + this.productVersion = productVersion; + this.majorVersion = majorVersion; + this.minorVersion = minorVersion; + this.isolationLevel = isolationLevel; + this.caseInsensitiveComparison = + "1".equalsIgnoreCase(lowerCaseTableNames) || "2".equalsIgnoreCase(lowerCaseTableNames); + this.storesLowerCaseTableName = "1".equalsIgnoreCase(lowerCaseTableNames); + } - public String getMajorVersion() { - return this.majorVersion; - } + public String getProductVersion() { + return this.productVersion; + } - public String getMinorVersion() { - return this.minorVersion; - } + public String getMajorVersion() { + return this.majorVersion; + } - public int getIsolationLevel() { - return this.isolationLevel; - } + public String getMinorVersion() { + return this.minorVersion; + } - public boolean getUseCaseInsensitiveComparisons() { - return caseInsensitiveComparison; - } + public int getIsolationLevel() { + return this.isolationLevel; + } - public boolean getStoresLowerCaseTableName() { - return storesLowerCaseTableName; - } + public boolean getUseCaseInsensitiveComparisons() { + return caseInsensitiveComparison; + } + + public boolean getStoresLowerCaseTableName() { + return storesLowerCaseTableName; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java index 910c83825e3..b86b2dd893e 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -30,553 +30,573 @@ public class FieldWithMetadata { - private final ConnectionProperties connectionProperties; - private final Query.Field field; - private final Query.Type vitessType; - private final boolean isImplicitTempTable; - private final boolean isSingleBit; - private final int precisionAdjustFactor; - - private int javaType; - private int colFlag; - private String encoding; - private String collationName; - private int collationIndex; - private int maxBytesPerChar; - - public FieldWithMetadata(ConnectionProperties connectionProperties, Query.Field field) throws SQLException { - this.connectionProperties = connectionProperties; - this.field = field; - this.colFlag = field.getFlags(); - this.vitessType = field.getType(); - this.collationIndex = field.getCharset(); - - // Map MySqlTypes to an initial java.sql Type - // Afterwards, below we will sometimes re-map the javaType based on other - // information we receive from the server, such as flags and encodings. - if (MysqlDefs.vitesstoMySqlType.containsKey(vitessType)) { - this.javaType = MysqlDefs.vitesstoMySqlType.get(vitessType); - } else if (field.getType().equals(Query.Type.TUPLE)) { - throw new SQLException(Constants.SQLExceptionMessages.INVALID_COLUMN_TYPE); - } else { - throw new SQLException(Constants.SQLExceptionMessages.UNKNOWN_COLUMN_TYPE); - } - - // All of the below remapping and metadata fields require the extra - // fields included when includeFields=IncludedFields.ALL - if (connectionProperties != null && connectionProperties.isIncludeAllFields()) { - this.isImplicitTempTable = checkForImplicitTemporaryTable(); - // Re-map BLOB to 'real' blob type - if (this.javaType == Types.BLOB) { - boolean isFromFunction = field.getOrgTable().isEmpty(); - if (connectionProperties.getBlobsAreStrings() || (connectionProperties.getFunctionsNeverReturnBlobs() && isFromFunction)) { - this.javaType = Types.VARCHAR; - } else if (collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary) { - if (connectionProperties.getUseBlobToStoreUTF8OutsideBMP() && shouldSetupForUtf8StringInBlob()) { - if (this.getColumnLength() == MysqlDefs.LENGTH_TINYBLOB || this.getColumnLength() == MysqlDefs.LENGTH_BLOB) { - this.javaType = Types.VARCHAR; - } else { - this.javaType = Types.LONGVARCHAR; - } - this.collationIndex = CharsetMapping.MYSQL_COLLATION_INDEX_utf8; - } else { - if (this.getColumnLength() == MysqlDefs.LENGTH_TINYBLOB) { - this.javaType = Types.VARBINARY; - } else if (this.getColumnLength() == MysqlDefs.LENGTH_BLOB || this.getColumnLength() == MysqlDefs.LENGTH_MEDIUMBLOB - || this.getColumnLength() == MysqlDefs.LENGTH_LONGBLOB) { - this.javaType = Types.LONGVARBINARY; - } - } - } else { - // *TEXT masquerading as blob - this.javaType = Types.LONGVARCHAR; - } - } - - // Re-map TINYINT(1) as bit or pseudo-boolean - if (this.javaType == Types.TINYINT && this.field.getColumnLength() == 1 && connectionProperties.getTinyInt1isBit()) { - this.javaType = Types.BIT; - } - - if (!isNativeNumericType() && !isNativeDateTimeType()) { - // For non-numeric types, try to pull the encoding from the passed collationIndex - // We will do some fixup afterwards - this.encoding = getEncodingForIndex(this.collationIndex); - // ucs2, utf16, and utf32 cannot be used as a client character set, but if it was received from server - // under some circumstances we can parse them as utf16 - if ("UnicodeBig".equals(this.encoding)) { - this.encoding = "UTF-16"; - } - // MySQL always encodes JSON data with utf8mb4. Discard whatever else we've found, if the type is JSON - if (vitessType == Query.Type.JSON) { - this.encoding = "UTF-8"; - } - this.isSingleBit = this.javaType == Types.BIT && (field.getColumnLength() == 0 || field.getColumnLength() == 1); - - // The server sends back a BINARY/VARBINARY field whenever varchar/text data is stored on disk as binary, but - // that doesn't mean the data is actually binary. For instance, a field with collation ascii_bin - // gets stored on disk as bytes for case-sensitive comparison, but is still an ascii string. - // Re-map these BINARY/VARBINARY types to CHAR/VARCHAR when the data is not actually - // binary encoded - boolean isBinaryEncoded = isBinary() && collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary; - if (javaType == Types.VARBINARY && !isBinaryEncoded) { - this.javaType = Types.VARCHAR; - } - if (javaType == Types.BINARY && !isBinaryEncoded) { - this.javaType = Types.CHAR; - } + private final ConnectionProperties connectionProperties; + private final Query.Field field; + private final Query.Type vitessType; + private final boolean isImplicitTempTable; + private final boolean isSingleBit; + private final int precisionAdjustFactor; + + private int javaType; + private int colFlag; + private String encoding; + private String collationName; + private int collationIndex; + private int maxBytesPerChar; + + public FieldWithMetadata(ConnectionProperties connectionProperties, Query.Field field) + throws SQLException { + this.connectionProperties = connectionProperties; + this.field = field; + this.colFlag = field.getFlags(); + this.vitessType = field.getType(); + this.collationIndex = field.getCharset(); + + // Map MySqlTypes to an initial java.sql Type + // Afterwards, below we will sometimes re-map the javaType based on other + // information we receive from the server, such as flags and encodings. + if (MysqlDefs.vitesstoMySqlType.containsKey(vitessType)) { + this.javaType = MysqlDefs.vitesstoMySqlType.get(vitessType); + } else if (field.getType().equals(Query.Type.TUPLE)) { + throw new SQLException(Constants.SQLExceptionMessages.INVALID_COLUMN_TYPE); + } else { + throw new SQLException(Constants.SQLExceptionMessages.UNKNOWN_COLUMN_TYPE); + } + + // All of the below remapping and metadata fields require the extra + // fields included when includeFields=IncludedFields.ALL + if (connectionProperties != null && connectionProperties.isIncludeAllFields()) { + this.isImplicitTempTable = checkForImplicitTemporaryTable(); + // Re-map BLOB to 'real' blob type + if (this.javaType == Types.BLOB) { + boolean isFromFunction = field.getOrgTable().isEmpty(); + if (connectionProperties.getBlobsAreStrings() || ( + connectionProperties.getFunctionsNeverReturnBlobs() && isFromFunction)) { + this.javaType = Types.VARCHAR; + } else if (collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary) { + if (connectionProperties.getUseBlobToStoreUTF8OutsideBMP() + && shouldSetupForUtf8StringInBlob()) { + if (this.getColumnLength() == MysqlDefs.LENGTH_TINYBLOB + || this.getColumnLength() == MysqlDefs.LENGTH_BLOB) { + this.javaType = Types.VARCHAR; } else { - // Default encoding for number-types and date-types - // We keep the default javaType as passed from the server, and just set the encoding - this.encoding = "US-ASCII"; - this.isSingleBit = false; + this.javaType = Types.LONGVARCHAR; } - - // Precision can be calculated from column length, but needs - // to be adjusted for the extra bytes used by the negative sign - // and decimal points, where appropriate. - if (isSigned()) { - switch (javaType) { - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - case Types.BIT: - // float/real/double are the same regardless of sign/decimal - // bit values can't actually be signed - this.precisionAdjustFactor = 0; - break; - default: - // other types we adjust for the negative symbol, and decimal - // symbol if there are decimals - this.precisionAdjustFactor = getDecimals() > 0 ? -2 : -1; - } - } else { - switch (javaType) { - case Types.DECIMAL: - case Types.NUMERIC: - // adjust for the decimal - this.precisionAdjustFactor = -1; - break; - default: - // all other types need no adjustment - this.precisionAdjustFactor = 0; - } + this.collationIndex = CharsetMapping.MYSQL_COLLATION_INDEX_utf8; + } else { + if (this.getColumnLength() == MysqlDefs.LENGTH_TINYBLOB) { + this.javaType = Types.VARBINARY; + } else if (this.getColumnLength() == MysqlDefs.LENGTH_BLOB + || this.getColumnLength() == MysqlDefs.LENGTH_MEDIUMBLOB + || this.getColumnLength() == MysqlDefs.LENGTH_LONGBLOB) { + this.javaType = Types.LONGVARBINARY; } + } } else { - // MySQL always encodes JSON data with utf8mb4. Discard whatever else we've found, if the type is JSON - if (vitessType == Query.Type.JSON) { - this.encoding = "UTF-8"; - } - // Defaults to appease final variables when not including all fields - this.isImplicitTempTable = false; - this.isSingleBit = false; + // *TEXT masquerading as blob + this.javaType = Types.LONGVARCHAR; + } + } + + // Re-map TINYINT(1) as bit or pseudo-boolean + if (this.javaType == Types.TINYINT && this.field.getColumnLength() == 1 + && connectionProperties.getTinyInt1isBit()) { + this.javaType = Types.BIT; + } + + if (!isNativeNumericType() && !isNativeDateTimeType()) { + // For non-numeric types, try to pull the encoding from the passed collationIndex + // We will do some fixup afterwards + this.encoding = getEncodingForIndex(this.collationIndex); + // ucs2, utf16, and utf32 cannot be used as a client character set, but if it was + // received from server + // under some circumstances we can parse them as utf16 + if ("UnicodeBig".equals(this.encoding)) { + this.encoding = "UTF-16"; + } + // MySQL always encodes JSON data with utf8mb4. Discard whatever else we've found, if the + // type is JSON + if (vitessType == Query.Type.JSON) { + this.encoding = "UTF-8"; + } + this.isSingleBit = this.javaType == Types.BIT && (field.getColumnLength() == 0 + || field.getColumnLength() == 1); + + // The server sends back a BINARY/VARBINARY field whenever varchar/text data is stored on + // disk as binary, but + // that doesn't mean the data is actually binary. For instance, a field with collation + // ascii_bin + // gets stored on disk as bytes for case-sensitive comparison, but is still an ascii string. + // Re-map these BINARY/VARBINARY types to CHAR/VARCHAR when the data is not actually + // binary encoded + boolean isBinaryEncoded = + isBinary() && collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary; + if (javaType == Types.VARBINARY && !isBinaryEncoded) { + this.javaType = Types.VARCHAR; + } + if (javaType == Types.BINARY && !isBinaryEncoded) { + this.javaType = Types.CHAR; + } + } else { + // Default encoding for number-types and date-types + // We keep the default javaType as passed from the server, and just set the encoding + this.encoding = "US-ASCII"; + this.isSingleBit = false; + } + + // Precision can be calculated from column length, but needs + // to be adjusted for the extra bytes used by the negative sign + // and decimal points, where appropriate. + if (isSigned()) { + switch (javaType) { + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.BIT: + // float/real/double are the same regardless of sign/decimal + // bit values can't actually be signed + this.precisionAdjustFactor = 0; + break; + default: + // other types we adjust for the negative symbol, and decimal + // symbol if there are decimals + this.precisionAdjustFactor = getDecimals() > 0 ? -2 : -1; + } + } else { + switch (javaType) { + case Types.DECIMAL: + case Types.NUMERIC: + // adjust for the decimal + this.precisionAdjustFactor = -1; + break; + default: + // all other types need no adjustment this.precisionAdjustFactor = 0; } - } - - /** - * Implicit temp tables are temporary tables created internally by MySQL for certain operations. - * For those types of tables, the table name is always prefixed with #sql_, typically followed by a numeric - * or other unique identifier. - */ - private boolean checkForImplicitTemporaryTable() { - return field.getTable().length() > 5 && field.getTable().startsWith("#sql_"); - } - - private boolean isNativeNumericType() { - switch (this.javaType) { - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.FLOAT: - case Types.DOUBLE: - case Types.REAL: - case Types.DECIMAL: - return true; - default: - return false; - } - } - - private boolean isNativeDateTimeType() { - switch (this.javaType) { - case Types.DATE: - case Types.TIME: - case Types.TIMESTAMP: - return true; - default: - return false; - } - } - - @VisibleForTesting - String getEncodingForIndex(int charsetIndex) { - String javaEncoding = null; - if (charsetIndex != MysqlDefs.NO_CHARSET_INFO) { - javaEncoding = CharsetMapping.getJavaEncodingForCollationIndex(charsetIndex, connectionProperties.getEncoding()); - } - // If nothing, get default based on configuration, may still be null - if (javaEncoding == null) { - javaEncoding = connectionProperties.getEncoding(); - } - return javaEncoding; - } - - public ConnectionProperties getConnectionProperties() throws SQLException { - checkConnectionProperties(); - return connectionProperties; - } - - public boolean hasConnectionProperties() { - return connectionProperties != null; - } - - private void checkConnectionProperties() throws SQLException { - if (!hasConnectionProperties()) { - throw new SQLException(Constants.SQLExceptionMessages.CONN_UNAVAILABLE); - } - } - - private boolean shouldSetupForUtf8StringInBlob() throws SQLException { - String includePattern = connectionProperties.getUtf8OutsideBmpIncludedColumnNamePattern(); - String excludePattern = connectionProperties.getUtf8OutsideBmpExcludedColumnNamePattern(); - - // When UseBlobToStoreUTF8OutsideBMP is set, we by default set blobs to UTF-8. So we first - // look for fields to exclude from that remapping (blacklist) - if (excludePattern != null && !StringUtils.isNullOrEmptyWithoutWS(excludePattern)) { - try { - if (getOrgName().matches(excludePattern)) { - // If we want to include more specific patters that were inadvertently covered by the exclude pattern, - // we set the includePattern (whitelist) - if (includePattern != null && !StringUtils.isNullOrEmptyWithoutWS(includePattern)) { - try { - if (getOrgName().matches(includePattern)) { - return true; - } - } catch (PatternSyntaxException pse) { - throw new SQLException("Illegal regex specified for \"utf8OutsideBmpIncludedColumnNamePattern\"", pse); - } - } - return false; - } - } catch (PatternSyntaxException pse) { - throw new SQLException("Illegal regex specified for \"utf8OutsideBmpExcludedColumnNamePattern\"", pse); - } - } - + } + } else { + // MySQL always encodes JSON data with utf8mb4. Discard whatever else we've found, if the + // type is JSON + if (vitessType == Query.Type.JSON) { + this.encoding = "UTF-8"; + } + // Defaults to appease final variables when not including all fields + this.isImplicitTempTable = false; + this.isSingleBit = false; + this.precisionAdjustFactor = 0; + } + } + + /** + * Implicit temp tables are temporary tables created internally by MySQL for certain operations. + * For those types of tables, the table name is always prefixed with #sql_, typically followed by + * a numeric or other unique identifier. + */ + private boolean checkForImplicitTemporaryTable() { + return field.getTable().length() > 5 && field.getTable().startsWith("#sql_"); + } + + private boolean isNativeNumericType() { + switch (this.javaType) { + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.DOUBLE: + case Types.REAL: + case Types.DECIMAL: return true; + default: + return false; } + } - public boolean isAutoIncrement() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE) > 0); - } - - public boolean isBinary() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.BINARY_FLAG_VALUE) > 0); - } - - public boolean isBlob() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.BLOB_FLAG_VALUE) > 0); - } - - public boolean isMultipleKey() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE) > 0); - } - - boolean isNotNull() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return true; - } - return ((this.colFlag & Query.MySqlFlag.NOT_NULL_FLAG_VALUE) > 0); - } - - public boolean isZeroFill() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.ZEROFILL_FLAG_VALUE) > 0); - } - - public boolean isPrimaryKey() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.PRI_KEY_FLAG_VALUE) > 0); - } - - public boolean isUniqueKey() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return ((this.colFlag & Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE) > 0); - } - - public boolean isUnsigned() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return true; - } - return ((this.colFlag & Query.MySqlFlag.UNSIGNED_FLAG_VALUE) > 0); - } - - public boolean isSigned() throws SQLException { - checkConnectionProperties(); - return !isUnsigned(); - } - - boolean isOpaqueBinary() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - - // Detect CHAR(n) CHARACTER SET BINARY which is a synonym for fixed-length binary types - if (this.collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary && isBinary() - && (this.vitessType == Query.Type.CHAR || this.vitessType == Query.Type.VARCHAR)) { - // Okay, queries resolved by temp tables also have this 'signature', check for that - return !isImplicitTemporaryTable(); - } - - // this is basically always false unless a valid charset is not found and someone explicitly sets a fallback - // using ConnectionProperties, as binary defaults to ISO8859-1 per mysql-connector-j implementation - return "binary".equalsIgnoreCase(getEncoding()); - } - - /** - * Is this field _definitely_ not writable? - * - * @return true if this field can not be written to in an INSERT/UPDATE - * statement. - */ - boolean isReadOnly() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - String orgColumnName = getOrgName(); - String orgTableName = getOrgTable(); - return !(orgColumnName != null && orgColumnName.length() > 0 && orgTableName != null && orgTableName.length() > 0); - } - - public synchronized String getCollation() throws SQLException { - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - - if (this.collationName == null) { - int collationIndex = getCollationIndex(); + private boolean isNativeDateTimeType() { + switch (this.javaType) { + case Types.DATE: + case Types.TIME: + case Types.TIMESTAMP: + return true; + default: + return false; + } + } + + @VisibleForTesting + String getEncodingForIndex(int charsetIndex) { + String javaEncoding = null; + if (charsetIndex != MysqlDefs.NO_CHARSET_INFO) { + javaEncoding = CharsetMapping + .getJavaEncodingForCollationIndex(charsetIndex, connectionProperties.getEncoding()); + } + // If nothing, get default based on configuration, may still be null + if (javaEncoding == null) { + javaEncoding = connectionProperties.getEncoding(); + } + return javaEncoding; + } + + public ConnectionProperties getConnectionProperties() throws SQLException { + checkConnectionProperties(); + return connectionProperties; + } + + public boolean hasConnectionProperties() { + return connectionProperties != null; + } + + private void checkConnectionProperties() throws SQLException { + if (!hasConnectionProperties()) { + throw new SQLException(Constants.SQLExceptionMessages.CONN_UNAVAILABLE); + } + } + + private boolean shouldSetupForUtf8StringInBlob() throws SQLException { + String includePattern = connectionProperties.getUtf8OutsideBmpIncludedColumnNamePattern(); + String excludePattern = connectionProperties.getUtf8OutsideBmpExcludedColumnNamePattern(); + + // When UseBlobToStoreUTF8OutsideBMP is set, we by default set blobs to UTF-8. So we first + // look for fields to exclude from that remapping (blacklist) + if (excludePattern != null && !StringUtils.isNullOrEmptyWithoutWS(excludePattern)) { + try { + if (getOrgName().matches(excludePattern)) { + // If we want to include more specific patters that were inadvertently covered by the + // exclude pattern, + // we set the includePattern (whitelist) + if (includePattern != null && !StringUtils.isNullOrEmptyWithoutWS(includePattern)) { try { - this.collationName = CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[collationIndex]; - } catch (ArrayIndexOutOfBoundsException ex) { - throw new SQLException("CollationIndex '" + collationIndex + "' out of bounds for collationName lookup, should be within 0 and " + CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length, ex); + if (getOrgName().matches(includePattern)) { + return true; + } + } catch (PatternSyntaxException pse) { + throw new SQLException( + "Illegal regex specified for \"utf8OutsideBmpIncludedColumnNamePattern\"", pse); } + } + return false; } - return this.collationName; - } - - - public synchronized int getMaxBytesPerCharacter() { - if (!connectionProperties.isIncludeAllFields()) { - return 0; - } - - if (this.maxBytesPerChar == 0) { - this.maxBytesPerChar = getMaxBytesPerChar(getCollationIndex(), getEncoding()); - } - return this.maxBytesPerChar; - } - - @VisibleForTesting - int getMaxBytesPerChar(Integer charsetIndex, String javaCharsetName) { - // if we can get it by charsetIndex just doing it - String charset = CharsetMapping.getMysqlCharsetNameForCollationIndex(charsetIndex); - // if we didn't find charset name by its full name - if (charset == null) { - charset = CharsetMapping.getMysqlCharsetForJavaEncoding(javaCharsetName); - } - // checking against static maps - return CharsetMapping.getMblen(charset); - } - - public String getName() { - return field.getName(); - } - - public String getTable() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return field.getTable(); - } - - public String getOrgTable() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return field.getOrgTable(); + } catch (PatternSyntaxException pse) { + throw new SQLException( + "Illegal regex specified for \"utf8OutsideBmpExcludedColumnNamePattern\"", pse); + } } - public String getDatabase() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return field.getDatabase(); - } - - public String getOrgName() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return field.getOrgName(); - } - - public int getColumnLength() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return 0; - } - return field.getColumnLength(); - } - - public int getDecimals() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return 0; - } - return field.getDecimals(); - } - - public int getJavaType() { - return javaType; - } - - private Query.Type getVitessType() { - return vitessType; - } - - public int getVitessTypeValue() { - return field.getTypeValue(); - } + return true; + } - boolean isImplicitTemporaryTable() { - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return isImplicitTempTable; + public boolean isAutoIncrement() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE) > 0); + } + + public boolean isBinary() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.BINARY_FLAG_VALUE) > 0); + } + + public boolean isBlob() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.BLOB_FLAG_VALUE) > 0); + } + + public boolean isMultipleKey() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE) > 0); + } + + boolean isNotNull() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return true; } + return ((this.colFlag & Query.MySqlFlag.NOT_NULL_FLAG_VALUE) > 0); + } - public String getEncoding() { - if (!connectionProperties.isIncludeAllFields()) { - return null; - } - return encoding; - } - - /** - * Precision can be calculated from column length, but needs - * to be adjusted for the extra values that can be included for the various - * numeric types - */ - public int getPrecisionAdjustFactor() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return 0; - } - return precisionAdjustFactor; + public boolean isZeroFill() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.ZEROFILL_FLAG_VALUE) > 0); + } + + public boolean isPrimaryKey() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.PRI_KEY_FLAG_VALUE) > 0); + } + + public boolean isUniqueKey() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return ((this.colFlag & Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE) > 0); + } + + public boolean isUnsigned() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return true; + } + return ((this.colFlag & Query.MySqlFlag.UNSIGNED_FLAG_VALUE) > 0); + } + + public boolean isSigned() throws SQLException { + checkConnectionProperties(); + return !isUnsigned(); + } + + boolean isOpaqueBinary() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; } - public boolean isSingleBit() throws SQLException { - checkConnectionProperties(); - if (!connectionProperties.isIncludeAllFields()) { - return false; - } - return isSingleBit; - } - - private int getCollationIndex() { - return collationIndex; - } - - @Override - public String toString() { - try { - StringBuilder asString = new StringBuilder(); - asString.append(getClass().getCanonicalName()); - asString.append("["); - asString.append("catalog="); - asString.append(this.getDatabase()); - asString.append(",tableName="); - asString.append(this.getTable()); - asString.append(",originalTableName="); - asString.append(this.getOrgTable()); - asString.append(",columnName="); - asString.append(this.getName()); - asString.append(",originalColumnName="); - asString.append(this.getOrgName()); - asString.append(",vitessType="); - asString.append(getVitessType()); - asString.append("("); - asString.append(getJavaType()); - asString.append(")"); - asString.append(",flags="); - if (isAutoIncrement()) { - asString.append("AUTO_INCREMENT"); - } - if (isPrimaryKey()) { - asString.append(" PRIMARY_KEY"); - } - if (isUniqueKey()) { - asString.append(" UNIQUE_KEY"); - } - if (isBinary()) { - asString.append(" BINARY"); - } - if (isBlob()) { - asString.append(" BLOB"); - } - if (isMultipleKey()) { - asString.append(" MULTI_KEY"); - } - if (isUnsigned()) { - asString.append(" UNSIGNED"); - } - if (isZeroFill()) { - asString.append(" ZEROFILL"); - } - - asString.append(", charsetIndex="); - asString.append(this.collationIndex); - asString.append(", charsetName="); - asString.append(this.encoding); - asString.append("]"); - return asString.toString(); - } catch (Throwable t) { - return super.toString(); - } - } + // Detect CHAR(n) CHARACTER SET BINARY which is a synonym for fixed-length binary types + if (this.collationIndex == CharsetMapping.MYSQL_COLLATION_INDEX_binary && isBinary() && ( + this.vitessType == Query.Type.CHAR || this.vitessType == Query.Type.VARCHAR)) { + // Okay, queries resolved by temp tables also have this 'signature', check for that + return !isImplicitTemporaryTable(); + } + + // this is basically always false unless a valid charset is not found and someone explicitly + // sets a fallback + // using ConnectionProperties, as binary defaults to ISO8859-1 per mysql-connector-j + // implementation + return "binary".equalsIgnoreCase(getEncoding()); + } + + /** + * Is this field _definitely_ not writable? + * + * @return true if this field can not be written to in an INSERT/UPDATE statement. + */ + boolean isReadOnly() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + String orgColumnName = getOrgName(); + String orgTableName = getOrgTable(); + return !(orgColumnName != null && orgColumnName.length() > 0 && orgTableName != null + && orgTableName.length() > 0); + } + + public synchronized String getCollation() throws SQLException { + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + + if (this.collationName == null) { + int collationIndex = getCollationIndex(); + try { + this.collationName = CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME[collationIndex]; + } catch (ArrayIndexOutOfBoundsException ex) { + throw new SQLException("CollationIndex '" + collationIndex + + "' out of bounds for collationName lookup, should be within 0 and " + + CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length, ex); + } + } + return this.collationName; + } + + + public synchronized int getMaxBytesPerCharacter() { + if (!connectionProperties.isIncludeAllFields()) { + return 0; + } + + if (this.maxBytesPerChar == 0) { + this.maxBytesPerChar = getMaxBytesPerChar(getCollationIndex(), getEncoding()); + } + return this.maxBytesPerChar; + } + + @VisibleForTesting + int getMaxBytesPerChar(Integer charsetIndex, String javaCharsetName) { + // if we can get it by charsetIndex just doing it + String charset = CharsetMapping.getMysqlCharsetNameForCollationIndex(charsetIndex); + // if we didn't find charset name by its full name + if (charset == null) { + charset = CharsetMapping.getMysqlCharsetForJavaEncoding(javaCharsetName); + } + // checking against static maps + return CharsetMapping.getMblen(charset); + } + + public String getName() { + return field.getName(); + } + + public String getTable() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return field.getTable(); + } + + public String getOrgTable() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return field.getOrgTable(); + } + + public String getDatabase() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return field.getDatabase(); + } + + public String getOrgName() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return field.getOrgName(); + } + + public int getColumnLength() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return 0; + } + return field.getColumnLength(); + } + + public int getDecimals() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return 0; + } + return field.getDecimals(); + } + + public int getJavaType() { + return javaType; + } + + private Query.Type getVitessType() { + return vitessType; + } + + public int getVitessTypeValue() { + return field.getTypeValue(); + } + + boolean isImplicitTemporaryTable() { + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return isImplicitTempTable; + } + + public String getEncoding() { + if (!connectionProperties.isIncludeAllFields()) { + return null; + } + return encoding; + } + + /** + * Precision can be calculated from column length, but needs to be adjusted for the extra values + * that can be included for the various numeric types + */ + public int getPrecisionAdjustFactor() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return 0; + } + return precisionAdjustFactor; + } + + public boolean isSingleBit() throws SQLException { + checkConnectionProperties(); + if (!connectionProperties.isIncludeAllFields()) { + return false; + } + return isSingleBit; + } + + private int getCollationIndex() { + return collationIndex; + } + + @Override + public String toString() { + try { + StringBuilder asString = new StringBuilder(); + asString.append(getClass().getCanonicalName()); + asString.append("["); + asString.append("catalog="); + asString.append(this.getDatabase()); + asString.append(",tableName="); + asString.append(this.getTable()); + asString.append(",originalTableName="); + asString.append(this.getOrgTable()); + asString.append(",columnName="); + asString.append(this.getName()); + asString.append(",originalColumnName="); + asString.append(this.getOrgName()); + asString.append(",vitessType="); + asString.append(getVitessType()); + asString.append("("); + asString.append(getJavaType()); + asString.append(")"); + asString.append(",flags="); + if (isAutoIncrement()) { + asString.append("AUTO_INCREMENT"); + } + if (isPrimaryKey()) { + asString.append(" PRIMARY_KEY"); + } + if (isUniqueKey()) { + asString.append(" UNIQUE_KEY"); + } + if (isBinary()) { + asString.append(" BINARY"); + } + if (isBlob()) { + asString.append(" BLOB"); + } + if (isMultipleKey()) { + asString.append(" MULTI_KEY"); + } + if (isUnsigned()) { + asString.append(" UNSIGNED"); + } + if (isZeroFill()) { + asString.append(" ZEROFILL"); + } + + asString.append(", charsetIndex="); + asString.append(this.collationIndex); + asString.append(", charsetName="); + asString.append(this.encoding); + asString.append("]"); + return asString.toString(); + } catch (Throwable t) { + return super.toString(); + } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java index 9fcd3d947be..88bf7e1eae3 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -55,811 +55,752 @@ */ public class VitessConnection extends ConnectionProperties implements Connection { - /* Get actual class name to be printed on */ - private static DatabaseMetaData databaseMetaData = null; - - /** - * A Map of currently open statements - */ - private Set openStatements = new HashSet<>(); - private VitessVTGateManager.VTGateConnections vTGateConnections; - private boolean closed = true; - private boolean readOnly = false; - private DBProperties dbProperties; - private final VitessJDBCUrl vitessJDBCUrl; - private final VTSession vtSession; - - - /** - * Constructor to Create Connection Object - * - * @param url - Connection url - * @param connectionProperties - property for the connection - * @throws SQLException - */ - public VitessConnection(String url, Properties connectionProperties) throws SQLException { - try { - this.vitessJDBCUrl = new VitessJDBCUrl(url, connectionProperties); - this.closed = false; - this.dbProperties = null; - initializeProperties(vitessJDBCUrl.getProperties()); - this.vtSession = new VTSession(this.getTarget(), this.getExecuteOptions()); - } catch (Exception e) { - throw new SQLException( - Constants.SQLExceptionMessages.CONN_INIT_ERROR + " - " + e.getMessage(), e); + /* Get actual class name to be printed on */ + private static DatabaseMetaData databaseMetaData = null; + + /** + * A Map of currently open statements + */ + private Set openStatements = new HashSet<>(); + private VitessVTGateManager.VTGateConnections vtGateConnections; + private boolean closed = true; + private boolean readOnly = false; + private DBProperties dbProperties; + private final VitessJDBCUrl vitessJDBCUrl; + private final VTSession vtSession; + + + /** + * Constructor to Create Connection Object + * + * @param url - Connection url + * @param connectionProperties - property for the connection + */ + public VitessConnection(String url, Properties connectionProperties) throws SQLException { + try { + this.vitessJDBCUrl = new VitessJDBCUrl(url, connectionProperties); + this.closed = false; + this.dbProperties = null; + initializeProperties(vitessJDBCUrl.getProperties()); + this.vtSession = new VTSession(this.getTarget(), this.getExecuteOptions()); + } catch (Exception exc) { + throw new SQLException( + Constants.SQLExceptionMessages.CONN_INIT_ERROR + " - " + e.getMessage(), exc); + } + } + + public void connect() { + this.vtGateConnections = new VitessVTGateManager.VTGateConnections(this); + } + + /** + * Creates statement for the given connection + * + * @return Statement Object + */ + public Statement createStatement() throws SQLException { + checkOpen(); + + return new VitessStatement(this); + } + + /** + * Create PreparedStatement for the given connection & sql + * + * @param sql - Sql Statement + * @return PreparedStatement Object + */ + public PreparedStatement prepareStatement(String sql) throws SQLException { + checkOpen(); + return new VitessPreparedStatement(this, sql); + } + + /** + * This method returns the sql form which the driver will sent to database + * + * @param sql - Sql Statement + * @return Form of the sql that the driver will sent to the underlying database + */ + public String nativeSQL(String sql) throws SQLException { + checkOpen(); + return sql; + } + + /** + * Return Auto commit status + * + * @return autoCommit + */ + public boolean getAutoCommit() throws SQLException { + checkOpen(); + return this.vtSession.isAutoCommit(); + } + + /** + * Sets this connection's auto-commit mode to the given state. + * + * @param autoCommit - true or false + */ + public void setAutoCommit(boolean autoCommit) throws SQLException { + checkOpen(); + if (this.vtSession.isAutoCommit() != autoCommit) { //If same then no-op + //Old Transaction Needs to be committed as per JDBC 4.1 Spec. + if (isInTransaction()) { + this.commit(); + } + this.vtSession.setAutoCommit(autoCommit); + } + } + + /** + * Commit on existing transaction and closed the transaction + */ + public void commit() throws SQLException { + checkOpen(); + checkAutoCommit(Constants.SQLExceptionMessages.COMMIT_WHEN_AUTO_COMMIT_TRUE); + if (isInTransaction()) { + commitTx(); + } + } + + private void commitTx() throws SQLException { + executeCommand("commit"); + } + + /** + * Rollback on existing transaction and closed the transaction + */ + public void rollback() throws SQLException { + checkOpen(); + checkAutoCommit(Constants.SQLExceptionMessages.ROLLBACK_WHEN_AUTO_COMMIT_TRUE); + if (isInTransaction()) { + rollbackTx(); + } + } + + private void rollbackTx() throws SQLException { + executeCommand("rollback"); + } + + private void executeCommand(String sql) throws SQLException { + try (Statement statement = this.createStatement()) { + statement.executeUpdate(sql); + } + } + + /** + * Closes an existing connection + */ + public void close() throws SQLException { + if (!this.closed) { //no-op when Connection already closed + try { + if (isInTransaction()) { //Rolling back active transaction on close + this.rollback(); } - } - - public void connect() { - this.vTGateConnections = new VitessVTGateManager.VTGateConnections(this); - } - - /** - * Creates statement for the given connection - * - * @return Statement Object - * @throws SQLException - */ - public Statement createStatement() throws SQLException { - checkOpen(); - - return new VitessStatement(this); - } - - /** - * Create PreparedStatement for the given connection & sql - * - * @param sql - Sql Statement - * @return PreparedStatement Object - * @throws SQLException - */ - public PreparedStatement prepareStatement(String sql) throws SQLException { - checkOpen(); - return new VitessPreparedStatement(this, sql); - } - - /** - * This method returns the sql form which the driver will sent to database - * - * @param sql - Sql Statement - * @return Form of the sql that the driver will sent to the underlying database - * @throws SQLException - */ - public String nativeSQL(String sql) throws SQLException { - checkOpen(); - return sql; - } - - /** - * Return Auto commit status - * - * @return autoCommit - * @throws SQLException - */ - public boolean getAutoCommit() throws SQLException { - checkOpen(); - return this.vtSession.isAutoCommit(); - } - - /** - * Sets this connection's auto-commit mode to the given state. - * - * @param autoCommit - true or false - * @throws SQLException - */ - public void setAutoCommit(boolean autoCommit) throws SQLException { - checkOpen(); - if (this.vtSession.isAutoCommit() != autoCommit) { //If same then no-op - //Old Transaction Needs to be committed as per JDBC 4.1 Spec. - if (isInTransaction()) { - this.commit(); - } - this.vtSession.setAutoCommit(autoCommit); - } - } - - /** - * Commit on existing transaction and closed the transaction - * - * @throws SQLException - */ - public void commit() throws SQLException { - checkOpen(); - checkAutoCommit(Constants.SQLExceptionMessages.COMMIT_WHEN_AUTO_COMMIT_TRUE); - if (isInTransaction()) { - commitTx(); - } - } - - private void commitTx() throws SQLException { - executeCommand("commit"); - } - - /** - * Rollback on existing transaction and closed the transaction - * - * @throws SQLException - */ - public void rollback() throws SQLException { - checkOpen(); - checkAutoCommit(Constants.SQLExceptionMessages.ROLLBACK_WHEN_AUTO_COMMIT_TRUE); - if (isInTransaction()) { - rollbackTx(); - } - } - - private void rollbackTx() throws SQLException{ - executeCommand("rollback"); - } - - private void executeCommand(String sql) throws SQLException { - try (Statement statement = this.createStatement()){ - statement.executeUpdate(sql); - } - } - - /** - * Closes an existing connection - * - * @throws SQLException - */ - public void close() throws SQLException { - if (!this.closed) { //no-op when Connection already closed - try { - if (isInTransaction()) { //Rolling back active transaction on close - this.rollback(); - } - closeAllOpenStatements(); - } finally { - this.closed = true; - } - } - } - - /** - * Return Connection state - * - * @return DatabaseMetadata Object - */ - public boolean isClosed() { - return this.closed; - } - - public DatabaseMetaData getMetaData() throws SQLException { - checkOpen(); - if (!metadataNullOrClosed()) { - return databaseMetaData; - } else { - synchronized (VitessConnection.class) { - if (metadataNullOrClosed()) { - String dbEngine = initializeDBProperties(); - if (dbEngine.equals("mariadb")) { - databaseMetaData = new VitessMariaDBDatabaseMetadata(this); - } else { - databaseMetaData = new VitessMySQLDatabaseMetadata(this); - } - } - } - return databaseMetaData; - } - } - - private boolean metadataNullOrClosed() throws SQLException { - return null == databaseMetaData || null == databaseMetaData.getConnection() || databaseMetaData.getConnection().isClosed(); - } - - public boolean isReadOnly() throws SQLException { - checkOpen(); - return readOnly; - } - - /** - * Set ReadOnly for the connection - * - * @param readOnly - true or false - * @throws SQLException - */ - public void setReadOnly(boolean readOnly) throws SQLException { - checkOpen(); - - if (isInTransaction()) { - throw new SQLException( - Constants.SQLExceptionMessages.METHOD_CALLED_ON_OPEN_TRANSACTION); - } - - // TODO implement read only properly - this.readOnly = readOnly; - } - - /** - * Return Catalog - * - * @return catalog string - * @throws SQLException - */ - public String getCatalog() throws SQLException { - checkOpen(); - return super.getCatalog(); - } - - /** - * As per JDBC 4.1 specs, if database does not support catalog, then silently ignore the call - * - * @param catalog - Catalog value - * @throws SQLException - */ - public void setCatalog(String catalog) throws SQLException { - checkOpen(); - super.setCatalog(catalog); //Ignoring any affect - } - - /** - * Get the Isolation Level - * - * @return Isolation Level of the Database - * @throws SQLException - */ - public int getTransactionIsolation() throws SQLException { - checkOpen(); - switch (this.vtSession.getTransactionIsolation()) { - case DEFAULT: - return this.getMetaData().getDefaultTransactionIsolation(); - case READ_COMMITTED: - return Connection.TRANSACTION_READ_COMMITTED; - case READ_UNCOMMITTED: - return Connection.TRANSACTION_READ_UNCOMMITTED; - case REPEATABLE_READ: - return Connection.TRANSACTION_REPEATABLE_READ; - case SERIALIZABLE: - return Connection.TRANSACTION_SERIALIZABLE; - default: - throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); - } - } - - /** - * TODO: Currently it will not allow to change the isolation level - * - * @param level - Isolation Level - * @throws SQLException - */ - public void setTransactionIsolation(int level) throws SQLException { - checkOpen(); - if (isInTransaction()) { - rollbackTx(); - } - if (Connection.TRANSACTION_NONE == level || !getMetaData() - .supportsTransactionIsolationLevel(level)) { - throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); - } - - Query.ExecuteOptions.TransactionIsolation isolation; - switch (level) { - case Connection.TRANSACTION_READ_COMMITTED: - isolation = Query.ExecuteOptions.TransactionIsolation.READ_COMMITTED; - break; - case Connection.TRANSACTION_READ_UNCOMMITTED: - isolation = Query.ExecuteOptions.TransactionIsolation.READ_UNCOMMITTED; - break; - case Connection.TRANSACTION_REPEATABLE_READ: - isolation = Query.ExecuteOptions.TransactionIsolation.REPEATABLE_READ; - break; - case Connection.TRANSACTION_SERIALIZABLE: - isolation = Query.ExecuteOptions.TransactionIsolation.SERIALIZABLE; - break; - default: - throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); - } - this.vtSession.setTransactionIsolation(isolation); - } - - /** - * Return Warnings - *

- * TODO: Not implementing as Error is Thrown when occured - * - * @return SQLWarning or null - * @throws SQLException - */ - public SQLWarning getWarnings() throws SQLException { - checkOpen(); - return null; - } - - /** - * Clear the warnings - Not saving Warnings - * - * @throws SQLException - */ - public void clearWarnings() throws SQLException { - checkOpen(); - } - - /** - * Create Statement object with ResultSet properties - * - * @param resultSetType - ResultSet Type - * @param resultSetConcurrency - ResultSet Concurrency - * @return Statement Object - * @throws SQLException - */ - public Statement createStatement(int resultSetType, int resultSetConcurrency) - throws SQLException { - VitessStatement vitessStatement; - - checkOpen(); - if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_TYPE_NOT_SUPPORTED); - } - if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_CONCUR_NOT_SUPPORTED); - } - vitessStatement = new VitessStatement(this, resultSetType, resultSetConcurrency); - - return vitessStatement; - } - - /** - * Create PreparedStatement object with ResultSet properties - * - * @param sql - Sql Statement - * @param resultSetType - ResultSet Type - * @param resultSetConcurrency - ResultSet Concurrency - * @return PreparedStatement Object - * @throws SQLException - */ - public PreparedStatement prepareStatement(String sql, int resultSetType, - int resultSetConcurrency) throws SQLException { - VitessPreparedStatement vitessPreparedStatement; - - checkOpen(); - if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_TYPE_NOT_SUPPORTED); - } - if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_CONCUR_NOT_SUPPORTED); - } - vitessPreparedStatement = - new VitessPreparedStatement(this, sql, resultSetType, resultSetConcurrency); - - return vitessPreparedStatement; - } - - /** - * Return ResultSet Holdability - * - * @return ResetSet Holdability Type - * @throws SQLException - */ - public int getHoldability() throws SQLException { - checkOpen(); - return this.getMetaData().getResultSetHoldability(); - } - - /** - * Feature is not Supported - * - * @param holdability - ResetSet Holdability Type - * @throws SQLException - */ - public void setHoldability(int holdability) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - /** - * TODO : This method should actually validate the connection. - * - * @param timeout - * @return - * @throws SQLException - */ - public boolean isValid(int timeout) throws SQLException { - if (timeout < 0) { - throw new SQLException(Constants.SQLExceptionMessages.TIMEOUT_NEGATIVE); - } - return closed ? Boolean.FALSE : Boolean.TRUE; - } - - /** - * TODO: For Implementation Possibility - * - * @param name - Property Name - * @param value - Property Value - * @throws SQLClientInfoException - */ - public void setClientInfo(String name, String value) throws SQLClientInfoException { - Map errorMap = new HashMap<>(); - ClientInfoStatus clientInfoStatus = ClientInfoStatus.REASON_UNKNOWN; - errorMap.put(name, clientInfoStatus); - - throw new SQLClientInfoException(Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED, - errorMap); - } - - /** - * TODO: For Implementation Possibility - * - * @param name - Property Name - * @return Property Value - */ - public String getClientInfo(String name) { - return null; - } - - /** - * TODO: For Implementation Possibility - * - * @return - Property Object - */ - public Properties getClientInfo() { - return null; - } - - /** - * TODO: For Implementation Possibility - * - * @param properties - Property Object - * @throws SQLClientInfoException - */ - public void setClientInfo(Properties properties) throws SQLClientInfoException { - Map errorMap = new HashMap<>(); - ClientInfoStatus clientInfoStatus = ClientInfoStatus.REASON_UNKNOWN; - for (String name : properties.stringPropertyNames()) { - errorMap.put(name, clientInfoStatus); - } - - throw new SQLClientInfoException(Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED, - errorMap); - } - - /** - * No-op for now - * - * @return Schema - * @throws SQLException - */ - public String getSchema() throws SQLException { - checkOpen(); - return null; - } - - /** - * No-op for now - * - * @param schema - Schema - * @throws SQLException - */ - public void setSchema(String schema) throws SQLException { - checkOpen(); - } - - /** - * Abort the Connection - * - * @param executor - Executor - * @throws SQLException - */ - public void abort(Executor executor) throws SQLException { - if (!closed) { //no-op on closed - if (null == executor) { - throw new SQLException(Constants.SQLExceptionMessages.EXECUTOR_NULL); - } - - executor.execute(new Runnable() { - @Override public void run() { - try { - close(); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - }); + closeAllOpenStatements(); + } finally { + this.closed = true; + } + } + } + + /** + * Return Connection state + * + * @return DatabaseMetadata Object + */ + public boolean isClosed() { + return this.closed; + } + + public DatabaseMetaData getMetaData() throws SQLException { + checkOpen(); + if (!metadataNullOrClosed()) { + return databaseMetaData; + } else { + synchronized (VitessConnection.class) { + if (metadataNullOrClosed()) { + String dbEngine = initializeDBProperties(); + if (dbEngine.equals("mariadb")) { + databaseMetaData = new VitessMariaDBDatabaseMetadata(this); + } else { + databaseMetaData = new VitessMySQLDatabaseMetadata(this); + } } - } - - /** - * Unwrap a class - * - * @param iface - A Class defining an interface that the result must implement. - * @param - the type of the class modeled by this Class object - * @return an object that implements the interface. May be a proxy for the actual implementing object. - * @throws SQLException - */ - public T unwrap(Class iface) throws SQLException { - try { - return iface.cast(this); - } catch (ClassCastException cce) { - throw new SQLException( - Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), cce); + } + return databaseMetaData; + } + } + + private boolean metadataNullOrClosed() throws SQLException { + return null == databaseMetaData || null == databaseMetaData.getConnection() || databaseMetaData + .getConnection().isClosed(); + } + + public boolean isReadOnly() throws SQLException { + checkOpen(); + return readOnly; + } + + /** + * Set ReadOnly for the connection + * + * @param readOnly - true or false + */ + public void setReadOnly(boolean readOnly) throws SQLException { + checkOpen(); + + if (isInTransaction()) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALLED_ON_OPEN_TRANSACTION); + } + + // TODO implement read only properly + this.readOnly = readOnly; + } + + /** + * Return Catalog + * + * @return catalog string + */ + public String getCatalog() throws SQLException { + checkOpen(); + return super.getCatalog(); + } + + /** + * As per JDBC 4.1 specs, if database does not support catalog, then silently ignore the call + * + * @param catalog - Catalog value + */ + public void setCatalog(String catalog) throws SQLException { + checkOpen(); + super.setCatalog(catalog); //Ignoring any affect + } + + /** + * Get the Isolation Level + * + * @return Isolation Level of the Database + */ + public int getTransactionIsolation() throws SQLException { + checkOpen(); + switch (this.vtSession.getTransactionIsolation()) { + case DEFAULT: + return this.getMetaData().getDefaultTransactionIsolation(); + case READ_COMMITTED: + return Connection.TRANSACTION_READ_COMMITTED; + case READ_UNCOMMITTED: + return Connection.TRANSACTION_READ_UNCOMMITTED; + case REPEATABLE_READ: + return Connection.TRANSACTION_REPEATABLE_READ; + case SERIALIZABLE: + return Connection.TRANSACTION_SERIALIZABLE; + default: + throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); + } + } + + /** + * TODO: Currently it will not allow to change the isolation level + * + * @param level - Isolation Level + */ + public void setTransactionIsolation(int level) throws SQLException { + checkOpen(); + if (isInTransaction()) { + rollbackTx(); + } + if (Connection.TRANSACTION_NONE == level || !getMetaData() + .supportsTransactionIsolationLevel(level)) { + throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); + } + + Query.ExecuteOptions.TransactionIsolation isolation; + switch (level) { + case Connection.TRANSACTION_READ_COMMITTED: + isolation = Query.ExecuteOptions.TransactionIsolation.READ_COMMITTED; + break; + case Connection.TRANSACTION_READ_UNCOMMITTED: + isolation = Query.ExecuteOptions.TransactionIsolation.READ_UNCOMMITTED; + break; + case Connection.TRANSACTION_REPEATABLE_READ: + isolation = Query.ExecuteOptions.TransactionIsolation.REPEATABLE_READ; + break; + case Connection.TRANSACTION_SERIALIZABLE: + isolation = Query.ExecuteOptions.TransactionIsolation.SERIALIZABLE; + break; + default: + throw new SQLException(Constants.SQLExceptionMessages.ISOLATION_LEVEL_NOT_SUPPORTED); + } + this.vtSession.setTransactionIsolation(isolation); + } + + /** + * Return Warnings + *

+ * TODO: Not implementing as Error is Thrown when occured + * + * @return SQLWarning or null + */ + public SQLWarning getWarnings() throws SQLException { + checkOpen(); + return null; + } + + /** + * Clear the warnings - Not saving Warnings + */ + public void clearWarnings() throws SQLException { + checkOpen(); + } + + /** + * Create Statement object with ResultSet properties + * + * @param resultSetType - ResultSet Type + * @param resultSetConcurrency - ResultSet Concurrency + * @return Statement Object + */ + public Statement createStatement(int resultSetType, int resultSetConcurrency) + throws SQLException { + + checkOpen(); + if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_TYPE_NOT_SUPPORTED); + } + if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_CONCUR_NOT_SUPPORTED); + } + + return new VitessStatement(this, resultSetType, resultSetConcurrency); + } + + /** + * Create PreparedStatement object with ResultSet properties + * + * @param sql - Sql Statement + * @param resultSetType - ResultSet Type + * @param resultSetConcurrency - ResultSet Concurrency + * @return PreparedStatement Object + */ + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + + checkOpen(); + if (resultSetType != ResultSet.TYPE_FORWARD_ONLY) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_TYPE_NOT_SUPPORTED); + } + if (resultSetConcurrency != ResultSet.CONCUR_READ_ONLY) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_CONCUR_NOT_SUPPORTED); + } + return new VitessPreparedStatement(this, sql, resultSetType, + resultSetConcurrency); + } + + /** + * Return ResultSet Holdability + * + * @return ResetSet Holdability Type + */ + public int getHoldability() throws SQLException { + checkOpen(); + return this.getMetaData().getResultSetHoldability(); + } + + /** + * Feature is not Supported + * + * @param holdability - ResetSet Holdability Type + */ + public void setHoldability(int holdability) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + /** + * TODO : This method should actually validate the connection. + */ + public boolean isValid(int timeout) throws SQLException { + if (timeout < 0) { + throw new SQLException(Constants.SQLExceptionMessages.TIMEOUT_NEGATIVE); + } + return closed ? Boolean.FALSE : Boolean.TRUE; + } + + /** + * TODO: For Implementation Possibility + * + * @param name - Property Name + * @param value - Property Value + */ + public void setClientInfo(String name, String value) throws SQLClientInfoException { + Map errorMap = new HashMap<>(); + ClientInfoStatus clientInfoStatus = ClientInfoStatus.REASON_UNKNOWN; + errorMap.put(name, clientInfoStatus); + + throw new SQLClientInfoException(Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED, + errorMap); + } + + /** + * TODO: For Implementation Possibility + * + * @param name - Property Name + * @return Property Value + */ + public String getClientInfo(String name) { + return null; + } + + /** + * TODO: For Implementation Possibility + * + * @return - Property Object + */ + public Properties getClientInfo() { + return null; + } + + /** + * TODO: For Implementation Possibility + * + * @param properties - Property Object + */ + public void setClientInfo(Properties properties) throws SQLClientInfoException { + Map errorMap = new HashMap<>(); + ClientInfoStatus clientInfoStatus = ClientInfoStatus.REASON_UNKNOWN; + for (String name : properties.stringPropertyNames()) { + errorMap.put(name, clientInfoStatus); + } + + throw new SQLClientInfoException(Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED, + errorMap); + } + + /** + * No-op for now + * + * @return Schema + */ + public String getSchema() throws SQLException { + checkOpen(); + return null; + } + + /** + * No-op for now + * + * @param schema - Schema + */ + public void setSchema(String schema) throws SQLException { + checkOpen(); + } + + /** + * Abort the Connection + * + * @param executor - Executor + */ + public void abort(Executor executor) throws SQLException { + if (!closed) { //no-op on closed + if (null == executor) { + throw new SQLException(Constants.SQLExceptionMessages.EXECUTOR_NULL); + } + + executor.execute(new Runnable() { + @Override + public void run() { + try { + close(); + } catch (SQLException exc) { + throw new RuntimeException(exc); + } } - } - - /** - * Checking Wrapper - * - * @param iface - A Class defining an interface that the result must implement. - * @return true if this implements the interface or directly or indirectly wraps an object that does. - * @throws SQLException - */ - public boolean isWrapperFor(Class iface) throws SQLException { - checkOpen(); - return iface.isInstance(this); - } - - public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) - throws SQLException { - checkOpen(); - return new VitessPreparedStatement(this, sql, autoGeneratedKeys); - } - - //Methods created for this class - - private void checkOpen() throws SQLException { - if (this.closed) { - throw new SQLException(Constants.SQLExceptionMessages.CONN_CLOSED); + }); + } + } + + /** + * Unwrap a class + * + * @param iface - A Class defining an interface that the result must implement. + * @param - the type of the class modeled by this Class object + * @return an object that implements the interface. May be a proxy for the actual implementing + * object. + */ + public T unwrap(Class iface) throws SQLException { + try { + return iface.cast(this); + } catch (ClassCastException ccexc) { + throw new SQLException(Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), + ccexc); + } + } + + /** + * Checking Wrapper + * + * @param iface - A Class defining an interface that the result must implement. + * @return true if this implements the interface or directly or indirectly wraps an object that + * does. + */ + public boolean isWrapperFor(Class iface) throws SQLException { + checkOpen(); + return iface.isInstance(this); + } + + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + checkOpen(); + return new VitessPreparedStatement(this, sql, autoGeneratedKeys); + } + + //Methods created for this class + + private void checkOpen() throws SQLException { + if (this.closed) { + throw new SQLException(Constants.SQLExceptionMessages.CONN_CLOSED); + } + } + + private void checkAutoCommit(String exception) throws SQLException { + if (this.vtSession.isAutoCommit()) { + throw new SQLException(exception); + } + } + + public boolean isInTransaction() { + return this.vtSession.isInTransaction(); + } + + public VTGateConnection getVtGateConn() { + return vtGateConnections.getVtGateConnInstance(); + } + + public VTSession getVtSession() { + return this.vtSession; + } + + public VitessJDBCUrl getUrl() { + return this.vitessJDBCUrl; + } + + /** + * Register a Statement instance as open. + * + * @param statement the Statement instance to remove + */ + public void registerStatement(Statement statement) { + this.openStatements.add(statement); + } + + /** + * Remove the given statement from the list of open statements + * + * @param statement the Statement instance to remove + */ + public void unregisterStatement(Statement statement) { + this.openStatements.remove(statement); + } + + /** + * Closes all currently open statements. + */ + private void closeAllOpenStatements() throws SQLException { + SQLException postponedException = null; + + // Copy openStatements, since VitessStatement.close() + // deregisters itself, modifying the original set. + for (Statement statement : new ArrayList<>(this.openStatements)) { + try { + VitessStatement vitessStatement = (VitessStatement) statement; + vitessStatement.close(); + } catch (SQLException sqlEx) { + postponedException = sqlEx; // throw it later, cleanup all statements first + } + } + + this.openStatements.clear(); + + if (postponedException != null) { + throw postponedException; + } + + } + + // UnSupported Feature List + + /** + * TODO: To support Stored Procedure + */ + public CallableStatement prepareCall(String sql) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + /** + * TODO: To support Stored Procedure + */ + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Map> getTypeMap() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setTypeMap(Map> map) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Savepoint setSavepoint() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Savepoint setSavepoint(String namexc) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void rollback(Savepoint savepoint) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Statement createStatement(int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + /** + * TODO: To support Stored Procedure + */ + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, + int resultSetHoldability) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Clob createClob() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Blob createBlob() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public NClob createNClob() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public SQLXML createSQLXML() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getNetworkTimeout() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + private String initializeDBProperties() throws SQLException { + HashMap dbVariables = new HashMap<>(); + String dbEngine = null; + + if (metadataNullOrClosed()) { + String versionValue; + + try (VitessStatement vitessStatement = new VitessStatement( + this); ResultSet resultSet = vitessStatement.executeQuery( + "SHOW VARIABLES WHERE VARIABLE_NAME IN (\'tx_isolation\',\'INNODB_VERSION\', " + + "\'lower_case_table_names\')")) { + while (resultSet.next()) { + dbVariables.put(resultSet.getString(1), resultSet.getString(2)); } - } - - private void checkAutoCommit(String exception) throws SQLException { - if (this.vtSession.isAutoCommit()) { - throw new SQLException(exception); + versionValue = dbVariables.get("innodb_version"); + String transactionIsolation = dbVariables.get("tx_isolation"); + String lowerCaseTables = dbVariables.get("lower_case_table_names"); + String productVersion = ""; + String majorVersion = ""; + String minorVersion = ""; + int isolationLevel = 0; + if (MysqlDefs.mysqlConnectionTransactionMapping.containsKey(transactionIsolation)) { + isolationLevel = MysqlDefs.mysqlConnectionTransactionMapping.get(transactionIsolation); } - } - - public boolean isInTransaction() { - return this.vtSession.isInTransaction(); - } - - public VTGateConnection getVtGateConn() { - return vTGateConnections.getVtGateConnInstance(); - } - - public VTSession getVtSession() { - return this.vtSession; - } - - public VitessJDBCUrl getUrl() { - return this.vitessJDBCUrl; - } - - /** - * Register a Statement instance as open. - * - * @param statement the Statement instance to remove - */ - public void registerStatement(Statement statement) { - this.openStatements.add(statement); - } - - /** - * Remove the given statement from the list of open statements - * - * @param statement the Statement instance to remove - */ - public void unregisterStatement(Statement statement) { - this.openStatements.remove(statement); - } - - /** - * Closes all currently open statements. - * - * @throws SQLException - */ - private void closeAllOpenStatements() throws SQLException { - SQLException postponedException = null; - - // Copy openStatements, since VitessStatement.close() - // deregisters itself, modifying the original set. - for (Statement statement : new ArrayList<>(this.openStatements)) { - try { - VitessStatement vitessStatement = (VitessStatement) statement; - vitessStatement.close(); - } catch (SQLException sqlEx) { - postponedException = sqlEx; // throw it later, cleanup all statements first - } - } - - this.openStatements.clear(); - - if (postponedException != null) { - throw postponedException; - } - - } - - // UnSupported Feature List - - /** - * TODO: To support Stored Procedure - * - * @param sql - * @return - * @throws SQLException - */ - public CallableStatement prepareCall(String sql) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - /** - * TODO: To support Stored Procedure - * - * @param sql - * @param resultSetType - * @param resultSetConcurrency - * @return - * @throws SQLException - */ - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Map> getTypeMap() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setTypeMap(Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Savepoint setSavepoint() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Savepoint setSavepoint(String name) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void rollback(Savepoint savepoint) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void releaseSavepoint(Savepoint savepoint) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Statement createStatement(int resultSetType, int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public PreparedStatement prepareStatement(String sql, int resultSetType, - int resultSetConcurrency, int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - /** - * TODO: To support Stored Procedure - * - * @param sql - * @param resultSetType - * @param resultSetConcurrency - * @param resultSetHoldability - * @return - * @throws SQLException - */ - public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, - int resultSetHoldability) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public PreparedStatement prepareStatement(String sql, String[] columnNames) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Clob createClob() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Blob createBlob() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public NClob createNClob() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public SQLXML createSQLXML() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Array createArrayOf(String typeName, Object[] elements) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Struct createStruct(String typeName, Object[] attributes) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getNetworkTimeout() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - private String initializeDBProperties() throws SQLException { - HashMap dbVariables = new HashMap<>(); - String dbEngine = null; - - if (metadataNullOrClosed()) { - String versionValue; - - try(VitessStatement vitessStatement = new VitessStatement(this); - ResultSet resultSet = vitessStatement.executeQuery( - "SHOW VARIABLES WHERE VARIABLE_NAME IN (\'tx_isolation\',\'INNODB_VERSION\', \'lower_case_table_names\')") - ) { - while (resultSet.next()) { - dbVariables.put(resultSet.getString(1), resultSet.getString(2)); - } - versionValue = dbVariables.get("innodb_version"); - String transactionIsolation = dbVariables.get("tx_isolation"); - String lowerCaseTables = dbVariables.get("lower_case_table_names"); - String productVersion = ""; - String majorVersion = ""; - String minorVersion = ""; - int isolationLevel = 0; - if (MysqlDefs.mysqlConnectionTransactionMapping.containsKey(transactionIsolation)) { - isolationLevel = - MysqlDefs.mysqlConnectionTransactionMapping.get(transactionIsolation); - } - if (null != versionValue) { - if (versionValue.toLowerCase().contains("mariadb")) { - dbEngine = "mariadb"; - } else { - dbEngine = "mysql"; - } - if (versionValue.contains("-")) { - String[] versions = versionValue.split("-"); - productVersion = versions[0]; - } else { - productVersion = versionValue; - } - String[] dbVersions = productVersion.split("\\.", 3); - majorVersion = dbVersions[0]; - minorVersion = dbVersions[1]; - } - this.dbProperties = - new DBProperties(productVersion, majorVersion, minorVersion, isolationLevel, lowerCaseTables); - } + if (null != versionValue) { + if (versionValue.toLowerCase().contains("mariadb")) { + dbEngine = "mariadb"; + } else { + dbEngine = "mysql"; + } + if (versionValue.contains("-")) { + String[] versions = versionValue.split("-"); + productVersion = versions[0]; + } else { + productVersion = versionValue; + } + String[] dbVersions = productVersion.split("\\.", 3); + majorVersion = dbVersions[0]; + minorVersion = dbVersions[1]; } - return dbEngine; + this.dbProperties = new DBProperties(productVersion, majorVersion, minorVersion, + isolationLevel, lowerCaseTables); + } } + return dbEngine; + } - public DBProperties getDbProperties() { - return this.dbProperties; - } + public DBProperties getDbProperties() { + return this.dbProperties; + } - public Context createContext(long deadlineAfter) { - return CommonUtils.createContext(getUsername(), deadlineAfter); - } + public Context createContext(long deadlineAfter) { + return CommonUtils.createContext(getUsername(), deadlineAfter); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDatabaseMetaData.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDatabaseMetaData.java index 61942951a15..a037ab5ce35 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDatabaseMetaData.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDatabaseMetaData.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -29,587 +29,589 @@ */ public abstract class VitessDatabaseMetaData implements DatabaseMetaData { - private static final String SEARCH_STRING_ESCAPE = "\\"; - private static final String EXTRA_NAME_CHARS = "#@"; - private static final String SCHEMA_TERM = ""; - private static final String CATALOG_SEPARATOR = "."; - private static final String PROCEDURE_TERM = "procedure"; - private static final String CATALOG_TERM = "database"; - private static final String DATABASE_PRODUCT_NAME = "MySQL"; - /* Get actual class name to be printed on */ - private static Logger logger = Logger.getLogger(VitessDatabaseMetaData.class.getName()); - protected final String quotedId = "`"; - protected VitessConnection connection = null; - - public String getURL() throws SQLException { - if (this.connection == null || this.connection.getUrl() == null) { - return null; - } - return this.connection.getUrl().getUrl(); - } - - public String getUserName() throws SQLException { - return this.connection.getUsername(); - } - - public boolean isReadOnly() throws SQLException { - return this.connection.isReadOnly(); - } - - public boolean allProceduresAreCallable() throws SQLException { - return false; - } - - public boolean allTablesAreSelectable() throws SQLException { - return false; - } - - public boolean nullsAreSortedHigh() throws SQLException { - return false; - } - - public boolean nullsAreSortedLow() throws SQLException { - return !this.nullsAreSortedHigh(); - } - - public String getDatabaseProductName() throws SQLException { - return DATABASE_PRODUCT_NAME; - } - - public String getDatabaseProductVersion() throws SQLException { - return this.connection.getDbProperties().getProductVersion(); - } - - public String getDriverVersion() throws SQLException { - return Constants.DRIVER_MAJOR_VERSION + "." + Constants.DRIVER_MINOR_VERSION; - } - - public int getDriverMajorVersion() { - return Constants.DRIVER_MAJOR_VERSION; - } - - public int getDriverMinorVersion() { - return Constants.DRIVER_MINOR_VERSION; - } - - public boolean usesLocalFiles() throws SQLException { - return false; - } - - public boolean usesLocalFilePerTable() throws SQLException { - return false; - } - - public boolean supportsMixedCaseIdentifiers() throws SQLException { - return !connection.getDbProperties().getUseCaseInsensitiveComparisons(); - } - - public boolean storesUpperCaseIdentifiers() throws SQLException { - return false; - } - - public boolean storesLowerCaseIdentifiers() throws SQLException { - return connection.getDbProperties().getStoresLowerCaseTableName(); - } - - public boolean storesMixedCaseIdentifiers() throws SQLException { - return !connection.getDbProperties().getStoresLowerCaseTableName(); - } - - public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { - return !connection.getDbProperties().getUseCaseInsensitiveComparisons(); - } - - public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { - return false; - } - - public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { - return connection.getDbProperties().getStoresLowerCaseTableName(); - } - - public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { - return !connection.getDbProperties().getStoresLowerCaseTableName(); - } - - public String getNumericFunctions() throws SQLException { - return - "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW," - + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE"; - } - - public String getStringFunctions() throws SQLException { - return - "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD," - + - "FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,LTRIM,MAKE_SET,MATCH," - + - "MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SPACE,STRCMP," - + - "SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER"; - } - - public String getSystemFunctions() throws SQLException { - return "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION"; - } - - public String getTimeDateFunctions() throws SQLException { - return - "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND," - + - "PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE,CURRENT_DATE,CURTIME," - + - "CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,SEC_TO_TIME,TIME_TO_SEC"; - } - - public String getSearchStringEscape() throws SQLException { - return SEARCH_STRING_ESCAPE; - } - - public String getExtraNameCharacters() throws SQLException { - return EXTRA_NAME_CHARS; - } - - public boolean supportsAlterTableWithAddColumn() throws SQLException { - return false; - } - - public boolean supportsAlterTableWithDropColumn() throws SQLException { - return false; - } - - public boolean supportsColumnAliasing() throws SQLException { - return true; - } - - public boolean nullPlusNonNullIsNull() throws SQLException { - return true; - } - - public boolean supportsConvert() throws SQLException { - return false; - } - - public boolean supportsConvert(int fromType, int toType) throws SQLException { - return false; - } - - public boolean supportsTableCorrelationNames() throws SQLException { - return false; - } - - public boolean supportsDifferentTableCorrelationNames() throws SQLException { - return false; - } - - public boolean supportsExpressionsInOrderBy() throws SQLException { - return false; - } - - public boolean supportsOrderByUnrelated() throws SQLException { - return false; - } - - public boolean supportsGroupBy() throws SQLException { - return false; - } - - public boolean supportsGroupByUnrelated() throws SQLException { - return false; - } - - public boolean supportsGroupByBeyondSelect() throws SQLException { - return false; - } - - public boolean supportsLikeEscapeClause() throws SQLException { - return true; - } - - public boolean supportsMultipleResultSets() throws SQLException { - return false; - } - - public boolean supportsMultipleTransactions() throws SQLException { - return true; - } - - public boolean supportsNonNullableColumns() throws SQLException { - return true; - } - - public boolean supportsMinimumSQLGrammar() throws SQLException { - return true; - } - - public boolean supportsCoreSQLGrammar() throws SQLException { - return false; - } - - public boolean supportsExtendedSQLGrammar() throws SQLException { - return false; - } - - public boolean supportsANSI92EntryLevelSQL() throws SQLException { - return false; - } - - public boolean supportsANSI92IntermediateSQL() throws SQLException { - return false; - } - - public boolean supportsANSI92FullSQL() throws SQLException { - return false; - } - - public boolean supportsIntegrityEnhancementFacility() throws SQLException { - return false; - } - - public boolean supportsOuterJoins() throws SQLException { - return false; - } + private static final String SEARCH_STRING_ESCAPE = "\\"; + private static final String EXTRA_NAME_CHARS = "#@"; + private static final String SCHEMA_TERM = ""; + private static final String CATALOG_SEPARATOR = "."; + private static final String PROCEDURE_TERM = "procedure"; + private static final String CATALOG_TERM = "database"; + private static final String DATABASE_PRODUCT_NAME = "MySQL"; + /* Get actual class name to be printed on */ + private static Logger logger = Logger.getLogger(VitessDatabaseMetaData.class.getName()); + protected final String quotedId = "`"; + protected VitessConnection connection = null; + + public String getURL() throws SQLException { + if (this.connection == null || this.connection.getUrl() == null) { + return null; + } + return this.connection.getUrl().getUrl(); + } + + public String getUserName() throws SQLException { + return this.connection.getUsername(); + } + + public boolean isReadOnly() throws SQLException { + return this.connection.isReadOnly(); + } + + public boolean allProceduresAreCallable() throws SQLException { + return false; + } + + public boolean allTablesAreSelectable() throws SQLException { + return false; + } + + public boolean nullsAreSortedHigh() throws SQLException { + return false; + } + + public boolean nullsAreSortedLow() throws SQLException { + return !this.nullsAreSortedHigh(); + } + + public String getDatabaseProductName() throws SQLException { + return DATABASE_PRODUCT_NAME; + } + + public String getDatabaseProductVersion() throws SQLException { + return this.connection.getDbProperties().getProductVersion(); + } + + public String getDriverVersion() throws SQLException { + return Constants.DRIVER_MAJOR_VERSION + "." + Constants.DRIVER_MINOR_VERSION; + } + + public int getDriverMajorVersion() { + return Constants.DRIVER_MAJOR_VERSION; + } + + public int getDriverMinorVersion() { + return Constants.DRIVER_MINOR_VERSION; + } + + public boolean usesLocalFiles() throws SQLException { + return false; + } + + public boolean usesLocalFilePerTable() throws SQLException { + return false; + } + + public boolean supportsMixedCaseIdentifiers() throws SQLException { + return !connection.getDbProperties().getUseCaseInsensitiveComparisons(); + } + + public boolean storesUpperCaseIdentifiers() throws SQLException { + return false; + } + + public boolean storesLowerCaseIdentifiers() throws SQLException { + return connection.getDbProperties().getStoresLowerCaseTableName(); + } + + public boolean storesMixedCaseIdentifiers() throws SQLException { + return !connection.getDbProperties().getStoresLowerCaseTableName(); + } + + public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException { + return !connection.getDbProperties().getUseCaseInsensitiveComparisons(); + } + + public boolean storesUpperCaseQuotedIdentifiers() throws SQLException { + return false; + } + + public boolean storesLowerCaseQuotedIdentifiers() throws SQLException { + return connection.getDbProperties().getStoresLowerCaseTableName(); + } + + public boolean storesMixedCaseQuotedIdentifiers() throws SQLException { + return !connection.getDbProperties().getStoresLowerCaseTableName(); + } + + public String getNumericFunctions() throws SQLException { + return + "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN," + + "MOD,PI,POW," + + "POWER,RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE"; + } + + public String getStringFunctions() throws SQLException { + return + "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT," + + "EXPORT_SET,FIELD," + + "FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD," + + "LTRIM,MAKE_SET,MATCH," + + "MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM," + + "SOUNDEX,SPACE,STRCMP," + + "SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER"; + } + + public String getSystemFunctions() throws SQLException { + return "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION"; + } + + public String getTimeDateFunctions() throws SQLException { + return + "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR," + + "MINUTE,SECOND," + + "PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE," + + "CURRENT_DATE,CURTIME," + + "CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME," + + "SEC_TO_TIME,TIME_TO_SEC"; + } + + public String getSearchStringEscape() throws SQLException { + return SEARCH_STRING_ESCAPE; + } + + public String getExtraNameCharacters() throws SQLException { + return EXTRA_NAME_CHARS; + } + + public boolean supportsAlterTableWithAddColumn() throws SQLException { + return false; + } + + public boolean supportsAlterTableWithDropColumn() throws SQLException { + return false; + } + + public boolean supportsColumnAliasing() throws SQLException { + return true; + } + + public boolean nullPlusNonNullIsNull() throws SQLException { + return true; + } + + public boolean supportsConvert() throws SQLException { + return false; + } + + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsExpressionsInOrderBy() throws SQLException { + return false; + } + + public boolean supportsOrderByUnrelated() throws SQLException { + return false; + } + + public boolean supportsGroupBy() throws SQLException { + return false; + } + + public boolean supportsGroupByUnrelated() throws SQLException { + return false; + } + + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + public boolean supportsLikeEscapeClause() throws SQLException { + return true; + } + + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + public boolean supportsMultipleTransactions() throws SQLException { + return true; + } + + public boolean supportsNonNullableColumns() throws SQLException { + return true; + } + + public boolean supportsMinimumSQLGrammar() throws SQLException { + return true; + } + + public boolean supportsCoreSQLGrammar() throws SQLException { + return false; + } + + public boolean supportsExtendedSQLGrammar() throws SQLException { + return false; + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } - public boolean supportsFullOuterJoins() throws SQLException { - return false; - } + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } - public boolean supportsLimitedOuterJoins() throws SQLException { - return false; - } + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } - public String getSchemaTerm() throws SQLException { - return SCHEMA_TERM; - } + public boolean supportsOuterJoins() throws SQLException { + return false; + } - public String getProcedureTerm() throws SQLException { - return PROCEDURE_TERM; - } + public boolean supportsFullOuterJoins() throws SQLException { + return false; + } - public String getCatalogTerm() throws SQLException { - return CATALOG_TERM; - } + public boolean supportsLimitedOuterJoins() throws SQLException { + return false; + } - public boolean isCatalogAtStart() throws SQLException { - return true; - } + public String getSchemaTerm() throws SQLException { + return SCHEMA_TERM; + } - public String getCatalogSeparator() throws SQLException { - return CATALOG_SEPARATOR; - } + public String getProcedureTerm() throws SQLException { + return PROCEDURE_TERM; + } - public VitessConnection getConnection() throws SQLException { - return this.connection; - } + public String getCatalogTerm() throws SQLException { + return CATALOG_TERM; + } - public void setConnection(VitessConnection vitessConnection) throws SQLException { - this.connection = vitessConnection; - } + public boolean isCatalogAtStart() throws SQLException { + return true; + } - public boolean supportsSchemasInDataManipulation() throws SQLException { - return false; - } + public String getCatalogSeparator() throws SQLException { + return CATALOG_SEPARATOR; + } - public boolean supportsSchemasInProcedureCalls() throws SQLException { - return false; - } + public VitessConnection getConnection() throws SQLException { + return this.connection; + } - public boolean supportsSchemasInTableDefinitions() throws SQLException { - return false; - } + public void setConnection(VitessConnection vitessConnection) throws SQLException { + this.connection = vitessConnection; + } - public boolean supportsSchemasInIndexDefinitions() throws SQLException { - return false; - } + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } - public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - return false; - } + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } - public boolean supportsCatalogsInDataManipulation() throws SQLException { - return false; - } + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } - public boolean supportsCatalogsInProcedureCalls() throws SQLException { - return false; - } + public boolean supportsSchemasInIndexDefinitions() throws SQLException { + return false; + } - public boolean supportsCatalogsInTableDefinitions() throws SQLException { - return false; - } + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } - public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - return false; - } + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } - public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { - return false; - } + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } - public boolean supportsPositionedDelete() throws SQLException { - return false; - } + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } - public boolean supportsPositionedUpdate() throws SQLException { - return false; - } + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } - public boolean supportsSelectForUpdate() throws SQLException { - return false; - } + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } - public boolean supportsStoredProcedures() throws SQLException { - return false; - } + public boolean supportsPositionedDelete() throws SQLException { + return false; + } - public boolean supportsSubqueriesInComparisons() throws SQLException { - return false; - } + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } - public boolean supportsSubqueriesInExists() throws SQLException { - return false; - } + public boolean supportsSelectForUpdate() throws SQLException { + return false; + } - public boolean supportsSubqueriesInIns() throws SQLException { - return false; - } + public boolean supportsStoredProcedures() throws SQLException { + return false; + } - public boolean supportsSubqueriesInQuantifieds() throws SQLException { - return false; - } + public boolean supportsSubqueriesInComparisons() throws SQLException { + return false; + } - public boolean supportsCorrelatedSubqueries() throws SQLException { - return false; - } + public boolean supportsSubqueriesInExists() throws SQLException { + return false; + } - public boolean supportsUnion() throws SQLException { - return false; - } + public boolean supportsSubqueriesInIns() throws SQLException { + return false; + } - public boolean supportsUnionAll() throws SQLException { - return false; - } + public boolean supportsSubqueriesInQuantifieds() throws SQLException { + return false; + } - public boolean supportsOpenCursorsAcrossCommit() throws SQLException { - return false; - } + public boolean supportsCorrelatedSubqueries() throws SQLException { + return false; + } - public boolean supportsOpenCursorsAcrossRollback() throws SQLException { - return false; - } + public boolean supportsUnion() throws SQLException { + return false; + } - public boolean supportsOpenStatementsAcrossCommit() throws SQLException { - return false; - } + public boolean supportsUnionAll() throws SQLException { + return false; + } - public boolean supportsOpenStatementsAcrossRollback() throws SQLException { - return false; - } + public boolean supportsOpenCursorsAcrossCommit() throws SQLException { + return false; + } - public int getMaxBinaryLiteralLength() throws SQLException { - return 16777208; - } + public boolean supportsOpenCursorsAcrossRollback() throws SQLException { + return false; + } - public int getMaxCharLiteralLength() throws SQLException { - return 16777208; - } + public boolean supportsOpenStatementsAcrossCommit() throws SQLException { + return false; + } - public int getMaxColumnNameLength() throws SQLException { - return 64; - } + public boolean supportsOpenStatementsAcrossRollback() throws SQLException { + return false; + } - public int getMaxColumnsInGroupBy() throws SQLException { - return 64; - } + public int getMaxBinaryLiteralLength() throws SQLException { + return 16777208; + } - public int getMaxColumnsInIndex() throws SQLException { - return 16; - } + public int getMaxCharLiteralLength() throws SQLException { + return 16777208; + } - public int getMaxColumnsInOrderBy() throws SQLException { - return 64; - } + public int getMaxColumnNameLength() throws SQLException { + return 64; + } - public int getMaxColumnsInSelect() throws SQLException { - return 256; - } + public int getMaxColumnsInGroupBy() throws SQLException { + return 64; + } - public int getMaxConnections() throws SQLException { - return 0; - } + public int getMaxColumnsInIndex() throws SQLException { + return 16; + } - public int getMaxCursorNameLength() throws SQLException { - return 0; - } + public int getMaxColumnsInOrderBy() throws SQLException { + return 64; + } - public int getMaxIndexLength() throws SQLException { - return 256; - } + public int getMaxColumnsInSelect() throws SQLException { + return 256; + } - public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { - return false; - } + public int getMaxConnections() throws SQLException { + return 0; + } - public int getMaxStatements() throws SQLException { - return 0; - } + public int getMaxCursorNameLength() throws SQLException { + return 0; + } - public int getMaxTableNameLength() throws SQLException { - return 64; - } + public int getMaxIndexLength() throws SQLException { + return 256; + } - public int getMaxTablesInSelect() throws SQLException { - return 256; - } + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } - public int getMaxUserNameLength() throws SQLException { - return 16; - } + public int getMaxStatements() throws SQLException { + return 0; + } - public int getMaxProcedureNameLength() throws SQLException { - return 256; - } + public int getMaxTableNameLength() throws SQLException { + return 64; + } - public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { - return false; - } + public int getMaxTablesInSelect() throws SQLException { + return 256; + } - public boolean supportsDataManipulationTransactionsOnly() throws SQLException { - return false; - } + public int getMaxUserNameLength() throws SQLException { + return 16; + } - public boolean dataDefinitionCausesTransactionCommit() throws SQLException { - return false; - } + public int getMaxProcedureNameLength() throws SQLException { + return 256; + } - public boolean dataDefinitionIgnoredInTransactions() throws SQLException { - return false; - } - - public String getIdentifierQuoteString() throws SQLException { - return this.quotedId; - } - - public ResultSet getProcedures(String catalog, String schemaPattern, - String procedureNamePattern) throws SQLException { - return null; - } - - public ResultSet getProcedureColumns(String catalog, String schemaPattern, - String procedureNamePattern, String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean supportsResultSetType(int type) throws SQLException { - return type == ResultSet.TYPE_FORWARD_ONLY; - } - - public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { - return (type == ResultSet.TYPE_FORWARD_ONLY && concurrency == ResultSet.CONCUR_READ_ONLY); - } - - public boolean ownUpdatesAreVisible(int type) throws SQLException { - return false; - } - - public boolean ownDeletesAreVisible(int type) throws SQLException { - return false; - } - - public boolean ownInsertsAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersUpdatesAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersDeletesAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersInsertsAreVisible(int type) throws SQLException { - return false; - } - - public boolean updatesAreDetected(int type) throws SQLException { - return false; - } - - public boolean deletesAreDetected(int type) throws SQLException { - return false; - } - - public boolean insertsAreDetected(int type) throws SQLException { - return false; - } - - public boolean supportsBatchUpdates() throws SQLException { - return true; - } - - public boolean supportsSavepoints() throws SQLException { - return false; - } - - public boolean supportsNamedParameters() throws SQLException { - return false; - } - - public boolean supportsMultipleOpenResults() throws SQLException { - return false; - } - - public boolean supportsGetGeneratedKeys() throws SQLException { - return true; - } + public boolean supportsDataDefinitionAndDataManipulationTransactions() throws SQLException { + return false; + } - public boolean supportsResultSetHoldability(int holdability) throws SQLException { - return false; - } + public boolean supportsDataManipulationTransactionsOnly() throws SQLException { + return false; + } - public int getResultSetHoldability() throws SQLException { - return 0; - } + public boolean dataDefinitionCausesTransactionCommit() throws SQLException { + return false; + } - public int getDatabaseMajorVersion() throws SQLException { - return Integer.valueOf(this.connection.getDbProperties().getMajorVersion()); - } + public boolean dataDefinitionIgnoredInTransactions() throws SQLException { + return false; + } - public int getDatabaseMinorVersion() throws SQLException { - return Integer.valueOf(this.connection.getDbProperties().getMinorVersion()); - } + public String getIdentifierQuoteString() throws SQLException { + return this.quotedId; + } - public int getJDBCMajorVersion() throws SQLException { - return 1; - } + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) + throws SQLException { + return null; + } + + public ResultSet getProcedureColumns(String catalog, String schemaPattern, + String procedureNamePattern, String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } - public int getJDBCMinorVersion() throws SQLException { - return 0; - } + public boolean supportsResultSetType(int type) throws SQLException { + return type == ResultSet.TYPE_FORWARD_ONLY; + } - public boolean supportsStatementPooling() throws SQLException { - return false; - } + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLException { + return (type == ResultSet.TYPE_FORWARD_ONLY && concurrency == ResultSet.CONCUR_READ_ONLY); + } - public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { - return false; - } - - public boolean autoCommitFailureClosesAllResultSets() throws SQLException { - return false; - } + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + public boolean insertsAreDetected(int type) throws SQLException { + return false; + } + + public boolean supportsBatchUpdates() throws SQLException { + return true; + } + + public boolean supportsSavepoints() throws SQLException { + return false; + } + + public boolean supportsNamedParameters() throws SQLException { + return false; + } + + public boolean supportsMultipleOpenResults() throws SQLException { + return false; + } + + public boolean supportsGetGeneratedKeys() throws SQLException { + return true; + } + + public boolean supportsResultSetHoldability(int holdability) throws SQLException { + return false; + } + + public int getResultSetHoldability() throws SQLException { + return 0; + } + + public int getDatabaseMajorVersion() throws SQLException { + return Integer.valueOf(this.connection.getDbProperties().getMajorVersion()); + } + + public int getDatabaseMinorVersion() throws SQLException { + return Integer.valueOf(this.connection.getDbProperties().getMinorVersion()); + } + + public int getJDBCMajorVersion() throws SQLException { + return 1; + } + + public int getJDBCMinorVersion() throws SQLException { + return 0; + } + + public boolean supportsStatementPooling() throws SQLException { + return false; + } + + public boolean supportsStoredFunctionsUsingCallSyntax() throws SQLException { + return false; + } + + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } - public boolean generatedKeyAlwaysReturned() throws SQLException { - return true; - } + public boolean generatedKeyAlwaysReturned() throws SQLException { + return true; + } - public T unwrap(Class iface) throws SQLException { - return null; - } + public T unwrap(Class iface) throws SQLException { + return null; + } - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java index a06f7df9904..0cb46209e1d 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -38,101 +38,97 @@ */ public class VitessDriver implements Driver { - static { - try { - DriverManager.registerDriver(new VitessDriver()); - } catch (SQLException e) { - throw new RuntimeException( - Constants.SQLExceptionMessages.INIT_FAILED + " : " + e.getErrorCode() + " - " + e - .getMessage()); - } + static { + try { + DriverManager.registerDriver(new VitessDriver()); + } catch (SQLException e) { + throw new RuntimeException( + Constants.SQLExceptionMessages.INIT_FAILED + " : " + e.getErrorCode() + " - " + e + .getMessage()); } + } - @Override - public Connection connect(String url, Properties info) throws SQLException { - if (!acceptsURL(url)) { - return null; - } - final VitessConnection connection = new VitessConnection(url, info); - connection.connect(); - return connection; + @Override + public Connection connect(String url, Properties info) throws SQLException { + if (!acceptsURL(url)) { + return null; } - - /** - * Checks whether a given url is in a valid format. - *

- * The current uri format is: jdbc:vitess://[host]:[port] - * - * @param url the URL of the database - * @return true, if this driver understands the given URL; - * false, otherwise - *

- * TODO: Write a better regex - */ - @Override - public boolean acceptsURL(String url) { - return null != url && url.startsWith(Constants.URL_PREFIX); + final VitessConnection connection = new VitessConnection(url, info); + connection.connect(); + return connection; + } + + /** + * Checks whether a given url is in a valid format. + *

+ * The current uri format is: jdbc:vitess://[host]:[port] + * + * @param url the URL of the database + * @return true, if this driver understands the given URL; false, otherwise + *

+ * TODO: Write a better regex + */ + @Override + public boolean acceptsURL(String url) { + return null != url && url.startsWith(Constants.URL_PREFIX); + } + + /** + * Given a String URL and a Properties object, computes the expected and required parameters for + * the driver. Parameters can be set in either the URL or Properties. + * + * @param url - Connection Url A vitess-compatible URL, per {@link VitessJDBCUrl} i.e. + * jdbc:vitess://locahost:9000/vt_keyspace?TABLET_TYPE=master + * @param info - Property for the connection May contain additional properties to configure + * this driver with + * @return DriverPropertyInfo Array Object + */ + @Override + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { + if (null == info) { + info = new Properties(); } - /** - * Given a String URL and a Properties object, computes the expected and - * required parameters for the driver. Parameters can be set in either the URL - * or Properties. - * - * @param url - Connection Url - * A vitess-compatible URL, per {@link VitessJDBCUrl} - * i.e. jdbc:vitess://locahost:9000/vt_keyspace?TABLET_TYPE=master - * @param info - Property for the connection - * May contain additional properties to configure this driver with - * @return DriverPropertyInfo Array Object - * @throws SQLException - */ - @Override - public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { - if (null == info) { - info = new Properties(); - } - - DriverPropertyInfo[] dpi = ConnectionProperties.exposeAsDriverPropertyInfo(info, 2); - if (acceptsURL(url)) { - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl(url, info); - - dpi[0] = new DriverPropertyInfo(Constants.Property.HOST, - vitessJDBCUrl.getHostInfos().get(0).getHostname()); - dpi[0].required = true; - dpi[0].description = Constants.VITESS_HOST; - - dpi[1] = new DriverPropertyInfo(Constants.Property.PORT, - (new Integer(vitessJDBCUrl.getHostInfos().get(0).getPort())).toString()); - dpi[1].required = false; - dpi[1].description = Constants.VITESS_PORT; - - } else { - throw new SQLException(Constants.SQLExceptionMessages.INVALID_CONN_URL + " : " + url); - } - - return dpi; - } + DriverPropertyInfo[] dpi = ConnectionProperties.exposeAsDriverPropertyInfo(info, 2); + if (acceptsURL(url)) { + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl(url, info); - @Override - public int getMajorVersion() { - return Constants.DRIVER_MAJOR_VERSION; - } + dpi[0] = new DriverPropertyInfo(Constants.Property.HOST, + vitessJDBCUrl.getHostInfos().get(0).getHostname()); + dpi[0].required = true; + dpi[0].description = Constants.VITESS_HOST; - @Override - public int getMinorVersion() { - return Constants.DRIVER_MINOR_VERSION; - } + dpi[1] = new DriverPropertyInfo(Constants.Property.PORT, + (new Integer(vitessJDBCUrl.getHostInfos().get(0).getPort())).toString()); + dpi[1].required = false; + dpi[1].description = Constants.VITESS_PORT; - @Override - public boolean jdbcCompliant() { - return Constants.JDBC_COMPLIANT; + } else { + throw new SQLException(Constants.SQLExceptionMessages.INVALID_CONN_URL + " : " + url); } - @Override - public Logger getParentLogger() throws SQLFeatureNotSupportedException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + return dpi; + } + + @Override + public int getMajorVersion() { + return Constants.DRIVER_MAJOR_VERSION; + } + + @Override + public int getMinorVersion() { + return Constants.DRIVER_MINOR_VERSION; + } + + @Override + public boolean jdbcCompliant() { + return Constants.JDBC_COMPLIANT; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java index 416a76734a6..44814416bc5 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -30,12 +30,11 @@ import java.util.regex.Pattern; /** - * VitessJDBCUrl is responsible for parsing a driver URL and Properties object, - * returning a new Properties object with configuration from the URL and passed in Properties - * merged. + * VitessJDBCUrl is responsible for parsing a driver URL and Properties object, returning a new + * Properties object with configuration from the URL and passed in Properties merged. *

- * Parameters passed in through the Properties object take precedence over the parameters - * in the URL, where there are conflicts. + * Parameters passed in through the Properties object take precedence over the parameters in the + * URL, where there are conflicts. *

* The Passed in URL is expected to conform to the following basic format: *

@@ -43,83 +42,80 @@ */ public class VitessJDBCUrl { - private final String url; - private final List hostInfos; - private final Properties info; + private final String url; + private final List hostInfos; + private final Properties info; - /* - Assuming List of vtGate ips could be given in url, separated by "," - */ - public static class HostInfo { - private String hostname; - private int port; + /* + Assuming List of vtGate ips could be given in url, separated by "," + */ + public static class HostInfo { - public HostInfo(String hostname, int port) { - this.hostname = hostname; - this.port = port; - } + private String hostname; + private int port; - public String getHostname() { - return hostname; - } + public HostInfo(String hostname, int port) { + this.hostname = hostname; + this.port = port; + } - public int getPort() { - return port; - } + public String getHostname() { + return hostname; + } - @Override - public String toString() { - return hostname + ":" + port; - } + public int getPort() { + return port; } - /** - *

Create VitessJDBC url object for given urls and properties.

- *

- *

To indicate that SSL should be used, URL's follow the MySQL and MariaDB convention of including - * the property useSSL=true. To use a keyStore and trustStore other than the JRE - * default, you can add the following URL properties:

- *

- *

- *

    - *
  • keyStore=path_to_keystore_file
  • - *
  • keyStorePassword=password (if set)
  • - *
  • keyPassword=password (only needed if the private key password differs from - * the keyStore password)
  • - *
  • keyAlias=alias_under_which_private_key_is_stored (if not set, then the - * first valid PrivateKeyEntry found in the keyStore will be used)
  • - *
  • trustStore=path_to_truststore_file
  • - *
  • trustStorePassword=password (if set)
  • - *
  • trustAlias=alias_under_which_certificate_chain_is_stored (if not set, - * then the first valid X509Certificate found in the trustStore will be used)
  • - *
- *

- *

- *

If useSSL=true, and any of these additional properties are not set on the JDBC URL, - * then the driver will look to see if these corresponding property was set at JVM startup time:

- *

- *

- *

    - *
  • -Djavax.net.ssl.keyStore
  • - *
  • -Djavax.net.ssl.keyStorePassword
  • - *
  • -Djavax.net.ssl.keyPassword
  • - *
  • -Djavax.net.ssl.keyAlias
  • - *
  • -Djavax.net.ssl.trustStore
  • - *
  • -Djavax.net.ssl.trustStorePassword
  • - *
  • -Djavax.net.ssl.trustStoreAlias
  • - *
- *

- *

- *

See:

- *

https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/#tls-ssl

- *

https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-using-ssl.html

- * - * @param url - * @param info - * @return - * @throws SQLException - */ - public VitessJDBCUrl(String url, Properties info) throws SQLException { + @Override + public String toString() { + return hostname + ":" + port; + } + } + + /** + *

Create VitessJDBC url object for given urls and properties.

+ *

+ *

To indicate that SSL should be used, URL's follow the MySQL and MariaDB convention of + * including the property useSSL=true. To use a keyStore and trustStore other than + * the JRE default, you can add the following URL properties:

+ *

+ *

+ *

    + *
  • keyStore=path_to_keystore_file
  • + *
  • keyStorePassword=password (if set)
  • + *
  • keyPassword=password (only needed if the private key password differs from + * the keyStore password)
  • + *
  • keyAlias=alias_under_which_private_key_is_stored (if not set, then the + * first valid PrivateKeyEntry found in the keyStore will be used)
  • + *
  • trustStore=path_to_truststore_file
  • + *
  • trustStorePassword=password (if set)
  • + *
  • trustAlias=alias_under_which_certificate_chain_is_stored (if not set, + * then the first valid X509Certificate found in the trustStore will be used)
  • + *
+ *

+ *

+ *

If useSSL=true, and any of these additional properties are not set on the JDBC + * URL, then the driver will look to see if these corresponding property was set at JVM startup + * time:

+ *

+ *

+ *

    + *
  • -Djavax.net.ssl.keyStore
  • + *
  • -Djavax.net.ssl.keyStorePassword
  • + *
  • -Djavax.net.ssl.keyPassword
  • + *
  • -Djavax.net.ssl.keyAlias
  • + *
  • -Djavax.net.ssl.trustStore
  • + *
  • -Djavax.net.ssl.trustStorePassword
  • + *
  • -Djavax.net.ssl.trustStoreAlias
  • + *
+ *

+ *

+ *

See:

+ *

https://mariadb.com/kb/en/mariadb/about-mariadb-connector-j/#tls-ssl

+ *

https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-reference-using-ssl.html

+ */ + public VitessJDBCUrl(String url, Properties info) throws SQLException { /* URL pattern e.g. jdbc:vitess://username:password@ip1:port1,ip2:port2/keyspace/catalog? property1=value1.. @@ -137,146 +133,144 @@ public VitessJDBCUrl(String url, Properties info) throws SQLException { m.group(12) = "property1=value1.." */ - final Pattern p = Pattern.compile(Constants.URL_PATTERN); - final Matcher m = p.matcher(url); - if (!m.find()) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - - info = getURLParamProperties(m.group(12), info); - - // Will add password property once its supported from vitess - // this.password = (m.group(5) == null ? info.getProperty("password") : m.group(5)); - String postUrl = m.group(6); - if (null == postUrl) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - - this.hostInfos = getURLHostInfos(postUrl); - this.url = url; + final Pattern p = Pattern.compile(Constants.URL_PATTERN); + final Matcher m = p.matcher(url); + if (!m.find()) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); + } - // For Backward Compatibility of username in connection url. - String userName = m.group(3); - if (!StringUtils.isNullOrEmptyWithoutWS(userName)) { - info.setProperty(Constants.Property.USERNAME, userName); - } + info = getURLParamProperties(m.group(12), info); - // For Backward Compatibility of keyspace & catalog/database/schema name in connection url. - String keyspace = m.group(8); - if (!StringUtils.isNullOrEmptyWithoutWS(keyspace)) { - info.setProperty(Constants.Property.KEYSPACE, keyspace); - String catalog = m.group(10); - if (!StringUtils.isNullOrEmptyWithoutWS(catalog)) { - info.setProperty(Constants.Property.DBNAME, catalog); - } else { - info.setProperty(Constants.Property.DBNAME, keyspace); - } - } + // Will add password property once its supported from vitess + // this.password = (m.group(5) == null ? info.getProperty("password") : m.group(5)); + String postUrl = m.group(6); + if (null == postUrl) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); + } - // For Backward Compatibility of old tablet type. - String oldTabletType = info.getProperty(Constants.Property.OLD_TABLET_TYPE); - String tabletType = info.getProperty(Constants.Property.TABLET_TYPE); - if (null != tabletType) { - info.setProperty(Constants.Property.OLD_TABLET_TYPE, tabletType); - } else if (null != oldTabletType) { - info.setProperty(Constants.Property.TABLET_TYPE, oldTabletType); - } + this.hostInfos = getURLHostInfos(postUrl); + this.url = url; - this.info = info; + // For Backward Compatibility of username in connection url. + String userName = m.group(3); + if (!StringUtils.isNullOrEmptyWithoutWS(userName)) { + info.setProperty(Constants.Property.USERNAME, userName); } - public String getUrl() { - return url; + // For Backward Compatibility of keyspace & catalog/database/schema name in connection url. + String keyspace = m.group(8); + if (!StringUtils.isNullOrEmptyWithoutWS(keyspace)) { + info.setProperty(Constants.Property.KEYSPACE, keyspace); + String catalog = m.group(10); + if (!StringUtils.isNullOrEmptyWithoutWS(catalog)) { + info.setProperty(Constants.Property.DBNAME, catalog); + } else { + info.setProperty(Constants.Property.DBNAME, keyspace); + } } - public List getHostInfos() { - return hostInfos; + // For Backward Compatibility of old tablet type. + String oldTabletType = info.getProperty(Constants.Property.OLD_TABLET_TYPE); + String tabletType = info.getProperty(Constants.Property.TABLET_TYPE); + if (null != tabletType) { + info.setProperty(Constants.Property.OLD_TABLET_TYPE, tabletType); + } else if (null != oldTabletType) { + info.setProperty(Constants.Property.TABLET_TYPE, oldTabletType); } - /** - * Get Properties object for params after ? in url. - * - * @param paramString Parameter String in the url - * @param info passed in the connection - * @return Properties updated with parameters - */ - - private static Properties getURLParamProperties(String paramString, Properties info) - throws SQLException { - // If passed in, don't use info properties directly so we don't act upon it accidentally. - // instead use as defaults for a new properties object - info = (info == null) ? new Properties() : new Properties(info); - - if (!StringUtils.isNullOrEmptyWithoutWS(paramString)) { - StringTokenizer queryParams = new StringTokenizer(paramString, "&"); //$NON-NLS-1$ - while (queryParams.hasMoreTokens()) { - String parameterValuePair = queryParams.nextToken(); - int indexOfEquals = parameterValuePair.indexOf('='); - - String parameter = null; - String value = null; - - if (indexOfEquals != -1) { - parameter = parameterValuePair.substring(0, indexOfEquals); - - if (indexOfEquals + 1 < parameterValuePair.length()) { - value = parameterValuePair.substring(indexOfEquals + 1); - } - } - - // Per the mysql-connector-java docs, passed in Properties values should take precedence over - // those in the URL. See javadoc for NonRegisteringDriver#connect - if ((null != value && value.length() > 0) && (parameter.length() > 0) && null == info.getProperty(parameter)) { - try { - info.put(parameter, URLDecoder.decode(value, "UTF-8")); - } catch (UnsupportedEncodingException | NoSuchMethodError badEncoding) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - } - } + this.info = info; + } + + public String getUrl() { + return url; + } + + public List getHostInfos() { + return hostInfos; + } + + /** + * Get Properties object for params after ? in url. + * + * @param paramString Parameter String in the url + * @param info passed in the connection + * @return Properties updated with parameters + */ + + private static Properties getURLParamProperties(String paramString, Properties info) + throws SQLException { + // If passed in, don't use info properties directly so we don't act upon it accidentally. + // instead use as defaults for a new properties object + info = (info == null) ? new Properties() : new Properties(info); + + if (!StringUtils.isNullOrEmptyWithoutWS(paramString)) { + StringTokenizer queryParams = new StringTokenizer(paramString, "&"); //$NON-NLS-1$ + while (queryParams.hasMoreTokens()) { + String parameterValuePair = queryParams.nextToken(); + int indexOfEquals = parameterValuePair.indexOf('='); + + String parameter = null; + String value = null; + + if (indexOfEquals != -1) { + parameter = parameterValuePair.substring(0, indexOfEquals); + + if (indexOfEquals + 1 < parameterValuePair.length()) { + value = parameterValuePair.substring(indexOfEquals + 1); + } } - return info; + // Per the mysql-connector-java docs, passed in Properties values should take precedence + // over + // those in the URL. See javadoc for NonRegisteringDriver#connect + if ((null != value && value.length() > 0) && (parameter.length() > 0) && null == info + .getProperty(parameter)) { + try { + info.put(parameter, URLDecoder.decode(value, "UTF-8")); + } catch (UnsupportedEncodingException | NoSuchMethodError badEncoding) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); + } + } + } } - /** - * Get List of Hosts for url separated by commas - * - * @param hostURLs - * @return - * @throws SQLException - */ - private static List getURLHostInfos(String hostURLs) throws SQLException { - List hostInfos = new ArrayList<>(); - - StringTokenizer stringTokenizer = new StringTokenizer(hostURLs, ","); - while (stringTokenizer.hasMoreTokens()) { - String hostString = stringTokenizer.nextToken(); + return info; + } + + /** + * Get List of Hosts for url separated by commas + */ + private static List getURLHostInfos(String hostURLs) throws SQLException { + List hostInfos = new ArrayList<>(); + + StringTokenizer stringTokenizer = new StringTokenizer(hostURLs, ","); + while (stringTokenizer.hasMoreTokens()) { + String hostString = stringTokenizer.nextToken(); /* pattern = ip:port */ - final Pattern p = Pattern.compile("([^/:]+):(\\d+)?"); - final Matcher m = p.matcher(hostString); - if (!m.find()) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - String hostname = m.group(1); - int port; - if (m.group(2) != null) { - port = Integer.parseInt(m.group(2)); - } else { - port = Integer.parseInt(Constants.DEFAULT_PORT); - } - HostInfo hostInfo = new HostInfo(hostname, port); - hostInfos.add(hostInfo); - } - if (hostInfos.size() == 0) { - throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); - } - return hostInfos; + final Pattern p = Pattern.compile("([^/:]+):(\\d+)?"); + final Matcher m = p.matcher(hostString); + if (!m.find()) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); + } + String hostname = m.group(1); + int port; + if (m.group(2) != null) { + port = Integer.parseInt(m.group(2)); + } else { + port = Integer.parseInt(Constants.DEFAULT_PORT); + } + HostInfo hostInfo = new HostInfo(hostname, port); + hostInfos.add(hostInfo); } - - public Properties getProperties() { - return info; + if (hostInfos.size() == 0) { + throw new SQLException(Constants.SQLExceptionMessages.MALFORMED_URL); } + return hostInfos; + } + + public Properties getProperties() { + return info; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMariaDBDatabaseMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMariaDBDatabaseMetadata.java index 5b0f47f7e07..e372f150996 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMariaDBDatabaseMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMariaDBDatabaseMetadata.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -30,511 +30,499 @@ /** * Created by ashudeep.sharma on 15/02/16. */ -public class VitessMariaDBDatabaseMetadata extends VitessDatabaseMetaData - implements DatabaseMetaData { +public class VitessMariaDBDatabaseMetadata extends VitessDatabaseMetaData implements + DatabaseMetaData { + + private static final String DRIVER_NAME = "Vitess MariaDB JDBC Driver"; + private static Logger logger = Logger.getLogger(VitessMariaDBDatabaseMetadata.class.getName()); + + public VitessMariaDBDatabaseMetadata(VitessConnection connection) throws SQLException { + this.setConnection(connection); + } + + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + public boolean nullsAreSortedAtEnd() throws SQLException { + return !this.nullsAreSortedAtStart(); + } + + public String getDatabaseProductVersion() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public String getDriverName() throws SQLException { + return DRIVER_NAME; + } + + public String getSQLKeywords() throws SQLException { + return "ACCESSIBLE," + "ANALYZE," + "ASENSITIVE," + "BEFORE," + "BIGINT," + "BINARY," + "BLOB," + + "CALL," + "CHANGE," + "CONDITION," + "DATABASE," + "DATABASES," + "DAY_HOUR," + + "DAY_MICROSECOND," + "DAY_MINUTE," + "DAY_SECOND," + "DELAYED," + "DETERMINISTIC," + + "DISTINCTROW," + "DIV," + "DUAL," + "EACH," + "ELSEIF," + "ENCLOSED," + "ESCAPED," + + "EXIT," + "EXPLAIN," + "FLOAT4," + "FLOAT8," + "FORCE," + "FULLTEXT," + "HIGH_PRIORITY," + + "HOUR_MICROSECOND," + "HOUR_MINUTE," + "HOUR_SECOND," + "IF," + "IGNORE," + "INFILE," + + "INOUT," + "INT1," + "INT2," + "INT3," + "INT4," + "INT8," + "ITERATE," + "KEY," + "KEYS," + + "KILL," + "LEAVE," + "LIMIT," + "LINEAR," + "LINES," + "LOAD," + "LOCALTIME," + + "LOCALTIMESTAMP," + "LOCK," + "LONG," + "LONGBLOB," + "LONGTEXT," + "LOOP," + + "LOW_PRIORITY," + "MEDIUMBLOB," + "MEDIUMINT," + "MEDIUMTEXT," + "MIDDLEINT," + + "MINUTE_MICROSECOND," + "MINUTE_SECOND," + "MOD," + "MODIFIES," + "NO_WRITE_TO_BINLOG," + + "OPTIMIZE," + "OPTIONALLY," + "OUT," + "OUTFILE," + "PURGE," + "RANGE," + "READS," + "" + + "READ_ONLY," + "READ_WRITE," + "REGEXP," + "RELEASE," + "RENAME," + "REPEAT," + "REPLACE," + + "REQUIRE," + "RETURN," + "RLIKE," + "SCHEMAS," + "SECOND_MICROSECOND," + "SENSITIVE," + + "SEPARATOR," + "SHOW," + "SPATIAL," + "SPECIFIC," + "SQLEXCEPTION," + "SQL_BIG_RESULT," + + "SQL_CALC_FOUND_ROWS," + "SQL_SMALL_RESULT," + "SSL," + "STARTING," + "STRAIGHT_JOIN," + + "TERMINATED," + "TINYBLOB," + "TINYINT," + "TINYTEXT," + "TRIGGER," + "UNDO," + "UNLOCK," + + "UNSIGNED," + "USE," + "UTC_DATE," + "UTC_TIME," + "UTC_TIMESTAMP," + "VARBINARY," + + "VARCHARACTER," + "WHILE," + "X509," + "XOR," + "YEAR_MONTH," + "ZEROFILL," + "GENERAL," + + "IGNORE_SERVER_IDS," + "MASTER_HEARTBEAT_PERIOD," + "MAXVALUE," + "RESIGNAL," + "SIGNAL" + + "SLOW"; + } + + public boolean supportsConvert() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsExpressionsInOrderBy() throws SQLException { + return false; + } + + public boolean supportsOrderByUnrelated() throws SQLException { + return false; + } + + public boolean supportsGroupBy() throws SQLException { + return false; + } + + public boolean supportsGroupByUnrelated() throws SQLException { + return false; + } + + public boolean supportsGroupByBeyondSelect() throws SQLException { + return false; + } + + public boolean supportsMultipleResultSets() throws SQLException { + return false; + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } + + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } + + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } + + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } + + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } + + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } + + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } + + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } + + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } + + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } + + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } + + public boolean supportsPositionedDelete() throws SQLException { + return false; + } + + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + public boolean supportsSubqueriesInComparisons() throws SQLException { + return false; + } - private static final String DRIVER_NAME = "Vitess MariaDB JDBC Driver"; - private static Logger logger = Logger.getLogger(VitessMariaDBDatabaseMetadata.class.getName()); + public int getMaxColumnsInTable() throws SQLException { + return 512; + } - public VitessMariaDBDatabaseMetadata(VitessConnection connection) throws SQLException { - this.setConnection(connection); - } - - public boolean nullsAreSortedAtStart() throws SQLException { - return false; - } - - public boolean nullsAreSortedAtEnd() throws SQLException { - return !this.nullsAreSortedAtStart(); - } - - public String getDatabaseProductVersion() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public String getDriverName() throws SQLException { - return DRIVER_NAME; - } - - public String getSQLKeywords() throws SQLException { - return "ACCESSIBLE," + "ANALYZE," + "ASENSITIVE," + "BEFORE," + "BIGINT," + "BINARY," - + "BLOB," + "CALL," + - "CHANGE," + "CONDITION," + "DATABASE," + "DATABASES," + "DAY_HOUR," + "DAY_MICROSECOND," - + "DAY_MINUTE," + "DAY_SECOND," + "DELAYED," + "DETERMINISTIC," + "DISTINCTROW," - + "DIV," + "DUAL," + "EACH," + "ELSEIF," + "ENCLOSED," + "ESCAPED," + "EXIT," - + "EXPLAIN," + "FLOAT4," + "FLOAT8," + "FORCE," + "FULLTEXT," + - "HIGH_PRIORITY," + "HOUR_MICROSECOND," + "HOUR_MINUTE," + "HOUR_SECOND," + "IF," - + "IGNORE," + "INFILE," + "INOUT," + "INT1," + "INT2," + "INT3," + "INT4," + "INT8," - + "ITERATE," + "KEY," + "KEYS," + "KILL," + - "LEAVE," + "LIMIT," + "LINEAR," + "LINES," + "LOAD," + "LOCALTIME," + "LOCALTIMESTAMP," - + "LOCK," + - "LONG," + "LONGBLOB," + "LONGTEXT," + "LOOP," + "LOW_PRIORITY," + "MEDIUMBLOB," - + "MEDIUMINT," + - "MEDIUMTEXT," + "MIDDLEINT," + "MINUTE_MICROSECOND," + "MINUTE_SECOND," + "MOD," - + "MODIFIES," + - "NO_WRITE_TO_BINLOG," + "OPTIMIZE," + "OPTIONALLY," + "OUT," + "OUTFILE," + "PURGE," - + "RANGE," + "READS," + - "" + "READ_ONLY," + "READ_WRITE," + "REGEXP," + "RELEASE," + "RENAME," + "REPEAT," - + "REPLACE," + - "REQUIRE," + "RETURN," + "RLIKE," + "SCHEMAS," + "SECOND_MICROSECOND," + "SENSITIVE," - + "SEPARATOR," + - "SHOW," + "SPATIAL," + "SPECIFIC," + "SQLEXCEPTION," + "SQL_BIG_RESULT," - + "SQL_CALC_FOUND_ROWS," + - "SQL_SMALL_RESULT," + "SSL," + "STARTING," + "STRAIGHT_JOIN," + "TERMINATED," - + "TINYBLOB," + "TINYINT," + "TINYTEXT," + "TRIGGER," + "UNDO," + "UNLOCK," - + "UNSIGNED," + "USE," + "UTC_DATE," + "UTC_TIME," + - "UTC_TIMESTAMP," + "VARBINARY," + "VARCHARACTER," + "WHILE," + "X509," + "XOR," - + "YEAR_MONTH," + - "ZEROFILL," + "GENERAL," + "IGNORE_SERVER_IDS," + "MASTER_HEARTBEAT_PERIOD," - + "MAXVALUE," + "RESIGNAL," + "SIGNAL" + "SLOW"; - } - - public boolean supportsConvert() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean supportsConvert(int fromType, int toType) throws SQLException { - return false; - } - - public boolean supportsTableCorrelationNames() throws SQLException { - return false; - } - - public boolean supportsDifferentTableCorrelationNames() throws SQLException { - return false; - } - - public boolean supportsExpressionsInOrderBy() throws SQLException { - return false; - } - - public boolean supportsOrderByUnrelated() throws SQLException { - return false; - } - - public boolean supportsGroupBy() throws SQLException { - return false; - } - - public boolean supportsGroupByUnrelated() throws SQLException { - return false; - } - - public boolean supportsGroupByBeyondSelect() throws SQLException { - return false; - } - - public boolean supportsMultipleResultSets() throws SQLException { - return false; - } - - public boolean supportsANSI92EntryLevelSQL() throws SQLException { - return false; - } - - public boolean supportsANSI92IntermediateSQL() throws SQLException { - return false; - } - - public boolean supportsANSI92FullSQL() throws SQLException { - return false; - } - - public boolean supportsIntegrityEnhancementFacility() throws SQLException { - return false; - } - - public boolean supportsSchemasInDataManipulation() throws SQLException { - return false; - } - - public boolean supportsSchemasInProcedureCalls() throws SQLException { - return false; - } - - public boolean supportsSchemasInTableDefinitions() throws SQLException { - return false; - } - - public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInDataManipulation() throws SQLException { - return false; - } - - public boolean supportsCatalogsInProcedureCalls() throws SQLException { - return false; - } - - public boolean supportsCatalogsInTableDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { - return false; - } - - public boolean supportsPositionedDelete() throws SQLException { - return false; - } - - public boolean supportsPositionedUpdate() throws SQLException { - return false; - } + public int getMaxCursorNameLength() throws SQLException { + return 0; + } - public boolean supportsSubqueriesInComparisons() throws SQLException { - return false; - } + public int getMaxSchemaNameLength() throws SQLException { + return 32; + } - public int getMaxColumnsInTable() throws SQLException { - return 512; - } + public int getMaxCatalogNameLength() throws SQLException { + return 0; + } - public int getMaxCursorNameLength() throws SQLException { - return 0; - } + public int getMaxRowSize() throws SQLException { + return 0; + } - public int getMaxSchemaNameLength() throws SQLException { - return 32; - } + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } - public int getMaxCatalogNameLength() throws SQLException { - return 0; - } + public int getMaxStatementLength() throws SQLException { + return 0; + } - public int getMaxRowSize() throws SQLException { - return 0; - } + public int getDefaultTransactionIsolation() throws SQLException { + return this.connection.TRANSACTION_REPEATABLE_READ; + } - public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { - return false; - } + public boolean supportsTransactions() throws SQLException { + return true; + } - public int getMaxStatementLength() throws SQLException { - return 0; - } - - public int getDefaultTransactionIsolation() throws SQLException { - return this.connection.TRANSACTION_REPEATABLE_READ; - } - - public boolean supportsTransactions() throws SQLException { + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + switch (level) { + case Connection.TRANSACTION_READ_UNCOMMITTED: + case Connection.TRANSACTION_READ_COMMITTED: + case Connection.TRANSACTION_REPEATABLE_READ: + case Connection.TRANSACTION_SERIALIZABLE: return true; - } - - public boolean supportsTransactionIsolationLevel(int level) throws SQLException { - switch (level) { - case Connection.TRANSACTION_READ_UNCOMMITTED: - case Connection.TRANSACTION_READ_COMMITTED: - case Connection.TRANSACTION_REPEATABLE_READ: - case Connection.TRANSACTION_SERIALIZABLE: - return true; - default: - return false; - } - } - - public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, - String[] types) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getSchemas() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getCatalogs() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getTableTypes() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getColumnPrivileges(String catalog, String schema, String table, - String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getTablePrivileges(String catalog, String schemaPattern, - String tableNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, - boolean nullable) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getVersionColumns(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getPrimaryKeys(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getImportedKeys(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getExportedKeys(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getCrossReference(String parentCatalog, String parentSchema, - String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getTypeInfo() throws SQLException { - String[] columnNames = - {"TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", "LITERAL_SUFFIX", - "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", "UNSIGNED_ATTRIBUTE", - "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", - "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"}; - Query.Type[] columnTypes = - {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.VARCHAR, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, Query.Type.BIT, - Query.Type.INT16, Query.Type.BIT, Query.Type.BIT, Query.Type.BIT, - Query.Type.VARCHAR, Query.Type.INT16, Query.Type.INT16, Query.Type.INT32, - Query.Type.INT32, Query.Type.INT32}; - - String[][] data = - {{"BIT", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BIT", "0", "0", "0", "0", - "10"}, - {"BOOL", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BOOL", "0", "0", "0", - "0", "10"}, - {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "TINYINT", "0", "0", "0", "0", "10"}, - {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", - "3", "1", "0", "1", "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "BIGINT", "0", "0", "0", "0", "10"}, - {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", - "LONG VARBINARY", "0", "0", "0", "0", "10"}, - {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", - "MEDIUMBLOB", "0", "0", "0", "0", "10"}, - {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "1", "3", "0", "0", "0", - "LONGBLOB", "0", "0", "0", "0", "10"}, - {"BLOB", "-4", "65535", "'", "'", "", "1", "1", "3", "0", "0", "0", "BLOB", "0", - "0", "0", "0", "10"}, - {"TINYBLOB", "-4", "255", "'", "'", "", "1", "1", "3", "0", "0", "0", "TINYBLOB", - "0", "0", "0", "0", "10"}, - {"VARBINARY", "-3", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", - "VARBINARY", "0", "0", "0", "0", "10"}, - {"BINARY", "-2", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "BINARY", - "0", "0", "0", "0", "10"}, - {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", - "LONG VARCHAR", "0", "0", "0", "0", "10"}, - {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", - "MEDIUMTEXT", "0", "0", "0", "0", "10"}, - {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "0", "3", "0", "0", "0", - "LONGTEXT", "0", "0", "0", "0", "10"}, - {"TEXT", "-1", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "TEXT", "0", - "0", "0", "0", "10"}, - {"TINYTEXT", "-1", "255", "'", "'", "", "1", "0", "3", "0", "0", "0", "TINYTEXT", - "0", "0", "0", "0", "10"}, - {"CHAR", "1", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "CHAR", "0", - "0", "0", "0", "10"}, - {"NUMERIC", "2", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "NUMERIC", "-308", "308", "0", "0", "10"}, - {"DECIMAL", "3", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "DECIMAL", "-308", "308", "0", "0", "10"}, - {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "INTEGER", "0", "0", "0", "0", "10"}, - {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, - {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "INT", "0", "0", "0", "0", "10"}, - {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "INT UNSIGNED", "0", "0", "0", "0", "10"}, - {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "MEDIUMINT", "0", "0", "0", "0", "10"}, - {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", - "0", "1", "SMALLINT", "0", "0", "0", "0", "10"}, - {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", - "1", "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"FLOAT", "7", "10", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "FLOAT", "-38", "38", "0", "0", "10"}, - {"DOUBLE", "8", "17", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "DOUBLE", "-308", "308", "0", "0", "10"}, - {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", - "0", "1", "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, - {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", - "REAL", "-308", "308", "0", "0", "10"}, - {"VARCHAR", "12", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "VARCHAR", - "0", "0", "0", "0", "10"}, - {"ENUM", "12", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "ENUM", "0", - "0", "0", "0", "10"}, - {"SET", "12", "64", "'", "'", "", "1", "0", "3", "0", "0", "0", "SET", "0", "0", - "0", "0", "10"}, - {"DATE", "91", "10", "'", "'", "", "1", "0", "3", "0", "0", "0", "DATE", "0", "0", - "0", "0", "10"}, - {"TIME", "92", "18", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIME", "0", - "0", "0", "0", "10"}, - {"DATETIME", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", - "DATETIME", "0", "0", "0", "0", "10"}, - {"TIMESTAMP", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", - "TIMESTAMP", "0", "0", "0", "0", "10"}}; - - return new VitessResultSet(columnNames, columnTypes, data, this.connection); - } - - public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, - boolean approximate) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean ownUpdatesAreVisible(int type) throws SQLException { - return false; - } - - public boolean ownDeletesAreVisible(int type) throws SQLException { - return false; - } - - public boolean ownInsertsAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersUpdatesAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersDeletesAreVisible(int type) throws SQLException { - return false; - } - - public boolean othersInsertsAreVisible(int type) throws SQLException { - return false; - } - - public boolean updatesAreDetected(int type) throws SQLException { - return false; - } - - public boolean deletesAreDetected(int type) throws SQLException { - return false; - } - - public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, - int[] types) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public VitessConnection getConnection() throws SQLException { - return connection; - } - - public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, - String attributeNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getSQLStateType() throws SQLException { - return DatabaseMetaData.sqlStateSQL; - } - - public boolean locatorsUpdateCopy() throws SQLException { - return false; - } - - public RowIdLifetime getRowIdLifetime() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean autoCommitFailureClosesAllResultSets() throws SQLException { - return false; - } - - public ResultSet getClientInfoProperties() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getFunctionColumns(String catalog, String schemaPattern, - String functionNamePattern, String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) throws SQLException { - return connection.createStatement().executeQuery("SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM," - + "' ' TABLE_NAME, ' ' COLUMN_NAME, 0 DATA_TYPE, 0 COLUMN_SIZE, 0 DECIMAL_DIGITS," - + "10 NUM_PREC_RADIX, ' ' COLUMN_USAGE, ' ' REMARKS, 0 CHAR_OCTET_LENGTH, 'YES' IS_NULLABLE FROM DUAL " - + "WHERE 1=0"); - } - - public T unwrap(Class iface) throws SQLException { - return null; - } - - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } + default: + return false; + } + } + + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, + String[] types) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getSchemas() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getCatalogs() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getTableTypes() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getColumnPrivileges(String catalog, String schema, String table, + String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, + boolean nullable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getVersionColumns(String catalog, String schema, String table) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getImportedKeys(String catalog, String schema, String table) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getExportedKeys(String catalog, String schema, String table) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, + String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getTypeInfo() throws SQLException { + String[] columnNames = {"TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", + "LITERAL_SUFFIX", "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", + "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", + "MINIMUM_SCALE", "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"}; + Query.Type[] columnTypes = {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, + Query.Type.BIT, Query.Type.INT16, Query.Type.BIT, Query.Type.BIT, Query.Type.BIT, + Query.Type.VARCHAR, Query.Type.INT16, Query.Type.INT16, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32}; + + String[][] data = { + {"BIT", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BIT", "0", "0", "0", "0", + "10"}, + {"BOOL", "-7", "1", "", "", "", "1", "1", "3", "0", "0", "0", "BOOL", "0", "0", "0", "0", + "10"}, + {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "TINYINT", "0", "0", "0", "0", "10"}, + {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", + "0", "1", "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "BIGINT", "0", "0", "0", "0", "10"}, + {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", + "LONG VARBINARY", "0", "0", "0", "0", "10"}, + {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "1", "3", "0", "0", "0", "MEDIUMBLOB", + "0", "0", "0", "0", "10"}, + {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "1", "3", "0", "0", "0", "LONGBLOB", + "0", "0", "0", "0", "10"}, + {"BLOB", "-4", "65535", "'", "'", "", "1", "1", "3", "0", "0", "0", "BLOB", "0", "0", "0", + "0", "10"}, + {"TINYBLOB", "-4", "255", "'", "'", "", "1", "1", "3", "0", "0", "0", "TINYBLOB", "0", "0", + "0", "0", "10"}, + {"VARBINARY", "-3", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "VARBINARY", "0", + "0", "0", "0", "10"}, + {"BINARY", "-2", "255", "'", "'", "(M)", "1", "1", "3", "0", "0", "0", "BINARY", "0", "0", + "0", "0", "10"}, + {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", + "LONG VARCHAR", "0", "0", "0", "0", "10"}, + {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "0", "3", "0", "0", "0", "MEDIUMTEXT", + "0", "0", "0", "0", "10"}, + {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "0", "3", "0", "0", "0", "LONGTEXT", + "0", "0", "0", "0", "10"}, + {"TEXT", "-1", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "TEXT", "0", "0", "0", + "0", "10"}, + {"TINYTEXT", "-1", "255", "'", "'", "", "1", "0", "3", "0", "0", "0", "TINYTEXT", "0", "0", + "0", "0", "10"}, + {"CHAR", "1", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "CHAR", "0", "0", "0", + "0", "10"}, + {"NUMERIC", "2", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", + "NUMERIC", "-308", "308", "0", "0", "10"}, + {"DECIMAL", "3", "65", "", "", "[(M,D])] [ZEROFILL]", "1", "0", "3", "0", "0", "1", + "DECIMAL", "-308", "308", "0", "0", "10"}, + {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "INTEGER", "0", "0", "0", "0", "10"}, + {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, + {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "INT", "0", "0", "0", "0", "10"}, + {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "INT UNSIGNED", "0", "0", "0", "0", "10"}, + {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "MEDIUMINT", "0", "0", "0", "0", "10"}, + {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "SMALLINT", "0", "0", "0", "0", "10"}, + {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "0", "3", "1", "0", "1", + "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"FLOAT", "7", "10", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "FLOAT", + "-38", "38", "0", "0", "10"}, + {"DOUBLE", "8", "17", "", "", "[(M|D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "DOUBLE", + "-308", "308", "0", "0", "10"}, + {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", + "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, + {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "0", "3", "0", "0", "1", "REAL", + "-308", "308", "0", "0", "10"}, + {"VARCHAR", "12", "255", "'", "'", "(M)", "1", "0", "3", "0", "0", "0", "VARCHAR", "0", "0", + "0", "0", "10"}, + {"ENUM", "12", "65535", "'", "'", "", "1", "0", "3", "0", "0", "0", "ENUM", "0", "0", "0", + "0", "10"}, + {"SET", "12", "64", "'", "'", "", "1", "0", "3", "0", "0", "0", "SET", "0", "0", "0", "0", + "10"}, + {"DATE", "91", "10", "'", "'", "", "1", "0", "3", "0", "0", "0", "DATE", "0", "0", "0", "0", + "10"}, + {"TIME", "92", "18", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIME", "0", "0", "0", + "0", "10"}, + {"DATETIME", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "DATETIME", "0", + "0", "0", "0", "10"}, + {"TIMESTAMP", "93", "27", "'", "'", "[(M)]", "1", "0", "3", "0", "0", "0", "TIMESTAMP", "0", + "0", "0", "0", "10"}}; + + return new VitessResultSet(columnNames, columnTypes, data, this.connection); + } + + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, + boolean approximate) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, + int[] types) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public VitessConnection getConnection() throws SQLException { + return connection; + } + + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, + String attributeNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getSQLStateType() throws SQLException { + return DatabaseMetaData.sqlStateSQL; + } + + public boolean locatorsUpdateCopy() throws SQLException { + return false; + } + + public RowIdLifetime getRowIdLifetime() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean autoCommitFailureClosesAllResultSets() throws SQLException { + return false; + } + + public ResultSet getClientInfoProperties() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getFunctionColumns(String catalog, String schemaPattern, + String functionNamePattern, String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { + return connection.createStatement().executeQuery("SELECT ' ' TABLE_CAT, ' ' TABLE_SCHEM," + + "' ' TABLE_NAME, ' ' COLUMN_NAME, 0 DATA_TYPE, 0 COLUMN_SIZE, 0 DECIMAL_DIGITS," + + "10 NUM_PREC_RADIX, ' ' COLUMN_USAGE, ' ' REMARKS, 0 CHAR_OCTET_LENGTH, 'YES' " + + "IS_NULLABLE FROM DUAL " + + "WHERE 1=0"); + } + + public T unwrap(Class iface) throws SQLException { + return null; + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java index e94541dacde..0c87ff34d0e 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,12 +17,13 @@ package io.vitess.jdbc; import com.google.common.annotations.VisibleForTesting; -import org.apache.commons.lang.StringUtils; import io.vitess.proto.Query; import io.vitess.util.Constants; import io.vitess.util.MysqlDefs; +import org.apache.commons.lang.StringUtils; + import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; @@ -45,1774 +46,1738 @@ /** * Created by ashudeep.sharma on 15/02/16. */ -public class VitessMySQLDatabaseMetadata extends VitessDatabaseMetaData - implements DatabaseMetaData { - - private static final String DRIVER_NAME = "Vitess MySQL JDBC Driver"; - private static Logger logger = Logger.getLogger(VitessMySQLDatabaseMetadata.class.getName()); - private static String mysqlKeywordsThatArentSQL92; - - static { - - String[] allMySQLKeywords = - new String[] {"ACCESSIBLE", "ADD", "ALL", "ALTER", "ANALYZE", "AND", "AS", "ASC", - "ASENSITIVE", "BEFORE", "BETWEEN", "BIGINT", "BINARY", "BLOB", "BOTH", "BY", "CALL", - "CASCADE", "CASE", "CHANGE", "CHAR", "CHARACTER", "CHECK", "COLLATE", "COLUMN", - "CONDITION", "CONNECTION", "CONSTRAINT", "CONTINUE", "CONVERT", "CREATE", "CROSS", - "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", - "DATABASE", "DATABASES", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", - "DEC", "DECIMAL", "DECLARE", "DEFAULT", "DELAYED", "DELETE", "DESC", "DESCRIBE", - "DETERMINISTIC", "DISTINCT", "DISTINCTROW", "DIV", "DOUBLE", "DROP", "DUAL", "EACH", - "ELSE", "ELSEIF", "ENCLOSED", "ESCAPED", "EXISTS", "EXIT", "EXPLAIN", "FALSE", - "FETCH", "FLOAT", "FLOAT4", "FLOAT8", "FOR", "FORCE", "FOREIGN", "FROM", "FULLTEXT", - "GRANT", "GROUP", "HAVING", "HIGH_PRIORITY", "HOUR_MICROSECOND", "HOUR_MINUTE", - "HOUR_SECOND", "IF", "IGNORE", "IN", "INDEX", "INFILE", "INNER", "INOUT", - "INSENSITIVE", "INSERT", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", "INTEGER", - "INTERVAL", "INTO", "IS", "ITERATE", "JOIN", "KEY", "KEYS", "KILL", "LEADING", - "LEAVE", "LEFT", "LIKE", "LIMIT", "LINEAR", "LINES", "LOAD", "LOCALTIME", - "LOCALTIMESTAMP", "LOCK", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", - "MATCH", "MEDIUMBLOB", "MEDIUMINT", "MEDIUMTEXT", "MIDDLEINT", "MINUTE_MICROSECOND", - "MINUTE_SECOND", "MOD", "MODIFIES", "NATURAL", "NOT", "NO_WRITE_TO_BINLOG", "NULL", - "NUMERIC", "ON", "OPTIMIZE", "OPTION", "OPTIONALLY", "OR", "ORDER", "OUT", "OUTER", - "OUTFILE", "PRECISION", "PRIMARY", "PROCEDURE", "PURGE", "RANGE", "READ", "READS", - "READ_ONLY", "READ_WRITE", "REAL", "REFERENCES", "REGEXP", "RELEASE", "RENAME", - "REPEAT", "REPLACE", "REQUIRE", "RESTRICT", "RETURN", "REVOKE", "RIGHT", "RLIKE", - "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND", "SELECT", "SENSITIVE", "SEPARATOR", - "SET", "SHOW", "SMALLINT", "SPATIAL", "SPECIFIC", "SQL", "SQLEXCEPTION", "SQLSTATE", - "SQLWARNING", "SQL_BIG_RESULT", "SQL_CALC_FOUND_ROWS", "SQL_SMALL_RESULT", "SSL", - "STARTING", "STRAIGHT_JOIN", "TABLE", "TERMINATED", "THEN", "TINYBLOB", "TINYINT", - "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE", "UNDO", "UNION", "UNIQUE", - "UNLOCK", "UNSIGNED", "UPDATE", "USAGE", "USE", "USING", "UTC_DATE", "UTC_TIME", - "UTC_TIMESTAMP", "VALUES", "VARBINARY", "VARCHAR", "VARCHARACTER", "VARYING", - "WHEN", "WHERE", "WHILE", "WITH", "WRITE", "X509", "XOR", "YEAR_MONTH", "ZEROFILL"}; - String[] sql92Keywords = - new String[] {"ABSOLUTE", "EXEC", "OVERLAPS", "ACTION", "EXECUTE", "PAD", "ADA", - "EXISTS", "PARTIAL", "ADD", "EXTERNAL", "PASCAL", "ALL", "EXTRACT", "POSITION", - "ALLOCATE", "FALSE", "PRECISION", "ALTER", "FETCH", "PREPARE", "AND", "FIRST", - "PRESERVE", "ANY", "FLOAT", "PRIMARY", "ARE", "FOR", "PRIOR", "AS", "FOREIGN", - "PRIVILEGES", "ASC", "FORTRAN", "PROCEDURE", "ASSERTION", "FOUND", "PUBLIC", "AT", - "FROM", "READ", "AUTHORIZATION", "FULL", "REAL", "AVG", "GET", "REFERENCES", - "BEGIN", "GLOBAL", "RELATIVE", "BETWEEN", "GO", "RESTRICT", "BIT", "GOTO", "REVOKE", - "BIT_LENGTH", "GRANT", "RIGHT", "BOTH", "GROUP", "ROLLBACK", "BY", "HAVING", "ROWS", - "CASCADE", "HOUR", "SCHEMA", "CASCADED", "IDENTITY", "SCROLL", "CASE", "IMMEDIATE", - "SECOND", "CAST", "IN", "SECTION", "CATALOG", "INCLUDE", "SELECT", "CHAR", "INDEX", - "SESSION", "CHAR_LENGTH", "INDICATOR", "SESSION_USER", "CHARACTER", "INITIALLY", - "SET", "CHARACTER_LENGTH", "INNER", "SIZE", "CHECK", "INPUT", "SMALLINT", "CLOSE", - "INSENSITIVE", "SOME", "COALESCE", "INSERT", "SPACE", "COLLATE", "INT", "SQL", - "COLLATION", "INTEGER", "SQLCA", "COLUMN", "INTERSECT", "SQLCODE", "COMMIT", - "INTERVAL", "SQLERROR", "CONNECT", "INTO", "SQLSTATE", "CONNECTION", "IS", - "SQLWARNING", "CONSTRAINT", "ISOLATION", "SUBSTRING", "CONSTRAINTS", "JOIN", "SUM", - "CONTINUE", "KEY", "SYSTEM_USER", "CONVERT", "LANGUAGE", "TABLE", "CORRESPONDING", - "LAST", "TEMPORARY", "COUNT", "LEADING", "THEN", "CREATE", "LEFT", "TIME", "CROSS", - "LEVEL", "TIMESTAMP", "CURRENT", "LIKE", "TIMEZONE_HOUR", "CURRENT_DATE", "LOCAL", - "TIMEZONE_MINUTE", "CURRENT_TIME", "LOWER", "TO", "CURRENT_TIMESTAMP", "MATCH", - "TRAILING", "CURRENT_USER", "MAX", "TRANSACTION", "CURSOR", "MIN", "TRANSLATE", - "DATE", "MINUTE", "TRANSLATION", "DAY", "MODULE", "TRIM", "DEALLOCATE", "MONTH", - "TRUE", "DEC", "NAMES", "UNION", "DECIMAL", "NATIONAL", "UNIQUE", "DECLARE", - "NATURAL", "UNKNOWN", "DEFAULT", "NCHAR", "UPDATE", "DEFERRABLE", "NEXT", "UPPER", - "DEFERRED", "NO", "USAGE", "DELETE", "NONE", "USER", "DESC", "NOT", "USING", - "DESCRIBE", "NULL", "VALUE", "DESCRIPTOR", "NULLIF", "VALUES", "DIAGNOSTICS", - "NUMERIC", "VARCHAR", "DISCONNECT", "OCTET_LENGTH", "VARYING", "DISTINCT", "OF", - "VIEW", "DOMAIN", "ON", "WHEN", "DOUBLE", "ONLY", "WHENEVER", "DROP", "OPEN", - "WHERE", "ELSE", "OPTION", "WITH", "END", "OR", "WORK", "END-EXEC", "ORDER", - "WRITE", "ESCAPE", "OUTER", "YEAR", "EXCEPT", "OUTPUT", "ZONE", "EXCEPTION"}; - TreeMap mySQLKeywordMap = new TreeMap(); - - for (String allMySQLKeyword : allMySQLKeywords) { - mySQLKeywordMap.put(allMySQLKeyword, null); - } - - HashMap sql92KeywordMap = new HashMap(sql92Keywords.length); +public class VitessMySQLDatabaseMetadata extends VitessDatabaseMetaData implements + DatabaseMetaData { + + private static final String DRIVER_NAME = "Vitess MySQL JDBC Driver"; + private static Logger logger = Logger.getLogger(VitessMySQLDatabaseMetadata.class.getName()); + private static String mysqlKeywordsThatArentSQL92; + + static { + + String[] allMySQLKeywords = new String[]{"ACCESSIBLE", "ADD", "ALL", "ALTER", "ANALYZE", "AND", + "AS", "ASC", "ASENSITIVE", "BEFORE", "BETWEEN", "BIGINT", "BINARY", "BLOB", "BOTH", "BY", + "CALL", "CASCADE", "CASE", "CHANGE", "CHAR", "CHARACTER", "CHECK", "COLLATE", "COLUMN", + "CONDITION", "CONNECTION", "CONSTRAINT", "CONTINUE", "CONVERT", "CREATE", "CROSS", + "CURRENT_DATE", "CURRENT_TIME", "CURRENT_TIMESTAMP", "CURRENT_USER", "CURSOR", "DATABASE", + "DATABASES", "DAY_HOUR", "DAY_MICROSECOND", "DAY_MINUTE", "DAY_SECOND", "DEC", "DECIMAL", + "DECLARE", "DEFAULT", "DELAYED", "DELETE", "DESC", "DESCRIBE", "DETERMINISTIC", "DISTINCT", + "DISTINCTROW", "DIV", "DOUBLE", "DROP", "DUAL", "EACH", "ELSE", "ELSEIF", "ENCLOSED", + "ESCAPED", "EXISTS", "EXIT", "EXPLAIN", "FALSE", "FETCH", "FLOAT", "FLOAT4", "FLOAT8", + "FOR", "FORCE", "FOREIGN", "FROM", "FULLTEXT", "GRANT", "GROUP", "HAVING", "HIGH_PRIORITY", + "HOUR_MICROSECOND", "HOUR_MINUTE", "HOUR_SECOND", "IF", "IGNORE", "IN", "INDEX", "INFILE", + "INNER", "INOUT", "INSENSITIVE", "INSERT", "INT", "INT1", "INT2", "INT3", "INT4", "INT8", + "INTEGER", "INTERVAL", "INTO", "IS", "ITERATE", "JOIN", "KEY", "KEYS", "KILL", "LEADING", + "LEAVE", "LEFT", "LIKE", "LIMIT", "LINEAR", "LINES", "LOAD", "LOCALTIME", "LOCALTIMESTAMP", + "LOCK", "LONG", "LONGBLOB", "LONGTEXT", "LOOP", "LOW_PRIORITY", "MATCH", "MEDIUMBLOB", + "MEDIUMINT", "MEDIUMTEXT", "MIDDLEINT", "MINUTE_MICROSECOND", "MINUTE_SECOND", "MOD", + "MODIFIES", "NATURAL", "NOT", "NO_WRITE_TO_BINLOG", "NULL", "NUMERIC", "ON", "OPTIMIZE", + "OPTION", "OPTIONALLY", "OR", "ORDER", "OUT", "OUTER", "OUTFILE", "PRECISION", "PRIMARY", + "PROCEDURE", "PURGE", "RANGE", "READ", "READS", "READ_ONLY", "READ_WRITE", "REAL", + "REFERENCES", "REGEXP", "RELEASE", "RENAME", "REPEAT", "REPLACE", "REQUIRE", "RESTRICT", + "RETURN", "REVOKE", "RIGHT", "RLIKE", "SCHEMA", "SCHEMAS", "SECOND_MICROSECOND", "SELECT", + "SENSITIVE", "SEPARATOR", "SET", "SHOW", "SMALLINT", "SPATIAL", "SPECIFIC", "SQL", + "SQLEXCEPTION", "SQLSTATE", "SQLWARNING", "SQL_BIG_RESULT", "SQL_CALC_FOUND_ROWS", + "SQL_SMALL_RESULT", "SSL", "STARTING", "STRAIGHT_JOIN", "TABLE", "TERMINATED", "THEN", + "TINYBLOB", "TINYINT", "TINYTEXT", "TO", "TRAILING", "TRIGGER", "TRUE", "UNDO", "UNION", + "UNIQUE", "UNLOCK", "UNSIGNED", "UPDATE", "USAGE", "USE", "USING", "UTC_DATE", "UTC_TIME", + "UTC_TIMESTAMP", "VALUES", "VARBINARY", "VARCHAR", "VARCHARACTER", "VARYING", "WHEN", + "WHERE", "WHILE", "WITH", "WRITE", "X509", "XOR", "YEAR_MONTH", "ZEROFILL"}; + String[] sql92Keywords = new String[]{"ABSOLUTE", "EXEC", "OVERLAPS", "ACTION", "EXECUTE", + "PAD", "ADA", "EXISTS", "PARTIAL", "ADD", "EXTERNAL", "PASCAL", "ALL", "EXTRACT", + "POSITION", "ALLOCATE", "FALSE", "PRECISION", "ALTER", "FETCH", "PREPARE", "AND", "FIRST", + "PRESERVE", "ANY", "FLOAT", "PRIMARY", "ARE", "FOR", "PRIOR", "AS", "FOREIGN", "PRIVILEGES", + "ASC", "FORTRAN", "PROCEDURE", "ASSERTION", "FOUND", "PUBLIC", "AT", "FROM", "READ", + "AUTHORIZATION", "FULL", "REAL", "AVG", "GET", "REFERENCES", "BEGIN", "GLOBAL", "RELATIVE", + "BETWEEN", "GO", "RESTRICT", "BIT", "GOTO", "REVOKE", "BIT_LENGTH", "GRANT", "RIGHT", + "BOTH", "GROUP", "ROLLBACK", "BY", "HAVING", "ROWS", "CASCADE", "HOUR", "SCHEMA", + "CASCADED", "IDENTITY", "SCROLL", "CASE", "IMMEDIATE", "SECOND", "CAST", "IN", "SECTION", + "CATALOG", "INCLUDE", "SELECT", "CHAR", "INDEX", "SESSION", "CHAR_LENGTH", "INDICATOR", + "SESSION_USER", "CHARACTER", "INITIALLY", "SET", "CHARACTER_LENGTH", "INNER", "SIZE", + "CHECK", "INPUT", "SMALLINT", "CLOSE", "INSENSITIVE", "SOME", "COALESCE", "INSERT", "SPACE", + "COLLATE", "INT", "SQL", "COLLATION", "INTEGER", "SQLCA", "COLUMN", "INTERSECT", "SQLCODE", + "COMMIT", "INTERVAL", "SQLERROR", "CONNECT", "INTO", "SQLSTATE", "CONNECTION", "IS", + "SQLWARNING", "CONSTRAINT", "ISOLATION", "SUBSTRING", "CONSTRAINTS", "JOIN", "SUM", + "CONTINUE", "KEY", "SYSTEM_USER", "CONVERT", "LANGUAGE", "TABLE", "CORRESPONDING", "LAST", + "TEMPORARY", "COUNT", "LEADING", "THEN", "CREATE", "LEFT", "TIME", "CROSS", "LEVEL", + "TIMESTAMP", "CURRENT", "LIKE", "TIMEZONE_HOUR", "CURRENT_DATE", "LOCAL", "TIMEZONE_MINUTE", + "CURRENT_TIME", "LOWER", "TO", "CURRENT_TIMESTAMP", "MATCH", "TRAILING", "CURRENT_USER", + "MAX", "TRANSACTION", "CURSOR", "MIN", "TRANSLATE", "DATE", "MINUTE", "TRANSLATION", "DAY", + "MODULE", "TRIM", "DEALLOCATE", "MONTH", "TRUE", "DEC", "NAMES", "UNION", "DECIMAL", + "NATIONAL", "UNIQUE", "DECLARE", "NATURAL", "UNKNOWN", "DEFAULT", "NCHAR", "UPDATE", + "DEFERRABLE", "NEXT", "UPPER", "DEFERRED", "NO", "USAGE", "DELETE", "NONE", "USER", "DESC", + "NOT", "USING", "DESCRIBE", "NULL", "VALUE", "DESCRIPTOR", "NULLIF", "VALUES", + "DIAGNOSTICS", "NUMERIC", "VARCHAR", "DISCONNECT", "OCTET_LENGTH", "VARYING", "DISTINCT", + "OF", "VIEW", "DOMAIN", "ON", "WHEN", "DOUBLE", "ONLY", "WHENEVER", "DROP", "OPEN", "WHERE", + "ELSE", "OPTION", "WITH", "END", "OR", "WORK", "END-EXEC", "ORDER", "WRITE", "ESCAPE", + "OUTER", "YEAR", "EXCEPT", "OUTPUT", "ZONE", "EXCEPTION"}; + TreeMap mySQLKeywordMap = new TreeMap(); + + for (String allMySQLKeyword : allMySQLKeywords) { + mySQLKeywordMap.put(allMySQLKeyword, null); + } + + HashMap sql92KeywordMap = new HashMap(sql92Keywords.length); + + for (String sql92Keyword : sql92Keywords) { + sql92KeywordMap.put(sql92Keyword, null); + } + + Iterator sql92KeywordIterator = sql92KeywordMap.keySet().iterator(); + + while (sql92KeywordIterator.hasNext()) { + mySQLKeywordMap.remove(sql92KeywordIterator.next()); + } + + StringBuffer keywordBuf = new StringBuffer(); + sql92KeywordIterator = mySQLKeywordMap.keySet().iterator(); + if (sql92KeywordIterator.hasNext()) { + keywordBuf.append(sql92KeywordIterator.next().toString()); + } + + while (sql92KeywordIterator.hasNext()) { + keywordBuf.append(","); + keywordBuf.append(sql92KeywordIterator.next().toString()); + } + + mysqlKeywordsThatArentSQL92 = keywordBuf.toString(); + } + + private int maxBufferSize = '\uffff'; + + public VitessMySQLDatabaseMetadata(VitessConnection connection) throws SQLException { + this.setConnection(connection); + } + + public boolean nullsAreSortedAtStart() throws SQLException { + return false; + } + + public boolean nullsAreSortedAtEnd() throws SQLException { + return false; + } + + public String getDriverName() throws SQLException { + return DRIVER_NAME; + } + + public String getSQLKeywords() throws SQLException { + return mysqlKeywordsThatArentSQL92; + } + + public String getSystemFunctions() throws SQLException { + return super.getSystemFunctions() + ",PASSWORD,ENCRYPT"; + } + + public boolean supportsConvert() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean supportsConvert(int fromType, int toType) throws SQLException { + return false; + } + + public boolean supportsTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsDifferentTableCorrelationNames() throws SQLException { + return false; + } + + public boolean supportsANSI92EntryLevelSQL() throws SQLException { + return false; + } - for (String sql92Keyword : sql92Keywords) { - sql92KeywordMap.put(sql92Keyword, null); - } + public boolean supportsANSI92IntermediateSQL() throws SQLException { + return false; + } - Iterator sql92KeywordIterator = sql92KeywordMap.keySet().iterator(); + public boolean supportsANSI92FullSQL() throws SQLException { + return false; + } - while (sql92KeywordIterator.hasNext()) { - mySQLKeywordMap.remove(sql92KeywordIterator.next()); - } - - StringBuffer keywordBuf = new StringBuffer(); - sql92KeywordIterator = mySQLKeywordMap.keySet().iterator(); - if (sql92KeywordIterator.hasNext()) { - keywordBuf.append(sql92KeywordIterator.next().toString()); - } - - while (sql92KeywordIterator.hasNext()) { - keywordBuf.append(","); - keywordBuf.append(sql92KeywordIterator.next().toString()); - } + public boolean supportsIntegrityEnhancementFacility() throws SQLException { + return false; + } - mysqlKeywordsThatArentSQL92 = keywordBuf.toString(); - } - - private int maxBufferSize = '\uffff'; - - public VitessMySQLDatabaseMetadata(VitessConnection connection) throws SQLException { - this.setConnection(connection); - } - - public boolean nullsAreSortedAtStart() throws SQLException { - return false; - } - - public boolean nullsAreSortedAtEnd() throws SQLException { - return false; - } + public boolean supportsSchemasInDataManipulation() throws SQLException { + return false; + } - public String getDriverName() throws SQLException { - return DRIVER_NAME; - } + public boolean supportsSchemasInProcedureCalls() throws SQLException { + return false; + } - public String getSQLKeywords() throws SQLException { - return mysqlKeywordsThatArentSQL92; - } + public boolean supportsSchemasInTableDefinitions() throws SQLException { + return false; + } - public String getSystemFunctions() throws SQLException { - return super.getSystemFunctions() + ",PASSWORD,ENCRYPT"; - } + public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { + return false; + } - public boolean supportsConvert() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean supportsCatalogsInDataManipulation() throws SQLException { + return false; + } - public boolean supportsConvert(int fromType, int toType) throws SQLException { - return false; - } + public boolean supportsCatalogsInProcedureCalls() throws SQLException { + return false; + } - public boolean supportsTableCorrelationNames() throws SQLException { - return false; - } + public boolean supportsCatalogsInTableDefinitions() throws SQLException { + return false; + } - public boolean supportsDifferentTableCorrelationNames() throws SQLException { - return false; - } + public boolean supportsCatalogsInIndexDefinitions() throws SQLException { + return false; + } - public boolean supportsANSI92EntryLevelSQL() throws SQLException { - return false; - } + public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { + return false; + } - public boolean supportsANSI92IntermediateSQL() throws SQLException { - return false; - } + public boolean supportsPositionedDelete() throws SQLException { + return false; + } - public boolean supportsANSI92FullSQL() throws SQLException { - return false; - } + public boolean supportsPositionedUpdate() throws SQLException { + return false; + } + + public int getMaxColumnsInTable() throws SQLException { + return 0; + } + + public int getMaxCursorNameLength() throws SQLException { + return 64; + } + + public int getMaxSchemaNameLength() throws SQLException { + return 0; + } + + public int getMaxCatalogNameLength() throws SQLException { + return 32; + } + + public int getMaxRowSize() throws SQLException { + return 2147483639; + } + + public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + return false; + } + + public int getMaxStatementLength() throws SQLException { + return 65531; + } - public boolean supportsIntegrityEnhancementFacility() throws SQLException { - return false; - } + public int getDefaultTransactionIsolation() throws SQLException { + return this.connection.getDbProperties().getIsolationLevel(); + } - public boolean supportsSchemasInDataManipulation() throws SQLException { - return false; - } + public boolean supportsTransactions() throws SQLException { + return true; + } - public boolean supportsSchemasInProcedureCalls() throws SQLException { - return false; - } - - public boolean supportsSchemasInTableDefinitions() throws SQLException { - return false; - } - - public boolean supportsSchemasInPrivilegeDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInDataManipulation() throws SQLException { - return false; - } - - public boolean supportsCatalogsInProcedureCalls() throws SQLException { - return false; - } - - public boolean supportsCatalogsInTableDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInIndexDefinitions() throws SQLException { - return false; - } - - public boolean supportsCatalogsInPrivilegeDefinitions() throws SQLException { - return false; - } - - public boolean supportsPositionedDelete() throws SQLException { - return false; - } - - public boolean supportsPositionedUpdate() throws SQLException { - return false; - } - - public int getMaxColumnsInTable() throws SQLException { - return 0; - } - - public int getMaxCursorNameLength() throws SQLException { - return 64; - } - - public int getMaxSchemaNameLength() throws SQLException { - return 0; - } - - public int getMaxCatalogNameLength() throws SQLException { - return 32; - } - - public int getMaxRowSize() throws SQLException { - return 2147483639; - } + public boolean supportsTransactionIsolationLevel(int level) throws SQLException { + switch (level) { + case Connection.TRANSACTION_READ_COMMITTED: + case Connection.TRANSACTION_READ_UNCOMMITTED: + case Connection.TRANSACTION_REPEATABLE_READ: + case Connection.TRANSACTION_SERIALIZABLE: + return true; - public boolean doesMaxRowSizeIncludeBlobs() throws SQLException { + default: return false; } + } + + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, + String[] types) throws SQLException { + ResultSet resultSet = null; + VitessStatement vitessStatement = null; + boolean reportTables = false; + boolean reportViews = false; + boolean reportSystemTables = false; + boolean reportSystemViews = false; + boolean reportLocalTemporaries = false; + final SortedMap> sortedRows = new TreeMap<>(); + + if (null == tableNamePattern) { + tableNamePattern = "%"; + } + if (null == catalog || catalog.length() == 0) { + catalog = this.connection.getCatalog(); + } + ArrayList> data = new ArrayList<>(); + try { + vitessStatement = new VitessStatement(this.connection); + resultSet = vitessStatement.executeQuery( + "SHOW FULL TABLES FROM " + this.quotedId + catalog + this.quotedId + " LIKE \'" + + tableNamePattern + "\'"); + + if (null == types || types.length == 0) { + reportTables = reportViews = reportSystemTables = reportSystemViews = + reportLocalTemporaries = true; + } else { + for (String type : types) { + if (TableType.TABLE.equalsTo(type)) { + reportTables = true; + + } else if (TableType.VIEW.equalsTo(type)) { + reportViews = true; + + } else if (TableType.SYSTEM_TABLE.equalsTo(type)) { + reportSystemTables = true; + + } else if (TableType.SYSTEM_VIEW.equalsTo(type)) { + reportSystemViews = true; + + } else if (TableType.LOCAL_TEMPORARY.equalsTo(type)) { + reportLocalTemporaries = true; + } + } + } + + int typeColumnIndex = 0; + boolean hasTableTypes; + try { + typeColumnIndex = resultSet.findColumn("table_type"); + hasTableTypes = true; + } catch (SQLException sqlEx) { + try { + typeColumnIndex = resultSet.findColumn("Type"); + hasTableTypes = true; + } catch (SQLException sqlEx2) { + hasTableTypes = false; + } + } - public int getMaxStatementLength() throws SQLException { - return 65531; - } - - public int getDefaultTransactionIsolation() throws SQLException { - return this.connection.getDbProperties().getIsolationLevel(); - } - - public boolean supportsTransactions() throws SQLException { - return true; - } - - public boolean supportsTransactionIsolationLevel(int level) throws SQLException { - switch (level) { - case Connection.TRANSACTION_READ_COMMITTED: - case Connection.TRANSACTION_READ_UNCOMMITTED: - case Connection.TRANSACTION_REPEATABLE_READ: - case Connection.TRANSACTION_SERIALIZABLE: - return true; + while (resultSet.next()) { + ArrayList row = new ArrayList<>(); + row.add(0, catalog); + row.add(1, null); + row.add(2, resultSet.getString(1)); + row.add(3, ""); + row.add(4, null); + row.add(5, null); + row.add(6, null); + row.add(7, null); + row.add(8, null); + row.add(9, null); + + if (hasTableTypes) { + String tableType = resultSet.getString(typeColumnIndex); + switch (TableType.getTableTypeCompliantWith(tableType)) { + case TABLE: + boolean reportTable = false; + TableMetaDataKey tablesKey = null; + if (reportSystemTables) { + row.add(3, TableType.TABLE.toString()); + tablesKey = new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, + resultSet.getString(1)); + reportTable = true; + } + if (reportTable) { + sortedRows.put(tablesKey, row); + } + break; + + case VIEW: + if (reportViews) { + row.add(3, TableType.VIEW.toString()); + sortedRows.put(new TableMetaDataKey(TableType.VIEW.getName(), catalog, null, + resultSet.getString(1)), row); + } + break; + + case SYSTEM_TABLE: + if (reportSystemTables) { + row.add(3, TableType.SYSTEM_TABLE.toString()); + sortedRows.put(new TableMetaDataKey(TableType.SYSTEM_TABLE.getName(), catalog, null, + resultSet.getString(1)), row); + } + break; + + case SYSTEM_VIEW: + if (reportSystemViews) { + row.add(3, TableType.SYSTEM_VIEW.toString()); + sortedRows.put(new TableMetaDataKey(TableType.SYSTEM_VIEW.getName(), catalog, null, + resultSet.getString(1)), row); + } + break; + + case LOCAL_TEMPORARY: + if (reportLocalTemporaries) { + row.add(3, TableType.LOCAL_TEMPORARY.toString()); + sortedRows.put( + new TableMetaDataKey(TableType.LOCAL_TEMPORARY.getName(), catalog, null, + resultSet.getString(1)), row); + } + break; default: - return false; + row.add(3, TableType.TABLE.toString()); + sortedRows.put(new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, + resultSet.getString(1)), row); + break; + } + } else { + if (reportTables) { + // Pre-MySQL-5.0.1, tables only + row.add(3, TableType.TABLE.toString()); + sortedRows.put(new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, + resultSet.getString(1)), row); + } } - } - - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getTables(String catalog, - String schemaPattern, String tableNamePattern, String[] types) throws SQLException { - ResultSet resultSet = null; - VitessStatement vitessStatement = null; - boolean reportTables = false; - boolean reportViews = false; - boolean reportSystemTables = false; - boolean reportSystemViews = false; - boolean reportLocalTemporaries = false; - final SortedMap> sortedRows = new TreeMap<>(); - - if (null == tableNamePattern) { - tableNamePattern = "%"; + data.add(row); + } + } finally { + if (null != resultSet) { + resultSet.close(); + } + if (null != vitessStatement) { + vitessStatement.close(); + } + } + String[] columnNames = new String[]{"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", + "REMARKS", "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", + "REF_GENERATION"}; + Query.Type[] columnTypes = new Query.Type[]{Query.Type.VARCHAR, Query.Type.VARCHAR, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR}; + + return new VitessResultSet(columnNames, columnTypes, data, this.connection); + } + + public ResultSet getSchemas() throws SQLException { + String[] columnNames = {"TABLE_SCHEM", "TABLE_CATALOG"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getCatalogs() throws SQLException { + ResultSet resultSet; + VitessStatement vitessStatement; + String getCatalogQB = "SHOW DATABASES"; + + vitessStatement = new VitessStatement(this.connection); + resultSet = vitessStatement.executeQuery(getCatalogQB); + + ArrayList row = new ArrayList<>(); + ArrayList> data = new ArrayList<>(); + while (resultSet.next()) { + row.add(resultSet.getString(1)); + } + Collections.sort(row); + + for (String result : row) { + ArrayList resultAsList = new ArrayList<>(); + resultAsList.add(result); + data.add(resultAsList); + } + resultSet.close(); + vitessStatement.close(); + String[] columnName = new String[]{"TABLE_CAT"}; + Query.Type[] columntype = new Query.Type[]{Query.Type.CHAR}; + return new VitessResultSet(columnName, columntype, data, this.connection); + } + + public ResultSet getTableTypes() throws SQLException { + String[] columnNames = {"table_type"}; + Query.Type[] columnType = {Query.Type.VARCHAR}; + String[][] data = new String[][]{{"LOCAL TEMPORARY"}, {"SYSTEM TABLES"}, {"SYSTEM VIEW"}, + {"TABLE"}, {"VIEW"}}; + return new VitessResultSet(columnNames, columnType, data, this.connection); + } + + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { + ResultSet resultSet = null; + VitessStatement vitessStatement = new VitessStatement(this.connection); + ArrayList> data = new ArrayList<>(); + //Null Matches All + if (null == columnNamePattern) { + columnNamePattern = "%"; + } + if (null == catalog || catalog.length() == 0) { + catalog = this.connection.getCatalog(); + } + try { + ArrayList tableList = new ArrayList<>(); + ResultSet tables = null; + if (null == tableNamePattern) { + try { + tables = getTables(catalog, schemaPattern, "%", new String[0]); + while (tables.next()) { + String tableName = tables.getString("TABLE_NAME"); + tableList.add(tableName); + } + } finally { + if (null != tables) { + tables.close(); + } } - if (null == catalog || catalog.length() == 0) { - catalog = this.connection.getCatalog(); + } else { + try { + tables = getTables(catalog, schemaPattern, tableNamePattern, new String[0]); + while (tables.next()) { + String tableName = tables.getString("TABLE_NAME"); + tableList.add(tableName); + } + } finally { + if (null != tables) { + tables.close(); + } } - ArrayList> data = new ArrayList<>(); + } + for (String tableName : tableList) { + resultSet = null; try { + + // Return correct ordinals if column name pattern is not '%' + // Currently, MySQL doesn't show enough data to do this, so we do it the 'hard' way...Once + // _SYSTEM tables are in, this should be + // much easier + boolean fixUpOrdinalsRequired = false; + Map ordinalFixUpMap = null; + if (!columnNamePattern.equals("%")) { + fixUpOrdinalsRequired = true; vitessStatement = new VitessStatement(this.connection); resultSet = vitessStatement.executeQuery( - "SHOW FULL TABLES FROM " + this.quotedId + catalog + this.quotedId + " LIKE \'" - + tableNamePattern + "\'"); + "SHOW FULL COLUMNS FROM " + this.quotedId + tableName + this.quotedId + " FROM " + + this.quotedId + catalog + this.quotedId); + ordinalFixUpMap = new HashMap<>(); - if (null == types || types.length == 0) { - reportTables = reportViews = - reportSystemTables = reportSystemViews = reportLocalTemporaries = true; + int fullOrdinalPos = 1; + while (resultSet.next()) { + String fullOrdColName = resultSet.getString("Field"); + ordinalFixUpMap.put(fullOrdColName, fullOrdinalPos++); + } + } + resultSet = vitessStatement.executeQuery( + "SHOW FULL COLUMNS FROM " + this.quotedId + tableName + this.quotedId + " FROM " + + this.quotedId + catalog + this.quotedId + " LIKE " + + Constants.LITERAL_SINGLE_QUOTE + columnNamePattern + + Constants.LITERAL_SINGLE_QUOTE); + int ordPos = 1; + + while (resultSet.next()) { + ArrayList row = new ArrayList<>(); + row.add(0, catalog); + row.add(1, null); + row.add(2, tableName); + row.add(3, resultSet.getString("Field")); + TypeDescriptor typeDesc = new TypeDescriptor(resultSet.getString("Type"), + resultSet.getString("Null")); + + row.add(4, Short.toString(typeDesc.dataType)); + + // DATA_TYPE (jdbc) + row.add(5, typeDesc.typeName); // TYPE_NAME + // (native) + if (null == typeDesc.columnSize) { + row.add(6, null); } else { - for (String type : types) { - if (TableType.TABLE.equalsTo(type)) { - reportTables = true; - - } else if (TableType.VIEW.equalsTo(type)) { - reportViews = true; - - } else if (TableType.SYSTEM_TABLE.equalsTo(type)) { - reportSystemTables = true; - - } else if (TableType.SYSTEM_VIEW.equalsTo(type)) { - reportSystemViews = true; - - } else if (TableType.LOCAL_TEMPORARY.equalsTo(type)) { - reportLocalTemporaries = true; - } + String collation = resultSet.getString("Collation"); + int mbminlen = 1; + if (collation != null && ("TEXT".equals(typeDesc.typeName) || "TINYTEXT" + .equals(typeDesc.typeName) || "MEDIUMTEXT".equals(typeDesc.typeName))) { + if (collation.indexOf("ucs2") > -1 || collation.indexOf("utf16") > -1) { + mbminlen = 2; + } else if (collation.indexOf("utf32") > -1) { + mbminlen = 4; } + } + row.add(6, mbminlen == 1 ? typeDesc.columnSize.toString() + : Integer.toString(typeDesc.columnSize / mbminlen)); + } + row.add(7, Integer.toString(typeDesc.bufferLength)); + row.add(8, typeDesc.decimalDigits == null ? null : typeDesc.decimalDigits.toString()); + row.add(9, Integer.toString(typeDesc.numPrecRadix)); + row.add(10, Integer.toString(typeDesc.nullability)); + + // + // Doesn't always have this field, depending on version + // + // + // REMARK column + // + row.add(11, "Comment"); + + // COLUMN_DEF + row.add(12, + resultSet.getString("Default") == null ? null : resultSet.getString("Default")); + + row.add(13, Integer.toString(0));// SQL_DATA_TYPE + row.add(14, Integer.toString(0));// SQL_DATE_TIME_SUB + + if (StringUtils.indexOfIgnoreCase(typeDesc.typeName, "CHAR") != -1 + || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BLOB") != -1 + || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "TEXT") != -1 + || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BINARY") != -1) { + row.add(15, row.get(6)); // CHAR_OCTET_LENGTH + } else { + row.add(15, Integer.toString(0)); } - int typeColumnIndex = 0; - boolean hasTableTypes; - try { - typeColumnIndex = resultSet.findColumn("table_type"); - hasTableTypes = true; - } catch (SQLException sqlEx) { - try { - typeColumnIndex = resultSet.findColumn("Type"); - hasTableTypes = true; - } catch (SQLException sqlEx2) { - hasTableTypes = false; - } + // ORDINAL_POSITION + if (!fixUpOrdinalsRequired) { + row.add(16, Integer.toString(ordPos++)); + } else { + String origColName = resultSet.getString("Field"); + Integer realOrdinal = ordinalFixUpMap.get(origColName); + + if (realOrdinal != null) { + row.add(16, realOrdinal.toString()); + } else { + throw new SQLException( + "Can not find column in full column list to determine true ordinal position."); + } } - while (resultSet.next()) { - ArrayList row = new ArrayList<>(); - row.add(0, catalog); - row.add(1, null); - row.add(2, resultSet.getString(1)); - row.add(3, ""); - row.add(4, null); - row.add(5, null); - row.add(6, null); - row.add(7, null); - row.add(8, null); - row.add(9, null); - - if (hasTableTypes) { - String tableType = resultSet.getString(typeColumnIndex); - switch (TableType.getTableTypeCompliantWith(tableType)) { - case TABLE: - boolean reportTable = false; - TableMetaDataKey tablesKey = null; - if (reportSystemTables) { - row.add(3, TableType.TABLE.toString()); - tablesKey = - new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, - resultSet.getString(1)); - reportTable = true; - } - if (reportTable) { - sortedRows.put(tablesKey, row); - } - break; - - case VIEW: - if (reportViews) { - row.add(3, TableType.VIEW.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.VIEW.getName(), catalog, null, - resultSet.getString(1)), row); - } - break; - - case SYSTEM_TABLE: - if (reportSystemTables) { - row.add(3, TableType.SYSTEM_TABLE.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.SYSTEM_TABLE.getName(), catalog, - null, resultSet.getString(1)), row); - } - break; - - case SYSTEM_VIEW: - if (reportSystemViews) { - row.add(3, TableType.SYSTEM_VIEW.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.SYSTEM_VIEW.getName(), catalog, - null, resultSet.getString(1)), row); - } - break; - - case LOCAL_TEMPORARY: - if (reportLocalTemporaries) { - row.add(3, TableType.LOCAL_TEMPORARY.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.LOCAL_TEMPORARY.getName(), - catalog, null, resultSet.getString(1)), row); - } - break; - - default: - row.add(3, TableType.TABLE.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, - resultSet.getString(1)), row); - break; - } - } else { - if (reportTables) { - // Pre-MySQL-5.0.1, tables only - row.add(3, TableType.TABLE.toString()); - sortedRows.put( - new TableMetaDataKey(TableType.TABLE.getName(), catalog, null, - resultSet.getString(1)), row); - } - } - data.add(row); + row.add(17, typeDesc.isNullable); + + // We don't support REF or DISTINCT types + row.add(18, null); + row.add(19, null); + row.add(20, null); + row.add(21, null); + String extra = resultSet.getString("Extra"); + if (null != extra) { + row.add(22, + StringUtils.indexOfIgnoreCase(extra, "auto_increment") != -1 ? "YES" : "NO"); + row.add(23, StringUtils.indexOfIgnoreCase(extra, "generated") != -1 ? "YES" : "NO"); } + data.add(row); + } } finally { - if (null != resultSet) { - resultSet.close(); - } - if (null != vitessStatement) { - vitessStatement.close(); - } - } - String[] columnNames = - new String[] {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", - "TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SELF_REFERENCING_COL_NAME", - "REF_GENERATION"}; - Query.Type[] columnTypes = - new Query.Type[] {Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR}; - - return new VitessResultSet(columnNames, columnTypes, data, this.connection); - } - - public ResultSet getSchemas() throws SQLException { - String[] columnNames = {"TABLE_SCHEM", "TABLE_CATALOG"}; - Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } - - public ResultSet getCatalogs() throws SQLException { - ResultSet resultSet; - VitessStatement vitessStatement; - String getCatalogQB = "SHOW DATABASES"; - - vitessStatement = new VitessStatement(this.connection); - resultSet = vitessStatement.executeQuery(getCatalogQB); - - ArrayList row = new ArrayList<>(); - ArrayList> data = new ArrayList<>(); - while (resultSet.next()) { - row.add(resultSet.getString(1)); - } - Collections.sort(row); - - for (String result : row) { - ArrayList resultAsList = new ArrayList<>(); - resultAsList.add(result); - data.add(resultAsList); + if (null != resultSet) { + resultSet.close(); + } } + } + } finally { + if (null != resultSet) { resultSet.close(); - vitessStatement.close(); - String[] columnName = new String[] {"TABLE_CAT"}; - Query.Type[] columntype = new Query.Type[] {Query.Type.CHAR}; - return new VitessResultSet(columnName, columntype, data, this.connection); + } + vitessStatement.close(); } - public ResultSet getTableTypes() throws SQLException { - String[] columnNames = {"table_type"}; - Query.Type[] columnType = {Query.Type.VARCHAR}; - String[][] data = - new String[][] {{"LOCAL TEMPORARY"}, {"SYSTEM TABLES"}, {"SYSTEM VIEW"}, {"TABLE"}, - {"VIEW"}}; - return new VitessResultSet(columnNames, columnType, data, this.connection); - } + String[] columnNames = new String[]{"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", + "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", + "NUM_PREC_RADIX", "NULLABLE", "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", + "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", + "SCOPE_TABLE", "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT", "IS_GENERATEDCOLUMN"}; - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getColumns(String catalog, - String schemaPattern, String tableNamePattern, String columnNamePattern) - throws SQLException { - ResultSet resultSet = null; - VitessStatement vitessStatement = new VitessStatement(this.connection); - ArrayList> data = new ArrayList<>(); - //Null Matches All - if (null == columnNamePattern) { - columnNamePattern = "%"; - } - if (null == catalog || catalog.length() == 0) { - catalog = this.connection.getCatalog(); - } - try { - ArrayList tableList = new ArrayList<>(); - ResultSet tables = null; - if (null == tableNamePattern) { - try { - tables = getTables(catalog, schemaPattern, "%", new String[0]); - while (tables.next()) { - String tableName = tables.getString("TABLE_NAME"); - tableList.add(tableName); - } - } finally { - if (null != tables) { - tables.close(); - } - } - } else { - try { - tables = getTables(catalog, schemaPattern, tableNamePattern, new String[0]); - while (tables.next()) { - String tableName = tables.getString("TABLE_NAME"); - tableList.add(tableName); - } - } finally { - if (null != tables) { - tables.close(); - } - } - } - for (String tableName : tableList) { - resultSet = null; - try { - - // Return correct ordinals if column name pattern is not '%' - // Currently, MySQL doesn't show enough data to do this, so we do it the 'hard' way...Once - // _SYSTEM tables are in, this should be - // much easier - boolean fixUpOrdinalsRequired = false; - Map ordinalFixUpMap = null; - if (!columnNamePattern.equals("%")) { - fixUpOrdinalsRequired = true; - vitessStatement = new VitessStatement(this.connection); - resultSet = - vitessStatement.executeQuery("SHOW FULL COLUMNS FROM " + this.quotedId + - tableName + this.quotedId + " FROM " + this.quotedId + catalog - + this.quotedId); - ordinalFixUpMap = new HashMap<>(); - - int fullOrdinalPos = 1; - while (resultSet.next()) { - String fullOrdColName = resultSet.getString("Field"); - ordinalFixUpMap.put(fullOrdColName, fullOrdinalPos++); - } - } - resultSet = vitessStatement - .executeQuery("SHOW FULL COLUMNS FROM " + this.quotedId + tableName + - this.quotedId + " FROM " + this.quotedId + catalog + this.quotedId - + " LIKE " + Constants.LITERAL_SINGLE_QUOTE + columnNamePattern - + Constants.LITERAL_SINGLE_QUOTE); - int ordPos = 1; - - while (resultSet.next()) { - ArrayList row = new ArrayList<>(); - row.add(0, catalog); - row.add(1, null); - row.add(2, tableName); - row.add(3, resultSet.getString("Field")); - TypeDescriptor typeDesc = new TypeDescriptor(resultSet.getString("Type"), - resultSet.getString("Null")); - - row.add(4, Short.toString(typeDesc.dataType)); - - // DATA_TYPE (jdbc) - row.add(5, typeDesc.typeName); // TYPE_NAME - // (native) - if (null == typeDesc.columnSize) { - row.add(6, null); - } else { - String collation = resultSet.getString("Collation"); - int mbminlen = 1; - if (collation != null && ("TEXT".equals(typeDesc.typeName) || "TINYTEXT" - .equals(typeDesc.typeName) || "MEDIUMTEXT" - .equals(typeDesc.typeName))) { - if (collation.indexOf("ucs2") > -1 - || collation.indexOf("utf16") > -1) { - mbminlen = 2; - } else if (collation.indexOf("utf32") > -1) { - mbminlen = 4; - } - } - row.add(6, mbminlen == 1 ? - typeDesc.columnSize.toString() : - Integer.toString(typeDesc.columnSize / mbminlen)); - } - row.add(7, Integer.toString(typeDesc.bufferLength)); - row.add(8, typeDesc.decimalDigits == null ? - null : - typeDesc.decimalDigits.toString()); - row.add(9, Integer.toString(typeDesc.numPrecRadix)); - row.add(10, Integer.toString(typeDesc.nullability)); - - // - // Doesn't always have this field, depending on version - // - // - // REMARK column - // - row.add(11, "Comment"); - - // COLUMN_DEF - row.add(12, resultSet.getString("Default") == null ? - null : - resultSet.getString("Default")); - - row.add(13, Integer.toString(0));// SQL_DATA_TYPE - row.add(14, Integer.toString(0));// SQL_DATE_TIME_SUB - - if (StringUtils.indexOfIgnoreCase(typeDesc.typeName, "CHAR") != -1 - || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BLOB") != -1 - || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "TEXT") != -1 - || StringUtils.indexOfIgnoreCase(typeDesc.typeName, "BINARY") != -1) { - row.add(15, row.get(6)); // CHAR_OCTET_LENGTH - } else { - row.add(15, Integer.toString(0)); - } - - // ORDINAL_POSITION - if (!fixUpOrdinalsRequired) { - row.add(16, Integer.toString(ordPos++)); - } else { - String origColName = resultSet.getString("Field"); - Integer realOrdinal = ordinalFixUpMap.get(origColName); - - if (realOrdinal != null) { - row.add(16, realOrdinal.toString()); - } else { - throw new SQLException( - "Can not find column in full column list to determine true ordinal position."); - } - } - - row.add(17, typeDesc.isNullable); - - // We don't support REF or DISTINCT types - row.add(18, null); - row.add(19, null); - row.add(20, null); - row.add(21, null); - String extra = resultSet.getString("Extra"); - if (null != extra) { - row.add(22, - StringUtils.indexOfIgnoreCase(extra, "auto_increment") != -1 ? - "YES" : - "NO"); - row.add(23, StringUtils.indexOfIgnoreCase(extra, "generated") != -1 ? - "YES" : - "NO"); - } - data.add(row); - } - } finally { - if (null != resultSet) { - resultSet.close(); - } - } - } - } finally { - if (null != resultSet) { - resultSet.close(); - } - vitessStatement.close(); - } + Query.Type[] columnType = new Query.Type[]{Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.INT32, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, Query.Type.CHAR, + Query.Type.CHAR}; - String[] columnNames = - new String[] {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", - "TYPE_NAME", "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "NUM_PREC_RADIX", - "NULLABLE", "REMARKS", "COLUMN_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", - "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", "IS_NULLABLE", "SCOPE_CATALOG", - "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE", "IS_AUTOINCREMENT", - "IS_GENERATEDCOLUMN"}; - - Query.Type[] columnType = - new Query.Type[] {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.INT32, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, - Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, - Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.CHAR, Query.Type.INT16, Query.Type.CHAR, Query.Type.CHAR}; - - return new VitessResultSet(columnNames, columnType, data, this.connection); - } + return new VitessResultSet(columnNames, columnType, data, this.connection); + } - public ResultSet getColumnPrivileges(String catalog, String schema, String table, - String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public ResultSet getColumnPrivileges(String catalog, String schema, String table, + String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } - public ResultSet getTablePrivileges(String catalog, String schemaPattern, - String tableNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getBestRowIdentifier( - String catalog, String schema, String table, int scope, boolean nullable) - throws SQLException { - ResultSet resultSet = null; - VitessStatement vitessStatement = new VitessStatement(this.connection); + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, + boolean nullable) throws SQLException { + ResultSet resultSet = null; + VitessStatement vitessStatement = new VitessStatement(this.connection); - if (null == table) { - throw new SQLException("Table Parameter cannot be null in getBestRowIdentifier"); - } + if (null == table) { + throw new SQLException("Table Parameter cannot be null in getBestRowIdentifier"); + } - String[] columnName = - new String[] {"SCOPE", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", - "BUFFER_LENGTH", "DECIMAL_DIGITS", "PSEUDO_COLUMN"}; + String[] columnName = new String[]{"SCOPE", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", + "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "PSEUDO_COLUMN"}; - Query.Type[] columnType = - new Query.Type[] {Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, Query.Type.CHAR, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT16, Query.Type.INT16}; + Query.Type[] columnType = new Query.Type[]{Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, + Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT16, Query.Type.INT16}; - ArrayList> data = new ArrayList<>(); + ArrayList> data = new ArrayList<>(); - try { - resultSet = vitessStatement - .executeQuery("SHOW COLUMNS FROM " + this.quotedId + table + this.quotedId + "" + - " FROM " + this.quotedId + catalog + this.quotedId); + try { + resultSet = vitessStatement.executeQuery( + "SHOW COLUMNS FROM " + this.quotedId + table + this.quotedId + "" + " FROM " + + this.quotedId + catalog + this.quotedId); - while (resultSet.next()) { - ArrayList row = new ArrayList<>(); - String keyType = resultSet.getString("Key"); - if (keyType != null && StringUtils.startsWithIgnoreCase(keyType, "PRI")) { - row.add(Integer.toString(DatabaseMetaData.bestRowSession)); - row.add(resultSet.getString("Field")); - String type = resultSet.getString("Type"); - int size = this.maxBufferSize; - int decimals = 0; - if (type.indexOf("enum") != -1) { - String temp = type.substring(type.indexOf("("), type.indexOf(")")); - StringTokenizer tokenizer = new StringTokenizer(temp, ","); - - int maxLength; - for ( - maxLength = 0; tokenizer.hasMoreTokens(); - maxLength = Math.max(maxLength, tokenizer.nextToken().length() - 2)) - ; - - size = maxLength; - decimals = 0; - type = "enum"; - } else if (type.indexOf("(") != -1) { - if (type.indexOf(",") != -1) { - size = Integer - .parseInt(type.substring(type.indexOf("(") + 1, type.indexOf(","))); - decimals = Integer - .parseInt(type.substring(type.indexOf(",") + 1, type.indexOf(")"))); - } else { - size = Integer - .parseInt(type.substring(type.indexOf("(") + 1, type.indexOf(")"))); - } - - type = type.substring(0, type.indexOf("(")); - } - - row.add(Integer.toString(MysqlDefs.mysqlToJavaType(type))); - row.add(type); - row.add(Integer.toString(size + decimals)); - row.add(Integer.toString(size + decimals)); - row.add(Integer.toString(decimals)); - row.add(Integer.toString(DatabaseMetaData.bestRowNotPseudo)); - data.add(row); - } + while (resultSet.next()) { + ArrayList row = new ArrayList<>(); + String keyType = resultSet.getString("Key"); + if (keyType != null && StringUtils.startsWithIgnoreCase(keyType, "PRI")) { + row.add(Integer.toString(DatabaseMetaData.bestRowSession)); + row.add(resultSet.getString("Field")); + String type = resultSet.getString("Type"); + int size = this.maxBufferSize; + int decimals = 0; + if (type.indexOf("enum") != -1) { + String temp = type.substring(type.indexOf("("), type.indexOf(")")); + StringTokenizer tokenizer = new StringTokenizer(temp, ","); + + int maxLength; + for (maxLength = 0; tokenizer.hasMoreTokens(); + maxLength = Math.max(maxLength, tokenizer.nextToken().length() - 2)) { + ; } - } finally { - if (resultSet != null) { - resultSet.close(); + + size = maxLength; + decimals = 0; + type = "enum"; + } else if (type.indexOf("(") != -1) { + if (type.indexOf(",") != -1) { + size = Integer.parseInt(type.substring(type.indexOf("(") + 1, type.indexOf(","))); + decimals = Integer.parseInt(type.substring(type.indexOf(",") + 1, type.indexOf(")"))); + } else { + size = Integer.parseInt(type.substring(type.indexOf("(") + 1, type.indexOf(")"))); } - vitessStatement.close(); - } - return new VitessResultSet(columnName, columnType, data, this.connection); - } - public ResultSet getVersionColumns(String catalog, String schema, String table) - throws SQLException { - if (null == table) { - throw new SQLException("Table cannot be null"); - } - ResultSet resultSet = null; - VitessStatement vitessStatement = null; - ArrayList> data = new ArrayList<>(); - - StringBuilder getVersionColumnsQB = new StringBuilder(); - getVersionColumnsQB.append("SHOW COLUMNS FROM "); - getVersionColumnsQB.append(this.quotedId); - getVersionColumnsQB.append(table); - getVersionColumnsQB.append(this.quotedId); - getVersionColumnsQB.append(" FROM "); - getVersionColumnsQB.append(this.quotedId); - getVersionColumnsQB.append(catalog); - getVersionColumnsQB.append(this.quotedId); - getVersionColumnsQB.append(" WHERE Extra LIKE '%on update CURRENT_TIMESTAMP%'"); + type = type.substring(0, type.indexOf("(")); + } - try { - vitessStatement = new VitessStatement(this.connection); - resultSet = vitessStatement.executeQuery(getVersionColumnsQB.toString()); - ArrayList row; - while (resultSet.next()) { - row = new ArrayList<>(); - TypeDescriptor typeDesc = - new TypeDescriptor(resultSet.getString("Type"), resultSet.getString("Null")); - row.add(0, null); - row.add(1, resultSet.getString("Field")); - row.add(2, Short.toString(typeDesc.dataType)); - row.add(3, typeDesc.typeName); - row.add(4, typeDesc.columnSize == null ? null : typeDesc.columnSize.toString()); - row.add(5, Integer.toString(typeDesc.bufferLength)); - row.add(6, - typeDesc.decimalDigits == null ? null : typeDesc.decimalDigits.toString()); - row.add(7, Integer.toString(java.sql.DatabaseMetaData.versionColumnNotPseudo)); - data.add(row); - } - } finally { - if (null != resultSet) { - resultSet.close(); - vitessStatement.close(); - } + row.add(Integer.toString(MysqlDefs.mysqlToJavaType(type))); + row.add(type); + row.add(Integer.toString(size + decimals)); + row.add(Integer.toString(size + decimals)); + row.add(Integer.toString(decimals)); + row.add(Integer.toString(DatabaseMetaData.bestRowNotPseudo)); + data.add(row); } - String[] columnNames = - new String[] {"SCOPE", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", "COLUMN_SIZE", - "BUFFER_LENGTH", "DECIMAL_DIGITS", "PSEUDO_COLUMN"}; - - Query.Type[] columnType = - new Query.Type[] {Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, Query.Type.CHAR, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT16, Query.Type.INT16}; - return new VitessResultSet(columnNames, columnType, data, this.connection); + } + } finally { + if (resultSet != null) { + resultSet.close(); + } + vitessStatement.close(); + } + return new VitessResultSet(columnName, columnType, data, this.connection); + } + + public ResultSet getVersionColumns(String catalog, String schema, String table) + throws SQLException { + if (null == table) { + throw new SQLException("Table cannot be null"); + } + ResultSet resultSet = null; + VitessStatement vitessStatement = null; + ArrayList> data = new ArrayList<>(); + + StringBuilder getVersionColumnsQB = new StringBuilder(); + getVersionColumnsQB.append("SHOW COLUMNS FROM "); + getVersionColumnsQB.append(this.quotedId); + getVersionColumnsQB.append(table); + getVersionColumnsQB.append(this.quotedId); + getVersionColumnsQB.append(" FROM "); + getVersionColumnsQB.append(this.quotedId); + getVersionColumnsQB.append(catalog); + getVersionColumnsQB.append(this.quotedId); + getVersionColumnsQB.append(" WHERE Extra LIKE '%on update CURRENT_TIMESTAMP%'"); + + try { + vitessStatement = new VitessStatement(this.connection); + resultSet = vitessStatement.executeQuery(getVersionColumnsQB.toString()); + ArrayList row; + while (resultSet.next()) { + row = new ArrayList<>(); + TypeDescriptor typeDesc = new TypeDescriptor(resultSet.getString("Type"), + resultSet.getString("Null")); + row.add(0, null); + row.add(1, resultSet.getString("Field")); + row.add(2, Short.toString(typeDesc.dataType)); + row.add(3, typeDesc.typeName); + row.add(4, typeDesc.columnSize == null ? null : typeDesc.columnSize.toString()); + row.add(5, Integer.toString(typeDesc.bufferLength)); + row.add(6, typeDesc.decimalDigits == null ? null : typeDesc.decimalDigits.toString()); + row.add(7, Integer.toString(java.sql.DatabaseMetaData.versionColumnNotPseudo)); + data.add(row); + } + } finally { + if (null != resultSet) { + resultSet.close(); + vitessStatement.close(); + } } + String[] columnNames = new String[]{"SCOPE", "COLUMN_NAME", "DATA_TYPE", "TYPE_NAME", + "COLUMN_SIZE", "BUFFER_LENGTH", "DECIMAL_DIGITS", "PSEUDO_COLUMN"}; - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getPrimaryKeys( - String catalog, String schema, String table) throws SQLException { + Query.Type[] columnType = new Query.Type[]{Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, + Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT16, Query.Type.INT16}; + return new VitessResultSet(columnNames, columnType, data, this.connection); + } - if (null == table) { - throw new SQLException("Table Name Cannot be Null"); - } - ResultSet resultSet = null; - VitessStatement vitessStatement = new VitessStatement(this.connection); - ArrayList> sortedData = new ArrayList<>(); - try { + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { - resultSet = vitessStatement - .executeQuery("SHOW KEYS FROM " + this.quotedId + table + this.quotedId + " " + - "FROM " + this.quotedId + catalog + this.quotedId); + if (null == table) { + throw new SQLException("Table Name Cannot be Null"); + } + ResultSet resultSet = null; + VitessStatement vitessStatement = new VitessStatement(this.connection); + ArrayList> sortedData = new ArrayList<>(); + try { - TreeMap> sortMap = new TreeMap<>(); + resultSet = vitessStatement.executeQuery( + "SHOW KEYS FROM " + this.quotedId + table + this.quotedId + " " + "FROM " + this.quotedId + + catalog + this.quotedId); - while (resultSet.next()) { - String keyType = resultSet.getString("Key_name"); - ArrayList row = new ArrayList<>(); - if (null != keyType) { - if (keyType.equalsIgnoreCase("PRIMARY") || keyType.equalsIgnoreCase("PRI")) { - row.add(0, (catalog == null) ? "" : catalog); - row.add(1, null); - row.add(2, table); - - String columnName = resultSet.getString("Column_name"); - row.add(3, columnName); - row.add(4, resultSet.getString("Seq_in_index")); - row.add(5, keyType); - sortMap.put(columnName, row); - } - } - } + TreeMap> sortMap = new TreeMap<>(); - // Now pull out in column name sorted order - for (ArrayList row : sortMap.values()) { - sortedData.add(row); - } - } finally { - if (null != resultSet) { - resultSet.close(); - } - vitessStatement.close(); + while (resultSet.next()) { + String keyType = resultSet.getString("Key_name"); + ArrayList row = new ArrayList<>(); + if (null != keyType) { + if (keyType.equalsIgnoreCase("PRIMARY") || keyType.equalsIgnoreCase("PRI")) { + row.add(0, (catalog == null) ? "" : catalog); + row.add(1, null); + row.add(2, table); + + String columnName = resultSet.getString("Column_name"); + row.add(3, columnName); + row.add(4, resultSet.getString("Seq_in_index")); + row.add(5, keyType); + sortMap.put(columnName, row); + } } - - String[] columnNames = - new String[] {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", - "PK_NAME"}; - Query.Type[] columnType = - new Query.Type[] {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.INT16, Query.Type.CHAR}; - - return new VitessResultSet(columnNames, columnType, sortedData, this.connection); - } - - public ResultSet getImportedKeys(String catalog, String schema, String table) - throws SQLException { - if (null == table) { - throw new SQLException("Table Name Cannot be Null"); + } + + // Now pull out in column name sorted order + for (ArrayList row : sortMap.values()) { + sortedData.add(row); + } + } finally { + if (null != resultSet) { + resultSet.close(); + } + vitessStatement.close(); + } + + String[] columnNames = new String[]{"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", + "KEY_SEQ", "PK_NAME"}; + Query.Type[] columnType = new Query.Type[]{Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.INT16, Query.Type.CHAR}; + + return new VitessResultSet(columnNames, columnType, sortedData, this.connection); + } + + public ResultSet getImportedKeys(String catalog, String schema, String table) + throws SQLException { + if (null == table) { + throw new SQLException("Table Name Cannot be Null"); + } + ResultSet resultSet = null; + VitessStatement vitessStatement = new VitessStatement(this.connection); + ArrayList> rows = new ArrayList<>(); + try { + resultSet = vitessStatement + .executeQuery("SHOW CREATE TABLE " + this.quotedId + table + this.quotedId); + while (resultSet.next()) { + extractForeignKeyForTable(rows, resultSet.getString(2), catalog, table); + } + } finally { + if (resultSet != null) { + resultSet.close(); + } + } + String[] columnNames = new String[]{"PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", + "PKCOLUMN_NAME", "FKTABLE_CAT", "FKTABLE_SCHEM", "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", + "UPDATE_RULE", "DELETE_RULE", "FK_NAME", "PK_NAME", "DEFERRABILITY"}; + Query.Type[] columnType = new Query.Type[]{Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.INT16, Query.Type.INT16, Query.Type.INT16, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.INT16}; + return new VitessResultSet(columnNames, columnType, rows, this.connection); + } + + @VisibleForTesting + void extractForeignKeyForTable(List> rows, String createTableString, + String catalog, String table) throws SQLException { + StringTokenizer lineTokenizer = new StringTokenizer(createTableString, "\n"); + + while (lineTokenizer.hasMoreTokens()) { + String line = lineTokenizer.nextToken().trim(); + String constraintName = null; + if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) { + boolean usingBackTicks = true; + int beginPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, this.quotedId, 0); + if (beginPos == -1) { + beginPos = line.indexOf("\""); + usingBackTicks = false; } - ResultSet resultSet = null; - VitessStatement vitessStatement = new VitessStatement(this.connection); - ArrayList> rows = new ArrayList<>(); - try { - resultSet = vitessStatement.executeQuery("SHOW CREATE TABLE " + this.quotedId + table + this.quotedId); - while (resultSet.next()) { - extractForeignKeyForTable(rows, resultSet.getString(2), catalog, table); - } - } finally { - if (resultSet != null) { - resultSet.close(); - } + if (beginPos != -1) { + int endPos; + if (usingBackTicks) { + endPos = io.vitess.util.StringUtils + .indexOfQuoteDoubleAware(line, this.quotedId, beginPos + 1); + } else { + endPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, "\"", beginPos + 1); + } + if (endPos != -1) { + constraintName = line.substring(beginPos + 1, endPos); + line = line.substring(endPos + 1, line.length()).trim(); + } } - String[] columnNames = - new String[] {"PKTABLE_CAT", "PKTABLE_SCHEM", "PKTABLE_NAME", "PKCOLUMN_NAME", "FKTABLE_CAT", - "FKTABLE_SCHEM", "FKTABLE_NAME", "FKCOLUMN_NAME", "KEY_SEQ", "UPDATE_RULE", "DELETE_RULE", - "FK_NAME", "PK_NAME", "DEFERRABILITY"}; - Query.Type[] columnType = - new Query.Type[] {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, - Query.Type.INT16, Query.Type.INT16, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16}; - return new VitessResultSet(columnNames, columnType, rows, this.connection); - } - - @VisibleForTesting - void extractForeignKeyForTable(List> rows, String createTableString, String catalog, String table) throws SQLException { - StringTokenizer lineTokenizer = new StringTokenizer(createTableString, "\n"); - - while (lineTokenizer.hasMoreTokens()) { - String line = lineTokenizer.nextToken().trim(); - String constraintName = null; - if (StringUtils.startsWithIgnoreCase(line, "CONSTRAINT")) { - boolean usingBackTicks = true; - int beginPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, this.quotedId, 0); - if (beginPos == -1) { - beginPos = line.indexOf("\""); - usingBackTicks = false; - } - if (beginPos != -1) { - int endPos; - if (usingBackTicks) { - endPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, this.quotedId, beginPos + 1); - } else { - endPos = io.vitess.util.StringUtils.indexOfQuoteDoubleAware(line, "\"", beginPos + 1); - } - if (endPos != -1) { - constraintName = line.substring(beginPos + 1, endPos); - line = line.substring(endPos + 1, line.length()).trim(); - } - } - } + } - if (line.startsWith("FOREIGN KEY")) { - if (line.endsWith(",")) { - line = line.substring(0, line.length() - 1); - } - int indexOfFK = line.indexOf("FOREIGN KEY"); - String localColumnName = null; - String referencedCatalogName = io.vitess.util.StringUtils.quoteIdentifier(catalog, this.quotedId); - String referencedTableName = null; - String referencedColumnName = null; - if (indexOfFK != -1) { - int afterFk = indexOfFK + "FOREIGN KEY".length(); - - int indexOfRef = io.vitess.util.StringUtils.indexOfIgnoreCase(afterFk, line, "REFERENCES", this.quotedId, this.quotedId); - if (indexOfRef != -1) { - int indexOfParenOpen = line.indexOf('(', afterFk); - int indexOfParenClose = io.vitess.util.StringUtils.indexOfIgnoreCase(indexOfParenOpen, line, ")", this.quotedId, this.quotedId); - localColumnName = line.substring(indexOfParenOpen + 1, indexOfParenClose); - - int afterRef = indexOfRef + "REFERENCES".length(); - int referencedColumnBegin = io.vitess.util.StringUtils.indexOfIgnoreCase(afterRef, line, "(", this.quotedId, this.quotedId); - - if (referencedColumnBegin != -1) { - referencedTableName = line.substring(afterRef, referencedColumnBegin); - int referencedColumnEnd = io.vitess.util.StringUtils.indexOfIgnoreCase(referencedColumnBegin + 1, line, ")", this.quotedId, this.quotedId); - if (referencedColumnEnd != -1) { - referencedColumnName = line.substring(referencedColumnBegin + 1, referencedColumnEnd); - } - int indexOfCatalogSep = io.vitess.util.StringUtils.indexOfIgnoreCase(0, referencedTableName, ".", this.quotedId, this.quotedId); - if (indexOfCatalogSep != -1) { - referencedCatalogName = referencedTableName.substring(0, indexOfCatalogSep); - referencedTableName = referencedTableName.substring(indexOfCatalogSep + 1); - } - } - } - } - if (constraintName == null) { - constraintName = "not_available"; - } - List localColumnsList = io.vitess.util.StringUtils.split(localColumnName, ",", this.quotedId, this.quotedId); - List referColumnsList = io.vitess.util.StringUtils.split(referencedColumnName, ",", this.quotedId, this.quotedId); - if (localColumnsList.size() != referColumnsList.size()) { - throw new SQLException("Mismatch columns list for foreign key local and reference columns"); - } - // Report a separate row for each column in the foreign key. All values the same except the column name. - for (int i = 0; i < localColumnsList.size(); i++) { - String localColumn = localColumnsList.get(i); - String referColumn = referColumnsList.get(i); - ArrayList row = new ArrayList<>(14); - row.add(io.vitess.util.StringUtils.unQuoteIdentifier(referencedCatalogName, this.quotedId)); // PKTABLE_CAT - row.add(null); // PKTABLE_SCHEM - row.add(io.vitess.util.StringUtils.unQuoteIdentifier(referencedTableName, this.quotedId)); // PKTABLE_NAME - row.add(io.vitess.util.StringUtils.unQuoteIdentifier(referColumn, this.quotedId)); // PKCOLUMN_NAME - row.add(catalog); // FKTABLE_CAT - row.add(null); // FKTABLE_SCHEM - row.add(table); // FKTABLE_NAME - row.add(io.vitess.util.StringUtils.unQuoteIdentifier(localColumn, this.quotedId)); // FKCOLUMN_NAME - row.add(Integer.toString(i + 1)); // KEY_SEQ - int[] actions = getForeignKeyActions(line); - row.add(Integer.toString(actions[1])); // UPDATE_RULE - row.add(Integer.toString(actions[0])); // DELETE_RULE - row.add(constraintName); // FK_NAME - row.add(null); // PK_NAME - row.add(Integer.toString(java.sql.DatabaseMetaData.importedKeyNotDeferrable)); // DEFERRABILITY - rows.add(row); - } + if (line.startsWith("FOREIGN KEY")) { + if (line.endsWith(",")) { + line = line.substring(0, line.length() - 1); + } + int indexOfFK = line.indexOf("FOREIGN KEY"); + String localColumnName = null; + String referencedCatalogName = io.vitess.util.StringUtils + .quoteIdentifier(catalog, this.quotedId); + String referencedTableName = null; + String referencedColumnName = null; + if (indexOfFK != -1) { + int afterFk = indexOfFK + "FOREIGN KEY".length(); + + int indexOfRef = io.vitess.util.StringUtils + .indexOfIgnoreCase(afterFk, line, "REFERENCES", this.quotedId, this.quotedId); + if (indexOfRef != -1) { + int indexOfParenOpen = line.indexOf('(', afterFk); + int indexOfParenClose = io.vitess.util.StringUtils + .indexOfIgnoreCase(indexOfParenOpen, line, ")", this.quotedId, this.quotedId); + localColumnName = line.substring(indexOfParenOpen + 1, indexOfParenClose); + + int afterRef = indexOfRef + "REFERENCES".length(); + int referencedColumnBegin = io.vitess.util.StringUtils + .indexOfIgnoreCase(afterRef, line, "(", this.quotedId, this.quotedId); + + if (referencedColumnBegin != -1) { + referencedTableName = line.substring(afterRef, referencedColumnBegin); + int referencedColumnEnd = io.vitess.util.StringUtils + .indexOfIgnoreCase(referencedColumnBegin + 1, line, ")", this.quotedId, + this.quotedId); + if (referencedColumnEnd != -1) { + referencedColumnName = line + .substring(referencedColumnBegin + 1, referencedColumnEnd); + } + int indexOfCatalogSep = io.vitess.util.StringUtils + .indexOfIgnoreCase(0, referencedTableName, ".", this.quotedId, this.quotedId); + if (indexOfCatalogSep != -1) { + referencedCatalogName = referencedTableName.substring(0, indexOfCatalogSep); + referencedTableName = referencedTableName.substring(indexOfCatalogSep + 1); + } } + } } - } - - - /** - * Parses the constraint to see what actions are taking for update and delete, such as cascade. - * @param constraint - * the constraint to parse - * @return the code from {@link DatabaseMetaData} corresponding to the foreign actions for the constraint - */ - private int[] getForeignKeyActions(String constraint) { - int[] actions = new int[] { java.sql.DatabaseMetaData.importedKeyNoAction, java.sql.DatabaseMetaData.importedKeyNoAction }; - int lastParenIndex = constraint.lastIndexOf(")"); - if (lastParenIndex != (constraint.length() - 1)) { - String cascadeOptions = constraint.substring(lastParenIndex + 1).trim().toUpperCase(Locale.ENGLISH); - actions[0] = getCascadeDeleteOption(cascadeOptions); - actions[1] = getCascadeUpdateOption(cascadeOptions); + if (constraintName == null) { + constraintName = "not_available"; } - return actions; - } - - /** - * Parses the cascade option string and returns the DBMD constant that - * represents it (for deletes) - * - * @param cascadeOptions - * the comment from 'SHOW TABLE STATUS' - * @return the DBMD constant that represents the cascade option - */ - private int getCascadeDeleteOption(String cascadeOptions) { - int onDeletePos = cascadeOptions.indexOf("ON DELETE"); - if (onDeletePos != -1) { - String deleteOptions = cascadeOptions.substring(onDeletePos, cascadeOptions.length()); - if (deleteOptions.startsWith("ON DELETE CASCADE")) { - return java.sql.DatabaseMetaData.importedKeyCascade; - } else if (deleteOptions.startsWith("ON DELETE SET NULL")) { - return java.sql.DatabaseMetaData.importedKeySetNull; - } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) { - return java.sql.DatabaseMetaData.importedKeyRestrict; - } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) { - return java.sql.DatabaseMetaData.importedKeyNoAction; - } + List localColumnsList = io.vitess.util.StringUtils + .split(localColumnName, ",", this.quotedId, this.quotedId); + List referColumnsList = io.vitess.util.StringUtils + .split(referencedColumnName, ",", this.quotedId, this.quotedId); + if (localColumnsList.size() != referColumnsList.size()) { + throw new SQLException( + "Mismatch columns list for foreign key local and reference columns"); } - return java.sql.DatabaseMetaData.importedKeyNoAction; - } - - /** - * Parses the cascade option string and returns the DBMD constant that - * represents it (for Updates) - * - * @param cascadeOptions - * the comment from 'SHOW TABLE STATUS' - * @return the DBMD constant that represents the cascade option - */ - private int getCascadeUpdateOption(String cascadeOptions) { - int onUpdatePos = cascadeOptions.indexOf("ON UPDATE"); - if (onUpdatePos != -1) { - String updateOptions = cascadeOptions.substring(onUpdatePos, cascadeOptions.length()); - if (updateOptions.startsWith("ON UPDATE CASCADE")) { - return java.sql.DatabaseMetaData.importedKeyCascade; - } else if (updateOptions.startsWith("ON UPDATE SET NULL")) { - return java.sql.DatabaseMetaData.importedKeySetNull; - } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) { - return java.sql.DatabaseMetaData.importedKeyRestrict; - } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) { - return java.sql.DatabaseMetaData.importedKeyNoAction; - } + // Report a separate row for each column in the foreign key. All values the same except + // the column name. + for (int i = 0; i < localColumnsList.size(); i++) { + String localColumn = localColumnsList.get(i); + String referColumn = referColumnsList.get(i); + ArrayList row = new ArrayList<>(14); + row.add(io.vitess.util.StringUtils + .unQuoteIdentifier(referencedCatalogName, this.quotedId)); // PKTABLE_CAT + row.add(null); // PKTABLE_SCHEM + row.add(io.vitess.util.StringUtils + .unQuoteIdentifier(referencedTableName, this.quotedId)); // PKTABLE_NAME + row.add(io.vitess.util.StringUtils + .unQuoteIdentifier(referColumn, this.quotedId)); // PKCOLUMN_NAME + row.add(catalog); // FKTABLE_CAT + row.add(null); // FKTABLE_SCHEM + row.add(table); // FKTABLE_NAME + row.add(io.vitess.util.StringUtils + .unQuoteIdentifier(localColumn, this.quotedId)); // FKCOLUMN_NAME + row.add(Integer.toString(i + 1)); // KEY_SEQ + int[] actions = getForeignKeyActions(line); + row.add(Integer.toString(actions[1])); // UPDATE_RULE + row.add(Integer.toString(actions[0])); // DELETE_RULE + row.add(constraintName); // FK_NAME + row.add(null); // PK_NAME + row.add(Integer + .toString(java.sql.DatabaseMetaData.importedKeyNotDeferrable)); // DEFERRABILITY + rows.add(row); } + } + } + } + + + /** + * Parses the constraint to see what actions are taking for update and delete, such as cascade. + * + * @param constraint the constraint to parse + * @return the code from {@link DatabaseMetaData} corresponding to the foreign actions for the + * constraint + */ + private int[] getForeignKeyActions(String constraint) { + int[] actions = new int[]{java.sql.DatabaseMetaData.importedKeyNoAction, + java.sql.DatabaseMetaData.importedKeyNoAction}; + int lastParenIndex = constraint.lastIndexOf(")"); + if (lastParenIndex != (constraint.length() - 1)) { + String cascadeOptions = constraint.substring(lastParenIndex + 1).trim() + .toUpperCase(Locale.ENGLISH); + actions[0] = getCascadeDeleteOption(cascadeOptions); + actions[1] = getCascadeUpdateOption(cascadeOptions); + } + return actions; + } + + /** + * Parses the cascade option string and returns the DBMD constant that represents it (for + * deletes) + * + * @param cascadeOptions the comment from 'SHOW TABLE STATUS' + * @return the DBMD constant that represents the cascade option + */ + private int getCascadeDeleteOption(String cascadeOptions) { + int onDeletePos = cascadeOptions.indexOf("ON DELETE"); + if (onDeletePos != -1) { + String deleteOptions = cascadeOptions.substring(onDeletePos, cascadeOptions.length()); + if (deleteOptions.startsWith("ON DELETE CASCADE")) { + return java.sql.DatabaseMetaData.importedKeyCascade; + } else if (deleteOptions.startsWith("ON DELETE SET NULL")) { + return java.sql.DatabaseMetaData.importedKeySetNull; + } else if (deleteOptions.startsWith("ON DELETE RESTRICT")) { + return java.sql.DatabaseMetaData.importedKeyRestrict; + } else if (deleteOptions.startsWith("ON DELETE NO ACTION")) { return java.sql.DatabaseMetaData.importedKeyNoAction; - } - - public ResultSet getExportedKeys(String catalog, String schema, String table) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getCrossReference(String parentCatalog, String parentSchema, - String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSet getTypeInfo() throws SQLException { - String[] columnNames = - {"TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", "LITERAL_SUFFIX", - "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", "UNSIGNED_ATTRIBUTE", - "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", "MINIMUM_SCALE", - "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"}; - Query.Type[] columnTypes = - {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.VARCHAR, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, Query.Type.BIT, - Query.Type.INT16, Query.Type.BIT, Query.Type.BIT, Query.Type.BIT, - Query.Type.VARCHAR, Query.Type.INT16, Query.Type.INT16, Query.Type.INT32, - Query.Type.INT32, Query.Type.INT32}; - - String[][] data = - {{"BIT", "-7", "1", "", "", "", "1", "true", "3", "false", "false", "false", "BIT", "0", - "0", "0", "0", "10"}, - {"BOOL", "-7", "1", "", "", "", "1", "true", "3", "false", "false", "false", "BOOL", - "0", "0", "0", "0", "10"}, - {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "TINYINT", "0", "0", "0", "0", "10"}, - {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", - "3", "true", "false", "true", "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "BIGINT", "0", "0", "0", "0", "10"}, - {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "true", "3", "false", - "false", "false", "LONG VARBINARY", "0", "0", "0", "0", "10"}, - {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "true", "3", "false", "false", - "false", "MEDIUMBLOB", "0", "0", "0", "0", "10"}, - {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "true", "3", "false", "false", - "false", "LONGBLOB", "0", "0", "0", "0", "10"}, - {"BLOB", "-4", "65535", "'", "'", "", "1", "true", "3", "false", "false", "false", - "BLOB", "0", "0", "0", "0", "10"}, - {"TINYBLOB", "-4", "255", "'", "'", "", "1", "true", "3", "false", "false", "false", - "TINYBLOB", "0", "0", "0", "0", "10"}, - {"VARBINARY", "-3", "65535", "'", "'", "(M)", "1", "true", "3", "false", "false", - "false", "VARBINARY", "0", "0", "0", "0", "10"}, - {"BINARY", "-2", "255", "'", "'", "(M)", "1", "true", "3", "false", "false", - "false", "BINARY", "0", "0", "0", "0", "10"}, - {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "false", "3", "false", - "false", "false", "LONG VARCHAR", "0", "0", "0", "0", "10"}, - {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "false", "3", "false", "false", - "false", "MEDIUMTEXT", "0", "0", "0", "0", "10"}, - {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "false", "3", "false", "false", - "false", "LONGTEXT", "0", "0", "0", "0", "10"}, - {"TEXT", "-1", "65535", "'", "'", "", "1", "false", "3", "false", "false", "false", - "TEXT", "0", "0", "0", "0", "10"}, - {"TINYTEXT", "-1", "255", "'", "'", "", "1", "false", "3", "false", "false", - "false", "TINYTEXT", "0", "0", "0", "0", "10"}, - {"CHAR", "1", "255", "'", "'", "(M)", "1", "false", "3", "false", "false", "false", - "CHAR", "0", "0", "0", "0", "10"}, - {"NUMERIC", "2", "65", "", "", "[(M[,D])] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "NUMERIC", "-308", "308", "0", "0", "10"}, - {"DECIMAL", "3", "65", "", "", "[(M[,D])] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "DECIMAL", "-308", "308", "0", "0", "10"}, - {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "INTEGER", "0", "0", "0", "0", "10"}, - {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, - {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", - "false", "true", "INT", "0", "0", "0", "0", "10"}, - {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", - "false", "true", "INT UNSIGNED", "0", "0", "0", "0", "10"}, - {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "MEDIUMINT", "0", "0", "0", "0", "10"}, - {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "SMALLINT", "0", "0", "0", "0", "10"}, - {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", - "true", "false", "true", "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, - {"FLOAT", "7", "10", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "FLOAT", "-38", "38", "0", "0", "10"}, - {"DOUBLE", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "DOUBLE", "-308", "308", "0", "0", "10"}, - {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", - "false", "false", "true", "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, - {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", - "false", "true", "REAL", "-308", "308", "0", "0", "10"}, - {"VARCHAR", "12", "65535", "'", "'", "(M)", "1", "false", "3", "false", "false", - "false", "VARCHAR", "0", "0", "0", "0", "10"}, - {"ENUM", "12", "65535", "'", "'", "", "1", "false", "3", "false", "false", "false", - "ENUM", "0", "0", "0", "0", "10"}, - {"SET", "12", "64", "'", "'", "", "1", "false", "3", "false", "false", "false", - "SET", "0", "0", "0", "0", "10"}, - {"DATE", "91", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", - "DATE", "0", "0", "0", "0", "10"}, - {"TIME", "92", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", - "TIME", "0", "0", "0", "0", "10"}, - {"DATETIME", "93", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", - "DATETIME", "0", "0", "0", "0", "10"}, - {"TIMESTAMP", "93", "0", "'", "'", "[(M)]", "1", "false", "3", "false", "false", - "false", "TIMESTAMP", "0", "0", "0", "0", "10"}}; - - return new VitessResultSet(columnNames, columnTypes, data, this.connection); - } - - @SuppressWarnings("StringBufferReplaceableByString") public ResultSet getIndexInfo( - String catalog, String schema, String table, boolean unique, boolean approximate) - throws SQLException { - - ArrayList> data = new ArrayList<>(); - final SortedMap> sortedRows = new TreeMap<>(); - VitessStatement vitessStatement = new VitessStatement(this.connection); - ResultSet resultSet = null; - try { - resultSet = vitessStatement - .executeQuery("SHOW INDEX FROM " + this.quotedId + table + this.quotedId + " " + - "FROM " + this.quotedId + catalog + this.quotedId); - - while (resultSet.next()) { - ArrayList row = new ArrayList<>(); - row.add(0, catalog); - row.add(1, null); - row.add(2, resultSet.getString("Table")); - - boolean indexIsUnique = resultSet.getInt("Non_unique") == 0; - - row.add(3, !indexIsUnique ? "true" : "false"); - row.add(4, ""); - row.add(5, resultSet.getString("Key_name")); - short indexType = DatabaseMetaData.tableIndexOther; - row.add(6, Integer.toString(indexType)); - row.add(7, resultSet.getString("Seq_in_index")); - row.add(8, resultSet.getString("Column_name")); - row.add(9, resultSet.getString("Collation")); - - long cardinality = resultSet.getLong("Cardinality"); - if (cardinality > Integer.MAX_VALUE) { - cardinality = Integer.MAX_VALUE; - } + } + } + return java.sql.DatabaseMetaData.importedKeyNoAction; + } + + /** + * Parses the cascade option string and returns the DBMD constant that represents it (for + * Updates) + * + * @param cascadeOptions the comment from 'SHOW TABLE STATUS' + * @return the DBMD constant that represents the cascade option + */ + private int getCascadeUpdateOption(String cascadeOptions) { + int onUpdatePos = cascadeOptions.indexOf("ON UPDATE"); + if (onUpdatePos != -1) { + String updateOptions = cascadeOptions.substring(onUpdatePos, cascadeOptions.length()); + if (updateOptions.startsWith("ON UPDATE CASCADE")) { + return java.sql.DatabaseMetaData.importedKeyCascade; + } else if (updateOptions.startsWith("ON UPDATE SET NULL")) { + return java.sql.DatabaseMetaData.importedKeySetNull; + } else if (updateOptions.startsWith("ON UPDATE RESTRICT")) { + return java.sql.DatabaseMetaData.importedKeyRestrict; + } else if (updateOptions.startsWith("ON UPDATE NO ACTION")) { + return java.sql.DatabaseMetaData.importedKeyNoAction; + } + } + return java.sql.DatabaseMetaData.importedKeyNoAction; + } + + public ResultSet getExportedKeys(String catalog, String schema, String table) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, + String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getTypeInfo() throws SQLException { + String[] columnNames = {"TYPE_NAME", "DATA_TYPE", "PRECISION", "LITERAL_PREFIX", + "LITERAL_SUFFIX", "CREATE_PARAMS", "NULLABLE", "CASE_SENSITIVE", "SEARCHABLE", + "UNSIGNED_ATTRIBUTE", "FIXED_PREC_SCALE", "AUTO_INCREMENT", "LOCAL_TYPE_NAME", + "MINIMUM_SCALE", "MAXIMUM_SCALE", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "NUM_PREC_RADIX"}; + Query.Type[] columnTypes = {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, + Query.Type.BIT, Query.Type.INT16, Query.Type.BIT, Query.Type.BIT, Query.Type.BIT, + Query.Type.VARCHAR, Query.Type.INT16, Query.Type.INT16, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32}; + + String[][] data = { + {"BIT", "-7", "1", "", "", "", "1", "true", "3", "false", "false", "false", "BIT", "0", "0", + "0", "0", "10"}, + {"BOOL", "-7", "1", "", "", "", "1", "true", "3", "false", "false", "false", "BOOL", "0", + "0", "0", "0", "10"}, + {"TINYINT", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "TINYINT", "0", "0", "0", "0", "10"}, + {"TINYINT UNSIGNED", "-6", "3", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", + "true", "false", "true", "TINYINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"BIGINT", "-5", "19", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "BIGINT", "0", "0", "0", "0", "10"}, + {"BIGINT UNSIGNED", "-5", "20", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "BIGINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"LONG VARBINARY", "-4", "16777215", "'", "'", "", "1", "true", "3", "false", "false", + "false", "LONG VARBINARY", "0", "0", "0", "0", "10"}, + {"MEDIUMBLOB", "-4", "16777215", "'", "'", "", "1", "true", "3", "false", "false", "false", + "MEDIUMBLOB", "0", "0", "0", "0", "10"}, + {"LONGBLOB", "-4", "2147483647", "'", "'", "", "1", "true", "3", "false", "false", "false", + "LONGBLOB", "0", "0", "0", "0", "10"}, + {"BLOB", "-4", "65535", "'", "'", "", "1", "true", "3", "false", "false", "false", "BLOB", + "0", "0", "0", "0", "10"}, + {"TINYBLOB", "-4", "255", "'", "'", "", "1", "true", "3", "false", "false", "false", + "TINYBLOB", "0", "0", "0", "0", "10"}, + {"VARBINARY", "-3", "65535", "'", "'", "(M)", "1", "true", "3", "false", "false", "false", + "VARBINARY", "0", "0", "0", "0", "10"}, + {"BINARY", "-2", "255", "'", "'", "(M)", "1", "true", "3", "false", "false", "false", + "BINARY", "0", "0", "0", "0", "10"}, + {"LONG VARCHAR", "-1", "16777215", "'", "'", "", "1", "false", "3", "false", "false", + "false", "LONG VARCHAR", "0", "0", "0", "0", "10"}, + {"MEDIUMTEXT", "-1", "16777215", "'", "'", "", "1", "false", "3", "false", "false", "false", + "MEDIUMTEXT", "0", "0", "0", "0", "10"}, + {"LONGTEXT", "-1", "2147483647", "'", "'", "", "1", "false", "3", "false", "false", "false", + "LONGTEXT", "0", "0", "0", "0", "10"}, + {"TEXT", "-1", "65535", "'", "'", "", "1", "false", "3", "false", "false", "false", "TEXT", + "0", "0", "0", "0", "10"}, + {"TINYTEXT", "-1", "255", "'", "'", "", "1", "false", "3", "false", "false", "false", + "TINYTEXT", "0", "0", "0", "0", "10"}, + {"CHAR", "1", "255", "'", "'", "(M)", "1", "false", "3", "false", "false", "false", "CHAR", + "0", "0", "0", "0", "10"}, + {"NUMERIC", "2", "65", "", "", "[(M[,D])] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "NUMERIC", "-308", "308", "0", "0", "10"}, + {"DECIMAL", "3", "65", "", "", "[(M[,D])] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "DECIMAL", "-308", "308", "0", "0", "10"}, + {"INTEGER", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "INTEGER", "0", "0", "0", "0", "10"}, + {"INTEGER UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "INTEGER UNSIGNED", "0", "0", "0", "0", "10"}, + {"INT", "4", "10", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "INT", "0", "0", "0", "0", "10"}, + {"INT UNSIGNED", "4", "10", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", "false", + "true", "INT UNSIGNED", "0", "0", "0", "0", "10"}, + {"MEDIUMINT", "4", "7", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "MEDIUMINT", "0", "0", "0", "0", "10"}, + {"MEDIUMINT UNSIGNED", "4", "8", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "MEDIUMINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"SMALLINT", "5", "5", "", "", "[(M)] [UNSIGNED] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "SMALLINT", "0", "0", "0", "0", "10"}, + {"SMALLINT UNSIGNED", "5", "5", "", "", "[(M)] [ZEROFILL]", "1", "false", "3", "true", + "false", "true", "SMALLINT UNSIGNED", "0", "0", "0", "0", "10"}, + {"FLOAT", "7", "10", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "FLOAT", "-38", "38", "0", "0", "10"}, + {"DOUBLE", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "DOUBLE", "-308", "308", "0", "0", "10"}, + {"DOUBLE PRECISION", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", + "false", "true", "DOUBLE PRECISION", "-308", "308", "0", "0", "10"}, + {"REAL", "8", "17", "", "", "[(M,D)] [ZEROFILL]", "1", "false", "3", "false", "false", + "true", "REAL", "-308", "308", "0", "0", "10"}, + {"VARCHAR", "12", "65535", "'", "'", "(M)", "1", "false", "3", "false", "false", "false", + "VARCHAR", "0", "0", "0", "0", "10"}, + {"ENUM", "12", "65535", "'", "'", "", "1", "false", "3", "false", "false", "false", "ENUM", + "0", "0", "0", "0", "10"}, + {"SET", "12", "64", "'", "'", "", "1", "false", "3", "false", "false", "false", "SET", "0", + "0", "0", "0", "10"}, + {"DATE", "91", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", "DATE", "0", + "0", "0", "0", "10"}, + {"TIME", "92", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", "TIME", "0", + "0", "0", "0", "10"}, + {"DATETIME", "93", "0", "'", "'", "", "1", "false", "3", "false", "false", "false", + "DATETIME", "0", "0", "0", "0", "10"}, + {"TIMESTAMP", "93", "0", "'", "'", "[(M)]", "1", "false", "3", "false", "false", "false", + "TIMESTAMP", "0", "0", "0", "0", "10"}}; + + return new VitessResultSet(columnNames, columnTypes, data, this.connection); + } + + @SuppressWarnings("StringBufferReplaceableByString") + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, + boolean approximate) throws SQLException { + + ArrayList> data = new ArrayList<>(); + final SortedMap> sortedRows = new TreeMap<>(); + VitessStatement vitessStatement = new VitessStatement(this.connection); + ResultSet resultSet = null; + try { + resultSet = vitessStatement.executeQuery( + "SHOW INDEX FROM " + this.quotedId + table + this.quotedId + " " + "FROM " + this.quotedId + + catalog + this.quotedId); + + while (resultSet.next()) { + ArrayList row = new ArrayList<>(); + row.add(0, catalog); + row.add(1, null); + row.add(2, resultSet.getString("Table")); + + boolean indexIsUnique = resultSet.getInt("Non_unique") == 0; + + row.add(3, !indexIsUnique ? "true" : "false"); + row.add(4, ""); + row.add(5, resultSet.getString("Key_name")); + short indexType = DatabaseMetaData.tableIndexOther; + row.add(6, Integer.toString(indexType)); + row.add(7, resultSet.getString("Seq_in_index")); + row.add(8, resultSet.getString("Column_name")); + row.add(9, resultSet.getString("Collation")); + + long cardinality = resultSet.getLong("Cardinality"); + if (cardinality > Integer.MAX_VALUE) { + cardinality = Integer.MAX_VALUE; + } - row.add(10, String.valueOf(cardinality)); - row.add(11, "0"); - row.add(12, null); + row.add(10, String.valueOf(cardinality)); + row.add(11, "0"); + row.add(12, null); - IndexMetaDataKey indexInfoKey = new IndexMetaDataKey(!indexIsUnique, indexType, - resultSet.getString("Key_name").toLowerCase(), - resultSet.getShort("Seq_in_index")); - sortedRows.put(indexInfoKey, row); - } + IndexMetaDataKey indexInfoKey = new IndexMetaDataKey(!indexIsUnique, indexType, + resultSet.getString("Key_name").toLowerCase(), resultSet.getShort("Seq_in_index")); + sortedRows.put(indexInfoKey, row); + } - for (ArrayList row : sortedRows.values()) { - data.add(row); - } + for (ArrayList row : sortedRows.values()) { + data.add(row); + } - } finally { - if (null != resultSet) { - resultSet.close(); - } - vitessStatement.close(); + } finally { + if (null != resultSet) { + resultSet.close(); + } + vitessStatement.close(); + } + String[] columnName = new String[]{"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "Non_unique", + "INDEX_QUALIFIER", "INDEX_NAME", "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", "ASC_OR_DESC", + "CARDINALITY", "PAGES", "FILTER_CONDITION"}; + + Query.Type[] columnType = new Query.Type[]{Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.BIT, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, Query.Type.INT16, + Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR}; + + return new VitessResultSet(columnName, columnType, data, this.connection); + } + + public boolean ownUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean ownInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersUpdatesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersDeletesAreVisible(int type) throws SQLException { + return false; + } + + public boolean othersInsertsAreVisible(int type) throws SQLException { + return false; + } + + public boolean updatesAreDetected(int type) throws SQLException { + return false; + } + + public boolean deletesAreDetected(int type) throws SQLException { + return false; + } + + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, + int[] types) throws SQLException { + String[] columnNames = {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "CLASS_NAME", "DATA_TYPE", + "REMARKS", "BASE_TYPE"}; + Query.Type[] columnType = {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, + Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, Query.Type.INT16}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) + throws SQLException { + String[] columnNames = {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SUPERTYPE_CAT", + "SUPERTYPE_SCHEM", "SUPERTYPE_NAME"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.CHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) + throws SQLException { + String[] columnNames = {"TABLE_CAT", "TYPE_SCHEM", "TABLE_NAME", "SUPERTABLE_NAME"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, + String attributeNamePattern) throws SQLException { + + String[] columnNames = {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "ATTR_NAME", "DATA_TYPE", + "ATTR_TYPE_NAME", "ATTR_SIZE", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", "REMARKS", + "ATTR_DEF", "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", + "ISNULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.INT16, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, + Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, + Query.Type.CHAR, Query.Type.INT16}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public int getSQLStateType() throws SQLException { + return DatabaseMetaData.sqlStateSQL99; + } + + public boolean locatorsUpdateCopy() throws SQLException { + return true; + } + + public RowIdLifetime getRowIdLifetime() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + String[] columnNames = {"TABLE_CAT", "TABLE_CATALOG"}; + Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getClientInfoProperties() throws SQLException { + String[] columnNames = {"NAME", "MAX_LEN", "DEFAULT_VALUE", "DESCRIPTION"}; + Query.Type[] columnType = {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, + Query.Type.VARCHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getFunctionColumns(String catalog, String schemaPattern, + String functionNamePattern, String columnNamePattern) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, + String columnNamePattern) throws SQLException { + String[] columnNames = {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", + "COLUMN_SIZE", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "COLUMN_USAGE", "REMARKS", + "CHAR_OCTET_LENGTH", "IS_NULLABLE"}; + Query.Type[] columnType = {Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, + Query.Type.VARCHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, + Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR}; + return new VitessResultSet(columnNames, columnType, new String[][]{}, this.connection); + } + + public T unwrap(Class iface) throws SQLException { + return null; + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + /** + * Enumeration for Table Types + */ + protected enum TableType {LOCAL_TEMPORARY("LOCAL TEMPORARY"), SYSTEM_TABLE( + "SYSTEM TABLE"), SYSTEM_VIEW("SYSTEM VIEW"), TABLE("TABLE", new String[]{"BASE TABLE"}), VIEW( + "VIEW"), UNKNOWN("UNKNOWN"); + + private String name; + private byte[] nameAsBytes; + private String[] synonyms; + + TableType(String tableTypeName) { + this(tableTypeName, null); + } + + TableType(String tableTypeName, String[] tableTypeSynonyms) { + this.name = tableTypeName; + this.nameAsBytes = tableTypeName.getBytes(); + this.synonyms = tableTypeSynonyms; + } + + static TableType getTableTypeEqualTo(String tableTypeName) { + for (TableType tableType : TableType.values()) { + if (tableType.equalsTo(tableTypeName)) { + return tableType; } - String[] columnName = - new String[] {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "Non_unique", "INDEX_QUALIFIER", - "INDEX_NAME", "TYPE", "ORDINAL_POSITION", "COLUMN_NAME", "ASC_OR_DESC", - "CARDINALITY", "PAGES", "FILTER_CONDITION"}; - - Query.Type[] columnType = - new Query.Type[] {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.BIT, - Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, Query.Type.INT16, - Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, - Query.Type.CHAR}; - - return new VitessResultSet(columnName, columnType, data, this.connection); + } + return UNKNOWN; } - public boolean ownUpdatesAreVisible(int type) throws SQLException { - return false; + static TableType getTableTypeCompliantWith(String tableTypeName) { + for (TableType tableType : TableType.values()) { + if (tableType.compliesWith(tableTypeName)) { + return tableType; + } + } + return UNKNOWN; } - public boolean ownDeletesAreVisible(int type) throws SQLException { - return false; + String getName() { + return this.name; } - public boolean ownInsertsAreVisible(int type) throws SQLException { - return false; + boolean equalsTo(String tableTypeName) { + return this.name.equalsIgnoreCase(tableTypeName); } - public boolean othersUpdatesAreVisible(int type) throws SQLException { + boolean compliesWith(String tableTypeName) { + if (equalsTo(tableTypeName)) { + return true; + } + if (null != this.synonyms) { + for (String synonym : this.synonyms) { + if (synonym.equalsIgnoreCase(tableTypeName)) { + return true; + } + } + } + return false; + }} + + + /** + * Helper class to provide means of comparing tables by TABLE_TYPE, TABLE_CAT, TABLE_SCHEM and + * TABLE_NAME. + */ + protected class TableMetaDataKey implements Comparable { + + String tableType; + String tableCat; + String tableSchem; + String tableName; + + TableMetaDataKey(String tableType, String tableCat, String tableSchem, String tableName) { + this.tableType = tableType == null ? "" : tableType; + this.tableCat = tableCat == null ? "" : tableCat; + this.tableSchem = tableSchem == null ? "" : tableSchem; + this.tableName = tableName == null ? "" : tableName; + } + + public int compareTo(TableMetaDataKey tablesKey) { + int compareResult; + + if ((compareResult = this.tableType.compareTo(tablesKey.tableType)) != 0) { + return compareResult; + } + if ((compareResult = this.tableCat.compareTo(tablesKey.tableCat)) != 0) { + return compareResult; + } + if ((compareResult = this.tableSchem.compareTo(tablesKey.tableSchem)) != 0) { + return compareResult; + } + return this.tableName.compareTo(tablesKey.tableName); + } + + @Override + public boolean equals(Object obj) { + if (null == obj) { return false; - } + } - public boolean othersDeletesAreVisible(int type) throws SQLException { - return false; - } + if (obj == this) { + return true; + } - public boolean othersInsertsAreVisible(int type) throws SQLException { - return false; + return obj instanceof TableMetaDataKey && compareTo((TableMetaDataKey) obj) == 0; } + } - public boolean updatesAreDetected(int type) throws SQLException { - return false; - } - public boolean deletesAreDetected(int type) throws SQLException { - return false; - } + /** + * Helper class to provide means of comparing indexes by Non_unique, TYPE, INDEX_NAME, and + * ORDINAL_POSITION. + */ + protected class IndexMetaDataKey implements Comparable { - public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, - int[] types) throws SQLException { - String[] columnNames = - {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "CLASS_NAME", "DATA_TYPE", "REMARKS", - "BASE_TYPE"}; - Query.Type[] columnType = - {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, Query.Type.VARCHAR, - Query.Type.INT32, Query.Type.VARCHAR, Query.Type.INT16}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } + Boolean columnNonUnique; + Short columnType; + String columnIndexName; + Short columnOrdinalPosition; - public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) - throws SQLException { - String[] columnNames = - {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "SUPERTYPE_CAT", "SUPERTYPE_SCHEM", - "SUPERTYPE_NAME"}; - Query.Type[] columnType = - {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, - Query.Type.CHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); + IndexMetaDataKey(boolean columnNonUnique, short columnType, String columnIndexName, + short columnOrdinalPosition) { + this.columnNonUnique = columnNonUnique; + this.columnType = columnType; + this.columnIndexName = columnIndexName; + this.columnOrdinalPosition = columnOrdinalPosition; } - public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) - throws SQLException { - String[] columnNames = {"TABLE_CAT", "TYPE_SCHEM", "TABLE_NAME", "SUPERTABLE_NAME"}; - Query.Type[] columnType = - {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } + public int compareTo(IndexMetaDataKey indexInfoKey) { + int compareResult; - public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, - String attributeNamePattern) throws SQLException { - - String[] columnNames = - {"TYPE_CAT", "TYPE_SCHEM", "TYPE_NAME", "ATTR_NAME", "DATA_TYPE", "ATTR_TYPE_NAME", - "ATTR_SIZE", "DECIMAL_DIGITS", "NUM_PREC_RADIX", "NULLABLE", "REMARKS", "ATTR_DEF", - "SQL_DATA_TYPE", "SQL_DATETIME_SUB", "CHAR_OCTET_LENGTH", "ORDINAL_POSITION", - "ISNULLABLE", "SCOPE_CATALOG", "SCOPE_SCHEMA", "SCOPE_TABLE", "SOURCE_DATA_TYPE"}; - Query.Type[] columnType = - {Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16, - Query.Type.CHAR, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, - Query.Type.INT32, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT32, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.CHAR, - Query.Type.CHAR, Query.Type.CHAR, Query.Type.CHAR, Query.Type.INT16}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); + if ((compareResult = this.columnNonUnique.compareTo(indexInfoKey.columnNonUnique)) != 0) { + return compareResult; + } + if ((compareResult = this.columnType.compareTo(indexInfoKey.columnType)) != 0) { + return compareResult; + } + if ((compareResult = this.columnIndexName.compareTo(indexInfoKey.columnIndexName)) != 0) { + return compareResult; + } + return this.columnOrdinalPosition.compareTo(indexInfoKey.columnOrdinalPosition); } - public int getSQLStateType() throws SQLException { - return DatabaseMetaData.sqlStateSQL99; - } + @Override + public boolean equals(Object obj) { + if (null == obj) { + return false; + } - public boolean locatorsUpdateCopy() throws SQLException { + if (obj == this) { return true; - } + } - public RowIdLifetime getRowIdLifetime() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + return obj instanceof IndexMetaDataKey && compareTo((IndexMetaDataKey) obj) == 0; } + } - public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { - String[] columnNames = {"TABLE_CAT", "TABLE_CATALOG"}; - Query.Type[] columnType = {Query.Type.CHAR, Query.Type.CHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } - public ResultSet getClientInfoProperties() throws SQLException { - String[] columnNames = {"NAME", "MAX_LEN", "DEFAULT_VALUE", "DESCRIPTION"}; - Query.Type[] columnType = - {Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR, Query.Type.VARCHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } + /** + * Parses and represents common data type information used by various column/parameter methods. + */ + class TypeDescriptor { - public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + int bufferLength; - public ResultSet getFunctionColumns(String catalog, String schemaPattern, - String functionNamePattern, String columnNamePattern) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + int charOctetLength; - public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, - String columnNamePattern) throws SQLException { - String[] columnNames = - {"TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", "COLUMN_SIZE", - "DECIMAL_DIGITS", "NUM_PREC_RADIX", "COLUMN_USAGE", "REMARKS", "CHAR_OCTET_LENGTH", - "IS_NULLABLE"}; - Query.Type[] columnType = - {Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.VARCHAR, - Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, Query.Type.INT32, - Query.Type.VARCHAR, Query.Type.VARCHAR, Query.Type.INT32, Query.Type.VARCHAR}; - return new VitessResultSet(columnNames, columnType, new String[][] {}, this.connection); - } + Integer columnSize; - public T unwrap(Class iface) throws SQLException { - return null; - } + short dataType; - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } + Integer decimalDigits; - /** - * Enumeration for Table Types - */ - protected enum TableType { - LOCAL_TEMPORARY("LOCAL TEMPORARY"), SYSTEM_TABLE("SYSTEM TABLE"), SYSTEM_VIEW( - "SYSTEM VIEW"), TABLE("TABLE", new String[] {"BASE TABLE"}), VIEW("VIEW"), UNKNOWN( - "UNKNOWN"); + String isNullable; - private String name; - private byte[] nameAsBytes; - private String[] synonyms; + int nullability; - TableType(String tableTypeName) { - this(tableTypeName, null); - } + int numPrecRadix = 10; - TableType(String tableTypeName, String[] tableTypeSynonyms) { - this.name = tableTypeName; - this.nameAsBytes = tableTypeName.getBytes(); - this.synonyms = tableTypeSynonyms; - } + String typeName; - static TableType getTableTypeEqualTo(String tableTypeName) { - for (TableType tableType : TableType.values()) { - if (tableType.equalsTo(tableTypeName)) { - return tableType; - } - } - return UNKNOWN; - } + TypeDescriptor(String typeInfo, String nullabilityInfo) throws SQLException { + if (typeInfo == null) { + throw new SQLException("NULL typeinfo not supported."); + } - static TableType getTableTypeCompliantWith(String tableTypeName) { - for (TableType tableType : TableType.values()) { - if (tableType.compliesWith(tableTypeName)) { - return tableType; - } - } - return UNKNOWN; - } + String mysqlType; + String fullMysqlType; - String getName() { - return this.name; - } + if (typeInfo.indexOf("(") != -1) { + mysqlType = typeInfo.substring(0, typeInfo.indexOf("(")).trim(); + } else { + mysqlType = typeInfo; + } - boolean equalsTo(String tableTypeName) { - return this.name.equalsIgnoreCase(tableTypeName); - } + int indexOfUnsignedInMysqlType = StringUtils.indexOfIgnoreCase(mysqlType, "unsigned"); - boolean compliesWith(String tableTypeName) { - if (equalsTo(tableTypeName)) { - return true; - } - if (null != this.synonyms) { - for (String synonym : this.synonyms) { - if (synonym.equalsIgnoreCase(tableTypeName)) { - return true; - } - } - } - return false; - } - } + if (indexOfUnsignedInMysqlType != -1) { + mysqlType = mysqlType.substring(0, (indexOfUnsignedInMysqlType - 1)); + } + // Add unsigned to typename reported to enduser as 'native type', if present - /** - * Helper class to provide means of comparing tables by TABLE_TYPE, TABLE_CAT, TABLE_SCHEM and TABLE_NAME. - */ - protected class TableMetaDataKey implements Comparable { - String tableType; - String tableCat; - String tableSchem; - String tableName; - - TableMetaDataKey(String tableType, String tableCat, String tableSchem, String tableName) { - this.tableType = tableType == null ? "" : tableType; - this.tableCat = tableCat == null ? "" : tableCat; - this.tableSchem = tableSchem == null ? "" : tableSchem; - this.tableName = tableName == null ? "" : tableName; - } + boolean isUnsigned = false; - public int compareTo(TableMetaDataKey tablesKey) { - int compareResult; + if ((StringUtils.indexOfIgnoreCase(typeInfo, "unsigned") != -1) && ( + StringUtils.indexOfIgnoreCase(typeInfo, "set") != 0) && ( + StringUtils.indexOfIgnoreCase(typeInfo, "enum") != 0)) { + fullMysqlType = mysqlType + " unsigned"; + isUnsigned = true; + } else { + fullMysqlType = mysqlType; + } + fullMysqlType = fullMysqlType.toUpperCase(Locale.ENGLISH); - if ((compareResult = this.tableType.compareTo(tablesKey.tableType)) != 0) { - return compareResult; - } - if ((compareResult = this.tableCat.compareTo(tablesKey.tableCat)) != 0) { - return compareResult; - } - if ((compareResult = this.tableSchem.compareTo(tablesKey.tableSchem)) != 0) { - return compareResult; - } - return this.tableName.compareTo(tablesKey.tableName); - } - - @Override public boolean equals(Object obj) { - if (null == obj) { - return false; - } - - if (obj == this) { - return true; - } - - return obj instanceof TableMetaDataKey && compareTo((TableMetaDataKey) obj) == 0; - } - } + this.dataType = (short) MysqlDefs.mysqlToJavaType(mysqlType); + this.typeName = fullMysqlType; - /** - * Helper class to provide means of comparing indexes by Non_unique, TYPE, INDEX_NAME, and ORDINAL_POSITION. - */ - protected class IndexMetaDataKey implements Comparable { - Boolean columnNonUnique; - Short columnType; - String columnIndexName; - Short columnOrdinalPosition; - - IndexMetaDataKey(boolean columnNonUnique, short columnType, String columnIndexName, - short columnOrdinalPosition) { - this.columnNonUnique = columnNonUnique; - this.columnType = columnType; - this.columnIndexName = columnIndexName; - this.columnOrdinalPosition = columnOrdinalPosition; - } + // Figure Out the Size - public int compareTo(IndexMetaDataKey indexInfoKey) { - int compareResult; + if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) { + String temp = typeInfo.substring(typeInfo.indexOf("("), typeInfo.lastIndexOf(")")); + StringTokenizer tokenizer = new StringTokenizer(temp, ","); + int maxLength = 0; - if ((compareResult = this.columnNonUnique.compareTo(indexInfoKey.columnNonUnique)) - != 0) { - return compareResult; - } - if ((compareResult = this.columnType.compareTo(indexInfoKey.columnType)) != 0) { - return compareResult; - } - if ((compareResult = this.columnIndexName.compareTo(indexInfoKey.columnIndexName)) - != 0) { - return compareResult; - } - return this.columnOrdinalPosition.compareTo(indexInfoKey.columnOrdinalPosition); + while (tokenizer.hasMoreTokens()) { + maxLength = Math.max(maxLength, (tokenizer.nextToken().length() - 2)); } - @Override public boolean equals(Object obj) { - if (null == obj) { - return false; - } + this.columnSize = maxLength; + this.decimalDigits = null; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "set")) { + String temp = typeInfo.substring(typeInfo.indexOf("(") + 1, typeInfo.lastIndexOf(")")); + StringTokenizer tokenizer = new StringTokenizer(temp, ","); + int maxLength = 0; - if (obj == this) { - return true; - } + int numElements = tokenizer.countTokens(); - return obj instanceof IndexMetaDataKey && compareTo((IndexMetaDataKey) obj) == 0; + if (numElements > 0) { + maxLength += (numElements - 1); } - } - - - /** - * Parses and represents common data type information used by various - * column/parameter methods. - */ - class TypeDescriptor { - int bufferLength; - int charOctetLength; + while (tokenizer.hasMoreTokens()) { + String setMember = tokenizer.nextToken().trim(); - Integer columnSize; - - short dataType; - - Integer decimalDigits; - - String isNullable; - - int nullability; - - int numPrecRadix = 10; - - String typeName; - - TypeDescriptor(String typeInfo, String nullabilityInfo) throws SQLException { - if (typeInfo == null) { - throw new SQLException("NULL typeinfo not supported."); - } - - String mysqlType; - String fullMysqlType; - - if (typeInfo.indexOf("(") != -1) { - mysqlType = typeInfo.substring(0, typeInfo.indexOf("(")).trim(); - } else { - mysqlType = typeInfo; - } - - int indexOfUnsignedInMysqlType = StringUtils.indexOfIgnoreCase(mysqlType, "unsigned"); - - if (indexOfUnsignedInMysqlType != -1) { - mysqlType = mysqlType.substring(0, (indexOfUnsignedInMysqlType - 1)); - } - - // Add unsigned to typename reported to enduser as 'native type', if present - - boolean isUnsigned = false; - - if ((StringUtils.indexOfIgnoreCase(typeInfo, "unsigned") != -1) && ( - StringUtils.indexOfIgnoreCase(typeInfo, "set") != 0) && ( - StringUtils.indexOfIgnoreCase(typeInfo, "enum") != 0)) { - fullMysqlType = mysqlType + " unsigned"; - isUnsigned = true; - } else { - fullMysqlType = mysqlType; - } - fullMysqlType = fullMysqlType.toUpperCase(Locale.ENGLISH); - - this.dataType = (short) MysqlDefs.mysqlToJavaType(mysqlType); - - this.typeName = fullMysqlType; - - // Figure Out the Size - - if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) { - String temp = typeInfo.substring(typeInfo.indexOf("("), typeInfo.lastIndexOf(")")); - StringTokenizer tokenizer = new StringTokenizer(temp, ","); - int maxLength = 0; - - while (tokenizer.hasMoreTokens()) { - maxLength = Math.max(maxLength, (tokenizer.nextToken().length() - 2)); - } - - this.columnSize = maxLength; - this.decimalDigits = null; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "set")) { - String temp = - typeInfo.substring(typeInfo.indexOf("(") + 1, typeInfo.lastIndexOf(")")); - StringTokenizer tokenizer = new StringTokenizer(temp, ","); - int maxLength = 0; - - int numElements = tokenizer.countTokens(); - - if (numElements > 0) { - maxLength += (numElements - 1); - } - - while (tokenizer.hasMoreTokens()) { - String setMember = tokenizer.nextToken().trim(); - - if (setMember.startsWith(Constants.LITERAL_SINGLE_QUOTE) && setMember - .endsWith(Constants.LITERAL_SINGLE_QUOTE)) { - maxLength += setMember.length() - 2; - } else { - maxLength += setMember.length(); - } - } + if (setMember.startsWith(Constants.LITERAL_SINGLE_QUOTE) && setMember + .endsWith(Constants.LITERAL_SINGLE_QUOTE)) { + maxLength += setMember.length() - 2; + } else { + maxLength += setMember.length(); + } + } - this.columnSize = maxLength; - this.decimalDigits = null; - } else if (typeInfo.indexOf(",") != -1) { - // Numeric with decimals - this.columnSize = Integer.valueOf( - typeInfo.substring((typeInfo.indexOf("(") + 1), (typeInfo.indexOf(","))) - .trim()); - this.decimalDigits = Integer.valueOf( - typeInfo.substring((typeInfo.indexOf(",") + 1), (typeInfo.indexOf(")"))) - .trim()); - } else { - this.columnSize = null; - this.decimalDigits = null; - - /* If the size is specified with the DDL, use that */ - if ((StringUtils.indexOfIgnoreCase(typeInfo, "char") != -1 - || StringUtils.indexOfIgnoreCase(typeInfo, "text") != -1 - || StringUtils.indexOfIgnoreCase(typeInfo, "blob") != -1 - || StringUtils.indexOfIgnoreCase(typeInfo, "binary") != -1 - || StringUtils.indexOfIgnoreCase(typeInfo, "bit") != -1) - && typeInfo.indexOf("(") != -1) { - int endParenIndex = typeInfo.indexOf(")"); - - if (endParenIndex == -1) { - endParenIndex = typeInfo.length(); - } - - this.columnSize = Integer.valueOf( - typeInfo.substring((typeInfo.indexOf("(") + 1), endParenIndex).trim()); - - // Adjust for pseudo-boolean - if (this.columnSize == 1 && StringUtils - .startsWithIgnoreCase(typeInfo, "tinyint")) { - this.dataType = Types.BIT; - this.typeName = "BIT"; - } - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinyint")) { - if (typeInfo.indexOf("(1)") != -1) { - this.dataType = Types.BIT; - this.typeName = "BIT"; - - } else { - this.columnSize = 3; - this.decimalDigits = 0; - } - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "smallint")) { - this.columnSize = 5; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumint")) { - this.columnSize = isUnsigned ? 8 : 7; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "int")) { - this.columnSize = 10; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "integer")) { - this.columnSize = 10; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "bigint")) { - this.dataType = Types.BIGINT; - this.columnSize = isUnsigned ? 20 : 19; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "int24")) { - this.columnSize = 19; - this.decimalDigits = 0; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "real")) { - this.columnSize = 12; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "float")) { - this.columnSize = 12; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "decimal")) { - this.columnSize = 12; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "numeric")) { - this.columnSize = 12; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "double")) { - this.columnSize = 22; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "char")) { - this.columnSize = 1; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "varchar")) { - this.columnSize = 255; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "timestamp")) { - this.columnSize = 19; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "datetime")) { - this.columnSize = 19; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "date")) { - this.columnSize = 10; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "time")) { - this.columnSize = 8; - - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinyblob")) { - this.columnSize = 255; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "blob")) { - this.columnSize = 65535; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumblob")) { - this.columnSize = 16777215; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "longblob")) { - this.columnSize = Integer.MAX_VALUE; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinytext")) { - this.columnSize = 255; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "text")) { - this.columnSize = 65535; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumtext")) { - this.columnSize = 16777215; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "longtext")) { - this.columnSize = Integer.MAX_VALUE; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) { - this.columnSize = 255; - } else if (StringUtils.startsWithIgnoreCase(typeInfo, "set")) { - this.columnSize = 255; - } + this.columnSize = maxLength; + this.decimalDigits = null; + } else if (typeInfo.indexOf(",") != -1) { + // Numeric with decimals + this.columnSize = Integer.valueOf( + typeInfo.substring((typeInfo.indexOf("(") + 1), (typeInfo.indexOf(","))).trim()); + this.decimalDigits = Integer.valueOf( + typeInfo.substring((typeInfo.indexOf(",") + 1), (typeInfo.indexOf(")"))).trim()); + } else { + this.columnSize = null; + this.decimalDigits = null; + + /* If the size is specified with the DDL, use that */ + if ((StringUtils.indexOfIgnoreCase(typeInfo, "char") != -1 + || StringUtils.indexOfIgnoreCase(typeInfo, "text") != -1 + || StringUtils.indexOfIgnoreCase(typeInfo, "blob") != -1 + || StringUtils.indexOfIgnoreCase(typeInfo, "binary") != -1 + || StringUtils.indexOfIgnoreCase(typeInfo, "bit") != -1) + && typeInfo.indexOf("(") != -1) { + int endParenIndex = typeInfo.indexOf(")"); + + if (endParenIndex == -1) { + endParenIndex = typeInfo.length(); + } + + this.columnSize = Integer + .valueOf(typeInfo.substring((typeInfo.indexOf("(") + 1), endParenIndex).trim()); + + // Adjust for pseudo-boolean + if (this.columnSize == 1 && StringUtils.startsWithIgnoreCase(typeInfo, "tinyint")) { + this.dataType = Types.BIT; + this.typeName = "BIT"; + } + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinyint")) { + if (typeInfo.indexOf("(1)") != -1) { + this.dataType = Types.BIT; + this.typeName = "BIT"; + + } else { + this.columnSize = 3; + this.decimalDigits = 0; + } + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "smallint")) { + this.columnSize = 5; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumint")) { + this.columnSize = isUnsigned ? 8 : 7; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "int")) { + this.columnSize = 10; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "integer")) { + this.columnSize = 10; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "bigint")) { + this.dataType = Types.BIGINT; + this.columnSize = isUnsigned ? 20 : 19; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "int24")) { + this.columnSize = 19; + this.decimalDigits = 0; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "real")) { + this.columnSize = 12; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "float")) { + this.columnSize = 12; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "decimal")) { + this.columnSize = 12; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "numeric")) { + this.columnSize = 12; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "double")) { + this.columnSize = 22; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "char")) { + this.columnSize = 1; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "varchar")) { + this.columnSize = 255; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "timestamp")) { + this.columnSize = 19; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "datetime")) { + this.columnSize = 19; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "date")) { + this.columnSize = 10; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "time")) { + this.columnSize = 8; + + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinyblob")) { + this.columnSize = 255; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "blob")) { + this.columnSize = 65535; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumblob")) { + this.columnSize = 16777215; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "longblob")) { + this.columnSize = Integer.MAX_VALUE; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "tinytext")) { + this.columnSize = 255; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "text")) { + this.columnSize = 65535; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "mediumtext")) { + this.columnSize = 16777215; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "longtext")) { + this.columnSize = Integer.MAX_VALUE; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "enum")) { + this.columnSize = 255; + } else if (StringUtils.startsWithIgnoreCase(typeInfo, "set")) { + this.columnSize = 255; + } - } - this.bufferLength = 65535; - this.numPrecRadix = 10; - - if (nullabilityInfo != null) { - switch (nullabilityInfo) { - case "YES": - this.nullability = DatabaseMetaData.columnNullable; - this.isNullable = "YES"; - - break; - case "UNKNOWN": - this.nullability = DatabaseMetaData.columnNullableUnknown; - this.isNullable = ""; - break; - default: - this.nullability = DatabaseMetaData.columnNoNulls; - this.isNullable = "NO"; - break; - } - } else { - this.nullability = DatabaseMetaData.columnNoNulls; - this.isNullable = "NO"; - } + } + this.bufferLength = 65535; + this.numPrecRadix = 10; + + if (nullabilityInfo != null) { + switch (nullabilityInfo) { + case "YES": + this.nullability = DatabaseMetaData.columnNullable; + this.isNullable = "YES"; + + break; + case "UNKNOWN": + this.nullability = DatabaseMetaData.columnNullableUnknown; + this.isNullable = ""; + break; + default: + this.nullability = DatabaseMetaData.columnNoNulls; + this.isNullable = "NO"; + break; } + } else { + this.nullability = DatabaseMetaData.columnNoNulls; + this.isNullable = "NO"; + } } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessParameterMetaData.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessParameterMetaData.java index 48cdecf4640..d6c2b2a1340 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessParameterMetaData.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessParameterMetaData.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -22,86 +22,85 @@ public class VitessParameterMetaData implements ParameterMetaData { - private final int parameterCount; - - /** - * This implementation (and defaults below) is equivalent to - * mysql-connector-java's "simple" (non-server) - * statement metadata - */ - VitessParameterMetaData(int count) { - this.parameterCount = count; - } - - @Override - public int getParameterCount() throws SQLException { - return parameterCount; - } - - @Override - public int isNullable(int param) throws SQLException { - throw new SQLException("Parameter metadata not available for the given statement"); - } - - @Override - public boolean isSigned(int param) throws SQLException { - checkBounds(param); - return false; - } - - @Override - public int getPrecision(int param) throws SQLException { - checkBounds(param); - return 0; - } - - @Override - public int getScale(int param) throws SQLException { - checkBounds(param); - return 0; + private final int parameterCount; + + /** + * This implementation (and defaults below) is equivalent to mysql-connector-java's "simple" + * (non-server) statement metadata + */ + VitessParameterMetaData(int count) { + this.parameterCount = count; + } + + @Override + public int getParameterCount() throws SQLException { + return parameterCount; + } + + @Override + public int isNullable(int param) throws SQLException { + throw new SQLException("Parameter metadata not available for the given statement"); + } + + @Override + public boolean isSigned(int param) throws SQLException { + checkBounds(param); + return false; + } + + @Override + public int getPrecision(int param) throws SQLException { + checkBounds(param); + return 0; + } + + @Override + public int getScale(int param) throws SQLException { + checkBounds(param); + return 0; + } + + @Override + public int getParameterType(int param) throws SQLException { + checkBounds(param); + return Types.VARCHAR; + } + + @Override + public String getParameterTypeName(int param) throws SQLException { + checkBounds(param); + return "VARCHAR"; + } + + @Override + public String getParameterClassName(int param) throws SQLException { + checkBounds(param); + return "java.lang.String"; + } + + @Override + public int getParameterMode(int param) throws SQLException { + return ParameterMetaData.parameterModeIn; + } + + private void checkBounds(int paramNumber) throws SQLException { + if (paramNumber < 1) { + throw new SQLException("Parameter index of '" + paramNumber + "' is invalid."); } - @Override - public int getParameterType(int param) throws SQLException { - checkBounds(param); - return Types.VARCHAR; + if (paramNumber > this.parameterCount) { + throw new SQLException("Parameter index of '" + paramNumber + + "' is greater than number of parameters, which is '" + this.parameterCount + "'."); } + } - @Override - public String getParameterTypeName(int param) throws SQLException { - checkBounds(param); - return "VARCHAR"; - } - - @Override - public String getParameterClassName(int param) throws SQLException { - checkBounds(param); - return "java.lang.String"; - } - - @Override - public int getParameterMode(int param) throws SQLException { - return ParameterMetaData.parameterModeIn; - } - - private void checkBounds(int paramNumber) throws SQLException { - if (paramNumber < 1) { - throw new SQLException("Parameter index of '" + paramNumber + "' is invalid."); - } + @Override + public T unwrap(Class iface) throws SQLException { + return null; + } - if (paramNumber > this.parameterCount) { - throw new SQLException( - "Parameter index of '" + paramNumber + "' is greater than number of parameters, which is '" + this.parameterCount + "'."); - } - } - - @Override - public T unwrap(Class iface) throws SQLException { - return null; - } - - @Override - public boolean isWrapperFor(Class iface) throws SQLException { - return false; - } + @Override + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java index d53d7c86ceb..eef8b6f2078 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -60,842 +60,832 @@ /** * Created by harshit.gangal on 25/01/16. *

- * This class expected for an sql query and a given set of parameters - * the DB Call can be made once with any of the following method - * execute, executeQuery, executeUpdate and executeBatch. - * After the call, the parameters will be reset - * and a new set of parameters needs to be provided before calling any of the above method. + * This class expected for an sql query and a given set of parameters the DB Call can be made once + * with any of the following method execute, executeQuery, executeUpdate and executeBatch. After the + * call, the parameters will be reset and a new set of parameters needs to be provided before + * calling any of the above method. */ public class VitessPreparedStatement extends VitessStatement implements PreparedStatement { - /* Get actual class name to be printed on */ - private final String sql; - private final Map bindVariables; - /** - * Holds batched commands - */ - private final List> batchedArgs; - private VitessParameterMetaData parameterMetadata; - - public VitessPreparedStatement(VitessConnection vitessConnection, String sql) - throws SQLException { - this(vitessConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - } - - public VitessPreparedStatement(VitessConnection vitessConnection, String sql, int resultSetType, - int resultSetConcurrency) throws SQLException { - this(vitessConnection, sql, resultSetType, resultSetConcurrency, - Statement.NO_GENERATED_KEYS); - } - - public VitessPreparedStatement(VitessConnection vitessConnection, String sql, - int autoGeneratedKeys) throws SQLException { - this(vitessConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - autoGeneratedKeys); - } - - public VitessPreparedStatement(VitessConnection vitessConnection, String sql, int resultSetType, - int resultSetConcurrency, int autoGeneratedKeys) throws SQLException { - super(vitessConnection, resultSetType, resultSetConcurrency); - checkSQLNullOrEmpty(sql); - this.bindVariables = new HashMap<>(); - this.sql = sql; - this.generatedId = -1; - this.retrieveGeneratedKeys = (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS); - this.batchedArgs = new ArrayList<>(); - } - - public ResultSet executeQuery() throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - - checkOpen(); - closeOpenResultSetAndResetCount(); - - //Setting to default value - this.generatedId = -1; - - vtGateConn = this.vitessConnection.getVtGateConn(); - - try { - if (vitessConnection.isSimpleExecute() && this.fetchSize == 0) { - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()).checkedGet(); - } else { - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.streamExecute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()); + /* Get actual class name to be printed on */ + private final String sql; + private final Map bindVariables; + /** + * Holds batched commands + */ + private final List> batchedArgs; + private VitessParameterMetaData parameterMetadata; + + public VitessPreparedStatement(VitessConnection vitessConnection, String sql) + throws SQLException { + this(vitessConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + } + + public VitessPreparedStatement(VitessConnection vitessConnection, String sql, int resultSetType, + int resultSetConcurrency) throws SQLException { + this(vitessConnection, sql, resultSetType, resultSetConcurrency, Statement.NO_GENERATED_KEYS); + } + + public VitessPreparedStatement(VitessConnection vitessConnection, String sql, + int autoGeneratedKeys) throws SQLException { + this(vitessConnection, sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + autoGeneratedKeys); + } + + public VitessPreparedStatement(VitessConnection vitessConnection, String sql, int resultSetType, + int resultSetConcurrency, int autoGeneratedKeys) throws SQLException { + super(vitessConnection, resultSetType, resultSetConcurrency); + checkSQLNullOrEmpty(sql); + this.bindVariables = new HashMap<>(); + this.sql = sql; + this.generatedId = -1; + this.retrieveGeneratedKeys = (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS); + this.batchedArgs = new ArrayList<>(); + } + + public ResultSet executeQuery() throws SQLException { + VTGateConnection vtGateConn; + Cursor cursor; + + checkOpen(); + closeOpenResultSetAndResetCount(); + + //Setting to default value + this.generatedId = -1; + + vtGateConn = this.vitessConnection.getVtGateConn(); + + try { + if (vitessConnection.isSimpleExecute() && this.fetchSize == 0) { + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn + .execute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()) + .checkedGet(); + } else { + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn + .streamExecute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()); + } + + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + this.vitessResultSet = new VitessResultSet(cursor, this); + } finally { + this.bindVariables.clear(); + } + return this.vitessResultSet; + } + + public int executeUpdate() throws SQLException { + VTGateConnection vtGateConn; + Cursor cursor; + int truncatedUpdateCount; + + checkOpen(); + checkNotReadOnly(); + closeOpenResultSetAndResetCount(); + + vtGateConn = this.vitessConnection.getVtGateConn(); + + try { + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn + .execute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()) + .checkedGet(); + + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + if (!(null == cursor.getFields() || cursor.getFields().isEmpty())) { + throw new SQLException(Constants.SQLExceptionMessages.SQL_RETURNED_RESULT_SET); + } + + if (this.retrieveGeneratedKeys) { + this.generatedId = cursor.getInsertId(); + } + + this.resultCount = cursor.getRowsAffected(); + + if (this.resultCount > Integer.MAX_VALUE) { + truncatedUpdateCount = Integer.MAX_VALUE; + } else { + truncatedUpdateCount = (int) this.resultCount; + } + } finally { + this.bindVariables.clear(); + } + return truncatedUpdateCount; + } + + public boolean execute() throws SQLException { + checkOpen(); + closeOpenResultSetAndResetCount(); + + if (!maybeSelect(this.sql)) { + this.executeUpdate(); + return false; + } else { + this.executeQuery(); + return true; + } + } + + public void clearParameters() throws SQLException { + checkOpen(); + this.bindVariables.clear(); + } + + public void setNull(int parameterIndex, int sqlType) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, null); + } + + public void setBoolean(int parameterIndex, boolean x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setByte(int parameterIndex, byte x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setShort(int parameterIndex, short x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setInt(int parameterIndex, int x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setLong(int parameterIndex, long x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setFloat(int parameterIndex, float x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setDouble(int parameterIndex, double x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setBigInteger(int parameterIndex, BigInteger x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setString(int parameterIndex, String x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setBytes(int parameterIndex, byte[] x) throws SQLException { + checkOpen(); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + } + + public void setDate(int parameterIndex, Date x) throws SQLException { + checkOpen(); + String date = DateTime.formatDate(x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); + } + + public void setTime(int parameterIndex, Time x) throws SQLException { + checkOpen(); + String time = DateTime.formatTime(x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); + } + + public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + checkOpen(); + String timeStamp = DateTime.formatTimestamp(x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); + } + + public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + checkOpen(); + String date = DateTime.formatDate(x, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); + } + + public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + checkOpen(); + String time = DateTime.formatTime(x, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); + } + + public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + checkOpen(); + String timeStamp = DateTime.formatTimestamp(x, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); + } + + public void setObject(int parameterIndex, Object x) throws SQLException { + if (x == null) { + setNull(parameterIndex, Types.NULL); + } else if (x instanceof String) { + setString(parameterIndex, (String) x); + } else if (x instanceof Short) { + setShort(parameterIndex, (Short) x); + } else if (x instanceof Integer) { + setInt(parameterIndex, (Integer) x); + } else if (x instanceof Long) { + setLong(parameterIndex, (Long) x); + } else if (x instanceof Float) { + setFloat(parameterIndex, (Float) x); + } else if (x instanceof Double) { + setDouble(parameterIndex, (Double) x); + } else if (x instanceof Boolean) { + setBoolean(parameterIndex, (Boolean) x); + } else if (x instanceof Byte) { + setByte(parameterIndex, (Byte) x); + } else if (x instanceof Character) { + setString(parameterIndex, String.valueOf(x)); + } else if (x instanceof Date) { + setDate(parameterIndex, (Date) x); + } else if (x instanceof Time) { + setTime(parameterIndex, (Time) x); + } else if (x instanceof Timestamp) { + setTimestamp(parameterIndex, (Timestamp) x); + } else if (x instanceof BigDecimal) { + setBigDecimal(parameterIndex, (BigDecimal) x); + } else if (x instanceof BigInteger) { + setBigInteger(parameterIndex, (BigInteger) x); + } else if (x instanceof byte[]) { + setBytes(parameterIndex, (byte[]) x); + } else if (getConnection().getTreatUtilDateAsTimestamp() && x instanceof java.util.Date) { + setTimestamp(parameterIndex, new Timestamp(((java.util.Date) x).getTime())); + } else { + throw new SQLException( + Constants.SQLExceptionMessages.SQL_TYPE_INFER + x.getClass().getCanonicalName()); + } + } + + /** + * Add bindVariables to the batch and clear it to have new set of bindVariables. + */ + public void addBatch() throws SQLException { + checkOpen(); + this.batchedArgs.add(new HashMap<>(this.bindVariables)); + this.bindVariables.clear(); + } + + /** + * Clear all the batched bindVariables. + */ + @Override + public void clearBatch() throws SQLException { + checkOpen(); + this.batchedArgs.clear(); + } + + /** + * Submits a batch of commands to the database for execution and if all commands execute + * successfully, returns an array of update counts. The array returned is according to the order + * in which they were added to the batch. + *

+ * If one of the commands in a batch update fails to execute properly, this method throws a + * BatchUpdateException, and a JDBC driver may or may not continue to process the + * remaining commands in the batch. If the driver continues processing after a failure, the array + * returned by the method BatchUpdateException.getUpdateCounts will contain as many + * elements as there are commands in the batch. + * + * @return int[] of results corresponding to each command + */ + @Override + public int[] executeBatch() throws SQLException { + checkOpen(); + // An executeBatch can't contain SELECT statements as defined by the documentation: + // https://docs.oracle.com/javase/tutorial/jdbc/basics/retrieving.html + // "This list may contain statements for updating, inserting, or deleting a row; and it may + // also contain DDL statements such as CREATE TABLE and DROP TABLE. It cannot, however, + // contain a statement that would produce a ResultSet object, such as a SELECT statement. + // In other words, the list can contain only statements that produce an update count." + checkNotReadOnly(); + + VTGateConnection vtGateConn; + List cursorWithErrorList; + List batchedQueries = new ArrayList<>(); + + if (0 == batchedArgs.size()) { + return new int[0]; + } + + try { + vtGateConn = this.vitessConnection.getVtGateConn(); + + this.retrieveGeneratedKeys = true; // mimicking mysql-connector-j + /* + * Current api does not support single query and multiple bindVariables list. + * So, List of the query is created to match the bindVariables list. + */ + for (int i = 0; i < batchedArgs.size(); ++i) { + batchedQueries.add(this.sql); + } + + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursorWithErrorList = vtGateConn + .executeBatch(context, batchedQueries, batchedArgs, vitessConnection.getVtSession()) + .checkedGet(); + + if (null == cursorWithErrorList) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + return this.generateBatchUpdateResult(cursorWithErrorList, batchedQueries); + } finally { + this.clearBatch(); + } + + + } + + //Methods which are currently not supported + + public ParameterMetaData getParameterMetaData() throws SQLException { + checkOpen(); + if (this.parameterMetadata == null) { + this.parameterMetadata = new VitessParameterMetaData(calculateParameterCount()); + } + + return this.parameterMetadata; + } + + /** + * This function was ported from mysql-connector-java ParseInfo object and greatly simplified to + * just the parts for counting parameters + */ + private int calculateParameterCount() throws SQLException { + if (sql == null) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + ": sql null"); + } + + char quotedIdentifierChar = '`'; + char currentQuoteChar = 0; + boolean inQuotes = false; + boolean inQuotedId = false; + int statementCount = 0; + int statementLength = sql.length(); + int statementStartPos = StringUtils.findStartOfStatement(sql); + + for (int i = statementStartPos; i < statementLength; ++i) { + char c = sql.charAt(i); + + if (c == '\\' && i < (statementLength - 1)) { + i++; + continue; // next character is escaped + } + + // are we in a quoted identifier? (only valid when the id is not inside a 'string') + if (!inQuotes && c == quotedIdentifierChar) { + inQuotedId = !inQuotedId; + } else if (!inQuotedId) { + // only respect quotes when not in a quoted identifier + if (inQuotes) { + if (((c == '\'') || (c == '"')) && c == currentQuoteChar) { + if (i < (statementLength - 1) && sql.charAt(i + 1) == currentQuoteChar) { + i++; + continue; // inline quote escape } - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } + inQuotes = !inQuotes; + currentQuoteChar = 0; + } + } else { + if (c == '#' || (c == '-' && (i + 1) < statementLength && sql.charAt(i + 1) == '-')) { + // comment, run out to end of statement, or newline, whichever comes first + int endOfStmt = statementLength - 1; - this.vitessResultSet = new VitessResultSet(cursor, this); - } finally { - this.bindVariables.clear(); - } - return this.vitessResultSet; - } + for (; i < endOfStmt; i++) { + c = sql.charAt(i); - public int executeUpdate() throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - int truncatedUpdateCount; + if (c == '\r' || c == '\n') { + break; + } + } - checkOpen(); - checkNotReadOnly(); - closeOpenResultSetAndResetCount(); + continue; + } else if (c == '/' && (i + 1) < statementLength) { + // Comment? + char cNext = sql.charAt(i + 1); + if (cNext == '*') { + i += 2; - vtGateConn = this.vitessConnection.getVtGateConn(); + for (int j = i; j < statementLength; j++) { + i++; + cNext = sql.charAt(j); - try { - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, this.sql, this.bindVariables, vitessConnection.getVtSession()).checkedGet(); + if (cNext == '*' && (j + 1) < statementLength) { + if (sql.charAt(j + 1) == '/') { + i++; - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } + if (i < statementLength) { + c = sql.charAt(i); + } - if (!(null == cursor.getFields() || cursor.getFields().isEmpty())) { - throw new SQLException(Constants.SQLExceptionMessages.SQL_RETURNED_RESULT_SET); + break; // comment done + } + } + } } - - if (this.retrieveGeneratedKeys) { - this.generatedId = cursor.getInsertId(); + } else if ((c == '\'') || (c == '"')) { + inQuotes = true; + currentQuoteChar = c; + } + } + } + + if ((c == '?') && !inQuotes && !inQuotedId) { + statementCount++; + } + } + + return statementCount; + } + + public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setCharacterStream(int parameterIndex, Reader reader, int length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setObject(int parameterIndex, Object parameterObject, int targetSqlType, + int scaleOrLength) throws SQLException { + if (null == parameterObject) { + setNull(parameterIndex, Types.OTHER); + } else { + try { + switch (targetSqlType) { + case Types.BOOLEAN: + if (parameterObject instanceof Boolean) { + setBoolean(parameterIndex, (Boolean) parameterObject); + break; + } else if (parameterObject instanceof String) { + setBoolean(parameterIndex, "true".equalsIgnoreCase((String) parameterObject) || !"0" + .equalsIgnoreCase((String) parameterObject)); + break; + } else if (parameterObject instanceof Number) { + int intValue = ((Number) parameterObject).intValue(); + setBoolean(parameterIndex, intValue != 0); + break; + } else { + throw new SQLException("Conversion from" + parameterObject.getClass().getName() + + "to Types.Boolean is not Possible"); } - - this.resultCount = cursor.getRowsAffected(); - - if (this.resultCount > Integer.MAX_VALUE) { - truncatedUpdateCount = Integer.MAX_VALUE; + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.REAL: + case Types.FLOAT: + case Types.DOUBLE: + case Types.DECIMAL: + case Types.NUMERIC: + setNumericObject(parameterIndex, parameterObject, targetSqlType, scaleOrLength); + break; + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (parameterObject instanceof BigDecimal) { + setString(parameterIndex, + (StringUtils.fixDecimalExponent((parameterObject).toString()))); } else { - truncatedUpdateCount = (int) this.resultCount; + setString(parameterIndex, parameterObject.toString()); } - } finally { - this.bindVariables.clear(); - } - return truncatedUpdateCount; - } - - public boolean execute() throws SQLException { - checkOpen(); - closeOpenResultSetAndResetCount(); - - if (!maybeSelect(this.sql)) { - this.executeUpdate(); - return false; - } else { - this.executeQuery(); - return true; - } - } - - public void clearParameters() throws SQLException { - checkOpen(); - this.bindVariables.clear(); - } - - public void setNull(int parameterIndex, int sqlType) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, null); - } - - public void setBoolean(int parameterIndex, boolean x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setByte(int parameterIndex, byte x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setShort(int parameterIndex, short x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setInt(int parameterIndex, int x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setLong(int parameterIndex, long x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setFloat(int parameterIndex, float x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setDouble(int parameterIndex, double x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setBigInteger(int parameterIndex, BigInteger x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setString(int parameterIndex, String x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setBytes(int parameterIndex, byte[] x) throws SQLException { - checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); - } - - public void setDate(int parameterIndex, Date x) throws SQLException { - checkOpen(); - String date = DateTime.formatDate(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); - } - - public void setTime(int parameterIndex, Time x) throws SQLException { - checkOpen(); - String time = DateTime.formatTime(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); - } - - public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { - checkOpen(); - String timeStamp = DateTime.formatTimestamp(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); - } - - public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { - checkOpen(); - String date = DateTime.formatDate(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); - } - - public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { - checkOpen(); - String time = DateTime.formatTime(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); - } - - public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { - checkOpen(); - String timeStamp = DateTime.formatTimestamp(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); - } - - public void setObject(int parameterIndex, Object x) throws SQLException { - if (x == null) { - setNull(parameterIndex, Types.NULL); - } else if (x instanceof String) { - setString(parameterIndex, (String) x); - } else if (x instanceof Short) { - setShort(parameterIndex, (Short) x); - } else if (x instanceof Integer) { - setInt(parameterIndex, (Integer) x); - } else if (x instanceof Long) { - setLong(parameterIndex, (Long) x); - } else if (x instanceof Float) { - setFloat(parameterIndex, (Float) x); - } else if (x instanceof Double) { - setDouble(parameterIndex, (Double) x); - } else if (x instanceof Boolean) { - setBoolean(parameterIndex, (Boolean) x); - } else if (x instanceof Byte) { - setByte(parameterIndex, (Byte) x); - } else if (x instanceof Character) { - setString(parameterIndex, String.valueOf(x)); - } else if (x instanceof Date) { - setDate(parameterIndex, (Date) x); - } else if (x instanceof Time) { - setTime(parameterIndex, (Time) x); - } else if (x instanceof Timestamp) { - setTimestamp(parameterIndex, (Timestamp) x); - } else if (x instanceof BigDecimal) { - setBigDecimal(parameterIndex, (BigDecimal) x); - } else if (x instanceof BigInteger) { - setBigInteger(parameterIndex, (BigInteger) x); - } else if (x instanceof byte[]) { - setBytes(parameterIndex, (byte[]) x); - } else if (getConnection().getTreatUtilDateAsTimestamp() && x instanceof java.util.Date) { - setTimestamp(parameterIndex, new Timestamp(((java.util.Date) x).getTime())); - } else { - throw new SQLException( - Constants.SQLExceptionMessages.SQL_TYPE_INFER + x.getClass().getCanonicalName()); - } - } - - /** - * Add bindVariables to the batch and clear it to have new set of bindVariables. - * - * @throws SQLException - */ - public void addBatch() throws SQLException { - checkOpen(); - this.batchedArgs.add(new HashMap<>(this.bindVariables)); - this.bindVariables.clear(); - } - - /** - * Clear all the batched bindVariables. - * - * @throws SQLException - */ - @Override public void clearBatch() throws SQLException { - checkOpen(); - this.batchedArgs.clear(); - } - - /** - * Submits a batch of commands to the database for execution and - * if all commands execute successfully, returns an array of update counts. - * The array returned is according to the order in which they were added to the batch. - *

- * If one of the commands in a batch update fails to execute properly, - * this method throws a BatchUpdateException, and a JDBC - * driver may or may not continue to process the remaining commands in - * the batch. If the driver continues processing after a failure, - * the array returned by the method BatchUpdateException.getUpdateCounts - * will contain as many elements as there are commands in the batch. - * - * @return int[] of results corresponding to each command - * @throws SQLException - */ - @Override public int[] executeBatch() throws SQLException { - checkOpen(); - // An executeBatch can't contain SELECT statements as defined by the documentation: - // https://docs.oracle.com/javase/tutorial/jdbc/basics/retrieving.html - // "This list may contain statements for updating, inserting, or deleting a row; and it may - // also contain DDL statements such as CREATE TABLE and DROP TABLE. It cannot, however, - // contain a statement that would produce a ResultSet object, such as a SELECT statement. - // In other words, the list can contain only statements that produce an update count." - checkNotReadOnly(); - - VTGateConnection vtGateConn; - List cursorWithErrorList; - List batchedQueries = new ArrayList<>(); - - if(0 == batchedArgs.size()) { - return new int[0]; - } - - try { - vtGateConn = this.vitessConnection.getVtGateConn(); - - this.retrieveGeneratedKeys = true; // mimicking mysql-connector-j - /* - * Current api does not support single query and multiple bindVariables list. - * So, List of the query is created to match the bindVariables list. - */ - for (int i = 0; i < batchedArgs.size(); ++i) { - batchedQueries.add(this.sql); + break; + case Types.CLOB: + if (parameterObject instanceof Clob) { + setClob(parameterIndex, (Clob) parameterObject); + } else { + setString(parameterIndex, parameterObject.toString()); } - - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursorWithErrorList = vtGateConn.executeBatch(context, batchedQueries, batchedArgs, vitessConnection.getVtSession()).checkedGet(); - - if (null == cursorWithErrorList) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + break; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + case Types.BLOB: + if (parameterObject instanceof Blob) { + setBlob(parameterIndex, (Blob) parameterObject); + } else { + setBytes(parameterIndex, (byte[]) parameterObject); } - - return this.generateBatchUpdateResult(cursorWithErrorList, batchedQueries); - } finally { - this.clearBatch(); - } - - - } - - //Methods which are currently not supported - - public ParameterMetaData getParameterMetaData() throws SQLException { - checkOpen(); - if (this.parameterMetadata == null) { - this.parameterMetadata = new VitessParameterMetaData(calculateParameterCount()); - } - - return this.parameterMetadata; - } - - /** - * This function was ported from mysql-connector-java ParseInfo object and greatly simplified to just the parts - * for counting parameters - */ - private int calculateParameterCount() throws SQLException { - if (sql == null) { - throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + ": sql null"); - } - - char quotedIdentifierChar = '`'; - char currentQuoteChar = 0; - boolean inQuotes = false; - boolean inQuotedId = false; - int statementCount = 0; - int statementLength = sql.length(); - int statementStartPos = StringUtils.findStartOfStatement(sql); - - for (int i = statementStartPos; i < statementLength; ++i) { - char c = sql.charAt(i); - - if (c == '\\' && i < (statementLength - 1)) { - i++; - continue; // next character is escaped + break; + case Types.DATE: + case Types.TIMESTAMP: + java.util.Date parameterAsDate; + if (parameterObject instanceof String) { + ParsePosition pp = new ParsePosition(0); + DateFormat sdf = new SimpleDateFormat( + StringUtils.getDateTimePattern((String) parameterObject, false), Locale.US); + parameterAsDate = sdf.parse((String) parameterObject, pp); + } else { + parameterAsDate = (java.util.Date) parameterObject; } - - // are we in a quoted identifier? (only valid when the id is not inside a 'string') - if (!inQuotes && c == quotedIdentifierChar) { - inQuotedId = !inQuotedId; - } else if (!inQuotedId) { - // only respect quotes when not in a quoted identifier - if (inQuotes) { - if (((c == '\'') || (c == '"')) && c == currentQuoteChar) { - if (i < (statementLength - 1) && sql.charAt(i + 1) == currentQuoteChar) { - i++; - continue; // inline quote escape - } - - inQuotes = !inQuotes; - currentQuoteChar = 0; - } + switch (targetSqlType) { + case Types.DATE: + if (parameterAsDate instanceof Date) { + setDate(parameterIndex, (Date) parameterAsDate); } else { - if (c == '#' || (c == '-' && (i + 1) < statementLength && sql.charAt(i + 1) == '-')) { - // comment, run out to end of statement, or newline, whichever comes first - int endOfStmt = statementLength - 1; - - for (; i < endOfStmt; i++) { - c = sql.charAt(i); - - if (c == '\r' || c == '\n') { - break; - } - } - - continue; - } else if (c == '/' && (i + 1) < statementLength) { - // Comment? - char cNext = sql.charAt(i + 1); - if (cNext == '*') { - i += 2; - - for (int j = i; j < statementLength; j++) { - i++; - cNext = sql.charAt(j); - - if (cNext == '*' && (j + 1) < statementLength) { - if (sql.charAt(j + 1) == '/') { - i++; - - if (i < statementLength) { - c = sql.charAt(i); - } - - break; // comment done - } - } - } - } - } else if ((c == '\'') || (c == '"')) { - inQuotes = true; - currentQuoteChar = c; - } + setDate(parameterIndex, new Date(parameterAsDate.getTime())); } - } - - if ((c == '?') && !inQuotes && !inQuotedId) { - statementCount++; - } - } - - return statementCount; - } - - public void setNull(int parameterIndex, int sqlType, String typeName) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setCharacterStream(int parameterIndex, Reader reader, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setObject(int parameterIndex, Object parameterObject, int targetSqlType, - int scaleOrLength) throws SQLException { - if (null == parameterObject) { - setNull(parameterIndex, Types.OTHER); - } else { - try { - switch (targetSqlType) { - case Types.BOOLEAN: - if (parameterObject instanceof Boolean) { - setBoolean(parameterIndex, (Boolean) parameterObject); - break; - } else if (parameterObject instanceof String) { - setBoolean(parameterIndex, - "true".equalsIgnoreCase((String) parameterObject) || !"0" - .equalsIgnoreCase((String) parameterObject)); - break; - } else if (parameterObject instanceof Number) { - int intValue = ((Number) parameterObject).intValue(); - setBoolean(parameterIndex, intValue != 0); - break; - } else { - throw new SQLException( - "Conversion from" + parameterObject.getClass().getName() - + "to Types.Boolean is not Possible"); - } - case Types.BIT: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.REAL: - case Types.FLOAT: - case Types.DOUBLE: - case Types.DECIMAL: - case Types.NUMERIC: - setNumericObject(parameterIndex, parameterObject, targetSqlType, - scaleOrLength); - break; - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - if (parameterObject instanceof BigDecimal) { - setString(parameterIndex, - (StringUtils.fixDecimalExponent((parameterObject).toString()))); - } else { - setString(parameterIndex, parameterObject.toString()); - } - break; - case Types.CLOB: - if (parameterObject instanceof Clob) { - setClob(parameterIndex, (Clob) parameterObject); - } else { - setString(parameterIndex, parameterObject.toString()); - } - break; - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: - case Types.BLOB: - if (parameterObject instanceof Blob) { - setBlob(parameterIndex, (Blob) parameterObject); - } else { - setBytes(parameterIndex, (byte[]) parameterObject); - } - break; - case Types.DATE: - case Types.TIMESTAMP: - java.util.Date parameterAsDate; - if (parameterObject instanceof String) { - ParsePosition pp = new ParsePosition(0); - DateFormat sdf = new SimpleDateFormat( - StringUtils.getDateTimePattern((String) parameterObject, false), - Locale.US); - parameterAsDate = sdf.parse((String) parameterObject, pp); - } else { - parameterAsDate = (java.util.Date) parameterObject; - } - switch (targetSqlType) { - case Types.DATE: - if (parameterAsDate instanceof Date) { - setDate(parameterIndex, (Date) parameterAsDate); - } else { - setDate(parameterIndex, new Date(parameterAsDate.getTime())); - } - break; - case Types.TIMESTAMP: - if (parameterAsDate instanceof Timestamp) { - setTimestamp(parameterIndex, (Timestamp) parameterAsDate); - } else { - setTimestamp(parameterIndex, - new Timestamp(parameterAsDate.getTime())); - } - break; - } - break; - case Types.TIME: - if (parameterObject instanceof String) { - DateFormat sdf = new SimpleDateFormat( - StringUtils.getDateTimePattern((String) parameterObject, true), - Locale.US); - setTime(parameterIndex, - new Time(sdf.parse((String) parameterObject).getTime())); - } else if (parameterObject instanceof Timestamp) { - Timestamp timestamp = (Timestamp) parameterObject; - setTime(parameterIndex, new Time(timestamp.getTime())); - } else { - setTime(parameterIndex, (Time) parameterObject); - } - break; - default: - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + break; + case Types.TIMESTAMP: + if (parameterAsDate instanceof Timestamp) { + setTimestamp(parameterIndex, (Timestamp) parameterAsDate); + } else { + setTimestamp(parameterIndex, new Timestamp(parameterAsDate.getTime())); } - } catch (Exception ex) { - throw new SQLException(ex); + break; } - } - } - - public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBinaryStream(int parameterIndex, InputStream x, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setCharacterStream(int parameterIndex, Reader reader, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setUnicodeStream(int parameterIndex, InputStream x, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setRef(int parameterIndex, Ref x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBlob(int parameterIndex, Blob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setClob(int parameterIndex, Clob x) throws SQLException { - checkOpen(); - if (x.length() > Integer.MAX_VALUE) { + break; + case Types.TIME: + if (parameterObject instanceof String) { + DateFormat sdf = new SimpleDateFormat( + StringUtils.getDateTimePattern((String) parameterObject, true), Locale.US); + setTime(parameterIndex, new Time(sdf.parse((String) parameterObject).getTime())); + } else if (parameterObject instanceof Timestamp) { + Timestamp timestamp = (Timestamp) parameterObject; + setTime(parameterIndex, new Time(timestamp.getTime())); + } else { + setTime(parameterIndex, (Time) parameterObject); + } + break; + default: throw new SQLFeatureNotSupportedException( - String.format("Clob size over %d not support", Integer.MAX_VALUE), Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - // Clob uses 1-based indexing! - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, - x.getSubString(1, (int) x.length())); - } - - public void setArray(int parameterIndex, Array x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public ResultSetMetaData getMetaData() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setURL(int parameterIndex, URL x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setRowId(int parameterIndex, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNString(int parameterIndex, String value) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNCharacterStream(int parameterIndex, Reader value, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNClob(int parameterIndex, NClob value) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBlob(int parameterIndex, InputStream inputStream, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setClob(int parameterIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setNClob(int parameterIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setObject(int parameterIndex, Object parameterObject, int targetSqlType) - throws SQLException { - if (!(parameterObject instanceof BigDecimal)) { - setObject(parameterIndex, parameterObject, targetSqlType, 0); - } else { - setObject(parameterIndex, parameterObject, targetSqlType, - ((BigDecimal) parameterObject).scale()); - } - } - - private void setNumericObject(int parameterIndex, Object parameterObj, int targetSqlType, - int scale) throws SQLException { - Number numberParam; - if (parameterObj instanceof Boolean) { - numberParam = (Boolean) parameterObj ? Integer.valueOf(1) : Integer.valueOf(0); - } else if (parameterObj instanceof String) { - switch (targetSqlType) { - case Types.BIT: - if ("1".equals(parameterObj) || "0".equals(parameterObj)) { - numberParam = Integer.valueOf((String) parameterObj); - } else { - boolean parameterAsBoolean = "true".equalsIgnoreCase((String) parameterObj); - numberParam = parameterAsBoolean ? Integer.valueOf(1) : Integer.valueOf(0); - } - break; - - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - numberParam = Integer.valueOf((String) parameterObj); - break; - - case Types.BIGINT: - numberParam = Long.valueOf((String) parameterObj); - break; - - case Types.REAL: - numberParam = Float.valueOf((String) parameterObj); - break; - - case Types.FLOAT: - case Types.DOUBLE: - numberParam = Double.valueOf((String) parameterObj); - break; - - case Types.DECIMAL: - case Types.NUMERIC: - default: - numberParam = new java.math.BigDecimal((String) parameterObj); + } catch (Exception ex) { + throw new SQLException(ex); + } + } + } + + public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setCharacterStream(int parameterIndex, Reader reader, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setRef(int parameterIndex, Ref x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBlob(int parameterIndex, Blob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setClob(int parameterIndex, Clob x) throws SQLException { + checkOpen(); + if (x.length() > Integer.MAX_VALUE) { + throw new SQLFeatureNotSupportedException( + String.format("Clob size over %d not support", Integer.MAX_VALUE), + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + // Clob uses 1-based indexing! + this.bindVariables + .put(Constants.LITERAL_V + parameterIndex, x.getSubString(1, (int) x.length())); + } + + public void setArray(int parameterIndex, Array x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public ResultSetMetaData getMetaData() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setURL(int parameterIndex, URL x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setRowId(int parameterIndex, RowId x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNString(int parameterIndex, String value) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNCharacterStream(int parameterIndex, Reader value, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNClob(int parameterIndex, NClob value) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setClob(int parameterIndex, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBlob(int parameterIndex, InputStream inputStream, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setClob(int parameterIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setNClob(int parameterIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setObject(int parameterIndex, Object parameterObject, int targetSqlType) + throws SQLException { + if (!(parameterObject instanceof BigDecimal)) { + setObject(parameterIndex, parameterObject, targetSqlType, 0); + } else { + setObject(parameterIndex, parameterObject, targetSqlType, + ((BigDecimal) parameterObject).scale()); + } + } + + private void setNumericObject(int parameterIndex, Object parameterObj, int targetSqlType, + int scale) throws SQLException { + Number numberParam; + if (parameterObj instanceof Boolean) { + numberParam = (Boolean) parameterObj ? Integer.valueOf(1) : Integer.valueOf(0); + } else if (parameterObj instanceof String) { + switch (targetSqlType) { + case Types.BIT: + if ("1".equals(parameterObj) || "0".equals(parameterObj)) { + numberParam = Integer.valueOf((String) parameterObj); + } else { + boolean parameterAsBoolean = "true".equalsIgnoreCase((String) parameterObj); + numberParam = parameterAsBoolean ? Integer.valueOf(1) : Integer.valueOf(0); + } + break; + + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + numberParam = Integer.valueOf((String) parameterObj); + break; + + case Types.BIGINT: + numberParam = Long.valueOf((String) parameterObj); + break; + + case Types.REAL: + numberParam = Float.valueOf((String) parameterObj); + break; + + case Types.FLOAT: + case Types.DOUBLE: + numberParam = Double.valueOf((String) parameterObj); + break; + + case Types.DECIMAL: + case Types.NUMERIC: + default: + numberParam = new java.math.BigDecimal((String) parameterObj); + } + } else { + numberParam = (Number) parameterObj; + } + switch (targetSqlType) { + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + setInt(parameterIndex, numberParam.intValue()); + break; + + case Types.BIGINT: + setLong(parameterIndex, numberParam.longValue()); + break; + + case Types.REAL: + setFloat(parameterIndex, numberParam.floatValue()); + break; + + case Types.FLOAT: + case Types.DOUBLE: + setDouble(parameterIndex, numberParam.doubleValue()); + break; + + case Types.DECIMAL: + case Types.NUMERIC: + + if (numberParam instanceof java.math.BigDecimal) { + BigDecimal scaledBigDecimal; + try { + scaledBigDecimal = ((java.math.BigDecimal) numberParam).setScale(scale); + } catch (ArithmeticException ex) { + try { + scaledBigDecimal = ((java.math.BigDecimal) numberParam) + .setScale(scale, BigDecimal.ROUND_HALF_UP); + } catch (ArithmeticException arEx) { + throw new SQLException( + "Can't set the scale of '" + scale + "' for Decimal Argument" + numberParam); } + } + setBigDecimal(parameterIndex, scaledBigDecimal); + } else if (numberParam instanceof java.math.BigInteger) { + setBigInteger(parameterIndex, (BigInteger) numberParam); } else { - numberParam = (Number) parameterObj; - } - switch (targetSqlType) { - case Types.BIT: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - setInt(parameterIndex, numberParam.intValue()); - break; - - case Types.BIGINT: - setLong(parameterIndex, numberParam.longValue()); - break; - - case Types.REAL: - setFloat(parameterIndex, numberParam.floatValue()); - break; - - case Types.FLOAT: - case Types.DOUBLE: - setDouble(parameterIndex, numberParam.doubleValue()); - break; - - case Types.DECIMAL: - case Types.NUMERIC: - - if (numberParam instanceof java.math.BigDecimal) { - BigDecimal scaledBigDecimal; - try { - scaledBigDecimal = ((java.math.BigDecimal) numberParam).setScale(scale); - } catch (ArithmeticException ex) { - try { - scaledBigDecimal = ((java.math.BigDecimal) numberParam) - .setScale(scale, BigDecimal.ROUND_HALF_UP); - } catch (ArithmeticException arEx) { - throw new SQLException( - "Can't set the scale of '" + scale + "' for Decimal Argument" - + numberParam); - } - } - setBigDecimal(parameterIndex, scaledBigDecimal); - } else if (numberParam instanceof java.math.BigInteger) { - setBigInteger(parameterIndex, (BigInteger) numberParam); - } else { - setBigDecimal(parameterIndex, - new java.math.BigDecimal(numberParam.doubleValue())); - } - break; + setBigDecimal(parameterIndex, new java.math.BigDecimal(numberParam.doubleValue())); } + break; } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java index f13a31d24fb..7c025010612 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -26,7 +26,6 @@ import io.vitess.util.Constants; import io.vitess.util.StringUtils; -import javax.sql.rowset.serial.SerialClob; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.Reader; @@ -56,1555 +55,1554 @@ import java.util.List; import java.util.Map; +import javax.sql.rowset.serial.SerialClob; + /** * Created by harshit.gangal on 23/01/16. */ public class VitessResultSet implements ResultSet { - private Cursor cursor; - private List fields; - private VitessStatement vitessStatement; - private boolean closed = false; - private Row row; - private int currentRow; - private int maxRows; - private int fetchSize; - /** - * Last column name index read - */ - private int lastIndexRead = -1; - - public VitessResultSet(Cursor cursor) throws SQLException { - this(cursor, null); - } - - public VitessResultSet(Cursor cursor, VitessStatement vitessStatement) throws SQLException { - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.CURSOR_NULL); - } - - this.cursor = cursor; - this.vitessStatement = vitessStatement; - try { - this.fields = enhancedFieldsFromCursor(vitessStatement == null ? null : vitessStatement.getConnection()); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); - } - this.currentRow = 0; - if (null != vitessStatement) { - this.maxRows = vitessStatement.getMaxRows(); - this.fetchSize = vitessStatement.getFetchSize(); - } - } - - public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, String[][] data, ConnectionProperties connection) - throws SQLException { - - if (columnNames.length != columnTypes.length) { - throw new SQLException(Constants.SQLExceptionMessages.INVALID_RESULT_SET); - } - Query.QueryResult.Builder queryResultBuilder = Query.QueryResult.newBuilder(); - for (int columnCounter = 0; columnCounter < columnNames.length; columnCounter++) { - Query.Field.Builder queryField = - Query.Field.newBuilder().setName(columnNames[columnCounter]) - .setType(columnTypes[columnCounter]); - queryResultBuilder.addFields(queryField.build()); - } - if (null != data) { - for (String[] rowData : data) { - - Query.Row.Builder queryRow = Query.Row.newBuilder(); - StringBuilder sb = new StringBuilder(); - for (String aRowData : rowData) { - sb.append(aRowData); - queryRow.addLengths(aRowData.length()); - } - queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); - queryResultBuilder.addRows(queryRow); - sb.delete(0, sb.length()); - } - } - this.cursor = new SimpleCursor(queryResultBuilder.build()); - this.vitessStatement = null; - try { - this.fields = enhancedFieldsFromCursor(connection); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); - } - this.currentRow = 0; - } - - public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, - ArrayList> data, VitessConnection connection) throws SQLException { - - if (columnNames.length != columnTypes.length) { - throw new SQLException(Constants.SQLExceptionMessages.INVALID_RESULT_SET); - } - Query.QueryResult.Builder queryResultBuilder = Query.QueryResult.newBuilder(); - for (int columnCounter = 0; columnCounter < columnNames.length; columnCounter++) { - Query.Field.Builder queryField = - Query.Field.newBuilder().setName(columnNames[columnCounter]) - .setType(columnTypes[columnCounter]); - queryResultBuilder.addFields(queryField.build()); - } - for (ArrayList rowData : data) { - - Query.Row.Builder queryRow = Query.Row.newBuilder(); - StringBuilder sb = new StringBuilder(); - for (String aRowData : rowData) { - if (null != aRowData) { - sb.append(aRowData); - queryRow.addLengths(aRowData.length()); - } else { - queryRow.addLengths(-1); - } - } - queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); - queryResultBuilder.addRows(queryRow); - sb.delete(0, sb.length()); - } - this.cursor = new SimpleCursor(queryResultBuilder.build()); - this.vitessStatement = null; - try { - this.fields = enhancedFieldsFromCursor(connection); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); - } - this.currentRow = 0; - } - - private List enhancedFieldsFromCursor(ConnectionProperties connection) throws SQLException { - if (cursor == null|| cursor.getFields() == null) { - throw new SQLException(Constants.SQLExceptionMessages.CURSOR_NULL); - } - List rawFields = cursor.getFields(); - List fields = new ArrayList<>(rawFields.size()); - for (Query.Field field : rawFields) { - fields.add(new FieldWithMetadata(connection, field)); - } - return fields; - } - - public boolean next() throws SQLException { - checkOpen(); - - if (this.maxRows > 0 && this.currentRow >= this.maxRows) { - return false; - } - - this.row = this.cursor.next(); - ++this.currentRow; - - return row != null; - } - - public void close() throws SQLException { - if (!this.closed) { - try { - this.cursor.close(); - } catch (Exception e) { - throw new SQLException(Constants.SQLExceptionMessages.VITESS_CURSOR_CLOSE_ERROR); - } finally { - //Dereferencing all the objects - this.closed = true; - this.cursor = null; - this.vitessStatement = null; - this.fields = null; - this.row = null; - } - } - } - - public boolean wasNull() throws SQLException { - checkOpen(); - if (this.lastIndexRead == -1) { - throw new SQLException(Constants.SQLExceptionMessages.NO_COLUMN_ACCESSED); - } - return this.row.wasNull(); - } - - public String getString(int columnIndex) throws SQLException { - Object object; - String columnValue; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; - } - - object = this.row.getObject(columnIndex); - if (object instanceof byte[]) { - FieldWithMetadata field = this.fields.get(columnIndex - 1); - if (field.hasConnectionProperties() && field.getConnectionProperties().isIncludeAllFields()) { - columnValue = convertBytesToString((byte[]) object, field.getEncoding()); - } else { - columnValue = new String((byte[]) object); - } + private Cursor cursor; + private List fields; + private VitessStatement vitessStatement; + private boolean closed = false; + private Row row; + private int currentRow; + private int maxRows; + private int fetchSize; + /** + * Last column name index read + */ + private int lastIndexRead = -1; + + public VitessResultSet(Cursor cursor) throws SQLException { + this(cursor, null); + } + + public VitessResultSet(Cursor cursor, VitessStatement vitessStatement) throws SQLException { + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.CURSOR_NULL); + } + + this.cursor = cursor; + this.vitessStatement = vitessStatement; + try { + this.fields = enhancedFieldsFromCursor( + vitessStatement == null ? null : vitessStatement.getConnection()); + } catch (SQLException e) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } + this.currentRow = 0; + if (null != vitessStatement) { + this.maxRows = vitessStatement.getMaxRows(); + this.fetchSize = vitessStatement.getFetchSize(); + } + } + + public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, String[][] data, + ConnectionProperties connection) throws SQLException { + + if (columnNames.length != columnTypes.length) { + throw new SQLException(Constants.SQLExceptionMessages.INVALID_RESULT_SET); + } + Query.QueryResult.Builder queryResultBuilder = Query.QueryResult.newBuilder(); + for (int columnCounter = 0; columnCounter < columnNames.length; columnCounter++) { + Query.Field.Builder queryField = Query.Field.newBuilder().setName(columnNames[columnCounter]) + .setType(columnTypes[columnCounter]); + queryResultBuilder.addFields(queryField.build()); + } + if (null != data) { + for (String[] rowData : data) { + + Query.Row.Builder queryRow = Query.Row.newBuilder(); + StringBuilder sb = new StringBuilder(); + for (String aRowData : rowData) { + sb.append(aRowData); + queryRow.addLengths(aRowData.length()); + } + queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); + queryResultBuilder.addRows(queryRow); + sb.delete(0, sb.length()); + } + } + this.cursor = new SimpleCursor(queryResultBuilder.build()); + this.vitessStatement = null; + try { + this.fields = enhancedFieldsFromCursor(connection); + } catch (SQLException e) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } + this.currentRow = 0; + } + + public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, + ArrayList> data, VitessConnection connection) throws SQLException { + + if (columnNames.length != columnTypes.length) { + throw new SQLException(Constants.SQLExceptionMessages.INVALID_RESULT_SET); + } + Query.QueryResult.Builder queryResultBuilder = Query.QueryResult.newBuilder(); + for (int columnCounter = 0; columnCounter < columnNames.length; columnCounter++) { + Query.Field.Builder queryField = Query.Field.newBuilder().setName(columnNames[columnCounter]) + .setType(columnTypes[columnCounter]); + queryResultBuilder.addFields(queryField.build()); + } + for (ArrayList rowData : data) { + + Query.Row.Builder queryRow = Query.Row.newBuilder(); + StringBuilder sb = new StringBuilder(); + for (String aRowData : rowData) { + if (null != aRowData) { + sb.append(aRowData); + queryRow.addLengths(aRowData.length()); } else { - columnValue = String.valueOf(object); - } - return columnValue; - } - - public boolean getBoolean(int columnIndex) throws SQLException { - String boolString; - int bool; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return false; - } - - // Mysql 5.0 and higher have a BIT Data Type, need to check for this as well. - FieldWithMetadata field = this.fields.get(columnIndex - 1); - - if (field.getVitessTypeValue() == Query.Type.BIT_VALUE) { - return byteArrayToBoolean(columnIndex); - } - - boolString = this.getString(columnIndex); - try { - bool = Integer.valueOf(boolString); - } catch (NumberFormatException nfe) { - return null != boolString && "true".equalsIgnoreCase(boolString.trim()); - } - return bool > 0; + queryRow.addLengths(-1); + } + } + queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); + queryResultBuilder.addRows(queryRow); + sb.delete(0, sb.length()); + } + this.cursor = new SimpleCursor(queryResultBuilder.build()); + this.vitessStatement = null; + try { + this.fields = enhancedFieldsFromCursor(connection); + } catch (SQLException e) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } + this.currentRow = 0; + } + + private List enhancedFieldsFromCursor(ConnectionProperties connection) + throws SQLException { + if (cursor == null || cursor.getFields() == null) { + throw new SQLException(Constants.SQLExceptionMessages.CURSOR_NULL); + } + List rawFields = cursor.getFields(); + List fields = new ArrayList<>(rawFields.size()); + for (Query.Field field : rawFields) { + fields.add(new FieldWithMetadata(connection, field)); + } + return fields; + } + + public boolean next() throws SQLException { + checkOpen(); + + if (this.maxRows > 0 && this.currentRow >= this.maxRows) { + return false; + } + + this.row = this.cursor.next(); + ++this.currentRow; + + return row != null; + } + + public void close() throws SQLException { + if (!this.closed) { + try { + this.cursor.close(); + } catch (Exception e) { + throw new SQLException(Constants.SQLExceptionMessages.VITESS_CURSOR_CLOSE_ERROR); + } finally { + //Dereferencing all the objects + this.closed = true; + this.cursor = null; + this.vitessStatement = null; + this.fields = null; + this.row = null; + } } + } - public byte getByte(int columnIndex) throws SQLException { - String byteString; - byte value; - - preAccessor(columnIndex); - if (isNull(columnIndex)) { - return 0; - } - - //If the return column type is of byte, - // return byte otherwise typecast - Object object = this.row.getObject(columnIndex); - if (object instanceof Byte) { - return (byte) object; - } - - byteString = this.getString(columnIndex); - try { - value = Byte.parseByte(byteString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } - - return value; + public boolean wasNull() throws SQLException { + checkOpen(); + if (this.lastIndexRead == -1) { + throw new SQLException(Constants.SQLExceptionMessages.NO_COLUMN_ACCESSED); } + return this.row.wasNull(); + } - public short getShort(int columnIndex) throws SQLException { - String shortString; - short value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - shortString = this.getString(columnIndex); + public String getString(int columnIndex) throws SQLException { + Object object; + String columnValue; - try { - value = Short.parseShort(shortString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } + preAccessor(columnIndex); - return value; + if (isNull(columnIndex)) { + return null; } - public int getInt(int columnIndex) throws SQLException { - String intString; - int value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - intString = this.getString(columnIndex); - - try { - value = Integer.parseInt(intString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } - - return value; + object = this.row.getObject(columnIndex); + if (object instanceof byte[]) { + FieldWithMetadata field = this.fields.get(columnIndex - 1); + if (field.hasConnectionProperties() && field.getConnectionProperties().isIncludeAllFields()) { + columnValue = convertBytesToString((byte[]) object, field.getEncoding()); + } else { + columnValue = new String((byte[]) object); + } + } else { + columnValue = String.valueOf(object); } + return columnValue; + } - public long getLong(int columnIndex) throws SQLException { - String longString; - long value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - longString = this.getString(columnIndex); + public boolean getBoolean(int columnIndex) throws SQLException { + String boolString; + int bool; - try { - value = Long.parseLong(longString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } + preAccessor(columnIndex); - return value; + if (isNull(columnIndex)) { + return false; } - public float getFloat(int columnIndex) throws SQLException { - String floatString; - float value; + // Mysql 5.0 and higher have a BIT Data Type, need to check for this as well. + FieldWithMetadata field = this.fields.get(columnIndex - 1); - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - floatString = this.getString(columnIndex); - - try { - value = Float.parseFloat(floatString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } - - return value; + if (field.getVitessTypeValue() == Query.Type.BIT_VALUE) { + return byteArrayToBoolean(columnIndex); } - public double getDouble(int columnIndex) throws SQLException { - String doubleString; - double value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return 0; - } - - doubleString = this.getString(columnIndex); - - try { - value = Double.parseDouble(doubleString); - } catch (NumberFormatException nfe) { - throw new SQLException(nfe); - } - - return value; + boolString = this.getString(columnIndex); + try { + bool = Integer.valueOf(boolString); + } catch (NumberFormatException nfe) { + return null != boolString && "true".equalsIgnoreCase(boolString.trim()); } + return bool > 0; + } - public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { - String bigDecimalString; - BigDecimal value; + public byte getByte(int columnIndex) throws SQLException { + String byteString; + byte value; - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; - } - - bigDecimalString = this.getString(columnIndex); - - try { - value = new BigDecimal(bigDecimalString); - value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); - } catch (Exception ex) { - throw new SQLException(ex); - } - - return value; + preAccessor(columnIndex); + if (isNull(columnIndex)) { + return 0; } - public BigInteger getBigInteger(int columnIndex) throws SQLException { - String bigIntegerString; - BigInteger value; - - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; - } - - bigIntegerString = this.getString(columnIndex); - - try { - value = new BigInteger(bigIntegerString); - } catch (Exception ex) { - throw new SQLException(ex); - } - - return value; + //If the return column type is of byte, + // return byte otherwise typecast + Object object = this.row.getObject(columnIndex); + if (object instanceof Byte) { + return (byte) object; } - public byte[] getBytes(int columnIndex) throws SQLException { - String bytesString; - byte[] value; - - preAccessor(columnIndex); - if (isNull(columnIndex)) { - return null; - } - //If the return column type is of byte[], - // return byte[] otherwise typecast - Object object = this.row.getObject(columnIndex); - if (object instanceof byte[]) { - return (byte[]) object; - } - - bytesString = this.getString(columnIndex); - try { - value = bytesString.getBytes(); - } catch (Exception ex) { - throw new SQLException(ex); - } - - return value; + byteString = this.getString(columnIndex); + try { + value = Byte.parseByte(byteString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public Date getDate(int columnIndex) throws SQLException { - preAccessor(columnIndex); + return value; + } - NullDateTime nullDateTime = getNullDateTime(columnIndex); - return getNullableDate(columnIndex, nullDateTime, null); - } - - public Time getTime(int columnIndex) throws SQLException { - preAccessor(columnIndex); + public short getShort(int columnIndex) throws SQLException { + String shortString; + short value; - if (isNull(columnIndex)) { - return null; - } + preAccessor(columnIndex); - return this.row.getTime(columnIndex); + if (isNull(columnIndex)) { + return 0; } - public Timestamp getTimestamp(int columnIndex) throws SQLException { - preAccessor(columnIndex); + shortString = this.getString(columnIndex); - NullDateTime nullDateTime = getNullDateTime(columnIndex); - return getNullableDateTime(columnIndex, nullDateTime, null); + try { + value = Short.parseShort(shortString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public String getString(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getString(columnIndex); - } + return value; + } - public boolean getBoolean(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBoolean(columnIndex); - } + public int getInt(int columnIndex) throws SQLException { + String intString; + int value; - public byte getByte(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getByte(columnIndex); - } + preAccessor(columnIndex); - public short getShort(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getShort(columnIndex); + if (isNull(columnIndex)) { + return 0; } - public int getInt(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getInt(columnIndex); - } + intString = this.getString(columnIndex); - public long getLong(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getLong(columnIndex); + try { + value = Integer.parseInt(intString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public float getFloat(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getFloat(columnIndex); - } + return value; + } - public double getDouble(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getDouble(columnIndex); - } + public long getLong(int columnIndex) throws SQLException { + String longString; + long value; - public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBigDecimal(columnIndex, scale); - } + preAccessor(columnIndex); - public BigInteger getBigInteger(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBigInteger(columnIndex); + if (isNull(columnIndex)) { + return 0; } - public byte[] getBytes(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBytes(columnIndex); - } + longString = this.getString(columnIndex); - public Date getDate(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getDate(columnIndex); + try { + value = Long.parseLong(longString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public Time getTime(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getTime(columnIndex); - } + return value; + } - public Timestamp getTimestamp(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getTimestamp(columnIndex); - } + public float getFloat(int columnIndex) throws SQLException { + String floatString; + float value; - public SQLWarning getWarnings() throws SQLException { - checkOpen(); - //no-op, All exceptions thrown, none kept as warning - return null; - } + preAccessor(columnIndex); - public void clearWarnings() throws SQLException { - checkOpen(); - //no-op, All exceptions thrown, none kept as warning + if (isNull(columnIndex)) { + return 0; } + floatString = this.getString(columnIndex); - public ResultSetMetaData getMetaData() throws SQLException { - return new VitessResultSetMetaData(fields); + try { + value = Float.parseFloat(floatString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public Object getObject(int columnIndex) throws SQLException { - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; - } - - Object retVal = this.row.getObject(columnIndex); + return value; + } - FieldWithMetadata field = this.fields.get(columnIndex - 1); - if (field.hasConnectionProperties() && field.getConnectionProperties().isIncludeAllFields() && retVal instanceof byte[]) { - retVal = convertBytesIfPossible((byte[]) retVal, field); - } + public double getDouble(int columnIndex) throws SQLException { + String doubleString; + double value; - return retVal; - } - - private Object convertBytesIfPossible(byte[] bytes, FieldWithMetadata field) throws SQLException { - String encoding = field.getEncoding(); - switch (field.getJavaType()) { - case Types.BIT: - if (!field.isSingleBit()) { - return bytes; - } - return byteArrayToBoolean(bytes); - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - if (!field.isOpaqueBinary()) { - return convertBytesToString(bytes, encoding); - } - return bytes; - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: - return bytes; - default: - return convertBytesToString(bytes, encoding); - } - } + preAccessor(columnIndex); - private String convertBytesToString(byte[] bytes, String encoding) throws SQLException { - if (encoding == null) { - return StringUtils.toString(bytes); - } else { - try { - return StringUtils.toString(bytes, 0, bytes.length, encoding); - } catch (UnsupportedEncodingException e) { - throw new SQLException("Unsupported character encoding: " + encoding, e); - } - } + if (isNull(columnIndex)) { + return 0; } - public Object getObject(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getObject(columnIndex); - } + doubleString = this.getString(columnIndex); - public int findColumn(String columnLabel) throws SQLException { - return this.cursor.findColumn(columnLabel); + try { + value = Double.parseDouble(doubleString); + } catch (NumberFormatException nfe) { + throw new SQLException(nfe); } - public BigDecimal getBigDecimal(int columnIndex) throws SQLException { - String bigDecimalString; - BigDecimal value; - - preAccessor(columnIndex); + return value; + } - if (isNull(columnIndex)) { - return null; - } + public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLException { + String bigDecimalString; + BigDecimal value; - bigDecimalString = this.getString(columnIndex); + preAccessor(columnIndex); - try { - value = new BigDecimal(bigDecimalString); - } catch (Exception ex) { - throw new SQLException(ex); - } - - return value; + if (isNull(columnIndex)) { + return null; } - public BigDecimal getBigDecimal(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBigDecimal(columnIndex); - } + bigDecimalString = this.getString(columnIndex); - public boolean isBeforeFirst() throws SQLException { - checkOpen(); - return this.currentRow == 0; + try { + value = new BigDecimal(bigDecimalString); + value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); + } catch (Exception ex) { + throw new SQLException(ex); } - public boolean isFirst() throws SQLException { - checkOpen(); - return currentRow == 1; - } + return value; + } - public int getRow() throws SQLException { - checkOpen(); - return this.currentRow; - } + public BigInteger getBigInteger(int columnIndex) throws SQLException { + String bigIntegerString; + BigInteger value; - public int getFetchDirection() throws SQLException { - checkOpen(); - return ResultSet.FETCH_FORWARD; - } + preAccessor(columnIndex); - public void setFetchDirection(int direction) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (isNull(columnIndex)) { + return null; } - public int getFetchSize() throws SQLException { - checkOpen(); - return this.fetchSize; - } + bigIntegerString = this.getString(columnIndex); - public void setFetchSize(int rows) throws SQLException { - checkOpen(); - if (rows < 0) { - throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "fetch size"); - } - this.fetchSize = rows; + try { + value = new BigInteger(bigIntegerString); + } catch (Exception ex) { + throw new SQLException(ex); } - public int getType() throws SQLException { - checkOpen(); - return ResultSet.TYPE_FORWARD_ONLY; - } + return value; + } - public int getConcurrency() throws SQLException { - checkOpen(); - return ResultSet.CONCUR_READ_ONLY; - } + public byte[] getBytes(int columnIndex) throws SQLException { + String bytesString; + byte[] value; - public Statement getStatement() throws SQLException { - checkOpen(); - return this.vitessStatement; + preAccessor(columnIndex); + if (isNull(columnIndex)) { + return null; } - - public Date getDate(int columnIndex, Calendar cal) throws SQLException { - preAccessor(columnIndex); - - NullDateTime nullDateTime = getNullDateTime(columnIndex); - return getNullableDate(columnIndex, nullDateTime, cal); + //If the return column type is of byte[], + // return byte[] otherwise typecast + Object object = this.row.getObject(columnIndex); + if (object instanceof byte[]) { + return (byte[]) object; } - public Date getDate(String columnLabel, Calendar cal) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getDate(columnIndex, cal); + bytesString = this.getString(columnIndex); + try { + value = bytesString.getBytes(); + } catch (Exception ex) { + throw new SQLException(ex); } - public Time getTime(int columnIndex, Calendar cal) throws SQLException { - preAccessor(columnIndex); + return value; + } - if (isNull(columnIndex)) { - return null; - } + public Date getDate(int columnIndex) throws SQLException { + preAccessor(columnIndex); - return this.row.getTime(columnIndex, cal); - } - - public Time getTime(String columnLabel, Calendar cal) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getTime(columnIndex, cal); - } + NullDateTime nullDateTime = getNullDateTime(columnIndex); + return getNullableDate(columnIndex, nullDateTime, null); + } - public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { - preAccessor(columnIndex); + public Time getTime(int columnIndex) throws SQLException { + preAccessor(columnIndex); - NullDateTime nullDateTime = getNullDateTime(columnIndex); - return getNullableDateTime(columnIndex, nullDateTime, cal); + if (isNull(columnIndex)) { + return null; } - public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getTimestamp(columnIndex, cal); - } + return this.row.getTime(columnIndex); + } - public boolean isClosed() { - return this.closed; - } + public Timestamp getTimestamp(int columnIndex) throws SQLException { + preAccessor(columnIndex); - public T unwrap(Class iface) throws SQLException { - try { - return iface.cast(this); - } catch (ClassCastException cce) { - throw new SQLException( - Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), cce); - } - } + NullDateTime nullDateTime = getNullDateTime(columnIndex); + return getNullableDateTime(columnIndex, nullDateTime, null); + } - public boolean isWrapperFor(Class iface) throws SQLException { - checkOpen(); - return iface.isInstance(this); - } + public String getString(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getString(columnIndex); + } - private void checkOpen() throws SQLException { - if (closed) - throw new SQLException(Constants.SQLExceptionMessages.CLOSED_RESULT_SET); - } + public boolean getBoolean(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBoolean(columnIndex); + } - private void preAccessor(int columnIndex) throws SQLException { - checkOpen(); + public byte getByte(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getByte(columnIndex); + } - if (columnIndex < 1 || columnIndex > this.fields.size()) { - throw new SQLException( - Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + columnIndex); - } + public short getShort(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getShort(columnIndex); + } - // set last read column index for wasNull() - lastIndexRead = columnIndex; - } + public int getInt(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getInt(columnIndex); + } - protected enum NullDateTime { - NO_CHANGE, - NULL, - ROUND, - } + public long getLong(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getLong(columnIndex); + } - private NullDateTime getNullDateTime(int columnIndex) throws SQLException { - if (isNull(columnIndex)) { - return NullDateTime.NULL; - } + public float getFloat(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getFloat(columnIndex); + } - if (!hasZeroDateTimePrefix(columnIndex)) { - return NullDateTime.NO_CHANGE; - } + public double getDouble(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getDouble(columnIndex); + } - switch (this.vitessStatement.getConnection().getZeroDateTimeBehavior()) { - case CONVERTTONULL: - return NullDateTime.NULL; - case EXCEPTION: - throw new SQLException( - Constants.SQLExceptionMessages.ZERO_TIMESTAMP + ": " + columnIndex); - case ROUND: - return NullDateTime.ROUND; - case GARBLE: - default: - return NullDateTime.NO_CHANGE; - } - } + public BigDecimal getBigDecimal(String columnLabel, int scale) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBigDecimal(columnIndex, scale); + } - private Date getNullableDate(int columnIndex, NullDateTime nullDateTime, Calendar cal) - throws SQLException { - switch (nullDateTime) { - case NULL: - return null; - case ROUND: - return new Date(-1900, 0, 1); - case NO_CHANGE: - default: - if (cal == null) { - return this.row.getDate(columnIndex); - } else { - return this.row.getDate(columnIndex, cal); - } - } - } + public BigInteger getBigInteger(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBigInteger(columnIndex); + } + + public byte[] getBytes(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBytes(columnIndex); + } - private Timestamp getNullableDateTime(int columnIndex, NullDateTime nullDateTime, Calendar cal) - throws SQLException { - switch (nullDateTime) { - case NULL: - return null; - case ROUND: - return new Timestamp(-1900, 0, 1, 0, 0, 0, 0); - case NO_CHANGE: - default: - if (cal == null) { - return this.row.getTimestamp(columnIndex); - } else { - return this.row.getTimestamp(columnIndex, cal); - } - } - } + public Date getDate(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getDate(columnIndex); + } - private boolean hasZeroDateTimePrefix(int columnIndex) throws SQLException { - return this.row.getRawValue(columnIndex).startsWith(Constants.ZERO_DATE_TIME_PREFIX); - } + public Time getTime(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getTime(columnIndex); + } - private boolean isNull(int columnIndex) throws SQLException { - return null == this.row.getObject(columnIndex); - } + public Timestamp getTimestamp(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getTimestamp(columnIndex); + } - //Unsupported Methods + public SQLWarning getWarnings() throws SQLException { + checkOpen(); + //no-op, All exceptions thrown, none kept as warning + return null; + } - public InputStream getAsciiStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public void clearWarnings() throws SQLException { + checkOpen(); + //no-op, All exceptions thrown, none kept as warning + } - public InputStream getUnicodeStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - public InputStream getBinaryStream(int columnIndex) throws SQLException { - preAccessor(columnIndex); - if (isNull(columnIndex)) { - return null; - } - FieldWithMetadata field = this.fields.get(columnIndex - 1); - switch (field.getJavaType()) { - case Types.BIT: - case Types.BINARY: - case Types.VARBINARY: - case Types.BLOB: - case Types.LONGVARBINARY: - return this.row.getBinaryInputStream(columnIndex); - } + public ResultSetMetaData getMetaData() throws SQLException { + return new VitessResultSetMetaData(fields); + } - byte[] bytes = getBytes(columnIndex); + public Object getObject(int columnIndex) throws SQLException { + preAccessor(columnIndex); + + if (isNull(columnIndex)) { + return null; + } + + Object retVal = this.row.getObject(columnIndex); + + FieldWithMetadata field = this.fields.get(columnIndex - 1); + if (field.hasConnectionProperties() && field.getConnectionProperties().isIncludeAllFields() + && retVal instanceof byte[]) { + retVal = convertBytesIfPossible((byte[]) retVal, field); + } + + return retVal; + } + + private Object convertBytesIfPossible(byte[] bytes, FieldWithMetadata field) throws SQLException { + String encoding = field.getEncoding(); + switch (field.getJavaType()) { + case Types.BIT: + if (!field.isSingleBit()) { + return bytes; + } + return byteArrayToBoolean(bytes); + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (!field.isOpaqueBinary()) { + return convertBytesToString(bytes, encoding); + } + return bytes; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + return bytes; + default: + return convertBytesToString(bytes, encoding); + } + } + + private String convertBytesToString(byte[] bytes, String encoding) throws SQLException { + if (encoding == null) { + return StringUtils.toString(bytes); + } else { + try { + return StringUtils.toString(bytes, 0, bytes.length, encoding); + } catch (UnsupportedEncodingException e) { + throw new SQLException("Unsupported character encoding: " + encoding, e); + } + } + } + + public Object getObject(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getObject(columnIndex); + } + + public int findColumn(String columnLabel) throws SQLException { + return this.cursor.findColumn(columnLabel); + } - if (bytes != null) { - return new ByteArrayInputStream(bytes); - } - return null; - } + public BigDecimal getBigDecimal(int columnIndex) throws SQLException { + String bigDecimalString; + BigDecimal value; - public InputStream getAsciiStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + preAccessor(columnIndex); - public InputStream getUnicodeStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (isNull(columnIndex)) { + return null; } - public InputStream getBinaryStream(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getBinaryStream(columnIndex); - } + bigDecimalString = this.getString(columnIndex); - public String getCursorName() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + try { + value = new BigDecimal(bigDecimalString); + } catch (Exception ex) { + throw new SQLException(ex); } - public Reader getCharacterStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + return value; + } - public Reader getCharacterStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public BigDecimal getBigDecimal(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBigDecimal(columnIndex); + } - public boolean isAfterLast() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean isBeforeFirst() throws SQLException { + checkOpen(); + return this.currentRow == 0; + } - public boolean isLast() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean isFirst() throws SQLException { + checkOpen(); + return currentRow == 1; + } - public void beforeFirst() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public int getRow() throws SQLException { + checkOpen(); + return this.currentRow; + } - public void afterLast() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public int getFetchDirection() throws SQLException { + checkOpen(); + return ResultSet.FETCH_FORWARD; + } - public boolean first() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public void setFetchDirection(int direction) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } - public boolean last() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + public int getFetchSize() throws SQLException { + checkOpen(); + return this.fetchSize; + } + + public void setFetchSize(int rows) throws SQLException { + checkOpen(); + if (rows < 0) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "fetch size"); } + this.fetchSize = rows; + } - public boolean absolute(int row) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public int getType() throws SQLException { + checkOpen(); + return ResultSet.TYPE_FORWARD_ONLY; + } - public boolean relative(int rows) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public int getConcurrency() throws SQLException { + checkOpen(); + return ResultSet.CONCUR_READ_ONLY; + } - public boolean previous() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Statement getStatement() throws SQLException { + checkOpen(); + return this.vitessStatement; + } - public boolean rowUpdated() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Date getDate(int columnIndex, Calendar cal) throws SQLException { + preAccessor(columnIndex); - public boolean rowInserted() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + NullDateTime nullDateTime = getNullDateTime(columnIndex); + return getNullableDate(columnIndex, nullDateTime, cal); + } - public boolean rowDeleted() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Date getDate(String columnLabel, Calendar cal) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getDate(columnIndex, cal); + } - public void updateNull(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Time getTime(int columnIndex, Calendar cal) throws SQLException { + preAccessor(columnIndex); - public void updateBoolean(int columnIndex, boolean x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (isNull(columnIndex)) { + return null; } - public void updateByte(int columnIndex, byte x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateShort(int columnIndex, short x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + return this.row.getTime(columnIndex, cal); + } - public void updateInt(int columnIndex, int x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Time getTime(String columnLabel, Calendar cal) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getTime(columnIndex, cal); + } - public void updateLong(int columnIndex, long x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLException { + preAccessor(columnIndex); - public void updateFloat(int columnIndex, float x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + NullDateTime nullDateTime = getNullDateTime(columnIndex); + return getNullableDateTime(columnIndex, nullDateTime, cal); + } - public void updateDouble(int columnIndex, double x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public Timestamp getTimestamp(String columnLabel, Calendar cal) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getTimestamp(columnIndex, cal); + } - public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean isClosed() { + return this.closed; + } - public void updateString(int columnIndex, String x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + public T unwrap(Class iface) throws SQLException { + try { + return iface.cast(this); + } catch (ClassCastException cce) { + throw new SQLException(Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), + cce); } + } - public void updateBytes(int columnIndex, byte[] x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + public boolean isWrapperFor(Class iface) throws SQLException { + checkOpen(); + return iface.isInstance(this); + } - public void updateDate(int columnIndex, Date x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + private void checkOpen() throws SQLException { + if (closed) { + throw new SQLException(Constants.SQLExceptionMessages.CLOSED_RESULT_SET); } + } - public void updateTime(int columnIndex, Time x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + private void preAccessor(int columnIndex) throws SQLException { + checkOpen(); - public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (columnIndex < 1 || columnIndex > this.fields.size()) { + throw new SQLException( + Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + columnIndex); } - public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + // set last read column index for wasNull() + lastIndexRead = columnIndex; + } - public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + protected enum NullDateTime { + NO_CHANGE, NULL, ROUND, + } - public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + private NullDateTime getNullDateTime(int columnIndex) throws SQLException { + if (isNull(columnIndex)) { + return NullDateTime.NULL; } - public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + if (!hasZeroDateTimePrefix(columnIndex)) { + return NullDateTime.NO_CHANGE; } - public void updateObject(int columnIndex, Object x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + switch (this.vitessStatement.getConnection().getZeroDateTimeBehavior()) { + case CONVERTTONULL: + return NullDateTime.NULL; + case EXCEPTION: + throw new SQLException(Constants.SQLExceptionMessages.ZERO_TIMESTAMP + ": " + columnIndex); + case ROUND: + return NullDateTime.ROUND; + case GARBLE: + default: + return NullDateTime.NO_CHANGE; } + } - public void updateNull(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBoolean(String columnLabel, boolean x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateByte(String columnLabel, byte x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateShort(String columnLabel, short x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateInt(String columnLabel, int x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateLong(String columnLabel, long x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateFloat(String columnLabel, float x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateDouble(String columnLabel, double x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateString(String columnLabel, String x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBytes(String columnLabel, byte[] x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateDate(String columnLabel, Date x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateTime(String columnLabel, Time x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(String columnLabel, InputStream x, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(String columnLabel, InputStream x, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(String columnLabel, Reader reader, int length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateObject(String columnLabel, Object x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void insertRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void deleteRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void refreshRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void cancelRowUpdates() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void moveToInsertRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void moveToCurrentRow() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Object getObject(int columnIndex, Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Ref getRef(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Blob getBlob(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Clob getClob(int columnIndex) throws SQLException { - preAccessor(columnIndex); - - if (isNull(columnIndex)) { - return null; + private Date getNullableDate(int columnIndex, NullDateTime nullDateTime, Calendar cal) + throws SQLException { + switch (nullDateTime) { + case NULL: + return null; + case ROUND: + return new Date(-1900, 0, 1); + case NO_CHANGE: + default: + if (cal == null) { + return this.row.getDate(columnIndex); + } else { + return this.row.getDate(columnIndex, cal); } - - return new SerialClob(getString(columnIndex).toCharArray()); - } - - public Array getArray(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Object getObject(String columnLabel, Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Ref getRef(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Blob getBlob(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Clob getClob(String columnLabel) throws SQLException { - int columnIndex = this.findColumn(columnLabel); - return getClob(columnIndex); - } - - public Array getArray(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public URL getURL(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public URL getURL(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } + } - public void updateRef(int columnIndex, Ref x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateRef(String columnLabel, Ref x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(int columnIndex, Blob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(String columnLabel, Blob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(int columnIndex, Clob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(String columnLabel, Clob x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateArray(int columnIndex, Array x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateArray(String columnLabel, Array x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public RowId getRowId(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public RowId getRowId(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateRowId(int columnIndex, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateRowId(String columnLabel, RowId x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getHoldability() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNString(int columnIndex, String nString) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNString(String columnLabel, String nString) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(int columnIndex, NClob nClob) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(String columnLabel, NClob nClob) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public NClob getNClob(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public NClob getNClob(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public SQLXML getSQLXML(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public SQLXML getSQLXML(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public String getNString(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public String getNString(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Reader getNCharacterStream(int columnIndex) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public Reader getNCharacterStream(String columnLabel) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNCharacterStream(String columnLabel, Reader reader, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(int columnIndex, InputStream x, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(String columnLabel, InputStream x, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(String columnLabel, InputStream x, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(String columnLabel, Reader reader, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(int columnIndex, InputStream inputStream, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(String columnLabel, InputStream inputStream, long length) - throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(int columnIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateClob(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(int columnIndex, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void updateNClob(String columnLabel, Reader reader) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public T getObject(int columnIndex, Class type) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public T getObject(String columnLabel, Class type) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - @VisibleForTesting - List getFields() { - return fields; - } - - private boolean byteArrayToBoolean(int columnIndex) throws SQLException { - return byteArrayToBoolean(this.row.getObject(columnIndex)); - } - - private boolean byteArrayToBoolean(Object value) { - if (value == null) { - return false; - } - - if (((byte[]) value).length == 0) { - return false; - } - - byte boolVal = ((byte[]) value)[0]; - - if (boolVal == (byte) '1') { - return true; - } else if (boolVal == (byte) '0') { - return false; - } - - return (boolVal == -1 || boolVal > 0); + private Timestamp getNullableDateTime(int columnIndex, NullDateTime nullDateTime, Calendar cal) + throws SQLException { + switch (nullDateTime) { + case NULL: + return null; + case ROUND: + return new Timestamp(-1900, 0, 1, 0, 0, 0, 0); + case NO_CHANGE: + default: + if (cal == null) { + return this.row.getTimestamp(columnIndex); + } else { + return this.row.getTimestamp(columnIndex, cal); + } } + } + + private boolean hasZeroDateTimePrefix(int columnIndex) throws SQLException { + return this.row.getRawValue(columnIndex).startsWith(Constants.ZERO_DATE_TIME_PREFIX); + } + + private boolean isNull(int columnIndex) throws SQLException { + return null == this.row.getObject(columnIndex); + } + + //Unsupported Methods + + public InputStream getAsciiStream(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public InputStream getUnicodeStream(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public InputStream getBinaryStream(int columnIndex) throws SQLException { + preAccessor(columnIndex); + if (isNull(columnIndex)) { + return null; + } + FieldWithMetadata field = this.fields.get(columnIndex - 1); + switch (field.getJavaType()) { + case Types.BIT: + case Types.BINARY: + case Types.VARBINARY: + case Types.BLOB: + case Types.LONGVARBINARY: + return this.row.getBinaryInputStream(columnIndex); + } + + byte[] bytes = getBytes(columnIndex); + + if (bytes != null) { + return new ByteArrayInputStream(bytes); + } + return null; + } + + public InputStream getAsciiStream(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public InputStream getUnicodeStream(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public InputStream getBinaryStream(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getBinaryStream(columnIndex); + } + + public String getCursorName() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Reader getCharacterStream(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Reader getCharacterStream(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean isAfterLast() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean isLast() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void beforeFirst() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void afterLast() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean first() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean last() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean absolute(int row) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean relative(int rows) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean previous() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean rowUpdated() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean rowInserted() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean rowDeleted() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNull(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBoolean(int columnIndex, boolean x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateByte(int columnIndex, byte x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateShort(int columnIndex, short x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateInt(int columnIndex, int x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateLong(int columnIndex, long x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateFloat(int columnIndex, float x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateDouble(int columnIndex, double x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateString(int columnIndex, String x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBytes(int columnIndex, byte[] x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateDate(int columnIndex, Date x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateTime(int columnIndex, Time x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateObject(int columnIndex, Object x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNull(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBoolean(String columnLabel, boolean x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateByte(String columnLabel, byte x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateShort(String columnLabel, short x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateInt(String columnLabel, int x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateLong(String columnLabel, long x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateFloat(String columnLabel, float x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateDouble(String columnLabel, double x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateString(String columnLabel, String x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBytes(String columnLabel, byte[] x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateDate(String columnLabel, Date x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateTime(String columnLabel, Time x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(String columnLabel, InputStream x, int length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(String columnLabel, Reader reader, int length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateObject(String columnLabel, Object x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void insertRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void deleteRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void refreshRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void cancelRowUpdates() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void moveToInsertRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void moveToCurrentRow() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Object getObject(int columnIndex, Map> map) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Ref getRef(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Blob getBlob(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Clob getClob(int columnIndex) throws SQLException { + preAccessor(columnIndex); + + if (isNull(columnIndex)) { + return null; + } + + return new SerialClob(getString(columnIndex).toCharArray()); + } + + public Array getArray(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Object getObject(String columnLabel, Map> map) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Ref getRef(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Blob getBlob(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Clob getClob(String columnLabel) throws SQLException { + int columnIndex = this.findColumn(columnLabel); + return getClob(columnIndex); + } + + public Array getArray(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public URL getURL(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public URL getURL(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRef(int columnIndex, Ref x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRef(String columnLabel, Ref x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(int columnIndex, Blob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(String columnLabel, Blob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(int columnIndex, Clob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(String columnLabel, Clob x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateArray(int columnIndex, Array x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateArray(String columnLabel, Array x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public RowId getRowId(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public RowId getRowId(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRowId(int columnIndex, RowId x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateRowId(String columnLabel, RowId x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getHoldability() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNString(int columnIndex, String nString) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNString(String columnLabel, String nString) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(int columnIndex, NClob nClob) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(String columnLabel, NClob nClob) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public NClob getNClob(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public NClob getNClob(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public SQLXML getSQLXML(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public SQLXML getSQLXML(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateSQLXML(String columnLabel, SQLXML xmlObject) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public String getNString(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public String getNString(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Reader getNCharacterStream(int columnIndex) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public Reader getNCharacterStream(String columnLabel) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNCharacterStream(String columnLabel, Reader reader, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(String columnLabel, InputStream x, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(String columnLabel, InputStream x, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(String columnLabel, Reader reader, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(int columnIndex, InputStream inputStream, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(String columnLabel, InputStream inputStream, long length) + throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(int columnIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateClob(String columnLabel, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(int columnIndex, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void updateNClob(String columnLabel, Reader reader) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public T getObject(int columnIndex, Class type) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public T getObject(String columnLabel, Class type) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + @VisibleForTesting + List getFields() { + return fields; + } + + private boolean byteArrayToBoolean(int columnIndex) throws SQLException { + return byteArrayToBoolean(this.row.getObject(columnIndex)); + } + + private boolean byteArrayToBoolean(Object value) { + if (value == null) { + return false; + } + + if (((byte[]) value).length == 0) { + return false; + } + + byte boolVal = ((byte[]) value)[0]; + + if (boolVal == (byte) '1') { + return true; + } else if (boolVal == (byte) '0') { + return false; + } + + return (boolVal == -1 || boolVal > 0); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java index 8eddb40752f..93a260ebab5 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -33,363 +33,364 @@ */ public class VitessResultSetMetaData implements ResultSetMetaData { - /* Get actual class name to be printed on */ - private static Logger logger = Logger.getLogger(VitessResultSetMetaData.class.getName()); - private List fields; - - public VitessResultSetMetaData(List fields) throws SQLException { - this.fields = ImmutableList.copyOf(fields); - } - - public int getColumnCount() throws SQLException { - return fields.size(); - } - - public boolean isAutoIncrement(int column) throws SQLException { - return getField(column).isAutoIncrement(); - } - - public boolean isCaseSensitive(int column) throws SQLException { - FieldWithMetadata field = getField(column); - switch (field.getJavaType()) { - case Types.BIT: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - case Types.DATE: - case Types.DECIMAL: - case Types.NUMERIC: - case Types.TIME: - case Types.TIMESTAMP: - return false; - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - if (field.isBinary() || !field.getConnectionProperties().isIncludeAllFields()) { - return true; - } - try { - String collationName = field.getCollation(); - return collationName != null && !collationName.endsWith("_ci"); - } catch (SQLException e) { - if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { - return false; - } else { - throw e; - } - } - default: - return true; - } - } - - public boolean isSearchable(int column) throws SQLException { - return true; - } - - public boolean isCurrency(int column) throws SQLException { + /* Get actual class name to be printed on */ + private static Logger logger = Logger.getLogger(VitessResultSetMetaData.class.getName()); + private List fields; + + public VitessResultSetMetaData(List fields) throws SQLException { + this.fields = ImmutableList.copyOf(fields); + } + + public int getColumnCount() throws SQLException { + return fields.size(); + } + + public boolean isAutoIncrement(int column) throws SQLException { + return getField(column).isAutoIncrement(); + } + + public boolean isCaseSensitive(int column) throws SQLException { + FieldWithMetadata field = getField(column); + switch (field.getJavaType()) { + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.DATE: + case Types.DECIMAL: + case Types.NUMERIC: + case Types.TIME: + case Types.TIMESTAMP: return false; - } - - /** - * Indicates the nullability of values in the designated column. - * - * @param column the first column is 1, the second is 2, ... - * @return the nullability status of the given column; one of columnNoNulls, - * columnNullable or columnNullableUnknown - * @exception SQLException if a database access error occurs - */ - public int isNullable(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (!field.getConnectionProperties().isIncludeAllFields()) { - return ResultSetMetaData.columnNullableUnknown; + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (field.isBinary() || !field.getConnectionProperties().isIncludeAllFields()) { + return true; } - return field.isNotNull() ? ResultSetMetaData.columnNoNulls : ResultSetMetaData.columnNullable; - } - - public boolean isSigned(int column) throws SQLException { - return getField(column).isSigned(); - } - - public int getColumnDisplaySize(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (!field.getConnectionProperties().isIncludeAllFields()) { - return 0; + try { + String collationName = field.getCollation(); + return collationName != null && !collationName.endsWith("_ci"); + } catch (SQLException e) { + if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { + return false; + } else { + throw e; + } } - // If we can't find a charset, we'll return 0. In that case assume 1 byte per char - return field.getColumnLength() / Math.max(field.getMaxBytesPerCharacter(), 1); + default: + return true; } - - public String getColumnLabel(int column) throws SQLException { - return getField(column).getName(); + } + + public boolean isSearchable(int column) throws SQLException { + return true; + } + + public boolean isCurrency(int column) throws SQLException { + return false; + } + + /** + * Indicates the nullability of values in the designated column. + * + * @param column the first column is 1, the second is 2, ... + * @return the nullability status of the given column; one of columnNoNulls, + * columnNullable or columnNullableUnknown + * @throws SQLException if a database access error occurs + */ + public int isNullable(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (!field.getConnectionProperties().isIncludeAllFields()) { + return ResultSetMetaData.columnNullableUnknown; } + return field.isNotNull() ? ResultSetMetaData.columnNoNulls : ResultSetMetaData.columnNullable; + } - public String getColumnName(int column) throws SQLException { - return getField(column).getName(); - } + public boolean isSigned(int column) throws SQLException { + return getField(column).isSigned(); + } - public String getSchemaName(int column) throws SQLException { - return getField(column).getDatabase(); + public int getColumnDisplaySize(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (!field.getConnectionProperties().isIncludeAllFields()) { + return 0; } - - public int getPrecision(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (!field.getConnectionProperties().isIncludeAllFields()) { - return 0; - } - if (isDecimalType(field.getJavaType(), field.getVitessTypeValue())) { - return field.getColumnLength() + field.getPrecisionAdjustFactor(); - } - switch (field.getJavaType()) { - case Types.VARBINARY: - case Types.LONGVARBINARY: - return field.getColumnLength(); - default: - return field.getColumnLength() / field.getMaxBytesPerCharacter(); - } + // If we can't find a charset, we'll return 0. In that case assume 1 byte per char + return field.getColumnLength() / Math.max(field.getMaxBytesPerCharacter(), 1); + } + + public String getColumnLabel(int column) throws SQLException { + return getField(column).getName(); + } + + public String getColumnName(int column) throws SQLException { + return getField(column).getName(); + } + + public String getSchemaName(int column) throws SQLException { + return getField(column).getDatabase(); + } + + public int getPrecision(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (!field.getConnectionProperties().isIncludeAllFields()) { + return 0; } - - private static boolean isDecimalType(int javaType, int vitessType) { - switch (javaType) { - case Types.BIT: - case Types.TINYINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - case Types.NUMERIC: - case Types.DECIMAL: - return true; - case Types.SMALLINT: - return vitessType != Query.Type.YEAR_VALUE; - default: - return false; - } + if (isDecimalType(field.getJavaType(), field.getVitessTypeValue())) { + return field.getColumnLength() + field.getPrecisionAdjustFactor(); } - - public int getScale(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (isDecimalType(field.getJavaType(), field.getVitessTypeValue())) { - return getField(column).getDecimals(); - } - return 0; + switch (field.getJavaType()) { + case Types.VARBINARY: + case Types.LONGVARBINARY: + return field.getColumnLength(); + default: + return field.getColumnLength() / field.getMaxBytesPerCharacter(); } - - public String getTableName(int column) throws SQLException { - return getField(column).getTable(); + } + + private static boolean isDecimalType(int javaType, int vitessType) { + switch (javaType) { + case Types.BIT: + case Types.TINYINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.NUMERIC: + case Types.DECIMAL: + return true; + case Types.SMALLINT: + return vitessType != Query.Type.YEAR_VALUE; + default: + return false; } + } - public String getCatalogName(int column) throws SQLException { - return getField(column).getDatabase(); + public int getScale(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (isDecimalType(field.getJavaType(), field.getVitessTypeValue())) { + return getField(column).getDecimals(); } + return 0; + } - public int getColumnType(int column) throws SQLException { - return getField(column).getJavaType(); - } + public String getTableName(int column) throws SQLException { + return getField(column).getTable(); + } - public String getColumnTypeName(int column) throws SQLException { - FieldWithMetadata field = getField(column); + public String getCatalogName(int column) throws SQLException { + return getField(column).getDatabase(); + } - int vitessTypeValue = field.getVitessTypeValue(); - int javaType = field.getJavaType(); + public int getColumnType(int column) throws SQLException { + return getField(column).getJavaType(); + } - switch (vitessTypeValue) { - case Query.Type.BIT_VALUE: - return "BIT"; + public String getColumnTypeName(int column) throws SQLException { + FieldWithMetadata field = getField(column); - case Query.Type.DECIMAL_VALUE: - return "DECIMAL"; + int vitessTypeValue = field.getVitessTypeValue(); + int javaType = field.getJavaType(); - case Query.Type.INT8_VALUE: - return "TINYINT"; - case Query.Type.UINT8_VALUE: - return "TINYINT UNSIGNED"; + switch (vitessTypeValue) { + case Query.Type.BIT_VALUE: + return "BIT"; - case Query.Type.INT16_VALUE: - return "SMALLINT"; - case Query.Type.UINT16_VALUE: - return "SMALLINT UNSIGNED"; + case Query.Type.DECIMAL_VALUE: + return "DECIMAL"; - case Query.Type.INT24_VALUE: - return "MEDIUMINT"; - case Query.Type.UINT24_VALUE: - return "MEDIUMINT UNSIGNED"; + case Query.Type.INT8_VALUE: + return "TINYINT"; + case Query.Type.UINT8_VALUE: + return "TINYINT UNSIGNED"; - case Query.Type.INT32_VALUE: - return "INT"; - case Query.Type.UINT32_VALUE: - return "INT UNSIGNED"; + case Query.Type.INT16_VALUE: + return "SMALLINT"; + case Query.Type.UINT16_VALUE: + return "SMALLINT UNSIGNED"; - case Query.Type.INT64_VALUE: - return "BIGINT"; - case Query.Type.UINT64_VALUE: - return "BIGINT UNSIGNED"; + case Query.Type.INT24_VALUE: + return "MEDIUMINT"; + case Query.Type.UINT24_VALUE: + return "MEDIUMINT UNSIGNED"; - case Query.Type.FLOAT32_VALUE: - return "FLOAT"; + case Query.Type.INT32_VALUE: + return "INT"; + case Query.Type.UINT32_VALUE: + return "INT UNSIGNED"; - case Query.Type.FLOAT64_VALUE: - return "DOUBLE"; + case Query.Type.INT64_VALUE: + return "BIGINT"; + case Query.Type.UINT64_VALUE: + return "BIGINT UNSIGNED"; - case Query.Type.NULL_TYPE_VALUE: - return "NULL"; + case Query.Type.FLOAT32_VALUE: + return "FLOAT"; - case Query.Type.TIMESTAMP_VALUE: - return "TIMESTAMP"; + case Query.Type.FLOAT64_VALUE: + return "DOUBLE"; - case Query.Type.DATE_VALUE: - return "DATE"; + case Query.Type.NULL_TYPE_VALUE: + return "NULL"; - case Query.Type.TIME_VALUE: - return "TIME"; + case Query.Type.TIMESTAMP_VALUE: + return "TIMESTAMP"; - case Query.Type.DATETIME_VALUE: - return "DATETIME"; + case Query.Type.DATE_VALUE: + return "DATE"; - case Query.Type.BLOB_VALUE: - return "BLOB"; + case Query.Type.TIME_VALUE: + return "TIME"; - case Query.Type.TEXT_VALUE: - return "TEXT"; + case Query.Type.DATETIME_VALUE: + return "DATETIME"; - case Query.Type.VARCHAR_VALUE: - return "VARCHAR"; + case Query.Type.BLOB_VALUE: + return "BLOB"; - case Query.Type.VARBINARY_VALUE: - if (javaType == Types.VARBINARY) { - return "VARBINARY"; - } - return "VARCHAR"; + case Query.Type.TEXT_VALUE: + return "TEXT"; - case Query.Type.BINARY_VALUE: - if (javaType == Types.BINARY) { - return "BINARY"; - } - return "CHAR"; + case Query.Type.VARCHAR_VALUE: + return "VARCHAR"; - case Query.Type.CHAR_VALUE: - return "CHAR"; + case Query.Type.VARBINARY_VALUE: + if (javaType == Types.VARBINARY) { + return "VARBINARY"; + } + return "VARCHAR"; - case Query.Type.ENUM_VALUE: - return "ENUM"; + case Query.Type.BINARY_VALUE: + if (javaType == Types.BINARY) { + return "BINARY"; + } + return "CHAR"; - case Query.Type.YEAR_VALUE: - return "YEAR"; + case Query.Type.CHAR_VALUE: + return "CHAR"; - case Query.Type.SET_VALUE: - return "SET"; + case Query.Type.ENUM_VALUE: + return "ENUM"; - case Query.Type.TUPLE_VALUE: - return "TUPLE"; + case Query.Type.YEAR_VALUE: + return "YEAR"; - default: - return "UNKNOWN"; - } - } + case Query.Type.SET_VALUE: + return "SET"; - public boolean isReadOnly(int column) throws SQLException { - return getField(column).isReadOnly(); - } + case Query.Type.TUPLE_VALUE: + return "TUPLE"; - public boolean isWritable(int column) throws SQLException { - return !isReadOnly(column); + default: + return "UNKNOWN"; } + } - public boolean isDefinitelyWritable(int column) throws SQLException { - return isWritable(column); - } + public boolean isReadOnly(int column) throws SQLException { + return getField(column).isReadOnly(); + } - public String getColumnClassName(int column) throws SQLException { - FieldWithMetadata field = getField(column); - if (!field.getConnectionProperties().isIncludeAllFields()) { - return null; - } - return getClassNameForJavaType(field.getJavaType(), field.getVitessTypeValue(), field.isUnsigned(), - field.isBinary() || field.isBlob(), field.isOpaqueBinary(), field.getConnectionProperties().getYearIsDateType()); - } + public boolean isWritable(int column) throws SQLException { + return !isReadOnly(column); + } - public T unwrap(Class iface) throws SQLException { - return null; - } + public boolean isDefinitelyWritable(int column) throws SQLException { + return isWritable(column); + } - public boolean isWrapperFor(Class iface) throws SQLException { - return false; + public String getColumnClassName(int column) throws SQLException { + FieldWithMetadata field = getField(column); + if (!field.getConnectionProperties().isIncludeAllFields()) { + return null; } - - private FieldWithMetadata getField(int columnIndex) throws SQLException { - if (columnIndex >= 1 && columnIndex <= this.fields.size()) { - return fields.get(columnIndex - 1); - } else { - throw new SQLException( - Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + columnIndex); - } + return getClassNameForJavaType(field.getJavaType(), field.getVitessTypeValue(), + field.isUnsigned(), field.isBinary() || field.isBlob(), field.isOpaqueBinary(), + field.getConnectionProperties().getYearIsDateType()); + } + + public T unwrap(Class iface) throws SQLException { + return null; + } + + public boolean isWrapperFor(Class iface) throws SQLException { + return false; + } + + private FieldWithMetadata getField(int columnIndex) throws SQLException { + if (columnIndex >= 1 && columnIndex <= this.fields.size()) { + return fields.get(columnIndex - 1); + } else { + throw new SQLException( + Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + columnIndex); } - - private String getClassNameForJavaType(int javaType, int vitessType, boolean isUnsigned, boolean isBinaryOrBlob, boolean isOpaqueBinary, - boolean treatYearAsDate) { - switch (javaType) { - case Types.BIT: - case Types.BOOLEAN: - return "java.lang.Boolean"; - case Types.TINYINT: - if (isUnsigned) { - return "java.lang.Integer"; - } - return "java.lang.Integer"; - case Types.SMALLINT: - if (vitessType == Query.Type.YEAR_VALUE) { - return treatYearAsDate ? "java.sql.Date" : "java.lang.Short"; - } - if (isUnsigned) { - return "java.lang.Integer"; - } - return "java.lang.Integer"; - case Types.INTEGER: - if (!isUnsigned || vitessType == Query.Type.UINT24_VALUE) { - return "java.lang.Integer"; - } - return "java.lang.Long"; - case Types.BIGINT: - if (!isUnsigned) { - return "java.lang.Long"; - } - return "java.math.BigInteger"; - case Types.DECIMAL: - case Types.NUMERIC: - return "java.math.BigDecimal"; - case Types.REAL: - return "java.lang.Float"; - case Types.FLOAT: - case Types.DOUBLE: - return "java.lang.Double"; - case Types.CHAR: - case Types.VARCHAR: - case Types.LONGVARCHAR: - if (!isOpaqueBinary) { - return "java.lang.String"; - } - return "[B"; - case Types.BINARY: - case Types.VARBINARY: - case Types.LONGVARBINARY: - if (isBinaryOrBlob) { - return "[B"; - } else { - return "java.lang.String"; - } - case Types.DATE: - return treatYearAsDate ? "java.sql.Date" : "java.lang.Short"; - case Types.TIME: - return "java.sql.Time"; - case Types.TIMESTAMP: - return "java.sql.Timestamp"; - default: - return "java.lang.Object"; + } + + private String getClassNameForJavaType(int javaType, int vitessType, boolean isUnsigned, + boolean isBinaryOrBlob, boolean isOpaqueBinary, boolean treatYearAsDate) { + switch (javaType) { + case Types.BIT: + case Types.BOOLEAN: + return "java.lang.Boolean"; + case Types.TINYINT: + if (isUnsigned) { + return "java.lang.Integer"; + } + return "java.lang.Integer"; + case Types.SMALLINT: + if (vitessType == Query.Type.YEAR_VALUE) { + return treatYearAsDate ? "java.sql.Date" : "java.lang.Short"; + } + if (isUnsigned) { + return "java.lang.Integer"; + } + return "java.lang.Integer"; + case Types.INTEGER: + if (!isUnsigned || vitessType == Query.Type.UINT24_VALUE) { + return "java.lang.Integer"; + } + return "java.lang.Long"; + case Types.BIGINT: + if (!isUnsigned) { + return "java.lang.Long"; + } + return "java.math.BigInteger"; + case Types.DECIMAL: + case Types.NUMERIC: + return "java.math.BigDecimal"; + case Types.REAL: + return "java.lang.Float"; + case Types.FLOAT: + case Types.DOUBLE: + return "java.lang.Double"; + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + if (!isOpaqueBinary) { + return "java.lang.String"; + } + return "[B"; + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + if (isBinaryOrBlob) { + return "[B"; + } else { + return "java.lang.String"; } + case Types.DATE: + return treatYearAsDate ? "java.sql.Date" : "java.lang.Short"; + case Types.TIME: + return "java.sql.Time"; + case Types.TIMESTAMP: + return "java.sql.Timestamp"; + default: + return "java.lang.Object"; } + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java index bde82e6f01e..de76f81038d 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -39,176 +39,169 @@ * Created by harshit.gangal on 19/01/16. *

* This class expects an sql query to be provided when a call to DB is made by the method: - * execute(sql), executeQuery(sql), executeUpdate(sql). - * When executeBatch() is called, the sql is not required; - * instead all the queries to be executed must be added via the addBatch(sql) method. - * In all the cases, once a method is called, - * no reference of the query/queries provided is/are kept. + * execute(sql), executeQuery(sql), executeUpdate(sql). When executeBatch() is called, the sql is + * not required; instead all the queries to be executed must be added via the addBatch(sql) method. + * In all the cases, once a method is called, no reference of the query/queries provided is/are + * kept. */ public class VitessStatement implements Statement { - protected static final String[] ON_DUPLICATE_KEY_UPDATE_CLAUSE = new String[] { "ON", "DUPLICATE", "KEY", "UPDATE" }; - protected VitessResultSet vitessResultSet; - protected VitessConnection vitessConnection; - protected boolean closed; - protected long resultCount; - protected long queryTimeoutInMillis; - protected int maxFieldSize = Constants.MAX_BUFFER_SIZE; - protected int maxRows = 0; - protected int fetchSize = 0; - protected int resultSetConcurrency; - protected int resultSetType; - protected boolean retrieveGeneratedKeys = false; - protected long generatedId = -1; - protected long[][] batchGeneratedKeys; - /** - * Holds batched commands - */ - private List batchedArgs; - - - public VitessStatement(VitessConnection vitessConnection) { - this(vitessConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - } - - public VitessStatement(VitessConnection vitessConnection, int resultSetType, - int resultSetConcurrency) { - this.vitessConnection = vitessConnection; - this.queryTimeoutInMillis = vitessConnection.getTimeout(); - this.vitessResultSet = null; - this.resultSetType = resultSetType; - this.resultSetConcurrency = resultSetConcurrency; - this.closed = false; - this.resultCount = -1; - this.vitessConnection.registerStatement(this); - this.batchedArgs = new ArrayList<>(); - this.batchGeneratedKeys = null; - } - - /** - * To execute an Select/Show Statement - * - * @param sql - SQL Query - * @return ResultSet - * @throws SQLException - */ - public ResultSet executeQuery(String sql) throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - - checkOpen(); - checkSQLNullOrEmpty(sql); - closeOpenResultSetAndResetCount(); - - if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method - throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); - } - - //Setting to default value - this.retrieveGeneratedKeys = false; - this.generatedId = -1; - - vtGateConn = this.vitessConnection.getVtGateConn(); - - if ((vitessConnection.isSimpleExecute() && this.fetchSize == 0) || vitessConnection.isInTransaction()) { - checkAndBeginTransaction(); - Context context = - this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); - } else { - /* Stream query is not suppose to run in a txn. */ - Context context = - this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.streamExecute(context, sql, null, vitessConnection.getVtSession()); - } - - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } - this.vitessResultSet = new VitessResultSet(cursor, this); - return this.vitessResultSet; - } - - /** - * To execute a DML statement - * - * @param sql - SQL Query - * @return Rows Affected Count - * @throws SQLException - */ - public int executeUpdate(String sql) throws SQLException { - return executeUpdate(sql, Statement.NO_GENERATED_KEYS); - } - - /** - * To Execute Unknown Statement - * - * @param sql - * @return - * @throws SQLException - */ - public boolean execute(String sql) throws SQLException { - return execute(sql, Statement.NO_GENERATED_KEYS); - } - - /** - * To get the resultSet generated - * - * @return ResultSet - * @throws SQLException - */ - public ResultSet getResultSet() throws SQLException { - checkOpen(); - return this.vitessResultSet; - } - - public int getUpdateCount() throws SQLException { - int truncatedUpdateCount; - - checkOpen(); + protected static final String[] ON_DUPLICATE_KEY_UPDATE_CLAUSE = new String[]{"ON", "DUPLICATE", + "KEY", "UPDATE"}; + protected VitessResultSet vitessResultSet; + protected VitessConnection vitessConnection; + protected boolean closed; + protected long resultCount; + protected long queryTimeoutInMillis; + protected int maxFieldSize = Constants.MAX_BUFFER_SIZE; + protected int maxRows = 0; + protected int fetchSize = 0; + protected int resultSetConcurrency; + protected int resultSetType; + protected boolean retrieveGeneratedKeys = false; + protected long generatedId = -1; + protected long[][] batchGeneratedKeys; + /** + * Holds batched commands + */ + private List batchedArgs; + + + public VitessStatement(VitessConnection vitessConnection) { + this(vitessConnection, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + } + + public VitessStatement(VitessConnection vitessConnection, int resultSetType, + int resultSetConcurrency) { + this.vitessConnection = vitessConnection; + this.queryTimeoutInMillis = vitessConnection.getTimeout(); + this.vitessResultSet = null; + this.resultSetType = resultSetType; + this.resultSetConcurrency = resultSetConcurrency; + this.closed = false; + this.resultCount = -1; + this.vitessConnection.registerStatement(this); + this.batchedArgs = new ArrayList<>(); + this.batchGeneratedKeys = null; + } + + /** + * To execute an Select/Show Statement + * + * @param sql - SQL Query + * @return ResultSet + */ + public ResultSet executeQuery(String sql) throws SQLException { + VTGateConnection vtGateConn; + Cursor cursor; + + checkOpen(); + checkSQLNullOrEmpty(sql); + closeOpenResultSetAndResetCount(); + + if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method + throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); + } + + //Setting to default value + this.retrieveGeneratedKeys = false; + this.generatedId = -1; + + vtGateConn = this.vitessConnection.getVtGateConn(); + + if ((vitessConnection.isSimpleExecute() && this.fetchSize == 0) || vitessConnection + .isInTransaction()) { + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); + } else { + /* Stream query is not suppose to run in a txn. */ + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn.streamExecute(context, sql, null, vitessConnection.getVtSession()); + } + + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + this.vitessResultSet = new VitessResultSet(cursor, this); + return this.vitessResultSet; + } + + /** + * To execute a DML statement + * + * @param sql - SQL Query + * @return Rows Affected Count + */ + public int executeUpdate(String sql) throws SQLException { + return executeUpdate(sql, Statement.NO_GENERATED_KEYS); + } + + /** + * To Execute Unknown Statement + */ + public boolean execute(String sql) throws SQLException { + return execute(sql, Statement.NO_GENERATED_KEYS); + } + + /** + * To get the resultSet generated + * + * @return ResultSet + */ + public ResultSet getResultSet() throws SQLException { + checkOpen(); + return this.vitessResultSet; + } + + public int getUpdateCount() throws SQLException { + int truncatedUpdateCount; + + checkOpen(); + + if (null != this.vitessResultSet) { + return -1; + } + + if (this.resultCount > Integer.MAX_VALUE) { + truncatedUpdateCount = Integer.MAX_VALUE; + } else { + truncatedUpdateCount = (int) this.resultCount; + } + return truncatedUpdateCount; + } + + public void close() throws SQLException { + SQLException postponedSQLException = null; + + if (!this.closed) { + if (null != this.vitessConnection) { + this.vitessConnection.unregisterStatement(this); + } + try { if (null != this.vitessResultSet) { - return -1; + this.vitessResultSet.close(); } + } catch (SQLException ex) { + postponedSQLException = ex; + } - if (this.resultCount > Integer.MAX_VALUE) { - truncatedUpdateCount = Integer.MAX_VALUE; - } else { - truncatedUpdateCount = (int) this.resultCount; - } - return truncatedUpdateCount; - } - - public void close() throws SQLException { - SQLException postponedSQLException = null; - - if (!this.closed) { - if (null != this.vitessConnection) { - this.vitessConnection.unregisterStatement(this); - } - try { - if (null != this.vitessResultSet) { - this.vitessResultSet.close(); - } - } catch (SQLException ex) { - postponedSQLException = ex; - } - - this.vitessConnection = null; - this.vitessResultSet = null; - this.closed = true; + this.vitessConnection = null; + this.vitessResultSet = null; + this.closed = true; - if (null != postponedSQLException) { - throw postponedSQLException; - } - } + if (null != postponedSQLException) { + throw postponedSQLException; + } } + } - public int getMaxFieldSize() throws SQLException { - checkOpen(); - return this.maxFieldSize; - } + public int getMaxFieldSize() throws SQLException { + checkOpen(); + return this.maxFieldSize; + } - public void setMaxFieldSize(int max) throws SQLException { + public void setMaxFieldSize(int max) throws SQLException { /* Currently not used checkOpen(); if (max < 0 || max > Constants.MAX_BUFFER_SIZE) { @@ -217,527 +210,510 @@ public void setMaxFieldSize(int max) throws SQLException { } this.maxFieldSize = max; */ - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getMaxRows() throws SQLException { - checkOpen(); - return this.maxRows; - } - - public void setMaxRows(int max) throws SQLException { - checkOpen(); - if (max < 0) { - throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "max row"); - } - this.maxRows = max; - } - - public int getQueryTimeout() throws SQLException { - checkOpen(); - return (int) (this.queryTimeoutInMillis / 1000); - } - - public void setQueryTimeout(int seconds) throws SQLException { - checkOpen(); - if (seconds < 0) { - throw new SQLException( - Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "query timeout"); + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getMaxRows() throws SQLException { + checkOpen(); + return this.maxRows; + } + + public void setMaxRows(int max) throws SQLException { + checkOpen(); + if (max < 0) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "max row"); + } + this.maxRows = max; + } + + public int getQueryTimeout() throws SQLException { + checkOpen(); + return (int) (this.queryTimeoutInMillis / 1000); + } + + public void setQueryTimeout(int seconds) throws SQLException { + checkOpen(); + if (seconds < 0) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "query timeout"); + } + this.queryTimeoutInMillis = + (0 == seconds) ? vitessConnection.getTimeout() : (long) seconds * 1000; + } + + /** + * Return Warnings + *

+ * Not implementing as Error is Thrown when occurred + * + * @return SQLWarning or null + */ + public SQLWarning getWarnings() throws SQLException { + checkOpen(); + return null; + } + + /** + * Clear the warnings - Not saving Warnings + */ + public void clearWarnings() { + //no-op + } + + public void setCursorName(String name) throws SQLException { + checkOpen(); + } + + public int getFetchDirection() throws SQLException { + checkOpen(); + return ResultSet.FETCH_FORWARD; + } + + public void setFetchDirection(int direction) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getFetchSize() throws SQLException { + checkOpen(); + return this.fetchSize; + } + + public void setFetchSize(int rows) throws SQLException { + checkOpen(); + if (rows < 0) { + throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "fetch size"); + } + this.fetchSize = rows; + } + + public int getResultSetConcurrency() throws SQLException { + checkOpen(); + return this.resultSetConcurrency; + } + + public int getResultSetType() throws SQLException { + checkOpen(); + return this.resultSetType; + } + + public VitessConnection getConnection() throws SQLException { + checkOpen(); + return vitessConnection; + } + + public boolean isClosed() { + return this.closed; + } + + /** + * Unwrap a class + * + * @param iface - A Class defining an interface that the result must implement. + * @param - the type of the class modeled by this Class object + * @return an object that implements the interface. May be a proxy for the actual implementing + * object. + */ + public T unwrap(Class iface) throws SQLException { + try { + return iface.cast(this); + } catch (ClassCastException cce) { + throw new SQLException(Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), + cce); + } + } + + /** + * Checking Wrapper + * + * @param iface - A Class defining an interface that the result must implement. + * @return true if this implements the interface or directly or indirectly wraps an object that + * does. + */ + public boolean isWrapperFor(Class iface) throws SQLException { + checkOpen(); + return iface.isInstance(this); + } + + /** + * + */ + public ResultSet getGeneratedKeys() throws SQLException { + checkOpen(); + if (!this.retrieveGeneratedKeys) { + throw new SQLException(Constants.SQLExceptionMessages.GENERATED_KEYS_NOT_REQUESTED); + } + + String[] columnNames = new String[1]; + columnNames[0] = "GENERATED_KEY"; + Query.Type[] columnTypes = new Query.Type[1]; + columnTypes[0] = Query.Type.UINT64; + String[][] data = null; + + if (this.generatedId > 0) { + // This is as per Mysql JDBC Driver. + // As the actual count of generated value is not known, + // only the rows affected is known, so using firstInsertId all the auto_inc values + // are generated. As per Vitess Config, the increment value is 1 and not changeable. + data = new String[(int) this.resultCount][1]; + for (int i = 0; i < this.resultCount; ++i) { + data[i][0] = String.valueOf(this.generatedId + i); + } + } else if (this.batchGeneratedKeys != null) { + long totalAffected = 0; + for (long[] batchGeneratedKey : this.batchGeneratedKeys) { + long rowsAffected = batchGeneratedKey[1]; + totalAffected += rowsAffected; + } + data = new String[(int) totalAffected][1]; + int idx = 0; + for (long[] batchGeneratedKey : this.batchGeneratedKeys) { + long insertId = batchGeneratedKey[0]; + long rowsAffected = batchGeneratedKey[1]; + for (int j = 0; j < rowsAffected; j++) { + data[idx++][0] = String.valueOf(insertId + j); } - this.queryTimeoutInMillis = - (0 == seconds) ? vitessConnection.getTimeout() : (long) seconds * 1000; - } - - /** - * Return Warnings - *

- * Not implementing as Error is Thrown when occurred - * - * @return SQLWarning or null - * @throws SQLException - */ - public SQLWarning getWarnings() throws SQLException { - checkOpen(); - return null; - } - - /** - * Clear the warnings - Not saving Warnings - * - */ - public void clearWarnings() { - //no-op - } - - public void setCursorName(String name) throws SQLException { - checkOpen(); - } - - public int getFetchDirection() throws SQLException { - checkOpen(); - return ResultSet.FETCH_FORWARD; - } - - public void setFetchDirection(int direction) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getFetchSize() throws SQLException { - checkOpen(); - return this.fetchSize; - } - - public void setFetchSize(int rows) throws SQLException { - checkOpen(); - if (rows < 0) { - throw new SQLException(Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "fetch size"); - } - this.fetchSize = rows; - } - - public int getResultSetConcurrency() throws SQLException { - checkOpen(); - return this.resultSetConcurrency; - } - - public int getResultSetType() throws SQLException { - checkOpen(); - return this.resultSetType; - } - - public VitessConnection getConnection() throws SQLException { - checkOpen(); - return vitessConnection; - } - - public boolean isClosed() { - return this.closed; - } - - /** - * Unwrap a class - * - * @param iface - A Class defining an interface that the result must implement. - * @param - the type of the class modeled by this Class object - * @return an object that implements the interface. May be a proxy for the actual implementing object. - * @throws SQLException - */ - public T unwrap(Class iface) throws SQLException { + } + } + return new VitessResultSet(columnNames, columnTypes, data, this.vitessConnection); + } + + /** + * To execute DML statement + * + * @param sql - SQL Query + * @param autoGeneratedKeys - Flag for generated Keys + * @return Row Affected Count + */ + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { + VTGateConnection vtGateConn; + Cursor cursor; + int truncatedUpdateCount; + + checkOpen(); + checkNotReadOnly(); + checkSQLNullOrEmpty(sql); + closeOpenResultSetAndResetCount(); + + if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method + throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); + } + + vtGateConn = this.vitessConnection.getVtGateConn(); + + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); + + if (null == cursor) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + if (!(null == cursor.getFields() || cursor.getFields().isEmpty())) { + throw new SQLException(Constants.SQLExceptionMessages.SQL_RETURNED_RESULT_SET); + } + + if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS) { + this.retrieveGeneratedKeys = true; + this.generatedId = cursor.getInsertId(); + } else { + this.retrieveGeneratedKeys = false; + this.generatedId = -1; + } + + this.resultCount = cursor.getRowsAffected(); + + if (this.resultCount > Integer.MAX_VALUE) { + truncatedUpdateCount = Integer.MAX_VALUE; + } else { + truncatedUpdateCount = (int) this.resultCount; + } + + return truncatedUpdateCount; + } + + /** + * To execute Unknown Statement + * + * @param sql - SQL Query + * @param autoGeneratedKeys - Flag for generated Keys + * @return - true if the first result is a ResultSet object; + * false if it is an update count or there are no results + */ + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { + checkOpen(); + checkSQLNullOrEmpty(sql); + closeOpenResultSetAndResetCount(); + + if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method + throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); + } + if (!maybeSelect(sql)) { + this.executeUpdate(sql, autoGeneratedKeys); + return false; + } else { + this.executeQuery(sql); + return true; + } + } + + /** + * Add the query in the batch. + */ + public void addBatch(String sql) throws SQLException { + checkOpen(); + checkSQLNullOrEmpty(sql); + if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method + throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); + } + this.batchedArgs.add(sql); + } + + /** + * Clear all the queries batched. + */ + public void clearBatch() throws SQLException { + checkOpen(); + this.batchedArgs.clear(); + } + + /** + * Submits a batch of commands to the database for execution and if all commands execute + * successfully, returns an array of update counts. The array returned is according to the order + * in which they were added to the batch. + *

+ * If one of the commands in a batch update fails to execute properly, this method throws a + * BatchUpdateException, and a JDBC driver may or may not continue to process the + * remaining commands in the batch. If the driver continues processing after a failure, the array + * returned by the method BatchUpdateException.getUpdateCounts will contain as many + * elements as there are commands in the batch. + * + * @return int[] of results corresponding to each command + */ + public int[] executeBatch() throws SQLException { + checkOpen(); + checkNotReadOnly(); + VTGateConnection vtGateConn; + List cursorWithErrorList; + + if (0 == batchedArgs.size()) { + return new int[0]; + } + + try { + vtGateConn = this.vitessConnection.getVtGateConn(); + + checkAndBeginTransaction(); + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + cursorWithErrorList = vtGateConn + .executeBatch(context, batchedArgs, null, vitessConnection.getVtSession()).checkedGet(); + + if (null == cursorWithErrorList) { + throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); + } + + this.retrieveGeneratedKeys = true;// mimicking mysql-connector-j + return this.generateBatchUpdateResult(cursorWithErrorList, batchedArgs); + } finally { + this.clearBatch(); + } + } + + // Internal Methods Created + + + protected void closeOpenResultSetAndResetCount() throws SQLException { + try { + if (null != this.vitessResultSet) { + this.vitessResultSet.close(); + } + } catch (SQLException ex) { + throw new SQLException(ex); + } finally { + this.vitessResultSet = null; + this.resultCount = -1; + } + } + + protected void checkOpen() throws SQLException { + if (closed) { + throw new SQLException(Constants.SQLExceptionMessages.STMT_CLOSED); + } + } + + protected void checkNotReadOnly() throws SQLException { + if (vitessConnection.isReadOnly()) { + throw new SQLException(Constants.SQLExceptionMessages.READ_ONLY); + } + } + + protected void checkSQLNullOrEmpty(String sql) throws SQLException { + if (StringUtils.isNullOrEmptyWithoutWS(sql)) { + throw new SQLException(Constants.SQLExceptionMessages.SQL_EMPTY); + } + } + + /** + * This method returns the updateCounts array containing the status for each query sent in the + * batch. If any of the query does return success. It throws a BatchUpdateException. + * + * @param cursorWithErrorList Consists list of Cursor and Error object. + * @param batchedArgs holds batched commands + * @return int[] of results corresponding to each query + */ + protected int[] generateBatchUpdateResult(List cursorWithErrorList, + List batchedArgs) throws BatchUpdateException { + int[] updateCounts = new int[cursorWithErrorList.size()]; + ArrayList generatedKeys = new ArrayList<>(); + + Vtrpc.RPCError rpcError = null; + String batchCommand = null; + CursorWithError cursorWithError = null; + for (int i = 0; i < cursorWithErrorList.size(); i++) { + cursorWithError = cursorWithErrorList.get(i); + batchCommand = batchedArgs.get(i); + if (null == cursorWithError.getError()) { try { - return iface.cast(this); - } catch (ClassCastException cce) { - throw new SQLException( - Constants.SQLExceptionMessages.CLASS_CAST_EXCEPTION + iface.toString(), cce); - } - } - - /** - * Checking Wrapper - * - * @param iface - A Class defining an interface that the result must implement. - * @return true if this implements the interface or directly or indirectly wraps an object that does. - * @throws SQLException - */ - public boolean isWrapperFor(Class iface) throws SQLException { - checkOpen(); - return iface.isInstance(this); - } - - /** - * @return - * @throws SQLException - */ - public ResultSet getGeneratedKeys() throws SQLException { - checkOpen(); - if (!this.retrieveGeneratedKeys) { - throw new SQLException(Constants.SQLExceptionMessages.GENERATED_KEYS_NOT_REQUESTED); - } - - String[] columnNames = new String[1]; - columnNames[0] = "GENERATED_KEY"; - Query.Type[] columnTypes = new Query.Type[1]; - columnTypes[0] = Query.Type.UINT64; - String[][] data = null; - - if (this.generatedId > 0) { - // This is as per Mysql JDBC Driver. - // As the actual count of generated value is not known, - // only the rows affected is known, so using firstInsertId all the auto_inc values - // are generated. As per Vitess Config, the increment value is 1 and not changeable. - data = new String[(int) this.resultCount][1]; - for (int i = 0; i < this.resultCount; ++i) { - data[i][0] = String.valueOf(this.generatedId + i); - } - } else if (this.batchGeneratedKeys != null) { - long totalAffected = 0; - for (long[] batchGeneratedKey : this.batchGeneratedKeys) { - long rowsAffected = batchGeneratedKey[1]; - totalAffected += rowsAffected; - } - data = new String[(int) totalAffected][1]; - int idx = 0; - for (long[] batchGeneratedKey : this.batchGeneratedKeys) { - long insertId = batchGeneratedKey[0]; - long rowsAffected = batchGeneratedKey[1]; - for (int j = 0; j < rowsAffected; j++) { - data[idx++][0] = String.valueOf(insertId + j); - } - } - } - return new VitessResultSet(columnNames, columnTypes, data, this.vitessConnection); - } - - /** - * To execute DML statement - * - * @param sql - SQL Query - * @param autoGeneratedKeys - Flag for generated Keys - * @return Row Affected Count - * @throws SQLException - */ - public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - int truncatedUpdateCount; - - checkOpen(); - checkNotReadOnly(); - checkSQLNullOrEmpty(sql); - closeOpenResultSetAndResetCount(); - - if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method - throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); - } - - vtGateConn = this.vitessConnection.getVtGateConn(); - - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); - - if (null == cursor) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } - - if (!(null == cursor.getFields() || cursor.getFields().isEmpty())) { - throw new SQLException(Constants.SQLExceptionMessages.SQL_RETURNED_RESULT_SET); - } - - if (autoGeneratedKeys == Statement.RETURN_GENERATED_KEYS) { - this.retrieveGeneratedKeys = true; - this.generatedId = cursor.getInsertId(); - } else { - this.retrieveGeneratedKeys = false; - this.generatedId = -1; - } - - this.resultCount = cursor.getRowsAffected(); - - if (this.resultCount > Integer.MAX_VALUE) { + long rowsAffected = cursorWithError.getCursor().getRowsAffected(); + int truncatedUpdateCount; + boolean queryBatchUpsert = false; + if (rowsAffected > Integer.MAX_VALUE) { truncatedUpdateCount = Integer.MAX_VALUE; - } else { - truncatedUpdateCount = (int) this.resultCount; - } - - return truncatedUpdateCount; - } - - /** - * To execute Unknown Statement - * - * @param sql - SQL Query - * @param autoGeneratedKeys - Flag for generated Keys - * @return - true if the first result is a ResultSet - * object; false if it is an update count or there are - * no results - * @throws SQLException - */ - public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { - checkOpen(); - checkSQLNullOrEmpty(sql); - closeOpenResultSetAndResetCount(); - - if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method - throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); - } - if (!maybeSelect(sql)) { - this.executeUpdate(sql, autoGeneratedKeys); - return false; - } else { - this.executeQuery(sql); - return true; - } - } - - /** - * Add the query in the batch. - * - * @param sql - * @throws SQLException - */ - public void addBatch(String sql) throws SQLException { - checkOpen(); - checkSQLNullOrEmpty(sql); - if (this instanceof VitessPreparedStatement) { // PreparedStatement cannot call this method - throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); - } - this.batchedArgs.add(sql); - } - - /** - * Clear all the queries batched. - * - * @throws SQLException - */ - public void clearBatch() throws SQLException { - checkOpen(); - this.batchedArgs.clear(); - } - - /** - * Submits a batch of commands to the database for execution and - * if all commands execute successfully, returns an array of update counts. - * The array returned is according to the order in which they were added to the batch. - *

- * If one of the commands in a batch update fails to execute properly, - * this method throws a BatchUpdateException, and a JDBC - * driver may or may not continue to process the remaining commands in - * the batch. If the driver continues processing after a failure, - * the array returned by the method BatchUpdateException.getUpdateCounts - * will contain as many elements as there are commands in the batch. - * - * @return int[] of results corresponding to each command - * @throws SQLException - */ - public int[] executeBatch() throws SQLException { - checkOpen(); - checkNotReadOnly(); - VTGateConnection vtGateConn; - List cursorWithErrorList; - - if(0 == batchedArgs.size()) { - return new int[0]; - } - - try { - vtGateConn = this.vitessConnection.getVtGateConn(); - - checkAndBeginTransaction(); - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursorWithErrorList = - vtGateConn.executeBatch(context, batchedArgs, null, vitessConnection.getVtSession()).checkedGet(); - - if (null == cursorWithErrorList) { - throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); - } - - this.retrieveGeneratedKeys = true;// mimicking mysql-connector-j - return this.generateBatchUpdateResult(cursorWithErrorList, batchedArgs); - } finally { - this.clearBatch(); - } - } - - // Internal Methods Created - - - protected void closeOpenResultSetAndResetCount() throws SQLException { - try { - if (null != this.vitessResultSet) { - this.vitessResultSet.close(); - } - } catch (SQLException ex) { - throw new SQLException(ex); - } finally { - this.vitessResultSet = null; - this.resultCount = -1; - } - } - - protected void checkOpen() throws SQLException { - if (closed) { - throw new SQLException(Constants.SQLExceptionMessages.STMT_CLOSED); - } - } - - protected void checkNotReadOnly() throws SQLException { - if (vitessConnection.isReadOnly()) { - throw new SQLException(Constants.SQLExceptionMessages.READ_ONLY); - } - } - - protected void checkSQLNullOrEmpty(String sql) throws SQLException { - if (StringUtils.isNullOrEmptyWithoutWS(sql)) { - throw new SQLException(Constants.SQLExceptionMessages.SQL_EMPTY); - } - } - - /** - * This method returns the updateCounts array containing the status for each query - * sent in the batch. If any of the query does return success. - * It throws a BatchUpdateException. - * - * @param cursorWithErrorList Consists list of Cursor and Error object. - * @param batchedArgs holds batched commands - * @return int[] of results corresponding to each query - * @throws BatchUpdateException - */ - protected int[] generateBatchUpdateResult(List cursorWithErrorList, List batchedArgs) - throws BatchUpdateException { - int[] updateCounts = new int[cursorWithErrorList.size()]; - ArrayList generatedKeys = new ArrayList<>(); - - Vtrpc.RPCError rpcError = null; - String batchCommand = null; - CursorWithError cursorWithError = null; - for (int i = 0; i < cursorWithErrorList.size(); i++) { - cursorWithError = cursorWithErrorList.get(i); - batchCommand = batchedArgs.get(i); - if (null == cursorWithError.getError()) { - try { - long rowsAffected = cursorWithError.getCursor().getRowsAffected(); - int truncatedUpdateCount; - boolean queryBatchUpsert = false; - if (rowsAffected > Integer.MAX_VALUE) { - truncatedUpdateCount = Integer.MAX_VALUE; - } else { - if (sqlIsUpsert(batchCommand)) { - // mimicking mysql-connector-j here. - // but it would fail for: insert into t1 values ('a'), ('b') on duplicate key update ts = now(); - truncatedUpdateCount = 1; - queryBatchUpsert = true; - } else { - truncatedUpdateCount = (int) rowsAffected; - } - } - updateCounts[i] = truncatedUpdateCount; - long insertId = cursorWithError.getCursor().getInsertId(); - if (this.retrieveGeneratedKeys && (!queryBatchUpsert || insertId > 0)) { - generatedKeys.add(new long[]{insertId, truncatedUpdateCount}); - } - } catch (SQLException ex) { - /* This case should not happen as API has returned cursor and not error. - * Handling by Statement.SUCCESS_NO_INFO - */ - updateCounts[i] = Statement.SUCCESS_NO_INFO; - if (this.retrieveGeneratedKeys) { - generatedKeys.add(new long[]{Statement.SUCCESS_NO_INFO, Statement.SUCCESS_NO_INFO}); - } - } + } else { + if (sqlIsUpsert(batchCommand)) { + // mimicking mysql-connector-j here. + // but it would fail for: insert into t1 values ('a'), ('b') on duplicate key + // update ts = now(); + truncatedUpdateCount = 1; + queryBatchUpsert = true; } else { - rpcError = cursorWithError.getError(); - updateCounts[i] = Statement.EXECUTE_FAILED; - if (this.retrieveGeneratedKeys) { - generatedKeys.add(new long[]{Statement.EXECUTE_FAILED, Statement.EXECUTE_FAILED}); - } + truncatedUpdateCount = (int) rowsAffected; } + } + updateCounts[i] = truncatedUpdateCount; + long insertId = cursorWithError.getCursor().getInsertId(); + if (this.retrieveGeneratedKeys && (!queryBatchUpsert || insertId > 0)) { + generatedKeys.add(new long[]{insertId, truncatedUpdateCount}); + } + } catch (SQLException ex) { + /* This case should not happen as API has returned cursor and not error. + * Handling by Statement.SUCCESS_NO_INFO + */ + updateCounts[i] = Statement.SUCCESS_NO_INFO; + if (this.retrieveGeneratedKeys) { + generatedKeys.add(new long[]{Statement.SUCCESS_NO_INFO, Statement.SUCCESS_NO_INFO}); + } } - - if (null != rpcError) { - int errno = Proto.getErrno(rpcError.getMessage()); - String sqlState = Proto.getSQLState(rpcError.getMessage()); - throw new BatchUpdateException(rpcError.toString(), sqlState, errno, updateCounts); - } + } else { + rpcError = cursorWithError.getError(); + updateCounts[i] = Statement.EXECUTE_FAILED; if (this.retrieveGeneratedKeys) { - this.batchGeneratedKeys = generatedKeys.toArray(new long[generatedKeys.size()][2]); - } - return updateCounts; - } - - private boolean sqlIsUpsert(String sql) { - return StringUtils.indexOfIgnoreCase(0, sql, ON_DUPLICATE_KEY_UPDATE_CLAUSE, "\"'`", "\"'`", StringUtils.SEARCH_MODE__ALL) != -1; - } - - protected boolean maybeSelect(String sql) { - char firstNonWsCharOfQuery = StringUtils.firstAlphaCharUc(sql, StringUtils.findStartOfStatement(sql)); - return firstNonWsCharOfQuery == 'S'; - } - - protected void checkAndBeginTransaction() throws SQLException { - if (!(this.vitessConnection.getAutoCommit() || this.vitessConnection.isInTransaction())) { - Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); - vtGateConn.execute(context,"begin",null,this.vitessConnection.getVtSession()).checkedGet(); + generatedKeys.add(new long[]{Statement.EXECUTE_FAILED, Statement.EXECUTE_FAILED}); } - } - - //Unsupported Methods - - /** - * Not Required to be implemented as More Results are handled in next() call - * - * @throws SQLException - */ - public boolean getMoreResults() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - /** - * Not Required to be implemented as More Results are handled in next() call - * - * @throws SQLException - */ - public boolean getMoreResults(int current) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setEscapeProcessing(boolean enable) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void cancel() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int executeUpdate(String sql, String[] columnNames) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean execute(String sql, int[] columnIndexes) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean execute(String sql, String[] columnNames) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public int getResultSetHoldability() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean isPoolable() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void setPoolable(boolean poolable) throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public void closeOnCompletion() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } - - public boolean isCloseOnCompletion() throws SQLException { - throw new SQLFeatureNotSupportedException( - Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); - } + } + } + + if (null != rpcError) { + int errno = Proto.getErrno(rpcError.getMessage()); + String sqlState = Proto.getSQLState(rpcError.getMessage()); + throw new BatchUpdateException(rpcError.toString(), sqlState, errno, updateCounts); + } + if (this.retrieveGeneratedKeys) { + this.batchGeneratedKeys = generatedKeys.toArray(new long[generatedKeys.size()][2]); + } + return updateCounts; + } + + private boolean sqlIsUpsert(String sql) { + return StringUtils.indexOfIgnoreCase(0, sql, ON_DUPLICATE_KEY_UPDATE_CLAUSE, "\"'`", "\"'`", + StringUtils.SEARCH_MODE__ALL) != -1; + } + + protected boolean maybeSelect(String sql) { + char firstNonWsCharOfQuery = StringUtils + .firstAlphaCharUc(sql, StringUtils.findStartOfStatement(sql)); + return firstNonWsCharOfQuery == 'S'; + } + + protected void checkAndBeginTransaction() throws SQLException { + if (!(this.vitessConnection.getAutoCommit() || this.vitessConnection.isInTransaction())) { + Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); + vtGateConn.execute(context, "begin", null, this.vitessConnection.getVtSession()).checkedGet(); + } + } + + //Unsupported Methods + + /** + * Not Required to be implemented as More Results are handled in next() call + */ + public boolean getMoreResults() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + /** + * Not Required to be implemented as More Results are handled in next() call + */ + public boolean getMoreResults(int current) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setEscapeProcessing(boolean enable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void cancel() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int executeUpdate(String sql, String[] columnNames) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean execute(String sql, int[] columnIndexes) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean execute(String sql, String[] columnNames) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public int getResultSetHoldability() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean isPoolable() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void setPoolable(boolean poolable) throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public void closeOnCompletion() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } + + public boolean isCloseOnCompletion() throws SQLException { + throw new SQLFeatureNotSupportedException( + Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); + } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java index b9047d2a8c9..6a5b496ee16 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -41,204 +41,200 @@ * Created by naveen.nahata on 24/02/16. */ public class VitessVTGateManager { - private static Logger logger = Logger.getLogger(VitessVTGateManager.class.getName()); - /* - Current implementation have one VTGateConn for ip-port-username combination - */ - private static ConcurrentHashMap vtGateConnHashMap = - new ConcurrentHashMap<>(); - private static Timer vtgateConnRefreshTimer = null; - private static Timer vtgateClosureTimer = null; - private static long vtgateClosureDelaySeconds = 0L; + + private static Logger logger = Logger.getLogger(VitessVTGateManager.class.getName()); + /* + Current implementation have one VTGateConn for ip-port-username combination + */ + private static ConcurrentHashMap vtGateConnHashMap = + new ConcurrentHashMap<>(); + private static Timer vtgateConnRefreshTimer = null; + private static Timer vtgateClosureTimer = null; + private static long vtgateClosureDelaySeconds = 0L; + + /** + * VTGateConnections object consist of vtGateIdentifire list and return vtGate object in round + * robin. + */ + public static class VTGateConnections { + + private List vtGateIdentifiers = new ArrayList<>(); + int counter; /** - * VTGateConnections object consist of vtGateIdentifire list and return vtGate object in round robin. + * Constructor */ - public static class VTGateConnections { - private List vtGateIdentifiers = new ArrayList<>(); - int counter; - - /** - * Constructor - * - * @param connection - */ - public VTGateConnections(final VitessConnection connection) { - maybeStartClosureTimer(connection); - for (final VitessJDBCUrl.HostInfo hostInfo : connection.getUrl().getHostInfos()) { - String identifier = getIdentifer(hostInfo.getHostname(), hostInfo.getPort(), connection.getUsername(), connection.getTarget()); - synchronized (VitessVTGateManager.class) { - if (!vtGateConnHashMap.containsKey(identifier)) { - updateVtGateConnHashMap(identifier, hostInfo, connection); - } - if (connection.getUseSSL() && connection.getRefreshConnection() && vtgateConnRefreshTimer == null) { - logger.info("ssl vtgate connection detected -- installing connection refresh based on ssl keystore modification"); - vtgateConnRefreshTimer = new Timer("ssl-refresh-vtgate-conn", true); - vtgateConnRefreshTimer.scheduleAtFixedRate( - new TimerTask() { - @Override - public void run() { - refreshUpdatedSSLConnections(hostInfo, connection); - } - }, - TimeUnit.SECONDS.toMillis(connection.getRefreshSeconds()), - TimeUnit.SECONDS.toMillis(connection.getRefreshSeconds())); - } - } - vtGateIdentifiers.add(identifier); - } - Random random = new Random(); - counter = random.nextInt(vtGateIdentifiers.size()); - } - - /** - * Return VTGate Instance object. - * - * @return - */ - public VTGateConnection getVtGateConnInstance() { - counter++; - counter = counter % vtGateIdentifiers.size(); - return vtGateConnHashMap.get(vtGateIdentifiers.get(counter)); - } - - } - - private static void maybeStartClosureTimer(VitessConnection connection) { - if (connection.getRefreshClosureDelayed() && vtgateClosureTimer == null) { - synchronized (VitessVTGateManager.class) { - if (vtgateClosureTimer == null) { - vtgateClosureTimer = new Timer("vtgate-conn-closure", true); - vtgateClosureDelaySeconds = connection.getRefreshClosureDelaySeconds(); - } - } + public VTGateConnections(final VitessConnection connection) { + maybeStartClosureTimer(connection); + for (final VitessJDBCUrl.HostInfo hostInfo : connection.getUrl().getHostInfos()) { + String identifier = getIdentifer(hostInfo.getHostname(), hostInfo.getPort(), + connection.getUsername(), connection.getTarget()); + synchronized (VitessVTGateManager.class) { + if (!vtGateConnHashMap.containsKey(identifier)) { + updateVtGateConnHashMap(identifier, hostInfo, connection); + } + if (connection.getUseSSL() && connection.getRefreshConnection() + && vtgateConnRefreshTimer == null) { + logger.info( + "ssl vtgate connection detected -- installing connection refresh based on ssl " + + "keystore modification"); + vtgateConnRefreshTimer = new Timer("ssl-refresh-vtgate-conn", true); + vtgateConnRefreshTimer.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + refreshUpdatedSSLConnections(hostInfo, connection); + } + }, TimeUnit.SECONDS.toMillis(connection.getRefreshSeconds()), + TimeUnit.SECONDS.toMillis(connection.getRefreshSeconds())); + } } - } - - private static String getIdentifer(String hostname, int port, String userIdentifer, String keyspace) { - return (hostname + port + userIdentifer + keyspace); + vtGateIdentifiers.add(identifier); + } + Random random = new Random(); + counter = random.nextInt(vtGateIdentifiers.size()); } /** - * Create VTGateConn and update vtGateConnHashMap. - * - * @param identifier - * @param hostInfo - * @param connection + * Return VTGate Instance object. */ - private static void updateVtGateConnHashMap(String identifier, VitessJDBCUrl.HostInfo hostInfo, - VitessConnection connection) { - vtGateConnHashMap.put(identifier, getVtGateConn(hostInfo, connection)); + public VTGateConnection getVtGateConnInstance() { + counter++; + counter = counter % vtGateIdentifiers.size(); + return vtGateConnHashMap.get(vtGateIdentifiers.get(counter)); } - private static void refreshUpdatedSSLConnections(VitessJDBCUrl.HostInfo hostInfo, VitessConnection connection) { - synchronized (VitessVTGateManager.class) { - int updatedCount = 0; - for (Map.Entry entry : vtGateConnHashMap.entrySet()) { - if (entry.getValue() instanceof RefreshableVTGateConnection) { - RefreshableVTGateConnection existing = (RefreshableVTGateConnection) entry.getValue(); - if (existing.checkKeystoreUpdates()) { - updatedCount++; - VTGateConnection old = vtGateConnHashMap.replace(entry.getKey(), getVtGateConn(hostInfo, connection)); - closeRefreshedConnection(old); - } - } - } - if (updatedCount > 0) { - logger.info("refreshed " + updatedCount + " vtgate connections due to keystore update"); - } - } - } + } - private static void closeRefreshedConnection(final VTGateConnection old) { - if (vtgateClosureTimer != null) { - logger.info(String.format("%s Closing connection with a %s second delay", old, vtgateClosureDelaySeconds)); - vtgateClosureTimer.schedule(new TimerTask() { - @Override - public void run() { - actuallyCloseRefreshedConnection(old); - } - }, - TimeUnit.SECONDS.toMillis(vtgateClosureDelaySeconds)); - } else { - actuallyCloseRefreshedConnection(old); + private static void maybeStartClosureTimer(VitessConnection connection) { + if (connection.getRefreshClosureDelayed() && vtgateClosureTimer == null) { + synchronized (VitessVTGateManager.class) { + if (vtgateClosureTimer == null) { + vtgateClosureTimer = new Timer("vtgate-conn-closure", true); + vtgateClosureDelaySeconds = connection.getRefreshClosureDelaySeconds(); } + } } - - private static void actuallyCloseRefreshedConnection(final VTGateConnection old) { - try { - logger.info(old + " Closing connection because it had been refreshed"); - old.close(); - } catch (IOException ioe) { - logger.log(Level.WARNING, String.format("Error closing VTGateConnection %s", old), ioe); + } + + private static String getIdentifer(String hostname, int port, String userIdentifer, + String keyspace) { + return (hostname + port + userIdentifer + keyspace); + } + + /** + * Create VTGateConn and update vtGateConnHashMap. + */ + private static void updateVtGateConnHashMap(String identifier, VitessJDBCUrl.HostInfo hostInfo, + VitessConnection connection) { + vtGateConnHashMap.put(identifier, getVtGateConn(hostInfo, connection)); + } + + private static void refreshUpdatedSSLConnections(VitessJDBCUrl.HostInfo hostInfo, + VitessConnection connection) { + synchronized (VitessVTGateManager.class) { + int updatedCount = 0; + for (Map.Entry entry : vtGateConnHashMap.entrySet()) { + if (entry.getValue() instanceof RefreshableVTGateConnection) { + RefreshableVTGateConnection existing = (RefreshableVTGateConnection) entry.getValue(); + if (existing.checkKeystoreUpdates()) { + updatedCount++; + VTGateConnection old = vtGateConnHashMap + .replace(entry.getKey(), getVtGateConn(hostInfo, connection)); + closeRefreshedConnection(old); + } } + } + if (updatedCount > 0) { + logger.info("refreshed " + updatedCount + " vtgate connections due to keystore update"); + } } - - /** - * Create vtGateConn object with given identifier. - * - * @param hostInfo - * @param connection - * @return - */ - private static VTGateConnection getVtGateConn(VitessJDBCUrl.HostInfo hostInfo, VitessConnection connection) { - final Context context = connection.createContext(connection.getTimeout()); - RetryingInterceptorConfig retryingConfig = getRetryingInterceptorConfig(connection); - if (connection.getUseSSL()) { - final String keyStorePath = connection.getKeyStore() != null - ? connection.getKeyStore() : System.getProperty(Constants.Property.KEYSTORE_FULL); - final String keyStorePassword = connection.getKeyStorePassword() != null - ? connection.getKeyStorePassword() : System.getProperty(Constants.Property.KEYSTORE_PASSWORD_FULL); - final String keyAlias = connection.getKeyAlias() != null - ? connection.getKeyAlias() : System.getProperty(Constants.Property.KEY_ALIAS_FULL); - final String keyPassword = connection.getKeyPassword() != null - ? connection.getKeyPassword() : System.getProperty(Constants.Property.KEY_PASSWORD_FULL); - final String trustStorePath = connection.getTrustStore() != null - ? connection.getTrustStore() : System.getProperty(Constants.Property.TRUSTSTORE_FULL); - final String trustStorePassword = connection.getTrustStorePassword() != null - ? connection.getTrustStorePassword() : System.getProperty(Constants.Property.TRUSTSTORE_PASSWORD_FULL); - final String trustAlias = connection.getTrustAlias() != null - ? connection.getTrustAlias() : System.getProperty(Constants.Property.TRUST_ALIAS_FULL); - - final TlsOptions tlsOptions = new TlsOptions() - .keyStorePath(keyStorePath) - .keyStorePassword(keyStorePassword) - .keyAlias(keyAlias) - .keyPassword(keyPassword) - .trustStorePath(trustStorePath) - .trustStorePassword(trustStorePassword) - .trustAlias(trustAlias); - - return new RefreshableVTGateConnection( - new GrpcClientFactory(retryingConfig).createTls(context, hostInfo.toString(), tlsOptions), - keyStorePath, - trustStorePath); - } else { - return new VTGateConnection(new GrpcClientFactory(retryingConfig).create(context, hostInfo.toString())); + } + + private static void closeRefreshedConnection(final VTGateConnection old) { + if (vtgateClosureTimer != null) { + logger.info(String + .format("%s Closing connection with a %s second delay", old, vtgateClosureDelaySeconds)); + vtgateClosureTimer.schedule(new TimerTask() { + @Override + public void run() { + actuallyCloseRefreshedConnection(old); } + }, TimeUnit.SECONDS.toMillis(vtgateClosureDelaySeconds)); + } else { + actuallyCloseRefreshedConnection(old); } + } + + private static void actuallyCloseRefreshedConnection(final VTGateConnection old) { + try { + logger.info(old + " Closing connection because it had been refreshed"); + old.close(); + } catch (IOException ioe) { + logger.log(Level.WARNING, String.format("Error closing VTGateConnection %s", old), ioe); + } + } + + /** + * Create vtGateConn object with given identifier. + */ + private static VTGateConnection getVtGateConn(VitessJDBCUrl.HostInfo hostInfo, + VitessConnection connection) { + final Context context = connection.createContext(connection.getTimeout()); + RetryingInterceptorConfig retryingConfig = getRetryingInterceptorConfig(connection); + if (connection.getUseSSL()) { + final String keyStorePath = connection.getKeyStore() != null ? connection.getKeyStore() + : System.getProperty(Constants.Property.KEYSTORE_FULL); + final String keyStorePassword = + connection.getKeyStorePassword() != null ? connection.getKeyStorePassword() + : System.getProperty(Constants.Property.KEYSTORE_PASSWORD_FULL); + final String keyAlias = connection.getKeyAlias() != null ? connection.getKeyAlias() + : System.getProperty(Constants.Property.KEY_ALIAS_FULL); + final String keyPassword = connection.getKeyPassword() != null ? connection.getKeyPassword() + : System.getProperty(Constants.Property.KEY_PASSWORD_FULL); + final String trustStorePath = connection.getTrustStore() != null ? connection.getTrustStore() + : System.getProperty(Constants.Property.TRUSTSTORE_FULL); + final String trustStorePassword = + connection.getTrustStorePassword() != null ? connection.getTrustStorePassword() + : System.getProperty(Constants.Property.TRUSTSTORE_PASSWORD_FULL); + final String trustAlias = connection.getTrustAlias() != null ? connection.getTrustAlias() + : System.getProperty(Constants.Property.TRUST_ALIAS_FULL); + + final TlsOptions tlsOptions = new TlsOptions().keyStorePath(keyStorePath) + .keyStorePassword(keyStorePassword).keyAlias(keyAlias).keyPassword(keyPassword) + .trustStorePath(trustStorePath).trustStorePassword(trustStorePassword) + .trustAlias(trustAlias); + + return new RefreshableVTGateConnection( + new GrpcClientFactory(retryingConfig).createTls(context, hostInfo.toString(), tlsOptions), + keyStorePath, trustStorePath); + } else { + return new VTGateConnection( + new GrpcClientFactory(retryingConfig).create(context, hostInfo.toString())); + } + } - private static RetryingInterceptorConfig getRetryingInterceptorConfig(VitessConnection conn) { - if (!conn.getGrpcRetriesEnabled()) { - return RetryingInterceptorConfig.noOpConfig(); - } - - return RetryingInterceptorConfig.exponentialConfig(conn.getGrpcRetryInitialBackoffMillis(), conn.getGrpcRetryMaxBackoffMillis(), conn.getGrpcRetryBackoffMultiplier()); + private static RetryingInterceptorConfig getRetryingInterceptorConfig(VitessConnection conn) { + if (!conn.getGrpcRetriesEnabled()) { + return RetryingInterceptorConfig.noOpConfig(); } - public static void close() throws SQLException { - SQLException exception = null; + return RetryingInterceptorConfig.exponentialConfig(conn.getGrpcRetryInitialBackoffMillis(), + conn.getGrpcRetryMaxBackoffMillis(), conn.getGrpcRetryBackoffMultiplier()); + } - for (VTGateConnection vtGateConn : vtGateConnHashMap.values()) { - try { - vtGateConn.close(); - } catch (IOException e) { - exception = new SQLException(e.getMessage(), e); - } - } - vtGateConnHashMap.clear(); - if (null != exception) { - throw exception; - } + public static void close() throws SQLException { + SQLException exception = null; + + for (VTGateConnection vtGateConn : vtGateConnHashMap.values()) { + try { + vtGateConn.close(); + } catch (IOException e) { + exception = new SQLException(e.getMessage(), e); + } + } + vtGateConnHashMap.clear(); + if (null != exception) { + throw exception; } + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/CommonUtils.java b/java/jdbc/src/main/java/io/vitess/util/CommonUtils.java index 75ce676eef4..4612542d3bc 100644 --- a/java/jdbc/src/main/java/io/vitess/util/CommonUtils.java +++ b/java/jdbc/src/main/java/io/vitess/util/CommonUtils.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,38 +16,34 @@ package io.vitess.util; -import org.joda.time.Duration; - import io.vitess.client.Context; import io.vitess.proto.Vtrpc; +import org.joda.time.Duration; + /** * Created by naveen.nahata on 24/02/16. */ public class CommonUtils { - /** - * Create context used to create grpc client and executing query. - * - * @param username - * @param timeout - * @return - */ - public static Context createContext(String username, long timeout) { - Context context = Context.getDefault(); - Vtrpc.CallerID callerID = null; - if (null != username) { - callerID = Vtrpc.CallerID.newBuilder().setPrincipal(username).build(); - } - - if (null != callerID) { - context = context.withCallerId(callerID); - } - if (timeout > 0) { - context = context.withDeadlineAfter(Duration.millis(timeout)); - } - - return context; + /** + * Create context used to create grpc client and executing query. + */ + public static Context createContext(String username, long timeout) { + Context context = Context.getDefault(); + Vtrpc.CallerID callerID = null; + if (null != username) { + callerID = Vtrpc.CallerID.newBuilder().setPrincipal(username).build(); } + + if (null != callerID) { + context = context.withCallerId(callerID); + } + if (timeout > 0) { + context = context.withDeadlineAfter(Duration.millis(timeout)); + } + + return context; + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/Constants.java b/java/jdbc/src/main/java/io/vitess/util/Constants.java index aebc7778b95..78666e7ed88 100644 --- a/java/jdbc/src/main/java/io/vitess/util/Constants.java +++ b/java/jdbc/src/main/java/io/vitess/util/Constants.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,6 +17,7 @@ package io.vitess.util; import com.google.protobuf.ByteString; + import io.vitess.proto.Query; import io.vitess.proto.Topodata; @@ -25,153 +26,157 @@ */ public class Constants { - public static final boolean JDBC_COMPLIANT = false; - public static final String URL_PREFIX = "jdbc:vitess://"; - public static final String URL_PATTERN = - "^jdbc:(vitess)://((\\w+)(:(\\w*))?@)?([^/?]*)(/([^/?]*))?(/(\\w+))?(\\?(\\S+))?"; - public static final String VITESS_HOST = "Hostname of Vitess Server"; - public static final String VITESS_PORT = "Port number of Vitess Server"; - public static final String VITESS_DB_NAME = "Database name"; - public static final String VITESS_TABLET_TYPE = - "Tablet Type to which Vitess will connect(master, replica, rdonly)"; - public static final String DEFAULT_PORT = "15991"; - public static final Topodata.TabletType DEFAULT_TABLET_TYPE = Topodata.TabletType.MASTER; - public static final String LITERAL_V = "v"; - public static final String LITERAL_SINGLE_QUOTE = "'"; - public static final int DRIVER_MAJOR_VERSION = 2; - public static final int DRIVER_MINOR_VERSION = 2; - public static final int MAX_BUFFER_SIZE = 65535; - //Default Timeout in miliseconds - public static final int DEFAULT_TIMEOUT = 30000; - public static final String VITESS_KEYSPACE = "Keyspace name in Vitess Server"; - public static final Constants.QueryExecuteType DEFAULT_EXECUTE_TYPE = QueryExecuteType.SIMPLE; - public static final String EXECUTE_TYPE_DESC = "Query execution type: simple or stream \n"; - public static final String USERNAME_DESC = "Username used for ACL validation \n"; - public static final Query.ExecuteOptions.IncludedFields DEFAULT_INCLUDED_FIELDS = Query.ExecuteOptions.IncludedFields.ALL; - public static final String DEFAULT_KEYSPACE = ""; - public static final String DEFAULT_SHARD = ""; - public static final String DEFAULT_USERNAME = null; - public static final String DEFAULT_TARGET = ""; - public static final String DEFAULT_CATALOG = DEFAULT_KEYSPACE; - public static final ByteString ZERO_DATE_TIME_PREFIX = ByteString.copyFromUtf8("0000-00-00"); + public static final boolean JDBC_COMPLIANT = false; + public static final String URL_PREFIX = "jdbc:vitess://"; + public static final String URL_PATTERN = "^jdbc:(vitess)://((\\w+)(:(\\w*))?@)?([^/?]*)(/" + + "([^/?]*))?(/(\\w+))?(\\?(\\S+))?"; + public static final String VITESS_HOST = "Hostname of Vitess Server"; + public static final String VITESS_PORT = "Port number of Vitess Server"; + public static final String VITESS_DB_NAME = "Database name"; + public static final String VITESS_TABLET_TYPE = "Tablet Type to which Vitess will connect" + + "(master, replica, rdonly)"; + public static final String DEFAULT_PORT = "15991"; + public static final Topodata.TabletType DEFAULT_TABLET_TYPE = Topodata.TabletType.MASTER; + public static final String LITERAL_V = "v"; + public static final String LITERAL_SINGLE_QUOTE = "'"; + public static final int DRIVER_MAJOR_VERSION = 2; + public static final int DRIVER_MINOR_VERSION = 2; + public static final int MAX_BUFFER_SIZE = 65535; + //Default Timeout in miliseconds + public static final int DEFAULT_TIMEOUT = 30000; + public static final String VITESS_KEYSPACE = "Keyspace name in Vitess Server"; + public static final Constants.QueryExecuteType DEFAULT_EXECUTE_TYPE = QueryExecuteType.SIMPLE; + public static final String EXECUTE_TYPE_DESC = "Query execution type: simple or stream \n"; + public static final String USERNAME_DESC = "Username used for ACL validation \n"; + public static final Query.ExecuteOptions.IncludedFields DEFAULT_INCLUDED_FIELDS = + Query.ExecuteOptions.IncludedFields.ALL; + public static final String DEFAULT_KEYSPACE = ""; + public static final String DEFAULT_SHARD = ""; + public static final String DEFAULT_USERNAME = null; + public static final String DEFAULT_TARGET = ""; + public static final String DEFAULT_CATALOG = DEFAULT_KEYSPACE; + public static final ByteString ZERO_DATE_TIME_PREFIX = ByteString.copyFromUtf8("0000-00-00"); private Constants() { - } - - - public static final class SQLExceptionMessages { - public static final String CONN_UNAVAILABLE = "Connection not available"; - public static final String CONN_CLOSED = "Connection is Closed"; - public static final String INIT_FAILED = "Failed to Initialize Vitess JDBC Driver"; - public static final String INVALID_CONN_URL = "Connection URL is invalid"; - public static final String STMT_CLOSED = "Statement is closed"; - public static final String SQL_FEATURE_NOT_SUPPORTED = "SQL Feature Not Supported"; - public static final String TIMEOUT_NEGATIVE = "Timeout value cannot be negative"; - public static final String COMMIT_WHEN_AUTO_COMMIT_TRUE = - "Cannot call commit when auto commit is true"; - public static final String ROLLBACK_WHEN_AUTO_COMMIT_TRUE = - "Cannot call rollback when auto commit is true"; - public static final String CLOSED_RESULT_SET = "Result Set closed"; - public static final String INVALID_COLUMN_INDEX = "Invalid Column Index"; - public static final String VITESS_CURSOR_CLOSE_ERROR = - "Getting Error while closing ResultSet"; - public static final String CONN_INIT_ERROR = "Connection initialization error"; - public static final String MALFORMED_URL = "Malformed URL Exception"; - public static final String SQL_TYPE_INFER = - "Cannot infer the SQL type to use for an instance of "; - public static final String DML_NOT_ON_MASTER = - "DML Statement cannot be executed on non master instance type"; - public static final String SQL_EMPTY = "SQL statement is not valid"; - public static final String RESULT_SET_TYPE_NOT_SUPPORTED = - "This Result Set type is not supported"; - public static final String RESULT_SET_CONCUR_NOT_SUPPORTED = - "This Result Set Concurrency is not supported"; - public static final String METHOD_CALLED_ON_OPEN_TRANSACTION = - "This method should not be called when a transaction is open"; - public static final String ISOLATION_LEVEL_NOT_SUPPORTED = - "This isolation level is not supported"; - public static final String EXECUTOR_NULL = "Executor cannot be null"; - public static final String CLASS_CAST_EXCEPTION = "Unable to unwrap to "; - public static final String INVALID_COLUMN_TYPE = "Invalid Column Type"; - public static final String UNKNOWN_COLUMN_TYPE = "Unknown Column Type"; - public static final String INVALID_RESULT_SET = "Unable to build ResultSet"; - public static final String METHOD_NOT_ALLOWED = - "This method cannot be called using this class object"; - public static final String SQL_RETURNED_RESULT_SET = - "ResultSet generation is not allowed through this method"; - public static final String ILLEGAL_VALUE_FOR = "Illegal value for "; - public static final String METHOD_CALL_FAILED = "Failed to execute this method"; - public static final String CURSOR_NULL = "Cursor cannot be null"; - public static final String NO_COLUMN_ACCESSED = - "No column was accessed before calling this method"; - public static final String RESULT_SET_INIT_ERROR = "ResultSet initialization error"; - public static final String GENERATED_KEYS_NOT_REQUESTED = - "Generated keys not requested. You need to specify " - + "Statement.RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection.prepareStatement()"; - public static final String NO_KEYSPACE = - "Querying Database Information without providing keyspace"; - public static final String QUERY_FAILED = "One or more queries failed in batch execution"; - public static final String READ_ONLY = - "Connection has been set to read only and an update was attempted"; - public static final String ZERO_TIMESTAMP = "Zero timestamp cannot be represented as java.sql.Date"; - } - - - public static final class Property { - @Deprecated - public static final String OLD_TABLET_TYPE = "TABLET_TYPE"; - public static final String TABLET_TYPE = "tabletType"; - public static final String HOST = "host"; - public static final String PORT = "port"; - public static final String DBNAME = "dbName"; - public static final String KEYSPACE = "keyspace"; - public static final String USERNAME = "userName"; - public static final String EXECUTE_TYPE = "executeType"; - public static final String TWOPC_ENABLED = "twopcEnabled"; - public static final String SHARD = "shard"; - - public static final String USE_SSL = "useSSL"; - public static final String KEYSTORE = "keyStore"; - public static final String KEYSTORE_PASSWORD = "keyStorePassword"; - public static final String KEY_ALIAS = "keyAlias"; - public static final String KEY_PASSWORD = "keyPassword"; - public static final String TRUSTSTORE = "trustStore"; - public static final String TRUSTSTORE_PASSWORD = "trustStorePassword"; - public static final String TRUST_ALIAS = "trustAlias"; - - public static final String KEYSTORE_FULL = "javax.net.ssl.keyStore"; - public static final String KEYSTORE_PASSWORD_FULL = "javax.net.ssl.keyStorePassword"; - public static final String KEY_ALIAS_FULL = "javax.net.ssl.keyAlias"; - public static final String KEY_PASSWORD_FULL = "javax.net.ssl.keyPassword"; - public static final String TRUSTSTORE_FULL = "javax.net.ssl.trustStore"; - public static final String TRUSTSTORE_PASSWORD_FULL = "javax.net.ssl.trustStorePassword"; - public static final String TRUST_ALIAS_FULL = "javax.net.ssl.trustAlias"; - public static final String INCLUDED_FIELDS = "includedFields"; - public static final String TARGET = "target"; - } - - - public enum QueryExecuteType { - SIMPLE, STREAM - } - - public enum ZeroDateTimeBehavior { - /** - * This is the current behavior. It completely garbles null timestamps. It is mostly likely - * entirely incorrect but we will keep it for backwards compatibility. - */ - GARBLE, - /** - * This matches the MySQL JDBC driver convertToNull behavior. - */ - CONVERTTONULL, - /** - * This matches the MySQL JDBC driver exception behavior. - */ - EXCEPTION, - /** - * This matches the MySQL JDBC driver round behavior. - */ - ROUND - } + } + + + public static final class SQLExceptionMessages { + + public static final String CONN_UNAVAILABLE = "Connection not available"; + public static final String CONN_CLOSED = "Connection is Closed"; + public static final String INIT_FAILED = "Failed to Initialize Vitess JDBC Driver"; + public static final String INVALID_CONN_URL = "Connection URL is invalid"; + public static final String STMT_CLOSED = "Statement is closed"; + public static final String SQL_FEATURE_NOT_SUPPORTED = "SQL Feature Not Supported"; + public static final String TIMEOUT_NEGATIVE = "Timeout value cannot be negative"; + public static final String COMMIT_WHEN_AUTO_COMMIT_TRUE = "Cannot call commit when auto " + + "commit is true"; + public static final String ROLLBACK_WHEN_AUTO_COMMIT_TRUE = "Cannot call rollback when auto " + + "commit is true"; + public static final String CLOSED_RESULT_SET = "Result Set closed"; + public static final String INVALID_COLUMN_INDEX = "Invalid Column Index"; + public static final String VITESS_CURSOR_CLOSE_ERROR = "Getting Error while closing ResultSet"; + public static final String CONN_INIT_ERROR = "Connection initialization error"; + public static final String MALFORMED_URL = "Malformed URL Exception"; + public static final String SQL_TYPE_INFER = "Cannot infer the SQL type to use for an instance" + + " of "; + public static final String DML_NOT_ON_MASTER = "DML Statement cannot be executed on non " + + "master instance type"; + public static final String SQL_EMPTY = "SQL statement is not valid"; + public static final String RESULT_SET_TYPE_NOT_SUPPORTED = "This Result Set type is not " + + "supported"; + public static final String RESULT_SET_CONCUR_NOT_SUPPORTED = "This Result Set Concurrency is " + + "not supported"; + public static final String METHOD_CALLED_ON_OPEN_TRANSACTION = "This method should not be " + + "called when a transaction is open"; + public static final String ISOLATION_LEVEL_NOT_SUPPORTED = "This isolation level is not " + + "supported"; + public static final String EXECUTOR_NULL = "Executor cannot be null"; + public static final String CLASS_CAST_EXCEPTION = "Unable to unwrap to "; + public static final String INVALID_COLUMN_TYPE = "Invalid Column Type"; + public static final String UNKNOWN_COLUMN_TYPE = "Unknown Column Type"; + public static final String INVALID_RESULT_SET = "Unable to build ResultSet"; + public static final String METHOD_NOT_ALLOWED = "This method cannot be called using this " + + "class object"; + public static final String SQL_RETURNED_RESULT_SET = "ResultSet generation is not allowed " + + "through this method"; + public static final String ILLEGAL_VALUE_FOR = "Illegal value for "; + public static final String METHOD_CALL_FAILED = "Failed to execute this method"; + public static final String CURSOR_NULL = "Cursor cannot be null"; + public static final String NO_COLUMN_ACCESSED = "No column was accessed before calling this " + + "method"; + public static final String RESULT_SET_INIT_ERROR = "ResultSet initialization error"; + public static final String GENERATED_KEYS_NOT_REQUESTED = + "Generated keys not requested. You need to specify " + + "Statement.RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection" + + ".prepareStatement()"; + public static final String NO_KEYSPACE = "Querying Database Information without providing " + + "keyspace"; + public static final String QUERY_FAILED = "One or more queries failed in batch execution"; + public static final String READ_ONLY = "Connection has been set to read only and an update " + + "was attempted"; + public static final String ZERO_TIMESTAMP = "Zero timestamp cannot be represented as java.sql" + + ".Date"; + } + + + public static final class Property { + + @Deprecated + public static final String OLD_TABLET_TYPE = "TABLET_TYPE"; + public static final String TABLET_TYPE = "tabletType"; + public static final String HOST = "host"; + public static final String PORT = "port"; + public static final String DBNAME = "dbName"; + public static final String KEYSPACE = "keyspace"; + public static final String USERNAME = "userName"; + public static final String EXECUTE_TYPE = "executeType"; + public static final String TWOPC_ENABLED = "twopcEnabled"; + public static final String SHARD = "shard"; + + public static final String USE_SSL = "useSSL"; + public static final String KEYSTORE = "keyStore"; + public static final String KEYSTORE_PASSWORD = "keyStorePassword"; + public static final String KEY_ALIAS = "keyAlias"; + public static final String KEY_PASSWORD = "keyPassword"; + public static final String TRUSTSTORE = "trustStore"; + public static final String TRUSTSTORE_PASSWORD = "trustStorePassword"; + public static final String TRUST_ALIAS = "trustAlias"; + + public static final String KEYSTORE_FULL = "javax.net.ssl.keyStore"; + public static final String KEYSTORE_PASSWORD_FULL = "javax.net.ssl.keyStorePassword"; + public static final String KEY_ALIAS_FULL = "javax.net.ssl.keyAlias"; + public static final String KEY_PASSWORD_FULL = "javax.net.ssl.keyPassword"; + public static final String TRUSTSTORE_FULL = "javax.net.ssl.trustStore"; + public static final String TRUSTSTORE_PASSWORD_FULL = "javax.net.ssl.trustStorePassword"; + public static final String TRUST_ALIAS_FULL = "javax.net.ssl.trustAlias"; + public static final String INCLUDED_FIELDS = "includedFields"; + public static final String TARGET = "target"; + } + + + public enum QueryExecuteType { + SIMPLE, STREAM + } + + public enum ZeroDateTimeBehavior { + /** + * This is the current behavior. It completely garbles null timestamps. It is mostly likely + * entirely incorrect but we will keep it for backwards compatibility. + */ + GARBLE, + /** + * This matches the MySQL JDBC driver convertToNull behavior. + */ + CONVERTTONULL, + /** + * This matches the MySQL JDBC driver exception behavior. + */ + EXCEPTION, + /** + * This matches the MySQL JDBC driver round behavior. + */ + ROUND + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/MysqlDefs.java b/java/jdbc/src/main/java/io/vitess/util/MysqlDefs.java index 075b5f4f5da..c52ee81f41a 100644 --- a/java/jdbc/src/main/java/io/vitess/util/MysqlDefs.java +++ b/java/jdbc/src/main/java/io/vitess/util/MysqlDefs.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,13 +16,13 @@ package io.vitess.util; +import io.vitess.proto.Query; + import java.sql.Connection; import java.sql.Types; import java.util.HashMap; import java.util.Map; -import io.vitess.proto.Query; - /** * Created by ashudeep.sharma on 07/03/16. */ @@ -32,519 +32,521 @@ * MysqlDefs contains many values that are needed for communication with the MySQL server. */ public final class MysqlDefs { - public static final int FIELD_TYPE_BLOB = 252; - /** - * Used to indicate that the server sent no field-level character set information, so the driver should use the - * connection-level character encoding instead. - */ - public static final int NO_CHARSET_INFO = -1; - static final int COM_BINLOG_DUMP = 18; - static final int COM_CHANGE_USER = 17; - static final int COM_CLOSE_STATEMENT = 25; - static final int COM_CONNECT_OUT = 20; - static final int COM_END = 29; - static final int COM_EXECUTE = 23; - static final int COM_FETCH = 28; - static final int COM_LONG_DATA = 24; - static final int COM_PREPARE = 22; - static final int COM_REGISTER_SLAVE = 21; - static final int COM_RESET_STMT = 26; - static final int COM_SET_OPTION = 27; - static final int COM_TABLE_DUMP = 19; - static final int CONNECT = 11; - static final int CREATE_DB = 5; - static final int DEBUG = 13; - static final int DELAYED_INSERT = 16; - static final int DROP_DB = 6; - static final int FIELD_LIST = 4; - static final int FIELD_TYPE_BIT = 16; - static final int FIELD_TYPE_DATE = 10; - static final int FIELD_TYPE_DATETIME = 12; - // Data Types - static final int FIELD_TYPE_DECIMAL = 0; - static final int FIELD_TYPE_DOUBLE = 5; - static final int FIELD_TYPE_ENUM = 247; - static final int FIELD_TYPE_FLOAT = 4; - static final int FIELD_TYPE_GEOMETRY = 255; - static final int FIELD_TYPE_INT24 = 9; - static final int FIELD_TYPE_LONG = 3; - static final int FIELD_TYPE_LONG_BLOB = 251; - static final int FIELD_TYPE_LONGLONG = 8; - static final int FIELD_TYPE_MEDIUM_BLOB = 250; - static final int FIELD_TYPE_NEW_DECIMAL = 246; - static final int FIELD_TYPE_NEWDATE = 14; - static final int FIELD_TYPE_NULL = 6; - static final int FIELD_TYPE_SET = 248; - static final int FIELD_TYPE_SHORT = 2; - static final int FIELD_TYPE_STRING = 254; - static final int FIELD_TYPE_TIME = 11; - static final int FIELD_TYPE_TIMESTAMP = 7; - static final int FIELD_TYPE_TINY = 1; - // Older data types - static final int FIELD_TYPE_TINY_BLOB = 249; - static final int FIELD_TYPE_VAR_STRING = 253; - static final int FIELD_TYPE_VARCHAR = 15; - // Newer data types - static final int FIELD_TYPE_YEAR = 13; - static final int FIELD_TYPE_JSON = 245; - static final int INIT_DB = 2; - - // Unlike mysql-vanilla, vtgate returns ints for Field.getLength(). To ensure no type conversion issues, - // we diverge from mysql-connector-j here, who instead have these fields as longs, and have a function clampedGetLength - // to convert field lengths to ints after comparison. - public static final int LENGTH_BLOB = 65535; - public static final int LENGTH_LONGBLOB = Integer.MAX_VALUE; - public static final int LENGTH_MEDIUMBLOB = 16777215; - public static final int LENGTH_TINYBLOB = 255; - - // Limitations - static final int MAX_ROWS = 50000000; // From the MySQL FAQ - static final byte OPEN_CURSOR_FLAG = 1; - - static final int PING = 14; - - static final int PROCESS_INFO = 10; - - static final int PROCESS_KILL = 12; - - static final int QUERY = 3; - - static final int QUIT = 1; - - static final int RELOAD = 7; - - static final int SHUTDOWN = 8; - - // - // Constants defined from mysql - // - // DB Operations - static final int SLEEP = 0; - - static final int STATISTICS = 9; - - static final int TIME = 15; - public static Map vitesstoMySqlType = new HashMap(); - public static Map mysqlConnectionTransactionMapping = - new HashMap(); - private static Map mysqlToJdbcTypesMap = new HashMap(); - - static { - mysqlToJdbcTypesMap.put("BIT", mysqlToJavaType(FIELD_TYPE_BIT)); - - mysqlToJdbcTypesMap.put("TINYINT", mysqlToJavaType(FIELD_TYPE_TINY)); - mysqlToJdbcTypesMap.put("SMALLINT", mysqlToJavaType(FIELD_TYPE_SHORT)); - mysqlToJdbcTypesMap.put("MEDIUMINT", mysqlToJavaType(FIELD_TYPE_INT24)); - mysqlToJdbcTypesMap.put("INT", mysqlToJavaType(FIELD_TYPE_LONG)); - mysqlToJdbcTypesMap.put("INTEGER", mysqlToJavaType(FIELD_TYPE_LONG)); - mysqlToJdbcTypesMap.put("BIGINT", mysqlToJavaType(FIELD_TYPE_LONGLONG)); - mysqlToJdbcTypesMap.put("INT24", mysqlToJavaType(FIELD_TYPE_INT24)); - mysqlToJdbcTypesMap.put("REAL", mysqlToJavaType(FIELD_TYPE_DOUBLE)); - mysqlToJdbcTypesMap.put("FLOAT", mysqlToJavaType(FIELD_TYPE_FLOAT)); - mysqlToJdbcTypesMap.put("DECIMAL", mysqlToJavaType(FIELD_TYPE_DECIMAL)); - mysqlToJdbcTypesMap.put("NUMERIC", mysqlToJavaType(FIELD_TYPE_DECIMAL)); - mysqlToJdbcTypesMap.put("DOUBLE", mysqlToJavaType(FIELD_TYPE_DOUBLE)); - mysqlToJdbcTypesMap.put("CHAR", mysqlToJavaType(FIELD_TYPE_STRING)); - mysqlToJdbcTypesMap.put("VARCHAR", mysqlToJavaType(FIELD_TYPE_VAR_STRING)); - mysqlToJdbcTypesMap.put("DATE", mysqlToJavaType(FIELD_TYPE_DATE)); - mysqlToJdbcTypesMap.put("TIME", mysqlToJavaType(FIELD_TYPE_TIME)); - mysqlToJdbcTypesMap.put("YEAR", mysqlToJavaType(FIELD_TYPE_YEAR)); - mysqlToJdbcTypesMap.put("TIMESTAMP", mysqlToJavaType(FIELD_TYPE_TIMESTAMP)); - mysqlToJdbcTypesMap.put("DATETIME", mysqlToJavaType(FIELD_TYPE_DATETIME)); - mysqlToJdbcTypesMap.put("TINYBLOB", Types.BINARY); - mysqlToJdbcTypesMap.put("BLOB", Types.LONGVARBINARY); - mysqlToJdbcTypesMap.put("MEDIUMBLOB", Types.LONGVARBINARY); - mysqlToJdbcTypesMap.put("LONGBLOB", Types.LONGVARBINARY); - mysqlToJdbcTypesMap.put("TINYTEXT", Types.VARCHAR); - mysqlToJdbcTypesMap.put("TEXT", Types.LONGVARCHAR); - mysqlToJdbcTypesMap.put("MEDIUMTEXT", Types.LONGVARCHAR); - mysqlToJdbcTypesMap.put("LONGTEXT", Types.LONGVARCHAR); - mysqlToJdbcTypesMap.put("ENUM", mysqlToJavaType(FIELD_TYPE_ENUM)); - mysqlToJdbcTypesMap.put("SET", mysqlToJavaType(FIELD_TYPE_SET)); - mysqlToJdbcTypesMap.put("GEOMETRY", mysqlToJavaType(FIELD_TYPE_GEOMETRY)); - mysqlToJdbcTypesMap.put("JSON", mysqlToJavaType(FIELD_TYPE_JSON)); - } - - static { - vitesstoMySqlType.put(Query.Type.NULL_TYPE, Types.NULL); - vitesstoMySqlType.put(Query.Type.INT8, Types.TINYINT); - vitesstoMySqlType.put(Query.Type.UINT8, Types.TINYINT); - vitesstoMySqlType.put(Query.Type.INT16, Types.SMALLINT); - vitesstoMySqlType.put(Query.Type.UINT16, Types.SMALLINT); - vitesstoMySqlType.put(Query.Type.INT24, Types.INTEGER); - vitesstoMySqlType.put(Query.Type.UINT24, Types.INTEGER); - vitesstoMySqlType.put(Query.Type.INT32, Types.INTEGER); - vitesstoMySqlType.put(Query.Type.UINT32, Types.INTEGER); - vitesstoMySqlType.put(Query.Type.INT64, Types.BIGINT); - vitesstoMySqlType.put(Query.Type.UINT64, Types.BIGINT); - vitesstoMySqlType.put(Query.Type.FLOAT32, Types.FLOAT); - vitesstoMySqlType.put(Query.Type.FLOAT64, Types.DOUBLE); - vitesstoMySqlType.put(Query.Type.TIMESTAMP, Types.TIMESTAMP); - vitesstoMySqlType.put(Query.Type.DATE, Types.DATE); - vitesstoMySqlType.put(Query.Type.TIME, Types.TIME); - vitesstoMySqlType.put(Query.Type.DATETIME, Types.TIMESTAMP); - vitesstoMySqlType.put(Query.Type.YEAR, Types.SMALLINT); - vitesstoMySqlType.put(Query.Type.DECIMAL, Types.DECIMAL); - vitesstoMySqlType.put(Query.Type.TEXT, Types.VARCHAR); - vitesstoMySqlType.put(Query.Type.BLOB, Types.BLOB); - vitesstoMySqlType.put(Query.Type.VARCHAR, Types.VARCHAR); - vitesstoMySqlType.put(Query.Type.VARBINARY, Types.VARBINARY); - vitesstoMySqlType.put(Query.Type.CHAR, Types.CHAR); - vitesstoMySqlType.put(Query.Type.BINARY, Types.BINARY); - vitesstoMySqlType.put(Query.Type.BIT, Types.BIT); - vitesstoMySqlType.put(Query.Type.ENUM, Types.CHAR); - vitesstoMySqlType.put(Query.Type.SET, Types.CHAR); - vitesstoMySqlType.put(Query.Type.TUPLE, Types.OTHER); - vitesstoMySqlType.put(Query.Type.GEOMETRY, Types.BINARY); - vitesstoMySqlType.put(Query.Type.JSON, Types.CHAR); - } - - static { - mysqlConnectionTransactionMapping.put("TRANSACTION-NONE", Connection.TRANSACTION_NONE); - mysqlConnectionTransactionMapping - .put("REPEATABLE-READ", Connection.TRANSACTION_REPEATABLE_READ); - mysqlConnectionTransactionMapping - .put("READ-COMMITTED", Connection.TRANSACTION_READ_COMMITTED); - mysqlConnectionTransactionMapping - .put("READ-UNCOMMITTED", Connection.TRANSACTION_READ_UNCOMMITTED); - mysqlConnectionTransactionMapping.put("SERIALIZABLE", Connection.TRANSACTION_SERIALIZABLE); - } - - /** - * Maps the given MySQL type to the correct JDBC type. - */ - public static int mysqlToJavaType(int mysqlType) { - int jdbcType; - switch (mysqlType) { - case MysqlDefs.FIELD_TYPE_NEW_DECIMAL: - case MysqlDefs.FIELD_TYPE_DECIMAL: - jdbcType = Types.DECIMAL; + public static final int FIELD_TYPE_BLOB = 252; + /** + * Used to indicate that the server sent no field-level character set information, so the driver + * should use the connection-level character encoding instead. + */ + public static final int NO_CHARSET_INFO = -1; + static final int COM_BINLOG_DUMP = 18; + static final int COM_CHANGE_USER = 17; + static final int COM_CLOSE_STATEMENT = 25; + static final int COM_CONNECT_OUT = 20; + static final int COM_END = 29; + static final int COM_EXECUTE = 23; + static final int COM_FETCH = 28; + static final int COM_LONG_DATA = 24; + static final int COM_PREPARE = 22; + static final int COM_REGISTER_SLAVE = 21; + static final int COM_RESET_STMT = 26; + static final int COM_SET_OPTION = 27; + static final int COM_TABLE_DUMP = 19; + static final int CONNECT = 11; + static final int CREATE_DB = 5; + static final int DEBUG = 13; + static final int DELAYED_INSERT = 16; + static final int DROP_DB = 6; + static final int FIELD_LIST = 4; + static final int FIELD_TYPE_BIT = 16; + static final int FIELD_TYPE_DATE = 10; + static final int FIELD_TYPE_DATETIME = 12; + // Data Types + static final int FIELD_TYPE_DECIMAL = 0; + static final int FIELD_TYPE_DOUBLE = 5; + static final int FIELD_TYPE_ENUM = 247; + static final int FIELD_TYPE_FLOAT = 4; + static final int FIELD_TYPE_GEOMETRY = 255; + static final int FIELD_TYPE_INT24 = 9; + static final int FIELD_TYPE_LONG = 3; + static final int FIELD_TYPE_LONG_BLOB = 251; + static final int FIELD_TYPE_LONGLONG = 8; + static final int FIELD_TYPE_MEDIUM_BLOB = 250; + static final int FIELD_TYPE_NEW_DECIMAL = 246; + static final int FIELD_TYPE_NEWDATE = 14; + static final int FIELD_TYPE_NULL = 6; + static final int FIELD_TYPE_SET = 248; + static final int FIELD_TYPE_SHORT = 2; + static final int FIELD_TYPE_STRING = 254; + static final int FIELD_TYPE_TIME = 11; + static final int FIELD_TYPE_TIMESTAMP = 7; + static final int FIELD_TYPE_TINY = 1; + // Older data types + static final int FIELD_TYPE_TINY_BLOB = 249; + static final int FIELD_TYPE_VAR_STRING = 253; + static final int FIELD_TYPE_VARCHAR = 15; + // Newer data types + static final int FIELD_TYPE_YEAR = 13; + static final int FIELD_TYPE_JSON = 245; + static final int INIT_DB = 2; + + // Unlike mysql-vanilla, vtgate returns ints for Field.getLength(). To ensure no type + // conversion issues, + // we diverge from mysql-connector-j here, who instead have these fields as longs, and have a + // function clampedGetLength + // to convert field lengths to ints after comparison. + public static final int LENGTH_BLOB = 65535; + public static final int LENGTH_LONGBLOB = Integer.MAX_VALUE; + public static final int LENGTH_MEDIUMBLOB = 16777215; + public static final int LENGTH_TINYBLOB = 255; + + // Limitations + static final int MAX_ROWS = 50000000; // From the MySQL FAQ + static final byte OPEN_CURSOR_FLAG = 1; + + static final int PING = 14; + + static final int PROCESS_INFO = 10; + + static final int PROCESS_KILL = 12; + + static final int QUERY = 3; + + static final int QUIT = 1; + + static final int RELOAD = 7; + + static final int SHUTDOWN = 8; + + // + // Constants defined from mysql + // + // DB Operations + static final int SLEEP = 0; + + static final int STATISTICS = 9; + + static final int TIME = 15; + public static Map vitesstoMySqlType = new HashMap(); + public static Map mysqlConnectionTransactionMapping = new HashMap(); + private static Map mysqlToJdbcTypesMap = new HashMap(); + + static { + mysqlToJdbcTypesMap.put("BIT", mysqlToJavaType(FIELD_TYPE_BIT)); + + mysqlToJdbcTypesMap.put("TINYINT", mysqlToJavaType(FIELD_TYPE_TINY)); + mysqlToJdbcTypesMap.put("SMALLINT", mysqlToJavaType(FIELD_TYPE_SHORT)); + mysqlToJdbcTypesMap.put("MEDIUMINT", mysqlToJavaType(FIELD_TYPE_INT24)); + mysqlToJdbcTypesMap.put("INT", mysqlToJavaType(FIELD_TYPE_LONG)); + mysqlToJdbcTypesMap.put("INTEGER", mysqlToJavaType(FIELD_TYPE_LONG)); + mysqlToJdbcTypesMap.put("BIGINT", mysqlToJavaType(FIELD_TYPE_LONGLONG)); + mysqlToJdbcTypesMap.put("INT24", mysqlToJavaType(FIELD_TYPE_INT24)); + mysqlToJdbcTypesMap.put("REAL", mysqlToJavaType(FIELD_TYPE_DOUBLE)); + mysqlToJdbcTypesMap.put("FLOAT", mysqlToJavaType(FIELD_TYPE_FLOAT)); + mysqlToJdbcTypesMap.put("DECIMAL", mysqlToJavaType(FIELD_TYPE_DECIMAL)); + mysqlToJdbcTypesMap.put("NUMERIC", mysqlToJavaType(FIELD_TYPE_DECIMAL)); + mysqlToJdbcTypesMap.put("DOUBLE", mysqlToJavaType(FIELD_TYPE_DOUBLE)); + mysqlToJdbcTypesMap.put("CHAR", mysqlToJavaType(FIELD_TYPE_STRING)); + mysqlToJdbcTypesMap.put("VARCHAR", mysqlToJavaType(FIELD_TYPE_VAR_STRING)); + mysqlToJdbcTypesMap.put("DATE", mysqlToJavaType(FIELD_TYPE_DATE)); + mysqlToJdbcTypesMap.put("TIME", mysqlToJavaType(FIELD_TYPE_TIME)); + mysqlToJdbcTypesMap.put("YEAR", mysqlToJavaType(FIELD_TYPE_YEAR)); + mysqlToJdbcTypesMap.put("TIMESTAMP", mysqlToJavaType(FIELD_TYPE_TIMESTAMP)); + mysqlToJdbcTypesMap.put("DATETIME", mysqlToJavaType(FIELD_TYPE_DATETIME)); + mysqlToJdbcTypesMap.put("TINYBLOB", Types.BINARY); + mysqlToJdbcTypesMap.put("BLOB", Types.LONGVARBINARY); + mysqlToJdbcTypesMap.put("MEDIUMBLOB", Types.LONGVARBINARY); + mysqlToJdbcTypesMap.put("LONGBLOB", Types.LONGVARBINARY); + mysqlToJdbcTypesMap.put("TINYTEXT", Types.VARCHAR); + mysqlToJdbcTypesMap.put("TEXT", Types.LONGVARCHAR); + mysqlToJdbcTypesMap.put("MEDIUMTEXT", Types.LONGVARCHAR); + mysqlToJdbcTypesMap.put("LONGTEXT", Types.LONGVARCHAR); + mysqlToJdbcTypesMap.put("ENUM", mysqlToJavaType(FIELD_TYPE_ENUM)); + mysqlToJdbcTypesMap.put("SET", mysqlToJavaType(FIELD_TYPE_SET)); + mysqlToJdbcTypesMap.put("GEOMETRY", mysqlToJavaType(FIELD_TYPE_GEOMETRY)); + mysqlToJdbcTypesMap.put("JSON", mysqlToJavaType(FIELD_TYPE_JSON)); + } + + static { + vitesstoMySqlType.put(Query.Type.NULL_TYPE, Types.NULL); + vitesstoMySqlType.put(Query.Type.INT8, Types.TINYINT); + vitesstoMySqlType.put(Query.Type.UINT8, Types.TINYINT); + vitesstoMySqlType.put(Query.Type.INT16, Types.SMALLINT); + vitesstoMySqlType.put(Query.Type.UINT16, Types.SMALLINT); + vitesstoMySqlType.put(Query.Type.INT24, Types.INTEGER); + vitesstoMySqlType.put(Query.Type.UINT24, Types.INTEGER); + vitesstoMySqlType.put(Query.Type.INT32, Types.INTEGER); + vitesstoMySqlType.put(Query.Type.UINT32, Types.INTEGER); + vitesstoMySqlType.put(Query.Type.INT64, Types.BIGINT); + vitesstoMySqlType.put(Query.Type.UINT64, Types.BIGINT); + vitesstoMySqlType.put(Query.Type.FLOAT32, Types.FLOAT); + vitesstoMySqlType.put(Query.Type.FLOAT64, Types.DOUBLE); + vitesstoMySqlType.put(Query.Type.TIMESTAMP, Types.TIMESTAMP); + vitesstoMySqlType.put(Query.Type.DATE, Types.DATE); + vitesstoMySqlType.put(Query.Type.TIME, Types.TIME); + vitesstoMySqlType.put(Query.Type.DATETIME, Types.TIMESTAMP); + vitesstoMySqlType.put(Query.Type.YEAR, Types.SMALLINT); + vitesstoMySqlType.put(Query.Type.DECIMAL, Types.DECIMAL); + vitesstoMySqlType.put(Query.Type.TEXT, Types.VARCHAR); + vitesstoMySqlType.put(Query.Type.BLOB, Types.BLOB); + vitesstoMySqlType.put(Query.Type.VARCHAR, Types.VARCHAR); + vitesstoMySqlType.put(Query.Type.VARBINARY, Types.VARBINARY); + vitesstoMySqlType.put(Query.Type.CHAR, Types.CHAR); + vitesstoMySqlType.put(Query.Type.BINARY, Types.BINARY); + vitesstoMySqlType.put(Query.Type.BIT, Types.BIT); + vitesstoMySqlType.put(Query.Type.ENUM, Types.CHAR); + vitesstoMySqlType.put(Query.Type.SET, Types.CHAR); + vitesstoMySqlType.put(Query.Type.TUPLE, Types.OTHER); + vitesstoMySqlType.put(Query.Type.GEOMETRY, Types.BINARY); + vitesstoMySqlType.put(Query.Type.JSON, Types.CHAR); + } + + static { + mysqlConnectionTransactionMapping.put("TRANSACTION-NONE", Connection.TRANSACTION_NONE); + mysqlConnectionTransactionMapping + .put("REPEATABLE-READ", Connection.TRANSACTION_REPEATABLE_READ); + mysqlConnectionTransactionMapping.put("READ-COMMITTED", Connection.TRANSACTION_READ_COMMITTED); + mysqlConnectionTransactionMapping + .put("READ-UNCOMMITTED", Connection.TRANSACTION_READ_UNCOMMITTED); + mysqlConnectionTransactionMapping.put("SERIALIZABLE", Connection.TRANSACTION_SERIALIZABLE); + } + + /** + * Maps the given MySQL type to the correct JDBC type. + */ + public static int mysqlToJavaType(int mysqlType) { + int jdbcType; + + switch (mysqlType) { + case MysqlDefs.FIELD_TYPE_NEW_DECIMAL: + case MysqlDefs.FIELD_TYPE_DECIMAL: + jdbcType = Types.DECIMAL; + + break; + + case MysqlDefs.FIELD_TYPE_TINY: + jdbcType = Types.TINYINT; + + break; + + case MysqlDefs.FIELD_TYPE_SHORT: + jdbcType = Types.SMALLINT; + + break; - break; + case MysqlDefs.FIELD_TYPE_LONG: + jdbcType = Types.INTEGER; + + break; - case MysqlDefs.FIELD_TYPE_TINY: - jdbcType = Types.TINYINT; + case MysqlDefs.FIELD_TYPE_FLOAT: + jdbcType = Types.REAL; - break; + break; - case MysqlDefs.FIELD_TYPE_SHORT: - jdbcType = Types.SMALLINT; + case MysqlDefs.FIELD_TYPE_DOUBLE: + jdbcType = Types.DOUBLE; - break; + break; - case MysqlDefs.FIELD_TYPE_LONG: - jdbcType = Types.INTEGER; + case MysqlDefs.FIELD_TYPE_NULL: + jdbcType = Types.NULL; - break; + break; - case MysqlDefs.FIELD_TYPE_FLOAT: - jdbcType = Types.REAL; + case MysqlDefs.FIELD_TYPE_TIMESTAMP: + jdbcType = Types.TIMESTAMP; - break; + break; - case MysqlDefs.FIELD_TYPE_DOUBLE: - jdbcType = Types.DOUBLE; + case MysqlDefs.FIELD_TYPE_LONGLONG: + jdbcType = Types.BIGINT; - break; + break; - case MysqlDefs.FIELD_TYPE_NULL: - jdbcType = Types.NULL; + case MysqlDefs.FIELD_TYPE_INT24: + jdbcType = Types.INTEGER; - break; + break; - case MysqlDefs.FIELD_TYPE_TIMESTAMP: - jdbcType = Types.TIMESTAMP; + case MysqlDefs.FIELD_TYPE_DATE: + jdbcType = Types.DATE; - break; + break; - case MysqlDefs.FIELD_TYPE_LONGLONG: - jdbcType = Types.BIGINT; + case MysqlDefs.FIELD_TYPE_TIME: + jdbcType = Types.TIME; - break; + break; - case MysqlDefs.FIELD_TYPE_INT24: - jdbcType = Types.INTEGER; + case MysqlDefs.FIELD_TYPE_DATETIME: + jdbcType = Types.TIMESTAMP; - break; + break; - case MysqlDefs.FIELD_TYPE_DATE: - jdbcType = Types.DATE; + case MysqlDefs.FIELD_TYPE_YEAR: + jdbcType = Types.DATE; - break; + break; - case MysqlDefs.FIELD_TYPE_TIME: - jdbcType = Types.TIME; + case MysqlDefs.FIELD_TYPE_NEWDATE: + jdbcType = Types.DATE; - break; + break; - case MysqlDefs.FIELD_TYPE_DATETIME: - jdbcType = Types.TIMESTAMP; + case MysqlDefs.FIELD_TYPE_ENUM: + jdbcType = Types.CHAR; - break; + break; - case MysqlDefs.FIELD_TYPE_YEAR: - jdbcType = Types.DATE; + case MysqlDefs.FIELD_TYPE_SET: + jdbcType = Types.CHAR; - break; + break; - case MysqlDefs.FIELD_TYPE_NEWDATE: - jdbcType = Types.DATE; + case MysqlDefs.FIELD_TYPE_TINY_BLOB: + jdbcType = Types.VARBINARY; - break; + break; - case MysqlDefs.FIELD_TYPE_ENUM: - jdbcType = Types.CHAR; + case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: + jdbcType = Types.LONGVARBINARY; - break; + break; - case MysqlDefs.FIELD_TYPE_SET: - jdbcType = Types.CHAR; + case MysqlDefs.FIELD_TYPE_LONG_BLOB: + jdbcType = Types.LONGVARBINARY; - break; + break; - case MysqlDefs.FIELD_TYPE_TINY_BLOB: - jdbcType = Types.VARBINARY; + case MysqlDefs.FIELD_TYPE_BLOB: + jdbcType = Types.LONGVARBINARY; - break; + break; - case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: - jdbcType = Types.LONGVARBINARY; + case MysqlDefs.FIELD_TYPE_VAR_STRING: + case MysqlDefs.FIELD_TYPE_VARCHAR: + jdbcType = Types.VARCHAR; - break; + break; - case MysqlDefs.FIELD_TYPE_LONG_BLOB: - jdbcType = Types.LONGVARBINARY; + case MysqlDefs.FIELD_TYPE_JSON: + case MysqlDefs.FIELD_TYPE_STRING: + jdbcType = Types.CHAR; - break; + break; + case MysqlDefs.FIELD_TYPE_GEOMETRY: + jdbcType = Types.BINARY; - case MysqlDefs.FIELD_TYPE_BLOB: - jdbcType = Types.LONGVARBINARY; + break; + case MysqlDefs.FIELD_TYPE_BIT: + jdbcType = Types.BIT; - break; - - case MysqlDefs.FIELD_TYPE_VAR_STRING: - case MysqlDefs.FIELD_TYPE_VARCHAR: - jdbcType = Types.VARCHAR; - - break; - - case MysqlDefs.FIELD_TYPE_JSON: - case MysqlDefs.FIELD_TYPE_STRING: - jdbcType = Types.CHAR; - - break; - case MysqlDefs.FIELD_TYPE_GEOMETRY: - jdbcType = Types.BINARY; - - break; - case MysqlDefs.FIELD_TYPE_BIT: - jdbcType = Types.BIT; - - break; - default: - jdbcType = Types.VARCHAR; - } - - return jdbcType; + break; + default: + jdbcType = Types.VARCHAR; } - /** - * Maps the given MySQL type to the correct JDBC type. - */ - public static int mysqlToJavaType(String mysqlType) { - if (mysqlType.equalsIgnoreCase("BIT")) { - return mysqlToJavaType(FIELD_TYPE_BIT); - } else if (mysqlType.equalsIgnoreCase("TINYINT")) { - return mysqlToJavaType(FIELD_TYPE_TINY); - } else if (mysqlType.equalsIgnoreCase("SMALLINT")) { - return mysqlToJavaType(FIELD_TYPE_SHORT); - } else if (mysqlType.equalsIgnoreCase("MEDIUMINT")) { - return mysqlToJavaType(FIELD_TYPE_INT24); - } else if (mysqlType.equalsIgnoreCase("INT") || mysqlType.equalsIgnoreCase("INTEGER")) { - return mysqlToJavaType(FIELD_TYPE_LONG); - } else if (mysqlType.equalsIgnoreCase("BIGINT")) { - return mysqlToJavaType(FIELD_TYPE_LONGLONG); - } else if (mysqlType.equalsIgnoreCase("INT24")) { - return mysqlToJavaType(FIELD_TYPE_INT24); - } else if (mysqlType.equalsIgnoreCase("REAL")) { - return mysqlToJavaType(FIELD_TYPE_DOUBLE); - } else if (mysqlType.equalsIgnoreCase("FLOAT")) { - return mysqlToJavaType(FIELD_TYPE_FLOAT); - } else if (mysqlType.equalsIgnoreCase("DECIMAL")) { - return mysqlToJavaType(FIELD_TYPE_DECIMAL); - } else if (mysqlType.equalsIgnoreCase("NUMERIC")) { - return mysqlToJavaType(FIELD_TYPE_DECIMAL); - } else if (mysqlType.equalsIgnoreCase("DOUBLE")) { - return mysqlToJavaType(FIELD_TYPE_DOUBLE); - } else if (mysqlType.equalsIgnoreCase("CHAR")) { - return mysqlToJavaType(FIELD_TYPE_STRING); - } else if (mysqlType.equalsIgnoreCase("VARCHAR")) { - return mysqlToJavaType(FIELD_TYPE_VAR_STRING); - } else if (mysqlType.equalsIgnoreCase("DATE")) { - return mysqlToJavaType(FIELD_TYPE_DATE); - } else if (mysqlType.equalsIgnoreCase("TIME")) { - return mysqlToJavaType(FIELD_TYPE_TIME); - } else if (mysqlType.equalsIgnoreCase("YEAR")) { - return mysqlToJavaType(FIELD_TYPE_YEAR); - } else if (mysqlType.equalsIgnoreCase("TIMESTAMP")) { - return mysqlToJavaType(FIELD_TYPE_TIMESTAMP); - } else if (mysqlType.equalsIgnoreCase("DATETIME")) { - return mysqlToJavaType(FIELD_TYPE_DATETIME); - } else if (mysqlType.equalsIgnoreCase("TINYBLOB")) { - return Types.BINARY; - } else if (mysqlType.equalsIgnoreCase("BLOB")) { - return Types.LONGVARBINARY; - } else if (mysqlType.equalsIgnoreCase("MEDIUMBLOB")) { - return Types.LONGVARBINARY; - } else if (mysqlType.equalsIgnoreCase("LONGBLOB")) { - return Types.LONGVARBINARY; - } else if (mysqlType.equalsIgnoreCase("TINYTEXT")) { - return Types.VARCHAR; - } else if (mysqlType.equalsIgnoreCase("TEXT")) { - return Types.LONGVARCHAR; - } else if (mysqlType.equalsIgnoreCase("MEDIUMTEXT")) { - return Types.LONGVARCHAR; - } else if (mysqlType.equalsIgnoreCase("LONGTEXT")) { - return Types.LONGVARCHAR; - } else if (mysqlType.equalsIgnoreCase("ENUM")) { - return mysqlToJavaType(FIELD_TYPE_ENUM); - } else if (mysqlType.equalsIgnoreCase("SET")) { - return mysqlToJavaType(FIELD_TYPE_SET); - } else if (mysqlType.equalsIgnoreCase("GEOMETRY")) { - return mysqlToJavaType(FIELD_TYPE_GEOMETRY); - } else if (mysqlType.equalsIgnoreCase("BINARY")) { - return Types.BINARY; // no concrete type on the wire - } else if (mysqlType.equalsIgnoreCase("VARBINARY")) { - return Types.VARBINARY; // no concrete type on the wire - } else if (mysqlType.equalsIgnoreCase("BIT")) { - return mysqlToJavaType(FIELD_TYPE_BIT); - } else if (mysqlType.equalsIgnoreCase("JSON")) { - return mysqlToJavaType(FIELD_TYPE_JSON); - } - - // Punt - return Types.OTHER; + return jdbcType; + } + + /** + * Maps the given MySQL type to the correct JDBC type. + */ + public static int mysqlToJavaType(String mysqlType) { + if (mysqlType.equalsIgnoreCase("BIT")) { + return mysqlToJavaType(FIELD_TYPE_BIT); + } else if (mysqlType.equalsIgnoreCase("TINYINT")) { + return mysqlToJavaType(FIELD_TYPE_TINY); + } else if (mysqlType.equalsIgnoreCase("SMALLINT")) { + return mysqlToJavaType(FIELD_TYPE_SHORT); + } else if (mysqlType.equalsIgnoreCase("MEDIUMINT")) { + return mysqlToJavaType(FIELD_TYPE_INT24); + } else if (mysqlType.equalsIgnoreCase("INT") || mysqlType.equalsIgnoreCase("INTEGER")) { + return mysqlToJavaType(FIELD_TYPE_LONG); + } else if (mysqlType.equalsIgnoreCase("BIGINT")) { + return mysqlToJavaType(FIELD_TYPE_LONGLONG); + } else if (mysqlType.equalsIgnoreCase("INT24")) { + return mysqlToJavaType(FIELD_TYPE_INT24); + } else if (mysqlType.equalsIgnoreCase("REAL")) { + return mysqlToJavaType(FIELD_TYPE_DOUBLE); + } else if (mysqlType.equalsIgnoreCase("FLOAT")) { + return mysqlToJavaType(FIELD_TYPE_FLOAT); + } else if (mysqlType.equalsIgnoreCase("DECIMAL")) { + return mysqlToJavaType(FIELD_TYPE_DECIMAL); + } else if (mysqlType.equalsIgnoreCase("NUMERIC")) { + return mysqlToJavaType(FIELD_TYPE_DECIMAL); + } else if (mysqlType.equalsIgnoreCase("DOUBLE")) { + return mysqlToJavaType(FIELD_TYPE_DOUBLE); + } else if (mysqlType.equalsIgnoreCase("CHAR")) { + return mysqlToJavaType(FIELD_TYPE_STRING); + } else if (mysqlType.equalsIgnoreCase("VARCHAR")) { + return mysqlToJavaType(FIELD_TYPE_VAR_STRING); + } else if (mysqlType.equalsIgnoreCase("DATE")) { + return mysqlToJavaType(FIELD_TYPE_DATE); + } else if (mysqlType.equalsIgnoreCase("TIME")) { + return mysqlToJavaType(FIELD_TYPE_TIME); + } else if (mysqlType.equalsIgnoreCase("YEAR")) { + return mysqlToJavaType(FIELD_TYPE_YEAR); + } else if (mysqlType.equalsIgnoreCase("TIMESTAMP")) { + return mysqlToJavaType(FIELD_TYPE_TIMESTAMP); + } else if (mysqlType.equalsIgnoreCase("DATETIME")) { + return mysqlToJavaType(FIELD_TYPE_DATETIME); + } else if (mysqlType.equalsIgnoreCase("TINYBLOB")) { + return Types.BINARY; + } else if (mysqlType.equalsIgnoreCase("BLOB")) { + return Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("MEDIUMBLOB")) { + return Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("LONGBLOB")) { + return Types.LONGVARBINARY; + } else if (mysqlType.equalsIgnoreCase("TINYTEXT")) { + return Types.VARCHAR; + } else if (mysqlType.equalsIgnoreCase("TEXT")) { + return Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("MEDIUMTEXT")) { + return Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("LONGTEXT")) { + return Types.LONGVARCHAR; + } else if (mysqlType.equalsIgnoreCase("ENUM")) { + return mysqlToJavaType(FIELD_TYPE_ENUM); + } else if (mysqlType.equalsIgnoreCase("SET")) { + return mysqlToJavaType(FIELD_TYPE_SET); + } else if (mysqlType.equalsIgnoreCase("GEOMETRY")) { + return mysqlToJavaType(FIELD_TYPE_GEOMETRY); + } else if (mysqlType.equalsIgnoreCase("BINARY")) { + return Types.BINARY; // no concrete type on the wire + } else if (mysqlType.equalsIgnoreCase("VARBINARY")) { + return Types.VARBINARY; // no concrete type on the wire + } else if (mysqlType.equalsIgnoreCase("BIT")) { + return mysqlToJavaType(FIELD_TYPE_BIT); + } else if (mysqlType.equalsIgnoreCase("JSON")) { + return mysqlToJavaType(FIELD_TYPE_JSON); } - /** - * @param mysqlType - */ - public static String typeToName(int mysqlType) { - switch (mysqlType) { - case MysqlDefs.FIELD_TYPE_DECIMAL: - return "FIELD_TYPE_DECIMAL"; + // Punt + return Types.OTHER; + } - case MysqlDefs.FIELD_TYPE_TINY: - return "FIELD_TYPE_TINY"; + /** + * + */ + public static String typeToName(int mysqlType) { + switch (mysqlType) { + case MysqlDefs.FIELD_TYPE_DECIMAL: + return "FIELD_TYPE_DECIMAL"; - case MysqlDefs.FIELD_TYPE_SHORT: - return "FIELD_TYPE_SHORT"; + case MysqlDefs.FIELD_TYPE_TINY: + return "FIELD_TYPE_TINY"; - case MysqlDefs.FIELD_TYPE_LONG: - return "FIELD_TYPE_LONG"; + case MysqlDefs.FIELD_TYPE_SHORT: + return "FIELD_TYPE_SHORT"; - case MysqlDefs.FIELD_TYPE_FLOAT: - return "FIELD_TYPE_FLOAT"; + case MysqlDefs.FIELD_TYPE_LONG: + return "FIELD_TYPE_LONG"; - case MysqlDefs.FIELD_TYPE_DOUBLE: - return "FIELD_TYPE_DOUBLE"; + case MysqlDefs.FIELD_TYPE_FLOAT: + return "FIELD_TYPE_FLOAT"; - case MysqlDefs.FIELD_TYPE_NULL: - return "FIELD_TYPE_NULL"; + case MysqlDefs.FIELD_TYPE_DOUBLE: + return "FIELD_TYPE_DOUBLE"; - case MysqlDefs.FIELD_TYPE_TIMESTAMP: - return "FIELD_TYPE_TIMESTAMP"; + case MysqlDefs.FIELD_TYPE_NULL: + return "FIELD_TYPE_NULL"; - case MysqlDefs.FIELD_TYPE_LONGLONG: - return "FIELD_TYPE_LONGLONG"; + case MysqlDefs.FIELD_TYPE_TIMESTAMP: + return "FIELD_TYPE_TIMESTAMP"; - case MysqlDefs.FIELD_TYPE_INT24: - return "FIELD_TYPE_INT24"; + case MysqlDefs.FIELD_TYPE_LONGLONG: + return "FIELD_TYPE_LONGLONG"; - case MysqlDefs.FIELD_TYPE_DATE: - return "FIELD_TYPE_DATE"; + case MysqlDefs.FIELD_TYPE_INT24: + return "FIELD_TYPE_INT24"; - case MysqlDefs.FIELD_TYPE_TIME: - return "FIELD_TYPE_TIME"; + case MysqlDefs.FIELD_TYPE_DATE: + return "FIELD_TYPE_DATE"; - case MysqlDefs.FIELD_TYPE_DATETIME: - return "FIELD_TYPE_DATETIME"; + case MysqlDefs.FIELD_TYPE_TIME: + return "FIELD_TYPE_TIME"; - case MysqlDefs.FIELD_TYPE_YEAR: - return "FIELD_TYPE_YEAR"; + case MysqlDefs.FIELD_TYPE_DATETIME: + return "FIELD_TYPE_DATETIME"; - case MysqlDefs.FIELD_TYPE_NEWDATE: - return "FIELD_TYPE_NEWDATE"; + case MysqlDefs.FIELD_TYPE_YEAR: + return "FIELD_TYPE_YEAR"; - case MysqlDefs.FIELD_TYPE_ENUM: - return "FIELD_TYPE_ENUM"; + case MysqlDefs.FIELD_TYPE_NEWDATE: + return "FIELD_TYPE_NEWDATE"; - case MysqlDefs.FIELD_TYPE_SET: - return "FIELD_TYPE_SET"; + case MysqlDefs.FIELD_TYPE_ENUM: + return "FIELD_TYPE_ENUM"; - case MysqlDefs.FIELD_TYPE_TINY_BLOB: - return "FIELD_TYPE_TINY_BLOB"; + case MysqlDefs.FIELD_TYPE_SET: + return "FIELD_TYPE_SET"; - case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: - return "FIELD_TYPE_MEDIUM_BLOB"; + case MysqlDefs.FIELD_TYPE_TINY_BLOB: + return "FIELD_TYPE_TINY_BLOB"; - case MysqlDefs.FIELD_TYPE_LONG_BLOB: - return "FIELD_TYPE_LONG_BLOB"; + case MysqlDefs.FIELD_TYPE_MEDIUM_BLOB: + return "FIELD_TYPE_MEDIUM_BLOB"; - case MysqlDefs.FIELD_TYPE_BLOB: - return "FIELD_TYPE_BLOB"; + case MysqlDefs.FIELD_TYPE_LONG_BLOB: + return "FIELD_TYPE_LONG_BLOB"; - case MysqlDefs.FIELD_TYPE_VAR_STRING: - return "FIELD_TYPE_VAR_STRING"; + case MysqlDefs.FIELD_TYPE_BLOB: + return "FIELD_TYPE_BLOB"; - case MysqlDefs.FIELD_TYPE_STRING: - return "FIELD_TYPE_STRING"; + case MysqlDefs.FIELD_TYPE_VAR_STRING: + return "FIELD_TYPE_VAR_STRING"; - case MysqlDefs.FIELD_TYPE_VARCHAR: - return "FIELD_TYPE_VARCHAR"; + case MysqlDefs.FIELD_TYPE_STRING: + return "FIELD_TYPE_STRING"; - case MysqlDefs.FIELD_TYPE_GEOMETRY: - return "FIELD_TYPE_GEOMETRY"; + case MysqlDefs.FIELD_TYPE_VARCHAR: + return "FIELD_TYPE_VARCHAR"; - case MysqlDefs.FIELD_TYPE_JSON: - return "FIELD_TYPE_JSON"; + case MysqlDefs.FIELD_TYPE_GEOMETRY: + return "FIELD_TYPE_GEOMETRY"; - default: - return " Unknown MySQL Type # " + mysqlType; - } - } + case MysqlDefs.FIELD_TYPE_JSON: + return "FIELD_TYPE_JSON"; - static void appendJdbcTypeMappingQuery(StringBuilder buf, String mysqlTypeColumnName) { - - buf.append("CASE "); - Map typesMap = new HashMap(); - typesMap.putAll(mysqlToJdbcTypesMap); - typesMap.put("BINARY", Types.BINARY); - typesMap.put("VARBINARY", Types.VARBINARY); - - for (String mysqlTypeName : typesMap.keySet()) { - buf.append(" WHEN "); - buf.append(mysqlTypeColumnName); - buf.append("='"); - buf.append(mysqlTypeName); - buf.append("' THEN "); - buf.append(typesMap.get(mysqlTypeName)); - - if (mysqlTypeName.equalsIgnoreCase("DOUBLE") || mysqlTypeName.equalsIgnoreCase("FLOAT") - || mysqlTypeName.equalsIgnoreCase("DECIMAL") || mysqlTypeName - .equalsIgnoreCase("NUMERIC")) { - buf.append(" WHEN "); - buf.append(mysqlTypeColumnName); - buf.append("='"); - buf.append(mysqlTypeName); - buf.append(" unsigned' THEN "); - buf.append(typesMap.get(mysqlTypeName)); - } - } - - buf.append(" ELSE "); - buf.append(Types.OTHER); - buf.append(" END "); + default: + return " Unknown MySQL Type # " + mysqlType; } + } + + static void appendJdbcTypeMappingQuery(StringBuilder buf, String mysqlTypeColumnName) { + + buf.append("CASE "); + Map typesMap = new HashMap(); + typesMap.putAll(mysqlToJdbcTypesMap); + typesMap.put("BINARY", Types.BINARY); + typesMap.put("VARBINARY", Types.VARBINARY); + + for (String mysqlTypeName : typesMap.keySet()) { + buf.append(" WHEN "); + buf.append(mysqlTypeColumnName); + buf.append("='"); + buf.append(mysqlTypeName); + buf.append("' THEN "); + buf.append(typesMap.get(mysqlTypeName)); + + if (mysqlTypeName.equalsIgnoreCase("DOUBLE") || mysqlTypeName.equalsIgnoreCase("FLOAT") + || mysqlTypeName.equalsIgnoreCase("DECIMAL") || mysqlTypeName + .equalsIgnoreCase("NUMERIC")) { + buf.append(" WHEN "); + buf.append(mysqlTypeColumnName); + buf.append("='"); + buf.append(mysqlTypeName); + buf.append(" unsigned' THEN "); + buf.append(typesMap.get(mysqlTypeName)); + } + } + + buf.append(" ELSE "); + buf.append(Types.OTHER); + buf.append(" END "); + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/StringUtils.java b/java/jdbc/src/main/java/io/vitess/util/StringUtils.java index 96b4203d70d..4173f025e7f 100644 --- a/java/jdbc/src/main/java/io/vitess/util/StringUtils.java +++ b/java/jdbc/src/main/java/io/vitess/util/StringUtils.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -34,927 +34,908 @@ */ public class StringUtils { - private static final String platformEncoding = System.getProperty("file.encoding"); - private static final ConcurrentHashMap charsetsByAlias = new ConcurrentHashMap(); - - // length of MySQL version reference in comments of type '/*![00000] */' - private static final int NON_COMMENTS_MYSQL_VERSION_REF_LENGTH = 5; + /** + * Full search mode: allow backslash escape, skip between markers, skip block comments, skip line + * comments and skip white space. + */ + public static final Set SEARCH_MODE__ALL = Collections + .unmodifiableSet(EnumSet.allOf(SearchMode.class)); + /** + * Search mode: skip between markers, skip block comments, skip line comments and skip white + * space. + */ + public static final Set SEARCH_MODE__MRK_COM_WS = Collections.unmodifiableSet(EnumSet + .of(SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS, + SearchMode.SKIP_LINE_COMMENTS, SearchMode.SKIP_WHITE_SPACE)); + private static final String platformEncoding = System.getProperty("file.encoding"); + private static final ConcurrentHashMap charsetsByAlias = + new ConcurrentHashMap(); + // length of MySQL version reference in comments of type '/*![00000] */' + private static final int NON_COMMENTS_MYSQL_VERSION_REF_LENGTH = 5; + + /* + * Convenience EnumSets for several SearchMode combinations + */ + + private StringUtils() { + } + + /** + * Determines whether or not the string 'searchIn' contains the string 'searchFor', disregarding + * case and leading whitespace + * + * @param searchIn the string to search in + * @param searchFor the string to search for + * @return true if the string starts with 'searchFor' ignoring whitespace + */ + public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor) { + return startsWithIgnoreCaseAndWs(searchIn, searchFor, 0); + } + + /** + * Determines whether or not the string 'searchIn' contains the string 'searchFor', disregarding + * case and leading whitespace + * + * @param searchIn the string to search in + * @param searchFor the string to search for + * @param beginPos where to start searching + * @return true if the string starts with 'searchFor' ignoring whitespace + */ + + public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor, int beginPos) { + if (null == searchIn) { + return true; + } + int inLength = searchIn.length(); - private StringUtils() { + for (; beginPos < inLength; beginPos++) { + if (!Character.isWhitespace(searchIn.charAt(beginPos))) { + break; + } } - public enum SearchMode { - ALLOW_BACKSLASH_ESCAPE, SKIP_BETWEEN_MARKERS, SKIP_BLOCK_COMMENTS, SKIP_LINE_COMMENTS, SKIP_WHITE_SPACE; + return startsWithIgnoreCase(searchIn, beginPos, searchFor); + } + + /** + * Determines whether or not the string 'searchIn' contains the string 'searchFor', dis-regarding + * case starting at 'startAt' Shorthand for a String.regionMatch(...) + * + * @param searchIn the string to search in + * @param startAt the position to start at + * @param searchFor the string to search for + * @return whether searchIn starts with searchFor, ignoring case + */ + public static boolean startsWithIgnoreCase(String searchIn, int startAt, String searchFor) { + return searchIn.regionMatches(true, startAt, searchFor, 0, searchFor.length()); + } + + private static boolean isCharEqualIgnoreCase(char charToCompare, char compareToCharUC, + char compareToCharLC) { + return Character.toLowerCase(charToCompare) == compareToCharLC + || Character.toUpperCase(charToCompare) == compareToCharUC; + } + + public static boolean isNullOrEmptyWithoutWS(String string) { + return null == string || 0 == string.trim().length(); + } + + /** + * Create the SQL string with parameters set by setXXX methods of PreparedStatement + * + * @return updated SQL string + */ + public static String getSqlWithoutParameter(String sql, Map parameterMap) { + if (!sql.contains("?")) { + return sql; } - /* - * Convenience EnumSets for several SearchMode combinations - */ - - /** - * Full search mode: allow backslash escape, skip between markers, skip block comments, skip line comments and skip white space. - */ - public static final Set SEARCH_MODE__ALL = Collections.unmodifiableSet(EnumSet.allOf(SearchMode.class)); - - /** - * Search mode: skip between markers, skip block comments, skip line comments and skip white space. - */ - public static final Set SEARCH_MODE__MRK_COM_WS = Collections.unmodifiableSet( - EnumSet.of(SearchMode.SKIP_BETWEEN_MARKERS, SearchMode.SKIP_BLOCK_COMMENTS, SearchMode.SKIP_LINE_COMMENTS, SearchMode.SKIP_WHITE_SPACE)); - - /** - * Determines whether or not the string 'searchIn' contains the string - * 'searchFor', disregarding case and leading whitespace - * - * @param searchIn the string to search in - * @param searchFor the string to search for - * @return true if the string starts with 'searchFor' ignoring whitespace - */ - public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor) { - return startsWithIgnoreCaseAndWs(searchIn, searchFor, 0); + StringBuilder newSql = new StringBuilder(sql); + + int paramLoc = 1; + while (getCharIndexFromSqlByParamLocation(sql, '?', paramLoc) > 0) { + // check the user has set the needs parameters + if (parameterMap.containsKey(paramLoc)) { + int tt = getCharIndexFromSqlByParamLocation(newSql.toString(), '?', 1); + newSql.deleteCharAt(tt); + newSql.insert(tt, parameterMap.get(paramLoc)); + } + paramLoc++; } - /** - * Determines whether or not the string 'searchIn' contains the string - * 'searchFor', disregarding case and leading whitespace - * - * @param searchIn the string to search in - * @param searchFor the string to search for - * @param beginPos where to start searching - * @return true if the string starts with 'searchFor' ignoring whitespace - */ - - public static boolean startsWithIgnoreCaseAndWs(String searchIn, String searchFor, - int beginPos) { - if (null == searchIn) { - return true; - } - - int inLength = searchIn.length(); - - for (; beginPos < inLength; beginPos++) { - if (!Character.isWhitespace(searchIn.charAt(beginPos))) { - break; - } - } - - return startsWithIgnoreCase(searchIn, beginPos, searchFor); + return newSql.toString(); + + } + + /** + * Get the index of given char from the SQL string by parameter location + *
The -1 will be return, if nothing found + */ + private static int getCharIndexFromSqlByParamLocation(final String sql, final char cchar, + final int paramLoc) { + int signalCount = 0; + int charIndex = -1; + int num = 0; + for (int i = 0; i < sql.length(); i++) { + char c = sql.charAt(i); + if (c == '\'' || c == '\\') { // record the count of char "'" and char "\" + signalCount++; + } else if (c == cchar && signalCount % 2 == 0) { // check if the ? is really the parameter + num++; + if (num == paramLoc) { + charIndex = i; + break; + } + } } - - /** - * Determines whether or not the string 'searchIn' contains the string - * 'searchFor', dis-regarding case starting at 'startAt' Shorthand for a - * String.regionMatch(...) - * - * @param searchIn the string to search in - * @param startAt the position to start at - * @param searchFor the string to search for - * @return whether searchIn starts with searchFor, ignoring case - */ - public static boolean startsWithIgnoreCase(String searchIn, int startAt, String searchFor) { - return searchIn.regionMatches(true, startAt, searchFor, 0, searchFor.length()); + return charIndex; + } + + /** + * Adds '+' to decimal numbers that are positive (MySQL doesn't understand them otherwise + * + * @param decimalString The value as a string + * @return String the string with a '+' added (if needed) + */ + public static String fixDecimalExponent(String decimalString) { + int ePos = decimalString.indexOf('E'); + + if (ePos == -1) { + ePos = decimalString.indexOf('e'); } - private static boolean isCharEqualIgnoreCase(char charToCompare, char compareToCharUC, char compareToCharLC) { - return Character.toLowerCase(charToCompare) == compareToCharLC || Character.toUpperCase(charToCompare) == compareToCharUC; - } + if (ePos != -1) { + if (decimalString.length() > (ePos + 1)) { + char maybeMinusChar = decimalString.charAt(ePos + 1); - public static boolean isNullOrEmptyWithoutWS(String string) { - return null == string || 0 == string.trim().length(); + if (maybeMinusChar != '-' && maybeMinusChar != '+') { + StringBuilder strBuilder = new StringBuilder(decimalString.length() + 1); + strBuilder.append(decimalString.substring(0, ePos + 1)); + strBuilder.append('+'); + strBuilder.append(decimalString.substring(ePos + 1, decimalString.length())); + decimalString = strBuilder.toString(); + } + } } - /** - * Create the SQL string with parameters set by setXXX methods of PreparedStatement - * - * @param sql - * @param parameterMap - * @return updated SQL string - */ - public static String getSqlWithoutParameter(String sql, Map parameterMap) { - if (!sql.contains("?")) { - return sql; - } + return decimalString; + } - StringBuilder newSql = new StringBuilder(sql); + /* + * DateTime Format Parsing Logic from Mysql JDBC + */ + public static String getDateTimePattern(String dt, boolean toTime) throws Exception { + int dtLength = (dt != null) ? dt.length() : 0; - int paramLoc = 1; - while (getCharIndexFromSqlByParamLocation(sql, '?', paramLoc) > 0) { - // check the user has set the needs parameters - if (parameterMap.containsKey(paramLoc)) { - int tt = getCharIndexFromSqlByParamLocation(newSql.toString(), '?', 1); - newSql.deleteCharAt(tt); - newSql.insert(tt, parameterMap.get(paramLoc)); - } - paramLoc++; - } + if ((dtLength >= 8) && (dtLength <= 10)) { + int dashCount = 0; + boolean isDateOnly = true; - return newSql.toString(); - - } - - /** - * Get the index of given char from the SQL string by parameter location - *
The -1 will be return, if nothing found - * - * @param sql - * @param cchar - * @param paramLoc - * @return - */ - private static int getCharIndexFromSqlByParamLocation(final String sql, final char cchar, - final int paramLoc) { - int signalCount = 0; - int charIndex = -1; - int num = 0; - for (int i = 0; i < sql.length(); i++) { - char c = sql.charAt(i); - if (c == '\'' || c == '\\')// record the count of char "'" and char "\" - { - signalCount++; - } else if (c == cchar - && signalCount % 2 == 0) {// check if the ? is really the parameter - num++; - if (num == paramLoc) { - charIndex = i; - break; - } - } - } - return charIndex; - } + for (int i = 0; i < dtLength; i++) { + char c = dt.charAt(i); - /** - * Adds '+' to decimal numbers that are positive (MySQL doesn't understand - * them otherwise - * - * @param decimalString The value as a string - * @return String the string with a '+' added (if needed) - */ - public static String fixDecimalExponent(String decimalString) { - int ePos = decimalString.indexOf('E'); + if (!Character.isDigit(c) && (c != '-')) { + isDateOnly = false; - if (ePos == -1) { - ePos = decimalString.indexOf('e'); + break; } - if (ePos != -1) { - if (decimalString.length() > (ePos + 1)) { - char maybeMinusChar = decimalString.charAt(ePos + 1); - - if (maybeMinusChar != '-' && maybeMinusChar != '+') { - StringBuilder strBuilder = new StringBuilder(decimalString.length() + 1); - strBuilder.append(decimalString.substring(0, ePos + 1)); - strBuilder.append('+'); - strBuilder.append(decimalString.substring(ePos + 1, decimalString.length())); - decimalString = strBuilder.toString(); - } - } + if (c == '-') { + dashCount++; } + } - return decimalString; + if (isDateOnly && (dashCount == 2)) { + return "yyyy-MM-dd"; + } } - /* - * DateTime Format Parsing Logic from Mysql JDBC - */ - public static String getDateTimePattern(String dt, boolean toTime) throws Exception { - int dtLength = (dt != null) ? dt.length() : 0; + // Special case - time-only + boolean colonsOnly = true; + for (int i = 0; i < dtLength; i++) { + char c = dt.charAt(i); - if ((dtLength >= 8) && (dtLength <= 10)) { - int dashCount = 0; - boolean isDateOnly = true; + if (!Character.isDigit(c) && (c != ':')) { + colonsOnly = false; - for (int i = 0; i < dtLength; i++) { - char c = dt.charAt(i); - - if (!Character.isDigit(c) && (c != '-')) { - isDateOnly = false; + break; + } + } - break; - } + if (colonsOnly) { + return "HH:mm:ss"; + } - if (c == '-') { - dashCount++; - } - } + int n; + int z; + int count; + int maxvecs; + char c; + char separator; + StringReader reader = new StringReader(dt + " "); + ArrayList vec = new ArrayList<>(); + ArrayList vecRemovelist = new ArrayList<>(); + Object[] nv = new Object[3]; + Object[] v; + nv[0] = 'y'; + nv[1] = new StringBuilder(); + nv[2] = 0; + vec.add(nv); + + if (toTime) { + nv = new Object[3]; + nv[0] = 'h'; + nv[1] = new StringBuilder(); + nv[2] = 0; + vec.add(nv); + } - if (isDateOnly && (dashCount == 2)) { - return "yyyy-MM-dd"; - } - } + while ((z = reader.read()) != -1) { + separator = (char) z; + maxvecs = vec.size(); - // Special case - time-only - boolean colonsOnly = true; - for (int i = 0; i < dtLength; i++) { - char c = dt.charAt(i); + for (count = 0; count < maxvecs; count++) { + v = vec.get(count); + n = (Integer) v[2]; + c = getSuccessor((Character) v[0], n); - if (!Character.isDigit(c) && (c != ':')) { - colonsOnly = false; + if (!Character.isLetterOrDigit(separator)) { + if ((c == (Character) v[0]) && (c != 'S')) { + vecRemovelist.add(v); + } else { + ((StringBuilder) v[1]).append(separator); - break; + if ((c == 'X') || (c == 'Y')) { + v[2] = 4; } - } - - if (colonsOnly) { - return "HH:mm:ss"; - } - - int n; - int z; - int count; - int maxvecs; - char c; - char separator; - StringReader reader = new StringReader(dt + " "); - ArrayList vec = new ArrayList<>(); - ArrayList vecRemovelist = new ArrayList<>(); - Object[] nv = new Object[3]; - Object[] v; - nv[0] = 'y'; - nv[1] = new StringBuilder(); - nv[2] = 0; - vec.add(nv); - - if (toTime) { + } + } else { + if (c == 'X') { + c = 'y'; nv = new Object[3]; - nv[0] = 'h'; - nv[1] = new StringBuilder(); - nv[2] = 0; + nv[1] = (new StringBuilder((v[1]).toString())).append('M'); + nv[0] = 'M'; + nv[2] = 1; vec.add(nv); - } - - while ((z = reader.read()) != -1) { - separator = (char) z; - maxvecs = vec.size(); - - for (count = 0; count < maxvecs; count++) { - v = vec.get(count); - n = (Integer) v[2]; - c = getSuccessor((Character) v[0], n); - - if (!Character.isLetterOrDigit(separator)) { - if ((c == (Character) v[0]) && (c != 'S')) { - vecRemovelist.add(v); - } else { - ((StringBuilder) v[1]).append(separator); - - if ((c == 'X') || (c == 'Y')) { - v[2] = 4; - } - } - } else { - if (c == 'X') { - c = 'y'; - nv = new Object[3]; - nv[1] = (new StringBuilder((v[1]).toString())).append('M'); - nv[0] = 'M'; - nv[2] = 1; - vec.add(nv); - } else if (c == 'Y') { - c = 'M'; - nv = new Object[3]; - nv[1] = (new StringBuilder((v[1]).toString())).append('d'); - nv[0] = 'd'; - nv[2] = 1; - vec.add(nv); - } - - ((StringBuilder) v[1]).append(c); - if (c == (Character) v[0]) { - v[2] = n + 1; - } else { - v[0] = c; - v[2] = 1; - } - } - } - - for (Object[] aVecRemovelist : vecRemovelist) { - v = aVecRemovelist; - vec.remove(v); - } - vecRemovelist.clear(); - } - - int size = vec.size(); - for (int i = 0; i < size; i++) { - v = vec.get(i); - c = (Character) v[0]; - n = (Integer) v[2]; - - boolean bk = getSuccessor(c, n) != c; - boolean atEnd = (((c == 's') || (c == 'm') || ((c == 'h') && toTime)) && bk); - boolean finishesAtDate = (bk && (c == 'd') && !toTime); - boolean containsEnd = ((v[1]).toString().indexOf('W') != -1); - - if ((!atEnd && !finishesAtDate) || (containsEnd)) { - vecRemovelist.add(v); - } - } + } else if (c == 'Y') { + c = 'M'; + nv = new Object[3]; + nv[1] = (new StringBuilder((v[1]).toString())).append('d'); + nv[0] = 'd'; + nv[2] = 1; + vec.add(nv); + } + + ((StringBuilder) v[1]).append(c); + if (c == (Character) v[0]) { + v[2] = n + 1; + } else { + v[0] = c; + v[2] = 1; + } + } + } + + for (Object[] aVecRemovelist : vecRemovelist) { + v = aVecRemovelist; + vec.remove(v); + } + vecRemovelist.clear(); + } - size = vecRemovelist.size(); + int size = vec.size(); + for (int i = 0; i < size; i++) { + v = vec.get(i); + c = (Character) v[0]; + n = (Integer) v[2]; - for (int i = 0; i < size; i++) { - vec.remove(vecRemovelist.get(i)); - } + boolean bk = getSuccessor(c, n) != c; + boolean atEnd = (((c == 's') || (c == 'm') || ((c == 'h') && toTime)) && bk); + boolean finishesAtDate = (bk && (c == 'd') && !toTime); + boolean containsEnd = ((v[1]).toString().indexOf('W') != -1); - vecRemovelist.clear(); - v = vec.get(0); // might throw exception - - StringBuilder format = (StringBuilder) v[1]; - format.setLength(format.length() - 1); - - return format.toString(); - } - - private static char getSuccessor(char c, int n) { - return ((c == 'y') && (n == 2)) ? - 'X' : - (((c == 'y') && (n < 4)) ? - 'y' : - ((c == 'y') ? - 'M' : - (((c == 'M') && (n == 2)) ? - 'Y' : - (((c == 'M') && (n < 3)) ? - 'M' : - ((c == 'M') ? - 'd' : - (((c == 'd') && (n < 2)) ? - 'd' : - ((c == 'd') ? - 'H' : - (((c == 'H') && (n < 2)) ? - 'H' : - ((c == 'H') ? - 'm' : - (((c == 'm') && (n < 2)) ? - 'm' : - ((c == 'm') ? - 's' : - (((c == 's') && (n < 2)) ? - 's' : - 'W')))))))))))); - } - - /** - * Finds the true start of a SQL statement, by skipping leading comments. - * If the query is multiple lines - * @param sql to parse - * @return position index in string - */ - public static int findStartOfStatement(String sql) { - int statementStartPos = 0; - if (StringUtils.startsWithIgnoreCaseAndWs(sql, "/*")) { - statementStartPos = sql.indexOf("*/"); - - if (statementStartPos == -1) { - statementStartPos = 0; - } else { - statementStartPos += 2; - } - } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "--") || StringUtils.startsWithIgnoreCaseAndWs(sql, "#")) { - statementStartPos = sql.indexOf('\n'); + if ((!atEnd && !finishesAtDate) || (containsEnd)) { + vecRemovelist.add(v); + } + } - if (statementStartPos == -1) { - statementStartPos = sql.indexOf('\r'); + size = vecRemovelist.size(); - if (statementStartPos == -1) { - statementStartPos = 0; - } - } - } - return statementStartPos; + for (int i = 0; i < size; i++) { + vec.remove(vecRemovelist.get(i)); } - public static char firstAlphaCharUc(String searchIn, int startAt) { - if (searchIn == null) { - return 0; - } + vecRemovelist.clear(); + v = vec.get(0); // might throw exception + + StringBuilder format = (StringBuilder) v[1]; + format.setLength(format.length() - 1); + + return format.toString(); + } + + private static char getSuccessor(char c, int n) { + return ((c == 'y') && (n == 2)) ? 'X' : (((c == 'y') && (n < 4)) ? 'y' : ((c == 'y') ? 'M' + : (((c == 'M') && (n == 2)) ? 'Y' : (((c == 'M') && (n < 3)) ? 'M' : ((c == 'M') ? 'd' + : (((c == 'd') && (n < 2)) ? 'd' : ((c == 'd') ? 'H' : (((c == 'H') && (n < 2)) ? 'H' + : ((c == 'H') ? 'm' : (((c == 'm') && (n < 2)) ? 'm' + : ((c == 'm') ? 's' : (((c == 's') && (n < 2)) ? 's' : 'W')))))))))))); + } + + /** + * Finds the true start of a SQL statement, by skipping leading comments. If the query is multiple + * lines + * + * @param sql to parse + * @return position index in string + */ + public static int findStartOfStatement(String sql) { + int statementStartPos = 0; + if (StringUtils.startsWithIgnoreCaseAndWs(sql, "/*")) { + statementStartPos = sql.indexOf("*/"); + + if (statementStartPos == -1) { + statementStartPos = 0; + } else { + statementStartPos += 2; + } + } else if (StringUtils.startsWithIgnoreCaseAndWs(sql, "--") || StringUtils + .startsWithIgnoreCaseAndWs(sql, "#")) { + statementStartPos = sql.indexOf('\n'); + + if (statementStartPos == -1) { + statementStartPos = sql.indexOf('\r'); + + if (statementStartPos == -1) { + statementStartPos = 0; + } + } + } + return statementStartPos; + } - int length = searchIn.length(); + public static char firstAlphaCharUc(String searchIn, int startAt) { + if (searchIn == null) { + return 0; + } - for (int i = startAt; i < length; i++) { - char c = searchIn.charAt(i); + int length = searchIn.length(); - if (Character.isLetter(c)) { - return Character.toUpperCase(c); - } - } + for (int i = startAt; i < length; i++) { + char c = searchIn.charAt(i); - return 0; + if (Character.isLetter(c)) { + return Character.toUpperCase(c); + } } - public static String toString(byte[] value, int offset, int length, String encoding) throws UnsupportedEncodingException { - Charset cs = findCharset(encoding); - return cs.decode(ByteBuffer.wrap(value, offset, length)).toString(); + return 0; + } + + public static String toString(byte[] value, int offset, int length, String encoding) + throws UnsupportedEncodingException { + Charset cs = findCharset(encoding); + return cs.decode(ByteBuffer.wrap(value, offset, length)).toString(); + } + + public static String toString(byte[] value, String encoding) throws UnsupportedEncodingException { + return findCharset(encoding).decode(ByteBuffer.wrap(value)).toString(); + } + + public static String toString(byte[] value, int offset, int length) { + try { + return findCharset(platformEncoding).decode(ByteBuffer.wrap(value, offset, length)) + .toString(); + } catch (UnsupportedEncodingException e) { + // can't happen, emulating new String(byte[]) } - - public static String toString(byte[] value, String encoding) throws UnsupportedEncodingException { - return findCharset(encoding) - .decode(ByteBuffer.wrap(value)) - .toString(); + return null; + } + + public static String toString(byte[] value) { + try { + return findCharset(platformEncoding).decode(ByteBuffer.wrap(value)).toString(); + } catch (UnsupportedEncodingException e) { + // can't happen, emulating new String(byte[]) } - - public static String toString(byte[] value, int offset, int length) { - try { - return findCharset(platformEncoding) - .decode(ByteBuffer.wrap(value, offset, length)) - .toString(); - } catch (UnsupportedEncodingException e) { - // can't happen, emulating new String(byte[]) - } - return null; + return null; + } + + public static byte[] getBytes(String value, String encoding) throws UnsupportedEncodingException { + return getBytes(value, 0, value.length(), encoding); + } + + public static byte[] getBytes(String value, int offset, int length, String encoding) + throws UnsupportedEncodingException { + Charset cs = findCharset(encoding); + ByteBuffer buf = cs.encode(CharBuffer.wrap(value.toCharArray(), offset, length)); + // can't simply .array() this to get the bytes especially with variable-length charsets the + // buffer is sometimes larger than the actual encoded data + int encodedLen = buf.limit(); + byte[] asBytes = new byte[encodedLen]; + buf.get(asBytes, 0, encodedLen); + return asBytes; + } + + private static Charset findCharset(String alias) throws UnsupportedEncodingException { + try { + Charset cs = charsetsByAlias.get(alias); + if (cs == null) { + cs = Charset.forName(alias); + Charset oldCs = charsetsByAlias.putIfAbsent(alias, cs); + if (oldCs != null) { + // if the previous value was recently set by another thread we return it instead of + // value we found here + cs = oldCs; + } + } + return cs; + // We re-throw these runtimes for compatibility with java.io + } catch (IllegalArgumentException iae) { + throw new UnsupportedEncodingException(alias); } - - public static String toString(byte[] value) { - try { - return findCharset(platformEncoding) - .decode(ByteBuffer.wrap(value)) - .toString(); - } catch (UnsupportedEncodingException e) { - // can't happen, emulating new String(byte[]) - } - return null; + } + + /** + * Searches for a quoteChar in the searchIn string + */ + public static int indexOfQuoteDoubleAware(String searchIn, String quoteChar, int startFrom) { + if (searchIn == null || quoteChar == null || quoteChar.length() == 0 || startFrom > searchIn + .length()) { + return -1; } - - public static byte[] getBytes(String value, String encoding) throws UnsupportedEncodingException { - return getBytes(value, 0, value.length(), encoding); + int lastIndex = searchIn.length() - 1; + int beginPos = startFrom; + int pos = -1; + boolean next = true; + while (next) { + pos = searchIn.indexOf(quoteChar, beginPos); + if (pos == -1 || pos == lastIndex || !searchIn.startsWith(quoteChar, pos + 1)) { + next = false; + } else { + beginPos = pos + 2; + } } - - public static byte[] getBytes(String value, int offset, int length, String encoding) throws UnsupportedEncodingException { - Charset cs = findCharset(encoding); - ByteBuffer buf = cs.encode(CharBuffer.wrap(value.toCharArray(), offset, length)); - // can't simply .array() this to get the bytes especially with variable-length charsets the buffer is sometimes larger than the actual encoded data - int encodedLen = buf.limit(); - byte[] asBytes = new byte[encodedLen]; - buf.get(asBytes, 0, encodedLen); - return asBytes; + return pos; + } + + /** + * Quotes an identifier, escaping any dangling quotes within + */ + public static String quoteIdentifier(String identifier, String quoteChar) { + if (identifier == null) { + return null; } - - private static Charset findCharset(String alias) throws UnsupportedEncodingException { - try { - Charset cs = charsetsByAlias.get(alias); - if (cs == null) { - cs = Charset.forName(alias); - Charset oldCs = charsetsByAlias.putIfAbsent(alias, cs); - if (oldCs != null) { - // if the previous value was recently set by another thread we return it instead of value we found here - cs = oldCs; - } - } - return cs; - // We re-throw these runtimes for compatibility with java.io - } catch (IllegalArgumentException iae) { - throw new UnsupportedEncodingException(alias); - } + identifier = identifier.trim(); + int quoteCharLength = quoteChar.length(); + if (quoteCharLength == 0 || " ".equals(quoteChar)) { + return identifier; } - /** - * Searches for a quoteChar in the searchIn string - * @param searchIn - * @param quoteChar - * @param startFrom - * @return - */ - public static int indexOfQuoteDoubleAware(String searchIn, String quoteChar, int startFrom) { - if (searchIn == null || quoteChar == null || quoteChar.length() == 0 || startFrom > searchIn.length()) { - return -1; - } - int lastIndex = searchIn.length() - 1; - int beginPos = startFrom; - int pos = -1; - boolean next = true; - while (next) { - pos = searchIn.indexOf(quoteChar, beginPos); - if (pos == -1 || pos == lastIndex || !searchIn.startsWith(quoteChar, pos + 1)) { - next = false; - } else { - beginPos = pos + 2; - } - } - return pos; - } - - /** - * Quotes an identifier, escaping any dangling quotes within - * @param identifier - * @param quoteChar - * @return - */ - public static String quoteIdentifier(String identifier, String quoteChar) { - if (identifier == null) { - return null; - } - identifier = identifier.trim(); - int quoteCharLength = quoteChar.length(); - if (quoteCharLength == 0 || " ".equals(quoteChar)) { - return identifier; - } - - if (identifier.startsWith(quoteChar) && identifier.endsWith(quoteChar)) { - String identifierQuoteTrimmed = identifier.substring(quoteCharLength, identifier.length() - quoteCharLength); - int quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar); - while (quoteCharPos >= 0) { - int quoteCharNextExpectedPos = quoteCharPos + quoteCharLength; - int quoteCharNextPosition = identifierQuoteTrimmed.indexOf(quoteChar, quoteCharNextExpectedPos); - - if (quoteCharNextPosition == quoteCharNextExpectedPos) { - quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar, quoteCharNextPosition + quoteCharLength); - } else { - // Not a pair of quotes! - break; - } - } - - if (quoteCharPos < 0) { - return identifier; - } - } - - return quoteChar + identifier.replaceAll(quoteChar, quoteChar + quoteChar) + quoteChar; - } - - /** - * Finds the position of the first of a consecutive sequence of strings within a string, ignoring case, with the option to skip text delimited by given - * markers or within comments. - *

- * Independently of the searchMode provided, when searching for the second and following strings SearchMode.SKIP_WHITE_SPACE will - * be added and SearchMode.SKIP_BETWEEN_MARKERS removed. - *

- * - * @param startingPosition - * the position to start the search from - * @param searchIn - * the string to search in - * @param searchFor - * the array of strings to search for - * @param openingMarkers - * characters which delimit the beginning of a text block to skip - * @param closingMarkers - * characters which delimit the end of a text block to skip - * @param searchMode - * a Set, ideally an EnumSet, containing the flags from the enum StringUtils.SearchMode that determine the - * behavior of the search - * @return the position where searchFor is found within searchIn starting from startingPosition. - */ - public static int indexOfIgnoreCase(int startingPosition, String searchIn, String[] searchForSequence, String openingMarkers, String closingMarkers, - Set searchMode) { - if ((searchIn == null) || (searchForSequence == null)) { - return -1; - } - - int searchInLength = searchIn.length(); - int searchForLength = 0; - for (String searchForPart : searchForSequence) { - searchForLength += searchForPart.length(); - } // minimum length for searchFor (without gaps between words) - - if (searchForLength == 0) { - return -1; - } + if (identifier.startsWith(quoteChar) && identifier.endsWith(quoteChar)) { + String identifierQuoteTrimmed = identifier + .substring(quoteCharLength, identifier.length() - quoteCharLength); + int quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar); + while (quoteCharPos >= 0) { + int quoteCharNextExpectedPos = quoteCharPos + quoteCharLength; + int quoteCharNextPosition = identifierQuoteTrimmed + .indexOf(quoteChar, quoteCharNextExpectedPos); + + if (quoteCharNextPosition == quoteCharNextExpectedPos) { + quoteCharPos = identifierQuoteTrimmed + .indexOf(quoteChar, quoteCharNextPosition + quoteCharLength); + } else { + // Not a pair of quotes! + break; + } + } + + if (quoteCharPos < 0) { + return identifier; + } + } - int searchForWordsCount = searchForSequence.length; - searchForLength += searchForWordsCount > 0 ? searchForWordsCount - 1 : 0; // add gaps between words - int stopSearchingAt = searchInLength - searchForLength; + return quoteChar + identifier.replaceAll(quoteChar, quoteChar + quoteChar) + quoteChar; + } + + /** + * Finds the position of the first of a consecutive sequence of strings within a string, ignoring + * case, with the option to skip text delimited by given markers or within comments. + *

+ * Independently of the searchMode provided, when searching for the second and + * following strings SearchMode.SKIP_WHITE_SPACE will be added and + * SearchMode.SKIP_BETWEEN_MARKERS removed. + *

+ * + * @param startingPosition the position to start the search from + * @param searchIn the string to search in + * @param searchFor the array of strings to search for + * @param openingMarkers characters which delimit the beginning of a text block to skip + * @param closingMarkers characters which delimit the end of a text block to skip + * @param searchMode a Set, ideally an EnumSet, containing the flags + * from the enum StringUtils.SearchMode that determine the behavior of the + * search + * @return the position where searchFor is found within searchIn + * starting from startingPosition. + */ + public static int indexOfIgnoreCase(int startingPosition, String searchIn, + String[] searchForSequence, String openingMarkers, String closingMarkers, + Set searchMode) { + if ((searchIn == null) || (searchForSequence == null)) { + return -1; + } - if (startingPosition > stopSearchingAt) { - return -1; - } + int searchInLength = searchIn.length(); + int searchForLength = 0; + for (String searchForPart : searchForSequence) { + searchForLength += searchForPart.length(); + } // minimum length for searchFor (without gaps between words) - if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) - && (openingMarkers == null || closingMarkers == null || openingMarkers.length() != closingMarkers.length())) { - throw new IllegalArgumentException("Must specify a valid openingMarkers and closingMarkers"); - } + if (searchForLength == 0) { + return -1; + } - if (Character.isWhitespace(searchForSequence[0].charAt(0)) && searchMode.contains(SearchMode.SKIP_WHITE_SPACE)) { - // Can't skip white spaces if first searchFor char is one - searchMode = EnumSet.copyOf(searchMode); - searchMode.remove(SearchMode.SKIP_WHITE_SPACE); - } + int searchForWordsCount = searchForSequence.length; + searchForLength += + searchForWordsCount > 0 ? searchForWordsCount - 1 : 0; // add gaps between words + int stopSearchingAt = searchInLength - searchForLength; - // searchMode set used to search 2nd and following words can't contain SearchMode.SKIP_BETWEEN_MARKERS and must - // contain SearchMode.SKIP_WHITE_SPACE - Set searchMode2 = EnumSet.of(SearchMode.SKIP_WHITE_SPACE); - searchMode2.addAll(searchMode); - searchMode2.remove(SearchMode.SKIP_BETWEEN_MARKERS); + if (startingPosition > stopSearchingAt) { + return -1; + } - for (int positionOfFirstWord = startingPosition; positionOfFirstWord <= stopSearchingAt; positionOfFirstWord++) { - positionOfFirstWord = indexOfIgnoreCase(positionOfFirstWord, searchIn, searchForSequence[0], openingMarkers, closingMarkers, searchMode); + if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) && (openingMarkers == null + || closingMarkers == null || openingMarkers.length() != closingMarkers.length())) { + throw new IllegalArgumentException("Must specify a valid openingMarkers and closingMarkers"); + } - if (positionOfFirstWord == -1 || positionOfFirstWord > stopSearchingAt) { - return -1; - } + if (Character.isWhitespace(searchForSequence[0].charAt(0)) && searchMode + .contains(SearchMode.SKIP_WHITE_SPACE)) { + // Can't skip white spaces if first searchFor char is one + searchMode = EnumSet.copyOf(searchMode); + searchMode.remove(SearchMode.SKIP_WHITE_SPACE); + } - int startingPositionForNextWord = positionOfFirstWord + searchForSequence[0].length(); - int wc = 0; - boolean match = true; - while (++wc < searchForWordsCount && match) { - int positionOfNextWord = indexOfNextChar(startingPositionForNextWord, searchInLength - 1, searchIn, null, null, searchMode2); - if (startingPositionForNextWord == positionOfNextWord || !startsWithIgnoreCase(searchIn, positionOfNextWord, searchForSequence[wc])) { - // either no gap between words or match failed - match = false; - } else { - startingPositionForNextWord = positionOfNextWord + searchForSequence[wc].length(); - } - } + // searchMode set used to search 2nd and following words can't contain SearchMode + // .SKIP_BETWEEN_MARKERS and must + // contain SearchMode.SKIP_WHITE_SPACE + Set searchMode2 = EnumSet.of(SearchMode.SKIP_WHITE_SPACE); + searchMode2.addAll(searchMode); + searchMode2.remove(SearchMode.SKIP_BETWEEN_MARKERS); - if (match) { - return positionOfFirstWord; - } - } + for (int positionOfFirstWord = startingPosition; positionOfFirstWord <= stopSearchingAt; + positionOfFirstWord++) { + positionOfFirstWord = indexOfIgnoreCase(positionOfFirstWord, searchIn, searchForSequence[0], + openingMarkers, closingMarkers, searchMode); + if (positionOfFirstWord == -1 || positionOfFirstWord > stopSearchingAt) { return -1; + } + + int startingPositionForNextWord = positionOfFirstWord + searchForSequence[0].length(); + int wc = 0; + boolean match = true; + while (++wc < searchForWordsCount && match) { + int positionOfNextWord = indexOfNextChar(startingPositionForNextWord, searchInLength - 1, + searchIn, null, null, searchMode2); + if (startingPositionForNextWord == positionOfNextWord || !startsWithIgnoreCase(searchIn, + positionOfNextWord, searchForSequence[wc])) { + // either no gap between words or match failed + match = false; + } else { + startingPositionForNextWord = positionOfNextWord + searchForSequence[wc].length(); + } + } + + if (match) { + return positionOfFirstWord; + } } - /** - * Convenience function for {@link #indexOfIgnoreCase(int, String, String, String, String, Set)}, passing {@link #SEARCH_MODE__ALL} - */ - public static int indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, String openingMarkers, String closingMarkers) { - return indexOfIgnoreCase(startingPosition, searchIn, searchFor, openingMarkers, closingMarkers, SEARCH_MODE__ALL); - } - - /** - * Finds the position of a substring within a string, ignoring case, with the option to skip text delimited by given markers or within comments. - * - * @param startingPosition - * the position to start the search from - * @param searchIn - * the string to search in - * @param searchFor - * the string to search for - * @param openingMarkers - * characters which delimit the beginning of a text block to skip - * @param closingMarkers - * characters which delimit the end of a text block to skip - * @param searchMode - * a Set, ideally an EnumSet, containing the flags from the enum StringUtils.SearchMode that determine the - * behavior of the search - * @return the position where searchFor is found within searchIn starting from startingPosition. - */ - public static int indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, String openingMarkers, String closingMarkers, - Set searchMode) { - if (searchIn == null || searchFor == null) { - return -1; - } - - int searchInLength = searchIn.length(); - int searchForLength = searchFor.length(); - int stopSearchingAt = searchInLength - searchForLength; - - if (startingPosition > stopSearchingAt || searchForLength == 0) { - return -1; - } - - if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) - && (openingMarkers == null || closingMarkers == null || openingMarkers.length() != closingMarkers.length())) { - throw new IllegalArgumentException("Must specify a valid openingMarkers and closingMarkers"); - } + return -1; + } + + /** + * Convenience function for {@link #indexOfIgnoreCase(int, String, String, String, String, Set)}, + * passing {@link #SEARCH_MODE__ALL} + */ + public static int indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, + String openingMarkers, String closingMarkers) { + return indexOfIgnoreCase(startingPosition, searchIn, searchFor, openingMarkers, closingMarkers, + SEARCH_MODE__ALL); + } + + /** + * Finds the position of a substring within a string, ignoring case, with the option to skip text + * delimited by given markers or within comments. + * + * @param startingPosition the position to start the search from + * @param searchIn the string to search in + * @param searchFor the string to search for + * @param openingMarkers characters which delimit the beginning of a text block to skip + * @param closingMarkers characters which delimit the end of a text block to skip + * @param searchMode a Set, ideally an EnumSet, containing the flags + * from the enum StringUtils.SearchMode that determine the behavior of the + * search + * @return the position where searchFor is found within searchIn + * starting from startingPosition. + */ + public static int indexOfIgnoreCase(int startingPosition, String searchIn, String searchFor, + String openingMarkers, String closingMarkers, Set searchMode) { + if (searchIn == null || searchFor == null) { + return -1; + } - // Some locales don't follow upper-case rule, so need to check both - char firstCharOfSearchForUc = Character.toUpperCase(searchFor.charAt(0)); - char firstCharOfSearchForLc = Character.toLowerCase(searchFor.charAt(0)); + int searchInLength = searchIn.length(); + int searchForLength = searchFor.length(); + int stopSearchingAt = searchInLength - searchForLength; - if (Character.isWhitespace(firstCharOfSearchForLc) && searchMode.contains(SearchMode.SKIP_WHITE_SPACE)) { - // Can't skip white spaces if first searchFor char is one - searchMode = EnumSet.copyOf(searchMode); - searchMode.remove(SearchMode.SKIP_WHITE_SPACE); - } + if (startingPosition > stopSearchingAt || searchForLength == 0) { + return -1; + } - for (int i = startingPosition; i <= stopSearchingAt; i++) { - i = indexOfNextChar(i, stopSearchingAt, searchIn, openingMarkers, closingMarkers, searchMode); + if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) && (openingMarkers == null + || closingMarkers == null || openingMarkers.length() != closingMarkers.length())) { + throw new IllegalArgumentException("Must specify a valid openingMarkers and closingMarkers"); + } - if (i == -1) { - return -1; - } + // Some locales don't follow upper-case rule, so need to check both + char firstCharOfSearchForUc = Character.toUpperCase(searchFor.charAt(0)); + char firstCharOfSearchForLc = Character.toLowerCase(searchFor.charAt(0)); - char c = searchIn.charAt(i); + if (Character.isWhitespace(firstCharOfSearchForLc) && searchMode + .contains(SearchMode.SKIP_WHITE_SPACE)) { + // Can't skip white spaces if first searchFor char is one + searchMode = EnumSet.copyOf(searchMode); + searchMode.remove(SearchMode.SKIP_WHITE_SPACE); + } - if (isCharEqualIgnoreCase(c, firstCharOfSearchForUc, firstCharOfSearchForLc) && startsWithIgnoreCase(searchIn, i, searchFor)) { - return i; - } - } + for (int i = startingPosition; i <= stopSearchingAt; i++) { + i = indexOfNextChar(i, stopSearchingAt, searchIn, openingMarkers, closingMarkers, searchMode); + if (i == -1) { return -1; - } + } - /** - * Finds the position the next character from a string, possibly skipping white space, comments and text between markers. - * - * @param startingPosition - * the position to start the search from - * @param stopPosition - * the position where to stop the search (inclusive) - * @param searchIn - * the string to search in - * @param openingMarkers - * characters which delimit the beginning of a text block to skip - * @param closingMarkers - * characters which delimit the end of a text block to skip - * @param searchMode - * a Set, ideally an EnumSet, containing the flags from the enum StringUtils.SearchMode that determine the - * behavior of the search - * @return the position where searchFor is found within searchIn starting from startingPosition. - */ - private static int indexOfNextChar(int startingPosition, int stopPosition, String searchIn, String openingMarkers, String closingMarkers, - Set searchMode) { - if (searchIn == null) { - return -1; - } + char c = searchIn.charAt(i); - int searchInLength = searchIn.length(); - if (startingPosition >= searchInLength) { - return -1; - } + if (isCharEqualIgnoreCase(c, firstCharOfSearchForUc, firstCharOfSearchForLc) + && startsWithIgnoreCase(searchIn, i, searchFor)) { + return i; + } + } - char c0 = Character.MIN_VALUE; // current char - char c1 = searchIn.charAt(startingPosition); // lookahead(1) - char c2 = startingPosition + 1 < searchInLength ? searchIn.charAt(startingPosition + 1) : Character.MIN_VALUE; // lookahead(2) - - for (int i = startingPosition; i <= stopPosition; i++) { - c0 = c1; - c1 = c2; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - - boolean dashDashCommentImmediateEnd = false; - int markerIndex = -1; - if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') { - i++; // next char is escaped, skip it - // reset lookahead - c1 = c2; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } else if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) && (markerIndex = openingMarkers.indexOf(c0)) != -1) { - // marker found, skip until closing, while being aware of nested markers if opening and closing markers are distinct - int nestedMarkersCount = 0; - char openingMarker = c0; - char closingMarker = closingMarkers.charAt(markerIndex); - while (++i <= stopPosition && ((c0 = searchIn.charAt(i)) != closingMarker || nestedMarkersCount != 0)) { - if (c0 == openingMarker) { - nestedMarkersCount++; - } else if (c0 == closingMarker) { - nestedMarkersCount--; - } else if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') { - i++; // next char is escaped, skip it - } - } - // reset lookahead - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - - } else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '/' && c1 == '*') { - if (c2 != '!') { - // comments block found, skip until end of block ("*/") (backslash escape doesn't work on comments) - i++; // move to next char ('*') - while (++i <= stopPosition - && (searchIn.charAt(i) != '*' || (i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE) != '/')) { - // continue - } - i++; // move to next char ('/') - } else { - // special non-comments block found, move to end of opening marker ("/*![12345]") - i++; // move to next char ('*') - i++; // move to next char ('!') - // check if a 5 digits MySQL version reference follows, if so skip them - int j = 1; - for (; j <= NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; j++) { - if (i + j >= searchInLength || !Character.isDigit(searchIn.charAt(i + j))) { - break; - } - } - if (j == NON_COMMENTS_MYSQL_VERSION_REF_LENGTH) { - i += NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; - } - } - // reset lookahead - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '*' && c1 == '/') { - // special non-comments block closing marker ("*/") found - assume that if we get it here it's because it - // belongs to a non-comments block ("/*!"), otherwise the query should be misspelled as nesting comments isn't allowed. - i++; // move to next char ('/') - // reset lookahead - c1 = c2; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } else if (searchMode.contains(SearchMode.SKIP_LINE_COMMENTS) - && ((c0 == '-' && c1 == '-' && (Character.isWhitespace(c2) || (dashDashCommentImmediateEnd = c2 == ';') || c2 == Character.MIN_VALUE)) - || c0 == '#')) { - if (dashDashCommentImmediateEnd) { - // comments line found but closed immediately by query delimiter marker - i++; // move to next char ('-') - i++; // move to next char (';') - // reset lookahead - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } else { - // comments line found, skip until eol (backslash escape doesn't work on comments) - while (++i <= stopPosition && (c0 = searchIn.charAt(i)) != '\n' && c0 != '\r') { - // continue - } - // reset lookahead - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - if (c0 == '\r' && c1 == '\n') { - // \r\n sequence found - i++; // skip next char ('\n') - c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; - } - c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; - } - } else if (!searchMode.contains(SearchMode.SKIP_WHITE_SPACE) || !Character.isWhitespace(c0)) { - return i; - } - } - return -1; + return -1; + } + + /** + * Finds the position the next character from a string, possibly skipping white space, comments + * and text between markers. + * + * @param startingPosition the position to start the search from + * @param stopPosition the position where to stop the search (inclusive) + * @param searchIn the string to search in + * @param openingMarkers characters which delimit the beginning of a text block to skip + * @param closingMarkers characters which delimit the end of a text block to skip + * @param searchMode a Set, ideally an EnumSet, containing the flags + * from the enum StringUtils.SearchMode that determine the behavior of the + * search + * @return the position where searchFor is found within searchIn + * starting from startingPosition. + */ + private static int indexOfNextChar(int startingPosition, int stopPosition, String searchIn, + String openingMarkers, String closingMarkers, Set searchMode) { + if (searchIn == null) { + return -1; } - /** - * Trims identifier, removes quote chars from first and last positions - * and replaces double occurrences of quote char from entire identifier, - * i.e converts quoted identifier into form as it is stored in database. - * - * @param identifier - * @param quoteChar - * ` or " - * @return - *
    - *
  • null -> null
  • - *
  • abc -> abc
  • - *
  • `abc` -> abc
  • - *
  • `ab``c` -> ab`c
  • - *
  • `"ab`c"` -> "ab`c"
  • - *
  • `ab"c` -> ab"c
  • - *
  • "abc" -> abc
  • - *
  • "`ab""c`" -> `ab"c`
  • - *
  • "ab`c" -> ab`c
  • - *
- */ - public static String unQuoteIdentifier(String identifier, String quoteChar) { - if (identifier == null) { - return null; - } - identifier = identifier.trim(); - int quoteCharLength = quoteChar.length(); - if (quoteCharLength == 0 || " ".equals(quoteChar)) { - return identifier; - } + int searchInLength = searchIn.length(); + if (startingPosition >= searchInLength) { + return -1; + } - // Check if the identifier is really quoted or if it simply contains quote chars in it (assuming that the value is a valid identifier). - if (identifier.startsWith(quoteChar) && identifier.endsWith(quoteChar)) { - String identifierQuoteTrimmed = identifier.substring(quoteCharLength, identifier.length() - quoteCharLength); - // Check for pairs of quotes. - int quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar); - while (quoteCharPos >= 0) { - int quoteCharNextExpectedPos = quoteCharPos + quoteCharLength; - int quoteCharNextPosition = identifierQuoteTrimmed.indexOf(quoteChar, quoteCharNextExpectedPos); - - if (quoteCharNextPosition == quoteCharNextExpectedPos) { - quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar, quoteCharNextPosition + quoteCharLength); - } else { - // Not a pair of quotes! Return as it is... - return identifier; - } + char c0 = Character.MIN_VALUE; // current char + char c1 = searchIn.charAt(startingPosition); // lookahead(1) + char c2 = startingPosition + 1 < searchInLength ? searchIn.charAt(startingPosition + 1) + : Character.MIN_VALUE; // lookahead(2) + + for (int i = startingPosition; i <= stopPosition; i++) { + c0 = c1; + c1 = c2; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + + boolean dashDashCommentImmediateEnd = false; + int markerIndex = -1; + if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') { + i++; // next char is escaped, skip it + // reset lookahead + c1 = c2; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } else if (searchMode.contains(SearchMode.SKIP_BETWEEN_MARKERS) + && (markerIndex = openingMarkers.indexOf(c0)) != -1) { + // marker found, skip until closing, while being aware of nested markers if opening and + // closing markers are distinct + int nestedMarkersCount = 0; + char openingMarker = c0; + char closingMarker = closingMarkers.charAt(markerIndex); + while (++i <= stopPosition && ((c0 = searchIn.charAt(i)) != closingMarker + || nestedMarkersCount != 0)) { + if (c0 == openingMarker) { + nestedMarkersCount++; + } else if (c0 == closingMarker) { + nestedMarkersCount--; + } else if (searchMode.contains(SearchMode.ALLOW_BACKSLASH_ESCAPE) && c0 == '\\') { + i++; // next char is escaped, skip it + } + } + // reset lookahead + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + + } else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '/' && c1 == '*') { + if (c2 != '!') { + // comments block found, skip until end of block ("*/") (backslash escape doesn't work + // on comments) + i++; // move to next char ('*') + while (++i <= stopPosition && (searchIn.charAt(i) != '*' + || (i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE) != '/')) { + // continue + } + i++; // move to next char ('/') + } else { + // special non-comments block found, move to end of opening marker ("/*![12345]") + i++; // move to next char ('*') + i++; // move to next char ('!') + // check if a 5 digits MySQL version reference follows, if so skip them + int j = 1; + for (; j <= NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; j++) { + if (i + j >= searchInLength || !Character.isDigit(searchIn.charAt(i + j))) { + break; } - return identifier.substring(quoteCharLength, (identifier.length() - quoteCharLength)).replaceAll(quoteChar + quoteChar, quoteChar); - } - return identifier; + } + if (j == NON_COMMENTS_MYSQL_VERSION_REF_LENGTH) { + i += NON_COMMENTS_MYSQL_VERSION_REF_LENGTH; + } + } + // reset lookahead + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } else if (searchMode.contains(SearchMode.SKIP_BLOCK_COMMENTS) && c0 == '*' && c1 == '/') { + // special non-comments block closing marker ("*/") found - assume that if we get it here + // it's because it + // belongs to a non-comments block ("/*!"), otherwise the query should be misspelled as + // nesting comments isn't allowed. + i++; // move to next char ('/') + // reset lookahead + c1 = c2; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } else if (searchMode.contains(SearchMode.SKIP_LINE_COMMENTS) && ( + (c0 == '-' && c1 == '-' && (Character.isWhitespace(c2) || (dashDashCommentImmediateEnd = + c2 == ';') || c2 == Character.MIN_VALUE)) || c0 == '#')) { + if (dashDashCommentImmediateEnd) { + // comments line found but closed immediately by query delimiter marker + i++; // move to next char ('-') + i++; // move to next char (';') + // reset lookahead + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } else { + // comments line found, skip until eol (backslash escape doesn't work on comments) + while (++i <= stopPosition && (c0 = searchIn.charAt(i)) != '\n' && c0 != '\r') { + // continue + } + // reset lookahead + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + if (c0 == '\r' && c1 == '\n') { + // \r\n sequence found + i++; // skip next char ('\n') + c1 = i + 1 < searchInLength ? searchIn.charAt(i + 1) : Character.MIN_VALUE; + } + c2 = i + 2 < searchInLength ? searchIn.charAt(i + 2) : Character.MIN_VALUE; + } + } else if (!searchMode.contains(SearchMode.SKIP_WHITE_SPACE) || !Character.isWhitespace(c0)) { + return i; + } + } + return -1; + } + + /** + * Trims identifier, removes quote chars from first and last positions and replaces double + * occurrences of quote char from entire identifier, i.e converts quoted identifier into form as + * it is stored in database. + * + * @param quoteChar ` or " + * @return
    + *
  • null -> null
  • + *
  • abc -> abc
  • + *
  • `abc` -> abc
  • + *
  • `ab``c` -> ab`c
  • + *
  • `"ab`c"` -> "ab`c"
  • + *
  • `ab"c` -> ab"c
  • + *
  • "abc" -> abc
  • + *
  • "`ab""c`" -> `ab"c`
  • + *
  • "ab`c" -> ab`c
  • + *
+ */ + public static String unQuoteIdentifier(String identifier, String quoteChar) { + if (identifier == null) { + return null; + } + identifier = identifier.trim(); + int quoteCharLength = quoteChar.length(); + if (quoteCharLength == 0 || " ".equals(quoteChar)) { + return identifier; } - /** - * Splits stringToSplit into a list, using the given delimiter (skipping delimiters within quotes) - * - * @param stringToSplit - * the string to split - * @param delimiter - * the string to split on - * @param markers - * the marker for the beginning of a text block to skip, when looking for a delimiter - * @param markerCloses - * the marker for the end of a text block to skip, when looking for a delimiter - * @return the list of strings, split by delimiter - * - * @throws IllegalArgumentException - */ - public static List split(String stringToSplit, String delimiter, String markers, String markerCloses) { - if (stringToSplit == null) { - return new ArrayList<>(); - } - if (delimiter == null) { - throw new IllegalArgumentException(); - } + // Check if the identifier is really quoted or if it simply contains quote chars in it + // (assuming that the value is a valid identifier). + if (identifier.startsWith(quoteChar) && identifier.endsWith(quoteChar)) { + String identifierQuoteTrimmed = identifier + .substring(quoteCharLength, identifier.length() - quoteCharLength); + // Check for pairs of quotes. + int quoteCharPos = identifierQuoteTrimmed.indexOf(quoteChar); + while (quoteCharPos >= 0) { + int quoteCharNextExpectedPos = quoteCharPos + quoteCharLength; + int quoteCharNextPosition = identifierQuoteTrimmed + .indexOf(quoteChar, quoteCharNextExpectedPos); + + if (quoteCharNextPosition == quoteCharNextExpectedPos) { + quoteCharPos = identifierQuoteTrimmed + .indexOf(quoteChar, quoteCharNextPosition + quoteCharLength); + } else { + // Not a pair of quotes! Return as it is... + return identifier; + } + } + return identifier.substring(quoteCharLength, (identifier.length() - quoteCharLength)) + .replaceAll(quoteChar + quoteChar, quoteChar); + } + return identifier; + } + + /** + * Splits stringToSplit into a list, using the given delimiter (skipping delimiters within + * quotes) + * + * @param stringToSplit the string to split + * @param delimiter the string to split on + * @param markers the marker for the beginning of a text block to skip, when looking for a + * delimiter + * @param markerCloses the marker for the end of a text block to skip, when looking for a + * delimiter + * @return the list of strings, split by delimiter + */ + public static List split(String stringToSplit, String delimiter, String markers, + String markerCloses) { + if (stringToSplit == null) { + return new ArrayList<>(); + } + if (delimiter == null) { + throw new IllegalArgumentException(); + } - int delimPos = 0; - int currentPos = 0; - List splitTokens = new ArrayList<>(); - while ((delimPos = indexOfIgnoreCase(currentPos, stringToSplit, delimiter, markers, markerCloses, SEARCH_MODE__MRK_COM_WS)) != -1) { - String token = stringToSplit.substring(currentPos, delimPos); - splitTokens.add(token); - currentPos = delimPos + 1; - } + int delimPos = 0; + int currentPos = 0; + List splitTokens = new ArrayList<>(); + while ( + (delimPos = indexOfIgnoreCase(currentPos, stringToSplit, delimiter, markers, markerCloses, + SEARCH_MODE__MRK_COM_WS)) != -1) { + String token = stringToSplit.substring(currentPos, delimPos); + splitTokens.add(token); + currentPos = delimPos + 1; + } - if (currentPos < stringToSplit.length()) { - String token = stringToSplit.substring(currentPos); - splitTokens.add(token); - } - return splitTokens; + if (currentPos < stringToSplit.length()) { + String token = stringToSplit.substring(currentPos); + splitTokens.add(token); } + return splitTokens; + } + + public enum SearchMode { + ALLOW_BACKSLASH_ESCAPE, SKIP_BETWEEN_MARKERS, SKIP_BLOCK_COMMENTS, SKIP_LINE_COMMENTS, + SKIP_WHITE_SPACE; + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/charset/CharsetMapping.java b/java/jdbc/src/main/java/io/vitess/util/charset/CharsetMapping.java index a5b559495dc..1d502a180e9 100644 --- a/java/jdbc/src/main/java/io/vitess/util/charset/CharsetMapping.java +++ b/java/jdbc/src/main/java/io/vitess/util/charset/CharsetMapping.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -24,529 +24,573 @@ import java.util.Map; /** - * These classes were pulled from mysql-connector-java and simplified to just the parts supporting the statically available - * charsets + * These classes were pulled from mysql-connector-java and simplified to just the parts supporting + * the statically available charsets */ public class CharsetMapping { - private static final int MAP_SIZE = 255; // Size of static maps - public static final String[] COLLATION_INDEX_TO_COLLATION_NAME; - private static final MysqlCharset[] COLLATION_INDEX_TO_CHARSET; - - static final Map CHARSET_NAME_TO_CHARSET; - private static final Map> JAVA_ENCODING_UC_TO_MYSQL_CHARSET; - - private static final String MYSQL_CHARSET_NAME_armscii8 = "armscii8"; - private static final String MYSQL_CHARSET_NAME_ascii = "ascii"; - private static final String MYSQL_CHARSET_NAME_big5 = "big5"; - private static final String MYSQL_CHARSET_NAME_binary = "binary"; - private static final String MYSQL_CHARSET_NAME_cp1250 = "cp1250"; - private static final String MYSQL_CHARSET_NAME_cp1251 = "cp1251"; - private static final String MYSQL_CHARSET_NAME_cp1256 = "cp1256"; - private static final String MYSQL_CHARSET_NAME_cp1257 = "cp1257"; - private static final String MYSQL_CHARSET_NAME_cp850 = "cp850"; - private static final String MYSQL_CHARSET_NAME_cp852 = "cp852"; - private static final String MYSQL_CHARSET_NAME_cp866 = "cp866"; - private static final String MYSQL_CHARSET_NAME_cp932 = "cp932"; - private static final String MYSQL_CHARSET_NAME_dec8 = "dec8"; - private static final String MYSQL_CHARSET_NAME_eucjpms = "eucjpms"; - private static final String MYSQL_CHARSET_NAME_euckr = "euckr"; - private static final String MYSQL_CHARSET_NAME_gb18030 = "gb18030"; - private static final String MYSQL_CHARSET_NAME_gb2312 = "gb2312"; - private static final String MYSQL_CHARSET_NAME_gbk = "gbk"; - private static final String MYSQL_CHARSET_NAME_geostd8 = "geostd8"; - private static final String MYSQL_CHARSET_NAME_greek = "greek"; - private static final String MYSQL_CHARSET_NAME_hebrew = "hebrew"; - private static final String MYSQL_CHARSET_NAME_hp8 = "hp8"; - private static final String MYSQL_CHARSET_NAME_keybcs2 = "keybcs2"; - private static final String MYSQL_CHARSET_NAME_koi8r = "koi8r"; - private static final String MYSQL_CHARSET_NAME_koi8u = "koi8u"; - private static final String MYSQL_CHARSET_NAME_latin1 = "latin1"; - private static final String MYSQL_CHARSET_NAME_latin2 = "latin2"; - private static final String MYSQL_CHARSET_NAME_latin5 = "latin5"; - private static final String MYSQL_CHARSET_NAME_latin7 = "latin7"; - private static final String MYSQL_CHARSET_NAME_macce = "macce"; - private static final String MYSQL_CHARSET_NAME_macroman = "macroman"; - private static final String MYSQL_CHARSET_NAME_sjis = "sjis"; - private static final String MYSQL_CHARSET_NAME_swe7 = "swe7"; - private static final String MYSQL_CHARSET_NAME_tis620 = "tis620"; - private static final String MYSQL_CHARSET_NAME_ucs2 = "ucs2"; - private static final String MYSQL_CHARSET_NAME_ujis = "ujis"; - private static final String MYSQL_CHARSET_NAME_utf16 = "utf16"; - private static final String MYSQL_CHARSET_NAME_utf16le = "utf16le"; - private static final String MYSQL_CHARSET_NAME_utf32 = "utf32"; - private static final String MYSQL_CHARSET_NAME_utf8 = "utf8"; - private static final String MYSQL_CHARSET_NAME_utf8mb4 = "utf8mb4"; - - private static final String MYSQL_4_0_CHARSET_NAME_cp1251cias = "cp1251cias"; - private static final String MYSQL_4_0_CHARSET_NAME_cp1251csas = "cp1251csas"; - private static final String MYSQL_4_0_CHARSET_NAME_croat = "croat"; // 4.1 => 27 latin2 latin2_croatian_ci - private static final String MYSQL_4_0_CHARSET_NAME_czech = "czech"; // 4.1 => 2 latin2 latin2_czech_ci - private static final String MYSQL_4_0_CHARSET_NAME_danish = "danish"; // 4.1 => 15 latin1 latin1_danish_ci - private static final String MYSQL_4_0_CHARSET_NAME_dos = "dos"; // 4.1 => 4 cp850 cp850_general_ci - private static final String MYSQL_4_0_CHARSET_NAME_estonia = "estonia"; // 4.1 => 20 latin7 latin7_estonian_ci - private static final String MYSQL_4_0_CHARSET_NAME_euc_kr = "euc_kr"; // 4.1 => 19 euckr euckr_korean_ci - private static final String MYSQL_4_0_CHARSET_NAME_german1 = "german1"; // 4.1 => 5 latin1 latin1_german1_ci - private static final String MYSQL_4_0_CHARSET_NAME_hungarian = "hungarian"; // 4.1 => 21 latin2 latin2_hungarian_ci - private static final String MYSQL_4_0_CHARSET_NAME_koi8_ru = "koi8_ru"; // 4.1 => 7 koi8r koi8r_general_ci - private static final String MYSQL_4_0_CHARSET_NAME_koi8_ukr = "koi8_ukr"; // 4.1 => 22 koi8u koi8u_ukrainian_ci - private static final String MYSQL_4_0_CHARSET_NAME_latin1_de = "latin1_de"; // 4.1 => 31 latin1 latin1_german2_ci - private static final String MYSQL_4_0_CHARSET_NAME_latvian = "latvian"; - private static final String MYSQL_4_0_CHARSET_NAME_latvian1 = "latvian1"; - private static final String MYSQL_4_0_CHARSET_NAME_usa7 = "usa7"; // 4.1 => 11 ascii ascii_general_ci - private static final String MYSQL_4_0_CHARSET_NAME_win1250 = "win1250"; // 4.1 => 26 cp1250 cp1250_general_ci - private static final String MYSQL_4_0_CHARSET_NAME_win1251 = "win1251"; // 4.1 => 17 (removed) - private static final String MYSQL_4_0_CHARSET_NAME_win1251ukr = "win1251ukr"; // 4.1 => 23 cp1251 cp1251_ukrainian_ci - - private static final String NOT_USED = MYSQL_CHARSET_NAME_latin1; // punting for not-used character sets - - public static final int MYSQL_COLLATION_INDEX_utf8 = 33; - public static final int MYSQL_COLLATION_INDEX_binary = 63; - - static { - // complete list of mysql character sets and their corresponding java encoding names - MysqlCharset[] charset = new MysqlCharset[]{new MysqlCharset(MYSQL_4_0_CHARSET_NAME_usa7, 1, 0, new String[]{"US-ASCII"}, 4, 0), - new MysqlCharset(MYSQL_CHARSET_NAME_ascii, 1, 0, new String[]{"US-ASCII", "ASCII"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_big5, 2, 0, new String[]{"Big5"}), - new MysqlCharset(MYSQL_CHARSET_NAME_gbk, 2, 0, new String[]{"GBK"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_sjis, 2, 0, new String[]{"SHIFT_JIS", "Cp943", "WINDOWS-31J"}), // SJIS is alias for SHIFT_JIS, Cp943 is rather a cp932 but we map it to sjis for years - new MysqlCharset(MYSQL_CHARSET_NAME_cp932, 2, 1, new String[]{"WINDOWS-31J"}), // MS932 is alias for WINDOWS-31J - - new MysqlCharset(MYSQL_CHARSET_NAME_gb2312, 2, 0, new String[]{"GB2312"}), - new MysqlCharset(MYSQL_CHARSET_NAME_ujis, 3, 0, new String[]{"EUC_JP"}), - new MysqlCharset(MYSQL_CHARSET_NAME_eucjpms, 3, 0, new String[]{"EUC_JP_Solaris"}, 5, 0, 3), // "EUC_JP_Solaris = >5.0.3 eucjpms," - - new MysqlCharset(MYSQL_CHARSET_NAME_gb18030, 4, 0, new String[]{"GB18030"}, 5, 7, 4), - - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_euc_kr, 2, 0, new String[]{"EUC_KR"}, 4, 0), - new MysqlCharset(MYSQL_CHARSET_NAME_euckr, 2, 0, new String[]{"EUC-KR"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_latin1, 1, 1, new String[]{"Cp1252", "ISO8859_1"}), - new MysqlCharset(MYSQL_CHARSET_NAME_swe7, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - new MysqlCharset(MYSQL_CHARSET_NAME_hp8, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - new MysqlCharset(MYSQL_CHARSET_NAME_dec8, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - new MysqlCharset(MYSQL_CHARSET_NAME_armscii8, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - new MysqlCharset(MYSQL_CHARSET_NAME_geostd8, 1, 0, new String[]{"Cp1252"}), // new mapping, Cp1252 ? - - new MysqlCharset(MYSQL_CHARSET_NAME_latin2, 1, 0, new String[]{"ISO8859_2"}), // latin2 is an alias - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_czech, 1, 0, new String[]{"ISO8859_2"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_hungarian, 1, 0, new String[]{"ISO8859_2"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_croat, 1, 0, new String[]{"ISO8859_2"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_greek, 1, 0, new String[]{"ISO8859_7", "greek"}), - new MysqlCharset(MYSQL_CHARSET_NAME_latin7, 1, 0, new String[]{"ISO-8859-13"}), // was ISO8859_7, that's incorrect; also + "LATIN7 = latin7," is wrong java encoding name - - new MysqlCharset(MYSQL_CHARSET_NAME_hebrew, 1, 0, new String[]{"ISO8859_8"}), // hebrew is an alias - new MysqlCharset(MYSQL_CHARSET_NAME_latin5, 1, 0, new String[]{"ISO8859_9"}), // LATIN5 is an alias - - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latvian, 1, 0, new String[]{"ISO8859_13"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latvian1, 1, 0, new String[]{"ISO8859_13"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_estonia, 1, 1, new String[]{"ISO8859_13"}, 4, 0), //, "ISO8859_13"); // punting for "estonia"; - - new MysqlCharset(MYSQL_CHARSET_NAME_cp850, 1, 0, new String[]{"Cp850", "Cp437"}), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_dos, 1, 0, new String[]{"Cp850", "Cp437"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_cp852, 1, 0, new String[]{"Cp852"}), - new MysqlCharset(MYSQL_CHARSET_NAME_keybcs2, 1, 0, new String[]{"Cp852"}), // new, Kamenicky encoding usually known as Cp895 but there is no official cp895 specification; close to Cp852, see http://ftp.muni.cz/pub/localization/charsets/cs-encodings-faq - - new MysqlCharset(MYSQL_CHARSET_NAME_cp866, 1, 0, new String[]{"Cp866"}), - - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_koi8_ru, 1, 0, new String[]{"KOI8_R"}, 4, 0), - new MysqlCharset(MYSQL_CHARSET_NAME_koi8r, 1, 1, new String[]{"KOI8_R"}), - new MysqlCharset(MYSQL_CHARSET_NAME_koi8u, 1, 0, new String[]{"KOI8_R"}), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_koi8_ukr, 1, 0, new String[]{"KOI8_R"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_tis620, 1, 0, new String[]{"TIS620"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_cp1250, 1, 0, new String[]{"Cp1250"}), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1250, 1, 0, new String[]{"Cp1250"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_cp1251, 1, 1, new String[]{"Cp1251"}), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1251, 1, 0, new String[]{"Cp1251"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_cp1251cias, 1, 0, new String[]{"Cp1251"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_cp1251csas, 1, 0, new String[]{"Cp1251"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1251ukr, 1, 0, new String[]{"Cp1251"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_cp1256, 1, 0, new String[]{"Cp1256"}), - new MysqlCharset(MYSQL_CHARSET_NAME_cp1257, 1, 0, new String[]{"Cp1257"}), - new MysqlCharset(MYSQL_CHARSET_NAME_macroman, 1, 0, new String[]{"MacRoman"}), - new MysqlCharset(MYSQL_CHARSET_NAME_macce, 1, 0, new String[]{"MacCentralEurope"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_utf8, 3, 1, new String[]{"UTF-8"}), - new MysqlCharset(MYSQL_CHARSET_NAME_utf8mb4, 4, 0, new String[]{"UTF-8"}), // "UTF-8 = *> 5.5.2 utf8mb4," - - new MysqlCharset(MYSQL_CHARSET_NAME_ucs2, 2, 0, new String[]{"UnicodeBig"}), - - new MysqlCharset(MYSQL_CHARSET_NAME_binary, 1, 1, new String[]{"ISO8859_1"}), // US-ASCII ? - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latin1_de, 1, 0, new String[]{"ISO8859_1"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_german1, 1, 0, new String[]{"ISO8859_1"}, 4, 0), - new MysqlCharset(MYSQL_4_0_CHARSET_NAME_danish, 1, 0, new String[]{"ISO8859_1"}, 4, 0), - - new MysqlCharset(MYSQL_CHARSET_NAME_utf16, 4, 0, new String[]{"UTF-16"}), - new MysqlCharset(MYSQL_CHARSET_NAME_utf16le, 4, 0, new String[]{"UTF-16LE"}), - new MysqlCharset(MYSQL_CHARSET_NAME_utf32, 4, 0, new String[]{"UTF-32"}) - }; - HashMap charsetNameToMysqlCharsetMap = new HashMap(); - HashMap> javaUcToMysqlCharsetMap = new HashMap>(); - - for (int i = 0; i < charset.length; i++) { - String charsetName = charset[i].charsetName; - - charsetNameToMysqlCharsetMap.put(charsetName, charset[i]); - - for (String encUC : charset[i].javaEncodingsUc) { - - // fill javaUcToMysqlCharsetMap - List charsets = javaUcToMysqlCharsetMap.get(encUC); - if (charsets == null) { - charsets = new ArrayList(); - javaUcToMysqlCharsetMap.put(encUC, charsets); - } - charsets.add(charset[i]); - } - } - - CHARSET_NAME_TO_CHARSET = Collections.unmodifiableMap(charsetNameToMysqlCharsetMap); - JAVA_ENCODING_UC_TO_MYSQL_CHARSET = Collections.unmodifiableMap(javaUcToMysqlCharsetMap); - - // complete list of mysql collations and their corresponding character sets each element of collation[1]..collation[MAP_SIZE-1] must not be null - Collation[] collation = new Collation[MAP_SIZE]; - collation[1] = new Collation(1, "big5_chinese_ci", 1, MYSQL_CHARSET_NAME_big5); - collation[84] = new Collation(84, "big5_bin", 0, MYSQL_CHARSET_NAME_big5); - - collation[2] = new Collation(2, "latin2_czech_cs", 0, MYSQL_CHARSET_NAME_latin2); - collation[9] = new Collation(9, "latin2_general_ci", 1, MYSQL_CHARSET_NAME_latin2); - collation[21] = new Collation(21, "latin2_hungarian_ci", 0, MYSQL_CHARSET_NAME_latin2); - collation[27] = new Collation(27, "latin2_croatian_ci", 0, MYSQL_CHARSET_NAME_latin2); - collation[77] = new Collation(77, "latin2_bin", 0, MYSQL_CHARSET_NAME_latin2); - - collation[4] = new Collation(4, "cp850_general_ci", 1, MYSQL_CHARSET_NAME_cp850); - collation[80] = new Collation(80, "cp850_bin", 0, MYSQL_CHARSET_NAME_cp850); - - collation[5] = new Collation(5, "latin1_german1_ci", 1, MYSQL_CHARSET_NAME_latin1); - collation[8] = new Collation(8, "latin1_swedish_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[15] = new Collation(15, "latin1_danish_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[31] = new Collation(31, "latin1_german2_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[47] = new Collation(47, "latin1_bin", 0, MYSQL_CHARSET_NAME_latin1); - collation[48] = new Collation(48, "latin1_general_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[49] = new Collation(49, "latin1_general_cs", 0, MYSQL_CHARSET_NAME_latin1); - collation[76] = new Collation(76, "not_implemented", 0, NOT_USED); - collation[94] = new Collation(94, "latin1_spanish_ci", 0, MYSQL_CHARSET_NAME_latin1); - collation[100] = new Collation(100, "not_implemented", 0, NOT_USED); - collation[125] = new Collation(125, "not_implemented", 0, NOT_USED); - collation[126] = new Collation(126, "not_implemented", 0, NOT_USED); - collation[127] = new Collation(127, "not_implemented", 0, NOT_USED); - collation[152] = new Collation(152, "not_implemented", 0, NOT_USED); - collation[153] = new Collation(153, "not_implemented", 0, NOT_USED); - collation[154] = new Collation(154, "not_implemented", 0, NOT_USED); - collation[155] = new Collation(155, "not_implemented", 0, NOT_USED); - collation[156] = new Collation(156, "not_implemented", 0, NOT_USED); - collation[157] = new Collation(157, "not_implemented", 0, NOT_USED); - collation[158] = new Collation(158, "not_implemented", 0, NOT_USED); - collation[184] = new Collation(184, "not_implemented", 0, NOT_USED); - collation[185] = new Collation(185, "not_implemented", 0, NOT_USED); - collation[186] = new Collation(186, "not_implemented", 0, NOT_USED); - collation[187] = new Collation(187, "not_implemented", 0, NOT_USED); - collation[188] = new Collation(188, "not_implemented", 0, NOT_USED); - collation[189] = new Collation(189, "not_implemented", 0, NOT_USED); - collation[190] = new Collation(190, "not_implemented", 0, NOT_USED); - collation[191] = new Collation(191, "not_implemented", 0, NOT_USED); - collation[216] = new Collation(216, "not_implemented", 0, NOT_USED); - collation[217] = new Collation(217, "not_implemented", 0, NOT_USED); - collation[218] = new Collation(218, "not_implemented", 0, NOT_USED); - collation[219] = new Collation(219, "not_implemented", 0, NOT_USED); - collation[220] = new Collation(220, "not_implemented", 0, NOT_USED); - collation[221] = new Collation(221, "not_implemented", 0, NOT_USED); - collation[222] = new Collation(222, "not_implemented", 0, NOT_USED); - collation[248] = new Collation(248, "gb18030_chinese_ci", 1, MYSQL_CHARSET_NAME_gb18030); - collation[249] = new Collation(249, "gb18030_bin", 0, MYSQL_CHARSET_NAME_gb18030); - collation[250] = new Collation(250, "gb18030_unicode_520_ci", 0, MYSQL_CHARSET_NAME_gb18030); - collation[251] = new Collation(251, "not_implemented", 0, NOT_USED); - collation[252] = new Collation(252, "not_implemented", 0, NOT_USED); - collation[253] = new Collation(253, "not_implemented", 0, NOT_USED); - collation[254] = new Collation(254, "not_implemented", 0, NOT_USED); - collation[10] = new Collation(10, "swe7_swedish_ci", 0, MYSQL_CHARSET_NAME_swe7); - collation[82] = new Collation(82, "swe7_bin", 0, MYSQL_CHARSET_NAME_swe7); - collation[6] = new Collation(6, "hp8_english_ci", 0, MYSQL_CHARSET_NAME_hp8); - collation[72] = new Collation(72, "hp8_bin", 0, MYSQL_CHARSET_NAME_hp8); - collation[3] = new Collation(3, "dec8_swedish_ci", 0, MYSQL_CHARSET_NAME_dec8); - collation[69] = new Collation(69, "dec8_bin", 0, MYSQL_CHARSET_NAME_dec8); - collation[32] = new Collation(32, "armscii8_general_ci", 0, MYSQL_CHARSET_NAME_armscii8); - collation[64] = new Collation(64, "armscii8_bin", 0, MYSQL_CHARSET_NAME_armscii8); - collation[92] = new Collation(92, "geostd8_general_ci", 0, MYSQL_CHARSET_NAME_geostd8); - collation[93] = new Collation(93, "geostd8_bin", 0, MYSQL_CHARSET_NAME_geostd8); - - collation[7] = new Collation(7, "koi8r_general_ci", 0, MYSQL_CHARSET_NAME_koi8r); - collation[74] = new Collation(74, "koi8r_bin", 0, MYSQL_CHARSET_NAME_koi8r); - - collation[11] = new Collation(11, "ascii_general_ci", 0, MYSQL_CHARSET_NAME_ascii); - collation[65] = new Collation(65, "ascii_bin", 0, MYSQL_CHARSET_NAME_ascii); - - collation[12] = new Collation(12, "ujis_japanese_ci", 0, MYSQL_CHARSET_NAME_ujis); - collation[91] = new Collation(91, "ujis_bin", 0, MYSQL_CHARSET_NAME_ujis); - - collation[13] = new Collation(13, "sjis_japanese_ci", 0, MYSQL_CHARSET_NAME_sjis); - collation[14] = new Collation(14, "cp1251_bulgarian_ci", 0, MYSQL_CHARSET_NAME_cp1251); - collation[16] = new Collation(16, "hebrew_general_ci", 0, MYSQL_CHARSET_NAME_hebrew); - collation[17] = new Collation(17, "latin1_german1_ci", 0, MYSQL_4_0_CHARSET_NAME_win1251); // removed since 4.1 - collation[18] = new Collation(18, "tis620_thai_ci", 0, MYSQL_CHARSET_NAME_tis620); - collation[19] = new Collation(19, "euckr_korean_ci", 0, MYSQL_CHARSET_NAME_euckr); - collation[20] = new Collation(20, "latin7_estonian_cs", 0, MYSQL_CHARSET_NAME_latin7); - collation[22] = new Collation(22, "koi8u_general_ci", 0, MYSQL_CHARSET_NAME_koi8u); - collation[23] = new Collation(23, "cp1251_ukrainian_ci", 0, MYSQL_CHARSET_NAME_cp1251); - collation[24] = new Collation(24, "gb2312_chinese_ci", 0, MYSQL_CHARSET_NAME_gb2312); - collation[25] = new Collation(25, "greek_general_ci", 0, MYSQL_CHARSET_NAME_greek); - collation[26] = new Collation(26, "cp1250_general_ci", 1, MYSQL_CHARSET_NAME_cp1250); - collation[28] = new Collation(28, "gbk_chinese_ci", 1, MYSQL_CHARSET_NAME_gbk); - collation[29] = new Collation(29, "cp1257_lithuanian_ci", 0, MYSQL_CHARSET_NAME_cp1257); - collation[30] = new Collation(30, "latin5_turkish_ci", 1, MYSQL_CHARSET_NAME_latin5); - collation[33] = new Collation(33, "utf8_general_ci", 1, MYSQL_CHARSET_NAME_utf8); - collation[34] = new Collation(34, "cp1250_czech_cs", 0, MYSQL_CHARSET_NAME_cp1250); - collation[35] = new Collation(35, "ucs2_general_ci", 1, MYSQL_CHARSET_NAME_ucs2); - collation[36] = new Collation(36, "cp866_general_ci", 1, MYSQL_CHARSET_NAME_cp866); - collation[37] = new Collation(37, "keybcs2_general_ci", 1, MYSQL_CHARSET_NAME_keybcs2); - collation[38] = new Collation(38, "macce_general_ci", 1, MYSQL_CHARSET_NAME_macce); - collation[39] = new Collation(39, "macroman_general_ci", 1, MYSQL_CHARSET_NAME_macroman); - collation[40] = new Collation(40, "cp852_general_ci", 1, MYSQL_CHARSET_NAME_cp852); - collation[41] = new Collation(41, "latin7_general_ci", 1, MYSQL_CHARSET_NAME_latin7); - collation[42] = new Collation(42, "latin7_general_cs", 0, MYSQL_CHARSET_NAME_latin7); - collation[43] = new Collation(43, "macce_bin", 0, MYSQL_CHARSET_NAME_macce); - collation[44] = new Collation(44, "cp1250_croatian_ci", 0, MYSQL_CHARSET_NAME_cp1250); - collation[45] = new Collation(45, "utf8mb4_general_ci", 1, MYSQL_CHARSET_NAME_utf8mb4); - collation[46] = new Collation(46, "utf8mb4_bin", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[50] = new Collation(50, "cp1251_bin", 0, MYSQL_CHARSET_NAME_cp1251); - collation[51] = new Collation(51, "cp1251_general_ci", 1, MYSQL_CHARSET_NAME_cp1251); - collation[52] = new Collation(52, "cp1251_general_cs", 0, MYSQL_CHARSET_NAME_cp1251); - collation[53] = new Collation(53, "macroman_bin", 0, MYSQL_CHARSET_NAME_macroman); - collation[54] = new Collation(54, "utf16_general_ci", 1, MYSQL_CHARSET_NAME_utf16); - collation[55] = new Collation(55, "utf16_bin", 0, MYSQL_CHARSET_NAME_utf16); - collation[56] = new Collation(56, "utf16le_general_ci", 1, MYSQL_CHARSET_NAME_utf16le); - collation[57] = new Collation(57, "cp1256_general_ci", 1, MYSQL_CHARSET_NAME_cp1256); - collation[58] = new Collation(58, "cp1257_bin", 0, MYSQL_CHARSET_NAME_cp1257); - collation[59] = new Collation(59, "cp1257_general_ci", 1, MYSQL_CHARSET_NAME_cp1257); - collation[60] = new Collation(60, "utf32_general_ci", 1, MYSQL_CHARSET_NAME_utf32); - collation[61] = new Collation(61, "utf32_bin", 0, MYSQL_CHARSET_NAME_utf32); - collation[62] = new Collation(62, "utf16le_bin", 0, MYSQL_CHARSET_NAME_utf16le); - collation[63] = new Collation(63, "binary", 1, MYSQL_CHARSET_NAME_binary); - collation[66] = new Collation(66, "cp1250_bin", 0, MYSQL_CHARSET_NAME_cp1250); - collation[67] = new Collation(67, "cp1256_bin", 0, MYSQL_CHARSET_NAME_cp1256); - collation[68] = new Collation(68, "cp866_bin", 0, MYSQL_CHARSET_NAME_cp866); - collation[70] = new Collation(70, "greek_bin", 0, MYSQL_CHARSET_NAME_greek); - collation[71] = new Collation(71, "hebrew_bin", 0, MYSQL_CHARSET_NAME_hebrew); - collation[73] = new Collation(73, "keybcs2_bin", 0, MYSQL_CHARSET_NAME_keybcs2); - collation[75] = new Collation(75, "koi8u_bin", 0, MYSQL_CHARSET_NAME_koi8u); - collation[78] = new Collation(78, "latin5_bin", 0, MYSQL_CHARSET_NAME_latin5); - collation[79] = new Collation(79, "latin7_bin", 0, MYSQL_CHARSET_NAME_latin7); - collation[81] = new Collation(81, "cp852_bin", 0, MYSQL_CHARSET_NAME_cp852); - collation[83] = new Collation(83, "utf8_bin", 0, MYSQL_CHARSET_NAME_utf8); - collation[85] = new Collation(85, "euckr_bin", 0, MYSQL_CHARSET_NAME_euckr); - collation[86] = new Collation(86, "gb2312_bin", 0, MYSQL_CHARSET_NAME_gb2312); - collation[87] = new Collation(87, "gbk_bin", 0, MYSQL_CHARSET_NAME_gbk); - collation[88] = new Collation(88, "sjis_bin", 0, MYSQL_CHARSET_NAME_sjis); - collation[89] = new Collation(89, "tis620_bin", 0, MYSQL_CHARSET_NAME_tis620); - collation[90] = new Collation(90, "ucs2_bin", 0, MYSQL_CHARSET_NAME_ucs2); - collation[95] = new Collation(95, "cp932_japanese_ci", 1, MYSQL_CHARSET_NAME_cp932); - collation[96] = new Collation(96, "cp932_bin", 0, MYSQL_CHARSET_NAME_cp932); - collation[97] = new Collation(97, "eucjpms_japanese_ci", 1, MYSQL_CHARSET_NAME_eucjpms); - collation[98] = new Collation(98, "eucjpms_bin", 0, MYSQL_CHARSET_NAME_eucjpms); - collation[99] = new Collation(99, "cp1250_polish_ci", 0, MYSQL_CHARSET_NAME_cp1250); - collation[101] = new Collation(101, "utf16_unicode_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[102] = new Collation(102, "utf16_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[103] = new Collation(103, "utf16_latvian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[104] = new Collation(104, "utf16_romanian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[105] = new Collation(105, "utf16_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[106] = new Collation(106, "utf16_polish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[107] = new Collation(107, "utf16_estonian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[108] = new Collation(108, "utf16_spanish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[109] = new Collation(109, "utf16_swedish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[110] = new Collation(110, "utf16_turkish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[111] = new Collation(111, "utf16_czech_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[112] = new Collation(112, "utf16_danish_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[113] = new Collation(113, "utf16_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[114] = new Collation(114, "utf16_slovak_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[115] = new Collation(115, "utf16_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[116] = new Collation(116, "utf16_roman_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[117] = new Collation(117, "utf16_persian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[118] = new Collation(118, "utf16_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[119] = new Collation(119, "utf16_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[120] = new Collation(120, "utf16_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[121] = new Collation(121, "utf16_german2_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[122] = new Collation(122, "utf16_croatian_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[123] = new Collation(123, "utf16_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[124] = new Collation(124, "utf16_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf16); - collation[128] = new Collation(128, "ucs2_unicode_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[129] = new Collation(129, "ucs2_icelandic_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[130] = new Collation(130, "ucs2_latvian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[131] = new Collation(131, "ucs2_romanian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[132] = new Collation(132, "ucs2_slovenian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[133] = new Collation(133, "ucs2_polish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[134] = new Collation(134, "ucs2_estonian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[135] = new Collation(135, "ucs2_spanish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[136] = new Collation(136, "ucs2_swedish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[137] = new Collation(137, "ucs2_turkish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[138] = new Collation(138, "ucs2_czech_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[139] = new Collation(139, "ucs2_danish_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[140] = new Collation(140, "ucs2_lithuanian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[141] = new Collation(141, "ucs2_slovak_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[142] = new Collation(142, "ucs2_spanish2_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[143] = new Collation(143, "ucs2_roman_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[144] = new Collation(144, "ucs2_persian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[145] = new Collation(145, "ucs2_esperanto_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[146] = new Collation(146, "ucs2_hungarian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[147] = new Collation(147, "ucs2_sinhala_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[148] = new Collation(148, "ucs2_german2_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[149] = new Collation(149, "ucs2_croatian_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[150] = new Collation(150, "ucs2_unicode_520_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[151] = new Collation(151, "ucs2_vietnamese_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[159] = new Collation(159, "ucs2_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_ucs2); - collation[160] = new Collation(160, "utf32_unicode_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[161] = new Collation(161, "utf32_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[162] = new Collation(162, "utf32_latvian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[163] = new Collation(163, "utf32_romanian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[164] = new Collation(164, "utf32_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[165] = new Collation(165, "utf32_polish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[166] = new Collation(166, "utf32_estonian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[167] = new Collation(167, "utf32_spanish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[168] = new Collation(168, "utf32_swedish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[169] = new Collation(169, "utf32_turkish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[170] = new Collation(170, "utf32_czech_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[171] = new Collation(171, "utf32_danish_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[172] = new Collation(172, "utf32_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[173] = new Collation(173, "utf32_slovak_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[174] = new Collation(174, "utf32_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[175] = new Collation(175, "utf32_roman_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[176] = new Collation(176, "utf32_persian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[177] = new Collation(177, "utf32_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[178] = new Collation(178, "utf32_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[179] = new Collation(179, "utf32_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[180] = new Collation(180, "utf32_german2_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[181] = new Collation(181, "utf32_croatian_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[182] = new Collation(182, "utf32_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[183] = new Collation(183, "utf32_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf32); - collation[192] = new Collation(192, "utf8_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[193] = new Collation(193, "utf8_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[194] = new Collation(194, "utf8_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[195] = new Collation(195, "utf8_romanian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[196] = new Collation(196, "utf8_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[197] = new Collation(197, "utf8_polish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[198] = new Collation(198, "utf8_estonian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[199] = new Collation(199, "utf8_spanish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[200] = new Collation(200, "utf8_swedish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[201] = new Collation(201, "utf8_turkish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[202] = new Collation(202, "utf8_czech_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[203] = new Collation(203, "utf8_danish_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[204] = new Collation(204, "utf8_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[205] = new Collation(205, "utf8_slovak_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[206] = new Collation(206, "utf8_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[207] = new Collation(207, "utf8_roman_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[208] = new Collation(208, "utf8_persian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[209] = new Collation(209, "utf8_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[210] = new Collation(210, "utf8_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[211] = new Collation(211, "utf8_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[212] = new Collation(212, "utf8_german2_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[213] = new Collation(213, "utf8_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[214] = new Collation(214, "utf8_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[215] = new Collation(215, "utf8_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[223] = new Collation(223, "utf8_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_utf8); - collation[224] = new Collation(224, "utf8mb4_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[225] = new Collation(225, "utf8mb4_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[226] = new Collation(226, "utf8mb4_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[227] = new Collation(227, "utf8mb4_romanian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[228] = new Collation(228, "utf8mb4_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[229] = new Collation(229, "utf8mb4_polish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[230] = new Collation(230, "utf8mb4_estonian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[231] = new Collation(231, "utf8mb4_spanish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[232] = new Collation(232, "utf8mb4_swedish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[233] = new Collation(233, "utf8mb4_turkish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[234] = new Collation(234, "utf8mb4_czech_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[235] = new Collation(235, "utf8mb4_danish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[236] = new Collation(236, "utf8mb4_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[237] = new Collation(237, "utf8mb4_slovak_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[238] = new Collation(238, "utf8mb4_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[239] = new Collation(239, "utf8mb4_roman_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[240] = new Collation(240, "utf8mb4_persian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[241] = new Collation(241, "utf8mb4_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[242] = new Collation(242, "utf8mb4_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[243] = new Collation(243, "utf8mb4_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[244] = new Collation(244, "utf8mb4_german2_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[245] = new Collation(245, "utf8mb4_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[246] = new Collation(246, "utf8mb4_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - collation[247] = new Collation(247, "utf8mb4_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); - - COLLATION_INDEX_TO_COLLATION_NAME = new String[MAP_SIZE]; - COLLATION_INDEX_TO_CHARSET = new MysqlCharset[MAP_SIZE]; - - // Add all collations to lookup maps for easy indexing - for (int i = 1; i < MAP_SIZE; i++) { - COLLATION_INDEX_TO_COLLATION_NAME[i] = collation[i].collationName; - COLLATION_INDEX_TO_CHARSET[i] = collation[i].mysqlCharset; - } - - // Sanity check - for (int i = 1; i < MAP_SIZE; i++) { - if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) { - throw new RuntimeException("Assertion failure: No mapping from charset index " + i + " to a mysql collation"); - } - if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) { - throw new RuntimeException("Assertion failure: No mapping from charset index " + i + " to a Java character set"); - } + private static final int MAP_SIZE = 255; // Size of static maps + public static final String[] COLLATION_INDEX_TO_COLLATION_NAME; + private static final MysqlCharset[] COLLATION_INDEX_TO_CHARSET; + + static final Map CHARSET_NAME_TO_CHARSET; + private static final Map> JAVA_ENCODING_UC_TO_MYSQL_CHARSET; + + private static final String MYSQL_CHARSET_NAME_armscii8 = "armscii8"; + private static final String MYSQL_CHARSET_NAME_ascii = "ascii"; + private static final String MYSQL_CHARSET_NAME_big5 = "big5"; + private static final String MYSQL_CHARSET_NAME_binary = "binary"; + private static final String MYSQL_CHARSET_NAME_cp1250 = "cp1250"; + private static final String MYSQL_CHARSET_NAME_cp1251 = "cp1251"; + private static final String MYSQL_CHARSET_NAME_cp1256 = "cp1256"; + private static final String MYSQL_CHARSET_NAME_cp1257 = "cp1257"; + private static final String MYSQL_CHARSET_NAME_cp850 = "cp850"; + private static final String MYSQL_CHARSET_NAME_cp852 = "cp852"; + private static final String MYSQL_CHARSET_NAME_cp866 = "cp866"; + private static final String MYSQL_CHARSET_NAME_cp932 = "cp932"; + private static final String MYSQL_CHARSET_NAME_dec8 = "dec8"; + private static final String MYSQL_CHARSET_NAME_eucjpms = "eucjpms"; + private static final String MYSQL_CHARSET_NAME_euckr = "euckr"; + private static final String MYSQL_CHARSET_NAME_gb18030 = "gb18030"; + private static final String MYSQL_CHARSET_NAME_gb2312 = "gb2312"; + private static final String MYSQL_CHARSET_NAME_gbk = "gbk"; + private static final String MYSQL_CHARSET_NAME_geostd8 = "geostd8"; + private static final String MYSQL_CHARSET_NAME_greek = "greek"; + private static final String MYSQL_CHARSET_NAME_hebrew = "hebrew"; + private static final String MYSQL_CHARSET_NAME_hp8 = "hp8"; + private static final String MYSQL_CHARSET_NAME_keybcs2 = "keybcs2"; + private static final String MYSQL_CHARSET_NAME_koi8r = "koi8r"; + private static final String MYSQL_CHARSET_NAME_koi8u = "koi8u"; + private static final String MYSQL_CHARSET_NAME_latin1 = "latin1"; + private static final String MYSQL_CHARSET_NAME_latin2 = "latin2"; + private static final String MYSQL_CHARSET_NAME_latin5 = "latin5"; + private static final String MYSQL_CHARSET_NAME_latin7 = "latin7"; + private static final String MYSQL_CHARSET_NAME_macce = "macce"; + private static final String MYSQL_CHARSET_NAME_macroman = "macroman"; + private static final String MYSQL_CHARSET_NAME_sjis = "sjis"; + private static final String MYSQL_CHARSET_NAME_swe7 = "swe7"; + private static final String MYSQL_CHARSET_NAME_tis620 = "tis620"; + private static final String MYSQL_CHARSET_NAME_ucs2 = "ucs2"; + private static final String MYSQL_CHARSET_NAME_ujis = "ujis"; + private static final String MYSQL_CHARSET_NAME_utf16 = "utf16"; + private static final String MYSQL_CHARSET_NAME_utf16le = "utf16le"; + private static final String MYSQL_CHARSET_NAME_utf32 = "utf32"; + private static final String MYSQL_CHARSET_NAME_utf8 = "utf8"; + private static final String MYSQL_CHARSET_NAME_utf8mb4 = "utf8mb4"; + + private static final String MYSQL_4_0_CHARSET_NAME_cp1251cias = "cp1251cias"; + private static final String MYSQL_4_0_CHARSET_NAME_cp1251csas = "cp1251csas"; + private static final String MYSQL_4_0_CHARSET_NAME_croat = "croat"; // 4.1 => 27 + // latin2 latin2_croatian_ci + private static final String MYSQL_4_0_CHARSET_NAME_czech = "czech"; // 4.1 => 2 latin2 + // latin2_czech_ci + private static final String MYSQL_4_0_CHARSET_NAME_danish = "danish"; // 4.1 => 15 + // latin1 latin1_danish_ci + private static final String MYSQL_4_0_CHARSET_NAME_dos = "dos"; // 4.1 => 4 cp850 + // cp850_general_ci + private static final String MYSQL_4_0_CHARSET_NAME_estonia = "estonia"; // 4.1 => 20 + // latin7 latin7_estonian_ci + private static final String MYSQL_4_0_CHARSET_NAME_euc_kr = "euc_kr"; // 4.1 => 19 + // euckr euckr_korean_ci + private static final String MYSQL_4_0_CHARSET_NAME_german1 = "german1"; // 4.1 => 5 + // latin1 latin1_german1_ci + private static final String MYSQL_4_0_CHARSET_NAME_hungarian = "hungarian"; // 4.1 => 21 + // latin2 latin2_hungarian_ci + private static final String MYSQL_4_0_CHARSET_NAME_koi8_ru = "koi8_ru"; // 4.1 => 7 + // koi8r koi8r_general_ci + private static final String MYSQL_4_0_CHARSET_NAME_koi8_ukr = "koi8_ukr"; // 4.1 => 22 + // koi8u koi8u_ukrainian_ci + private static final String MYSQL_4_0_CHARSET_NAME_latin1_de = "latin1_de"; // 4.1 => 31 + // latin1 latin1_german2_ci + private static final String MYSQL_4_0_CHARSET_NAME_latvian = "latvian"; + private static final String MYSQL_4_0_CHARSET_NAME_latvian1 = "latvian1"; + private static final String MYSQL_4_0_CHARSET_NAME_usa7 = "usa7"; // 4.1 => 11 + // ascii ascii_general_ci + private static final String MYSQL_4_0_CHARSET_NAME_win1250 = "win1250"; // 4.1 => 26 + // cp1250 cp1250_general_ci + private static final String MYSQL_4_0_CHARSET_NAME_win1251 = "win1251"; // 4.1 => 17 + // (removed) + private static final String MYSQL_4_0_CHARSET_NAME_win1251ukr = "win1251ukr"; // 4.1 => 23 + // cp1251 cp1251_ukrainian_ci + + private static final String NOT_USED = MYSQL_CHARSET_NAME_latin1; // punting for not-used + // character sets + + public static final int MYSQL_COLLATION_INDEX_utf8 = 33; + public static final int MYSQL_COLLATION_INDEX_binary = 63; + + static { + // complete list of mysql character sets and their corresponding java encoding names + MysqlCharset[] charset = new MysqlCharset[]{ + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_usa7, 1, 0, new String[]{"US-ASCII"}, 4, 0), + new MysqlCharset(MYSQL_CHARSET_NAME_ascii, 1, 0, new String[]{"US-ASCII", "ASCII"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_big5, 2, 0, new String[]{"Big5"}), + new MysqlCharset(MYSQL_CHARSET_NAME_gbk, 2, 0, new String[]{"GBK"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_sjis, 2, 0, + new String[]{"SHIFT_JIS", "Cp943", "WINDOWS-31J"}), + // SJIS is alias for SHIFT_JIS, Cp943 is rather a cp932 but we map it to sjis for years + new MysqlCharset(MYSQL_CHARSET_NAME_cp932, 2, 1, new String[]{"WINDOWS-31J"}), + // MS932 is alias for WINDOWS-31J + + new MysqlCharset(MYSQL_CHARSET_NAME_gb2312, 2, 0, new String[]{"GB2312"}), + new MysqlCharset(MYSQL_CHARSET_NAME_ujis, 3, 0, new String[]{"EUC_JP"}), + new MysqlCharset(MYSQL_CHARSET_NAME_eucjpms, 3, 0, new String[]{"EUC_JP_Solaris"}, 5, 0, 3), + // "EUC_JP_Solaris = >5.0.3 eucjpms," + + new MysqlCharset(MYSQL_CHARSET_NAME_gb18030, 4, 0, new String[]{"GB18030"}, 5, 7, 4), + + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_euc_kr, 2, 0, new String[]{"EUC_KR"}, 4, 0), + new MysqlCharset(MYSQL_CHARSET_NAME_euckr, 2, 0, new String[]{"EUC-KR"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_latin1, 1, 1, new String[]{"Cp1252", "ISO8859_1"}), + new MysqlCharset(MYSQL_CHARSET_NAME_swe7, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + new MysqlCharset(MYSQL_CHARSET_NAME_hp8, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + new MysqlCharset(MYSQL_CHARSET_NAME_dec8, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + new MysqlCharset(MYSQL_CHARSET_NAME_armscii8, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + new MysqlCharset(MYSQL_CHARSET_NAME_geostd8, 1, 0, new String[]{"Cp1252"}), + // new mapping, Cp1252 ? + + new MysqlCharset(MYSQL_CHARSET_NAME_latin2, 1, 0, new String[]{"ISO8859_2"}), + // latin2 is an alias + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_czech, 1, 0, new String[]{"ISO8859_2"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_hungarian, 1, 0, new String[]{"ISO8859_2"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_croat, 1, 0, new String[]{"ISO8859_2"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_greek, 1, 0, new String[]{"ISO8859_7", "greek"}), + new MysqlCharset(MYSQL_CHARSET_NAME_latin7, 1, 0, new String[]{"ISO-8859-13"}), + // was ISO8859_7, that's incorrect; also + "LATIN7 = latin7," is wrong java encoding + // name + + new MysqlCharset(MYSQL_CHARSET_NAME_hebrew, 1, 0, new String[]{"ISO8859_8"}), + // hebrew is an alias + new MysqlCharset(MYSQL_CHARSET_NAME_latin5, 1, 0, new String[]{"ISO8859_9"}), + // LATIN5 is an alias + + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latvian, 1, 0, new String[]{"ISO8859_13"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latvian1, 1, 0, new String[]{"ISO8859_13"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_estonia, 1, 1, new String[]{"ISO8859_13"}, 4, 0), + //, "ISO8859_13"); // punting for "estonia"; + + new MysqlCharset(MYSQL_CHARSET_NAME_cp850, 1, 0, new String[]{"Cp850", "Cp437"}), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_dos, 1, 0, new String[]{"Cp850", "Cp437"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_cp852, 1, 0, new String[]{"Cp852"}), + new MysqlCharset(MYSQL_CHARSET_NAME_keybcs2, 1, 0, new String[]{"Cp852"}), + // new, Kamenicky encoding usually known as Cp895 but there is no official cp895 + // specification; close to Cp852, see http://ftp.muni + // .cz/pub/localization/charsets/cs-encodings-faq + + new MysqlCharset(MYSQL_CHARSET_NAME_cp866, 1, 0, new String[]{"Cp866"}), + + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_koi8_ru, 1, 0, new String[]{"KOI8_R"}, 4, 0), + new MysqlCharset(MYSQL_CHARSET_NAME_koi8r, 1, 1, new String[]{"KOI8_R"}), + new MysqlCharset(MYSQL_CHARSET_NAME_koi8u, 1, 0, new String[]{"KOI8_R"}), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_koi8_ukr, 1, 0, new String[]{"KOI8_R"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_tis620, 1, 0, new String[]{"TIS620"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_cp1250, 1, 0, new String[]{"Cp1250"}), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1250, 1, 0, new String[]{"Cp1250"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_cp1251, 1, 1, new String[]{"Cp1251"}), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1251, 1, 0, new String[]{"Cp1251"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_cp1251cias, 1, 0, new String[]{"Cp1251"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_cp1251csas, 1, 0, new String[]{"Cp1251"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_win1251ukr, 1, 0, new String[]{"Cp1251"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_cp1256, 1, 0, new String[]{"Cp1256"}), + new MysqlCharset(MYSQL_CHARSET_NAME_cp1257, 1, 0, new String[]{"Cp1257"}), + new MysqlCharset(MYSQL_CHARSET_NAME_macroman, 1, 0, new String[]{"MacRoman"}), + new MysqlCharset(MYSQL_CHARSET_NAME_macce, 1, 0, new String[]{"MacCentralEurope"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_utf8, 3, 1, new String[]{"UTF-8"}), + new MysqlCharset(MYSQL_CHARSET_NAME_utf8mb4, 4, 0, new String[]{"UTF-8"}), + // "UTF-8 = *> 5.5.2 utf8mb4," + + new MysqlCharset(MYSQL_CHARSET_NAME_ucs2, 2, 0, new String[]{"UnicodeBig"}), + + new MysqlCharset(MYSQL_CHARSET_NAME_binary, 1, 1, new String[]{"ISO8859_1"}), + // US-ASCII ? + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_latin1_de, 1, 0, new String[]{"ISO8859_1"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_german1, 1, 0, new String[]{"ISO8859_1"}, 4, 0), + new MysqlCharset(MYSQL_4_0_CHARSET_NAME_danish, 1, 0, new String[]{"ISO8859_1"}, 4, 0), + + new MysqlCharset(MYSQL_CHARSET_NAME_utf16, 4, 0, new String[]{"UTF-16"}), + new MysqlCharset(MYSQL_CHARSET_NAME_utf16le, 4, 0, new String[]{"UTF-16LE"}), + new MysqlCharset(MYSQL_CHARSET_NAME_utf32, 4, 0, new String[]{"UTF-32"})}; + + HashMap charsetNameToMysqlCharsetMap = new HashMap(); + HashMap> javaUcToMysqlCharsetMap = new HashMap>(); + + for (int i = 0; i < charset.length; i++) { + String charsetName = charset[i].charsetName; + + charsetNameToMysqlCharsetMap.put(charsetName, charset[i]); + + for (String encUC : charset[i].javaEncodingsUc) { + + // fill javaUcToMysqlCharsetMap + List charsets = javaUcToMysqlCharsetMap.get(encUC); + if (charsets == null) { + charsets = new ArrayList(); + javaUcToMysqlCharsetMap.put(encUC, charsets); } + charsets.add(charset[i]); + } } - /** - * MySQL charset could map to several Java encodings. - * So here we choose the one according to next rules: - *
  • if there is no static mapping for this charset then return javaEncoding value as is because this - * could be a custom charset for example - *
  • if static mapping exists and javaEncoding equals to one of Java encoding canonical names or aliases available - * for this mapping then javaEncoding value as is; this is required when result should match to connection encoding, for example if connection encoding is - * Cp943 we must avoid getting SHIFT_JIS for sjis mysql charset - *
  • if static mapping exists and javaEncoding doesn't match any Java encoding canonical - * names or aliases available for this mapping then return default Java encoding (the first in mapping list) - * - * @param collationIndex - * @param javaEncoding - */ - public static String getJavaEncodingForCollationIndex(Integer collationIndex, String javaEncoding) { - String res = javaEncoding; - if (collationIndex != null && collationIndex > 0 && collationIndex < MAP_SIZE) { - MysqlCharset cs = COLLATION_INDEX_TO_CHARSET[collationIndex]; - if (cs != null) { - res = cs.getMatchingJavaEncoding(javaEncoding); - } - } - return res; + CHARSET_NAME_TO_CHARSET = Collections.unmodifiableMap(charsetNameToMysqlCharsetMap); + JAVA_ENCODING_UC_TO_MYSQL_CHARSET = Collections.unmodifiableMap(javaUcToMysqlCharsetMap); + + // complete list of mysql collations and their corresponding character sets each element of + // collation[1]..collation[MAP_SIZE-1] must not be null + Collation[] collation = new Collation[MAP_SIZE]; + collation[1] = new Collation(1, "big5_chinese_ci", 1, MYSQL_CHARSET_NAME_big5); + collation[84] = new Collation(84, "big5_bin", 0, MYSQL_CHARSET_NAME_big5); + + collation[2] = new Collation(2, "latin2_czech_cs", 0, MYSQL_CHARSET_NAME_latin2); + collation[9] = new Collation(9, "latin2_general_ci", 1, MYSQL_CHARSET_NAME_latin2); + collation[21] = new Collation(21, "latin2_hungarian_ci", 0, MYSQL_CHARSET_NAME_latin2); + collation[27] = new Collation(27, "latin2_croatian_ci", 0, MYSQL_CHARSET_NAME_latin2); + collation[77] = new Collation(77, "latin2_bin", 0, MYSQL_CHARSET_NAME_latin2); + + collation[4] = new Collation(4, "cp850_general_ci", 1, MYSQL_CHARSET_NAME_cp850); + collation[80] = new Collation(80, "cp850_bin", 0, MYSQL_CHARSET_NAME_cp850); + + collation[5] = new Collation(5, "latin1_german1_ci", 1, MYSQL_CHARSET_NAME_latin1); + collation[8] = new Collation(8, "latin1_swedish_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[15] = new Collation(15, "latin1_danish_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[31] = new Collation(31, "latin1_german2_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[47] = new Collation(47, "latin1_bin", 0, MYSQL_CHARSET_NAME_latin1); + collation[48] = new Collation(48, "latin1_general_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[49] = new Collation(49, "latin1_general_cs", 0, MYSQL_CHARSET_NAME_latin1); + collation[76] = new Collation(76, "not_implemented", 0, NOT_USED); + collation[94] = new Collation(94, "latin1_spanish_ci", 0, MYSQL_CHARSET_NAME_latin1); + collation[100] = new Collation(100, "not_implemented", 0, NOT_USED); + collation[125] = new Collation(125, "not_implemented", 0, NOT_USED); + collation[126] = new Collation(126, "not_implemented", 0, NOT_USED); + collation[127] = new Collation(127, "not_implemented", 0, NOT_USED); + collation[152] = new Collation(152, "not_implemented", 0, NOT_USED); + collation[153] = new Collation(153, "not_implemented", 0, NOT_USED); + collation[154] = new Collation(154, "not_implemented", 0, NOT_USED); + collation[155] = new Collation(155, "not_implemented", 0, NOT_USED); + collation[156] = new Collation(156, "not_implemented", 0, NOT_USED); + collation[157] = new Collation(157, "not_implemented", 0, NOT_USED); + collation[158] = new Collation(158, "not_implemented", 0, NOT_USED); + collation[184] = new Collation(184, "not_implemented", 0, NOT_USED); + collation[185] = new Collation(185, "not_implemented", 0, NOT_USED); + collation[186] = new Collation(186, "not_implemented", 0, NOT_USED); + collation[187] = new Collation(187, "not_implemented", 0, NOT_USED); + collation[188] = new Collation(188, "not_implemented", 0, NOT_USED); + collation[189] = new Collation(189, "not_implemented", 0, NOT_USED); + collation[190] = new Collation(190, "not_implemented", 0, NOT_USED); + collation[191] = new Collation(191, "not_implemented", 0, NOT_USED); + collation[216] = new Collation(216, "not_implemented", 0, NOT_USED); + collation[217] = new Collation(217, "not_implemented", 0, NOT_USED); + collation[218] = new Collation(218, "not_implemented", 0, NOT_USED); + collation[219] = new Collation(219, "not_implemented", 0, NOT_USED); + collation[220] = new Collation(220, "not_implemented", 0, NOT_USED); + collation[221] = new Collation(221, "not_implemented", 0, NOT_USED); + collation[222] = new Collation(222, "not_implemented", 0, NOT_USED); + collation[248] = new Collation(248, "gb18030_chinese_ci", 1, MYSQL_CHARSET_NAME_gb18030); + collation[249] = new Collation(249, "gb18030_bin", 0, MYSQL_CHARSET_NAME_gb18030); + collation[250] = new Collation(250, "gb18030_unicode_520_ci", 0, MYSQL_CHARSET_NAME_gb18030); + collation[251] = new Collation(251, "not_implemented", 0, NOT_USED); + collation[252] = new Collation(252, "not_implemented", 0, NOT_USED); + collation[253] = new Collation(253, "not_implemented", 0, NOT_USED); + collation[254] = new Collation(254, "not_implemented", 0, NOT_USED); + collation[10] = new Collation(10, "swe7_swedish_ci", 0, MYSQL_CHARSET_NAME_swe7); + collation[82] = new Collation(82, "swe7_bin", 0, MYSQL_CHARSET_NAME_swe7); + collation[6] = new Collation(6, "hp8_english_ci", 0, MYSQL_CHARSET_NAME_hp8); + collation[72] = new Collation(72, "hp8_bin", 0, MYSQL_CHARSET_NAME_hp8); + collation[3] = new Collation(3, "dec8_swedish_ci", 0, MYSQL_CHARSET_NAME_dec8); + collation[69] = new Collation(69, "dec8_bin", 0, MYSQL_CHARSET_NAME_dec8); + collation[32] = new Collation(32, "armscii8_general_ci", 0, MYSQL_CHARSET_NAME_armscii8); + collation[64] = new Collation(64, "armscii8_bin", 0, MYSQL_CHARSET_NAME_armscii8); + collation[92] = new Collation(92, "geostd8_general_ci", 0, MYSQL_CHARSET_NAME_geostd8); + collation[93] = new Collation(93, "geostd8_bin", 0, MYSQL_CHARSET_NAME_geostd8); + + collation[7] = new Collation(7, "koi8r_general_ci", 0, MYSQL_CHARSET_NAME_koi8r); + collation[74] = new Collation(74, "koi8r_bin", 0, MYSQL_CHARSET_NAME_koi8r); + + collation[11] = new Collation(11, "ascii_general_ci", 0, MYSQL_CHARSET_NAME_ascii); + collation[65] = new Collation(65, "ascii_bin", 0, MYSQL_CHARSET_NAME_ascii); + + collation[12] = new Collation(12, "ujis_japanese_ci", 0, MYSQL_CHARSET_NAME_ujis); + collation[91] = new Collation(91, "ujis_bin", 0, MYSQL_CHARSET_NAME_ujis); + + collation[13] = new Collation(13, "sjis_japanese_ci", 0, MYSQL_CHARSET_NAME_sjis); + collation[14] = new Collation(14, "cp1251_bulgarian_ci", 0, MYSQL_CHARSET_NAME_cp1251); + collation[16] = new Collation(16, "hebrew_general_ci", 0, MYSQL_CHARSET_NAME_hebrew); + collation[17] = new Collation(17, "latin1_german1_ci", 0, + MYSQL_4_0_CHARSET_NAME_win1251); // removed since 4.1 + collation[18] = new Collation(18, "tis620_thai_ci", 0, MYSQL_CHARSET_NAME_tis620); + collation[19] = new Collation(19, "euckr_korean_ci", 0, MYSQL_CHARSET_NAME_euckr); + collation[20] = new Collation(20, "latin7_estonian_cs", 0, MYSQL_CHARSET_NAME_latin7); + collation[22] = new Collation(22, "koi8u_general_ci", 0, MYSQL_CHARSET_NAME_koi8u); + collation[23] = new Collation(23, "cp1251_ukrainian_ci", 0, MYSQL_CHARSET_NAME_cp1251); + collation[24] = new Collation(24, "gb2312_chinese_ci", 0, MYSQL_CHARSET_NAME_gb2312); + collation[25] = new Collation(25, "greek_general_ci", 0, MYSQL_CHARSET_NAME_greek); + collation[26] = new Collation(26, "cp1250_general_ci", 1, MYSQL_CHARSET_NAME_cp1250); + collation[28] = new Collation(28, "gbk_chinese_ci", 1, MYSQL_CHARSET_NAME_gbk); + collation[29] = new Collation(29, "cp1257_lithuanian_ci", 0, MYSQL_CHARSET_NAME_cp1257); + collation[30] = new Collation(30, "latin5_turkish_ci", 1, MYSQL_CHARSET_NAME_latin5); + collation[33] = new Collation(33, "utf8_general_ci", 1, MYSQL_CHARSET_NAME_utf8); + collation[34] = new Collation(34, "cp1250_czech_cs", 0, MYSQL_CHARSET_NAME_cp1250); + collation[35] = new Collation(35, "ucs2_general_ci", 1, MYSQL_CHARSET_NAME_ucs2); + collation[36] = new Collation(36, "cp866_general_ci", 1, MYSQL_CHARSET_NAME_cp866); + collation[37] = new Collation(37, "keybcs2_general_ci", 1, MYSQL_CHARSET_NAME_keybcs2); + collation[38] = new Collation(38, "macce_general_ci", 1, MYSQL_CHARSET_NAME_macce); + collation[39] = new Collation(39, "macroman_general_ci", 1, MYSQL_CHARSET_NAME_macroman); + collation[40] = new Collation(40, "cp852_general_ci", 1, MYSQL_CHARSET_NAME_cp852); + collation[41] = new Collation(41, "latin7_general_ci", 1, MYSQL_CHARSET_NAME_latin7); + collation[42] = new Collation(42, "latin7_general_cs", 0, MYSQL_CHARSET_NAME_latin7); + collation[43] = new Collation(43, "macce_bin", 0, MYSQL_CHARSET_NAME_macce); + collation[44] = new Collation(44, "cp1250_croatian_ci", 0, MYSQL_CHARSET_NAME_cp1250); + collation[45] = new Collation(45, "utf8mb4_general_ci", 1, MYSQL_CHARSET_NAME_utf8mb4); + collation[46] = new Collation(46, "utf8mb4_bin", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[50] = new Collation(50, "cp1251_bin", 0, MYSQL_CHARSET_NAME_cp1251); + collation[51] = new Collation(51, "cp1251_general_ci", 1, MYSQL_CHARSET_NAME_cp1251); + collation[52] = new Collation(52, "cp1251_general_cs", 0, MYSQL_CHARSET_NAME_cp1251); + collation[53] = new Collation(53, "macroman_bin", 0, MYSQL_CHARSET_NAME_macroman); + collation[54] = new Collation(54, "utf16_general_ci", 1, MYSQL_CHARSET_NAME_utf16); + collation[55] = new Collation(55, "utf16_bin", 0, MYSQL_CHARSET_NAME_utf16); + collation[56] = new Collation(56, "utf16le_general_ci", 1, MYSQL_CHARSET_NAME_utf16le); + collation[57] = new Collation(57, "cp1256_general_ci", 1, MYSQL_CHARSET_NAME_cp1256); + collation[58] = new Collation(58, "cp1257_bin", 0, MYSQL_CHARSET_NAME_cp1257); + collation[59] = new Collation(59, "cp1257_general_ci", 1, MYSQL_CHARSET_NAME_cp1257); + collation[60] = new Collation(60, "utf32_general_ci", 1, MYSQL_CHARSET_NAME_utf32); + collation[61] = new Collation(61, "utf32_bin", 0, MYSQL_CHARSET_NAME_utf32); + collation[62] = new Collation(62, "utf16le_bin", 0, MYSQL_CHARSET_NAME_utf16le); + collation[63] = new Collation(63, "binary", 1, MYSQL_CHARSET_NAME_binary); + collation[66] = new Collation(66, "cp1250_bin", 0, MYSQL_CHARSET_NAME_cp1250); + collation[67] = new Collation(67, "cp1256_bin", 0, MYSQL_CHARSET_NAME_cp1256); + collation[68] = new Collation(68, "cp866_bin", 0, MYSQL_CHARSET_NAME_cp866); + collation[70] = new Collation(70, "greek_bin", 0, MYSQL_CHARSET_NAME_greek); + collation[71] = new Collation(71, "hebrew_bin", 0, MYSQL_CHARSET_NAME_hebrew); + collation[73] = new Collation(73, "keybcs2_bin", 0, MYSQL_CHARSET_NAME_keybcs2); + collation[75] = new Collation(75, "koi8u_bin", 0, MYSQL_CHARSET_NAME_koi8u); + collation[78] = new Collation(78, "latin5_bin", 0, MYSQL_CHARSET_NAME_latin5); + collation[79] = new Collation(79, "latin7_bin", 0, MYSQL_CHARSET_NAME_latin7); + collation[81] = new Collation(81, "cp852_bin", 0, MYSQL_CHARSET_NAME_cp852); + collation[83] = new Collation(83, "utf8_bin", 0, MYSQL_CHARSET_NAME_utf8); + collation[85] = new Collation(85, "euckr_bin", 0, MYSQL_CHARSET_NAME_euckr); + collation[86] = new Collation(86, "gb2312_bin", 0, MYSQL_CHARSET_NAME_gb2312); + collation[87] = new Collation(87, "gbk_bin", 0, MYSQL_CHARSET_NAME_gbk); + collation[88] = new Collation(88, "sjis_bin", 0, MYSQL_CHARSET_NAME_sjis); + collation[89] = new Collation(89, "tis620_bin", 0, MYSQL_CHARSET_NAME_tis620); + collation[90] = new Collation(90, "ucs2_bin", 0, MYSQL_CHARSET_NAME_ucs2); + collation[95] = new Collation(95, "cp932_japanese_ci", 1, MYSQL_CHARSET_NAME_cp932); + collation[96] = new Collation(96, "cp932_bin", 0, MYSQL_CHARSET_NAME_cp932); + collation[97] = new Collation(97, "eucjpms_japanese_ci", 1, MYSQL_CHARSET_NAME_eucjpms); + collation[98] = new Collation(98, "eucjpms_bin", 0, MYSQL_CHARSET_NAME_eucjpms); + collation[99] = new Collation(99, "cp1250_polish_ci", 0, MYSQL_CHARSET_NAME_cp1250); + collation[101] = new Collation(101, "utf16_unicode_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[102] = new Collation(102, "utf16_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[103] = new Collation(103, "utf16_latvian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[104] = new Collation(104, "utf16_romanian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[105] = new Collation(105, "utf16_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[106] = new Collation(106, "utf16_polish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[107] = new Collation(107, "utf16_estonian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[108] = new Collation(108, "utf16_spanish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[109] = new Collation(109, "utf16_swedish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[110] = new Collation(110, "utf16_turkish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[111] = new Collation(111, "utf16_czech_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[112] = new Collation(112, "utf16_danish_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[113] = new Collation(113, "utf16_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[114] = new Collation(114, "utf16_slovak_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[115] = new Collation(115, "utf16_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[116] = new Collation(116, "utf16_roman_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[117] = new Collation(117, "utf16_persian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[118] = new Collation(118, "utf16_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[119] = new Collation(119, "utf16_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[120] = new Collation(120, "utf16_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[121] = new Collation(121, "utf16_german2_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[122] = new Collation(122, "utf16_croatian_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[123] = new Collation(123, "utf16_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[124] = new Collation(124, "utf16_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf16); + collation[128] = new Collation(128, "ucs2_unicode_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[129] = new Collation(129, "ucs2_icelandic_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[130] = new Collation(130, "ucs2_latvian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[131] = new Collation(131, "ucs2_romanian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[132] = new Collation(132, "ucs2_slovenian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[133] = new Collation(133, "ucs2_polish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[134] = new Collation(134, "ucs2_estonian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[135] = new Collation(135, "ucs2_spanish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[136] = new Collation(136, "ucs2_swedish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[137] = new Collation(137, "ucs2_turkish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[138] = new Collation(138, "ucs2_czech_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[139] = new Collation(139, "ucs2_danish_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[140] = new Collation(140, "ucs2_lithuanian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[141] = new Collation(141, "ucs2_slovak_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[142] = new Collation(142, "ucs2_spanish2_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[143] = new Collation(143, "ucs2_roman_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[144] = new Collation(144, "ucs2_persian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[145] = new Collation(145, "ucs2_esperanto_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[146] = new Collation(146, "ucs2_hungarian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[147] = new Collation(147, "ucs2_sinhala_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[148] = new Collation(148, "ucs2_german2_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[149] = new Collation(149, "ucs2_croatian_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[150] = new Collation(150, "ucs2_unicode_520_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[151] = new Collation(151, "ucs2_vietnamese_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[159] = new Collation(159, "ucs2_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_ucs2); + collation[160] = new Collation(160, "utf32_unicode_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[161] = new Collation(161, "utf32_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[162] = new Collation(162, "utf32_latvian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[163] = new Collation(163, "utf32_romanian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[164] = new Collation(164, "utf32_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[165] = new Collation(165, "utf32_polish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[166] = new Collation(166, "utf32_estonian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[167] = new Collation(167, "utf32_spanish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[168] = new Collation(168, "utf32_swedish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[169] = new Collation(169, "utf32_turkish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[170] = new Collation(170, "utf32_czech_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[171] = new Collation(171, "utf32_danish_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[172] = new Collation(172, "utf32_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[173] = new Collation(173, "utf32_slovak_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[174] = new Collation(174, "utf32_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[175] = new Collation(175, "utf32_roman_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[176] = new Collation(176, "utf32_persian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[177] = new Collation(177, "utf32_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[178] = new Collation(178, "utf32_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[179] = new Collation(179, "utf32_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[180] = new Collation(180, "utf32_german2_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[181] = new Collation(181, "utf32_croatian_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[182] = new Collation(182, "utf32_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[183] = new Collation(183, "utf32_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf32); + collation[192] = new Collation(192, "utf8_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[193] = new Collation(193, "utf8_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[194] = new Collation(194, "utf8_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[195] = new Collation(195, "utf8_romanian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[196] = new Collation(196, "utf8_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[197] = new Collation(197, "utf8_polish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[198] = new Collation(198, "utf8_estonian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[199] = new Collation(199, "utf8_spanish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[200] = new Collation(200, "utf8_swedish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[201] = new Collation(201, "utf8_turkish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[202] = new Collation(202, "utf8_czech_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[203] = new Collation(203, "utf8_danish_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[204] = new Collation(204, "utf8_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[205] = new Collation(205, "utf8_slovak_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[206] = new Collation(206, "utf8_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[207] = new Collation(207, "utf8_roman_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[208] = new Collation(208, "utf8_persian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[209] = new Collation(209, "utf8_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[210] = new Collation(210, "utf8_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[211] = new Collation(211, "utf8_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[212] = new Collation(212, "utf8_german2_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[213] = new Collation(213, "utf8_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[214] = new Collation(214, "utf8_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[215] = new Collation(215, "utf8_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[223] = new Collation(223, "utf8_general_mysql500_ci", 0, MYSQL_CHARSET_NAME_utf8); + collation[224] = new Collation(224, "utf8mb4_unicode_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[225] = new Collation(225, "utf8mb4_icelandic_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[226] = new Collation(226, "utf8mb4_latvian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[227] = new Collation(227, "utf8mb4_romanian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[228] = new Collation(228, "utf8mb4_slovenian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[229] = new Collation(229, "utf8mb4_polish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[230] = new Collation(230, "utf8mb4_estonian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[231] = new Collation(231, "utf8mb4_spanish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[232] = new Collation(232, "utf8mb4_swedish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[233] = new Collation(233, "utf8mb4_turkish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[234] = new Collation(234, "utf8mb4_czech_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[235] = new Collation(235, "utf8mb4_danish_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[236] = new Collation(236, "utf8mb4_lithuanian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[237] = new Collation(237, "utf8mb4_slovak_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[238] = new Collation(238, "utf8mb4_spanish2_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[239] = new Collation(239, "utf8mb4_roman_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[240] = new Collation(240, "utf8mb4_persian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[241] = new Collation(241, "utf8mb4_esperanto_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[242] = new Collation(242, "utf8mb4_hungarian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[243] = new Collation(243, "utf8mb4_sinhala_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[244] = new Collation(244, "utf8mb4_german2_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[245] = new Collation(245, "utf8mb4_croatian_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[246] = new Collation(246, "utf8mb4_unicode_520_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + collation[247] = new Collation(247, "utf8mb4_vietnamese_ci", 0, MYSQL_CHARSET_NAME_utf8mb4); + + COLLATION_INDEX_TO_COLLATION_NAME = new String[MAP_SIZE]; + COLLATION_INDEX_TO_CHARSET = new MysqlCharset[MAP_SIZE]; + + // Add all collations to lookup maps for easy indexing + for (int i = 1; i < MAP_SIZE; i++) { + COLLATION_INDEX_TO_COLLATION_NAME[i] = collation[i].collationName; + COLLATION_INDEX_TO_CHARSET[i] = collation[i].mysqlCharset; } - public static String getMysqlCharsetNameForCollationIndex(Integer collationIndex) { - if (collationIndex != null && collationIndex > 0 && collationIndex < MAP_SIZE) { - return COLLATION_INDEX_TO_CHARSET[collationIndex].charsetName; - } - return null; + // Sanity check + for (int i = 1; i < MAP_SIZE; i++) { + if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) { + throw new RuntimeException( + "Assertion failure: No mapping from charset index " + i + " to a mysql collation"); + } + if (COLLATION_INDEX_TO_COLLATION_NAME[i] == null) { + throw new RuntimeException( + "Assertion failure: No mapping from charset index " + i + " to a Java character set"); + } } + } + + /** + * MySQL charset could map to several Java encodings. So here we choose the one according to next + * rules: + *
  • if there is no static mapping for this charset then return javaEncoding value as is + * because this could be a custom charset for example + *
  • if static mapping exists and javaEncoding equals to one of Java encoding canonical names + * or aliases available for this mapping then javaEncoding value as is; this is required when + * result should match to connection encoding, for example if connection encoding is Cp943 we must + * avoid getting SHIFT_JIS for sjis mysql charset + *
  • if static mapping exists and javaEncoding doesn't match any Java encoding canonical + * names or aliases available for this mapping then return default Java encoding (the first in + * mapping list) + */ + public static String getJavaEncodingForCollationIndex(Integer collationIndex, + String javaEncoding) { + String res = javaEncoding; + if (collationIndex != null && collationIndex > 0 && collationIndex < MAP_SIZE) { + MysqlCharset cs = COLLATION_INDEX_TO_CHARSET[collationIndex]; + if (cs != null) { + res = cs.getMatchingJavaEncoding(javaEncoding); + } + } + return res; + } - public static String getMysqlCharsetForJavaEncoding(String javaEncoding) { - if (javaEncoding != null) { - List mysqlCharsets = CharsetMapping.JAVA_ENCODING_UC_TO_MYSQL_CHARSET.get(javaEncoding.toUpperCase(Locale.ENGLISH)); + public static String getMysqlCharsetNameForCollationIndex(Integer collationIndex) { + if (collationIndex != null && collationIndex > 0 && collationIndex < MAP_SIZE) { + return COLLATION_INDEX_TO_CHARSET[collationIndex].charsetName; + } + return null; + } - if (mysqlCharsets != null && !mysqlCharsets.isEmpty()) { - return mysqlCharsets.get(0).charsetName; - } - } + public static String getMysqlCharsetForJavaEncoding(String javaEncoding) { + if (javaEncoding != null) { + List mysqlCharsets = CharsetMapping.JAVA_ENCODING_UC_TO_MYSQL_CHARSET + .get(javaEncoding.toUpperCase(Locale.ENGLISH)); - return null; + if (mysqlCharsets != null && !mysqlCharsets.isEmpty()) { + return mysqlCharsets.get(0).charsetName; + } } - public static int getMblen(String charsetName) { - if (charsetName != null) { - MysqlCharset cs = CHARSET_NAME_TO_CHARSET.get(charsetName); - if (cs != null) { - return cs.mblen; - } - } - return 0; + return null; + } + + public static int getMblen(String charsetName) { + if (charsetName != null) { + MysqlCharset cs = CHARSET_NAME_TO_CHARSET.get(charsetName); + if (cs != null) { + return cs.mblen; + } } + return 0; + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/charset/Collation.java b/java/jdbc/src/main/java/io/vitess/util/charset/Collation.java index 638958564a5..53c095f623e 100644 --- a/java/jdbc/src/main/java/io/vitess/util/charset/Collation.java +++ b/java/jdbc/src/main/java/io/vitess/util/charset/Collation.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,33 +17,27 @@ package io.vitess.util.charset; /** - * These classes were pulled from mysql-connector-java and simplified to just the parts supporting the statically available - * charsets + * These classes were pulled from mysql-connector-java and simplified to just the parts supporting + * the statically available charsets */ class Collation { - public final int index; - public final String collationName; - public final int priority; - public final MysqlCharset mysqlCharset; - public Collation(int index, String collationName, int priority, String charsetName) { - this.index = index; - this.collationName = collationName; - this.priority = priority; - this.mysqlCharset = CharsetMapping.CHARSET_NAME_TO_CHARSET.get(charsetName); - } + public final int index; + public final String collationName; + public final int priority; + public final MysqlCharset mysqlCharset; - @Override - public String toString() { - return "[" + - "index=" + - this.index + - ",collationName=" + - this.collationName + - ",charsetName=" + - this.mysqlCharset.charsetName + - ",javaCharsetName=" + - this.mysqlCharset.getMatchingJavaEncoding(null) + - "]"; - } + public Collation(int index, String collationName, int priority, String charsetName) { + this.index = index; + this.collationName = collationName; + this.priority = priority; + this.mysqlCharset = CharsetMapping.CHARSET_NAME_TO_CHARSET.get(charsetName); + } + + @Override + public String toString() { + return "[" + "index=" + this.index + ",collationName=" + this.collationName + ",charsetName=" + + this.mysqlCharset.charsetName + ",javaCharsetName=" + this.mysqlCharset + .getMatchingJavaEncoding(null) + "]"; + } } diff --git a/java/jdbc/src/main/java/io/vitess/util/charset/MysqlCharset.java b/java/jdbc/src/main/java/io/vitess/util/charset/MysqlCharset.java index 7357673ee4e..78447d31e73 100644 --- a/java/jdbc/src/main/java/io/vitess/util/charset/MysqlCharset.java +++ b/java/jdbc/src/main/java/io/vitess/util/charset/MysqlCharset.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,118 +17,121 @@ package io.vitess.util.charset; import java.nio.charset.Charset; -import java.sql.SQLException; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Set; /** - * These classes were pulled from mysql-connector-java and simplified to just the parts supporting the statically available - * charsets + * These classes were pulled from mysql-connector-java and simplified to just the parts supporting + * the statically available charsets */ class MysqlCharset { - public final String charsetName; - public final int mblen; - public final int priority; - public final Set javaEncodingsUc = new HashSet<>(); - private String defaultEncoding = null; - - public int major = 4; - public int minor = 1; - public int subminor = 0; - - /** - * Constructs MysqlCharset object - * - * @param charsetName MySQL charset name - * @param mblen Max number of bytes per character - * @param priority MysqlCharset with highest lever of this param will be used for Java encoding --> Mysql charsets conversion. - * @param javaEncodings List of Java encodings corresponding to this MySQL charset; the first name in list is the default for mysql --> java data conversion - */ - public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings) { - this.charsetName = charsetName; - this.mblen = mblen; - this.priority = priority; - - for (int i = 0; i < javaEncodings.length; i++) { - String encoding = javaEncodings[i]; - try { - Charset cs = Charset.forName(encoding); - addEncodingMapping(cs.name()); - - Set als = cs.aliases(); - Iterator ali = als.iterator(); - while (ali.hasNext()) { - addEncodingMapping(ali.next()); - } - } catch (Exception e) { - // if there is no support of this charset in JVM it's still possible to use our converter for 1-byte charsets - if (mblen == 1) { - addEncodingMapping(encoding); - } - } - } - if (this.javaEncodingsUc.size() == 0) { - if (mblen > 1) { - addEncodingMapping("UTF-8"); - } else { - addEncodingMapping("Cp1252"); - } - } - } + public final String charsetName; + public final int mblen; + public final int priority; + public final Set javaEncodingsUc = new HashSet<>(); + private String defaultEncoding = null; - private void addEncodingMapping(String encoding) { - String encodingUc = encoding.toUpperCase(Locale.ENGLISH); + public int major = 4; + public int minor = 1; + public int subminor = 0; - if (this.defaultEncoding == null) { - this.defaultEncoding = encodingUc; - } + /** + * Constructs MysqlCharset object + * + * @param charsetName MySQL charset name + * @param mblen Max number of bytes per character + * @param priority MysqlCharset with highest lever of this param will be used for Java + * encoding --> Mysql charsets conversion. + * @param javaEncodings List of Java encodings corresponding to this MySQL charset; the first + * name in list is the default for mysql --> java data conversion + */ + public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings) { + this.charsetName = charsetName; + this.mblen = mblen; + this.priority = priority; + + for (int i = 0; i < javaEncodings.length; i++) { + String encoding = javaEncodings[i]; + try { + Charset cs = Charset.forName(encoding); + addEncodingMapping(cs.name()); - if (!this.javaEncodingsUc.contains(encodingUc)) { - this.javaEncodingsUc.add(encodingUc); + Set als = cs.aliases(); + Iterator ali = als.iterator(); + while (ali.hasNext()) { + addEncodingMapping(ali.next()); + } + } catch (Exception exc) { + // if there is no support of this charset in JVM it's still possible to use our converter + // for 1-byte charsets + if (mblen == 1) { + addEncodingMapping(encoding); } + } } - public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings, int major, int minor) { - this(charsetName, mblen, priority, javaEncodings); - this.major = major; - this.minor = minor; + if (this.javaEncodingsUc.size() == 0) { + if (mblen > 1) { + addEncodingMapping("UTF-8"); + } else { + addEncodingMapping("Cp1252"); + } } + } - public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings, int major, int minor, int subminor) { - this(charsetName, mblen, priority, javaEncodings); - this.major = major; - this.minor = minor; - this.subminor = subminor; + private void addEncodingMapping(String encoding) { + String encodingUc = encoding.toUpperCase(Locale.ENGLISH); + + if (this.defaultEncoding == null) { + this.defaultEncoding = encodingUc; } - @Override - public String toString() { - StringBuilder asString = new StringBuilder(); - asString.append("["); - asString.append("charsetName="); - asString.append(this.charsetName); - asString.append(",mblen="); - asString.append(this.mblen); - // asString.append(",javaEncoding="); - // asString.append(this.javaEncodings.toString()); - asString.append("]"); - return asString.toString(); + if (!this.javaEncodingsUc.contains(encodingUc)) { + this.javaEncodingsUc.add(encodingUc); } + } - /** - * If javaEncoding parameter value is one of available java encodings for this charset - * then returns javaEncoding value as is. Otherwise returns first available java encoding name. - * - * @param javaEncoding - * @throws SQLException - */ - String getMatchingJavaEncoding(String javaEncoding) { - if (javaEncoding != null && this.javaEncodingsUc.contains(javaEncoding.toUpperCase(Locale.ENGLISH))) { - return javaEncoding; - } - return this.defaultEncoding; + public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings, + int major, int minor) { + this(charsetName, mblen, priority, javaEncodings); + this.major = major; + this.minor = minor; + } + + public MysqlCharset(String charsetName, int mblen, int priority, String[] javaEncodings, + int major, int minor, int subminor) { + this(charsetName, mblen, priority, javaEncodings); + this.major = major; + this.minor = minor; + this.subminor = subminor; + } + + @Override + public String toString() { + StringBuilder asString = new StringBuilder(); + asString.append("["); + asString.append("charsetName="); + asString.append(this.charsetName); + asString.append(",mblen="); + asString.append(this.mblen); + // asString.append(",javaEncoding="); + // asString.append(this.javaEncodings.toString()); + asString.append("]"); + return asString.toString(); + } + + /** + * If javaEncoding parameter value is one of available java encodings for this charset then + * returns javaEncoding value as is. Otherwise returns first available java encoding name. + */ + String getMatchingJavaEncoding(String javaEncoding) { + if (javaEncoding != null && this.javaEncodingsUc + .contains(javaEncoding.toUpperCase(Locale.ENGLISH))) { + return javaEncoding; } + return this.defaultEncoding; + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/BaseTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/BaseTest.java index 5d4f7fbfaff..c677a376674 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/BaseTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/BaseTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,29 +16,30 @@ package io.vitess.jdbc; -import org.junit.Assert; -import org.junit.BeforeClass; - import java.sql.SQLException; import java.util.Properties; +import org.junit.Assert; +import org.junit.BeforeClass; + public class BaseTest { - String dbURL = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace"; - - @BeforeClass - public static void setUp() { - try { - Class.forName("io.vitess.jdbc.VitessDriver"); - } catch (ClassNotFoundException e) { - Assert.fail("Driver is not in the CLASSPATH -> " + e.getMessage()); - } - } - protected VitessConnection getVitessConnection() throws SQLException { - return new VitessConnection(dbURL, new Properties()); - } + String dbURL = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace"; - protected VitessStatement getVitessStatement() throws SQLException { - return new VitessStatement(getVitessConnection()); + @BeforeClass + public static void setUp() { + try { + Class.forName("io.vitess.jdbc.VitessDriver"); + } catch (ClassNotFoundException e) { + Assert.fail("Driver is not in the CLASSPATH -> " + e.getMessage()); } + } + + protected VitessConnection getVitessConnection() throws SQLException { + return new VitessConnection(dbURL, new Properties()); + } + + protected VitessStatement getVitessStatement() throws SQLException { + return new VitessStatement(getVitessConnection()); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java index 195b867fa4d..6f5057d97c8 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/ConnectionPropertiesTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,20 +16,6 @@ package io.vitess.jdbc; -import org.junit.Assert; -import org.junit.Test; -import org.mockito.Mockito; - -import io.vitess.proto.Query; -import io.vitess.proto.Topodata; -import io.vitess.util.Constants; -import io.vitess.util.Constants.ZeroDateTimeBehavior; - -import java.sql.DriverPropertyInfo; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Properties; - import static io.vitess.util.Constants.DEFAULT_EXECUTE_TYPE; import static io.vitess.util.Constants.DEFAULT_INCLUDED_FIELDS; import static io.vitess.util.Constants.DEFAULT_TABLET_TYPE; @@ -41,259 +27,282 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -public class ConnectionPropertiesTest { - - private static final int NUM_PROPS = 39; - - @Test - public void testReflection() throws Exception { - ConnectionProperties props = new ConnectionProperties(); - Properties info = Mockito.spy(Properties.class); - Mockito.doReturn(info).when(info).clone(); - props.initializeProperties(info); - - // Just testing that we are properly picking up all the fields defined in the properties - // For each field we call initializeFrom, which should call getProperty and remove - verify(info, times(NUM_PROPS)).getProperty(anyString()); - verify(info, times(NUM_PROPS)).remove(anyString()); - } - - @Test - public void testDefaults() throws SQLException { - - ConnectionProperties props = new ConnectionProperties(); - props.initializeProperties(new Properties()); - - assertEquals("blobsAreStrings", false, props.getBlobsAreStrings()); - assertEquals("functionsNeverReturnBlobs", false, props.getFunctionsNeverReturnBlobs()); - assertEquals("tinyInt1isBit", true, props.getTinyInt1isBit()); - assertEquals("yearIsDateType", true, props.getYearIsDateType()); - assertEquals("useBlobToStoreUTF8OutsideBMP", false, props.getUseBlobToStoreUTF8OutsideBMP()); - assertEquals("utf8OutsideBmpIncludedColumnNamePattern", null, props.getUtf8OutsideBmpIncludedColumnNamePattern()); - assertEquals("utf8OutsideBmpExcludedColumnNamePattern", null, props.getUtf8OutsideBmpExcludedColumnNamePattern()); - assertEquals("zeroDateTimeBehavior", ZeroDateTimeBehavior.GARBLE, props.getZeroDateTimeBehavior()); - assertEquals("characterEncoding", null, props.getEncoding()); - assertEquals("executeType", DEFAULT_EXECUTE_TYPE, props.getExecuteType()); - assertEquals("twopcEnabled", false, props.getTwopcEnabled()); - assertEquals("includedFields", DEFAULT_INCLUDED_FIELDS, props.getIncludedFields()); - assertEquals("includedFieldsCache", true, props.isIncludeAllFields()); - assertEquals("tabletType", DEFAULT_TABLET_TYPE, props.getTabletType()); - assertEquals("useSSL", false, props.getUseSSL()); - assertEquals("useAffectedRows", true, props.getUseAffectedRows()); - assertEquals("refreshConnection", false, props.getRefreshConnection()); - assertEquals("refreshSeconds", 60, props.getRefreshSeconds()); - } +import io.vitess.proto.Query; +import io.vitess.proto.Topodata; +import io.vitess.util.Constants; +import io.vitess.util.Constants.ZeroDateTimeBehavior; - @Test - public void testInitializeFromProperties() throws SQLException { - - ConnectionProperties props = new ConnectionProperties(); - Properties info = new Properties(); - info.setProperty("blobsAreStrings", "yes"); - info.setProperty("functionsNeverReturnBlobs", "yes"); - info.setProperty("tinyInt1isBit", "yes"); - info.setProperty("yearIsDateType", "yes"); - info.setProperty("useBlobToStoreUTF8OutsideBMP", "yes"); - info.setProperty("utf8OutsideBmpIncludedColumnNamePattern", "(foo|bar)?baz"); - info.setProperty("utf8OutsideBmpExcludedColumnNamePattern", "(foo|bar)?baz"); - info.setProperty("characterEncoding", "utf-8"); - info.setProperty("zeroDateTimeBehavior", "convertToNull"); - info.setProperty("executeType", Constants.QueryExecuteType.STREAM.name()); - info.setProperty("twopcEnabled", "yes"); - info.setProperty("includedFields", Query.ExecuteOptions.IncludedFields.TYPE_ONLY.name()); - info.setProperty(Constants.Property.TABLET_TYPE, Topodata.TabletType.BACKUP.name()); - - props.initializeProperties(info); - - assertEquals("blobsAreStrings", true, props.getBlobsAreStrings()); - assertEquals("functionsNeverReturnBlobs", true, props.getFunctionsNeverReturnBlobs()); - assertEquals("tinyInt1isBit", true, props.getTinyInt1isBit()); - assertEquals("yearIsDateType", true, props.getYearIsDateType()); - assertEquals("useBlobToStoreUTF8OutsideBMP", true, props.getUseBlobToStoreUTF8OutsideBMP()); - assertEquals("utf8OutsideBmpIncludedColumnNamePattern", "(foo|bar)?baz", props.getUtf8OutsideBmpIncludedColumnNamePattern()); - assertEquals("utf8OutsideBmpExcludedColumnNamePattern", "(foo|bar)?baz", props.getUtf8OutsideBmpExcludedColumnNamePattern()); - assertEquals("zeroDateTimeBehavior", ZeroDateTimeBehavior.CONVERTTONULL, props.getZeroDateTimeBehavior()); - assertEquals("characterEncoding", "utf-8", props.getEncoding()); - assertEquals("executeType", Constants.QueryExecuteType.STREAM, props.getExecuteType()); - assertEquals("twopcEnabled", true, props.getTwopcEnabled()); - assertEquals("includedFields", Query.ExecuteOptions.IncludedFields.TYPE_ONLY, props.getIncludedFields()); - assertEquals("includedFieldsCache", false, props.isIncludeAllFields()); - assertEquals("tabletType", Topodata.TabletType.BACKUP, props.getTabletType()); - } +import java.sql.DriverPropertyInfo; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Properties; - @Test - public void testEncodingValidation() { - ConnectionProperties props = new ConnectionProperties(); - Properties info = new Properties(); - - String fakeEncoding = "utf-12345"; - info.setProperty("characterEncoding", fakeEncoding); - try { - props.initializeProperties(info); - fail("should have failed to parse encoding " + fakeEncoding); - } catch (SQLException e) { - assertEquals("Unsupported character encoding: " + fakeEncoding, e.getMessage()); - } - } +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; - @Test - public void testDriverPropertiesOutput() throws SQLException { - Properties info = new Properties(); - DriverPropertyInfo[] infos = ConnectionProperties.exposeAsDriverPropertyInfo(info, 0); - assertEquals(NUM_PROPS, infos.length); - - // Test the expected fields for just 1 - int indexForFullTest = 3; - assertEquals("executeType", infos[indexForFullTest].name); - assertEquals("Query execution type: simple or stream", - infos[indexForFullTest].description); - assertEquals(false, infos[indexForFullTest].required); - Constants.QueryExecuteType[] enumConstants = Constants.QueryExecuteType.values(); - String[] allowed = new String[enumConstants.length]; - for (int i = 0; i < enumConstants.length; i++) { - allowed[i] = enumConstants[i].toString(); - } - Assert.assertArrayEquals(allowed, infos[indexForFullTest].choices); - - // Test that name exists for the others, as a sanity check - assertEquals("dbName", infos[1].name); - assertEquals("characterEncoding", infos[2].name); - assertEquals("executeType", infos[3].name); - assertEquals("functionsNeverReturnBlobs", infos[4].name); - assertEquals("grpcRetriesEnabled", infos[5].name); - assertEquals("grpcRetriesBackoffMultiplier", infos[6].name); - assertEquals("grpcRetriesInitialBackoffMillis", infos[7].name); - assertEquals("grpcRetriesMaxBackoffMillis", infos[8].name); - assertEquals(Constants.Property.INCLUDED_FIELDS, infos[9].name); - assertEquals(Constants.Property.TABLET_TYPE, infos[21].name); - assertEquals(Constants.Property.TWOPC_ENABLED, infos[29].name); - } +public class ConnectionPropertiesTest { - @Test - public void testValidBooleanValues() throws SQLException { - ConnectionProperties props = new ConnectionProperties(); - Properties info = new Properties(); - - info.setProperty("blobsAreStrings", "true"); - info.setProperty("functionsNeverReturnBlobs", "yes"); - info.setProperty("tinyInt1isBit", "no"); - - props.initializeProperties(info); - - info.setProperty(Constants.Property.TWOPC_ENABLED, "false-ish"); - try { - props.initializeProperties(info); - fail("should have thrown an exception on bad value false-ish"); - } catch (IllegalArgumentException e) { - String expected = String.format("Property '%s' Value 'false-ish' not in the list of allowable values: [true, false, yes, no]", - Constants.Property.TWOPC_ENABLED); - assertEquals(expected , e.getMessage()); - } + private static final int NUM_PROPS = 39; + + @Test + public void testReflection() throws Exception { + ConnectionProperties props = new ConnectionProperties(); + Properties info = Mockito.spy(Properties.class); + Mockito.doReturn(info).when(info).clone(); + props.initializeProperties(info); + + // Just testing that we are properly picking up all the fields defined in the properties + // For each field we call initializeFrom, which should call getProperty and remove + verify(info, times(NUM_PROPS)).getProperty(anyString()); + verify(info, times(NUM_PROPS)).remove(anyString()); + } + + @Test + public void testDefaults() throws SQLException { + + ConnectionProperties props = new ConnectionProperties(); + props.initializeProperties(new Properties()); + + assertEquals("blobsAreStrings", false, props.getBlobsAreStrings()); + assertEquals("functionsNeverReturnBlobs", false, props.getFunctionsNeverReturnBlobs()); + assertEquals("tinyInt1isBit", true, props.getTinyInt1isBit()); + assertEquals("yearIsDateType", true, props.getYearIsDateType()); + assertEquals("useBlobToStoreUTF8OutsideBMP", false, props.getUseBlobToStoreUTF8OutsideBMP()); + assertEquals("utf8OutsideBmpIncludedColumnNamePattern", null, + props.getUtf8OutsideBmpIncludedColumnNamePattern()); + assertEquals("utf8OutsideBmpExcludedColumnNamePattern", null, + props.getUtf8OutsideBmpExcludedColumnNamePattern()); + assertEquals("zeroDateTimeBehavior", ZeroDateTimeBehavior.GARBLE, + props.getZeroDateTimeBehavior()); + assertEquals("characterEncoding", null, props.getEncoding()); + assertEquals("executeType", DEFAULT_EXECUTE_TYPE, props.getExecuteType()); + assertEquals("twopcEnabled", false, props.getTwopcEnabled()); + assertEquals("includedFields", DEFAULT_INCLUDED_FIELDS, props.getIncludedFields()); + assertEquals("includedFieldsCache", true, props.isIncludeAllFields()); + assertEquals("tabletType", DEFAULT_TABLET_TYPE, props.getTabletType()); + assertEquals("useSSL", false, props.getUseSSL()); + assertEquals("useAffectedRows", true, props.getUseAffectedRows()); + assertEquals("refreshConnection", false, props.getRefreshConnection()); + assertEquals("refreshSeconds", 60, props.getRefreshSeconds()); + } + + @Test + public void testInitializeFromProperties() throws SQLException { + + ConnectionProperties props = new ConnectionProperties(); + Properties info = new Properties(); + info.setProperty("blobsAreStrings", "yes"); + info.setProperty("functionsNeverReturnBlobs", "yes"); + info.setProperty("tinyInt1isBit", "yes"); + info.setProperty("yearIsDateType", "yes"); + info.setProperty("useBlobToStoreUTF8OutsideBMP", "yes"); + info.setProperty("utf8OutsideBmpIncludedColumnNamePattern", "(foo|bar)?baz"); + info.setProperty("utf8OutsideBmpExcludedColumnNamePattern", "(foo|bar)?baz"); + info.setProperty("characterEncoding", "utf-8"); + info.setProperty("zeroDateTimeBehavior", "convertToNull"); + info.setProperty("executeType", Constants.QueryExecuteType.STREAM.name()); + info.setProperty("twopcEnabled", "yes"); + info.setProperty("includedFields", Query.ExecuteOptions.IncludedFields.TYPE_ONLY.name()); + info.setProperty(Constants.Property.TABLET_TYPE, Topodata.TabletType.BACKUP.name()); + + props.initializeProperties(info); + + assertEquals("blobsAreStrings", true, props.getBlobsAreStrings()); + assertEquals("functionsNeverReturnBlobs", true, props.getFunctionsNeverReturnBlobs()); + assertEquals("tinyInt1isBit", true, props.getTinyInt1isBit()); + assertEquals("yearIsDateType", true, props.getYearIsDateType()); + assertEquals("useBlobToStoreUTF8OutsideBMP", true, props.getUseBlobToStoreUTF8OutsideBMP()); + assertEquals("utf8OutsideBmpIncludedColumnNamePattern", "(foo|bar)?baz", + props.getUtf8OutsideBmpIncludedColumnNamePattern()); + assertEquals("utf8OutsideBmpExcludedColumnNamePattern", "(foo|bar)?baz", + props.getUtf8OutsideBmpExcludedColumnNamePattern()); + assertEquals("zeroDateTimeBehavior", ZeroDateTimeBehavior.CONVERTTONULL, + props.getZeroDateTimeBehavior()); + assertEquals("characterEncoding", "utf-8", props.getEncoding()); + assertEquals("executeType", Constants.QueryExecuteType.STREAM, props.getExecuteType()); + assertEquals("twopcEnabled", true, props.getTwopcEnabled()); + assertEquals("includedFields", Query.ExecuteOptions.IncludedFields.TYPE_ONLY, + props.getIncludedFields()); + assertEquals("includedFieldsCache", false, props.isIncludeAllFields()); + assertEquals("tabletType", Topodata.TabletType.BACKUP, props.getTabletType()); + } + + @Test + public void testEncodingValidation() { + ConnectionProperties props = new ConnectionProperties(); + Properties info = new Properties(); + + String fakeEncoding = "utf-12345"; + info.setProperty("characterEncoding", fakeEncoding); + try { + props.initializeProperties(info); + fail("should have failed to parse encoding " + fakeEncoding); + } catch (SQLException e) { + assertEquals("Unsupported character encoding: " + fakeEncoding, e.getMessage()); } - - @Test - public void testValidEnumValues() throws SQLException { - ConnectionProperties props = new ConnectionProperties(); - Properties info = new Properties(); - - info.setProperty("executeType", "foo"); - try { - props.initializeProperties(info); - fail("should have thrown an exception on bad value foo"); - } catch (IllegalArgumentException e) { - assertEquals( - "Property 'executeType' Value 'foo' not in the list of allowable values: " - + Arrays.toString(Constants.QueryExecuteType.values()) - , e.getMessage()); - } + } + + @Test + public void testDriverPropertiesOutput() throws SQLException { + Properties info = new Properties(); + DriverPropertyInfo[] infos = ConnectionProperties.exposeAsDriverPropertyInfo(info, 0); + assertEquals(NUM_PROPS, infos.length); + + // Test the expected fields for just 1 + int indexForFullTest = 3; + assertEquals("executeType", infos[indexForFullTest].name); + assertEquals("Query execution type: simple or stream", infos[indexForFullTest].description); + assertEquals(false, infos[indexForFullTest].required); + Constants.QueryExecuteType[] enumConstants = Constants.QueryExecuteType.values(); + String[] allowed = new String[enumConstants.length]; + for (int i = 0; i < enumConstants.length; i++) { + allowed[i] = enumConstants[i].toString(); } - - @Test - public void testSettersUpdateCaches() throws SQLException { - ConnectionProperties props = new ConnectionProperties(); - props.initializeProperties(new Properties()); - - // included fields and all boolean cache - assertEquals(DEFAULT_INCLUDED_FIELDS, props.getIncludedFields()); - assertTrue(props.isIncludeAllFields()); - - // execute type and simple boolean cache - assertEquals(DEFAULT_EXECUTE_TYPE, props.getExecuteType()); - assertEquals(DEFAULT_EXECUTE_TYPE == Constants.QueryExecuteType.SIMPLE, props.isSimpleExecute()); - - // tablet type and twopc - assertEquals(DEFAULT_TABLET_TYPE, props.getTabletType()); - assertFalse(props.getTwopcEnabled()); - - props.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - props.setExecuteType(Constants.QueryExecuteType.STREAM); - props.setTabletType(Topodata.TabletType.BACKUP); - props.setTwopcEnabled(true); - - // included fields and all boolean cache - assertEquals(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME, props.getIncludedFields()); - assertFalse(props.isIncludeAllFields()); - - // execute type and simple boolean cache - assertEquals(Constants.QueryExecuteType.STREAM, props.getExecuteType()); - assertEquals(DEFAULT_EXECUTE_TYPE != Constants.QueryExecuteType.SIMPLE, props.isSimpleExecute()); - - // tablet type and twopc - assertEquals(Topodata.TabletType.BACKUP, props.getTabletType()); - assertTrue(props.getTwopcEnabled()); + Assert.assertArrayEquals(allowed, infos[indexForFullTest].choices); + + // Test that name exists for the others, as a sanity check + assertEquals("dbName", infos[1].name); + assertEquals("characterEncoding", infos[2].name); + assertEquals("executeType", infos[3].name); + assertEquals("functionsNeverReturnBlobs", infos[4].name); + assertEquals("grpcRetriesEnabled", infos[5].name); + assertEquals("grpcRetriesBackoffMultiplier", infos[6].name); + assertEquals("grpcRetriesInitialBackoffMillis", infos[7].name); + assertEquals("grpcRetriesMaxBackoffMillis", infos[8].name); + assertEquals(Constants.Property.INCLUDED_FIELDS, infos[9].name); + assertEquals(Constants.Property.TABLET_TYPE, infos[21].name); + assertEquals(Constants.Property.TWOPC_ENABLED, infos[29].name); + } + + @Test + public void testValidBooleanValues() throws SQLException { + ConnectionProperties props = new ConnectionProperties(); + Properties info = new Properties(); + + info.setProperty("blobsAreStrings", "true"); + info.setProperty("functionsNeverReturnBlobs", "yes"); + info.setProperty("tinyInt1isBit", "no"); + + props.initializeProperties(info); + + info.setProperty(Constants.Property.TWOPC_ENABLED, "false-ish"); + try { + props.initializeProperties(info); + fail("should have thrown an exception on bad value false-ish"); + } catch (IllegalArgumentException e) { + String expected = String.format( + "Property '%s' Value 'false-ish' not in the list of allowable values: [true, false, " + + "yes, no]", + Constants.Property.TWOPC_ENABLED); + assertEquals(expected, e.getMessage()); } - - @Test - public void testTarget() throws SQLException { - ConnectionProperties props = new ConnectionProperties(); - - // Setting keyspace - Properties info = new Properties(); - info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); - props.initializeProperties(info); - assertEquals("target", "test_keyspace@master", props.getTarget()); - - // Setting keyspace and shard - info = new Properties(); - info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); - info.setProperty(Constants.Property.SHARD, "80-c0"); - props.initializeProperties(info); - assertEquals("target", "test_keyspace:80-c0@master", props.getTarget()); - - // Setting tablet type - info = new Properties(); - info.setProperty(Constants.Property.TABLET_TYPE, "replica"); - props.initializeProperties(info); - assertEquals("target", "@replica", props.getTarget()); - - // Setting shard which will have no impact without keyspace - info = new Properties(); - info.setProperty(Constants.Property.SHARD, "80-c0"); - props.initializeProperties(info); - assertEquals("target", "@master", props.getTarget()); - - // Setting shard and tablet type. Shard will have no impact. - info = new Properties(); - info.setProperty(Constants.Property.SHARD, "80-c0"); - info.setProperty(Constants.Property.TABLET_TYPE, "replica"); - props.initializeProperties(info); - assertEquals("target", "@replica", props.getTarget()); - - // Setting keyspace, shard and tablet type. - info = new Properties(); - info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); - info.setProperty(Constants.Property.SHARD, "80-c0"); - info.setProperty(Constants.Property.TABLET_TYPE, "rdonly"); - props.initializeProperties(info); - assertEquals("target", "test_keyspace:80-c0@rdonly", props.getTarget()); - - // Setting keyspace, shard, tablet type and target. Target supersede others. - info = new Properties(); - info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); - info.setProperty(Constants.Property.SHARD, "80-c0"); - info.setProperty(Constants.Property.TABLET_TYPE, "rdonly"); - info.setProperty(Constants.Property.TARGET, "dummy"); - props.initializeProperties(info); - assertEquals("target", "dummy", props.getTarget()); + } + + @Test + public void testValidEnumValues() throws SQLException { + ConnectionProperties props = new ConnectionProperties(); + Properties info = new Properties(); + + info.setProperty("executeType", "foo"); + try { + props.initializeProperties(info); + fail("should have thrown an exception on bad value foo"); + } catch (IllegalArgumentException e) { + assertEquals( + "Property 'executeType' Value 'foo' not in the list of allowable values: " + Arrays + .toString(Constants.QueryExecuteType.values()), e.getMessage()); } + } + + @Test + public void testSettersUpdateCaches() throws SQLException { + ConnectionProperties props = new ConnectionProperties(); + props.initializeProperties(new Properties()); + + // included fields and all boolean cache + assertEquals(DEFAULT_INCLUDED_FIELDS, props.getIncludedFields()); + assertTrue(props.isIncludeAllFields()); + + // execute type and simple boolean cache + assertEquals(DEFAULT_EXECUTE_TYPE, props.getExecuteType()); + assertEquals(DEFAULT_EXECUTE_TYPE == Constants.QueryExecuteType.SIMPLE, + props.isSimpleExecute()); + + // tablet type and twopc + assertEquals(DEFAULT_TABLET_TYPE, props.getTabletType()); + assertFalse(props.getTwopcEnabled()); + + props.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + props.setExecuteType(Constants.QueryExecuteType.STREAM); + props.setTabletType(Topodata.TabletType.BACKUP); + props.setTwopcEnabled(true); + + // included fields and all boolean cache + assertEquals(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME, props.getIncludedFields()); + assertFalse(props.isIncludeAllFields()); + + // execute type and simple boolean cache + assertEquals(Constants.QueryExecuteType.STREAM, props.getExecuteType()); + assertEquals(DEFAULT_EXECUTE_TYPE != Constants.QueryExecuteType.SIMPLE, + props.isSimpleExecute()); + + // tablet type and twopc + assertEquals(Topodata.TabletType.BACKUP, props.getTabletType()); + assertTrue(props.getTwopcEnabled()); + } + + @Test + public void testTarget() throws SQLException { + ConnectionProperties props = new ConnectionProperties(); + + // Setting keyspace + Properties info = new Properties(); + info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); + props.initializeProperties(info); + assertEquals("target", "test_keyspace@master", props.getTarget()); + + // Setting keyspace and shard + info = new Properties(); + info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); + info.setProperty(Constants.Property.SHARD, "80-c0"); + props.initializeProperties(info); + assertEquals("target", "test_keyspace:80-c0@master", props.getTarget()); + + // Setting tablet type + info = new Properties(); + info.setProperty(Constants.Property.TABLET_TYPE, "replica"); + props.initializeProperties(info); + assertEquals("target", "@replica", props.getTarget()); + + // Setting shard which will have no impact without keyspace + info = new Properties(); + info.setProperty(Constants.Property.SHARD, "80-c0"); + props.initializeProperties(info); + assertEquals("target", "@master", props.getTarget()); + + // Setting shard and tablet type. Shard will have no impact. + info = new Properties(); + info.setProperty(Constants.Property.SHARD, "80-c0"); + info.setProperty(Constants.Property.TABLET_TYPE, "replica"); + props.initializeProperties(info); + assertEquals("target", "@replica", props.getTarget()); + + // Setting keyspace, shard and tablet type. + info = new Properties(); + info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); + info.setProperty(Constants.Property.SHARD, "80-c0"); + info.setProperty(Constants.Property.TABLET_TYPE, "rdonly"); + props.initializeProperties(info); + assertEquals("target", "test_keyspace:80-c0@rdonly", props.getTarget()); + + // Setting keyspace, shard, tablet type and target. Target supersede others. + info = new Properties(); + info.setProperty(Constants.Property.KEYSPACE, "test_keyspace"); + info.setProperty(Constants.Property.SHARD, "80-c0"); + info.setProperty(Constants.Property.TABLET_TYPE, "rdonly"); + info.setProperty(Constants.Property.TARGET, "dummy"); + props.initializeProperties(info); + assertEquals("target", "dummy", props.getTarget()); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java index 863399930a3..a112d3c154f 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/FieldWithMetadataTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,6 +16,13 @@ package io.vitess.jdbc; +import io.vitess.proto.Query; +import io.vitess.util.MysqlDefs; +import io.vitess.util.charset.CharsetMapping; + +import java.sql.SQLException; +import java.sql.Types; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -25,721 +32,591 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import io.vitess.proto.Query; -import io.vitess.util.MysqlDefs; -import io.vitess.util.charset.CharsetMapping; - -import java.sql.SQLException; -import java.sql.Types; - @PrepareForTest(FieldWithMetadata.class) @RunWith(PowerMockRunner.class) public class FieldWithMetadataTest extends BaseTest { - @Test - public void testImplicitTempTable() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setTable("#sql_my_temptable") - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .setType(Query.Type.VARCHAR) - .setName("foo") - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(getVitessConnection(), raw); - - Assert.assertEquals(true, fieldWithMetadata.isImplicitTemporaryTable()); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); - - VitessConnection conn = getVitessConnection(); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - - raw = Query.Field.newBuilder() - .setType(Query.Type.VARCHAR) - .setName("foo") - .build(); - - fieldWithMetadata = new FieldWithMetadata(conn, raw); - - Assert.assertEquals(false, fieldWithMetadata.isImplicitTemporaryTable()); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + @Test + public void testImplicitTempTable() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setTable("#sql_my_temptable") + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).setType(Query.Type.VARCHAR).setName("foo") + .build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(getVitessConnection(), raw); + + Assert.assertEquals(true, fieldWithMetadata.isImplicitTemporaryTable()); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + + VitessConnection conn = getVitessConnection(); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + + raw = Query.Field.newBuilder().setType(Query.Type.VARCHAR).setName("foo").build(); + + fieldWithMetadata = new FieldWithMetadata(conn, raw); + + Assert.assertEquals(false, fieldWithMetadata.isImplicitTemporaryTable()); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + } + + @Test + public void testBlobRemapping() throws SQLException { + VitessConnection conn = getVitessConnection(); + conn.setBlobsAreStrings(true); + + Query.Field raw = Query.Field.newBuilder().setTable("#sql_my_temptable") + .setCharset(/* latin1, doesn't matter just dont want utf8 for now */ 5) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).setType(Query.Type.BLOB).setName("foo") + .setOrgName("foo").build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); + + conn.setBlobsAreStrings(false); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); + + conn.setFunctionsNeverReturnBlobs(true); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); + + conn.setFunctionsNeverReturnBlobs(false); + conn.setUseBlobToStoreUTF8OutsideBMP(true); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); + + raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setColumnLength(MysqlDefs.LENGTH_BLOB).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); + + conn.setUtf8OutsideBmpExcludedColumnNamePattern("^fo.*$"); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARBINARY, fieldWithMetadata.getJavaType()); + Assert.assertNotEquals("utf8_general_ci", fieldWithMetadata.getCollation()); + + conn.setUtf8OutsideBmpIncludedColumnNamePattern("^foo$"); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); + + raw = raw.toBuilder().setColumnLength(MysqlDefs.LENGTH_LONGBLOB).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); + + conn.setUseBlobToStoreUTF8OutsideBMP(false); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.LONGVARBINARY, fieldWithMetadata.getJavaType()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BLOB, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(null, fieldWithMetadata.getCollation()); + } + + @Test + public void testTinyIntAsBit() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.INT8).setName("foo").setOrgName("foo").build(); + conn.setTinyInt1isBit(true); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.TINYINT, fieldWithMetadata.getJavaType()); + + raw = raw.toBuilder().setColumnLength(1).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.TINYINT, fieldWithMetadata.getJavaType()); + } + + @Test + public void testNonNumericNotDateTimeRemapping() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.VARBINARY).setName("foo").setOrgName("foo") + .setCharset(/* utf-16 UnicodeBig */35).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(/* remapped by TEXT special case */Types.VARCHAR, + fieldWithMetadata.getJavaType()); + Assert.assertEquals("UTF-16", fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.VARBINARY, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + + conn = getVitessConnection(); + raw = raw.toBuilder().setType(Query.Type.JSON).setColumnLength(MysqlDefs.LENGTH_LONGBLOB) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary).build(); + + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.CHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals("UTF-8", fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.CHAR, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + + conn = getVitessConnection(); + raw = raw.toBuilder().setType(Query.Type.BIT).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + Assert.assertEquals("ISO-8859-1", fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + + conn = getVitessConnection(); + raw = raw.toBuilder().setColumnLength(1).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + Assert.assertEquals("ISO-8859-1", fieldWithMetadata.getEncoding()); + Assert.assertEquals(true, fieldWithMetadata.isSingleBit()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); + Assert.assertEquals(null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + } + + @Test + public void testVarBinaryToVarCharRemapping() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.VARBINARY).setName("foo").setOrgName("foo") + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert + .assertEquals("no remapping - base case", Types.VARBINARY, fieldWithMetadata.getJavaType()); + + raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals("remap to varchar due to non-binary encoding", Types.VARCHAR, + fieldWithMetadata.getJavaType()); + } + + @Test + public void testBinaryToCharRemapping() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.BINARY).setName("foo").setOrgName("foo") + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals("no remapping - base case", Types.BINARY, fieldWithMetadata.getJavaType()); + + raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals("remap to char due to non-binary encoding", Types.CHAR, + fieldWithMetadata.getJavaType()); + } + + @Test + public void testNumericAndDateTimeEncoding() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Type[] types = new Query.Type[]{Query.Type.INT8, Query.Type.UINT8, Query.Type.INT16, + Query.Type.UINT16, Query.Type.INT24, Query.Type.UINT24, Query.Type.INT32, Query.Type.UINT32, + Query.Type.INT64, Query.Type.UINT64, Query.Type.DECIMAL, Query.Type.UINT24, + Query.Type.INT32, Query.Type.UINT32, Query.Type.FLOAT32, Query.Type.FLOAT64, + Query.Type.DATE, Query.Type.DATETIME, Query.Type.TIME, Query.Type.TIMESTAMP, + Query.Type.YEAR}; + + for (Query.Type type : types) { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3).setType(type) + .setName("foo").setOrgName("foo").setCharset(/* utf-16 UnicodeBig */35).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(type.name(), "US-ASCII", fieldWithMetadata.getEncoding()); + Assert.assertEquals(type.name(), false, fieldWithMetadata.isSingleBit()); } - @Test - public void testBlobRemapping() throws SQLException { - VitessConnection conn = getVitessConnection(); - conn.setBlobsAreStrings(true); - - Query.Field raw = Query.Field.newBuilder() - .setTable("#sql_my_temptable") - .setCharset(/* latin1, doesn't matter just dont want utf8 for now */ 5) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .setType(Query.Type.BLOB) - .setName("foo") - .setOrgName("foo") - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); - - conn.setBlobsAreStrings(false); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); - - conn.setFunctionsNeverReturnBlobs(true); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); - - conn.setFunctionsNeverReturnBlobs(false); - conn.setUseBlobToStoreUTF8OutsideBMP(true); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); - - raw = raw.toBuilder() - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setColumnLength(MysqlDefs.LENGTH_BLOB) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); - - conn.setUtf8OutsideBmpExcludedColumnNamePattern("^fo.*$"); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARBINARY, fieldWithMetadata.getJavaType()); - Assert.assertNotEquals("utf8_general_ci", fieldWithMetadata.getCollation()); - - conn.setUtf8OutsideBmpIncludedColumnNamePattern("^foo$"); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARCHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); - - raw = raw.toBuilder() - .setColumnLength(MysqlDefs.LENGTH_LONGBLOB) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARCHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("utf8_general_ci", fieldWithMetadata.getCollation()); - - conn.setUseBlobToStoreUTF8OutsideBMP(false); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.LONGVARBINARY, fieldWithMetadata.getJavaType()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BLOB, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(null, fieldWithMetadata.getCollation()); - } + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - @Test - public void testTinyIntAsBit() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.INT8) - .setName("foo") - .setOrgName("foo") - .build(); - conn.setTinyInt1isBit(true); - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.TINYINT, fieldWithMetadata.getJavaType()); - - raw = raw.toBuilder() - .setColumnLength(1) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.TINYINT, fieldWithMetadata.getJavaType()); - } + for (Query.Type type : types) { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3).setType(type) + .setName("foo").setOrgName("foo").setCharset(/* utf-16 UnicodeBig */35).build(); - @Test - public void testNonNumericNotDateTimeRemapping() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.VARBINARY) - .setName("foo") - .setOrgName("foo") - .setCharset(/* utf-16 UnicodeBig */35) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(/* remapped by TEXT special case */Types.VARCHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("UTF-16", fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.VARBINARY, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - - conn = getVitessConnection(); - raw = raw.toBuilder() - .setType(Query.Type.JSON) - .setColumnLength(MysqlDefs.LENGTH_LONGBLOB) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .build(); - - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.CHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals("UTF-8", fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.CHAR, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - - conn = getVitessConnection(); - raw = raw.toBuilder() - .setType(Query.Type.BIT) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - Assert.assertEquals("ISO-8859-1", fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - - conn = getVitessConnection(); - raw = raw.toBuilder() - .setColumnLength(1) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - Assert.assertEquals("ISO-8859-1", fieldWithMetadata.getEncoding()); - Assert.assertEquals(true, fieldWithMetadata.isSingleBit()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(Types.BIT, fieldWithMetadata.getJavaType()); - Assert.assertEquals(null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(false, fieldWithMetadata.isSingleBit()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(type.name(), null, fieldWithMetadata.getEncoding()); + Assert.assertEquals(type.name(), false, fieldWithMetadata.isSingleBit()); } - - @Test - public void testVarBinaryToVarCharRemapping() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.VARBINARY) - .setName("foo") - .setOrgName("foo") - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals("no remapping - base case", Types.VARBINARY, fieldWithMetadata.getJavaType()); - - raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals("remap to varchar due to non-binary encoding", Types.VARCHAR, fieldWithMetadata.getJavaType()); + } + + @Test + public void testPrecisionAdjustFactor() throws SQLException { + VitessConnection conn = getVitessConnection(); + assertPrecisionEquals(conn, Query.Type.FLOAT32, true, 0, 0); + assertPrecisionEquals(conn, Query.Type.FLOAT64, true, 32, 0); + assertPrecisionEquals(conn, Query.Type.BIT, true, 0, 0); + assertPrecisionEquals(conn, Query.Type.DECIMAL, true, 0, -1); + assertPrecisionEquals(conn, Query.Type.DECIMAL, true, 3, -2); + assertPrecisionEquals(conn, Query.Type.INT32, true, /* this can't happen, but just checking */3, + -2); + assertPrecisionEquals(conn, Query.Type.INT32, true, 0, -1); + assertPrecisionEquals(conn, Query.Type.FLOAT32, false, 0, 0); + assertPrecisionEquals(conn, Query.Type.FLOAT64, false, 32, 0); + assertPrecisionEquals(conn, Query.Type.BIT, false, 0, 0); + assertPrecisionEquals(conn, Query.Type.DECIMAL, false, 0, -1); + assertPrecisionEquals(conn, Query.Type.DECIMAL, false, 3, -1); + assertPrecisionEquals(conn, Query.Type.UINT32, false, 0, 0); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (Query.Type type : Query.Type.values()) { + if (type == Query.Type.UNRECOGNIZED || type == Query.Type.EXPRESSION) { + continue; + } + + // All should be 0 + assertPrecisionEquals(conn, type, true, 0, 0); + assertPrecisionEquals(conn, type, false, 0, 0); + assertPrecisionEquals(conn, type, true, 2, 0); + assertPrecisionEquals(conn, type, false, 2, 0); } - - @Test - public void testBinaryToCharRemapping() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.BINARY) - .setName("foo") - .setOrgName("foo") - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals("no remapping - base case", Types.BINARY, fieldWithMetadata.getJavaType()); - - raw = raw.toBuilder().setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals("remap to char due to non-binary encoding", Types.CHAR, fieldWithMetadata.getJavaType()); + } + + private void assertPrecisionEquals(VitessConnection conn, Query.Type fieldType, boolean signed, + int decimals, int expectedPrecisionAdjustFactor) throws SQLException { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3).setType(fieldType) + .setDecimals(decimals).setFlags(signed ? 0 : Query.MySqlFlag.UNSIGNED_FLAG_VALUE) + .setName("foo").setOrgName("foo").build(); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert + .assertEquals(expectedPrecisionAdjustFactor, fieldWithMetadata.getPrecisionAdjustFactor()); + } + + @Test + public void testFlags() throws SQLException { + VitessConnection conn = getVitessConnection(); + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.VARBINARY).setName("foo").setOrgName("foo").build(); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isAutoIncrement()); + Assert.assertEquals(false, fieldWithMetadata.isMultipleKey()); + Assert.assertEquals(false, fieldWithMetadata.isNotNull()); + Assert.assertEquals(false, fieldWithMetadata.isPrimaryKey()); + Assert.assertEquals(false, fieldWithMetadata.isUniqueKey()); + Assert.assertEquals(false, fieldWithMetadata.isUnsigned()); + Assert.assertEquals(/* just inverses isUnsigned */true, fieldWithMetadata.isSigned()); + Assert.assertEquals(false, fieldWithMetadata.isZeroFill()); + + int value = 0; + for (Query.MySqlFlag flag : Query.MySqlFlag.values()) { + if (flag == Query.MySqlFlag.UNRECOGNIZED) { + continue; + } + value |= flag.getNumber(); } - - @Test - public void testNumericAndDateTimeEncoding() throws SQLException{ - VitessConnection conn = getVitessConnection(); - - Query.Type[] types = new Query.Type[]{ - Query.Type.INT8, - Query.Type.UINT8, - Query.Type.INT16, - Query.Type.UINT16, - Query.Type.INT24, - Query.Type.UINT24, - Query.Type.INT32, - Query.Type.UINT32, - Query.Type.INT64, - Query.Type.UINT64, - Query.Type.DECIMAL, - Query.Type.UINT24, - Query.Type.INT32, - Query.Type.UINT32, - Query.Type.FLOAT32, - Query.Type.FLOAT64, - Query.Type.DATE, - Query.Type.DATETIME, - Query.Type.TIME, - Query.Type.TIMESTAMP, - Query.Type.YEAR - }; - - - for (Query.Type type : types) { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(type) - .setName("foo") - .setOrgName("foo") - .setCharset(/* utf-16 UnicodeBig */35) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(type.name(),"US-ASCII", fieldWithMetadata.getEncoding()); - Assert.assertEquals(type.name(),false, fieldWithMetadata.isSingleBit()); - } - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - - for (Query.Type type : types) { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(type) - .setName("foo") - .setOrgName("foo") - .setCharset(/* utf-16 UnicodeBig */35) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(type.name(),null, fieldWithMetadata.getEncoding()); - Assert.assertEquals(type.name(),false, fieldWithMetadata.isSingleBit()); - } - } - - @Test - public void testPrecisionAdjustFactor() throws SQLException { - VitessConnection conn = getVitessConnection(); - assertPrecisionEquals(conn, Query.Type.FLOAT32, true, 0, 0); - assertPrecisionEquals(conn, Query.Type.FLOAT64, true, 32, 0); - assertPrecisionEquals(conn, Query.Type.BIT, true, 0, 0); - assertPrecisionEquals(conn, Query.Type.DECIMAL, true, 0, -1); - assertPrecisionEquals(conn, Query.Type.DECIMAL, true, 3, -2); - assertPrecisionEquals(conn, Query.Type.INT32, true, /* this can't happen, but just checking */3, -2); - assertPrecisionEquals(conn, Query.Type.INT32, true, 0, -1); - assertPrecisionEquals(conn, Query.Type.FLOAT32, false, 0, 0); - assertPrecisionEquals(conn, Query.Type.FLOAT64, false, 32, 0); - assertPrecisionEquals(conn, Query.Type.BIT, false, 0, 0); - assertPrecisionEquals(conn, Query.Type.DECIMAL, false, 0, -1); - assertPrecisionEquals(conn, Query.Type.DECIMAL, false, 3, -1); - assertPrecisionEquals(conn, Query.Type.UINT32, false, 0, 0); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (Query.Type type : Query.Type.values()) { - if (type == Query.Type.UNRECOGNIZED || type == Query.Type.EXPRESSION) { - continue; - } - - // All should be 0 - assertPrecisionEquals(conn, type, true, 0, 0); - assertPrecisionEquals(conn, type, false, 0, 0); - assertPrecisionEquals(conn, type, true, 2, 0); - assertPrecisionEquals(conn, type, false, 2, 0); - } - } - - private void assertPrecisionEquals(VitessConnection conn, Query.Type fieldType, boolean signed, int decimals, int expectedPrecisionAdjustFactor) throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(fieldType) - .setDecimals(decimals) - .setFlags(signed ? 0 : Query.MySqlFlag.UNSIGNED_FLAG_VALUE) - .setName("foo") - .setOrgName("foo") - .build(); - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(expectedPrecisionAdjustFactor, fieldWithMetadata.getPrecisionAdjustFactor()); - } - - @Test - public void testFlags() throws SQLException { - VitessConnection conn = getVitessConnection(); - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.VARBINARY) - .setName("foo") - .setOrgName("foo") - .build(); - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isAutoIncrement()); - Assert.assertEquals(false, fieldWithMetadata.isMultipleKey()); - Assert.assertEquals(false, fieldWithMetadata.isNotNull()); - Assert.assertEquals(false, fieldWithMetadata.isPrimaryKey()); - Assert.assertEquals(false, fieldWithMetadata.isUniqueKey()); - Assert.assertEquals(false, fieldWithMetadata.isUnsigned()); - Assert.assertEquals(/* just inverses isUnsigned */true, fieldWithMetadata.isSigned()); - Assert.assertEquals(false, fieldWithMetadata.isZeroFill()); - - int value = 0; - for (Query.MySqlFlag flag : Query.MySqlFlag.values()) { - if (flag == Query.MySqlFlag.UNRECOGNIZED) { - continue; - } - value |= flag.getNumber(); - } - raw = raw.toBuilder() - .setFlags(value) - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isBinary()); - Assert.assertEquals(true, fieldWithMetadata.isBlob()); - Assert.assertEquals(true, fieldWithMetadata.isAutoIncrement()); - Assert.assertEquals(true, fieldWithMetadata.isMultipleKey()); - Assert.assertEquals(true, fieldWithMetadata.isNotNull()); - Assert.assertEquals(true, fieldWithMetadata.isPrimaryKey()); - Assert.assertEquals(true, fieldWithMetadata.isUniqueKey()); - Assert.assertEquals(true, fieldWithMetadata.isUnsigned()); - Assert.assertEquals(/* just inverses isUnsigned */false, fieldWithMetadata.isSigned()); - Assert.assertEquals(true, fieldWithMetadata.isZeroFill()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isBinary()); - Assert.assertEquals(false, fieldWithMetadata.isBlob()); - Assert.assertEquals(false, fieldWithMetadata.isAutoIncrement()); - Assert.assertEquals(false, fieldWithMetadata.isMultipleKey()); - Assert.assertEquals(true, fieldWithMetadata.isNotNull()); - Assert.assertEquals(false, fieldWithMetadata.isPrimaryKey()); - Assert.assertEquals(false, fieldWithMetadata.isUniqueKey()); - Assert.assertEquals(true, fieldWithMetadata.isUnsigned()); - Assert.assertEquals(/* just inverses isUnsigned */false, fieldWithMetadata.isSigned()); - Assert.assertEquals(false, fieldWithMetadata.isZeroFill()); - - } - - @Test - public void testOpaqueBinary() throws SQLException { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setColumnLength(3) - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .build(); - - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isOpaqueBinary()); - - raw = raw.toBuilder() - .setTable("#sql_foo_bar") - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); - - raw = raw.toBuilder() - .setCharset(/* short circuits collation -> encoding lookup, resulting in null */-1) - .build(); - - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); - - conn.setEncoding("binary"); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isOpaqueBinary()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); - } - - @Test - public void testReadOnly() throws SQLException { - VitessConnection conn = getVitessConnection(); - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setOrgTable("foo") - .build(); - FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isReadOnly()); - - raw = raw.toBuilder() - .setOrgName("") - .setOrgTable("foo") - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); - - raw = raw.toBuilder() - .setOrgName("foo") - .setOrgTable("") - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); - - raw = raw.toBuilder() - .setOrgTable("") - .setOrgName("") - .build(); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = new FieldWithMetadata(conn, raw); - Assert.assertEquals(false, fieldWithMetadata.isReadOnly()); + raw = raw.toBuilder().setFlags(value).build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isBinary()); + Assert.assertEquals(true, fieldWithMetadata.isBlob()); + Assert.assertEquals(true, fieldWithMetadata.isAutoIncrement()); + Assert.assertEquals(true, fieldWithMetadata.isMultipleKey()); + Assert.assertEquals(true, fieldWithMetadata.isNotNull()); + Assert.assertEquals(true, fieldWithMetadata.isPrimaryKey()); + Assert.assertEquals(true, fieldWithMetadata.isUniqueKey()); + Assert.assertEquals(true, fieldWithMetadata.isUnsigned()); + Assert.assertEquals(/* just inverses isUnsigned */false, fieldWithMetadata.isSigned()); + Assert.assertEquals(true, fieldWithMetadata.isZeroFill()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isBinary()); + Assert.assertEquals(false, fieldWithMetadata.isBlob()); + Assert.assertEquals(false, fieldWithMetadata.isAutoIncrement()); + Assert.assertEquals(false, fieldWithMetadata.isMultipleKey()); + Assert.assertEquals(true, fieldWithMetadata.isNotNull()); + Assert.assertEquals(false, fieldWithMetadata.isPrimaryKey()); + Assert.assertEquals(false, fieldWithMetadata.isUniqueKey()); + Assert.assertEquals(true, fieldWithMetadata.isUnsigned()); + Assert.assertEquals(/* just inverses isUnsigned */false, fieldWithMetadata.isSigned()); + Assert.assertEquals(false, fieldWithMetadata.isZeroFill()); + + } + + @Test + public void testOpaqueBinary() throws SQLException { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setColumnLength(3) + .setType(Query.Type.CHAR).setName("foo").setOrgName("foo") + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build(); + + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isOpaqueBinary()); + + raw = raw.toBuilder().setTable("#sql_foo_bar").build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + + raw = raw.toBuilder() + .setCharset(/* short circuits collation -> encoding lookup, resulting in null */-1).build(); + + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + + conn.setEncoding("binary"); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isOpaqueBinary()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isOpaqueBinary()); + } + + @Test + public void testReadOnly() throws SQLException { + VitessConnection conn = getVitessConnection(); + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setOrgTable("foo").build(); + FieldWithMetadata fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isReadOnly()); + + raw = raw.toBuilder().setOrgName("").setOrgTable("foo").build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); + + raw = raw.toBuilder().setOrgName("foo").setOrgTable("").build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); + + raw = raw.toBuilder().setOrgTable("").setOrgName("").build(); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(true, fieldWithMetadata.isReadOnly()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = new FieldWithMetadata(conn, raw); + Assert.assertEquals(false, fieldWithMetadata.isReadOnly()); + } + + @Test + public void testDefaultsWithoutAllFields() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setName("foo").setOrgName("foo").setTable("foo") + .setOrgTable("foo").setDatabase("foo").setType(Query.Type.CHAR).setFlags( + Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE | Query.MySqlFlag.PRI_KEY_FLAG_VALUE + | Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE | Query.MySqlFlag.BINARY_FLAG_VALUE + | Query.MySqlFlag.BLOB_FLAG_VALUE | Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE + | Query.MySqlFlag.UNSIGNED_FLAG_VALUE | Query.MySqlFlag.ZEROFILL_FLAG_VALUE) + .build(); + VitessConnection conn = getVitessConnection(); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + FieldWithMetadata field = new FieldWithMetadata(conn, raw); + Assert.assertEquals("foo", field.getName()); + Assert.assertEquals(null, field.getOrgName()); + Assert.assertEquals(null, field.getTable()); + Assert.assertEquals(null, field.getOrgTable()); + Assert.assertEquals(null, field.getDatabase()); + Assert.assertEquals(0, field.getDecimals()); + Assert.assertEquals(0, field.getColumnLength()); + Assert.assertEquals(0, field.getPrecisionAdjustFactor()); + Assert.assertEquals(false, field.isSingleBit()); + Assert.assertEquals(false, field.isAutoIncrement()); + Assert.assertEquals(false, field.isBinary()); + Assert.assertEquals(false, field.isBlob()); + Assert.assertEquals(false, field.isMultipleKey()); + Assert.assertEquals(true, field.isNotNull()); + Assert.assertEquals(false, field.isZeroFill()); + Assert.assertEquals(false, field.isPrimaryKey()); + Assert.assertEquals(false, field.isUniqueKey()); + Assert.assertEquals(true, field.isUnsigned()); + Assert.assertEquals(false, field.isSigned()); + Assert.assertEquals(false, field.isOpaqueBinary()); + Assert.assertEquals(false, field.isReadOnly()); + } + + @Test + public void testToString() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setName("foo").setOrgName("foo").setTable("foo") + .setOrgTable("foo").setDatabase("foo").setType(Query.Type.CHAR).setFlags( + Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE | Query.MySqlFlag.PRI_KEY_FLAG_VALUE + | Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE | Query.MySqlFlag.BINARY_FLAG_VALUE + | Query.MySqlFlag.BLOB_FLAG_VALUE | Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE + | Query.MySqlFlag.UNSIGNED_FLAG_VALUE | Query.MySqlFlag.ZEROFILL_FLAG_VALUE) + .build(); + FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); + String result = + "io.vitess.jdbc.FieldWithMetadata[catalog=foo," + "tableName=foo,originalTableName=foo," + + "columnName=foo,originalColumnName=foo," + "vitessType=" + Query.Type.CHAR.toString() + + "(1)," + "flags=AUTO_INCREMENT PRIMARY_KEY UNIQUE_KEY BINARY " + + "BLOB MULTI_KEY UNSIGNED ZEROFILL, charsetIndex=0, charsetName=null]"; + Assert.assertEquals(result, field.toString()); + } + + public void testCollations() throws Exception { + VitessConnection conn = getVitessConnection(); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setCharset(33).build(); + + FieldWithMetadata fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + String first = fieldWithMetadata.getCollation(); + String second = fieldWithMetadata.getCollation(); + + Assert.assertEquals("utf8_general_ci", first); + Assert.assertEquals("cached response is same as first", first, second); + + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)) + .invoke("getCollationIndex"); + + try { + raw = raw.toBuilder() + // value chosen because it's obviously out of bounds for the underlying array + .setCharset(Integer.MAX_VALUE).build(); + + fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + fieldWithMetadata.getCollation(); + Assert.fail("Should have received an array index out of bounds because " + + "charset/collationIndex of Int.MAX is well above size of charset array"); + } catch (SQLException e) { + if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { + Assert.assertEquals("CollationIndex '" + Integer.MAX_VALUE + "' out of bounds for " + + "collationName lookup, should be within 0 and " + + CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length, e.getMessage()); + } else { + // just rethrow so we fail that way + throw e; + } } - @Test - public void testDefaultsWithoutAllFields() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setName("foo") - .setOrgName("foo") - .setTable("foo") - .setOrgTable("foo") - .setDatabase("foo") - .setType(Query.Type.CHAR) - .setFlags(Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE | - Query.MySqlFlag.PRI_KEY_FLAG_VALUE | - Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE | - Query.MySqlFlag.BINARY_FLAG_VALUE | - Query.MySqlFlag.BLOB_FLAG_VALUE | - Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE | - Query.MySqlFlag.UNSIGNED_FLAG_VALUE | - Query.MySqlFlag.ZEROFILL_FLAG_VALUE - ) - .build(); - VitessConnection conn = getVitessConnection(); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - FieldWithMetadata field = new FieldWithMetadata(conn, raw); - Assert.assertEquals("foo", field.getName()); - Assert.assertEquals(null, field.getOrgName()); - Assert.assertEquals(null, field.getTable()); - Assert.assertEquals(null, field.getOrgTable()); - Assert.assertEquals(null, field.getDatabase()); - Assert.assertEquals(0, field.getDecimals()); - Assert.assertEquals(0, field.getColumnLength()); - Assert.assertEquals(0, field.getPrecisionAdjustFactor()); - Assert.assertEquals(false, field.isSingleBit()); - Assert.assertEquals(false, field.isAutoIncrement()); - Assert.assertEquals(false, field.isBinary()); - Assert.assertEquals(false, field.isBlob()); - Assert.assertEquals(false, field.isMultipleKey()); - Assert.assertEquals(true, field.isNotNull()); - Assert.assertEquals(false, field.isZeroFill()); - Assert.assertEquals(false, field.isPrimaryKey()); - Assert.assertEquals(false, field.isUniqueKey()); - Assert.assertEquals(true, field.isUnsigned()); - Assert.assertEquals(false, field.isSigned()); - Assert.assertEquals(false, field.isOpaqueBinary()); - Assert.assertEquals(false, field.isReadOnly()); - } - - @Test - public void testToString() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setName("foo") - .setOrgName("foo") - .setTable("foo") - .setOrgTable("foo") - .setDatabase("foo") - .setType(Query.Type.CHAR) - .setFlags(Query.MySqlFlag.AUTO_INCREMENT_FLAG_VALUE | - Query.MySqlFlag.PRI_KEY_FLAG_VALUE | - Query.MySqlFlag.UNIQUE_KEY_FLAG_VALUE | - Query.MySqlFlag.BINARY_FLAG_VALUE | - Query.MySqlFlag.BLOB_FLAG_VALUE | - Query.MySqlFlag.MULTIPLE_KEY_FLAG_VALUE | - Query.MySqlFlag.UNSIGNED_FLAG_VALUE | - Query.MySqlFlag.ZEROFILL_FLAG_VALUE - ) - .build(); - FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); - String result = "io.vitess.jdbc.FieldWithMetadata[catalog=foo," + - "tableName=foo,originalTableName=foo," + - "columnName=foo,originalColumnName=foo," + - "vitessType=" + Query.Type.CHAR.toString() + "(1)," + - "flags=AUTO_INCREMENT PRIMARY_KEY UNIQUE_KEY BINARY " + - "BLOB MULTI_KEY UNSIGNED ZEROFILL, charsetIndex=0, charsetName=null]"; - Assert.assertEquals(result, field.toString()); - } - - public void testCollations() throws Exception { - VitessConnection conn = getVitessConnection(); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(33) - .build(); - - FieldWithMetadata fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - String first = fieldWithMetadata.getCollation(); - String second = fieldWithMetadata.getCollation(); - - Assert.assertEquals("utf8_general_ci", first); - Assert.assertEquals("cached response is same as first", first, second); - - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)).invoke("getCollationIndex"); - - try { - raw = raw.toBuilder() - // value chosen because it's obviously out of bounds for the underlying array - .setCharset(Integer.MAX_VALUE) - .build(); - - fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - fieldWithMetadata.getCollation(); - Assert.fail("Should have received an array index out of bounds because " + - "charset/collationIndex of Int.MAX is well above size of charset array"); - } catch (SQLException e) { - if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { - Assert.assertEquals("CollationIndex '" + Integer.MAX_VALUE + "' out of bounds for " + - "collationName lookup, should be within 0 and " + - CharsetMapping.COLLATION_INDEX_TO_COLLATION_NAME.length, - e.getMessage()); - } else { - // just rethrow so we fail that way - throw e; - } - } - - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)).invoke("getCollationIndex"); - //Mockito.verify(fieldWithMetadata, Mockito.times(1)).getCollationIndex(); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - Assert.assertEquals("null response when not including all fields", null, fieldWithMetadata.getCollation()); - - // We should not call this at all, because we're short circuiting due to included fields - //Mockito.verify(fieldWithMetadata, Mockito.never()).getCollationIndex(); - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(0)).invoke("getCollationIndex"); - } - - @Test - public void testMaxBytesPerChar() throws Exception { - VitessConnection conn = PowerMockito.spy(getVitessConnection()); - - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(33) - .build(); - - FieldWithMetadata fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - - int first = fieldWithMetadata.getMaxBytesPerCharacter(); - int second = fieldWithMetadata.getMaxBytesPerCharacter(); - - Assert.assertEquals("cached response is same as first", first, second); - // We called getMaxBytesPerCharacter 2 times above, but should only have made 1 call to fieldWithMetadata.getMaxBytesPerChar: - // first - call conn - // second - return cached - Mockito.verify(fieldWithMetadata, VerificationModeFactory.times(1)).getMaxBytesPerChar(33, "UTF-8"); - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)).invoke("getCollationIndex"); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); - Assert.assertEquals("0 return value when not including all fields", 0, fieldWithMetadata.getMaxBytesPerCharacter()); - - // We should not call this function because we short circuited due to not including all fields. - Mockito.verify(fieldWithMetadata, VerificationModeFactory.times(0)).getMaxBytesPerChar(33, "UTF-8"); - // Should not be called at all, because it's new for just this test - PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(0)).invoke("getCollationIndex"); - } - - @Test public void testGetEncodingForIndex() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(33) - .build(); - FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); - - // No default encoding configured, and passing NO_CHARSET_INFO basically says "mysql doesn't know" - // which means don't try looking it up - Assert.assertEquals(null, field.getEncodingForIndex(MysqlDefs.NO_CHARSET_INFO)); - // Similarly, a null index or one landing out of bounds for the charset index should return null - Assert.assertEquals(null, field.getEncodingForIndex(Integer.MAX_VALUE)); - Assert.assertEquals(null, field.getEncodingForIndex(-123)); - - // charsetIndex 25 is MYSQL_CHARSET_NAME_greek, which is a charset with multiple names, ISO8859_7 and greek - // Without an encoding configured in the connection, we should return the first (default) encoding for a charset, - // in this case ISO8859_7 - Assert.assertEquals("ISO-8859-7", field.getEncodingForIndex(25)); - field.getConnectionProperties().setEncoding("greek"); - // With an encoding configured, we should return that because it matches one of the names for the charset - Assert.assertEquals("greek", field.getEncodingForIndex(25)); - - field.getConnectionProperties().setEncoding(null); - Assert.assertEquals("UTF-8", field.getEncodingForIndex(CharsetMapping.MYSQL_COLLATION_INDEX_utf8)); - Assert.assertEquals("ISO-8859-1", field.getEncodingForIndex(CharsetMapping.MYSQL_COLLATION_INDEX_binary)); - - field.getConnectionProperties().setEncoding("NOT_REAL"); - // Same tests as the first one, but testing that when there is a default configured, it falls back to that regardless - Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(MysqlDefs.NO_CHARSET_INFO)); - Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(Integer.MAX_VALUE)); - Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(-123)); - } - - @Test public void testGetMaxBytesPerChar() throws SQLException { - Query.Field raw = Query.Field.newBuilder() - .setTable("foo") - .setType(Query.Type.CHAR) - .setName("foo") - .setOrgName("foo") - .setCharset(33) - .build(); - FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); - - // Default state when no good info is passed in - Assert.assertEquals(0, field.getMaxBytesPerChar(MysqlDefs.NO_CHARSET_INFO, null)); - // use passed collation index - Assert.assertEquals(3, field.getMaxBytesPerChar(CharsetMapping.MYSQL_COLLATION_INDEX_utf8, null)); - // use first, if both are passed and valid - Assert.assertEquals(3, field.getMaxBytesPerChar(CharsetMapping.MYSQL_COLLATION_INDEX_utf8, "UnicodeBig")); - // use passed default charset - Assert.assertEquals(2, field.getMaxBytesPerChar(MysqlDefs.NO_CHARSET_INFO, "UnicodeBig")); - } + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)) + .invoke("getCollationIndex"); + //Mockito.verify(fieldWithMetadata, Mockito.times(1)).getCollationIndex(); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + Assert.assertEquals("null response when not including all fields", null, + fieldWithMetadata.getCollation()); + + // We should not call this at all, because we're short circuiting due to included fields + //Mockito.verify(fieldWithMetadata, Mockito.never()).getCollationIndex(); + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(0)) + .invoke("getCollationIndex"); + } + + @Test + public void testMaxBytesPerChar() throws Exception { + VitessConnection conn = PowerMockito.spy(getVitessConnection()); + + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setCharset(33).build(); + + FieldWithMetadata fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + + int first = fieldWithMetadata.getMaxBytesPerCharacter(); + int second = fieldWithMetadata.getMaxBytesPerCharacter(); + + Assert.assertEquals("cached response is same as first", first, second); + // We called getMaxBytesPerCharacter 2 times above, but should only have made 1 call to + // fieldWithMetadata.getMaxBytesPerChar: + // first - call conn + // second - return cached + Mockito.verify(fieldWithMetadata, VerificationModeFactory.times(1)) + .getMaxBytesPerChar(33, "UTF-8"); + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(1)) + .invoke("getCollationIndex"); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + fieldWithMetadata = PowerMockito.spy(new FieldWithMetadata(conn, raw)); + Assert.assertEquals("0 return value when not including all fields", 0, + fieldWithMetadata.getMaxBytesPerCharacter()); + + // We should not call this function because we short circuited due to not including all fields. + Mockito.verify(fieldWithMetadata, VerificationModeFactory.times(0)) + .getMaxBytesPerChar(33, "UTF-8"); + // Should not be called at all, because it's new for just this test + PowerMockito.verifyPrivate(fieldWithMetadata, VerificationModeFactory.times(0)) + .invoke("getCollationIndex"); + } + + @Test + public void testGetEncodingForIndex() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setCharset(33).build(); + FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); + + // No default encoding configured, and passing NO_CHARSET_INFO basically says "mysql doesn't + // know" + // which means don't try looking it up + Assert.assertEquals(null, field.getEncodingForIndex(MysqlDefs.NO_CHARSET_INFO)); + // Similarly, a null index or one landing out of bounds for the charset index should return null + Assert.assertEquals(null, field.getEncodingForIndex(Integer.MAX_VALUE)); + Assert.assertEquals(null, field.getEncodingForIndex(-123)); + + // charsetIndex 25 is MYSQL_CHARSET_NAME_greek, which is a charset with multiple names, + // ISO8859_7 and greek + // Without an encoding configured in the connection, we should return the first (default) + // encoding for a charset, + // in this case ISO8859_7 + Assert.assertEquals("ISO-8859-7", field.getEncodingForIndex(25)); + field.getConnectionProperties().setEncoding("greek"); + // With an encoding configured, we should return that because it matches one of the names for + // the charset + Assert.assertEquals("greek", field.getEncodingForIndex(25)); + + field.getConnectionProperties().setEncoding(null); + Assert.assertEquals("UTF-8", + field.getEncodingForIndex(CharsetMapping.MYSQL_COLLATION_INDEX_utf8)); + Assert.assertEquals("ISO-8859-1", + field.getEncodingForIndex(CharsetMapping.MYSQL_COLLATION_INDEX_binary)); + + field.getConnectionProperties().setEncoding("NOT_REAL"); + // Same tests as the first one, but testing that when there is a default configured, it falls + // back to that regardless + Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(MysqlDefs.NO_CHARSET_INFO)); + Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(Integer.MAX_VALUE)); + Assert.assertEquals("NOT_REAL", field.getEncodingForIndex(-123)); + } + + @Test + public void testGetMaxBytesPerChar() throws SQLException { + Query.Field raw = Query.Field.newBuilder().setTable("foo").setType(Query.Type.CHAR) + .setName("foo").setOrgName("foo").setCharset(33).build(); + FieldWithMetadata field = new FieldWithMetadata(getVitessConnection(), raw); + + // Default state when no good info is passed in + Assert.assertEquals(0, field.getMaxBytesPerChar(MysqlDefs.NO_CHARSET_INFO, null)); + // use passed collation index + Assert + .assertEquals(3, field.getMaxBytesPerChar(CharsetMapping.MYSQL_COLLATION_INDEX_utf8, null)); + // use first, if both are passed and valid + Assert.assertEquals(3, + field.getMaxBytesPerChar(CharsetMapping.MYSQL_COLLATION_INDEX_utf8, "UnicodeBig")); + // use passed default charset + Assert.assertEquals(2, field.getMaxBytesPerChar(MysqlDefs.NO_CHARSET_INFO, "UnicodeBig")); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessConnectionTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessConnectionTest.java index 64df7a23a58..73d312521ff 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessConnectionTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessConnectionTest.java @@ -16,11 +16,15 @@ package io.vitess.jdbc; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.modules.junit4.PowerMockRunner; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import io.vitess.client.VTSession; import io.vitess.proto.Query; @@ -35,15 +39,11 @@ import java.sql.Statement; import java.util.Properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.modules.junit4.PowerMockRunner; /** * Created by harshit.gangal on 19/01/16. @@ -51,220 +51,228 @@ @RunWith(PowerMockRunner.class) public class VitessConnectionTest extends BaseTest { - @Test - public void testVitessConnection() throws SQLException { - VitessConnection vitessConnection = new VitessConnection(dbURL, new Properties()); - assertFalse(vitessConnection.isClosed()); - assertNull(vitessConnection.getDbProperties()); - } - - @Test - public void testCreateStatement() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - Statement statement = vitessConnection.createStatement(); - assertEquals(vitessConnection, statement.getConnection()); - } - - @Test - public void testCreateStatementForClose() - throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertFailsOnClosedConnection(vitessConnection, vitessConnection::createStatement); - } - - @Test - public void testnativeSQL() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertEquals("query", vitessConnection.nativeSQL("query")); - } - - @Test - public void testCreatePreperedStatement() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - PreparedStatement preparedStatementstatement = vitessConnection.prepareStatement("query"); - assertEquals(vitessConnection, preparedStatementstatement.getConnection()); - } - - @Test - public void testCreatePreparedStatementForClose() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertFailsOnClosedConnection(vitessConnection, () -> vitessConnection.prepareStatement("query")); - } - - @Test - public void testDefaultGetAutoCommit() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertTrue(vitessConnection.getAutoCommit()); - } - - @Test - public void testDefaultGetAutoCommitForClose() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertFailsOnClosedConnection(vitessConnection, vitessConnection::getAutoCommit); + @Test + public void testVitessConnection() throws SQLException { + VitessConnection vitessConnection = new VitessConnection(dbURL, new Properties()); + assertFalse(vitessConnection.isClosed()); + assertNull(vitessConnection.getDbProperties()); + } + + @Test + public void testCreateStatement() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + Statement statement = vitessConnection.createStatement(); + assertEquals(vitessConnection, statement.getConnection()); + } + + @Test + public void testCreateStatementForClose() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertFailsOnClosedConnection(vitessConnection, vitessConnection::createStatement); + } + + @Test + public void testnativeSQL() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertEquals("query", vitessConnection.nativeSQL("query")); + } + + @Test + public void testCreatePreperedStatement() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + PreparedStatement preparedStatementstatement = vitessConnection.prepareStatement("query"); + assertEquals(vitessConnection, preparedStatementstatement.getConnection()); + } + + @Test + public void testCreatePreparedStatementForClose() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertFailsOnClosedConnection(vitessConnection, + () -> vitessConnection.prepareStatement("query")); + } + + @Test + public void testDefaultGetAutoCommit() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertTrue(vitessConnection.getAutoCommit()); + } + + @Test + public void testDefaultGetAutoCommitForClose() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertFailsOnClosedConnection(vitessConnection, vitessConnection::getAutoCommit); + } + + @Test + public void testDefaultSetAutoCommit() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(false); + assertFalse(vitessConnection.getAutoCommit()); + } + + @Test + public void testDefaultSetAutoCommitForClose() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertFailsOnClosedConnection(vitessConnection, () -> vitessConnection.setAutoCommit(false)); + } + + @Test + public void testCommit() throws Exception { + VTSession mockSession = PowerMockito.mock(VTSession.class); + VitessConnection vitessConnection = getVitessConnection(); + Field privateVTSessionField = VitessConnection.class.getDeclaredField("vtSession"); + privateVTSessionField.setAccessible(true); + privateVTSessionField.set(vitessConnection, mockSession); + PowerMockito.when(mockSession.isInTransaction()).thenReturn(false); + PowerMockito.when(mockSession.isAutoCommit()).thenReturn(false); + vitessConnection.commit(); + } + + @Test(expected = SQLException.class) + public void testCommitForException() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(true); + vitessConnection.commit(); + } + + @Test + public void testRollback() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(false); + vitessConnection.rollback(); + } + + @Test(expected = SQLException.class) + public void testRollbackForException() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(true); + vitessConnection.rollback(); + } + + @Test + public void testClosed() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setAutoCommit(false); + vitessConnection.close(); + assertTrue(vitessConnection.isClosed()); + } + + @Test(expected = SQLException.class) + public void testClosedForException() throws Exception { + VTSession mockSession = PowerMockito.mock(VTSession.class); + VitessConnection vitessConnection = getVitessConnection(); + Field privateVTSessionField = VitessConnection.class.getDeclaredField("vtSession"); + privateVTSessionField.setAccessible(true); + privateVTSessionField.set(vitessConnection, mockSession); + PowerMockito.when(mockSession.isInTransaction()).thenReturn(true); + PowerMockito.when(mockSession.isAutoCommit()).thenReturn(true); + vitessConnection.close(); + } + + @Test + public void testGetCatalog() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + assertEquals("keyspace", vitessConnection.getCatalog()); + } + + @Test + public void testSetCatalog() throws SQLException { + VitessConnection vitessConnection = getVitessConnection(); + vitessConnection.setCatalog("myDB"); + assertEquals("myDB", vitessConnection.getCatalog()); + } + + @Test + public void testPropertiesFromJdbcUrl() throws SQLException { + String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica" + + "&includedFields=type_and_name&blobsAreStrings=yes"; + VitessConnection conn = new VitessConnection(url, new Properties()); + + // Properties from the url should be passed into the connection properties, and override + // whatever defaults we've defined + assertEquals(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME, conn.getIncludedFields()); + assertFalse(conn.isIncludeAllFields()); + assertEquals(Topodata.TabletType.REPLICA, conn.getTabletType()); + assertTrue(conn.getBlobsAreStrings()); + } + + @Test + public void testClientFoundRows() throws SQLException { + String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica" + + "&useAffectedRows=true"; + VitessConnection conn = new VitessConnection(url, new Properties()); + + assertTrue(conn.getUseAffectedRows()); + assertFalse(conn.getVtSession().getSession().getOptions().getClientFoundRows()); + } + + @Test + public void testClientFoundRows2() throws SQLException { + String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica" + + "&useAffectedRows=false"; + VitessConnection conn = new VitessConnection(url, new Properties()); + + assertFalse(conn.getUseAffectedRows()); + assertTrue(conn.getVtSession().getSession().getOptions().getClientFoundRows()); + } + + @Test + public void testWorkload() throws SQLException { + for (Query.ExecuteOptions.Workload workload : Query.ExecuteOptions.Workload.values()) { + if (workload == Query.ExecuteOptions.Workload.UNRECOGNIZED) { + continue; + } + String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&workload=" + + workload.toString().toLowerCase(); + VitessConnection conn = new VitessConnection(url, new Properties()); + + assertEquals(workload, conn.getWorkload()); + assertEquals(workload, conn.getVtSession().getSession().getOptions().getWorkload()); } - - @Test - public void testDefaultSetAutoCommit() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(false); - assertFalse(vitessConnection.getAutoCommit()); - } - - @Test - public void testDefaultSetAutoCommitForClose() - throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertFailsOnClosedConnection(vitessConnection, () -> vitessConnection.setAutoCommit(false)); - } - - @Test - public void testCommit() throws Exception { - VTSession mockSession = PowerMockito.mock(VTSession.class); - VitessConnection vitessConnection = getVitessConnection(); - Field privateVTSessionField = VitessConnection.class.getDeclaredField("vtSession"); - privateVTSessionField.setAccessible(true); - privateVTSessionField.set(vitessConnection, mockSession); - PowerMockito.when(mockSession.isInTransaction()).thenReturn(false); - PowerMockito.when(mockSession.isAutoCommit()).thenReturn(false); - vitessConnection.commit(); - } - - @Test(expected = SQLException.class) - public void testCommitForException() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(true); - vitessConnection.commit(); - } - - @Test - public void testRollback() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(false); - vitessConnection.rollback(); - } - - @Test(expected = SQLException.class) - public void testRollbackForException() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(true); - vitessConnection.rollback(); - } - - @Test - public void testClosed() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setAutoCommit(false); - vitessConnection.close(); - assertTrue(vitessConnection.isClosed()); - } - - @Test(expected = SQLException.class) - public void testClosedForException() throws Exception { - VTSession mockSession = PowerMockito.mock(VTSession.class); - VitessConnection vitessConnection = getVitessConnection(); - Field privateVTSessionField = VitessConnection.class.getDeclaredField("vtSession"); - privateVTSessionField.setAccessible(true); - privateVTSessionField.set(vitessConnection, mockSession); - PowerMockito.when(mockSession.isInTransaction()).thenReturn(true); - PowerMockito.when(mockSession.isAutoCommit()).thenReturn(true); - vitessConnection.close(); - } - - @Test - public void testGetCatalog() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - assertEquals("keyspace", vitessConnection.getCatalog()); - } - - @Test - public void testSetCatalog() throws SQLException { - VitessConnection vitessConnection = getVitessConnection(); - vitessConnection.setCatalog("myDB"); - assertEquals("myDB", vitessConnection.getCatalog()); - } - - @Test - public void testPropertiesFromJdbcUrl() throws SQLException { - String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&includedFields=type_and_name&blobsAreStrings=yes"; - VitessConnection conn = new VitessConnection(url, new Properties()); - - // Properties from the url should be passed into the connection properties, and override whatever defaults we've defined - assertEquals(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME, conn.getIncludedFields()); - assertFalse(conn.isIncludeAllFields()); - assertEquals(Topodata.TabletType.REPLICA, conn.getTabletType()); - assertTrue(conn.getBlobsAreStrings()); - } - - @Test - public void testClientFoundRows() throws SQLException { - String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&useAffectedRows=true"; - VitessConnection conn = new VitessConnection(url, new Properties()); - - assertTrue(conn.getUseAffectedRows()); - assertFalse(conn.getVtSession().getSession().getOptions().getClientFoundRows()); - } - - @Test - public void testClientFoundRows2() throws SQLException { - String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&useAffectedRows=false"; - VitessConnection conn = new VitessConnection(url, new Properties()); - - assertFalse(conn.getUseAffectedRows()); - assertTrue(conn.getVtSession().getSession().getOptions().getClientFoundRows()); - } - - @Test - public void testWorkload() throws SQLException { - for (Query.ExecuteOptions.Workload workload : Query.ExecuteOptions.Workload.values()) { - if (workload == Query.ExecuteOptions.Workload.UNRECOGNIZED) { - continue; - } - String url = "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?TABLET_TYPE=replica&workload=" + workload.toString().toLowerCase(); - VitessConnection conn = new VitessConnection(url, new Properties()); - - assertEquals(workload, conn.getWorkload()); - assertEquals(workload, conn.getVtSession().getSession().getOptions().getWorkload()); - } - } - - @Test - public void testTransactionIsolation() throws SQLException { - VitessConnection conn = Mockito.spy(getVitessConnection()); - doReturn(new DBProperties("random", "random", "random", Connection.TRANSACTION_REPEATABLE_READ, "random")) - .when(conn) - .getDbProperties(); - doReturn(new VitessMySQLDatabaseMetadata(conn)).when(conn).getMetaData(); - - assertEquals(TransactionIsolation.DEFAULT, conn.getVtSession().getSession().getOptions().getTransactionIsolation()); - assertEquals(Connection.TRANSACTION_REPEATABLE_READ, conn.getTransactionIsolation()); - - conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); - - assertEquals(TransactionIsolation.READ_COMMITTED, conn.getVtSession().getSession().getOptions().getTransactionIsolation()); - assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation()); - - VitessStatement statement = mock(VitessStatement.class); - when(conn.createStatement()).thenReturn(statement); - when(conn.isInTransaction()).thenReturn(true); - conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); - - verify(statement).executeUpdate("rollback"); - assertEquals(TransactionIsolation.READ_UNCOMMITTED, conn.getVtSession().getSession().getOptions().getTransactionIsolation()); - assertEquals(Connection.TRANSACTION_READ_UNCOMMITTED, conn.getTransactionIsolation()); - } - - interface Runthis { - void run() throws SQLException; - } - - private void assertFailsOnClosedConnection(VitessConnection connection, Runthis failingRunnable) throws SQLException { - connection.close(); - try { - failingRunnable.run(); - fail("expected this to fail on a closed connection"); - } catch (SQLException e) { - assertEquals(e.getMessage(), Constants.SQLExceptionMessages.CONN_CLOSED); - } + } + + @Test + public void testTransactionIsolation() throws SQLException { + VitessConnection conn = Mockito.spy(getVitessConnection()); + doReturn(new DBProperties("random", "random", "random", Connection.TRANSACTION_REPEATABLE_READ, + "random")).when(conn).getDbProperties(); + doReturn(new VitessMySQLDatabaseMetadata(conn)).when(conn).getMetaData(); + + assertEquals(TransactionIsolation.DEFAULT, + conn.getVtSession().getSession().getOptions().getTransactionIsolation()); + assertEquals(Connection.TRANSACTION_REPEATABLE_READ, conn.getTransactionIsolation()); + + conn.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED); + + assertEquals(TransactionIsolation.READ_COMMITTED, + conn.getVtSession().getSession().getOptions().getTransactionIsolation()); + assertEquals(Connection.TRANSACTION_READ_COMMITTED, conn.getTransactionIsolation()); + + VitessStatement statement = mock(VitessStatement.class); + when(conn.createStatement()).thenReturn(statement); + when(conn.isInTransaction()).thenReturn(true); + conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED); + + verify(statement).executeUpdate("rollback"); + assertEquals(TransactionIsolation.READ_UNCOMMITTED, + conn.getVtSession().getSession().getOptions().getTransactionIsolation()); + assertEquals(Connection.TRANSACTION_READ_UNCOMMITTED, conn.getTransactionIsolation()); + } + + interface Runthis { + + void run() throws SQLException; + } + + private void assertFailsOnClosedConnection(VitessConnection connection, Runthis failingRunnable) + throws SQLException { + connection.close(); + try { + failingRunnable.run(); + fail("expected this to fail on a closed connection"); + } catch (SQLException e) { + assertEquals(e.getMessage(), Constants.SQLExceptionMessages.CONN_CLOSED); } + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessDatabaseMetadataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessDatabaseMetadataTest.java index d930e08d3a7..9da77d6f039 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessDatabaseMetadataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessDatabaseMetadataTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -19,12 +19,6 @@ import com.google.common.base.Charsets; import com.google.common.io.CharStreams; import com.google.protobuf.ByteString; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import io.vitess.client.cursor.Cursor; import io.vitess.client.cursor.SimpleCursor; @@ -44,1082 +38,1181 @@ import java.util.Properties; import java.util.Scanner; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + /** * Created by ashudeep.sharma on 08/03/16. */ -@RunWith(PowerMockRunner.class) @PrepareForTest({VitessMySQLDatabaseMetadata.class, VitessConnection.class}) public class VitessDatabaseMetadataTest extends BaseTest { - - private ResultSet resultSet; - - @Test public void getPseudoColumnsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getPseudoColumns(null, null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TABLE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TABLE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("COLUMN_NAME", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("COLUMN_SIZE", resultSetMetaData.getColumnName(6)); - Assert.assertEquals("DECIMAL_DIGITS", resultSetMetaData.getColumnName(7)); - Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(8)); - Assert.assertEquals("COLUMN_USAGE", resultSetMetaData.getColumnName(9)); - Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(10)); - Assert.assertEquals("CHAR_OCTET_LENGTH", resultSetMetaData.getColumnName(11)); - Assert.assertEquals("IS_NULLABLE", resultSetMetaData.getColumnName(12)); - } - - @Test public void getClientInfoPropertiesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getClientInfoProperties(); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("NAME", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("MAX_LEN", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("DEFAULT_VALUE", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("DESCRIPTION", resultSetMetaData.getColumnName(4)); - } - - @Test public void getSchemasTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getSchemas(null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TABLE_CATALOG", resultSetMetaData.getColumnName(2)); - } - - @Test public void getAttributesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getAttributes(null, null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("ATTR_NAME", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("ATTR_TYPE_NAME", resultSetMetaData.getColumnName(6)); - Assert.assertEquals("ATTR_SIZE", resultSetMetaData.getColumnName(7)); - Assert.assertEquals("DECIMAL_DIGITS", resultSetMetaData.getColumnName(8)); - Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(9)); - Assert.assertEquals("NULLABLE", resultSetMetaData.getColumnName(10)); - Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(11)); - Assert.assertEquals("ATTR_DEF", resultSetMetaData.getColumnName(12)); - Assert.assertEquals("SQL_DATA_TYPE", resultSetMetaData.getColumnName(13)); - Assert.assertEquals("SQL_DATETIME_SUB", resultSetMetaData.getColumnName(14)); - Assert.assertEquals("CHAR_OCTET_LENGTH", resultSetMetaData.getColumnName(15)); - Assert.assertEquals("ORDINAL_POSITION", resultSetMetaData.getColumnName(16)); - Assert.assertEquals("ISNULLABLE", resultSetMetaData.getColumnName(17)); - Assert.assertEquals("SCOPE_CATALOG", resultSetMetaData.getColumnName(18)); - Assert.assertEquals("SCOPE_SCHEMA", resultSetMetaData.getColumnName(19)); - Assert.assertEquals("SCOPE_TABLE", resultSetMetaData.getColumnName(20)); - Assert.assertEquals("SOURCE_DATA_TYPE", resultSetMetaData.getColumnName(21)); - } - - @Test public void getSuperTablesTest() throws SQLException { - - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getSuperTables(null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TABLE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("SUPERTABLE_NAME", resultSetMetaData.getColumnName(4)); - } - - @Test public void getSuperTypesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getSuperTypes(null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("SUPERTYPE_CAT", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("SUPERTYPE_SCHEM", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("SUPERTYPE_NAME", resultSetMetaData.getColumnName(6)); - } - - @Test public void getUDTsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getUDTs(null, null, null, null); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("CLASS_NAME", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(6)); - Assert.assertEquals("BASE_TYPE", resultSetMetaData.getColumnName(7)); - } - - @Test public void getTypeInfoTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getTypeInfo(); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(2)); - Assert.assertEquals("PRECISION", resultSetMetaData.getColumnName(3)); - Assert.assertEquals("LITERAL_PREFIX", resultSetMetaData.getColumnName(4)); - Assert.assertEquals("LITERAL_SUFFIX", resultSetMetaData.getColumnName(5)); - Assert.assertEquals("CREATE_PARAMS", resultSetMetaData.getColumnName(6)); - Assert.assertEquals("NULLABLE", resultSetMetaData.getColumnName(7)); - Assert.assertEquals("CASE_SENSITIVE", resultSetMetaData.getColumnName(8)); - Assert.assertEquals("SEARCHABLE", resultSetMetaData.getColumnName(9)); - Assert.assertEquals("UNSIGNED_ATTRIBUTE", resultSetMetaData.getColumnName(10)); - Assert.assertEquals("FIXED_PREC_SCALE", resultSetMetaData.getColumnName(11)); - Assert.assertEquals("AUTO_INCREMENT", resultSetMetaData.getColumnName(12)); - Assert.assertEquals("LOCAL_TYPE_NAME", resultSetMetaData.getColumnName(13)); - Assert.assertEquals("MINIMUM_SCALE", resultSetMetaData.getColumnName(14)); - Assert.assertEquals("MAXIMUM_SCALE", resultSetMetaData.getColumnName(15)); - Assert.assertEquals("SQL_DATA_TYPE", resultSetMetaData.getColumnName(16)); - Assert.assertEquals("SQL_DATETIME_SUB", resultSetMetaData.getColumnName(17)); - Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(18)); - - //Check for ResultSet Data as well - } - - @Test public void getTableTypesTest() throws SQLException { - - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getTableTypes(); - - ArrayList data = new ArrayList(); - while (resultSet.next()) { - data.add(resultSet.getString("table_type")); - } - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("table_type", resultSetMetaData.getColumnName(1)); - //Checking Data - Assert.assertEquals("LOCAL TEMPORARY", data.get(0)); - Assert.assertEquals("SYSTEM TABLES", data.get(1)); - Assert.assertEquals("SYSTEM VIEW", data.get(2)); - Assert.assertEquals("TABLE", data.get(3)); - Assert.assertEquals("VIEW", data.get(4)); - } - - @Test public void getSchemasTest2() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - this.resultSet = vitessDatabaseMetaData.getSchemas(); - - ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); - Assert.assertEquals("TABLE_SCHEM", resultSetMetaData.getColumnName(1)); - Assert.assertEquals("TABLE_CATALOG", resultSetMetaData.getColumnName(2)); - } - - @Test public void allProceduresAreCallableTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.allProceduresAreCallable()); - } - - @Test public void allTablesAreSelectableTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.allTablesAreSelectable()); - } - - @Test public void nullsAreSortedHighTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.nullsAreSortedHigh()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.nullsAreSortedHigh()); - } - - @Test public void nullsAreSortedLowTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.nullsAreSortedLow()); - Assert.assertEquals(true, vitessMariaDBDatabaseMetadata.nullsAreSortedLow()); - } - - @Test public void nullsAreSortedAtStartTest() throws SQLException { - VitessDatabaseMetaData vitessMySQLDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); - - Assert.assertEquals(false, vitessMySQLDatabaseMetaData.nullsAreSortedAtStart()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.nullsAreSortedAtStart()); - } - - @Test public void nullsAreSortedAtEndTest() throws SQLException { - VitessDatabaseMetaData vitessMySQLDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); - - Assert.assertEquals(false, vitessMySQLDatabaseMetaData.nullsAreSortedAtEnd()); - Assert.assertEquals(true, vitessMariaDBDatabaseMetadata.nullsAreSortedAtEnd()); - } - - @Test public void getDatabaseProductNameTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("MySQL", vitessDatabaseMetaData.getDatabaseProductName()); - } - - @Test public void getDriverVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - StringBuilder driverVersionBuilder = new StringBuilder(); - driverVersionBuilder.append(Constants.DRIVER_MAJOR_VERSION); - driverVersionBuilder.append("."); - driverVersionBuilder.append(Constants.DRIVER_MINOR_VERSION); - Assert.assertEquals(driverVersionBuilder.toString(), - vitessDatabaseMetaData.getDriverVersion()); - } - - @Test public void getDriverMajorVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(Constants.DRIVER_MAJOR_VERSION, - vitessDatabaseMetaData.getDriverMajorVersion()); - } - - @Test public void getDriverMinorVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(Constants.DRIVER_MINOR_VERSION, - vitessDatabaseMetaData.getDriverMinorVersion()); - } - - @Test public void getSearchStringEscapeTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("\\", vitessDatabaseMetaData.getSearchStringEscape()); - } - - @Test public void getExtraNameCharactersTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("#@", vitessDatabaseMetaData.getExtraNameCharacters()); - } - - @Test public void supportsAlterTableWithAddColumnTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsAlterTableWithAddColumn()); - } - - @Test public void supportsAlterTableWithDropColumnTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsAlterTableWithDropColumn()); - } - - @Test public void supportsColumnAliasingTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsColumnAliasing()); - } - - @Test public void nullPlusNonNullIsNullTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.nullPlusNonNullIsNull()); - } - - @Test public void supportsExpressionsInOrderByTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsExpressionsInOrderBy()); - } - - @Test public void supportsOrderByUnrelatedTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOrderByUnrelated()); - } - - @Test public void supportsGroupByTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupBy()); - } - - @Test public void supportsGroupByUnrelatedTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupByUnrelated()); - } - - @Test public void supportsGroupByBeyondSelectTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupByBeyondSelect()); - } - - @Test public void supportsLikeEscapeClauseTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsLikeEscapeClause()); - } - - @Test public void supportsMultipleResultSetsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsMultipleResultSets()); - } - - @Test public void supportsMultipleTransactionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsMultipleTransactions()); - } - - @Test public void supportsNonNullableColumnsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsNonNullableColumns()); - } - - @Test public void supportsMinimumSQLGrammarTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, vitessDatabaseMetaData.supportsMinimumSQLGrammar()); - } - - @Test public void supportsCoreSQLGrammarTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsCoreSQLGrammar()); - } - - @Test public void supportsExtendedSQLGrammarTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsExtendedSQLGrammar()); - } - - @Test public void supportsOuterJoinsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOuterJoins()); - } - - @Test public void supportsFullOuterJoinsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsFullOuterJoins()); - } - - @Test public void supportsLimitedOuterJoinsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.supportsLimitedOuterJoins()); - } - - @Test public void getSchemaTermTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("", vitessDatabaseMetaData.getSchemaTerm()); - } - - @Test public void getProcedureTermTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("procedure", vitessDatabaseMetaData.getProcedureTerm()); - } +@RunWith(PowerMockRunner.class) +@PrepareForTest({VitessMySQLDatabaseMetadata.class, VitessConnection.class}) +public class VitessDatabaseMetadataTest extends BaseTest { + + private ResultSet resultSet; + + @Test + public void getPseudoColumnsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getPseudoColumns(null, null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TABLE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TABLE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("COLUMN_NAME", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("COLUMN_SIZE", resultSetMetaData.getColumnName(6)); + Assert.assertEquals("DECIMAL_DIGITS", resultSetMetaData.getColumnName(7)); + Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(8)); + Assert.assertEquals("COLUMN_USAGE", resultSetMetaData.getColumnName(9)); + Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(10)); + Assert.assertEquals("CHAR_OCTET_LENGTH", resultSetMetaData.getColumnName(11)); + Assert.assertEquals("IS_NULLABLE", resultSetMetaData.getColumnName(12)); + } + + @Test + public void getClientInfoPropertiesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getClientInfoProperties(); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("NAME", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("MAX_LEN", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("DEFAULT_VALUE", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("DESCRIPTION", resultSetMetaData.getColumnName(4)); + } + + @Test + public void getSchemasTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getSchemas(null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TABLE_CATALOG", resultSetMetaData.getColumnName(2)); + } + + @Test + public void getAttributesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getAttributes(null, null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("ATTR_NAME", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("ATTR_TYPE_NAME", resultSetMetaData.getColumnName(6)); + Assert.assertEquals("ATTR_SIZE", resultSetMetaData.getColumnName(7)); + Assert.assertEquals("DECIMAL_DIGITS", resultSetMetaData.getColumnName(8)); + Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(9)); + Assert.assertEquals("NULLABLE", resultSetMetaData.getColumnName(10)); + Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(11)); + Assert.assertEquals("ATTR_DEF", resultSetMetaData.getColumnName(12)); + Assert.assertEquals("SQL_DATA_TYPE", resultSetMetaData.getColumnName(13)); + Assert.assertEquals("SQL_DATETIME_SUB", resultSetMetaData.getColumnName(14)); + Assert.assertEquals("CHAR_OCTET_LENGTH", resultSetMetaData.getColumnName(15)); + Assert.assertEquals("ORDINAL_POSITION", resultSetMetaData.getColumnName(16)); + Assert.assertEquals("ISNULLABLE", resultSetMetaData.getColumnName(17)); + Assert.assertEquals("SCOPE_CATALOG", resultSetMetaData.getColumnName(18)); + Assert.assertEquals("SCOPE_SCHEMA", resultSetMetaData.getColumnName(19)); + Assert.assertEquals("SCOPE_TABLE", resultSetMetaData.getColumnName(20)); + Assert.assertEquals("SOURCE_DATA_TYPE", resultSetMetaData.getColumnName(21)); + } + + @Test + public void getSuperTablesTest() throws SQLException { + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getSuperTables(null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TABLE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TABLE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("SUPERTABLE_NAME", resultSetMetaData.getColumnName(4)); + } + + @Test + public void getSuperTypesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getSuperTypes(null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("SUPERTYPE_CAT", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("SUPERTYPE_SCHEM", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("SUPERTYPE_NAME", resultSetMetaData.getColumnName(6)); + } + + @Test + public void getUDTsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getUDTs(null, null, null, null); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TYPE_CAT", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TYPE_SCHEM", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("CLASS_NAME", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("REMARKS", resultSetMetaData.getColumnName(6)); + Assert.assertEquals("BASE_TYPE", resultSetMetaData.getColumnName(7)); + } + + @Test + public void getTypeInfoTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getTypeInfo(); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TYPE_NAME", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("DATA_TYPE", resultSetMetaData.getColumnName(2)); + Assert.assertEquals("PRECISION", resultSetMetaData.getColumnName(3)); + Assert.assertEquals("LITERAL_PREFIX", resultSetMetaData.getColumnName(4)); + Assert.assertEquals("LITERAL_SUFFIX", resultSetMetaData.getColumnName(5)); + Assert.assertEquals("CREATE_PARAMS", resultSetMetaData.getColumnName(6)); + Assert.assertEquals("NULLABLE", resultSetMetaData.getColumnName(7)); + Assert.assertEquals("CASE_SENSITIVE", resultSetMetaData.getColumnName(8)); + Assert.assertEquals("SEARCHABLE", resultSetMetaData.getColumnName(9)); + Assert.assertEquals("UNSIGNED_ATTRIBUTE", resultSetMetaData.getColumnName(10)); + Assert.assertEquals("FIXED_PREC_SCALE", resultSetMetaData.getColumnName(11)); + Assert.assertEquals("AUTO_INCREMENT", resultSetMetaData.getColumnName(12)); + Assert.assertEquals("LOCAL_TYPE_NAME", resultSetMetaData.getColumnName(13)); + Assert.assertEquals("MINIMUM_SCALE", resultSetMetaData.getColumnName(14)); + Assert.assertEquals("MAXIMUM_SCALE", resultSetMetaData.getColumnName(15)); + Assert.assertEquals("SQL_DATA_TYPE", resultSetMetaData.getColumnName(16)); + Assert.assertEquals("SQL_DATETIME_SUB", resultSetMetaData.getColumnName(17)); + Assert.assertEquals("NUM_PREC_RADIX", resultSetMetaData.getColumnName(18)); + + //Check for ResultSet Data as well + } + + @Test + public void getTableTypesTest() throws SQLException { + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getTableTypes(); + + ArrayList data = new ArrayList(); + while (resultSet.next()) { + data.add(resultSet.getString("table_type")); + } + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("table_type", resultSetMetaData.getColumnName(1)); + //Checking Data + Assert.assertEquals("LOCAL TEMPORARY", data.get(0)); + Assert.assertEquals("SYSTEM TABLES", data.get(1)); + Assert.assertEquals("SYSTEM VIEW", data.get(2)); + Assert.assertEquals("TABLE", data.get(3)); + Assert.assertEquals("VIEW", data.get(4)); + } + + @Test + public void getSchemasTest2() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + this.resultSet = vitessDatabaseMetaData.getSchemas(); + + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + Assert.assertEquals("TABLE_SCHEM", resultSetMetaData.getColumnName(1)); + Assert.assertEquals("TABLE_CATALOG", resultSetMetaData.getColumnName(2)); + } + + @Test + public void allProceduresAreCallableTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.allProceduresAreCallable()); + } + + @Test + public void allTablesAreSelectableTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.allTablesAreSelectable()); + } + + @Test + public void nullsAreSortedHighTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.nullsAreSortedHigh()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.nullsAreSortedHigh()); + } + + @Test + public void nullsAreSortedLowTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(true, vitessDatabaseMetaData.nullsAreSortedLow()); + Assert.assertEquals(true, vitessMariaDBDatabaseMetadata.nullsAreSortedLow()); + } + + @Test + public void nullsAreSortedAtStartTest() throws SQLException { + VitessDatabaseMetaData vitessMySQLDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySQLDatabaseMetaData.nullsAreSortedAtStart()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.nullsAreSortedAtStart()); + } + + @Test + public void nullsAreSortedAtEndTest() throws SQLException { + VitessDatabaseMetaData vitessMySQLDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySQLDatabaseMetaData.nullsAreSortedAtEnd()); + Assert.assertEquals(true, vitessMariaDBDatabaseMetadata.nullsAreSortedAtEnd()); + } + + @Test + public void getDatabaseProductNameTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals("MySQL", vitessDatabaseMetaData.getDatabaseProductName()); + } + + @Test + public void getDriverVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + StringBuilder driverVersionBuilder = new StringBuilder(); + driverVersionBuilder.append(Constants.DRIVER_MAJOR_VERSION); + driverVersionBuilder.append("."); + driverVersionBuilder.append(Constants.DRIVER_MINOR_VERSION); + Assert.assertEquals(driverVersionBuilder.toString(), vitessDatabaseMetaData.getDriverVersion()); + } - @Test public void getCatalogTermTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getDriverMajorVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals("database", vitessDatabaseMetaData.getCatalogTerm()); - } + Assert.assertEquals(Constants.DRIVER_MAJOR_VERSION, + vitessDatabaseMetaData.getDriverMajorVersion()); + } - @Test public void isCatalogAtStartTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getDriverMinorVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(true, vitessDatabaseMetaData.isCatalogAtStart()); - } + Assert.assertEquals(Constants.DRIVER_MINOR_VERSION, + vitessDatabaseMetaData.getDriverMinorVersion()); + } - @Test public void getCatalogSeparatorTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getSearchStringEscapeTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(".", vitessDatabaseMetaData.getCatalogSeparator()); - } + Assert.assertEquals("\\", vitessDatabaseMetaData.getSearchStringEscape()); + } - @Test public void supportsSchemasInDataManipulationTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getExtraNameCharactersTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInDataManipulation()); - } + Assert.assertEquals("#@", vitessDatabaseMetaData.getExtraNameCharacters()); + } - @Test public void supportsSchemasInProcedureCallsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsAlterTableWithAddColumnTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInProcedureCalls()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsAlterTableWithAddColumn()); + } - @Test public void supportsSchemasInTableDefinitionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsAlterTableWithDropColumnTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInTableDefinitions()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsAlterTableWithDropColumn()); + } - @Test public void supportsSchemasInIndexDefinitionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsColumnAliasingTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInIndexDefinitions()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsColumnAliasing()); + } - @Test public void supportsSelectForUpdateTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void nullPlusNonNullIsNullTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSelectForUpdate()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.nullPlusNonNullIsNull()); + } - @Test public void supportsStoredProceduresTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsExpressionsInOrderByTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsStoredProcedures()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsExpressionsInOrderBy()); + } - @Test public void supportsSubqueriesInComparisonsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsOrderByUnrelatedTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInComparisons()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOrderByUnrelated()); + } - @Test public void supportsSubqueriesInExistsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsGroupByTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInExists()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupBy()); + } - @Test public void supportsSubqueriesInInsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsGroupByUnrelatedTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInIns()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupByUnrelated()); + } - @Test public void supportsSubqueriesInQuantifiedsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsGroupByBeyondSelectTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInQuantifieds()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsGroupByBeyondSelect()); + } - @Test public void supportsCorrelatedSubqueriesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsLikeEscapeClauseTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsCorrelatedSubqueries()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsLikeEscapeClause()); + } - @Test public void supportsUnionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsMultipleResultSetsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsUnion()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsMultipleResultSets()); + } - @Test public void supportsUnionAllTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsMultipleTransactionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsUnionAll()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsMultipleTransactions()); + } - @Test public void supportsOpenCursorsAcrossRollbackTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsNonNullableColumnsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenCursorsAcrossRollback()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsNonNullableColumns()); + } - @Test public void supportsOpenStatementsAcrossCommitTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsMinimumSQLGrammarTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenStatementsAcrossCommit()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.supportsMinimumSQLGrammar()); + } - @Test public void supportsOpenStatementsAcrossRollbackTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsCoreSQLGrammarTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenStatementsAcrossRollback()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsCoreSQLGrammar()); + } - @Test public void supportsOpenCursorsAcrossCommitTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsExtendedSQLGrammarTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenCursorsAcrossCommit()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsExtendedSQLGrammar()); + } - @Test public void getMaxBinaryLiteralLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsOuterJoinsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(16777208, vitessDatabaseMetaData.getMaxBinaryLiteralLength()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOuterJoins()); + } - @Test public void getMaxCharLiteralLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsFullOuterJoinsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(16777208, vitessDatabaseMetaData.getMaxCharLiteralLength()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsFullOuterJoins()); + } - @Test public void getMaxColumnNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsLimitedOuterJoinsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnNameLength()); - } - - @Test public void getMaxColumnsInGroupByTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsLimitedOuterJoins()); + } - Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnsInGroupBy()); - } + @Test + public void getSchemaTermTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxColumnsInIndexTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals("", vitessDatabaseMetaData.getSchemaTerm()); + } - Assert.assertEquals(16, vitessDatabaseMetaData.getMaxColumnsInIndex()); - } + @Test + public void getProcedureTermTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxColumnsInOrderByTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnsInOrderBy()); - } - - @Test public void getMaxColumnsInSelectTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(256, vitessDatabaseMetaData.getMaxColumnsInSelect()); - } - - @Test public void getMaxIndexLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(256, vitessDatabaseMetaData.getMaxIndexLength()); - } - - @Test public void doesMaxRowSizeIncludeBlobsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.doesMaxRowSizeIncludeBlobs()); - } - - @Test public void getMaxTableNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(64, vitessDatabaseMetaData.getMaxTableNameLength()); - } - - @Test public void getMaxTablesInSelectTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(256, vitessDatabaseMetaData.getMaxTablesInSelect()); - } - - @Test public void getMaxUserNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(16, vitessDatabaseMetaData.getMaxUserNameLength()); - } - - @Test public void supportsDataDefinitionAndDataManipulationTransactionsTest() - throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsDataDefinitionAndDataManipulationTransactions()); - } - - @Test public void dataDefinitionCausesTransactionCommitTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.dataDefinitionCausesTransactionCommit()); - } - - @Test public void dataDefinitionIgnoredInTransactionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(false, vitessDatabaseMetaData.dataDefinitionIgnoredInTransactions()); - } - - @Test public void getIdentifierQuoteStringTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals("`", vitessDatabaseMetaData.getIdentifierQuoteString()); - } - - @Test public void getProceduresTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(null, vitessDatabaseMetaData.getProcedures(null, null, null)); - } - - @Test public void supportsResultSetTypeTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(true, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.CLOSE_CURSORS_AT_COMMIT)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.CONCUR_UPDATABLE)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_FORWARD)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_REVERSE)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.HOLD_CURSORS_OVER_COMMIT)); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_UNKNOWN)); - } - - @Test public void supportsResultSetConcurrencyTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, - ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, - ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.CLOSE_CURSORS_AT_COMMIT, - ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.CONCUR_READ_ONLY, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.CONCUR_UPDATABLE, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.FETCH_FORWARD, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.FETCH_REVERSE, ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.HOLD_CURSORS_OVER_COMMIT, - ResultSet.CONCUR_READ_ONLY)); - Assert.assertEquals(false, vitessDatabaseMetaData - .supportsResultSetConcurrency(ResultSet.FETCH_UNKNOWN, ResultSet.CONCUR_READ_ONLY)); - } - - @Test public void getJDBCMajorVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals(1, vitessDatabaseMetaData.getJDBCMajorVersion()); - } + Assert.assertEquals("procedure", vitessDatabaseMetaData.getProcedureTerm()); + } - @Test public void getJDBCMinorVersionTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void getCatalogTermTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(0, vitessDatabaseMetaData.getJDBCMinorVersion()); - } + Assert.assertEquals("database", vitessDatabaseMetaData.getCatalogTerm()); + } - @Test public void getNumericFunctionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void isCatalogAtStartTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals( - "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW,POWER," - + "RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE", - vitessDatabaseMetaData.getNumericFunctions()); - } + Assert.assertEquals(true, vitessDatabaseMetaData.isCatalogAtStart()); + } - @Test public void getStringFunctionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - - Assert.assertEquals( - "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT,EXPORT_SET,FIELD," - + - "FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD,LTRIM,MAKE_SET," - + - "MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD,RTRIM,SOUNDEX,SPACE," - + - "STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER", - vitessDatabaseMetaData.getStringFunctions()); - } + @Test + public void getCatalogSeparatorTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getSystemFunctionsTest() throws SQLException { - VitessDatabaseMetaData vitessMySQLDatabaseMetadata = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatbaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(".", vitessDatabaseMetaData.getCatalogSeparator()); + } - Assert.assertEquals( - "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION,PASSWORD,ENCRYPT", - vitessMySQLDatabaseMetadata.getSystemFunctions()); - Assert.assertEquals("DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION", - vitessMariaDBDatbaseMetadata.getSystemFunctions()); - } + @Test + public void supportsSchemasInDataManipulationTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getTimeDateFunctionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInDataManipulation()); + } - Assert.assertEquals( - "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND," - + - "PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE,CURRENT_DATE,CURTIME," - + - "CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,SEC_TO_TIME,TIME_TO_SEC", - vitessDatabaseMetaData.getTimeDateFunctions()); - } + @Test + public void supportsSchemasInProcedureCallsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void autoCommitFailureClosesAllResultSetsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInProcedureCalls()); + } - Assert.assertEquals(false, vitessDatabaseMetaData.autoCommitFailureClosesAllResultSets()); - } + @Test + public void supportsSchemasInTableDefinitionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getUrlTest() throws SQLException { - String connectionUrl = "jdbc:vitess://://"; - VitessJDBCUrl mockUrl = PowerMockito.mock(VitessJDBCUrl.class); - PowerMockito.when(mockUrl.getUrl()).thenReturn(connectionUrl); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInTableDefinitions()); + } - VitessConnection mockConn = PowerMockito.mock(VitessConnection.class); - PowerMockito.when(mockConn.getUrl()).thenReturn(mockUrl); + @Test + public void supportsSchemasInIndexDefinitionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(connectionUrl, mockConn.getUrl().getUrl()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSchemasInIndexDefinitions()); + } - @Test public void isReadOnlyTest() throws SQLException { - VitessConnection mockConn = PowerMockito.mock(VitessConnection.class); - PowerMockito.when(mockConn.isReadOnly()).thenReturn(false); - Assert.assertEquals(false, mockConn.isReadOnly()); + @Test + public void supportsSelectForUpdateTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSelectForUpdate()); + } - @Test public void getDriverNameTest() throws SQLException { - VitessDatabaseMetaData vitessMySQLDatabaseMetadata = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + @Test + public void supportsStoredProceduresTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert - .assertEquals("Vitess MySQL JDBC Driver", vitessMySQLDatabaseMetadata.getDriverName()); - Assert.assertEquals("Vitess MariaDB JDBC Driver", - vitessMariaDBDatabaseMetadata.getDriverName()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsStoredProcedures()); + } - @Test public void usesLocalFilesTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsSubqueriesInComparisonsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.usesLocalFiles()); - Assert.assertEquals(false, vitessDatabaseMetaData.usesLocalFilePerTable()); - Assert.assertEquals(false, vitessDatabaseMetaData.storesUpperCaseIdentifiers()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInComparisons()); + } - @Test public void storeIdentifiersTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + @Test + public void supportsSubqueriesInExistsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, vitessDatabaseMetaData.storesUpperCaseIdentifiers()); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInExists()); + } - @Test public void supportsTransactionsTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(true, vitessDatabaseMetaData.supportsTransactions()); - } + @Test + public void supportsSubqueriesInInsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsTransactionIsolationLevelTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(false, - vitessDatabaseMetaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE)); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED)); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ)); - Assert.assertEquals(true, vitessDatabaseMetaData - .supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE)); - } + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInIns()); + } - @Test public void getMaxProcedureNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - Assert.assertEquals(256, vitessDatabaseMetaData.getMaxProcedureNameLength()); - } + @Test + public void supportsSubqueriesInQuantifiedsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxCatalogNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsSubqueriesInQuantifieds()); + } - Assert.assertEquals(32, vitessMySqlDatabaseMetaData.getMaxCatalogNameLength()); - Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxCatalogNameLength()); - } + @Test + public void supportsCorrelatedSubqueriesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxRowSizeTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsCorrelatedSubqueries()); + } - Assert.assertEquals(2147483639, vitessMySqlDatabaseMetaData.getMaxRowSize()); - Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxRowSize()); - } + @Test + public void supportsUnionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxStatementLengthTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsUnion()); + } - Assert.assertEquals(65531, vitessMySqlDatabaseMetaData.getMaxStatementLength()); - Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxStatementLength()); - } + @Test + public void supportsUnionAllTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxStatementsTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsUnionAll()); + } - Assert.assertEquals(0, vitessMySqlDatabaseMetaData.getMaxStatements()); - Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxStatements()); - } + @Test + public void supportsOpenCursorsAcrossRollbackTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsDataManipulationTransactionsOnlyTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenCursorsAcrossRollback()); + } - Assert.assertEquals(false, - vitessMySqlDatabaseMetaData.supportsDataManipulationTransactionsOnly()); - Assert.assertEquals(false, - vitessMariaDBDatabaseMetadata.supportsDataManipulationTransactionsOnly()); - } + @Test + public void supportsOpenStatementsAcrossCommitTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getMaxSchemaNameLengthTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenStatementsAcrossCommit()); + } - Assert.assertEquals(0, vitessMySqlDatabaseMetaData.getMaxSchemaNameLength()); - Assert.assertEquals(32, vitessMariaDBDatabaseMetadata.getMaxSchemaNameLength()); - } + @Test + public void supportsOpenStatementsAcrossRollbackTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsSavepointsTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenStatementsAcrossRollback()); + } - Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsSavepoints()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsSavepoints()); - } + @Test + public void supportsOpenCursorsAcrossCommitTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsMultipleOpenResultsTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(false, vitessDatabaseMetaData.supportsOpenCursorsAcrossCommit()); + } - Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsMultipleOpenResults()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsMultipleOpenResults()); - } + @Test + public void getMaxBinaryLiteralLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void locatorsUpdateCopyTest() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(16777208, vitessDatabaseMetaData.getMaxBinaryLiteralLength()); + } - Assert.assertEquals(true, vitessMySqlDatabaseMetaData.locatorsUpdateCopy()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.locatorsUpdateCopy()); - } + @Test + public void getMaxCharLiteralLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void supportsStatementPooling() throws SQLException { - VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = - new VitessMariaDBDatabaseMetadata(null); + Assert.assertEquals(16777208, vitessDatabaseMetaData.getMaxCharLiteralLength()); + } - Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsStatementPooling()); - Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsStatementPooling()); - } + @Test + public void getMaxColumnNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getCatalogsTest() throws SQLException, Exception { - String sql = "SHOW DATABASES"; - Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder().addFields( - Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR).build()) - .addRows(Query.Row.newBuilder().addLengths("vitessDB".length()) - .setValues(ByteString.copyFromUtf8("vitessDB"))).addRows( - Query.Row.newBuilder().addLengths("sampleDB".length()) - .setValues(ByteString.copyFromUtf8("sampleDB"))).addRows( - Query.Row.newBuilder().addLengths("testDB".length()) - .setValues(ByteString.copyFromUtf8("testDB"))).addRows( - Query.Row.newBuilder().addLengths("dummyDB".length()) - .setValues(ByteString.copyFromUtf8("dummyDB"))).build()); - - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); - - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - ResultSet resultSet = vitessDatabaseMetaData.getCatalogs(); - ArrayList resultSetList = new ArrayList(); - while (resultSet.next()) { - resultSetList.add(resultSet.getString(1)); - } - Assert.assertEquals("dummyDB", resultSetList.get(0)); - Assert.assertEquals("sampleDB", resultSetList.get(1)); - Assert.assertEquals("testDB", resultSetList.get(2)); - Assert.assertEquals("vitessDB", resultSetList.get(3)); - } + Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnNameLength()); + } - @Test public void getTablesTest() throws SQLException, Exception { + @Test + public void getMaxColumnsInGroupByTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - String sql = "SHOW FULL TABLES FROM `vt` LIKE '%'"; - Cursor mockedCursor = getTablesCursor(); + Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnsInGroupBy()); + } - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); + @Test + public void getMaxColumnsInIndexTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(getVitessConnection()); - ResultSet actualResultSet = vitessDatabaseMetaData.getTables("vt", null, null, null); - ResultSet expectedResultSet = new VitessResultSet(mockedCursor); + Assert.assertEquals(16, vitessDatabaseMetaData.getMaxColumnsInIndex()); + } - assertResultSetEquals(actualResultSet, expectedResultSet); - } + @Test + public void getMaxColumnsInOrderByTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - @Test public void getTablesProperResultTypeTest() throws SQLException, Exception { + Assert.assertEquals(64, vitessDatabaseMetaData.getMaxColumnsInOrderBy()); + } - String sql = "SHOW FULL TABLES FROM `vt` LIKE '%'"; - Cursor mockedCursor = getTablesCursor(); + @Test + public void getMaxColumnsInSelectTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); + Assert.assertEquals(256, vitessDatabaseMetaData.getMaxColumnsInSelect()); + } - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(getVitessConnection()); - ResultSet actualResultSet = vitessDatabaseMetaData.getTables("vt", null, null, null); - actualResultSet.next(); - Assert.assertEquals(String.class, actualResultSet.getObject("TABLE_CAT").getClass()); - } + @Test + public void getMaxIndexLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); - private Cursor getTablesCursor() throws Exception { - return new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_TYPE").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_CAT").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_SCHEM").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("SELF_REFERENCING_COL_NAME") - .setType(Query.Type.VARCHAR)).addFields( - Query.Field.newBuilder().setName("REF_GENERATION").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleTable1".length()).addLengths("TABLE".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB1sampleTable1TABLE"))).addRows( - Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleView1".length()).addLengths("VIEW".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB1SampleView1VIEW"))).addRows( - Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleSystemView".length()).addLengths("SYSTEM VIEW".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB2SampleSystemViewSYSTEM VIEW"))) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleSystemTable".length()).addLengths("SYSTEM TABLE".length()) + Assert.assertEquals(256, vitessDatabaseMetaData.getMaxIndexLength()); + } + + @Test + public void doesMaxRowSizeIncludeBlobsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.doesMaxRowSizeIncludeBlobs()); + } + + @Test + public void getMaxTableNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(64, vitessDatabaseMetaData.getMaxTableNameLength()); + } + + @Test + public void getMaxTablesInSelectTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(256, vitessDatabaseMetaData.getMaxTablesInSelect()); + } + + @Test + public void getMaxUserNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(16, vitessDatabaseMetaData.getMaxUserNameLength()); + } + + @Test + public void supportsDataDefinitionAndDataManipulationTransactionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsDataDefinitionAndDataManipulationTransactions()); + } + + @Test + public void dataDefinitionCausesTransactionCommitTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.dataDefinitionCausesTransactionCommit()); + } + + @Test + public void dataDefinitionIgnoredInTransactionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.dataDefinitionIgnoredInTransactions()); + } + + @Test + public void getIdentifierQuoteStringTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals("`", vitessDatabaseMetaData.getIdentifierQuoteString()); + } + + @Test + public void getProceduresTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(null, vitessDatabaseMetaData.getProcedures(null, null, null)); + } + + @Test + public void supportsResultSetTypeTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(true, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_FORWARD_ONLY)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.CLOSE_CURSORS_AT_COMMIT)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.CONCUR_UPDATABLE)); + Assert + .assertEquals(false, vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_FORWARD)); + Assert + .assertEquals(false, vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_REVERSE)); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsResultSetType(ResultSet.HOLD_CURSORS_OVER_COMMIT)); + Assert + .assertEquals(false, vitessDatabaseMetaData.supportsResultSetType(ResultSet.FETCH_UNKNOWN)); + } + + @Test + public void supportsResultSetConcurrencyTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.CLOSE_CURSORS_AT_COMMIT, + ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.CONCUR_READ_ONLY, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.CONCUR_UPDATABLE, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.FETCH_FORWARD, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.FETCH_REVERSE, ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.HOLD_CURSORS_OVER_COMMIT, + ResultSet.CONCUR_READ_ONLY)); + Assert.assertEquals(false, vitessDatabaseMetaData + .supportsResultSetConcurrency(ResultSet.FETCH_UNKNOWN, ResultSet.CONCUR_READ_ONLY)); + } + + @Test + public void getJDBCMajorVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(1, vitessDatabaseMetaData.getJDBCMajorVersion()); + } + + @Test + public void getJDBCMinorVersionTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(0, vitessDatabaseMetaData.getJDBCMinorVersion()); + } + + @Test + public void getNumericFunctionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals( + "ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,MAX,MIN," + + "MOD,PI,POW,POWER," + + "RADIANS,RAND,ROUND,SIN,SQRT,TAN,TRUNCATE", + vitessDatabaseMetaData.getNumericFunctions()); + } + + @Test + public void getStringFunctionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals( + "ASCII,BIN,BIT_LENGTH,CHAR,CHARACTER_LENGTH,CHAR_LENGTH,CONCAT,CONCAT_WS,CONV,ELT," + + "EXPORT_SET,FIELD," + + "FIND_IN_SET,HEX,INSERT,INSTR,LCASE,LEFT,LENGTH,LOAD_FILE,LOCATE,LOCATE,LOWER,LPAD," + + "LTRIM,MAKE_SET," + + "MATCH,MID,OCT,OCTET_LENGTH,ORD,POSITION,QUOTE,REPEAT,REPLACE,REVERSE,RIGHT,RPAD," + + "RTRIM,SOUNDEX,SPACE," + + "STRCMP,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER", + vitessDatabaseMetaData.getStringFunctions()); + } + + @Test + public void getSystemFunctionsTest() throws SQLException { + VitessDatabaseMetaData vitessMySQLDatabaseMetadata = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatbaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals( + "DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION,PASSWORD,ENCRYPT", + vitessMySQLDatabaseMetadata.getSystemFunctions()); + Assert.assertEquals("DATABASE,USER,SYSTEM_USER,SESSION_USER,LAST_INSERT_ID,VERSION", + vitessMariaDBDatbaseMetadata.getSystemFunctions()); + } + + @Test + public void getTimeDateFunctionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals( + "DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR," + + "MINUTE,SECOND," + + "PERIOD_ADD,PERIOD_DIFF,TO_DAYS,FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE," + + "CURRENT_DATE,CURTIME," + + "CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME," + + "SEC_TO_TIME,TIME_TO_SEC", + vitessDatabaseMetaData.getTimeDateFunctions()); + } + + @Test + public void autoCommitFailureClosesAllResultSetsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.autoCommitFailureClosesAllResultSets()); + } + + @Test + public void getUrlTest() throws SQLException { + String connectionUrl = "jdbc:vitess://://"; + VitessJDBCUrl mockUrl = PowerMockito.mock(VitessJDBCUrl.class); + PowerMockito.when(mockUrl.getUrl()).thenReturn(connectionUrl); + + VitessConnection mockConn = PowerMockito.mock(VitessConnection.class); + PowerMockito.when(mockConn.getUrl()).thenReturn(mockUrl); + + Assert.assertEquals(connectionUrl, mockConn.getUrl().getUrl()); + } + + @Test + public void isReadOnlyTest() throws SQLException { + VitessConnection mockConn = PowerMockito.mock(VitessConnection.class); + PowerMockito.when(mockConn.isReadOnly()).thenReturn(false); + Assert.assertEquals(false, mockConn.isReadOnly()); + + } + + @Test + public void getDriverNameTest() throws SQLException { + VitessDatabaseMetaData vitessMySQLDatabaseMetadata = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals("Vitess MySQL JDBC Driver", vitessMySQLDatabaseMetadata.getDriverName()); + Assert + .assertEquals("Vitess MariaDB JDBC Driver", vitessMariaDBDatabaseMetadata.getDriverName()); + } + + @Test + public void usesLocalFilesTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.usesLocalFiles()); + Assert.assertEquals(false, vitessDatabaseMetaData.usesLocalFilePerTable()); + Assert.assertEquals(false, vitessDatabaseMetaData.storesUpperCaseIdentifiers()); + } + + @Test + public void storeIdentifiersTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + + Assert.assertEquals(false, vitessDatabaseMetaData.storesUpperCaseIdentifiers()); + } + + @Test + public void supportsTransactionsTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(true, vitessDatabaseMetaData.supportsTransactions()); + } + + @Test + public void supportsTransactionIsolationLevelTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(false, + vitessDatabaseMetaData.supportsTransactionIsolationLevel(Connection.TRANSACTION_NONE)); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_COMMITTED)); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsTransactionIsolationLevel(Connection.TRANSACTION_READ_UNCOMMITTED)); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsTransactionIsolationLevel(Connection.TRANSACTION_REPEATABLE_READ)); + Assert.assertEquals(true, vitessDatabaseMetaData + .supportsTransactionIsolationLevel(Connection.TRANSACTION_SERIALIZABLE)); + } + + @Test + public void getMaxProcedureNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + Assert.assertEquals(256, vitessDatabaseMetaData.getMaxProcedureNameLength()); + } + + @Test + public void getMaxCatalogNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(32, vitessMySqlDatabaseMetaData.getMaxCatalogNameLength()); + Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxCatalogNameLength()); + } + + @Test + public void getMaxRowSizeTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(2147483639, vitessMySqlDatabaseMetaData.getMaxRowSize()); + Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxRowSize()); + } + + @Test + public void getMaxStatementLengthTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(65531, vitessMySqlDatabaseMetaData.getMaxStatementLength()); + Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxStatementLength()); + } + + @Test + public void getMaxStatementsTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(0, vitessMySqlDatabaseMetaData.getMaxStatements()); + Assert.assertEquals(0, vitessMariaDBDatabaseMetadata.getMaxStatements()); + } + + @Test + public void supportsDataManipulationTransactionsOnlyTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, + vitessMySqlDatabaseMetaData.supportsDataManipulationTransactionsOnly()); + Assert.assertEquals(false, + vitessMariaDBDatabaseMetadata.supportsDataManipulationTransactionsOnly()); + } + + @Test + public void getMaxSchemaNameLengthTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(0, vitessMySqlDatabaseMetaData.getMaxSchemaNameLength()); + Assert.assertEquals(32, vitessMariaDBDatabaseMetadata.getMaxSchemaNameLength()); + } + + @Test + public void supportsSavepointsTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsSavepoints()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsSavepoints()); + } + + @Test + public void supportsMultipleOpenResultsTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsMultipleOpenResults()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsMultipleOpenResults()); + } + + @Test + public void locatorsUpdateCopyTest() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(true, vitessMySqlDatabaseMetaData.locatorsUpdateCopy()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.locatorsUpdateCopy()); + } + + @Test + public void supportsStatementPooling() throws SQLException { + VitessDatabaseMetaData vitessMySqlDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + VitessDatabaseMetaData vitessMariaDBDatabaseMetadata = new VitessMariaDBDatabaseMetadata(null); + + Assert.assertEquals(false, vitessMySqlDatabaseMetaData.supportsStatementPooling()); + Assert.assertEquals(false, vitessMariaDBDatabaseMetadata.supportsStatementPooling()); + } + + @Test + public void getCatalogsTest() throws SQLException, Exception { + String sql = "SHOW DATABASES"; + Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder().addFields( + Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR).build()).addRows( + Query.Row.newBuilder().addLengths("vitessDB".length()) + .setValues(ByteString.copyFromUtf8("vitessDB"))).addRows( + Query.Row.newBuilder().addLengths("sampleDB".length()) + .setValues(ByteString.copyFromUtf8("sampleDB"))).addRows( + Query.Row.newBuilder().addLengths("testDB".length()) + .setValues(ByteString.copyFromUtf8("testDB"))).addRows( + Query.Row.newBuilder().addLengths("dummyDB".length()) + .setValues(ByteString.copyFromUtf8("dummyDB"))).build()); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(null); + ResultSet resultSet = vitessDatabaseMetaData.getCatalogs(); + ArrayList resultSetList = new ArrayList(); + while (resultSet.next()) { + resultSetList.add(resultSet.getString(1)); + } + Assert.assertEquals("dummyDB", resultSetList.get(0)); + Assert.assertEquals("sampleDB", resultSetList.get(1)); + Assert.assertEquals("testDB", resultSetList.get(2)); + Assert.assertEquals("vitessDB", resultSetList.get(3)); + } + + @Test + public void getTablesTest() throws SQLException, Exception { + + String sql = "SHOW FULL TABLES FROM `vt` LIKE '%'"; + Cursor mockedCursor = getTablesCursor(); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + getVitessConnection()); + ResultSet actualResultSet = vitessDatabaseMetaData.getTables("vt", null, null, null); + ResultSet expectedResultSet = new VitessResultSet(mockedCursor); + + assertResultSetEquals(actualResultSet, expectedResultSet); + } + + @Test + public void getTablesProperResultTypeTest() throws SQLException, Exception { + + String sql = "SHOW FULL TABLES FROM `vt` LIKE '%'"; + Cursor mockedCursor = getTablesCursor(); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + getVitessConnection()); + ResultSet actualResultSet = vitessDatabaseMetaData.getTables("vt", null, null, null); + actualResultSet.next(); + Assert.assertEquals(String.class, actualResultSet.getObject("TABLE_CAT").getClass()); + } + + private Cursor getTablesCursor() throws Exception { + return new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_TYPE").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_CAT").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_SCHEM").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("SELF_REFERENCING_COL_NAME") + .setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("REF_GENERATION").setType(Query.Type.VARCHAR)) + .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleTable1".length()).addLengths("TABLE".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("TestDB1sampleTable1TABLE"))).addRows( + Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleView1".length()).addLengths("VIEW".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB2SampleSystemTableSYSTEM TABLE"))) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("SampleLocalTemporary".length()).addLengths("LOCAL TEMPORARY".length()) + .setValues(ByteString.copyFromUtf8("TestDB1SampleView1VIEW"))).addRows( + Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleSystemView".length()).addLengths("SYSTEM VIEW".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB2SampleLocalTemporaryLOCAL TEMPORARY"))) - .build()); - } - - @Test public void getColumnsTest() throws SQLException, Exception { - - String sql = "SHOW FULL COLUMNS FROM `sampleTable1` FROM `TestDB1` LIKE '%'"; - Cursor mockedTablecursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_TYPE").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_CAT").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_SCHEM").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("SELF_REFERENCING_COL_NAME") - .setType(Query.Type.VARCHAR)).addFields( - Query.Field.newBuilder().setName("REF_GENERATION").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) - .addLengths("sampleTable1".length()).addLengths("TABLE".length()) + .setValues(ByteString.copyFromUtf8("TestDB2SampleSystemViewSYSTEM VIEW"))).addRows( + Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleSystemTable".length()).addLengths("SYSTEM TABLE".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) .addLengths("".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("TestDB1sampleTable1TABLE"))).build()); - - Cursor actualCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("Field").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Type").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Key").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Default").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Extra").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Privileges").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("shipmentid".length()) - .addLengths("bigint".length()).addLengths("NULL".length()).addLengths("NO".length()) - .addLengths("PRI".length()).addLengths("NULL".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("TestDB2SampleSystemTableSYSTEM TABLE"))) + .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("SampleLocalTemporary".length()).addLengths("LOCAL TEMPORARY".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("TestDB2SampleLocalTemporaryLOCAL TEMPORARY"))) + .build()); + } + + @Test + public void getColumnsTest() throws SQLException, Exception { + + String sql = "SHOW FULL COLUMNS FROM `sampleTable1` FROM `TestDB1` LIKE '%'"; + Cursor mockedTablecursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_TYPE").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_CAT").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_SCHEM").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("SELF_REFERENCING_COL_NAME") + .setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("REF_GENERATION").setType(Query.Type.VARCHAR)) + .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths("".length()) + .addLengths("sampleTable1".length()).addLengths("TABLE".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .addLengths("".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("TestDB1sampleTable1TABLE"))).build()); + + Cursor actualCursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("Field").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Type").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Key").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Default").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Extra").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Privileges").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)).addRows( + Query.Row.newBuilder().addLengths("shipmentid".length()).addLengths("bigint".length()) + .addLengths("NULL".length()).addLengths("NO".length()).addLengths("PRI".length()) + .addLengths("NULL".length()).addLengths("".length()) .addLengths("select,insert,update,references".length()).addLengths("".length()) .setValues(ByteString .copyFromUtf8("shipmentidbigintNULLNOPRINULLselect,insert,update,references"))) - .addRows(Query.Row.newBuilder().addLengths("trackingid".length()) - .addLengths("varchar".length()).addLengths("utf8_general_ci".length()) - .addLengths("YES".length()).addLengths("".length()).addLengths("NULL".length()) - .addLengths("".length()).addLengths("select,insert,update,references".length()) - .addLengths("".length()).setValues(ByteString.copyFromUtf8( - "trackingidvarcharutf8_general_ciYESNULLselect,insert,update,references"))) - .build()); - Cursor expectedCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("DATA_TYPE").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("COLUMN_SIZE").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("BUFFER_LENGTH").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("DECIMAL_DIGITS").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("NUM_PREC_RADIX").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("NULLABLE").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("COLUMN_DEF").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("SQL_DATA_TYPE").setType(Query.Type.INT32)) - .addFields( - Query.Field.newBuilder().setName("SQL_DATETIME_SUB").setType(Query.Type.INT32)) - .addFields( - Query.Field.newBuilder().setName("CHAR_OCTET_LENGTH").setType(Query.Type.INT32)) - .addFields( - Query.Field.newBuilder().setName("ORDINAL_POSITION").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("ISNULLABLE").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("SCOPE_CATALOG").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("SCOPE_SCHEMA").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("SCOPE_TABLE").setType(Query.Type.CHAR)) - .addFields( - Query.Field.newBuilder().setName("SOURCE_DATA_TYPE").setType(Query.Type.INT16)) - .addFields( - Query.Field.newBuilder().setName("IS_AUTOINCREMENT").setType(Query.Type.CHAR)) - .addFields( - Query.Field.newBuilder().setName("IS_GENERATEDCOLUMN").setType(Query.Type.CHAR)) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths(-1) - .addLengths("sampleTable1".length()).addLengths("shipmentid".length()) - .addLengths("-5".length()).addLengths("BIGINT".length()).addLengths("19".length()) - .addLengths("65535".length()).addLengths("0".length()).addLengths("10".length()) - .addLengths("0".length()).addLengths("Comment".length()).addLengths("NULL".length()) - .addLengths("0".length()).addLengths("0".length()).addLengths("0".length()) - .addLengths("1".length()).addLengths("NO".length()).addLengths(-1).addLengths(-1) - .addLengths(-1).addLengths(-1).addLengths("NO".length()).addLengths("NO".length()) + .addRows( + Query.Row.newBuilder().addLengths("trackingid".length()).addLengths("varchar".length()) + .addLengths("utf8_general_ci".length()).addLengths("YES".length()) + .addLengths("".length()).addLengths("NULL".length()).addLengths("".length()) + .addLengths("select,insert,update,references".length()).addLengths("".length()) .setValues(ByteString.copyFromUtf8( - "TestDB1sampleTable1shipmentid-5BIGINT19655350100CommentNULL0001NONONO"))) - .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths(-1) + "trackingidvarcharutf8_general_ciYESNULLselect,insert,update,references"))) + .build()); + Cursor expectedCursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("DATA_TYPE").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("TYPE_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("COLUMN_SIZE").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("BUFFER_LENGTH").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("DECIMAL_DIGITS").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("NUM_PREC_RADIX").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("NULLABLE").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("REMARKS").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("COLUMN_DEF").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SQL_DATA_TYPE").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("SQL_DATETIME_SUB").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("CHAR_OCTET_LENGTH").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("ORDINAL_POSITION").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("ISNULLABLE").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SCOPE_CATALOG").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SCOPE_SCHEMA").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SCOPE_TABLE").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("SOURCE_DATA_TYPE").setType(Query.Type.INT16)) + .addFields(Query.Field.newBuilder().setName("IS_AUTOINCREMENT").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("IS_GENERATEDCOLUMN").setType(Query.Type.CHAR)) + .addRows(Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths(-1) + .addLengths("sampleTable1".length()).addLengths("shipmentid".length()) + .addLengths("-5".length()).addLengths("BIGINT".length()).addLengths("19".length()) + .addLengths("65535".length()).addLengths("0".length()).addLengths("10".length()) + .addLengths("0".length()).addLengths("Comment".length()).addLengths("NULL".length()) + .addLengths("0".length()).addLengths("0".length()).addLengths("0".length()) + .addLengths("1".length()).addLengths("NO".length()).addLengths(-1).addLengths(-1) + .addLengths(-1).addLengths(-1).addLengths("NO".length()).addLengths("NO".length()) + .setValues(ByteString.copyFromUtf8( + "TestDB1sampleTable1shipmentid-5BIGINT19655350100CommentNULL0001NONONO"))).addRows( + Query.Row.newBuilder().addLengths("TestDB1".length()).addLengths(-1) .addLengths("sampleTable1".length()).addLengths("trackingid".length()) .addLengths("12".length()).addLengths("VARCHAR".length()).addLengths("255".length()) .addLengths("65535".length()).addLengths(-1).addLengths("10".length()) @@ -1129,398 +1222,405 @@ private Cursor getTablesCursor() throws Exception { .addLengths(-1).addLengths(-1).addLengths("NO".length()).addLengths("NO".length()) .setValues(ByteString.copyFromUtf8( "TestDB1sampleTable1trackingid12VARCHAR25565535101CommentNULL002552YESNONO"))) - .build()); - - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(actualCursor)); - - VitessDatabaseMetaData vitessDatabaseMetaData = - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) - .getColumns("TestDB1", null, null, null); - PowerMockito.when(vitessDatabaseMetaData.getTables("TestDB1", null, "%", new String[0])) - .thenReturn(new VitessResultSet(mockedTablecursor)); - ResultSet actualResultSet = vitessDatabaseMetaData.getColumns("TestDB1", null, null, null); - ResultSet expectedResultSet = new VitessResultSet(expectedCursor); - - assertResultSetEquals(actualResultSet, expectedResultSet); - } - - @Test public void getPrimaryKeysTest() throws SQLException, Exception { - - String sql = "SHOW KEYS FROM `shipment` FROM `vt`"; - Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Key_name").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Seq_in_index").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Column_name").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Cardinality").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Sub_part").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Packed").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Index_type").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) - .addFields( - Query.Field.newBuilder().setName("Index_comment").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("shipment".length()).addLengths("0".length()) - .addLengths("PRIMARY".length()).addLengths("1".length()) - .addLengths("shipmentid".length()).addLengths("A".length()) - .addLengths("434880".length()).addLengths(-1).addLengths(-1).addLengths("".length()) - .addLengths("BTREE".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("shipment0PRIMARY1shipmentidA434880BTREE"))) - .build()); - Cursor expectedcursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("KEY_SEQ").setType(Query.Type.INT16)) - .addFields(Query.Field.newBuilder().setName("PK_NAME").setType(Query.Type.CHAR)) - .addRows(Query.Row.newBuilder().addLengths("vt".length()).addLengths(-1) + .build()); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(actualCursor)); + + VitessDatabaseMetaData vitessDatabaseMetaData = PowerMockito + .mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) + .getColumns("TestDB1", null, null, null); + PowerMockito.when(vitessDatabaseMetaData.getTables("TestDB1", null, "%", new String[0])) + .thenReturn(new VitessResultSet(mockedTablecursor)); + ResultSet actualResultSet = vitessDatabaseMetaData.getColumns("TestDB1", null, null, null); + ResultSet expectedResultSet = new VitessResultSet(expectedCursor); + + assertResultSetEquals(actualResultSet, expectedResultSet); + } + + @Test + public void getPrimaryKeysTest() throws SQLException, Exception { + + String sql = "SHOW KEYS FROM `shipment` FROM `vt`"; + Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Key_name").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Seq_in_index").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Column_name").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Cardinality").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Sub_part").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Packed").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Index_type").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Index_comment").setType(Query.Type.VARCHAR)) + .addRows(Query.Row.newBuilder().addLengths("shipment".length()).addLengths("0".length()) + .addLengths("PRIMARY".length()).addLengths("1".length()) + .addLengths("shipmentid".length()).addLengths("A".length()) + .addLengths("434880".length()).addLengths(-1).addLengths(-1).addLengths("".length()) + .addLengths("BTREE".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("shipment0PRIMARY1shipmentidA434880BTREE"))) + .build()); + Cursor expectedcursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("KEY_SEQ").setType(Query.Type.INT16)) + .addFields(Query.Field.newBuilder().setName("PK_NAME").setType(Query.Type.CHAR)).addRows( + Query.Row.newBuilder().addLengths("vt".length()).addLengths(-1) .addLengths("shipment".length()).addLengths("shipmentid".length()) .addLengths("1".length()).addLengths("PRIMARY".length()) .setValues(ByteString.copyFromUtf8("vtshipmentshipmentid1PRIMARY"))).build()); - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - VitessDatabaseMetaData vitessDatabaseMetaData = - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) - .getPrimaryKeys("vt", null, "shipment"); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); - ResultSet expectedResultSet = vitessDatabaseMetaData.getPrimaryKeys("vt", null, "shipment"); - ResultSet actualResultSet = new VitessResultSet(expectedcursor); - - assertResultSetEquals(actualResultSet, expectedResultSet); - } - - @Test public void getIndexInfoTest() throws SQLException, Exception { - - String sql = "SHOW INDEX FROM `shipment` FROM `vt`"; - Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("Table").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Key_name").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Seq_in_index").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Column_name").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Cardinality").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Sub_part").setType(Query.Type.INT64)) - .addFields(Query.Field.newBuilder().setName("Packed").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Index_type").setType(Query.Type.VARCHAR)) - .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) - .addFields( - Query.Field.newBuilder().setName("Index_comment").setType(Query.Type.VARCHAR)) - .addRows(Query.Row.newBuilder().addLengths("shipment".length()).addLengths("0".length()) - .addLengths("PRIMARY".length()).addLengths("1".length()) - .addLengths("shipmentid".length()).addLengths("A".length()) - .addLengths("434880".length()).addLengths(-1).addLengths(-1).addLengths("".length()) - .addLengths("BTREE".length()).addLengths("".length()).addLengths("".length()) - .setValues(ByteString.copyFromUtf8("shipment0PRIMARY1shipmentidA434880BTREE"))) - .build()); - - Cursor expectedcursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.BIT)) - .addFields(Query.Field.newBuilder().setName("INDEX_QUALIFIER").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("INDEX_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("TYPE").setType(Query.Type.INT16)) - .addFields( - Query.Field.newBuilder().setName("ORDINAL_POSITION").setType(Query.Type.INT16)) - .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("ASC_OR_DESC").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("CARDINALITY").setType(Query.Type.INT32)) - .addFields(Query.Field.newBuilder().setName("PAGES").setType(Query.Type.INT32)) - .addFields( - Query.Field.newBuilder().setName("FILTER_CONDITION").setType(Query.Type.CHAR)) - .addRows(Query.Row.newBuilder().addLengths("vt".length()).addLengths(-1) - .addLengths("shipment".length()).addLengths("false".length()) - .addLengths("".length()).addLengths("PRIMARY".length()).addLengths("3".length()) - .addLengths("1".length()).addLengths("shipmentid".length()).addLengths("A".length()) - .addLengths("434880".length()).addLengths("0".length()).addLengths(-1) - .setValues(ByteString.copyFromUtf8("vtshipmentfalsePRIMARY31shipmentidA4348800"))) - .build()); - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - VitessDatabaseMetaData vitessDatabaseMetaData = - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.mock(VitessMySQLDatabaseMetadata.class); - PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) - .getIndexInfo("vt", null, "shipment", true, false); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); - ResultSet actualResultSet = - vitessDatabaseMetaData.getIndexInfo("vt", null, "shipment", true, false); - ResultSet expectedResultSet = new VitessResultSet(expectedcursor); - - assertResultSetEquals(actualResultSet, expectedResultSet); - } - - private void assertResultSetEquals(ResultSet actualResultSet, ResultSet expectedResultSet) - throws SQLException { - ResultSetMetaData actualResultSetMetadata = actualResultSet.getMetaData(); - ResultSetMetaData expectedResultSetMetadata = expectedResultSet.getMetaData(); - //Column Count Comparison - Assert.assertEquals(expectedResultSetMetadata.getColumnCount(), - actualResultSetMetadata.getColumnCount()); - //Column Type Comparison - for (int i = 0; i < expectedResultSetMetadata.getColumnCount(); i++) { - Assert.assertEquals(expectedResultSetMetadata.getColumnType(i + 1), - actualResultSetMetadata.getColumnType(i + 1)); - } - - //Actual Values Comparison - while (expectedResultSet.next() && actualResultSet.next()) { - for (int i = 0; i < expectedResultSetMetadata.getColumnCount(); i++) { - switch (expectedResultSetMetadata.getColumnType(i + 1)) { - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - Assert.assertEquals(expectedResultSet.getInt(i + 1), - actualResultSet.getInt(i + 1)); - break; - case Types.BIGINT: - Assert.assertEquals(expectedResultSet.getLong(i + 1), - actualResultSet.getLong(i + 1)); - break; - case Types.FLOAT: - Assert.assertEquals(expectedResultSet.getFloat(i + 1), - actualResultSet.getFloat(i + 1), 0.1); - break; - case Types.DOUBLE: - Assert.assertEquals(expectedResultSet.getDouble(i + 1), - actualResultSet.getDouble(i + 1), 0.1); - break; - case Types.TIME: - Assert.assertEquals(expectedResultSet.getTime(i + 1), - actualResultSet.getTime(i + 1)); - break; - case Types.TIMESTAMP: - Assert.assertEquals(expectedResultSet.getTimestamp(i + 1), - actualResultSet.getTimestamp(i + 1)); - break; - case Types.DATE: - Assert.assertEquals(expectedResultSet.getDate(i + 1), - actualResultSet.getDate(i + 1)); - break; - case Types.BLOB: - Assert.assertEquals(expectedResultSet.getBlob(i + 1), - actualResultSet.getBlob(i + 1)); - break; - case Types.BINARY: - case Types.LONGVARBINARY: - Assert.assertEquals(expectedResultSet.getBytes(i + 1), - actualResultSet.getBytes(i + 1)); - break; - default: - Assert.assertEquals(expectedResultSet.getString(i + 1), - actualResultSet.getString(i + 1)); - break; - } - } - } - } - - @Test public void getUserNameTest() { - try { - VitessConnection vitessConnection = - new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - VitessDatabaseMetaData vitessDatabaseMetaData = - new VitessMySQLDatabaseMetadata(vitessConnection); - Assert.assertEquals("username", vitessDatabaseMetaData.getUserName()); - - vitessConnection = new VitessConnection("jdbc:vitess://ip1:port1/keyspace", null); - vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); - Assert.assertEquals(null, vitessDatabaseMetaData.getUserName()); - - Properties properties = new Properties(); - properties.put(Constants.Property.USERNAME, "username"); - vitessConnection = new VitessConnection("jdbc:vitess://ip1:port1/keyspace", properties); - vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); - Assert.assertEquals("username", vitessDatabaseMetaData.getUserName()); - - } catch (SQLException e) { - Assert.fail("Exception Occured: " + e.getMessage()); - } - } - - @Test public void testCaseSensitivityIdentifierFuncsMySql() throws Exception { - assertCaseSensitivityForDatabaseType(false); - } - - @Test public void testCaseSensitivityIdentifierFuncsMariaDb() throws Exception { - assertCaseSensitivityForDatabaseType(true); - } - - private void assertCaseSensitivityForDatabaseType(boolean useMariaDb) throws Exception { - VitessConnection connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - mockStatementForLowercaseTablesValue("0", useMariaDb); - Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); - connection.close(); - - connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - mockStatementForLowercaseTablesValue("1", useMariaDb); - Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesLowerCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesMixedCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); - connection.close(); - - connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - mockStatementForLowercaseTablesValue("2", useMariaDb); - Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); - connection.close(); - - connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - mockStatementForLowercaseTablesValue("something random", useMariaDb); - Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); - Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); - Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); - connection.close(); - } - - private void mockStatementForLowercaseTablesValue(String lcTablesValue, boolean useMariaDb) throws Exception { - String sql = "SHOW VARIABLES WHERE VARIABLE_NAME IN (\'tx_isolation\',\'INNODB_VERSION\', \'lower_case_table_names\')"; - String versionName = "innodb_version"; - String versionValue = "5.7.16-10"; - if (useMariaDb) { - versionValue = versionValue + "-mariadb"; + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + VitessDatabaseMetaData vitessDatabaseMetaData = PowerMockito + .mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) + .getPrimaryKeys("vt", null, "shipment"); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + ResultSet expectedResultSet = vitessDatabaseMetaData.getPrimaryKeys("vt", null, "shipment"); + ResultSet actualResultSet = new VitessResultSet(expectedcursor); + + assertResultSetEquals(actualResultSet, expectedResultSet); + } + + @Test + public void getIndexInfoTest() throws SQLException, Exception { + + String sql = "SHOW INDEX FROM `shipment` FROM `vt`"; + Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("Table").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Key_name").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Seq_in_index").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Column_name").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Collation").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Cardinality").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Sub_part").setType(Query.Type.INT64)) + .addFields(Query.Field.newBuilder().setName("Packed").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Null").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Index_type").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Comment").setType(Query.Type.VARCHAR)) + .addFields(Query.Field.newBuilder().setName("Index_comment").setType(Query.Type.VARCHAR)) + .addRows(Query.Row.newBuilder().addLengths("shipment".length()).addLengths("0".length()) + .addLengths("PRIMARY".length()).addLengths("1".length()) + .addLengths("shipmentid".length()).addLengths("A".length()) + .addLengths("434880".length()).addLengths(-1).addLengths(-1).addLengths("".length()) + .addLengths("BTREE".length()).addLengths("".length()).addLengths("".length()) + .setValues(ByteString.copyFromUtf8("shipment0PRIMARY1shipmentidA434880BTREE"))) + .build()); + + Cursor expectedcursor = new SimpleCursor(Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("TABLE_CAT").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_SCHEM").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TABLE_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("Non_unique").setType(Query.Type.BIT)) + .addFields(Query.Field.newBuilder().setName("INDEX_QUALIFIER").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("INDEX_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("TYPE").setType(Query.Type.INT16)) + .addFields(Query.Field.newBuilder().setName("ORDINAL_POSITION").setType(Query.Type.INT16)) + .addFields(Query.Field.newBuilder().setName("COLUMN_NAME").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("ASC_OR_DESC").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("CARDINALITY").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("PAGES").setType(Query.Type.INT32)) + .addFields(Query.Field.newBuilder().setName("FILTER_CONDITION").setType(Query.Type.CHAR)) + .addRows(Query.Row.newBuilder().addLengths("vt".length()).addLengths(-1) + .addLengths("shipment".length()).addLengths("false".length()).addLengths("".length()) + .addLengths("PRIMARY".length()).addLengths("3".length()).addLengths("1".length()) + .addLengths("shipmentid".length()).addLengths("A".length()) + .addLengths("434880".length()).addLengths("0".length()).addLengths(-1) + .setValues(ByteString.copyFromUtf8("vtshipmentfalsePRIMARY31shipmentidA4348800"))) + .build()); + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + VitessDatabaseMetaData vitessDatabaseMetaData = PowerMockito + .mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.mock(VitessMySQLDatabaseMetadata.class); + PowerMockito.doCallRealMethod().when(vitessDatabaseMetaData) + .getIndexInfo("vt", null, "shipment", true, false); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + ResultSet actualResultSet = vitessDatabaseMetaData + .getIndexInfo("vt", null, "shipment", true, false); + ResultSet expectedResultSet = new VitessResultSet(expectedcursor); + + assertResultSetEquals(actualResultSet, expectedResultSet); + } + + private void assertResultSetEquals(ResultSet actualResultSet, ResultSet expectedResultSet) + throws SQLException { + ResultSetMetaData actualResultSetMetadata = actualResultSet.getMetaData(); + ResultSetMetaData expectedResultSetMetadata = expectedResultSet.getMetaData(); + //Column Count Comparison + Assert.assertEquals(expectedResultSetMetadata.getColumnCount(), + actualResultSetMetadata.getColumnCount()); + //Column Type Comparison + for (int i = 0; i < expectedResultSetMetadata.getColumnCount(); i++) { + Assert.assertEquals(expectedResultSetMetadata.getColumnType(i + 1), + actualResultSetMetadata.getColumnType(i + 1)); + } + + //Actual Values Comparison + while (expectedResultSet.next() && actualResultSet.next()) { + for (int i = 0; i < expectedResultSetMetadata.getColumnCount(); i++) { + switch (expectedResultSetMetadata.getColumnType(i + 1)) { + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + Assert.assertEquals(expectedResultSet.getInt(i + 1), actualResultSet.getInt(i + 1)); + break; + case Types.BIGINT: + Assert.assertEquals(expectedResultSet.getLong(i + 1), actualResultSet.getLong(i + 1)); + break; + case Types.FLOAT: + Assert.assertEquals(expectedResultSet.getFloat(i + 1), actualResultSet.getFloat(i + 1), + 0.1); + break; + case Types.DOUBLE: + Assert + .assertEquals(expectedResultSet.getDouble(i + 1), actualResultSet.getDouble(i + 1), + 0.1); + break; + case Types.TIME: + Assert.assertEquals(expectedResultSet.getTime(i + 1), actualResultSet.getTime(i + 1)); + break; + case Types.TIMESTAMP: + Assert.assertEquals(expectedResultSet.getTimestamp(i + 1), + actualResultSet.getTimestamp(i + 1)); + break; + case Types.DATE: + Assert.assertEquals(expectedResultSet.getDate(i + 1), actualResultSet.getDate(i + 1)); + break; + case Types.BLOB: + Assert.assertEquals(expectedResultSet.getBlob(i + 1), actualResultSet.getBlob(i + 1)); + break; + case Types.BINARY: + case Types.LONGVARBINARY: + Assert.assertEquals(expectedResultSet.getBytes(i + 1), actualResultSet.getBytes(i + 1)); + break; + default: + Assert + .assertEquals(expectedResultSet.getString(i + 1), actualResultSet.getString(i + 1)); + break; } - String txIsoName = "tx_isolation"; - String txIsoValue = "REPEATABLE-READ"; - String lcTablesName = "lower_case_table_names"; - - Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("Variable_name").setType(Query.Type.VARCHAR).build()) - .addFields(Query.Field.newBuilder().setName("Value").setType(Query.Type.VARCHAR).build()) - .addRows(Query.Row.newBuilder().addLengths(versionName.length()).addLengths(versionValue.length()).setValues(ByteString.copyFromUtf8(versionName + versionValue))) - .addRows(Query.Row.newBuilder().addLengths(txIsoName.length()).addLengths(txIsoValue.length()).setValues(ByteString.copyFromUtf8(txIsoName + txIsoValue))) - .addRows(Query.Row.newBuilder().addLengths(lcTablesName.length()).addLengths(lcTablesValue.length()).setValues(ByteString.copyFromUtf8(lcTablesName + lcTablesValue))) - .build()); - - VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.when(vitessStatement.executeQuery(sql)) - .thenReturn(new VitessResultSet(mockedCursor)); - } - - /** - * Tests that we're properly stitching together the results of SHOW CREATE TABLE. See {@link #extractForeignKeyForTableTest()} - * for more thorough testing of the actual parsing - */ - @Test public void getImportedKeysTest() throws Exception { - try (InputStream resourceAsStream = this.getClass().getResourceAsStream("/getImportedKeysTestCase.sql")) { - String table = "testA"; - String showCreate = CharStreams.toString(new InputStreamReader(resourceAsStream, Charsets.UTF_8)); - - Query.QueryResult queryResult = Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("Table").setType(Query.Type.CHAR)) - .addFields(Query.Field.newBuilder().setName("Create Table").setType(Query.Type.CHAR)) - .addRows(Query.Row.newBuilder() - .addLengths(table.length()) - .addLengths(showCreate.length()) - .setValues(ByteString.copyFromUtf8(table + showCreate))) - .build(); - - String sql = "SHOW CREATE TABLE `testA`"; - VitessConnection vitessConnection = - new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - VitessStatement vitessStatement = PowerMockito.spy(new VitessStatement(vitessConnection)); - PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); - PowerMockito.doReturn(new VitessResultSet(new SimpleCursor(queryResult), vitessStatement)) - .when(vitessStatement).executeQuery(sql); - - VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); - ResultSet importedKeys = vitessDatabaseMetaData.getImportedKeys("test", "test", "testA"); - importedKeys.next(); - Assert.assertEquals("test", importedKeys.getString("PKTABLE_CAT")); - Assert.assertEquals(null, importedKeys.getString("PKTABLE_SCHEM")); - Assert.assertEquals("fTable", importedKeys.getString("PKTABLE_NAME")); - Assert.assertEquals("id", importedKeys.getString("PKCOLUMN_NAME")); - Assert.assertEquals("test", importedKeys.getString("FKTABLE_CAT")); - Assert.assertEquals(null, importedKeys.getString("FKTABLE_SCHEM")); - Assert.assertEquals("testA", importedKeys.getString("FKTABLE_NAME")); - Assert.assertEquals("fIdOne", importedKeys.getString("FKCOLUMN_NAME")); - Assert.assertEquals(1, importedKeys.getInt("KEY_SEQ")); - Assert.assertEquals(3, importedKeys.getInt("UPDATE_RULE")); - Assert.assertEquals(3, importedKeys.getInt("DELETE_RULE")); - Assert.assertEquals("fk_testA", importedKeys.getString("FK_NAME")); - Assert.assertEquals(null, importedKeys.getString("PK_NAME")); - Assert.assertEquals(7, importedKeys.getInt("DEFERRABILITY")); - } - } - - /** - * Tests parsing all the various outputs of SHOW CREATE TABLE for the foreign key constraints. - */ - @Test public void extractForeignKeyForTableTest() throws SQLException, IOException { - VitessConnection vitessConnection = - new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); - VitessMySQLDatabaseMetadata vitessDatabaseMetaData = - new VitessMySQLDatabaseMetadata(vitessConnection); - - try (InputStream resourceAsStream = this.getClass().getResourceAsStream("/extractForeignKeyForTableTestCases.sql")) { - Scanner scanner = new Scanner(resourceAsStream); - List> rows = new ArrayList<>(); - String testName = null; - String testExpected = null; - String testInput = ""; - String startTag = "-- name: "; - String expectedTag = "-- expected: "; - while (scanner.hasNextLine()) { - String line = scanner.nextLine(); - if (line.startsWith(startTag)) { - if (testName != null) { - rows.clear(); - vitessDatabaseMetaData.extractForeignKeyForTable(rows, testInput, "test", "testA"); - assertForeignKeysOutput(testName, testExpected, rows); - testInput = ""; - } - testName = line.substring(startTag.length()); - } else if (line.startsWith(expectedTag)) { - testExpected = line.substring(expectedTag.length()); - } else if (line.startsWith("--") || line.trim().isEmpty()) { - // Just general comment or whitespace, we can ignore - } else { - testInput += line + "\n"; - } - } - + } + } + } + + @Test + public void getUserNameTest() { + try { + VitessConnection vitessConnection = new VitessConnection( + "jdbc:vitess://username@ip1:port1/keyspace", null); + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + vitessConnection); + Assert.assertEquals("username", vitessDatabaseMetaData.getUserName()); + + vitessConnection = new VitessConnection("jdbc:vitess://ip1:port1/keyspace", null); + vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); + Assert.assertEquals(null, vitessDatabaseMetaData.getUserName()); + + Properties properties = new Properties(); + properties.put(Constants.Property.USERNAME, "username"); + vitessConnection = new VitessConnection("jdbc:vitess://ip1:port1/keyspace", properties); + vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata(vitessConnection); + Assert.assertEquals("username", vitessDatabaseMetaData.getUserName()); + + } catch (SQLException e) { + Assert.fail("Exception Occured: " + e.getMessage()); + } + } + + @Test + public void testCaseSensitivityIdentifierFuncsMySql() throws Exception { + assertCaseSensitivityForDatabaseType(false); + } + + @Test + public void testCaseSensitivityIdentifierFuncsMariaDb() throws Exception { + assertCaseSensitivityForDatabaseType(true); + } + + private void assertCaseSensitivityForDatabaseType(boolean useMariaDb) throws Exception { + VitessConnection connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", + null); + mockStatementForLowercaseTablesValue("0", useMariaDb); + Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); + connection.close(); + + connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); + mockStatementForLowercaseTablesValue("1", useMariaDb); + Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesLowerCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesMixedCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); + connection.close(); + + connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); + mockStatementForLowercaseTablesValue("2", useMariaDb); + Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); + connection.close(); + + connection = new VitessConnection("jdbc:vitess://username@ip1:port1/keyspace", null); + mockStatementForLowercaseTablesValue("something random", useMariaDb); + Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().supportsMixedCaseQuotedIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseIdentifiers()); + Assert.assertEquals(false, connection.getMetaData().storesLowerCaseQuotedIdentifiers()); + Assert.assertEquals(true, connection.getMetaData().storesMixedCaseQuotedIdentifiers()); + connection.close(); + } + + private void mockStatementForLowercaseTablesValue(String lcTablesValue, boolean useMariaDb) + throws Exception { + String sql = "SHOW VARIABLES WHERE VARIABLE_NAME IN (\'tx_isolation\',\'INNODB_VERSION\', " + + "\'lower_case_table_names\')"; + String versionName = "innodb_version"; + String versionValue = "5.7.16-10"; + if (useMariaDb) { + versionValue = versionValue + "-mariadb"; + } + String txIsoName = "tx_isolation"; + String txIsoValue = "REPEATABLE-READ"; + String lcTablesName = "lower_case_table_names"; + + Cursor mockedCursor = new SimpleCursor(Query.QueryResult.newBuilder().addFields( + Query.Field.newBuilder().setName("Variable_name").setType(Query.Type.VARCHAR).build()) + .addFields(Query.Field.newBuilder().setName("Value").setType(Query.Type.VARCHAR).build()) + .addRows(Query.Row.newBuilder().addLengths(versionName.length()) + .addLengths(versionValue.length()) + .setValues(ByteString.copyFromUtf8(versionName + versionValue))).addRows( + Query.Row.newBuilder().addLengths(txIsoName.length()).addLengths(txIsoValue.length()) + .setValues(ByteString.copyFromUtf8(txIsoName + txIsoValue))).addRows( + Query.Row.newBuilder().addLengths(lcTablesName.length()) + .addLengths(lcTablesValue.length()) + .setValues(ByteString.copyFromUtf8(lcTablesName + lcTablesValue))).build()); + + VitessStatement vitessStatement = PowerMockito.mock(VitessStatement.class); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.when(vitessStatement.executeQuery(sql)) + .thenReturn(new VitessResultSet(mockedCursor)); + } + + /** + * Tests that we're properly stitching together the results of SHOW CREATE TABLE. See {@link + * #extractForeignKeyForTableTest()} for more thorough testing of the actual parsing + */ + @Test + public void getImportedKeysTest() throws Exception { + try (InputStream resourceAsStream = this.getClass() + .getResourceAsStream("/getImportedKeysTestCase.sql")) { + String table = "testA"; + String showCreate = CharStreams + .toString(new InputStreamReader(resourceAsStream, Charsets.UTF_8)); + + Query.QueryResult queryResult = Query.QueryResult.newBuilder() + .addFields(Query.Field.newBuilder().setName("Table").setType(Query.Type.CHAR)) + .addFields(Query.Field.newBuilder().setName("Create Table").setType(Query.Type.CHAR)) + .addRows(Query.Row.newBuilder().addLengths(table.length()).addLengths(showCreate.length()) + .setValues(ByteString.copyFromUtf8(table + showCreate))).build(); + + String sql = "SHOW CREATE TABLE `testA`"; + VitessConnection vitessConnection = new VitessConnection( + "jdbc:vitess://username@ip1:port1/keyspace", null); + VitessStatement vitessStatement = PowerMockito.spy(new VitessStatement(vitessConnection)); + PowerMockito.whenNew(VitessStatement.class).withAnyArguments().thenReturn(vitessStatement); + PowerMockito.doReturn(new VitessResultSet(new SimpleCursor(queryResult), vitessStatement)) + .when(vitessStatement).executeQuery(sql); + + VitessDatabaseMetaData vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + vitessConnection); + ResultSet importedKeys = vitessDatabaseMetaData.getImportedKeys("test", "test", "testA"); + importedKeys.next(); + Assert.assertEquals("test", importedKeys.getString("PKTABLE_CAT")); + Assert.assertEquals(null, importedKeys.getString("PKTABLE_SCHEM")); + Assert.assertEquals("fTable", importedKeys.getString("PKTABLE_NAME")); + Assert.assertEquals("id", importedKeys.getString("PKCOLUMN_NAME")); + Assert.assertEquals("test", importedKeys.getString("FKTABLE_CAT")); + Assert.assertEquals(null, importedKeys.getString("FKTABLE_SCHEM")); + Assert.assertEquals("testA", importedKeys.getString("FKTABLE_NAME")); + Assert.assertEquals("fIdOne", importedKeys.getString("FKCOLUMN_NAME")); + Assert.assertEquals(1, importedKeys.getInt("KEY_SEQ")); + Assert.assertEquals(3, importedKeys.getInt("UPDATE_RULE")); + Assert.assertEquals(3, importedKeys.getInt("DELETE_RULE")); + Assert.assertEquals("fk_testA", importedKeys.getString("FK_NAME")); + Assert.assertEquals(null, importedKeys.getString("PK_NAME")); + Assert.assertEquals(7, importedKeys.getInt("DEFERRABILITY")); + } + } + + /** + * Tests parsing all the various outputs of SHOW CREATE TABLE for the foreign key constraints. + */ + @Test + public void extractForeignKeyForTableTest() throws SQLException, IOException { + VitessConnection vitessConnection = new VitessConnection( + "jdbc:vitess://username@ip1:port1/keyspace", null); + VitessMySQLDatabaseMetadata vitessDatabaseMetaData = new VitessMySQLDatabaseMetadata( + vitessConnection); + + try (InputStream resourceAsStream = this.getClass() + .getResourceAsStream("/extractForeignKeyForTableTestCases.sql")) { + Scanner scanner = new Scanner(resourceAsStream); + List> rows = new ArrayList<>(); + String testName = null; + String testExpected = null; + String testInput = ""; + String startTag = "-- name: "; + String expectedTag = "-- expected: "; + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + if (line.startsWith(startTag)) { + if (testName != null) { rows.clear(); - vitessDatabaseMetaData.extractForeignKeyForTable(rows, testExpected, "test", "testA"); + vitessDatabaseMetaData.extractForeignKeyForTable(rows, testInput, "test", "testA"); assertForeignKeysOutput(testName, testExpected, rows); + testInput = ""; + } + testName = line.substring(startTag.length()); + } else if (line.startsWith(expectedTag)) { + testExpected = line.substring(expectedTag.length()); + } else if (line.startsWith("--") || line.trim().isEmpty()) { + // Just general comment or whitespace, we can ignore + } else { + testInput += line + "\n"; } - } - - private void assertForeignKeysOutput(String testName, String expected, List> output) { - // Uncomment below for debugging - //System.out.println("Name: " + testName); - //System.out.println("Expected: " + expected); - //System.out.println("Output: " + String.valueOf(output)); - Assert.assertEquals(testName, expected, String.valueOf(output)); - } + } + + rows.clear(); + vitessDatabaseMetaData.extractForeignKeyForTable(rows, testExpected, "test", "testA"); + assertForeignKeysOutput(testName, testExpected, rows); + } + } + + private void assertForeignKeysOutput(String testName, String expected, + List> output) { + // Uncomment below for debugging + //System.out.println("Name: " + testName); + //System.out.println("Expected: " + expected); + //System.out.println("Output: " + String.valueOf(output)); + Assert.assertEquals(testName, expected, String.valueOf(output)); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessDriverTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessDriverTest.java index 326403f8298..37e5d176215 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessDriverTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessDriverTest.java @@ -16,8 +16,8 @@ package io.vitess.jdbc; -import org.junit.BeforeClass; -import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import io.vitess.util.Constants; @@ -26,91 +26,92 @@ import java.sql.SQLException; import java.util.Properties; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import org.junit.BeforeClass; +import org.junit.Test; /** * Created by harshit.gangal on 19/01/16. */ public class VitessDriverTest { - private static VitessDriver driver = new VitessDriver(); + private static VitessDriver driver = new VitessDriver(); - String dbURL = - "jdbc:vitess://localhost:9000/shipment/vt_shipment?tabletType=master&executeType=stream&userName" - + "=user"; + String dbURL = + "jdbc:vitess://localhost:9000/shipment/vt_shipment?tabletType=master&executeType=stream" + + "&userName" + + "=user"; - @BeforeClass - public static void setUp() { - // load Vitess driver - try { - Class.forName("io.vitess.jdbc.VitessDriver"); - } catch (ClassNotFoundException e) { - fail("Driver is not in the CLASSPATH -> " + e); - } + @BeforeClass + public static void setUp() { + // load Vitess driver + try { + Class.forName("io.vitess.jdbc.VitessDriver"); + } catch (ClassNotFoundException e) { + fail("Driver is not in the CLASSPATH -> " + e); } - - @Test - public void testConnect() throws SQLException { - VitessConnection connection = - (VitessConnection) DriverManager.getConnection(dbURL, new Properties()); - assertEquals(connection.getUrl().getUrl(), dbURL); - } - - @Test - public void testAcceptsURL() { - assertEquals(true, driver.acceptsURL(dbURL)); - } - - @Test - public void testAcceptsMalformedURL() { - String url = - "jdbc:MalfromdedUrl://localhost:9000/shipment/vt_shipment?tabletType=master"; - assertEquals(false, driver.acceptsURL(url)); - } - - @Test - public void testGetPropertyInfo() throws SQLException { - // Used to ensure that we're properly adding the below URL-based properties at the beginning - // of the full ConnectionProperties configuration - DriverPropertyInfo[] underlying = ConnectionProperties.exposeAsDriverPropertyInfo(new Properties(), 0); - - int additionalProp = 2; - DriverPropertyInfo[] driverPropertyInfos = driver.getPropertyInfo(dbURL, null); - assertEquals(underlying.length + additionalProp, driverPropertyInfos.length); - - assertEquals(driverPropertyInfos[0].description, Constants.VITESS_HOST); - assertEquals(driverPropertyInfos[0].required, true); - assertEquals(driverPropertyInfos[0].name, Constants.Property.HOST); - assertEquals(driverPropertyInfos[0].value, "localhost"); - - assertEquals(driverPropertyInfos[1].description, Constants.VITESS_PORT); - assertEquals(driverPropertyInfos[1].required, false); - assertEquals(driverPropertyInfos[1].name, Constants.Property.PORT); - assertEquals(driverPropertyInfos[1].value, "9000"); - - // Validate the remainder of the driver properties match up with the underlying - for (int i = additionalProp; i < driverPropertyInfos.length; i++) { - assertEquals(underlying[i - additionalProp].description, driverPropertyInfos[i].description); - assertEquals(underlying[i - additionalProp].required, driverPropertyInfos[i].required); - assertEquals(underlying[i - additionalProp].name, driverPropertyInfos[i].name); - assertEquals(underlying[i - additionalProp].value, driverPropertyInfos[i].value); - } - } - - @Test - public void testGetMajorVersion() { - assertEquals(driver.getMajorVersion(), Constants.DRIVER_MAJOR_VERSION); - } - - @Test - public void testGetMinorVersion() { - assertEquals(driver.getMinorVersion(), Constants.DRIVER_MINOR_VERSION); - } - - @Test - public void testJdbcCompliant() { - assertEquals(false, driver.jdbcCompliant()); + } + + @Test + public void testConnect() throws SQLException { + VitessConnection connection = (VitessConnection) DriverManager + .getConnection(dbURL, new Properties()); + assertEquals(connection.getUrl().getUrl(), dbURL); + } + + @Test + public void testAcceptsURL() { + assertEquals(true, driver.acceptsURL(dbURL)); + } + + @Test + public void testAcceptsMalformedURL() { + String url = "jdbc:MalfromdedUrl://localhost:9000/shipment/vt_shipment?tabletType=master"; + assertEquals(false, driver.acceptsURL(url)); + } + + @Test + public void testGetPropertyInfo() throws SQLException { + // Used to ensure that we're properly adding the below URL-based properties at the beginning + // of the full ConnectionProperties configuration + DriverPropertyInfo[] underlying = ConnectionProperties + .exposeAsDriverPropertyInfo(new Properties(), 0); + + int additionalProp = 2; + DriverPropertyInfo[] driverPropertyInfos = driver.getPropertyInfo(dbURL, null); + assertEquals(underlying.length + additionalProp, driverPropertyInfos.length); + + assertEquals(driverPropertyInfos[0].description, Constants.VITESS_HOST); + assertEquals(driverPropertyInfos[0].required, true); + assertEquals(driverPropertyInfos[0].name, Constants.Property.HOST); + assertEquals(driverPropertyInfos[0].value, "localhost"); + + assertEquals(driverPropertyInfos[1].description, Constants.VITESS_PORT); + assertEquals(driverPropertyInfos[1].required, false); + assertEquals(driverPropertyInfos[1].name, Constants.Property.PORT); + assertEquals(driverPropertyInfos[1].value, "9000"); + + // Validate the remainder of the driver properties match up with the underlying + for (int i = additionalProp; i < driverPropertyInfos.length; i++) { + assertEquals(underlying[i - additionalProp].description, driverPropertyInfos[i].description); + assertEquals(underlying[i - additionalProp].required, driverPropertyInfos[i].required); + assertEquals(underlying[i - additionalProp].name, driverPropertyInfos[i].name); + assertEquals(underlying[i - additionalProp].value, driverPropertyInfos[i].value); } + } + + @Test + public void testGetMajorVersion() { + assertEquals(driver.getMajorVersion(), Constants.DRIVER_MAJOR_VERSION); + } + + @Test + public void testGetMinorVersion() { + assertEquals(driver.getMinorVersion(), Constants.DRIVER_MINOR_VERSION); + } + + @Test + public void testJdbcCompliant() { + assertEquals(false, driver.jdbcCompliant()); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessJDBCUrlTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessJDBCUrlTest.java index 130d5bedf31..60cb1829107 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessJDBCUrlTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessJDBCUrlTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,220 +16,265 @@ package io.vitess.jdbc; -import org.junit.Assert; -import org.junit.Test; - import io.vitess.proto.Topodata; import io.vitess.util.Constants; import java.sql.SQLException; import java.util.Properties; +import org.junit.Assert; +import org.junit.Test; + /** * Created by naveen.nahata on 18/02/16. */ public class VitessJDBCUrlTest { - @Test public void testURLwithUserNamePwd() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991/keyspace/catalog", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - - @Test public void testURLwithoutUserNamePwd() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://hostname:15991/keyspace/catalog", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals(vitessJDBCUrl.getHostInfos().get(0).getHostname(), "hostname"); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testURLwithUserNamePwdinParams() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://hostname:15991/keyspace/catalog?userName=user&password=password", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testURLwithUserNamePwdinProperties() throws Exception { - Properties info = new Properties(); - info.setProperty("userName", "user"); - info.setProperty("password", "password"); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://hostname:15991/keyspace/catalog", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testURLwithUserNamePwdMultipleHost() throws Exception { - Properties info = new Properties(); - info.setProperty("userName", "user"); - info.setProperty("password", "password"); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://hostname1:15991,hostname2:15991," - + "hostname3:15991/keyspace/catalog?TABLET_TYPE=master", info); - Assert.assertEquals(3, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); - Assert.assertEquals("hostname3", vitessJDBCUrl.getHostInfos().get(2).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(2).getPort()); - Assert.assertEquals(Topodata.TabletType.MASTER.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testMulitpleJDBCURlURLwithUserNamePwdMultipleHost() throws Exception { - Properties info = new Properties(); - info.setProperty("userName", "user"); - info.setProperty("password", "password"); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://hostname1:15991,hostname2:15991,hostname3" - + ":15991/keyspace/catalog?TABLET_TYPE=master", info); - VitessJDBCUrl vitessJDBCUrl1 = new VitessJDBCUrl( - "jdbc:vitess://hostname1:15001,hostname2:15001,hostname3" - + ":15001/keyspace/catalog?TABLET_TYPE=master", info); - Assert.assertEquals(3, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals(3, vitessJDBCUrl1.getHostInfos().size()); - Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("hostname1", vitessJDBCUrl1.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(0).getPort()); - Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); - Assert.assertEquals("hostname2", vitessJDBCUrl1.getHostInfos().get(1).getHostname()); - Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(1).getPort()); - Assert.assertEquals("hostname3", vitessJDBCUrl.getHostInfos().get(2).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(2).getPort()); - Assert.assertEquals("hostname3", vitessJDBCUrl1.getHostInfos().get(2).getHostname()); - Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(2).getPort()); - Assert.assertEquals(Topodata.TabletType.MASTER.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - } - - @Test public void testWithKeyspaceandCatalog() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://user:password@hostname:port/keyspace/catalog", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("keyspace", vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals("catalog", vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - } - - @Test public void testWithKeyspace() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991/keyspace", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals("keyspace", vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals("keyspace", vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - } - - @Test public void testWithoutKeyspace() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = - new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - - vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991/", info); - Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - } - - @Test public void testCompleteURL() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://user:pass@hostname1:15991,hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2", - info); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); - Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); - Assert.assertEquals("keyspace", vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); - Assert.assertEquals("catalog", vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); - Assert.assertEquals("val1", vitessJDBCUrl.getProperties().getProperty("prop1")); - Assert.assertEquals("val2", vitessJDBCUrl.getProperties().getProperty("prop2")); - } - - @Test public void testLeaveOriginalPropertiesAlone() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://user:pass@hostname1:15991,hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2", - info); - - Assert.assertEquals(null, info.getProperty("prop1")); - Assert.assertEquals("val1", vitessJDBCUrl.getProperties().getProperty("prop1")); - } - - @Test public void testPropertiesTakePrecendenceOverUrl() throws SQLException { - Properties info = new Properties(); - info.setProperty("prop1", "val3"); - info.setProperty("prop2", "val4"); - - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://user:pass@hostname1:15991,hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2&prop3=val3", - info); - - Assert.assertEquals("val3", vitessJDBCUrl.getProperties().getProperty("prop1")); - Assert.assertEquals("val4", vitessJDBCUrl.getProperties().getProperty("prop2")); - Assert.assertEquals("val3", vitessJDBCUrl.getProperties().getProperty("prop3")); - } - - @Test public void testJDBCURlURLwithLegacyTabletType() throws Exception { - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://host:12345?TABLET_TYPE=replica", null); - Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE).toUpperCase()); - } - - @Test public void testJDBCURlURLwithNewTabletType() throws Exception { - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://host:12345?tabletType=replica", null); - Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE).toUpperCase()); - } - - @Test public void testJDBCURlURLwithBothTabletType() throws Exception { - //new tablet type should supersede old tablet type. - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://host:12345?TABLET_TYPE=rdonly&tabletType=replica", null); - Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); - Assert.assertEquals(Topodata.TabletType.REPLICA.name(), vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE).toUpperCase()); - } - - @Test public void testCompleteURLWithTarget() throws Exception { - Properties info = new Properties(); - VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( - "jdbc:vitess://user@h1:8080,h2:8081?target=keyspace:-80@replica&prop=val", - info); - Assert.assertEquals("user", vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); - Assert.assertEquals("h1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); - Assert.assertEquals(8080, vitessJDBCUrl.getHostInfos().get(0).getPort()); - Assert.assertEquals("h2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); - Assert.assertEquals(8081, vitessJDBCUrl.getHostInfos().get(1).getPort()); - Assert.assertEquals("keyspace:-80@replica", vitessJDBCUrl.getProperties().getProperty(Constants.Property.TARGET)); - Assert.assertEquals("val", vitessJDBCUrl.getProperties().getProperty("prop")); - } + @Test + public void testURLwithUserNamePwd() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:password@hostname:15991/keyspace/catalog", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + + @Test + public void testURLwithoutUserNamePwd() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://hostname:15991/keyspace/catalog", + info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals(vitessJDBCUrl.getHostInfos().get(0).getHostname(), "hostname"); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert + .assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testURLwithUserNamePwdinParams() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://hostname:15991/keyspace/catalog?userName=user&password=password", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testURLwithUserNamePwdinProperties() throws Exception { + Properties info = new Properties(); + info.setProperty("userName", "user"); + info.setProperty("password", "password"); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://hostname:15991/keyspace/catalog", + info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("hostname", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testURLwithUserNamePwdMultipleHost() throws Exception { + Properties info = new Properties(); + info.setProperty("userName", "user"); + info.setProperty("password", "password"); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://hostname1:15991,hostname2:15991," + + "hostname3:15991/keyspace/catalog?TABLET_TYPE=master", info); + Assert.assertEquals(3, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); + Assert.assertEquals("hostname3", vitessJDBCUrl.getHostInfos().get(2).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(2).getPort()); + Assert.assertEquals(Topodata.TabletType.MASTER.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testMulitpleJDBCURlURLwithUserNamePwdMultipleHost() throws Exception { + Properties info = new Properties(); + info.setProperty("userName", "user"); + info.setProperty("password", "password"); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://hostname1:15991,hostname2:15991,hostname3" + + ":15991/keyspace/catalog?TABLET_TYPE=master", info); + VitessJDBCUrl vitessJDBCUrl1 = new VitessJDBCUrl( + "jdbc:vitess://hostname1:15001,hostname2:15001,hostname3" + + ":15001/keyspace/catalog?TABLET_TYPE=master", info); + Assert.assertEquals(3, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals(3, vitessJDBCUrl1.getHostInfos().size()); + Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("hostname1", vitessJDBCUrl1.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(0).getPort()); + Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); + Assert.assertEquals("hostname2", vitessJDBCUrl1.getHostInfos().get(1).getHostname()); + Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(1).getPort()); + Assert.assertEquals("hostname3", vitessJDBCUrl.getHostInfos().get(2).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(2).getPort()); + Assert.assertEquals("hostname3", vitessJDBCUrl1.getHostInfos().get(2).getHostname()); + Assert.assertEquals(15001, vitessJDBCUrl1.getHostInfos().get(2).getPort()); + Assert.assertEquals(Topodata.TabletType.MASTER.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + } + + @Test + public void testWithKeyspaceandCatalog() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:password@hostname:port/keyspace/catalog", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("keyspace", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals("catalog", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + } + + @Test + public void testWithKeyspace() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:password@hostname:15991/keyspace", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert.assertEquals("keyspace", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals("keyspace", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + } + + @Test + public void testWithoutKeyspace() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991", + info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert + .assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + + vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://user:password@hostname:15991/", info); + Assert.assertEquals(1, vitessJDBCUrl.getHostInfos().size()); + Assert + .assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals(null, vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + } + + @Test + public void testCompleteURL() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:pass@hostname1:15991," + + "hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2", + info); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + Assert.assertEquals("hostname1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("hostname2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); + Assert.assertEquals(15991, vitessJDBCUrl.getHostInfos().get(1).getPort()); + Assert.assertEquals("keyspace", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.KEYSPACE)); + Assert.assertEquals("catalog", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.DBNAME)); + Assert.assertEquals("val1", vitessJDBCUrl.getProperties().getProperty("prop1")); + Assert.assertEquals("val2", vitessJDBCUrl.getProperties().getProperty("prop2")); + } + + @Test + public void testLeaveOriginalPropertiesAlone() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:pass@hostname1:15991," + + "hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2", + info); + + Assert.assertEquals(null, info.getProperty("prop1")); + Assert.assertEquals("val1", vitessJDBCUrl.getProperties().getProperty("prop1")); + } + + @Test + public void testPropertiesTakePrecendenceOverUrl() throws SQLException { + Properties info = new Properties(); + info.setProperty("prop1", "val3"); + info.setProperty("prop2", "val4"); + + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user:pass@hostname1:15991," + + "hostname2:15991/keyspace/catalog?prop1=val1&prop2=val2&prop3=val3", + info); + + Assert.assertEquals("val3", vitessJDBCUrl.getProperties().getProperty("prop1")); + Assert.assertEquals("val4", vitessJDBCUrl.getProperties().getProperty("prop2")); + Assert.assertEquals("val3", vitessJDBCUrl.getProperties().getProperty("prop3")); + } + + @Test + public void testJDBCURlURLwithLegacyTabletType() throws Exception { + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://host:12345?TABLET_TYPE=replica", + null); + Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE) + .toUpperCase()); + } + + @Test + public void testJDBCURlURLwithNewTabletType() throws Exception { + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl("jdbc:vitess://host:12345?tabletType=replica", + null); + Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE) + .toUpperCase()); + } + + @Test + public void testJDBCURlURLwithBothTabletType() throws Exception { + //new tablet type should supersede old tablet type. + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://host:12345?TABLET_TYPE=rdonly&tabletType=replica", null); + Assert.assertEquals("host", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(12345, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TABLET_TYPE).toUpperCase()); + Assert.assertEquals(Topodata.TabletType.REPLICA.name(), + vitessJDBCUrl.getProperties().getProperty(Constants.Property.OLD_TABLET_TYPE) + .toUpperCase()); + } + + @Test + public void testCompleteURLWithTarget() throws Exception { + Properties info = new Properties(); + VitessJDBCUrl vitessJDBCUrl = new VitessJDBCUrl( + "jdbc:vitess://user@h1:8080,h2:8081?target=keyspace:-80@replica&prop=val", info); + Assert.assertEquals("user", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.USERNAME)); + Assert.assertEquals("h1", vitessJDBCUrl.getHostInfos().get(0).getHostname()); + Assert.assertEquals(8080, vitessJDBCUrl.getHostInfos().get(0).getPort()); + Assert.assertEquals("h2", vitessJDBCUrl.getHostInfos().get(1).getHostname()); + Assert.assertEquals(8081, vitessJDBCUrl.getHostInfos().get(1).getPort()); + Assert.assertEquals("keyspace:-80@replica", + vitessJDBCUrl.getProperties().getProperty(Constants.Property.TARGET)); + Assert.assertEquals("val", vitessJDBCUrl.getProperties().getProperty("prop")); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessParameterMetaDataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessParameterMetaDataTest.java index 57212aa40d5..a7374dfe47c 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessParameterMetaDataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessParameterMetaDataTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,6 +16,10 @@ package io.vitess.jdbc; +import java.sql.ParameterMetaData; +import java.sql.SQLException; +import java.sql.Types; + import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; @@ -24,67 +28,68 @@ import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; -import java.sql.ParameterMetaData; -import java.sql.SQLException; -import java.sql.Types; - @RunWith(PowerMockRunner.class) @PrepareForTest(VitessParameterMetaData.class) public class VitessParameterMetaDataTest { - @Test - public void testValidSimpleResponses() throws SQLException { - VitessParameterMetaData metaData = new VitessParameterMetaData(5); - Assert.assertEquals("parameterCount", 5, metaData.getParameterCount()); - Assert.assertEquals("parameterMode", ParameterMetaData.parameterModeIn, metaData.getParameterMode(2)); - Assert.assertEquals("parameterType", Types.VARCHAR, metaData.getParameterType(2)); - Assert.assertEquals("precision", 0, metaData.getPrecision(2)); - Assert.assertEquals("scale", 0, metaData.getScale(2)); - Assert.assertEquals("parameterClassName", "java.lang.String", metaData.getParameterClassName(2)); - Assert.assertEquals("parameterTypeName", "VARCHAR", metaData.getParameterTypeName(2)); - Assert.assertEquals("signed", false, metaData.isSigned(2)); - } + @Test + public void testValidSimpleResponses() throws SQLException { + VitessParameterMetaData metaData = new VitessParameterMetaData(5); + Assert.assertEquals("parameterCount", 5, metaData.getParameterCount()); + Assert.assertEquals("parameterMode", ParameterMetaData.parameterModeIn, + metaData.getParameterMode(2)); + Assert.assertEquals("parameterType", Types.VARCHAR, metaData.getParameterType(2)); + Assert.assertEquals("precision", 0, metaData.getPrecision(2)); + Assert.assertEquals("scale", 0, metaData.getScale(2)); + Assert + .assertEquals("parameterClassName", "java.lang.String", metaData.getParameterClassName(2)); + Assert.assertEquals("parameterTypeName", "VARCHAR", metaData.getParameterTypeName(2)); + Assert.assertEquals("signed", false, metaData.isSigned(2)); + } - @Test - public void testOutOfBoundsValidation() { - int parameterCount = 1; - VitessParameterMetaData metaData = new VitessParameterMetaData(parameterCount); + @Test + public void testOutOfBoundsValidation() { + int parameterCount = 1; + VitessParameterMetaData metaData = new VitessParameterMetaData(parameterCount); - try { - metaData.getParameterType(0); - Assert.fail(); - } catch (SQLException e) { - Assert.assertEquals("Parameter index of '0' is invalid.", e.getMessage()); - } + try { + metaData.getParameterType(0); + Assert.fail(); + } catch (SQLException e) { + Assert.assertEquals("Parameter index of '0' is invalid.", e.getMessage()); + } - int paramNumber = 2; - try { - metaData.getParameterType(paramNumber); - Assert.fail(); - } catch (SQLException e) { - Assert.assertEquals("Parameter index of '" + paramNumber + "' is greater than number of parameters, which is '" + parameterCount + "'.", e.getMessage()); - } + int paramNumber = 2; + try { + metaData.getParameterType(paramNumber); + Assert.fail(); + } catch (SQLException e) { + Assert.assertEquals("Parameter index of '" + paramNumber + + "' is greater than number of parameters, which is '" + parameterCount + "'.", + e.getMessage()); } + } - @Test - public void testOutOfBoundCoverage() throws Exception { - int param = 2; - VitessParameterMetaData metaData = PowerMockito.spy(new VitessParameterMetaData(5)); + @Test + public void testOutOfBoundCoverage() throws Exception { + int param = 2; + VitessParameterMetaData metaData = PowerMockito.spy(new VitessParameterMetaData(5)); - metaData.getParameterType(param); - metaData.getPrecision(param); - metaData.getScale(param); - metaData.getParameterClassName(param); - metaData.getParameterTypeName(param); - metaData.isSigned(param); + metaData.getParameterType(param); + metaData.getPrecision(param); + metaData.getScale(param); + metaData.getParameterClassName(param); + metaData.getParameterTypeName(param); + metaData.isSigned(param); - PowerMockito.verifyPrivate(metaData, VerificationModeFactory.times(6)).invoke("checkBounds", param); - } + PowerMockito.verifyPrivate(metaData, VerificationModeFactory.times(6)) + .invoke("checkBounds", param); + } - @Test(expected = SQLException.class) - public void testNullableNotAvailable() throws SQLException { - VitessParameterMetaData metaData = new VitessParameterMetaData(5); - metaData.isNullable(3); - Assert.fail(); - } + @Test(expected = SQLException.class) + public void testNullableNotAvailable() throws SQLException { + VitessParameterMetaData metaData = new VitessParameterMetaData(5); + metaData.isNullable(3); + Assert.fail(); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessPreparedStatementTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessPreparedStatementTest.java index 95512fd6f8d..8d89e4daeea 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessPreparedStatementTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessPreparedStatementTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,15 +16,15 @@ package io.vitess.jdbc; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyMap; +import static org.mockito.Matchers.anyString; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; + import com.google.common.collect.ImmutableMap; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Matchers; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import io.vitess.client.Context; import io.vitess.client.SQLFuture; @@ -37,7 +37,6 @@ import io.vitess.proto.Vtrpc; import io.vitess.util.Constants; -import javax.sql.rowset.serial.SerialClob; import java.lang.reflect.Field; import java.math.BigDecimal; import java.math.BigInteger; @@ -55,707 +54,696 @@ import java.util.Map; import java.util.TimeZone; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyMap; -import static org.mockito.Matchers.anyString; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.when; +import javax.sql.rowset.serial.SerialClob; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; /** * Created by harshit.gangal on 09/02/16. */ -@RunWith(PowerMockRunner.class) @PrepareForTest({VTGateConnection.class, - Vtrpc.RPCError.class}) public class VitessPreparedStatementTest { - - private String sqlSelect = "select 1 from test_table"; - private String sqlShow = "show tables"; - private String sqlUpdate = "update test_table set msg = null"; - private String sqlInsert = "insert into test_table(msg) values (?)"; - - @Test public void testStatementExecute() { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement preparedStatement; - try { - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - preparedStatement.executeQuery(sqlSelect); - fail("Should have thrown exception for calling this method"); - } catch (SQLException ex) { - assertEquals("This method cannot be called using this class object", - ex.getMessage()); - } - - try { - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - preparedStatement.executeUpdate(sqlUpdate); - fail("Should have thrown exception for calling this method"); - } catch (SQLException ex) { - assertEquals("This method cannot be called using this class object", - ex.getMessage()); - } - - try { - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - preparedStatement.execute(sqlShow); - fail("Should have thrown exception for calling this method"); - } catch (SQLException ex) { - assertEquals("This method cannot be called using this class object", - ex.getMessage()); - } +@RunWith(PowerMockRunner.class) +@PrepareForTest({VTGateConnection.class, Vtrpc.RPCError.class}) +public class VitessPreparedStatementTest { + + private String sqlSelect = "select 1 from test_table"; + private String sqlShow = "show tables"; + private String sqlUpdate = "update test_table set msg = null"; + private String sqlInsert = "insert into test_table(msg) values (?)"; + + @Test + public void testStatementExecute() { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement preparedStatement; + try { + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + preparedStatement.executeQuery(sqlSelect); + fail("Should have thrown exception for calling this method"); + } catch (SQLException ex) { + assertEquals("This method cannot be called using this class object", ex.getMessage()); } - @Test public void testExecuteQuery() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(),any(VTSession.class))). - thenReturn(mockSqlFutureCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.SIMPLE); - when(mockConn.isSimpleExecute()).thenReturn(true); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - - VitessPreparedStatement preparedStatement; - try { - - //Empty Sql Statement - try { - new VitessPreparedStatement(mockConn, ""); - fail("Should have thrown exception for empty sql"); - } catch (SQLException ex) { - assertEquals("SQL statement is not valid", ex.getMessage()); - } - - //show query - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - ResultSet rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - //select on replica with bind variables - preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - //select on replica without bind variables - preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - - //select on master - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - try { - //when returned cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - preparedStatement.executeQuery(); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + try { + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + preparedStatement.executeUpdate(sqlUpdate); + fail("Should have thrown exception for calling this method"); + } catch (SQLException ex) { + assertEquals("This method cannot be called using this class object", ex.getMessage()); } - @Test public void testExecuteQueryWithStream() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockCursor); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.STREAM); - - VitessPreparedStatement preparedStatement; - try { - - //Empty Sql Statement - try { - new VitessPreparedStatement(mockConn, ""); - fail("Should have thrown exception for empty sql"); - } catch (SQLException ex) { - assertEquals("SQL statement is not valid", ex.getMessage()); - } - - //show query - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - ResultSet rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - //select on replica with bind variables - preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - //select on replica without bind variables - preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - - //select on master - rs = preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - try { - //when returned cursor is null - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(null); - preparedStatement.executeQuery(); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + try { + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + preparedStatement.execute(sqlShow); + fail("Should have thrown exception for calling this method"); + } catch (SQLException ex) { + assertEquals("This method cannot be called using this class object", ex.getMessage()); } - - - @Test public void testExecuteUpdate() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - List fieldList = mock(ArrayList.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessPreparedStatement preparedStatement; - try { - - //executing dml on master - preparedStatement = - new VitessPreparedStatement(mockConn, sqlUpdate, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - int updateCount = preparedStatement.executeUpdate(); - assertEquals(0, updateCount); - - //tx is null & autoCommit is true - when(mockConn.getAutoCommit()).thenReturn(true); - preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate); - updateCount = preparedStatement.executeUpdate(); - assertEquals(0, updateCount); - - //cursor fields is not null - when(mockCursor.getFields()).thenReturn(fieldList); - when(fieldList.isEmpty()).thenReturn(false); - try { - preparedStatement.executeUpdate(); - fail("Should have thrown exception for field not null"); - } catch (SQLException ex) { - assertEquals("ResultSet generation is not allowed through this method", - ex.getMessage()); - } - - //cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - preparedStatement.executeUpdate(); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - //read only - when(mockConn.isReadOnly()).thenReturn(true); - try { - preparedStatement.executeUpdate(); - fail("Should have thrown exception for read only"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); - } - - //read only - when(mockConn.isReadOnly()).thenReturn(true); - try { - preparedStatement.executeBatch(); - fail("Should have thrown exception for read only"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + } + + @Test + public void testExecuteQuery() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))). + thenReturn(mockSqlFutureCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.SIMPLE); + when(mockConn.isSimpleExecute()).thenReturn(true); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + + VitessPreparedStatement preparedStatement; + try { + + //Empty Sql Statement + try { + new VitessPreparedStatement(mockConn, ""); + fail("Should have thrown exception for empty sql"); + } catch (SQLException ex) { + assertEquals("SQL statement is not valid", ex.getMessage()); + } + + //show query + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + ResultSet rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on replica with bind variables + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on replica without bind variables + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on master + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + try { + //when returned cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + preparedStatement.executeQuery(); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testExecute() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - List mockFieldList = PowerMockito.spy(new ArrayList<>()); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + } + + @Test + public void testExecuteQueryWithStream() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockCursor); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.STREAM); + + VitessPreparedStatement preparedStatement; + try { + + //Empty Sql Statement + try { + new VitessPreparedStatement(mockConn, ""); + fail("Should have thrown exception for empty sql"); + } catch (SQLException ex) { + assertEquals("SQL statement is not valid", ex.getMessage()); + } + + //show query + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + ResultSet rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on replica with bind variables + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on replica without bind variables + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + //select on master + rs = preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + try { + //when returned cursor is null when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.SIMPLE); - when(mockConn.isSimpleExecute()).thenReturn(true); - - when(mockConn.getAutoCommit()).thenReturn(true); - - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(mockFieldList); - - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect, ResultSet.TYPE_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); - try { - - int fieldSize = 5; - when(mockCursor.getFields()).thenReturn(mockFieldList); - PowerMockito.doReturn(fieldSize).when(mockFieldList).size(); - PowerMockito.doReturn(false).when(mockFieldList).isEmpty(); - boolean hasResultSet = preparedStatement.execute(); - Assert.assertTrue(hasResultSet); - Assert.assertNotNull(preparedStatement.getResultSet()); - - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - hasResultSet = preparedStatement.execute(); - Assert.assertTrue(hasResultSet); - Assert.assertNotNull(preparedStatement.getResultSet()); - - int mockUpdateCount = 10; - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - when(mockCursor.getRowsAffected()).thenReturn((long) mockUpdateCount); - preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate); - hasResultSet = preparedStatement.execute(); - Assert.assertFalse(hasResultSet); - Assert.assertNull(preparedStatement.getResultSet()); - assertEquals(mockUpdateCount, preparedStatement.getUpdateCount()); - - //cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); - preparedStatement.execute(); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(null); + preparedStatement.executeQuery(); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testExecuteFetchSizeAsStreaming() throws SQLException { - testExecute(5, true, false, true); - testExecute(5, false, false, true); - testExecute(0, true, true, false); - testExecute(0, false, false, true); + } + + + @Test + public void testExecuteUpdate() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + List fieldList = mock(ArrayList.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessPreparedStatement preparedStatement; + try { + + //executing dml on master + preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + int updateCount = preparedStatement.executeUpdate(); + assertEquals(0, updateCount); + + //tx is null & autoCommit is true + when(mockConn.getAutoCommit()).thenReturn(true); + preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate); + updateCount = preparedStatement.executeUpdate(); + assertEquals(0, updateCount); + + //cursor fields is not null + when(mockCursor.getFields()).thenReturn(fieldList); + when(fieldList.isEmpty()).thenReturn(false); + try { + preparedStatement.executeUpdate(); + fail("Should have thrown exception for field not null"); + } catch (SQLException ex) { + assertEquals("ResultSet generation is not allowed through this method", ex.getMessage()); + } + + //cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + preparedStatement.executeUpdate(); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); + } + + //read only + when(mockConn.isReadOnly()).thenReturn(true); + try { + preparedStatement.executeUpdate(); + fail("Should have thrown exception for read only"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); + } + + //read only + when(mockConn.isReadOnly()).thenReturn(true); + try { + preparedStatement.executeBatch(); + fail("Should have thrown exception for read only"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRunExecute, boolean shouldRunStreamExecute) throws SQLException { - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - - VitessConnection mockConn = mock(VitessConnection.class); - when(mockConn.isSimpleExecute()).thenReturn(simpleExecute); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockCursor); - - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlSelect); - statement.setFetchSize(fetchSize); - statement.executeQuery(); - - if (shouldRunExecute) { - Mockito.verify(mockVtGateConn, Mockito.times(2)).execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class)); - } - - if (shouldRunStreamExecute) { - Mockito.verify(mockVtGateConn).streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class)); - } + } + + @Test + public void testExecute() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + List mockFieldList = PowerMockito.spy(new ArrayList<>()); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.SIMPLE); + when(mockConn.isSimpleExecute()).thenReturn(true); + + when(mockConn.getAutoCommit()).thenReturn(true); + + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(mockFieldList); + + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect, + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + try { + + int fieldSize = 5; + when(mockCursor.getFields()).thenReturn(mockFieldList); + PowerMockito.doReturn(fieldSize).when(mockFieldList).size(); + PowerMockito.doReturn(false).when(mockFieldList).isEmpty(); + boolean hasResultSet = preparedStatement.execute(); + Assert.assertTrue(hasResultSet); + Assert.assertNotNull(preparedStatement.getResultSet()); + + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + hasResultSet = preparedStatement.execute(); + Assert.assertTrue(hasResultSet); + Assert.assertNotNull(preparedStatement.getResultSet()); + + int mockUpdateCount = 10; + when(mockCursor.getFields()) + .thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + when(mockCursor.getRowsAffected()).thenReturn((long) mockUpdateCount); + preparedStatement = new VitessPreparedStatement(mockConn, sqlUpdate); + hasResultSet = preparedStatement.execute(); + Assert.assertFalse(hasResultSet); + Assert.assertNull(preparedStatement.getResultSet()); + assertEquals(mockUpdateCount, preparedStatement.getUpdateCount()); + + //cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + preparedStatement = new VitessPreparedStatement(mockConn, sqlShow); + preparedStatement.execute(); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testGetUpdateCount() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFuture = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFuture); - when(mockSqlFuture.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect); - try { - - when(mockCursor.getRowsAffected()).thenReturn(10L); - int updateCount = preparedStatement.executeUpdate(); - assertEquals(10L, updateCount); - assertEquals(10L, preparedStatement.getUpdateCount()); - - // Truncated Update Count - when(mockCursor.getRowsAffected()) - .thenReturn((long) Integer.MAX_VALUE + 10); - updateCount = preparedStatement.executeUpdate(); - assertEquals(Integer.MAX_VALUE, updateCount); - assertEquals(Integer.MAX_VALUE, preparedStatement.getUpdateCount()); - - when(mockConn.isSimpleExecute()).thenReturn(true); - preparedStatement.executeQuery(); - assertEquals(-1, preparedStatement.getUpdateCount()); - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + } + + @Test + public void testExecuteFetchSizeAsStreaming() throws SQLException { + testExecute(5, true, false, true); + testExecute(5, false, false, true); + testExecute(0, true, true, false); + testExecute(0, false, false, true); + } + + private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRunExecute, + boolean shouldRunStreamExecute) throws SQLException { + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + + VitessConnection mockConn = mock(VitessConnection.class); + when(mockConn.isSimpleExecute()).thenReturn(simpleExecute); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockCursor); + + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlSelect); + statement.setFetchSize(fetchSize); + statement.executeQuery(); + + if (shouldRunExecute) { + Mockito.verify(mockVtGateConn, Mockito.times(2)) + .execute(any(Context.class), anyString(), anyMap(), any(VTSession.class)); } - @Test public void testSetParameters() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - Mockito.when(mockConn.getTreatUtilDateAsTimestamp()).thenReturn(true); - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect); - Boolean boolValue = true; - Byte byteValue = Byte.MAX_VALUE; - Short shortValue = Short.MAX_VALUE; - Integer intValue = Integer.MAX_VALUE; - Long longValue = Long.MAX_VALUE; - Float floatValue = Float.MAX_VALUE; - Double doubleValue = Double.MAX_VALUE; - BigDecimal bigDecimalValue = new BigDecimal(3.14159265358979323846); - BigDecimal expectedDecimalValue = new BigDecimal("3.14159"); - BigInteger bigIntegerValue = new BigInteger("18446744073709551615"); - String stringValue = "vitess"; - byte[] bytesValue = stringValue.getBytes(); - Date dateValue = new Date(0); - // Use a time value that won't go negative after adjusting for time zone. - // The java.sql.Time class does not properly format negative times. - Time timeValue = new Time(12 * 60 * 60 * 1000); - Timestamp timestampValue = new Timestamp(0); - - preparedStatement.setNull(1, Types.INTEGER); - preparedStatement.setBoolean(2, boolValue); - preparedStatement.setByte(3, byteValue); - preparedStatement.setShort(4, shortValue); - preparedStatement.setInt(5, intValue); - preparedStatement.setLong(6, longValue); - preparedStatement.setFloat(7, floatValue); - preparedStatement.setDouble(8, doubleValue); - preparedStatement.setBigDecimal(9, bigDecimalValue); - preparedStatement.setBigInteger(10, bigIntegerValue); - preparedStatement.setString(11, stringValue); - preparedStatement.setBytes(12, bytesValue); - preparedStatement.setDate(13, dateValue); - preparedStatement.setTime(14, timeValue); - preparedStatement.setTimestamp(15, timestampValue); - preparedStatement.setDate(16, dateValue, Calendar.getInstance(TimeZone.getDefault())); - preparedStatement.setTime(17, timeValue, Calendar.getInstance(TimeZone.getDefault())); - preparedStatement - .setTimestamp(18, timestampValue, Calendar.getInstance(TimeZone.getDefault())); - preparedStatement.setObject(19, boolValue); - preparedStatement.setObject(20, byteValue); - preparedStatement.setObject(21, shortValue); - preparedStatement.setObject(22, intValue); - preparedStatement.setObject(23, longValue); - preparedStatement.setObject(24, floatValue); - preparedStatement.setObject(25, doubleValue); - preparedStatement.setObject(26, bigDecimalValue); - preparedStatement.setObject(27, bigIntegerValue); - preparedStatement.setObject(28, stringValue); - preparedStatement.setObject(29, dateValue); - preparedStatement.setObject(30, timeValue); - preparedStatement.setObject(31, timestampValue); - preparedStatement.setObject(32, 'a'); - preparedStatement.setObject(33, null); - preparedStatement.setObject(34, boolValue, Types.BOOLEAN, 0); - preparedStatement.setObject(35, shortValue, Types.SMALLINT, 0); - preparedStatement.setObject(36, longValue, Types.BIGINT, 0); - preparedStatement.setObject(37, floatValue, Types.DOUBLE, 2); - preparedStatement.setObject(38, doubleValue, Types.DOUBLE, 3); - preparedStatement.setObject(39, bigDecimalValue, Types.DECIMAL, 5); - preparedStatement.setObject(40, stringValue, Types.VARCHAR, 0); - preparedStatement.setObject(41, dateValue, Types.DATE, 0); - preparedStatement.setObject(42, timeValue, Types.TIME, 0); - preparedStatement.setObject(43, timestampValue, Types.TIMESTAMP, 0); - preparedStatement.setClob(44, new SerialClob("clob".toCharArray())); - preparedStatement.setObject(45, bytesValue); - Field bindVariablesMap = preparedStatement.getClass().getDeclaredField("bindVariables"); - bindVariablesMap.setAccessible(true); - Map bindVariables = - (Map) bindVariablesMap.get(preparedStatement); - assertEquals(null, bindVariables.get("v1")); - assertEquals(boolValue, bindVariables.get("v2")); - assertEquals(byteValue, bindVariables.get("v3")); - assertEquals(shortValue, bindVariables.get("v4")); - assertEquals(intValue, bindVariables.get("v5")); - assertEquals(longValue, bindVariables.get("v6")); - assertEquals(floatValue, bindVariables.get("v7")); - assertEquals(doubleValue, bindVariables.get("v8")); - assertEquals(bigDecimalValue, bindVariables.get("v9")); - assertEquals(bigIntegerValue, bindVariables.get("v10")); - assertEquals(stringValue, bindVariables.get("v11")); - assertEquals(bytesValue, bindVariables.get("v12")); - assertEquals(dateValue.toString(), bindVariables.get("v13")); - assertEquals(timeValue.toString(), bindVariables.get("v14")); - assertEquals(timestampValue.toString(), bindVariables.get("v15")); - assertEquals(dateValue.toString(), bindVariables.get("v16")); - assertEquals(timeValue.toString(), bindVariables.get("v17")); - assertEquals(timestampValue.toString(), bindVariables.get("v18")); - assertEquals(boolValue, bindVariables.get("v19")); - assertEquals(byteValue, bindVariables.get("v20")); - assertEquals(shortValue, bindVariables.get("v21")); - assertEquals(intValue, bindVariables.get("v22")); - assertEquals(longValue, bindVariables.get("v23")); - assertEquals(floatValue, bindVariables.get("v24")); - assertEquals(doubleValue, bindVariables.get("v25")); - assertEquals(bigDecimalValue, bindVariables.get("v26")); - assertEquals(bigIntegerValue, bindVariables.get("v27")); - assertEquals(stringValue, bindVariables.get("v28")); - assertEquals(dateValue.toString(), bindVariables.get("v29")); - assertEquals(timeValue.toString(), bindVariables.get("v30")); - assertEquals(timestampValue.toString(), bindVariables.get("v31")); - assertEquals("a", bindVariables.get("v32")); - assertEquals(null, bindVariables.get("v33")); - assertEquals(true, bindVariables.get("v34")); - assertEquals(shortValue.intValue(), bindVariables.get("v35")); - assertEquals(longValue, bindVariables.get("v36")); - assertEquals((double) floatValue, (double) bindVariables.get("v37"), 0.1); - assertEquals(doubleValue, (double) bindVariables.get("v38"), 0.1); - assertEquals(expectedDecimalValue, bindVariables.get("v39")); - assertEquals(stringValue, bindVariables.get("v40")); - assertEquals(dateValue.toString(), bindVariables.get("v41")); - assertEquals(timeValue.toString(), bindVariables.get("v42")); - assertEquals(timestampValue.toString(), bindVariables.get("v43")); - assertEquals("clob", bindVariables.get("v44")); - Assert.assertArrayEquals(bytesValue, (byte[])bindVariables.get("v45")); - - preparedStatement.clearParameters(); + if (shouldRunStreamExecute) { + Mockito.verify(mockVtGateConn) + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class)); } - - @Test public void testTreatUtilDateAsTimestamp() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlSelect); - - java.util.Date utilDateValue = new java.util.Date(System.currentTimeMillis()); - Timestamp timestamp = new Timestamp(utilDateValue.getTime()); - try { - preparedStatement.setObject(1, utilDateValue); - fail("setObject on java.util.Date should have failed with SQLException"); - } catch (SQLException e) { - Assert.assertTrue(e.getMessage().startsWith(Constants.SQLExceptionMessages.SQL_TYPE_INFER)); - } - - preparedStatement.clearParameters(); - - Mockito.when(mockConn.getTreatUtilDateAsTimestamp()).thenReturn(true); - preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); - preparedStatement.setObject(1, utilDateValue); - - Field bindVariablesMap = preparedStatement.getClass().getDeclaredField("bindVariables"); - bindVariablesMap.setAccessible(true); - Map bindVariables = - (Map) bindVariablesMap.get(preparedStatement); - - assertEquals(DateTime.formatTimestamp(timestamp), bindVariables.get("v1")); + } + + @Test + public void testGetUpdateCount() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFuture = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFuture); + when(mockSqlFuture.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); + try { + + when(mockCursor.getRowsAffected()).thenReturn(10L); + int updateCount = preparedStatement.executeUpdate(); + assertEquals(10L, updateCount); + assertEquals(10L, preparedStatement.getUpdateCount()); + + // Truncated Update Count + when(mockCursor.getRowsAffected()).thenReturn((long) Integer.MAX_VALUE + 10); + updateCount = preparedStatement.executeUpdate(); + assertEquals(Integer.MAX_VALUE, updateCount); + assertEquals(Integer.MAX_VALUE, preparedStatement.getUpdateCount()); + + when(mockConn.isSimpleExecute()).thenReturn(true); + preparedStatement.executeQuery(); + assertEquals(-1, preparedStatement.getUpdateCount()); + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testAutoGeneratedKeys() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - try { - - long expectedFirstGeneratedId = 121; - long[] expectedGeneratedIds = {121, 122}; - int expectedAffectedRows = 2; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - when(mockCursor.getRowsAffected()) - .thenReturn(Long.valueOf(expectedAffectedRows)); - - //Executing Insert Statement - VitessPreparedStatement preparedStatement = - new VitessPreparedStatement(mockConn, sqlInsert, Statement.RETURN_GENERATED_KEYS); - int updateCount = preparedStatement.executeUpdate(); - assertEquals(expectedAffectedRows, updateCount); - - ResultSet rs = preparedStatement.getGeneratedKeys(); - int i = 0; - while (rs.next()) { - long generatedId = rs.getLong(1); - assertEquals(expectedGeneratedIds[i++], generatedId); - } - - } catch (SQLException e) { - fail("Test failed " + e.getMessage()); - } + } + + @Test + public void testSetParameters() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + Mockito.when(mockConn.getTreatUtilDateAsTimestamp()).thenReturn(true); + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); + Boolean boolValue = true; + Byte byteValue = Byte.MAX_VALUE; + Short shortValue = Short.MAX_VALUE; + Integer intValue = Integer.MAX_VALUE; + Long longValue = Long.MAX_VALUE; + Float floatValue = Float.MAX_VALUE; + Double doubleValue = Double.MAX_VALUE; + BigDecimal bigDecimalValue = new BigDecimal(3.14159265358979323846); + BigDecimal expectedDecimalValue = new BigDecimal("3.14159"); + BigInteger bigIntegerValue = new BigInteger("18446744073709551615"); + String stringValue = "vitess"; + byte[] bytesValue = stringValue.getBytes(); + Date dateValue = new Date(0); + // Use a time value that won't go negative after adjusting for time zone. + // The java.sql.Time class does not properly format negative times. + Time timeValue = new Time(12 * 60 * 60 * 1000); + Timestamp timestampValue = new Timestamp(0); + + preparedStatement.setNull(1, Types.INTEGER); + preparedStatement.setBoolean(2, boolValue); + preparedStatement.setByte(3, byteValue); + preparedStatement.setShort(4, shortValue); + preparedStatement.setInt(5, intValue); + preparedStatement.setLong(6, longValue); + preparedStatement.setFloat(7, floatValue); + preparedStatement.setDouble(8, doubleValue); + preparedStatement.setBigDecimal(9, bigDecimalValue); + preparedStatement.setBigInteger(10, bigIntegerValue); + preparedStatement.setString(11, stringValue); + preparedStatement.setBytes(12, bytesValue); + preparedStatement.setDate(13, dateValue); + preparedStatement.setTime(14, timeValue); + preparedStatement.setTimestamp(15, timestampValue); + preparedStatement.setDate(16, dateValue, Calendar.getInstance(TimeZone.getDefault())); + preparedStatement.setTime(17, timeValue, Calendar.getInstance(TimeZone.getDefault())); + preparedStatement.setTimestamp(18, timestampValue, Calendar.getInstance(TimeZone.getDefault())); + preparedStatement.setObject(19, boolValue); + preparedStatement.setObject(20, byteValue); + preparedStatement.setObject(21, shortValue); + preparedStatement.setObject(22, intValue); + preparedStatement.setObject(23, longValue); + preparedStatement.setObject(24, floatValue); + preparedStatement.setObject(25, doubleValue); + preparedStatement.setObject(26, bigDecimalValue); + preparedStatement.setObject(27, bigIntegerValue); + preparedStatement.setObject(28, stringValue); + preparedStatement.setObject(29, dateValue); + preparedStatement.setObject(30, timeValue); + preparedStatement.setObject(31, timestampValue); + preparedStatement.setObject(32, 'a'); + preparedStatement.setObject(33, null); + preparedStatement.setObject(34, boolValue, Types.BOOLEAN, 0); + preparedStatement.setObject(35, shortValue, Types.SMALLINT, 0); + preparedStatement.setObject(36, longValue, Types.BIGINT, 0); + preparedStatement.setObject(37, floatValue, Types.DOUBLE, 2); + preparedStatement.setObject(38, doubleValue, Types.DOUBLE, 3); + preparedStatement.setObject(39, bigDecimalValue, Types.DECIMAL, 5); + preparedStatement.setObject(40, stringValue, Types.VARCHAR, 0); + preparedStatement.setObject(41, dateValue, Types.DATE, 0); + preparedStatement.setObject(42, timeValue, Types.TIME, 0); + preparedStatement.setObject(43, timestampValue, Types.TIMESTAMP, 0); + preparedStatement.setClob(44, new SerialClob("clob".toCharArray())); + preparedStatement.setObject(45, bytesValue); + Field bindVariablesMap = preparedStatement.getClass().getDeclaredField("bindVariables"); + bindVariablesMap.setAccessible(true); + Map bindVariables = (Map) bindVariablesMap + .get(preparedStatement); + assertEquals(null, bindVariables.get("v1")); + assertEquals(boolValue, bindVariables.get("v2")); + assertEquals(byteValue, bindVariables.get("v3")); + assertEquals(shortValue, bindVariables.get("v4")); + assertEquals(intValue, bindVariables.get("v5")); + assertEquals(longValue, bindVariables.get("v6")); + assertEquals(floatValue, bindVariables.get("v7")); + assertEquals(doubleValue, bindVariables.get("v8")); + assertEquals(bigDecimalValue, bindVariables.get("v9")); + assertEquals(bigIntegerValue, bindVariables.get("v10")); + assertEquals(stringValue, bindVariables.get("v11")); + assertEquals(bytesValue, bindVariables.get("v12")); + assertEquals(dateValue.toString(), bindVariables.get("v13")); + assertEquals(timeValue.toString(), bindVariables.get("v14")); + assertEquals(timestampValue.toString(), bindVariables.get("v15")); + assertEquals(dateValue.toString(), bindVariables.get("v16")); + assertEquals(timeValue.toString(), bindVariables.get("v17")); + assertEquals(timestampValue.toString(), bindVariables.get("v18")); + assertEquals(boolValue, bindVariables.get("v19")); + assertEquals(byteValue, bindVariables.get("v20")); + assertEquals(shortValue, bindVariables.get("v21")); + assertEquals(intValue, bindVariables.get("v22")); + assertEquals(longValue, bindVariables.get("v23")); + assertEquals(floatValue, bindVariables.get("v24")); + assertEquals(doubleValue, bindVariables.get("v25")); + assertEquals(bigDecimalValue, bindVariables.get("v26")); + assertEquals(bigIntegerValue, bindVariables.get("v27")); + assertEquals(stringValue, bindVariables.get("v28")); + assertEquals(dateValue.toString(), bindVariables.get("v29")); + assertEquals(timeValue.toString(), bindVariables.get("v30")); + assertEquals(timestampValue.toString(), bindVariables.get("v31")); + assertEquals("a", bindVariables.get("v32")); + assertEquals(null, bindVariables.get("v33")); + assertEquals(true, bindVariables.get("v34")); + assertEquals(shortValue.intValue(), bindVariables.get("v35")); + assertEquals(longValue, bindVariables.get("v36")); + assertEquals((double) floatValue, (double) bindVariables.get("v37"), 0.1); + assertEquals(doubleValue, (double) bindVariables.get("v38"), 0.1); + assertEquals(expectedDecimalValue, bindVariables.get("v39")); + assertEquals(stringValue, bindVariables.get("v40")); + assertEquals(dateValue.toString(), bindVariables.get("v41")); + assertEquals(timeValue.toString(), bindVariables.get("v42")); + assertEquals(timestampValue.toString(), bindVariables.get("v43")); + assertEquals("clob", bindVariables.get("v44")); + Assert.assertArrayEquals(bytesValue, (byte[]) bindVariables.get("v45")); + + preparedStatement.clearParameters(); + } + + @Test + public void testTreatUtilDateAsTimestamp() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); + + java.util.Date utilDateValue = new java.util.Date(System.currentTimeMillis()); + Timestamp timestamp = new Timestamp(utilDateValue.getTime()); + try { + preparedStatement.setObject(1, utilDateValue); + fail("setObject on java.util.Date should have failed with SQLException"); + } catch (SQLException e) { + Assert.assertTrue(e.getMessage().startsWith(Constants.SQLExceptionMessages.SQL_TYPE_INFER)); } - @Test public void testAddBatch() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); - try { - statement.addBatch(this.sqlInsert); - fail("Should have thrown Exception"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED, ex.getMessage()); - } - statement.setString(1, "string1"); - statement.addBatch(); - try { - Field privateStringField = - VitessPreparedStatement.class.getDeclaredField("batchedArgs"); - privateStringField.setAccessible(true); - assertEquals("string1", - (((List>) privateStringField.get(statement)).get(0)).get("v1")); - } catch (NoSuchFieldException e) { - fail("Private Field should exists: batchedArgs"); - } catch (IllegalAccessException e) { - fail("Private Field should be accessible: batchedArgs"); - } + preparedStatement.clearParameters(); + + Mockito.when(mockConn.getTreatUtilDateAsTimestamp()).thenReturn(true); + preparedStatement = new VitessPreparedStatement(mockConn, sqlSelect); + preparedStatement.setObject(1, utilDateValue); + + Field bindVariablesMap = preparedStatement.getClass().getDeclaredField("bindVariables"); + bindVariablesMap.setAccessible(true); + Map bindVariables = (Map) bindVariablesMap + .get(preparedStatement); + + assertEquals(DateTime.formatTimestamp(timestamp), bindVariables.get("v1")); + } + + @Test + public void testAutoGeneratedKeys() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + try { + + long expectedFirstGeneratedId = 121; + long[] expectedGeneratedIds = {121, 122}; + int expectedAffectedRows = 2; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedAffectedRows)); + + //Executing Insert Statement + VitessPreparedStatement preparedStatement = new VitessPreparedStatement(mockConn, sqlInsert, + Statement.RETURN_GENERATED_KEYS); + int updateCount = preparedStatement.executeUpdate(); + assertEquals(expectedAffectedRows, updateCount); + + ResultSet rs = preparedStatement.getGeneratedKeys(); + int i = 0; + while (rs.next()) { + long generatedId = rs.getLong(1); + assertEquals(expectedGeneratedIds[i++], generatedId); + } + + } catch (SQLException e) { + fail("Test failed " + e.getMessage()); } - - @Test public void testClearBatch() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); - statement.setString(1, "string1"); - statement.addBatch(); - statement.clearBatch(); - try { - Field privateStringField = - VitessPreparedStatement.class.getDeclaredField("batchedArgs"); - privateStringField.setAccessible(true); - Assert.assertTrue( - ((List>) privateStringField.get(statement)).isEmpty()); - } catch (NoSuchFieldException e) { - fail("Private Field should exists: batchedArgs"); - } catch (IllegalAccessException e) { - fail("Private Field should be accessible: batchedArgs"); - } + } + + @Test + public void testAddBatch() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); + try { + statement.addBatch(this.sqlInsert); + fail("Should have thrown Exception"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED, ex.getMessage()); } - - @Test public void testExecuteBatch() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); - int[] updateCounts = statement.executeBatch(); - assertEquals(0, updateCounts.length); - - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockConn.getAutoCommit()).thenReturn(true); - - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - when(mockVtGateConn - .executeBatch(any(Context.class), Matchers.anyList(), Matchers.anyList(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - - List mockCursorWithErrorList = new ArrayList<>(); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); - - CursorWithError mockCursorWithError1 = mock(CursorWithError.class); - when(mockCursorWithError1.getError()).thenReturn(null); - when(mockCursorWithError1.getCursor()) - .thenReturn(mock(Cursor.class)); - mockCursorWithErrorList.add(mockCursorWithError1); - - statement.setString(1, "string1"); - statement.addBatch(); - updateCounts = statement.executeBatch(); - assertEquals(1, updateCounts.length); - - CursorWithError mockCursorWithError2 = mock(CursorWithError.class); - Vtrpc.RPCError rpcError = Vtrpc.RPCError.newBuilder().setMessage("preparedStatement execute batch error").build(); - when(mockCursorWithError2.getError()) - .thenReturn(rpcError); - mockCursorWithErrorList.add(mockCursorWithError2); - statement.setString(1, "string1"); - statement.addBatch(); - statement.setString(1, "string2"); - statement.addBatch(); - try { - statement.executeBatch(); - fail("Should have thrown Exception"); - } catch (BatchUpdateException ex) { - assertEquals(rpcError.toString(), ex.getMessage()); - assertEquals(2, ex.getUpdateCounts().length); - assertEquals(Statement.EXECUTE_FAILED, ex.getUpdateCounts()[1]); - } + statement.setString(1, "string1"); + statement.addBatch(); + try { + Field privateStringField = VitessPreparedStatement.class.getDeclaredField("batchedArgs"); + privateStringField.setAccessible(true); + assertEquals("string1", + (((List>) privateStringField.get(statement)).get(0)).get("v1")); + } catch (NoSuchFieldException e) { + fail("Private Field should exists: batchedArgs"); + } catch (IllegalAccessException e) { + fail("Private Field should be accessible: batchedArgs"); } - - @Test public void testStatementCount() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - Map testCases = ImmutableMap.builder() - .put("select * from foo where a = ?", 1) - .put("select * from foo where a = ? and b = ?", 2) - .put("select * from foo where a = ? and b = \"?\"", 1) - .put("select * from foo where a = ? and b = '?'", 1) - .put("select * from foo where a = ? and b = `?`", 1) - .put("select foo.*, `bar.baz?` from foo, bar where foo.a = ? and bar.b = foo.b", 1) - .put("select * from foo where a = ? and b = \"`?`\"", 1) - .put("select * from foo where a = ? --and b = ?", 1) - .put("select * from foo where a = ? /* and b = ? */ and c = ?", 2) - .put("/* leading comment? */ select * from foo where a = ? and b = ?", 2) - .put("select * from foo where a = ? and b = ? and c = 'test' and d = ?", 3) - .put("select * from foo where a = ? and b = \\`?\\`", 2) // not valid sql but validates escaping - .put("select * from foo where a = ? and b = \\?", 1) // not valid sql but validates escaping - .put("update foo set a = ?, b = ? where c = 'test' and d = ?", 3) - .put("insert into foo (`a`, `b`) values (?, ?), (?, ?) on /* test? */ duplicate key update a = \"?\"", 4) - .put("delete from foo where a = ? and b = '?'", 1) - .build(); - - for (Map.Entry testCase : testCases.entrySet()) { - VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, testCase.getKey()); - assertEquals(testCase.getKey(), testCase.getValue().longValue(), statement.getParameterMetaData().getParameterCount()); - } + } + + @Test + public void testClearBatch() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); + statement.setString(1, "string1"); + statement.addBatch(); + statement.clearBatch(); + try { + Field privateStringField = VitessPreparedStatement.class.getDeclaredField("batchedArgs"); + privateStringField.setAccessible(true); + Assert.assertTrue(((List>) privateStringField.get(statement)).isEmpty()); + } catch (NoSuchFieldException e) { + fail("Private Field should exists: batchedArgs"); + } catch (IllegalAccessException e) { + fail("Private Field should be accessible: batchedArgs"); + } + } + + @Test + public void testExecuteBatch() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, sqlInsert); + int[] updateCounts = statement.executeBatch(); + assertEquals(0, updateCounts.length); + + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockConn.getAutoCommit()).thenReturn(true); + + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + when(mockVtGateConn.executeBatch(any(Context.class), Matchers.anyList(), Matchers.anyList(), + any(VTSession.class))).thenReturn(mockSqlFutureCursor); + + List mockCursorWithErrorList = new ArrayList<>(); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); + + CursorWithError mockCursorWithError1 = mock(CursorWithError.class); + when(mockCursorWithError1.getError()).thenReturn(null); + when(mockCursorWithError1.getCursor()).thenReturn(mock(Cursor.class)); + mockCursorWithErrorList.add(mockCursorWithError1); + + statement.setString(1, "string1"); + statement.addBatch(); + updateCounts = statement.executeBatch(); + assertEquals(1, updateCounts.length); + + CursorWithError mockCursorWithError2 = mock(CursorWithError.class); + Vtrpc.RPCError rpcError = Vtrpc.RPCError.newBuilder() + .setMessage("preparedStatement execute batch error").build(); + when(mockCursorWithError2.getError()).thenReturn(rpcError); + mockCursorWithErrorList.add(mockCursorWithError2); + statement.setString(1, "string1"); + statement.addBatch(); + statement.setString(1, "string2"); + statement.addBatch(); + try { + statement.executeBatch(); + fail("Should have thrown Exception"); + } catch (BatchUpdateException ex) { + assertEquals(rpcError.toString(), ex.getMessage()); + assertEquals(2, ex.getUpdateCounts().length); + assertEquals(Statement.EXECUTE_FAILED, ex.getUpdateCounts()[1]); + } + } + + @Test + public void testStatementCount() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + Map testCases = ImmutableMap.builder() + .put("select * from foo where a = ?", 1).put("select * from foo where a = ? and b = ?", 2) + .put("select * from foo where a = ? and b = \"?\"", 1) + .put("select * from foo where a = ? and b = '?'", 1) + .put("select * from foo where a = ? and b = `?`", 1) + .put("select foo.*, `bar.baz?` from foo, bar where foo.a = ? and bar.b = foo.b", 1) + .put("select * from foo where a = ? and b = \"`?`\"", 1) + .put("select * from foo where a = ? --and b = ?", 1) + .put("select * from foo where a = ? /* and b = ? */ and c = ?", 2) + .put("/* leading comment? */ select * from foo where a = ? and b = ?", 2) + .put("select * from foo where a = ? and b = ? and c = 'test' and d = ?", 3) + .put("select * from foo where a = ? and b = \\`?\\`", + 2) // not valid sql but validates escaping + .put("select * from foo where a = ? and b = \\?", 1) // not valid sql but validates escaping + .put("update foo set a = ?, b = ? where c = 'test' and d = ?", 3).put( + "insert into foo (`a`, `b`) values (?, ?), (?, ?) on /* test? */ duplicate key update" + + " a = \"?\"", + 4).put("delete from foo where a = ? and b = '?'", 1).build(); + + for (Map.Entry testCase : testCases.entrySet()) { + VitessPreparedStatement statement = new VitessPreparedStatement(mockConn, testCase.getKey()); + assertEquals(testCase.getKey(), testCase.getValue().longValue(), + statement.getParameterMetaData().getParameterCount()); } + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetMetadataTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetMetadataTest.java index 3ac7be7b5eb..4ce4146d97e 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetMetadataTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetMetadataTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,9 +16,6 @@ package io.vitess.jdbc; -import org.junit.Assert; -import org.junit.Test; - import io.vitess.proto.Query; import io.vitess.util.Constants; import io.vitess.util.charset.CharsetMapping; @@ -29,533 +26,640 @@ import java.util.ArrayList; import java.util.List; +import org.junit.Assert; +import org.junit.Test; + /** * Created by ashudeep.sharma on 08/02/16. */ public class VitessResultSetMetadataTest extends BaseTest { - private List fieldList; - - private List generateFieldList() { - List fieldList = new ArrayList<>(); - - fieldList.add(field("col1", "tbl", Query.Type.INT8, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.NOT_NULL_FLAG_VALUE).setOrgName("foo").setOrgTable("foo").build()); - fieldList.add(field("col2", "tbl", Query.Type.UINT8, 3, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col3", "tbl", Query.Type.INT16, 6, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col4", "tbl", Query.Type.UINT16, 5, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col5", "tbl", Query.Type.INT24, 9, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col6", "tbl", Query.Type.UINT24, 8, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col7", "tbl", Query.Type.INT32, 11, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col8", "tbl", Query.Type.UINT32, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col9", "tbl", Query.Type.INT64, 20, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col10", "tbl", Query.Type.UINT64, 20, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); - fieldList.add(field("col11", "tbl", Query.Type.FLOAT32, 12, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setDecimals(31).build()); - fieldList.add(field("col12", "tbl", Query.Type.FLOAT64, 22, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setDecimals(31).build()); - fieldList.add(field("col13", "tbl", Query.Type.TIMESTAMP, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col14", "tbl", Query.Type.DATE, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col15", "tbl", Query.Type.TIME, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col16", "tbl", Query.Type.DATETIME, 19, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col17", "tbl", Query.Type.YEAR, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col18", "tbl", Query.Type.DECIMAL, 7, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setDecimals(2).build()); - fieldList.add(field("col19", "tbl", Query.Type.TEXT, 765, /* utf8_bin -- not case insensitive */ 83).build()); - fieldList.add(field("col20", "tbl", Query.Type.BLOB, 65535, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + private List fieldList; + + private List generateFieldList() { + List fieldList = new ArrayList<>(); + + fieldList.add( + field("col1", "tbl", Query.Type.INT8, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.NOT_NULL_FLAG_VALUE).setOrgName("foo").setOrgTable("foo") + .build()); + fieldList.add( + field("col2", "tbl", Query.Type.UINT8, 3, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col3", "tbl", Query.Type.INT16, 6, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col4", "tbl", Query.Type.UINT16, 5, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col5", "tbl", Query.Type.INT24, 9, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col6", "tbl", Query.Type.UINT24, 8, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col7", "tbl", Query.Type.INT32, 11, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col8", "tbl", Query.Type.UINT32, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col9", "tbl", Query.Type.INT64, 20, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col10", "tbl", Query.Type.UINT64, 20, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.UNSIGNED_FLAG_VALUE).build()); + fieldList.add( + field("col11", "tbl", Query.Type.FLOAT32, 12, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setDecimals(31).build()); + fieldList.add( + field("col12", "tbl", Query.Type.FLOAT64, 22, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setDecimals(31).build()); + fieldList.add( + field("col13", "tbl", Query.Type.TIMESTAMP, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col14", "tbl", Query.Type.DATE, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col15", "tbl", Query.Type.TIME, 10, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col16", "tbl", Query.Type.DATETIME, 19, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col17", "tbl", Query.Type.YEAR, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col18", "tbl", Query.Type.DECIMAL, 7, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setDecimals(2).build()); + fieldList.add( + field("col19", "tbl", Query.Type.TEXT, 765, /* utf8_bin -- not case insensitive */ 83) + .build()); + fieldList.add( + field("col20", "tbl", Query.Type.BLOB, 65535, CharsetMapping.MYSQL_COLLATION_INDEX_binary) .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE | Query.MySqlFlag.BLOB_FLAG_VALUE) - .setDecimals(/* this is set to facilitate testing of getScale, since this is non-numeric */2).build()); - fieldList.add(field("col21", "tbl", Query.Type.VARCHAR, 768, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col22", "tbl", Query.Type.VARBINARY, 256, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build()); - fieldList.add(field("col23", "tbl", Query.Type.CHAR, 48, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col24", "tbl", Query.Type.BINARY, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build()); - fieldList.add(field("col25", "tbl", Query.Type.BIT, 8, CharsetMapping.MYSQL_COLLATION_INDEX_binary).build()); - fieldList.add(field("col26", "tbl", Query.Type.ENUM, 3, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col27", "tbl", Query.Type.SET, 9, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col28", "tbl", Query.Type.TUPLE, 0, CharsetMapping.MYSQL_COLLATION_INDEX_utf8).build()); - fieldList.add(field("col29", "tbl", Query.Type.VARBINARY, 256, CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build()); - fieldList.add(field("col30", "tbl", Query.Type.BLOB, 65535, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .setDecimals(/* this is set to facilitate testing of getScale, since this is + non-numeric */ + 2).build()); + fieldList.add( + field("col21", "tbl", Query.Type.VARCHAR, 768, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add(field("col22", "tbl", Query.Type.VARBINARY, 256, + CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) + .build()); + fieldList.add( + field("col23", "tbl", Query.Type.CHAR, 48, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add( + field("col24", "tbl", Query.Type.BINARY, 4, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).build()); + fieldList.add( + field("col25", "tbl", Query.Type.BIT, 8, CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .build()); + fieldList.add( + field("col26", "tbl", Query.Type.ENUM, 3, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add( + field("col27", "tbl", Query.Type.SET, 9, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add( + field("col28", "tbl", Query.Type.TUPLE, 0, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) + .build()); + fieldList.add(field("col29", "tbl", Query.Type.VARBINARY, 256, + CharsetMapping.MYSQL_COLLATION_INDEX_binary).setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) + .build()); + fieldList.add( + field("col30", "tbl", Query.Type.BLOB, 65535, CharsetMapping.MYSQL_COLLATION_INDEX_utf8) .setFlags(Query.MySqlFlag.BLOB_FLAG_VALUE).build()); - return fieldList; + return fieldList; + } + + private Query.Field.Builder field(String name, String table, Query.Type type, int length, + int charset) { + return Query.Field.newBuilder().setName(name).setTable(table).setType(type) + .setColumnLength(length).setCharset(charset); + } + + private void initializeFieldList(VitessConnection connection) throws SQLException { + List fields = generateFieldList(); + this.fieldList = new ArrayList<>(fields.size()); + for (Query.Field field : fields) { + this.fieldList.add(new FieldWithMetadata(connection, field)); } + } - private Query.Field.Builder field(String name, String table, Query.Type type, int length, int charset) { - return Query.Field.newBuilder() - .setName(name) - .setTable(table) - .setType(type) - .setColumnLength(length) - .setCharset(charset); - } - - private void initializeFieldList(VitessConnection connection) throws SQLException { - List fields = generateFieldList(); - this.fieldList = new ArrayList<>(fields.size()); - for (Query.Field field : fields) { - this.fieldList.add(new FieldWithMetadata(connection, field)); - } - } - - public List getFieldList() throws SQLException { - return getFieldList(getVitessConnection()); - } - - public List getFieldList(VitessConnection conn) throws SQLException { - initializeFieldList(conn); - return this.fieldList; - } + public List getFieldList() throws SQLException { + return getFieldList(getVitessConnection()); + } - @Test public void testgetColumnCount() throws SQLException { + public List getFieldList(VitessConnection conn) throws SQLException { + initializeFieldList(conn); + return this.fieldList; + } - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals(30, vitessResultSetMetadata.getColumnCount()); - } + @Test + public void testgetColumnCount() throws SQLException { - @Test public void testgetColumnName() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals(30, vitessResultSetMetadata.getColumnCount()); + } - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - for (int i = 1; i <= vitessResultSetMetadata.getColumnCount(); i++) { - Assert.assertEquals("col" + i, vitessResultSetMetadata.getColumnName(i)); - } - } + @Test + public void testgetColumnName() throws SQLException { - @Test public void testgetColumnTypeName() throws SQLException { - - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("TINYINT", vitessResultSetMetadata.getColumnTypeName(1)); - Assert.assertEquals("TINYINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(2)); - Assert.assertEquals("SMALLINT", vitessResultSetMetadata.getColumnTypeName(3)); - Assert.assertEquals("SMALLINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(4)); - Assert.assertEquals("MEDIUMINT", vitessResultSetMetadata.getColumnTypeName(5)); - Assert.assertEquals("MEDIUMINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(6)); - Assert.assertEquals("INT", vitessResultSetMetadata.getColumnTypeName(7)); - Assert.assertEquals("INT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(8)); - Assert.assertEquals("BIGINT", vitessResultSetMetadata.getColumnTypeName(9)); - Assert.assertEquals("BIGINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(10)); - Assert.assertEquals("FLOAT", vitessResultSetMetadata.getColumnTypeName(11)); - Assert.assertEquals("DOUBLE", vitessResultSetMetadata.getColumnTypeName(12)); - Assert.assertEquals("TIMESTAMP", vitessResultSetMetadata.getColumnTypeName(13)); - Assert.assertEquals("DATE", vitessResultSetMetadata.getColumnTypeName(14)); - Assert.assertEquals("TIME", vitessResultSetMetadata.getColumnTypeName(15)); - Assert.assertEquals("DATETIME", vitessResultSetMetadata.getColumnTypeName(16)); - Assert.assertEquals("YEAR", vitessResultSetMetadata.getColumnTypeName(17)); - Assert.assertEquals("DECIMAL", vitessResultSetMetadata.getColumnTypeName(18)); - Assert.assertEquals("TEXT", vitessResultSetMetadata.getColumnTypeName(19)); - Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(20)); - Assert.assertEquals("VARCHAR", vitessResultSetMetadata.getColumnTypeName(21)); - Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(22)); - Assert.assertEquals("CHAR", vitessResultSetMetadata.getColumnTypeName(23)); - Assert.assertEquals("BINARY", vitessResultSetMetadata.getColumnTypeName(24)); - Assert.assertEquals("BIT", vitessResultSetMetadata.getColumnTypeName(25)); - Assert.assertEquals("ENUM", vitessResultSetMetadata.getColumnTypeName(26)); - Assert.assertEquals("SET", vitessResultSetMetadata.getColumnTypeName(27)); - Assert.assertEquals("TUPLE", vitessResultSetMetadata.getColumnTypeName(28)); - Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(29)); - Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(30)); + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + for (int i = 1; i <= vitessResultSetMetadata.getColumnCount(); i++) { + Assert.assertEquals("col" + i, vitessResultSetMetadata.getColumnName(i)); } - - @Test public void testgetColumnType() throws SQLException { - - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("TINYINT", Types.TINYINT, vitessResultSetMetadata.getColumnType(1)); - Assert.assertEquals("TINYINT", Types.TINYINT, vitessResultSetMetadata.getColumnType(2)); - Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(3)); - Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(4)); - Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(5)); - Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(6)); - Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(7)); - Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(8)); - Assert.assertEquals("BIGINT", Types.BIGINT, vitessResultSetMetadata.getColumnType(9)); - Assert.assertEquals("BIGINT", Types.BIGINT, vitessResultSetMetadata.getColumnType(10)); - Assert.assertEquals("FLOAT", Types.FLOAT, vitessResultSetMetadata.getColumnType(11)); - Assert.assertEquals("DOUBLE", Types.DOUBLE, vitessResultSetMetadata.getColumnType(12)); - Assert.assertEquals("TIMESTAMP", Types.TIMESTAMP, vitessResultSetMetadata.getColumnType(13)); - Assert.assertEquals("DATE", Types.DATE, vitessResultSetMetadata.getColumnType(14)); - Assert.assertEquals("TIME", Types.TIME, vitessResultSetMetadata.getColumnType(15)); - Assert.assertEquals("TIMESTAMP", Types.TIMESTAMP, vitessResultSetMetadata.getColumnType(16)); - Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(17)); - Assert.assertEquals("DECIMAL", Types.DECIMAL, vitessResultSetMetadata.getColumnType(18)); - Assert.assertEquals("VARCHAR", Types.VARCHAR, vitessResultSetMetadata.getColumnType(19)); - Assert.assertEquals("LONGVARBINARY", Types.LONGVARBINARY, vitessResultSetMetadata.getColumnType(20)); - Assert.assertEquals("VARCHAR", Types.VARCHAR, vitessResultSetMetadata.getColumnType(21)); - Assert.assertEquals("VARBINARY", Types.VARBINARY, vitessResultSetMetadata.getColumnType(22)); - Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(23)); - Assert.assertEquals("BINARY", Types.BINARY, vitessResultSetMetadata.getColumnType(24)); - Assert.assertEquals("BIT", Types.BIT, vitessResultSetMetadata.getColumnType(25)); - Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(26)); - Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(27)); - Assert.assertEquals("VARBINARY", Types.VARBINARY, vitessResultSetMetadata.getColumnType(29)); - Assert.assertEquals("LONGVARCHAR", Types.LONGVARCHAR, vitessResultSetMetadata.getColumnType(30)); - try { - int type = vitessResultSetMetadata.getColumnType(28); - } catch (SQLException ex) { - Assert - .assertEquals(Constants.SQLExceptionMessages.INVALID_COLUMN_TYPE, ex.getMessage()); - } - - try { - int type = vitessResultSetMetadata.getColumnType(0); - } catch (SQLException ex) { - Assert.assertEquals(Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + 0, - ex.getMessage()); - } + } + + @Test + public void testgetColumnTypeName() throws SQLException { + + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("TINYINT", vitessResultSetMetadata.getColumnTypeName(1)); + Assert.assertEquals("TINYINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(2)); + Assert.assertEquals("SMALLINT", vitessResultSetMetadata.getColumnTypeName(3)); + Assert.assertEquals("SMALLINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(4)); + Assert.assertEquals("MEDIUMINT", vitessResultSetMetadata.getColumnTypeName(5)); + Assert.assertEquals("MEDIUMINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(6)); + Assert.assertEquals("INT", vitessResultSetMetadata.getColumnTypeName(7)); + Assert.assertEquals("INT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(8)); + Assert.assertEquals("BIGINT", vitessResultSetMetadata.getColumnTypeName(9)); + Assert.assertEquals("BIGINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(10)); + Assert.assertEquals("FLOAT", vitessResultSetMetadata.getColumnTypeName(11)); + Assert.assertEquals("DOUBLE", vitessResultSetMetadata.getColumnTypeName(12)); + Assert.assertEquals("TIMESTAMP", vitessResultSetMetadata.getColumnTypeName(13)); + Assert.assertEquals("DATE", vitessResultSetMetadata.getColumnTypeName(14)); + Assert.assertEquals("TIME", vitessResultSetMetadata.getColumnTypeName(15)); + Assert.assertEquals("DATETIME", vitessResultSetMetadata.getColumnTypeName(16)); + Assert.assertEquals("YEAR", vitessResultSetMetadata.getColumnTypeName(17)); + Assert.assertEquals("DECIMAL", vitessResultSetMetadata.getColumnTypeName(18)); + Assert.assertEquals("TEXT", vitessResultSetMetadata.getColumnTypeName(19)); + Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(20)); + Assert.assertEquals("VARCHAR", vitessResultSetMetadata.getColumnTypeName(21)); + Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(22)); + Assert.assertEquals("CHAR", vitessResultSetMetadata.getColumnTypeName(23)); + Assert.assertEquals("BINARY", vitessResultSetMetadata.getColumnTypeName(24)); + Assert.assertEquals("BIT", vitessResultSetMetadata.getColumnTypeName(25)); + Assert.assertEquals("ENUM", vitessResultSetMetadata.getColumnTypeName(26)); + Assert.assertEquals("SET", vitessResultSetMetadata.getColumnTypeName(27)); + Assert.assertEquals("TUPLE", vitessResultSetMetadata.getColumnTypeName(28)); + Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(29)); + Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(30)); + } + + @Test + public void testgetColumnType() throws SQLException { + + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("TINYINT", Types.TINYINT, vitessResultSetMetadata.getColumnType(1)); + Assert.assertEquals("TINYINT", Types.TINYINT, vitessResultSetMetadata.getColumnType(2)); + Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(3)); + Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(4)); + Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(5)); + Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(6)); + Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(7)); + Assert.assertEquals("INTEGER", Types.INTEGER, vitessResultSetMetadata.getColumnType(8)); + Assert.assertEquals("BIGINT", Types.BIGINT, vitessResultSetMetadata.getColumnType(9)); + Assert.assertEquals("BIGINT", Types.BIGINT, vitessResultSetMetadata.getColumnType(10)); + Assert.assertEquals("FLOAT", Types.FLOAT, vitessResultSetMetadata.getColumnType(11)); + Assert.assertEquals("DOUBLE", Types.DOUBLE, vitessResultSetMetadata.getColumnType(12)); + Assert.assertEquals("TIMESTAMP", Types.TIMESTAMP, vitessResultSetMetadata.getColumnType(13)); + Assert.assertEquals("DATE", Types.DATE, vitessResultSetMetadata.getColumnType(14)); + Assert.assertEquals("TIME", Types.TIME, vitessResultSetMetadata.getColumnType(15)); + Assert.assertEquals("TIMESTAMP", Types.TIMESTAMP, vitessResultSetMetadata.getColumnType(16)); + Assert.assertEquals("SMALLINT", Types.SMALLINT, vitessResultSetMetadata.getColumnType(17)); + Assert.assertEquals("DECIMAL", Types.DECIMAL, vitessResultSetMetadata.getColumnType(18)); + Assert.assertEquals("VARCHAR", Types.VARCHAR, vitessResultSetMetadata.getColumnType(19)); + Assert.assertEquals("LONGVARBINARY", Types.LONGVARBINARY, + vitessResultSetMetadata.getColumnType(20)); + Assert.assertEquals("VARCHAR", Types.VARCHAR, vitessResultSetMetadata.getColumnType(21)); + Assert.assertEquals("VARBINARY", Types.VARBINARY, vitessResultSetMetadata.getColumnType(22)); + Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(23)); + Assert.assertEquals("BINARY", Types.BINARY, vitessResultSetMetadata.getColumnType(24)); + Assert.assertEquals("BIT", Types.BIT, vitessResultSetMetadata.getColumnType(25)); + Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(26)); + Assert.assertEquals("CHAR", Types.CHAR, vitessResultSetMetadata.getColumnType(27)); + Assert.assertEquals("VARBINARY", Types.VARBINARY, vitessResultSetMetadata.getColumnType(29)); + Assert + .assertEquals("LONGVARCHAR", Types.LONGVARCHAR, vitessResultSetMetadata.getColumnType(30)); + try { + int type = vitessResultSetMetadata.getColumnType(28); + } catch (SQLException ex) { + Assert.assertEquals(Constants.SQLExceptionMessages.INVALID_COLUMN_TYPE, ex.getMessage()); } - @Test public void testgetColumnLabel() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fieldList); - for (int i = 1; i <= vitessResultSetMetaData.getColumnCount(); i++) { - Assert.assertEquals("col" + i, vitessResultSetMetaData.getColumnLabel(i)); - } + try { + int type = vitessResultSetMetadata.getColumnType(0); + } catch (SQLException ex) { + Assert.assertEquals(Constants.SQLExceptionMessages.INVALID_COLUMN_INDEX + ": " + 0, + ex.getMessage()); } - - @Test public void testgetTableName() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - for (int i = 1; i <= vitessResultSetMetadata.getColumnCount(); i++) { - Assert.assertEquals(vitessResultSetMetadata.getTableName(i), "tbl"); - } + } + + @Test + public void testgetColumnLabel() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fieldList); + for (int i = 1; i <= vitessResultSetMetaData.getColumnCount(); i++) { + Assert.assertEquals("col" + i, vitessResultSetMetaData.getColumnLabel(i)); } - - @Test public void isReadOnlyTest() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals(vitessResultSetMetadata.isReadOnly(1), false); - Assert.assertEquals(vitessResultSetMetadata.isWritable(1), true); - Assert.assertEquals(vitessResultSetMetadata.isDefinitelyWritable(1), true); - - for (int i = 2; i <= vitessResultSetMetadata.getColumnCount(); i++) { - Assert.assertEquals(vitessResultSetMetadata.isReadOnly(i), true); - Assert.assertEquals(vitessResultSetMetadata.isWritable(i), false); - Assert.assertEquals(vitessResultSetMetadata.isDefinitelyWritable(i), false); - } + } + + @Test + public void testgetTableName() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + for (int i = 1; i <= vitessResultSetMetadata.getColumnCount(); i++) { + Assert.assertEquals(vitessResultSetMetadata.getTableName(i), "tbl"); } - - @Test public void getColumnTypeNameTest() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("TINYINT", vitessResultSetMetadata.getColumnTypeName(1)); - Assert.assertEquals("TINYINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(2)); - Assert.assertEquals("SMALLINT", vitessResultSetMetadata.getColumnTypeName(3)); - Assert.assertEquals("SMALLINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(4)); - Assert.assertEquals("MEDIUMINT", vitessResultSetMetadata.getColumnTypeName(5)); - Assert.assertEquals("MEDIUMINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(6)); - Assert.assertEquals("INT", vitessResultSetMetadata.getColumnTypeName(7)); - Assert.assertEquals("INT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(8)); - Assert.assertEquals("BIGINT", vitessResultSetMetadata.getColumnTypeName(9)); - Assert.assertEquals("BIGINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(10)); - Assert.assertEquals("FLOAT", vitessResultSetMetadata.getColumnTypeName(11)); - Assert.assertEquals("DOUBLE", vitessResultSetMetadata.getColumnTypeName(12)); - Assert.assertEquals("TIMESTAMP", vitessResultSetMetadata.getColumnTypeName(13)); - Assert.assertEquals("DATE", vitessResultSetMetadata.getColumnTypeName(14)); - Assert.assertEquals("TIME", vitessResultSetMetadata.getColumnTypeName(15)); - Assert.assertEquals("DATETIME", vitessResultSetMetadata.getColumnTypeName(16)); - Assert.assertEquals("YEAR", vitessResultSetMetadata.getColumnTypeName(17)); - Assert.assertEquals("DECIMAL", vitessResultSetMetadata.getColumnTypeName(18)); - Assert.assertEquals("TEXT", vitessResultSetMetadata.getColumnTypeName(19)); - Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(20)); - Assert.assertEquals("VARCHAR", vitessResultSetMetadata.getColumnTypeName(21)); - Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(22)); - Assert.assertEquals("CHAR", vitessResultSetMetadata.getColumnTypeName(23)); - Assert.assertEquals("BINARY", vitessResultSetMetadata.getColumnTypeName(24)); - Assert.assertEquals("BIT", vitessResultSetMetadata.getColumnTypeName(25)); - Assert.assertEquals("ENUM", vitessResultSetMetadata.getColumnTypeName(26)); - Assert.assertEquals("SET", vitessResultSetMetadata.getColumnTypeName(27)); - Assert.assertEquals("TUPLE", vitessResultSetMetadata.getColumnTypeName(28)); + } + + @Test + public void isReadOnlyTest() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals(vitessResultSetMetadata.isReadOnly(1), false); + Assert.assertEquals(vitessResultSetMetadata.isWritable(1), true); + Assert.assertEquals(vitessResultSetMetadata.isDefinitelyWritable(1), true); + + for (int i = 2; i <= vitessResultSetMetadata.getColumnCount(); i++) { + Assert.assertEquals(vitessResultSetMetadata.isReadOnly(i), true); + Assert.assertEquals(vitessResultSetMetadata.isWritable(i), false); + Assert.assertEquals(vitessResultSetMetadata.isDefinitelyWritable(i), false); } - - @Test public void getSchemaNameTest() throws SQLException { - List fieldList = getFieldList(); - VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fieldList); - Assert.assertEquals(vitessResultSetMetaData.getSchemaName(1), ""); - Assert.assertEquals(vitessResultSetMetaData.getCatalogName(1), ""); - Assert.assertEquals(vitessResultSetMetaData.getPrecision(1), 3); - Assert.assertEquals(vitessResultSetMetaData.getScale(1), 0); - Assert.assertEquals(vitessResultSetMetaData.getColumnDisplaySize(1), 4); - Assert.assertEquals(vitessResultSetMetaData.isCurrency(1), false); + } + + @Test + public void getColumnTypeNameTest() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetadata = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("TINYINT", vitessResultSetMetadata.getColumnTypeName(1)); + Assert.assertEquals("TINYINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(2)); + Assert.assertEquals("SMALLINT", vitessResultSetMetadata.getColumnTypeName(3)); + Assert.assertEquals("SMALLINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(4)); + Assert.assertEquals("MEDIUMINT", vitessResultSetMetadata.getColumnTypeName(5)); + Assert.assertEquals("MEDIUMINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(6)); + Assert.assertEquals("INT", vitessResultSetMetadata.getColumnTypeName(7)); + Assert.assertEquals("INT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(8)); + Assert.assertEquals("BIGINT", vitessResultSetMetadata.getColumnTypeName(9)); + Assert.assertEquals("BIGINT UNSIGNED", vitessResultSetMetadata.getColumnTypeName(10)); + Assert.assertEquals("FLOAT", vitessResultSetMetadata.getColumnTypeName(11)); + Assert.assertEquals("DOUBLE", vitessResultSetMetadata.getColumnTypeName(12)); + Assert.assertEquals("TIMESTAMP", vitessResultSetMetadata.getColumnTypeName(13)); + Assert.assertEquals("DATE", vitessResultSetMetadata.getColumnTypeName(14)); + Assert.assertEquals("TIME", vitessResultSetMetadata.getColumnTypeName(15)); + Assert.assertEquals("DATETIME", vitessResultSetMetadata.getColumnTypeName(16)); + Assert.assertEquals("YEAR", vitessResultSetMetadata.getColumnTypeName(17)); + Assert.assertEquals("DECIMAL", vitessResultSetMetadata.getColumnTypeName(18)); + Assert.assertEquals("TEXT", vitessResultSetMetadata.getColumnTypeName(19)); + Assert.assertEquals("BLOB", vitessResultSetMetadata.getColumnTypeName(20)); + Assert.assertEquals("VARCHAR", vitessResultSetMetadata.getColumnTypeName(21)); + Assert.assertEquals("VARBINARY", vitessResultSetMetadata.getColumnTypeName(22)); + Assert.assertEquals("CHAR", vitessResultSetMetadata.getColumnTypeName(23)); + Assert.assertEquals("BINARY", vitessResultSetMetadata.getColumnTypeName(24)); + Assert.assertEquals("BIT", vitessResultSetMetadata.getColumnTypeName(25)); + Assert.assertEquals("ENUM", vitessResultSetMetadata.getColumnTypeName(26)); + Assert.assertEquals("SET", vitessResultSetMetadata.getColumnTypeName(27)); + Assert.assertEquals("TUPLE", vitessResultSetMetadata.getColumnTypeName(28)); + } + + @Test + public void getSchemaNameTest() throws SQLException { + List fieldList = getFieldList(); + VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fieldList); + Assert.assertEquals(vitessResultSetMetaData.getSchemaName(1), ""); + Assert.assertEquals(vitessResultSetMetaData.getCatalogName(1), ""); + Assert.assertEquals(vitessResultSetMetaData.getPrecision(1), 3); + Assert.assertEquals(vitessResultSetMetaData.getScale(1), 0); + Assert.assertEquals(vitessResultSetMetaData.getColumnDisplaySize(1), 4); + Assert.assertEquals(vitessResultSetMetaData.isCurrency(1), false); + } + + @Test + public void testCaseSensitivity() throws SQLException { + VitessConnection connection = getVitessConnection(); + List fieldList = getFieldList(connection); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + + // numeric types and date types are not case sensitive + Assert.assertEquals("int8 case sensitivity", false, md.isCaseSensitive(1)); + Assert.assertEquals("uint8 case sensitivity", false, md.isCaseSensitive(2)); + Assert.assertEquals("int16 case sensitivity", false, md.isCaseSensitive(3)); + Assert.assertEquals("uint16 case sensitivity", false, md.isCaseSensitive(4)); + Assert.assertEquals("int24 case sensitivity", false, md.isCaseSensitive(5)); + Assert.assertEquals("uint24 case sensitivity", false, md.isCaseSensitive(6)); + Assert.assertEquals("int32 case sensitivity", false, md.isCaseSensitive(7)); + Assert.assertEquals("uint32 case sensitivity", false, md.isCaseSensitive(8)); + Assert.assertEquals("int64 case sensitivity", false, md.isCaseSensitive(9)); + Assert.assertEquals("uint64 case sensitivity", false, md.isCaseSensitive(10)); + Assert.assertEquals("float32 case sensitivity", false, md.isCaseSensitive(11)); + Assert.assertEquals("float64 case sensitivity", false, md.isCaseSensitive(12)); + Assert.assertEquals("timestamp case sensitivity", false, md.isCaseSensitive(13)); + Assert.assertEquals("date case sensitivity", false, md.isCaseSensitive(14)); + Assert.assertEquals("time case sensitivity", false, md.isCaseSensitive(15)); + Assert.assertEquals("datetime case sensitivity", false, md.isCaseSensitive(16)); + Assert.assertEquals("year case sensitivity", false, md.isCaseSensitive(17)); + Assert.assertEquals("decimal case sensitivity", false, md.isCaseSensitive(18)); + + // These are handled on a case-by-case basis + Assert.assertEquals("text cases sensitivity", /* due to binary */true, md.isCaseSensitive(19)); + Assert.assertEquals("blob case sensitivity", /* due to binary */true, md.isCaseSensitive(20)); + Assert.assertEquals("varchar case sensitivity", /* due to utf-8_ci */ false, + md.isCaseSensitive(21)); + Assert.assertEquals("varbinary case sensitivity", /* due to binary */true, + md.isCaseSensitive(22)); + Assert + .assertEquals("char case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(23)); + Assert.assertEquals("binary case sensitivity", /* due to binary */true, md.isCaseSensitive(24)); + Assert.assertEquals("bit case sensitivity", /* due to numeric type */false, + md.isCaseSensitive(25)); + Assert + .assertEquals("enum case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(26)); + Assert.assertEquals("set case sensitivity", /* due to utf-8_ci, SET == CHAR */ false, + md.isCaseSensitive(27)); + Assert.assertEquals("tuple case sensitivity", /* due to default case */ true, + md.isCaseSensitive(28)); + Assert.assertEquals("varbinary case sensitivity", /* due to binary */ true, + md.isCaseSensitive(29)); + Assert.assertEquals( + "text cases sensitivity", /* due to utf8_bin (not case insensitive) encoding */false, + md.isCaseSensitive(30)); + + connection.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + // with limited included fields, we can really only know about numeric types -- those should + // return false. the rest should return true + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals(fieldList.get(i).getName() + + " - non-numeric case insensitive due to lack of included fields", + i >= 18 && i != 24, + md.isCaseSensitive(i + 1)); } - - @Test public void testCaseSensitivity() throws SQLException { - VitessConnection connection = getVitessConnection(); - List fieldList = getFieldList(connection); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - - // numeric types and date types are not case sensitive - Assert.assertEquals("int8 case sensitivity", false, md.isCaseSensitive(1)); - Assert.assertEquals("uint8 case sensitivity", false, md.isCaseSensitive(2)); - Assert.assertEquals("int16 case sensitivity", false, md.isCaseSensitive(3)); - Assert.assertEquals("uint16 case sensitivity", false, md.isCaseSensitive(4)); - Assert.assertEquals("int24 case sensitivity", false, md.isCaseSensitive(5)); - Assert.assertEquals("uint24 case sensitivity", false, md.isCaseSensitive(6)); - Assert.assertEquals("int32 case sensitivity", false, md.isCaseSensitive(7)); - Assert.assertEquals("uint32 case sensitivity", false, md.isCaseSensitive(8)); - Assert.assertEquals("int64 case sensitivity", false, md.isCaseSensitive(9)); - Assert.assertEquals("uint64 case sensitivity", false, md.isCaseSensitive(10)); - Assert.assertEquals("float32 case sensitivity", false, md.isCaseSensitive(11)); - Assert.assertEquals("float64 case sensitivity", false, md.isCaseSensitive(12)); - Assert.assertEquals("timestamp case sensitivity", false, md.isCaseSensitive(13)); - Assert.assertEquals("date case sensitivity", false, md.isCaseSensitive(14)); - Assert.assertEquals("time case sensitivity", false, md.isCaseSensitive(15)); - Assert.assertEquals("datetime case sensitivity", false, md.isCaseSensitive(16)); - Assert.assertEquals("year case sensitivity", false, md.isCaseSensitive(17)); - Assert.assertEquals("decimal case sensitivity", false, md.isCaseSensitive(18)); - - // These are handled on a case-by-case basis - Assert.assertEquals("text cases sensitivity", /* due to binary */true, md.isCaseSensitive(19)); - Assert.assertEquals("blob case sensitivity", /* due to binary */true, md.isCaseSensitive(20)); - Assert.assertEquals("varchar case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(21)); - Assert.assertEquals("varbinary case sensitivity", /* due to binary */true, md.isCaseSensitive(22)); - Assert.assertEquals("char case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(23)); - Assert.assertEquals("binary case sensitivity", /* due to binary */true, md.isCaseSensitive(24)); - Assert.assertEquals("bit case sensitivity", /* due to numeric type */false, md.isCaseSensitive(25)); - Assert.assertEquals("enum case sensitivity", /* due to utf-8_ci */ false, md.isCaseSensitive(26)); - Assert.assertEquals("set case sensitivity", /* due to utf-8_ci, SET == CHAR */ false, md.isCaseSensitive(27)); - Assert.assertEquals("tuple case sensitivity", /* due to default case */ true, md.isCaseSensitive(28)); - Assert.assertEquals("varbinary case sensitivity", /* due to binary */ true, md.isCaseSensitive(29)); - Assert.assertEquals("text cases sensitivity", /* due to utf8_bin (not case insensitive) encoding */false, md.isCaseSensitive(30)); - - connection.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - // with limited included fields, we can really only know about numeric types -- those should return false. the rest should return true - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - non-numeric case insensitive due to lack of included fields", i >= 18 && i != 24, md.isCaseSensitive(i + 1)); - } + } + + @Test + public void testIsNullable() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("NOT_NULL flag means columnNoNulls (0) value for isNullable", + ResultSetMetaData.columnNoNulls, md.isNullable(1)); + for (int i = 1; i < fieldList.size(); i++) { + Assert.assertEquals("lack of NOT_NULL flag means columnNullable (1) value for isNullable", + ResultSetMetaData.columnNullable, md.isNullable(i + 1)); } - @Test public void testIsNullable() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("NOT_NULL flag means columnNoNulls (0) value for isNullable", ResultSetMetaData.columnNoNulls, md.isNullable(1)); - for (int i = 1; i < fieldList.size(); i++) { - Assert.assertEquals("lack of NOT_NULL flag means columnNullable (1) value for isNullable", ResultSetMetaData.columnNullable, md.isNullable(i + 1)); - } - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - isNullable is columnNullableUnknown (2) for all when lack of included fields", 2, md.isNullable(i + 1)); - } + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals(fieldList.get(i).getName() + + " - isNullable is columnNullableUnknown (2) for all when lack of included fields" + , 2, + md.isNullable(i + 1)); } - - @Test public void testDisplaySize() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - - Assert.assertEquals("int8 display size", 4, md.getColumnDisplaySize(1)); - Assert.assertEquals("uint8 display size", 3, md.getColumnDisplaySize(2)); - Assert.assertEquals("int16 display size", 6, md.getColumnDisplaySize(3)); - Assert.assertEquals("uint16 display size", 5, md.getColumnDisplaySize(4)); - Assert.assertEquals("int24 display size", 9, md.getColumnDisplaySize(5)); - Assert.assertEquals("uint24 display size", 8, md.getColumnDisplaySize(6)); - Assert.assertEquals("int32 display size", 11, md.getColumnDisplaySize(7)); - Assert.assertEquals("uint32 display size", 10, md.getColumnDisplaySize(8)); - Assert.assertEquals("int64 display size", 20, md.getColumnDisplaySize(9)); - // unsigned long gets an extra digit of precision over signed, so display sizes are the same - Assert.assertEquals("uint64 display size", 20, md.getColumnDisplaySize(10)); - Assert.assertEquals("float32 display size", 12, md.getColumnDisplaySize(11)); - Assert.assertEquals("float64 display size", 22, md.getColumnDisplaySize(12)); - Assert.assertEquals("timestamp display size", 10, md.getColumnDisplaySize(13)); - Assert.assertEquals("date display size", 10, md.getColumnDisplaySize(14)); - Assert.assertEquals("time display size", 10, md.getColumnDisplaySize(15)); - Assert.assertEquals("datetime display size", 19, md.getColumnDisplaySize(16)); - Assert.assertEquals("year display size", 4, md.getColumnDisplaySize(17)); - Assert.assertEquals("decimal display size", 7, md.getColumnDisplaySize(18)); - Assert.assertEquals("text display size", 255, md.getColumnDisplaySize(19)); - Assert.assertEquals("blob display size", 65535, md.getColumnDisplaySize(20)); - Assert.assertEquals("varchar display size", 256, md.getColumnDisplaySize(21)); - Assert.assertEquals("varbinary display size", 256, md.getColumnDisplaySize(22)); - Assert.assertEquals("char display size", 16, md.getColumnDisplaySize(23)); - Assert.assertEquals("binary display size", 4, md.getColumnDisplaySize(24)); - Assert.assertEquals("bit display size", 8, md.getColumnDisplaySize(25)); - Assert.assertEquals("enum display size", 1, md.getColumnDisplaySize(26)); - Assert.assertEquals("set display size", 3, md.getColumnDisplaySize(27)); - Assert.assertEquals("tuple display size", 0, md.getColumnDisplaySize(28)); - Assert.assertEquals("varbinary display size", 256, md.getColumnDisplaySize(29)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - getColumnDisplaySize is 0 for all when lack of included fields", 0, md.getColumnDisplaySize(i + 1)); - } + } + + @Test + public void testDisplaySize() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + + Assert.assertEquals("int8 display size", 4, md.getColumnDisplaySize(1)); + Assert.assertEquals("uint8 display size", 3, md.getColumnDisplaySize(2)); + Assert.assertEquals("int16 display size", 6, md.getColumnDisplaySize(3)); + Assert.assertEquals("uint16 display size", 5, md.getColumnDisplaySize(4)); + Assert.assertEquals("int24 display size", 9, md.getColumnDisplaySize(5)); + Assert.assertEquals("uint24 display size", 8, md.getColumnDisplaySize(6)); + Assert.assertEquals("int32 display size", 11, md.getColumnDisplaySize(7)); + Assert.assertEquals("uint32 display size", 10, md.getColumnDisplaySize(8)); + Assert.assertEquals("int64 display size", 20, md.getColumnDisplaySize(9)); + // unsigned long gets an extra digit of precision over signed, so display sizes are the same + Assert.assertEquals("uint64 display size", 20, md.getColumnDisplaySize(10)); + Assert.assertEquals("float32 display size", 12, md.getColumnDisplaySize(11)); + Assert.assertEquals("float64 display size", 22, md.getColumnDisplaySize(12)); + Assert.assertEquals("timestamp display size", 10, md.getColumnDisplaySize(13)); + Assert.assertEquals("date display size", 10, md.getColumnDisplaySize(14)); + Assert.assertEquals("time display size", 10, md.getColumnDisplaySize(15)); + Assert.assertEquals("datetime display size", 19, md.getColumnDisplaySize(16)); + Assert.assertEquals("year display size", 4, md.getColumnDisplaySize(17)); + Assert.assertEquals("decimal display size", 7, md.getColumnDisplaySize(18)); + Assert.assertEquals("text display size", 255, md.getColumnDisplaySize(19)); + Assert.assertEquals("blob display size", 65535, md.getColumnDisplaySize(20)); + Assert.assertEquals("varchar display size", 256, md.getColumnDisplaySize(21)); + Assert.assertEquals("varbinary display size", 256, md.getColumnDisplaySize(22)); + Assert.assertEquals("char display size", 16, md.getColumnDisplaySize(23)); + Assert.assertEquals("binary display size", 4, md.getColumnDisplaySize(24)); + Assert.assertEquals("bit display size", 8, md.getColumnDisplaySize(25)); + Assert.assertEquals("enum display size", 1, md.getColumnDisplaySize(26)); + Assert.assertEquals("set display size", 3, md.getColumnDisplaySize(27)); + Assert.assertEquals("tuple display size", 0, md.getColumnDisplaySize(28)); + Assert.assertEquals("varbinary display size", 256, md.getColumnDisplaySize(29)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals(fieldList.get(i).getName() + + " - getColumnDisplaySize is 0 for all when lack of included fields", 0, + md.getColumnDisplaySize(i + 1)); } - - @Test public void testGetPrecision() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - - Assert.assertEquals("int8 precision", 3, md.getPrecision(1)); - Assert.assertEquals("uint8 precision", 3, md.getPrecision(2)); - Assert.assertEquals("int16 precision", 5, md.getPrecision(3)); - Assert.assertEquals("uint16 precision", 5, md.getPrecision(4)); - Assert.assertEquals("int24 precision", 8, md.getPrecision(5)); - Assert.assertEquals("uint24 precision", 8, md.getPrecision(6)); - Assert.assertEquals("int32 precision", 10, md.getPrecision(7)); - Assert.assertEquals("uint32 precision", 10, md.getPrecision(8)); - Assert.assertEquals("int64 precision", 19, md.getPrecision(9)); - Assert.assertEquals("uint64 precision", 20, md.getPrecision(10)); - Assert.assertEquals("float32 precision", 12, md.getPrecision(11)); - Assert.assertEquals("float64 precision", 22, md.getPrecision(12)); - Assert.assertEquals("timestamp precision", 10, md.getPrecision(13)); - Assert.assertEquals("date precision", 10, md.getPrecision(14)); - Assert.assertEquals("time precision", 10, md.getPrecision(15)); - Assert.assertEquals("datetime precision", 19, md.getPrecision(16)); - Assert.assertEquals("year precision", 4, md.getPrecision(17)); - Assert.assertEquals("decimal precision", 5, md.getPrecision(18)); // 7 - decimal - sign - Assert.assertEquals("text precision", 255, md.getPrecision(19)); - Assert.assertEquals("blob precision", 65535, md.getPrecision(20)); - Assert.assertEquals("varchar precision", 256, md.getPrecision(21)); - Assert.assertEquals("varbinary precision", 256, md.getPrecision(22)); - Assert.assertEquals("char precision", 16, md.getPrecision(23)); - Assert.assertEquals("binary precision", 4, md.getPrecision(24)); - Assert.assertEquals("bit precision", 8, md.getPrecision(25)); - Assert.assertEquals("enum precision", 1, md.getPrecision(26)); - Assert.assertEquals("set precision", 3, md.getPrecision(27)); - Assert.assertEquals("tuple precision", 0, md.getPrecision(28)); - Assert.assertEquals("varbinary precision", 256, md.getPrecision(29)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - getPrecision is 0 for all when lack of included fields", 0, md.getPrecision(i + 1)); - } + } + + @Test + public void testGetPrecision() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + + Assert.assertEquals("int8 precision", 3, md.getPrecision(1)); + Assert.assertEquals("uint8 precision", 3, md.getPrecision(2)); + Assert.assertEquals("int16 precision", 5, md.getPrecision(3)); + Assert.assertEquals("uint16 precision", 5, md.getPrecision(4)); + Assert.assertEquals("int24 precision", 8, md.getPrecision(5)); + Assert.assertEquals("uint24 precision", 8, md.getPrecision(6)); + Assert.assertEquals("int32 precision", 10, md.getPrecision(7)); + Assert.assertEquals("uint32 precision", 10, md.getPrecision(8)); + Assert.assertEquals("int64 precision", 19, md.getPrecision(9)); + Assert.assertEquals("uint64 precision", 20, md.getPrecision(10)); + Assert.assertEquals("float32 precision", 12, md.getPrecision(11)); + Assert.assertEquals("float64 precision", 22, md.getPrecision(12)); + Assert.assertEquals("timestamp precision", 10, md.getPrecision(13)); + Assert.assertEquals("date precision", 10, md.getPrecision(14)); + Assert.assertEquals("time precision", 10, md.getPrecision(15)); + Assert.assertEquals("datetime precision", 19, md.getPrecision(16)); + Assert.assertEquals("year precision", 4, md.getPrecision(17)); + Assert.assertEquals("decimal precision", 5, md.getPrecision(18)); // 7 - decimal - sign + Assert.assertEquals("text precision", 255, md.getPrecision(19)); + Assert.assertEquals("blob precision", 65535, md.getPrecision(20)); + Assert.assertEquals("varchar precision", 256, md.getPrecision(21)); + Assert.assertEquals("varbinary precision", 256, md.getPrecision(22)); + Assert.assertEquals("char precision", 16, md.getPrecision(23)); + Assert.assertEquals("binary precision", 4, md.getPrecision(24)); + Assert.assertEquals("bit precision", 8, md.getPrecision(25)); + Assert.assertEquals("enum precision", 1, md.getPrecision(26)); + Assert.assertEquals("set precision", 3, md.getPrecision(27)); + Assert.assertEquals("tuple precision", 0, md.getPrecision(28)); + Assert.assertEquals("varbinary precision", 256, md.getPrecision(29)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals( + fieldList.get(i).getName() + " - getPrecision is 0 for all when lack of included fields", + 0, md.getPrecision(i + 1)); } - - @Test public void testGetScale() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("int8 precision", 0, md.getScale(1)); - Assert.assertEquals("uint8 precision", 0, md.getScale(2)); - Assert.assertEquals("int16 precision", 0, md.getScale(3)); - Assert.assertEquals("uint16 precision", 0, md.getScale(4)); - Assert.assertEquals("int24 precision", 0, md.getScale(5)); - Assert.assertEquals("uint24 precision", 0, md.getScale(6)); - Assert.assertEquals("int32 precision", 0, md.getScale(7)); - Assert.assertEquals("uint32 precision", 0, md.getScale(8)); - Assert.assertEquals("int64 precision", 0, md.getScale(9)); - Assert.assertEquals("uint64 precision", 0, md.getScale(10)); - Assert.assertEquals("float32 precision", 31, md.getScale(11)); - Assert.assertEquals("float64 precision", 31, md.getScale(12)); - Assert.assertEquals("timestamp precision", 0, md.getScale(13)); - Assert.assertEquals("date precision", 0, md.getScale(14)); - Assert.assertEquals("time precision", 0, md.getScale(15)); - Assert.assertEquals("datetime precision", 0, md.getScale(16)); - Assert.assertEquals("year precision", 0, md.getScale(17)); - Assert.assertEquals("decimal precision", 2, md.getScale(18)); - Assert.assertEquals("text precision", 0, md.getScale(19)); - Assert.assertEquals("blob precision", 0, md.getScale(20)); - Assert.assertEquals("varchar precision", 0, md.getScale(21)); - Assert.assertEquals("varbinary precision", 0, md.getScale(22)); - Assert.assertEquals("char precision", 0, md.getScale(23)); - Assert.assertEquals("binary precision", 0, md.getScale(24)); - Assert.assertEquals("bit precision", 0, md.getScale(25)); - Assert.assertEquals("enum precision", 0, md.getScale(26)); - Assert.assertEquals("set precision", 0, md.getScale(27)); - Assert.assertEquals("tuple precision", 0, md.getScale(28)); - Assert.assertEquals("varbinary precision", 0, md.getScale(29)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - getScale is 0 for all when lack of included fields", 0, md.getScale(i + 1)); - } + } + + @Test + public void testGetScale() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("int8 precision", 0, md.getScale(1)); + Assert.assertEquals("uint8 precision", 0, md.getScale(2)); + Assert.assertEquals("int16 precision", 0, md.getScale(3)); + Assert.assertEquals("uint16 precision", 0, md.getScale(4)); + Assert.assertEquals("int24 precision", 0, md.getScale(5)); + Assert.assertEquals("uint24 precision", 0, md.getScale(6)); + Assert.assertEquals("int32 precision", 0, md.getScale(7)); + Assert.assertEquals("uint32 precision", 0, md.getScale(8)); + Assert.assertEquals("int64 precision", 0, md.getScale(9)); + Assert.assertEquals("uint64 precision", 0, md.getScale(10)); + Assert.assertEquals("float32 precision", 31, md.getScale(11)); + Assert.assertEquals("float64 precision", 31, md.getScale(12)); + Assert.assertEquals("timestamp precision", 0, md.getScale(13)); + Assert.assertEquals("date precision", 0, md.getScale(14)); + Assert.assertEquals("time precision", 0, md.getScale(15)); + Assert.assertEquals("datetime precision", 0, md.getScale(16)); + Assert.assertEquals("year precision", 0, md.getScale(17)); + Assert.assertEquals("decimal precision", 2, md.getScale(18)); + Assert.assertEquals("text precision", 0, md.getScale(19)); + Assert.assertEquals("blob precision", 0, md.getScale(20)); + Assert.assertEquals("varchar precision", 0, md.getScale(21)); + Assert.assertEquals("varbinary precision", 0, md.getScale(22)); + Assert.assertEquals("char precision", 0, md.getScale(23)); + Assert.assertEquals("binary precision", 0, md.getScale(24)); + Assert.assertEquals("bit precision", 0, md.getScale(25)); + Assert.assertEquals("enum precision", 0, md.getScale(26)); + Assert.assertEquals("set precision", 0, md.getScale(27)); + Assert.assertEquals("tuple precision", 0, md.getScale(28)); + Assert.assertEquals("varbinary precision", 0, md.getScale(29)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals( + fieldList.get(i).getName() + " - getScale is 0 for all when lack of included fields", 0, + md.getScale(i + 1)); } - - @Test public void testGetColumnClassName() throws SQLException { - VitessConnection conn = getVitessConnection(); - List fieldList = getFieldList(conn); - VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(1)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(2)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(3)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(4)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(5)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(6)); - Assert.assertEquals("java.lang.Integer", md.getColumnClassName(7)); - Assert.assertEquals("java.lang.Long", md.getColumnClassName(8)); - Assert.assertEquals("java.lang.Long", md.getColumnClassName(9)); - Assert.assertEquals("java.math.BigInteger", md.getColumnClassName(10)); - Assert.assertEquals("java.lang.Double", md.getColumnClassName(11)); - Assert.assertEquals("java.lang.Double", md.getColumnClassName(12)); - Assert.assertEquals("java.sql.Timestamp", md.getColumnClassName(13)); - Assert.assertEquals("java.sql.Date", md.getColumnClassName(14)); - Assert.assertEquals("java.sql.Time", md.getColumnClassName(15)); - Assert.assertEquals("java.sql.Timestamp", md.getColumnClassName(16)); - Assert.assertEquals("java.sql.Date", md.getColumnClassName(17)); - Assert.assertEquals("java.math.BigDecimal", md.getColumnClassName(18)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(19)); - Assert.assertEquals("[B", md.getColumnClassName(20)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(21)); - Assert.assertEquals("[B", md.getColumnClassName(22)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(23)); - Assert.assertEquals("[B", md.getColumnClassName(24)); - Assert.assertEquals("java.lang.Boolean", md.getColumnClassName(25)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(26)); - Assert.assertEquals("java.lang.String", md.getColumnClassName(27)); - Assert.assertEquals("java.lang.Object", md.getColumnClassName(28)); - Assert.assertEquals("[B", md.getColumnClassName(29)); - - conn.setYearIsDateType(false); - md = new VitessResultSetMetaData(fieldList); - Assert.assertEquals("java.lang.Short", md.getColumnClassName(17)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - for (int i = 0; i < fieldList.size(); i++) { - Assert.assertEquals(fieldList.get(i).getName() + " - class name is null when no included fields", null, md.getColumnClassName(i + 1)); - } + } + + @Test + public void testGetColumnClassName() throws SQLException { + VitessConnection conn = getVitessConnection(); + List fieldList = getFieldList(conn); + VitessResultSetMetaData md = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(1)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(2)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(3)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(4)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(5)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(6)); + Assert.assertEquals("java.lang.Integer", md.getColumnClassName(7)); + Assert.assertEquals("java.lang.Long", md.getColumnClassName(8)); + Assert.assertEquals("java.lang.Long", md.getColumnClassName(9)); + Assert.assertEquals("java.math.BigInteger", md.getColumnClassName(10)); + Assert.assertEquals("java.lang.Double", md.getColumnClassName(11)); + Assert.assertEquals("java.lang.Double", md.getColumnClassName(12)); + Assert.assertEquals("java.sql.Timestamp", md.getColumnClassName(13)); + Assert.assertEquals("java.sql.Date", md.getColumnClassName(14)); + Assert.assertEquals("java.sql.Time", md.getColumnClassName(15)); + Assert.assertEquals("java.sql.Timestamp", md.getColumnClassName(16)); + Assert.assertEquals("java.sql.Date", md.getColumnClassName(17)); + Assert.assertEquals("java.math.BigDecimal", md.getColumnClassName(18)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(19)); + Assert.assertEquals("[B", md.getColumnClassName(20)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(21)); + Assert.assertEquals("[B", md.getColumnClassName(22)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(23)); + Assert.assertEquals("[B", md.getColumnClassName(24)); + Assert.assertEquals("java.lang.Boolean", md.getColumnClassName(25)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(26)); + Assert.assertEquals("java.lang.String", md.getColumnClassName(27)); + Assert.assertEquals("java.lang.Object", md.getColumnClassName(28)); + Assert.assertEquals("[B", md.getColumnClassName(29)); + + conn.setYearIsDateType(false); + md = new VitessResultSetMetaData(fieldList); + Assert.assertEquals("java.lang.Short", md.getColumnClassName(17)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + for (int i = 0; i < fieldList.size(); i++) { + Assert.assertEquals( + fieldList.get(i).getName() + " - class name is null when no included fields", null, + md.getColumnClassName(i + 1)); } - - /** - * Some of the tests above verify that their particular part honors the IncludedFields.ALL value, but - * this further verifies that when someone has disabled ALL, the values returned by the driver are basically the same - * as what they used to be before we supported returning all fields. - */ - @Test public void testDefaultValuesWithoutIncludedFields() throws SQLException { - VitessConnection conn = getVitessConnection(); - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - List fields = getFieldList(conn); - VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fields); - for (int i = 1; i < fields.size() + 1; i++) { - FieldWithMetadata field = fields.get(i - 1); - Assert.assertEquals(false, vitessResultSetMetaData.isAutoIncrement(i)); - boolean shouldBeSensitive = true; - switch (field.getJavaType()) { - case Types.BIT: - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.FLOAT: - case Types.REAL: - case Types.DOUBLE: - case Types.DATE: - case Types.DECIMAL: - case Types.NUMERIC: - case Types.TIME: - case Types.TIMESTAMP: - shouldBeSensitive = false; - break; - } - Assert.assertEquals(shouldBeSensitive, vitessResultSetMetaData.isCaseSensitive(i)); - Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isSearchable(i)); - Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isCurrency(i)); - Assert.assertEquals(field.getName(), ResultSetMetaData.columnNullableUnknown, vitessResultSetMetaData.isNullable(i)); - Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isSigned(i)); - Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getColumnDisplaySize(i)); - Assert.assertEquals(field.getName(), field.getName(), vitessResultSetMetaData.getColumnLabel(i)); - Assert.assertEquals(field.getName(), field.getName(), vitessResultSetMetaData.getColumnName(i)); - Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getPrecision(i)); - Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getScale(i)); - Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getTableName(i)); - Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getCatalogName(i)); - // These two do not depend on IncludedFields and are covered by tests above - //Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnType(i)); - //Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnTypeName(i)); - Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isReadOnly(i)); - Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isWritable(i)); - Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isDefinitelyWritable(i)); - Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnClassName(i)); - } + } + + /** + * Some of the tests above verify that their particular part honors the IncludedFields.ALL value, + * but this further verifies that when someone has disabled ALL, the values returned by the driver + * are basically the same as what they used to be before we supported returning all fields. + */ + @Test + public void testDefaultValuesWithoutIncludedFields() throws SQLException { + VitessConnection conn = getVitessConnection(); + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + List fields = getFieldList(conn); + VitessResultSetMetaData vitessResultSetMetaData = new VitessResultSetMetaData(fields); + for (int i = 1; i < fields.size() + 1; i++) { + FieldWithMetadata field = fields.get(i - 1); + Assert.assertEquals(false, vitessResultSetMetaData.isAutoIncrement(i)); + boolean shouldBeSensitive = true; + switch (field.getJavaType()) { + case Types.BIT: + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.DATE: + case Types.DECIMAL: + case Types.NUMERIC: + case Types.TIME: + case Types.TIMESTAMP: + shouldBeSensitive = false; + break; + } + Assert.assertEquals(shouldBeSensitive, vitessResultSetMetaData.isCaseSensitive(i)); + Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isSearchable(i)); + Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isCurrency(i)); + Assert.assertEquals(field.getName(), ResultSetMetaData.columnNullableUnknown, + vitessResultSetMetaData.isNullable(i)); + Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isSigned(i)); + Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getColumnDisplaySize(i)); + Assert.assertEquals(field.getName(), field.getName(), + vitessResultSetMetaData.getColumnLabel(i)); + Assert + .assertEquals(field.getName(), field.getName(), vitessResultSetMetaData.getColumnName(i)); + Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getPrecision(i)); + Assert.assertEquals(field.getName(), 0, vitessResultSetMetaData.getScale(i)); + Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getTableName(i)); + Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getCatalogName(i)); + // These two do not depend on IncludedFields and are covered by tests above + //Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnType(i)); + //Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnTypeName(i)); + Assert.assertEquals(field.getName(), false, vitessResultSetMetaData.isReadOnly(i)); + Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isWritable(i)); + Assert.assertEquals(field.getName(), true, vitessResultSetMetaData.isDefinitelyWritable(i)); + Assert.assertEquals(field.getName(), null, vitessResultSetMetaData.getColumnClassName(i)); } + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetTest.java index ce2c8b79aa2..7c41baf9636 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessResultSetTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,15 +16,9 @@ package io.vitess.jdbc; +import static org.junit.Assert.assertEquals; + import com.google.protobuf.ByteString; -import org.junit.Assert; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Matchers; -import org.mockito.internal.verification.VerificationModeFactory; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; import io.vitess.client.cursor.Cursor; import io.vitess.client.cursor.SimpleCursor; @@ -44,7 +38,14 @@ import java.sql.Timestamp; import java.util.Properties; -import static org.junit.Assert.assertEquals; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Matchers; +import org.mockito.internal.verification.VerificationModeFactory; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; /** * Created by harshit.gangal on 19/01/16. @@ -53,7 +54,7 @@ @PrepareForTest(VitessResultSet.class) public class VitessResultSetTest extends BaseTest { - public Cursor getCursorWithRows() { + public Cursor getCursorWithRows() { /* INT8(1, 257), -50 UINT8(2, 770), 50 @@ -85,8 +86,8 @@ public Cursor getCursorWithRows() { TUPLE(28, 28), UNRECOGNIZED(-1, -1); */ - return new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(getField("col1", Query.Type.INT8)) + return new SimpleCursor( + Query.QueryResult.newBuilder().addFields(getField("col1", Query.Type.INT8)) .addFields(getField("col2", Query.Type.UINT8)) .addFields(getField("col3", Query.Type.INT16)) .addFields(getField("col4", Query.Type.UINT16)) @@ -113,8 +114,8 @@ public Cursor getCursorWithRows() { .addFields(getField("col25", Query.Type.BIT)) .addFields(getField("col26", Query.Type.ENUM)) .addFields(getField("col27", Query.Type.SET)) - .addFields(getField("col28", Query.Type.TIMESTAMP)) - .addRows(Query.Row.newBuilder().addLengths("-50".length()).addLengths("50".length()) + .addFields(getField("col28", Query.Type.TIMESTAMP)).addRows( + Query.Row.newBuilder().addLengths("-50".length()).addLengths("50".length()) .addLengths("-23000".length()).addLengths("23000".length()) .addLengths("-100".length()).addLengths("100".length()).addLengths("-100".length()) .addLengths("100".length()).addLengths("-1000".length()).addLengths("1000".length()) @@ -126,23 +127,25 @@ public Cursor getCursorWithRows() { .addLengths("HELLO TDS TEAM".length()).addLengths("HELLO TDS TEAM".length()) .addLengths("N".length()).addLengths("HELLO TDS TEAM".length()) .addLengths("1".length()).addLengths("val123".length()) - .addLengths("val123".length()).addLengths("0000-00-00 00:00:00".length()) - .setValues(ByteString - .copyFromUtf8("-5050-2300023000-100100-100100-1000100024.52100.432016-02-06 " + - "14:15:162016-02-0612:34:562016-02-06 14:15:1620161234.56789HELLO TDS TEAMHELLO TDS TEAMHELLO" - + - " TDS TEAMHELLO TDS TEAMNHELLO TDS TEAM1val123val1230000-00-00 00:00:00"))).build()); - } - - private Query.Field getField(String fieldName, Query.Type typ) { - return Query.Field.newBuilder().setName(fieldName).setType(typ).build(); - } - - private Query.Field getField(String fieldName) { - return Query.Field.newBuilder().setName(fieldName).build(); - } - - public Cursor getCursorWithRowsAsNull() { + .addLengths("val123".length()).addLengths("0000-00-00 00:00:00".length()).setValues( + ByteString.copyFromUtf8( + "-5050-2300023000-100100-100100-1000100024.52100.432016-02-06 " + + "14:15:162016-02-0612:34:562016-02-06 14:15:1620161234.56789HELLO TDS " + + "TEAMHELLO TDS TEAMHELLO" + + " TDS TEAMHELLO TDS TEAMNHELLO TDS TEAM1val123val1230000-00-00 " + + "00:00:00"))) + .build()); + } + + private Query.Field getField(String fieldName, Query.Type typ) { + return Query.Field.newBuilder().setName(fieldName).setType(typ).build(); + } + + private Query.Field getField(String fieldName) { + return Query.Field.newBuilder().setName(fieldName).build(); + } + + public Cursor getCursorWithRowsAsNull() { /* INT8(1, 257), -50 UINT8(2, 770), 50 @@ -174,8 +177,8 @@ public Cursor getCursorWithRowsAsNull() { TUPLE(28, 28), UNRECOGNIZED(-1, -1); */ - return new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(getField("col1", Query.Type.INT8)) + return new SimpleCursor( + Query.QueryResult.newBuilder().addFields(getField("col1", Query.Type.INT8)) .addFields(getField("col2", Query.Type.UINT8)) .addFields(getField("col3", Query.Type.INT16)) .addFields(getField("col4", Query.Type.UINT16)) @@ -201,8 +204,8 @@ public Cursor getCursorWithRowsAsNull() { .addFields(getField("col24", Query.Type.BINARY)) .addFields(getField("col25", Query.Type.BIT)) .addFields(getField("col26", Query.Type.ENUM)) - .addFields(getField("col27", Query.Type.SET)) - .addRows(Query.Row.newBuilder().addLengths("-50".length()).addLengths("50".length()) + .addFields(getField("col27", Query.Type.SET)).addRows( + Query.Row.newBuilder().addLengths("-50".length()).addLengths("50".length()) .addLengths("-23000".length()).addLengths("23000".length()) .addLengths("-100".length()).addLengths("100".length()).addLengths("-100".length()) .addLengths("100".length()).addLengths("-1000".length()).addLengths("1000".length()) @@ -213,621 +216,660 @@ public Cursor getCursorWithRowsAsNull() { .addLengths("HELLO TDS TEAM".length()).addLengths("HELLO TDS TEAM".length()) .addLengths("HELLO TDS TEAM".length()).addLengths("HELLO TDS TEAM".length()) .addLengths("N".length()).addLengths("HELLO TDS TEAM".length()) - .addLengths("0".length()).addLengths("val123".length()).addLengths(-1).setValues(ByteString.copyFromUtf8( - "-5050-2300023000-100100-100100-1000100024.52100.432016-02-06 " + - "14:15:162016-02-0612:34:562016-02-06 14:15:1620161234.56789HELLO TDS TEAMHELLO TDS " + - "TEAMHELLO TDS TEAMHELLO TDS TEAMNHELLO TDS TEAM0val123"))).build()); - } - - @Test public void testNextWithZeroRows() throws Exception { - Cursor cursor = new SimpleCursor(Query.QueryResult.newBuilder() - .addFields(getField("col0")) - .addFields(getField("col1")) + .addLengths("0".length()).addLengths("val123".length()).addLengths(-1).setValues( + ByteString.copyFromUtf8( + "-5050-2300023000-100100-100100-1000100024.52100.432016-02-06 " + + "14:15:162016-02-0612:34:562016-02-06 14:15:1620161234.56789HELLO TDS " + + "TEAMHELLO TDS " + + "TEAMHELLO TDS TEAMHELLO TDS TEAMNHELLO TDS TEAM0val123"))).build()); + } + + @Test + public void testNextWithZeroRows() throws Exception { + Cursor cursor = new SimpleCursor( + Query.QueryResult.newBuilder().addFields(getField("col0")).addFields(getField("col1")) .addFields(getField("col2")).build()); - VitessResultSet vitessResultSet = new VitessResultSet(cursor); - assertEquals(false, vitessResultSet.next()); - } - - @Test public void testNextWithNonZeroRows() throws Exception { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor); - assertEquals(true, vitessResultSet.next()); - assertEquals(false, vitessResultSet.next()); - } - - @Test public void testgetString() throws SQLException { - Cursor cursor = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals("-50", vitessResultSet.getString(1)); - assertEquals("50", vitessResultSet.getString(2)); - assertEquals("-23000", vitessResultSet.getString(3)); - assertEquals("23000", vitessResultSet.getString(4)); - assertEquals("-100", vitessResultSet.getString(5)); - assertEquals("100", vitessResultSet.getString(6)); - assertEquals("-100", vitessResultSet.getString(7)); - assertEquals("100", vitessResultSet.getString(8)); - assertEquals("-1000", vitessResultSet.getString(9)); - assertEquals("1000", vitessResultSet.getString(10)); - assertEquals("24.52", vitessResultSet.getString(11)); - assertEquals("100.43", vitessResultSet.getString(12)); - assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString(13)); - assertEquals("2016-02-06", vitessResultSet.getString(14)); - assertEquals("12:34:56", vitessResultSet.getString(15)); - assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString(16)); - assertEquals("2016", vitessResultSet.getString(17)); - assertEquals("1234.56789", vitessResultSet.getString(18)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(19)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(20)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(21)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(22)); - assertEquals("N", vitessResultSet.getString(23)); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString(24)); - assertEquals("0", vitessResultSet.getString(25)); - assertEquals("val123", vitessResultSet.getString(26)); - assertEquals(null, vitessResultSet.getString(27)); - } - - @Test public void getObjectUint64AsBigInteger() throws SQLException { - Cursor cursor = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - - assertEquals(new BigInteger("1000"), vitessResultSet.getObject(10)); - } - - @Test public void getBigInteger() throws SQLException { - Cursor cursor = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - - assertEquals(new BigInteger("1000"), vitessResultSet.getBigInteger(10)); - } - - @Test public void testgetBoolean() throws SQLException { - Cursor cursor = getCursorWithRows(); - Cursor cursorWithRowsAsNull = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(true, vitessResultSet.getBoolean(25)); - assertEquals(false, vitessResultSet.getBoolean(1)); - vitessResultSet = new VitessResultSet(cursorWithRowsAsNull, getVitessStatement()); - vitessResultSet.next(); - assertEquals(false, vitessResultSet.getBoolean(25)); - assertEquals(false, vitessResultSet.getBoolean(1)); - } - - @Test public void testgetByte() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-50, vitessResultSet.getByte(1)); - assertEquals(1, vitessResultSet.getByte(25)); - } - - @Test public void testgetShort() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-23000, vitessResultSet.getShort(3)); - } - - @Test public void testgetInt() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-100, vitessResultSet.getInt(7)); - } - - @Test public void testgetLong() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-1000, vitessResultSet.getInt(9)); - } - - @Test public void testgetFloat() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(24.52f, vitessResultSet.getFloat(11), 0.001); - } - - @Test public void testgetDouble() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(100.43, vitessResultSet.getFloat(12), 0.001); - } - - @Test public void testBigDecimal() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new BigDecimal(BigInteger.valueOf(123456789), 5), - vitessResultSet.getBigDecimal(18)); - } - - @Test public void testgetBytes() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - Assert.assertArrayEquals("HELLO TDS TEAM".getBytes("UTF-8"), vitessResultSet.getBytes(19)); - } - - @Test public void testgetDate() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new java.sql.Date(116, 1, 6), vitessResultSet.getDate(14)); - } - - @Test public void testgetTime() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new Time(12, 34, 56), vitessResultSet.getTime(15)); - } - - @Test public void testgetTimestamp() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new Timestamp(116, 1, 6, 14, 15, 16, 0), - vitessResultSet.getTimestamp(13)); - } - - @Test public void testgetZeroTimestampGarble() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=garble", new Properties()))); - vitessResultSet.next(); - assertEquals("0002-11-30 00:00:00.0", - vitessResultSet.getTimestamp(28).toString()); - } - - @Test public void testgetZeroTimestampConvertToNill() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=convertToNull", new Properties()))); - vitessResultSet.next(); - Assert.assertNull(vitessResultSet.getTimestamp(28)); - } - - @Test public void testgetZeroTimestampException() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=exception", new Properties()))); - vitessResultSet.next(); - try { - vitessResultSet.getTimestamp(28); - Assert.fail("expected getTimestamp to throw an exception"); - } catch (SQLException e) {} - } - - @Test public void testgetZeroTimestampRound() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=round", new Properties()))); - vitessResultSet.next(); - assertEquals("0001-01-01 00:00:00.0", vitessResultSet.getTimestamp(28).toString()); - } - - @Test public void testgetZeroDateRound() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, - new VitessStatement(new VitessConnection( - "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=round", new Properties()))); - vitessResultSet.next(); - assertEquals("0001-01-01", vitessResultSet.getDate(28).toString()); - } - - @Test public void testgetStringbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals("-50", vitessResultSet.getString("col1")); - assertEquals("50", vitessResultSet.getString("col2")); - assertEquals("-23000", vitessResultSet.getString("col3")); - assertEquals("23000", vitessResultSet.getString("col4")); - assertEquals("-100", vitessResultSet.getString("col5")); - assertEquals("100", vitessResultSet.getString("col6")); - assertEquals("-100", vitessResultSet.getString("col7")); - assertEquals("100", vitessResultSet.getString("col8")); - assertEquals("-1000", vitessResultSet.getString("col9")); - assertEquals("1000", vitessResultSet.getString("col10")); - assertEquals("24.52", vitessResultSet.getString("col11")); - assertEquals("100.43", vitessResultSet.getString("col12")); - assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString("col13")); - assertEquals("2016-02-06", vitessResultSet.getString("col14")); - assertEquals("12:34:56", vitessResultSet.getString("col15")); - assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString("col16")); - assertEquals("2016", vitessResultSet.getString("col17")); - assertEquals("1234.56789", vitessResultSet.getString("col18")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col19")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col20")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col21")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col22")); - assertEquals("N", vitessResultSet.getString("col23")); - assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col24")); - assertEquals("1", vitessResultSet.getString("col25")); - assertEquals("val123", vitessResultSet.getString("col26")); - assertEquals("val123", vitessResultSet.getString("col27")); - } - - @Test public void testgetBooleanbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(true, vitessResultSet.getBoolean("col25")); - assertEquals(false, vitessResultSet.getBoolean("col1")); - } - - @Test public void testgetBytebyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-50, vitessResultSet.getByte("col1")); - assertEquals(1, vitessResultSet.getByte("col25")); - } - - @Test public void testgetShortbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-23000, vitessResultSet.getShort("col3")); - } - - @Test public void testgetIntbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-100, vitessResultSet.getInt("col7")); - } - - @Test public void testgetLongbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(-1000, vitessResultSet.getInt("col9")); - } - - @Test public void testBigIntegerbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new BigInteger("1000"), - vitessResultSet.getBigInteger("col10")); - } - - @Test public void testgetFloatbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(24.52f, vitessResultSet.getFloat("col11"), 0.001); - } - - @Test public void testgetDoublebyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(100.43, vitessResultSet.getFloat("col12"), 0.001); - } - - @Test public void testBigDecimalbyColumnLabel() throws SQLException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new BigDecimal(BigInteger.valueOf(123456789), 5), - vitessResultSet.getBigDecimal("col18")); - } - - @Test public void testgetBytesbyColumnLabel() - throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - Assert.assertArrayEquals("HELLO TDS TEAM".getBytes("UTF-8"), - vitessResultSet.getBytes("col19")); - } - - @Test public void testgetDatebyColumnLabel() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new java.sql.Date(116, 1, 6), vitessResultSet.getDate("col14")); - } - - @Test public void testgetTimebyColumnLabel() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new Time(12, 34, 56), vitessResultSet.getTime("col15")); - } - - @Test public void testgetTimestampbyColumnLabel() - throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - assertEquals(new Timestamp(116, 1, 6, 14, 15, 16, 0), - vitessResultSet.getTimestamp("col13")); - } - - @Test public void testgetAsciiStream() throws SQLException, UnsupportedEncodingException { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor); - vitessResultSet.next(); - // Need to implement AssertEquivalant - //Assert.assertEquals((InputStream)(new ByteArrayInputStream("HELLO TDS TEAM".getBytes())), vitessResultSet - // .getAsciiStream(19)); - } - - @Test public void testGetBinaryStream() throws SQLException, IOException { - Cursor cursor = getCursorWithRowsAsNull(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - vitessResultSet.next(); - byte[] ba1 = new byte[128]; - new ByteArrayInputStream("HELLO TDS TEAM".getBytes()).read(ba1, 0, 128); - byte[] ba2 = new byte[128]; - vitessResultSet.getBinaryStream(19).read(ba2, 0, 128); - Assert.assertArrayEquals(ba1, ba2); - - byte[] ba3 = new byte[128]; - vitessResultSet.getBinaryStream(22).read(ba3, 0, 128); - Assert.assertArrayEquals(ba1, ba3); - - assertEquals(null, vitessResultSet.getBinaryStream(27)); - } - - @Test public void testEnhancedFieldsFromCursor() throws Exception { - Cursor cursor = getCursorWithRows(); - VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); - assertEquals(cursor.getFields().size(), vitessResultSet.getFields().size()); - } - - @Test public void testGetStringUsesEncoding() throws Exception { - VitessConnection conn = getVitessConnection(); - VitessResultSet resultOne = PowerMockito.spy(new VitessResultSet(getCursorWithRows(), new VitessStatement(conn))); - resultOne.next(); - // test all ways to get to convertBytesToString - - // Verify that we're going through convertBytesToString for column types that return bytes (string-like), - // but not for those that return a real object - resultOne.getString("col21"); // is a string, should go through convert bytes - resultOne.getString("col13"); // is a datetime, should not - PowerMockito.verifyPrivate(resultOne, VerificationModeFactory.times(1)).invoke("convertBytesToString", Matchers.any(byte[].class), Matchers.anyString()); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - VitessResultSet resultTwo = PowerMockito.spy(new VitessResultSet(getCursorWithRows(), new VitessStatement(conn))); - resultTwo.next(); - - // neither of these should go through convertBytesToString, because we didn't include all fields - resultTwo.getString("col21"); - resultTwo.getString("col13"); - PowerMockito.verifyPrivate(resultTwo, VerificationModeFactory.times(0)).invoke("convertBytesToString", Matchers.any(byte[].class), Matchers.anyString()); - } - - @Test public void testGetObjectForBitValues() throws Exception { - VitessConnection conn = getVitessConnection(); - - ByteString.Output value = ByteString.newOutput(); - value.write(new byte[] {1}); - value.write(new byte[] {0}); - value.write(new byte[] {1,2,3,4}); - - Query.QueryResult result = Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("col1").setColumnLength(1).setType(Query.Type.BIT)) - .addFields(Query.Field.newBuilder().setName("col2").setColumnLength(1).setType(Query.Type.BIT)) - .addFields(Query.Field.newBuilder().setName("col3").setColumnLength(4).setType(Query.Type.BIT)) - .addRows(Query.Row.newBuilder() - .addLengths(1) - .addLengths(1) - .addLengths(4) - .setValues(value.toByteString())) - .build(); - - VitessResultSet vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - assertEquals(true, vitessResultSet.getObject(1)); - assertEquals(false, vitessResultSet.getObject(2)); - Assert.assertArrayEquals(new byte[] {1,2,3,4}, (byte[]) vitessResultSet.getObject(3)); - - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(3)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - Assert.assertArrayEquals(new byte[] { 1 }, (byte[]) vitessResultSet.getObject(1)); - Assert.assertArrayEquals(new byte[] { 0 }, (byte[]) vitessResultSet.getObject(2)); - Assert.assertArrayEquals(new byte[] {1,2,3,4}, (byte[]) vitessResultSet.getObject(3)); - - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - } - - @Test public void testGetObjectForVarBinLikeValues() throws Exception { - VitessConnection conn = getVitessConnection(); - - ByteString.Output value = ByteString.newOutput(); - - byte[] binary = new byte[] {1,2,3,4}; - byte[] varbinary = new byte[] {1,2,3,4,5,6,7,8,9,10,11,12,13}; - byte[] blob = new byte[MysqlDefs.LENGTH_BLOB]; - for (int i = 0; i < blob.length; i++) { - blob[i] = 1; - } - byte[] fakeGeometry = new byte[] {2,3,4}; - - value.write(binary); - value.write(varbinary); - value.write(blob); - value.write(fakeGeometry); - - Query.QueryResult result = Query.QueryResult.newBuilder() - .addFields(Query.Field.newBuilder().setName("col1") - .setColumnLength(4) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setType(Query.Type.BINARY) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)) - .addFields(Query.Field.newBuilder().setName("col2") - .setColumnLength(13) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setType(Query.Type.VARBINARY) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)) - .addFields(Query.Field.newBuilder().setName("col3") // should go to LONGVARBINARY due to below settings - .setColumnLength(MysqlDefs.LENGTH_BLOB) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .setType(Query.Type.BLOB)) - .addFields(Query.Field.newBuilder().setName("col4") - .setType(Query.Type.GEOMETRY) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setType(Query.Type.BINARY) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)) - .addRows(Query.Row.newBuilder() - .addLengths(4) - .addLengths(13) - .addLengths(MysqlDefs.LENGTH_BLOB) - .addLengths(3) - .setValues(value.toByteString())) - .build(); - - VitessResultSet vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - // All of these types should pass straight through, returning the direct bytes - Assert.assertArrayEquals(binary, (byte[]) vitessResultSet.getObject(1)); - Assert.assertArrayEquals(varbinary, (byte[]) vitessResultSet.getObject(2)); - Assert.assertArrayEquals(blob, (byte[]) vitessResultSet.getObject(3)); - Assert.assertArrayEquals(fakeGeometry, (byte[]) vitessResultSet.getObject(4)); - - // We should still call the function 4 times - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(4)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - // Same as above since this doesn't really do much but pass right through for the varbinary type - Assert.assertArrayEquals(binary, (byte[]) vitessResultSet.getObject(1)); - Assert.assertArrayEquals(varbinary, (byte[]) vitessResultSet.getObject(2)); - Assert.assertArrayEquals(blob, (byte[]) vitessResultSet.getObject(3)); - Assert.assertArrayEquals(fakeGeometry, (byte[]) vitessResultSet.getObject(4)); - - // Never call because not including all - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - } - - @Test public void testGetObjectForStringLikeValues() throws Exception { - ByteString.Output value = ByteString.newOutput(); - - String trimmedCharStr = "wasting space"; - String varcharStr = "i have a variable length!"; - String masqueradingBlobStr = "look at me, im a blob"; - String textStr = "an enthralling string of TEXT in some foreign language"; - String jsonStr = "{\"status\": \"ok\"}"; - - int paddedCharColLength = 20; - byte[] trimmedChar = StringUtils.getBytes(trimmedCharStr, "UTF-16"); - byte[] varchar = StringUtils.getBytes(varcharStr, "UTF-8"); - byte[] masqueradingBlob = StringUtils.getBytes(masqueradingBlobStr, "US-ASCII"); - byte[] text = StringUtils.getBytes(textStr, "ISO8859_8"); - byte[] opaqueBinary = new byte[] { 1,2,3,4,5,6,7,8,9}; - byte[] json = StringUtils.getBytes(jsonStr, "UTF-8"); - - value.write(trimmedChar); - value.write(varchar); - value.write(opaqueBinary); - value.write(masqueradingBlob); - value.write(text); - value.write(json); - - Query.QueryResult result = Query.QueryResult.newBuilder() - // This tests CHAR - .addFields(Query.Field.newBuilder().setName("col1") - .setColumnLength(paddedCharColLength) - .setCharset(/* utf-16 collation index from CharsetMapping */ 54) - .setType(Query.Type.CHAR)) - // This tests VARCHAR - .addFields(Query.Field.newBuilder().setName("col2") - .setColumnLength(varchar.length) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8) - .setType(Query.Type.VARCHAR)) - // This tests VARCHAR that is an opaque binary - .addFields(Query.Field.newBuilder().setName("col2") - .setColumnLength(opaqueBinary.length) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) - .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE) - .setType(Query.Type.VARCHAR)) - // This tests LONGVARCHAR - .addFields(Query.Field.newBuilder().setName("col3") - .setColumnLength(masqueradingBlob.length) - .setCharset(/* us-ascii collation index from CharsetMapping */11) - .setType(Query.Type.BLOB)) - // This tests TEXT, which falls through the default case of the switch - .addFields(Query.Field.newBuilder().setName("col4") - .setColumnLength(text.length) - .setCharset(/* corresponds to greek, from CharsetMapping */25) - .setType(Query.Type.TEXT)) - .addFields(Query.Field.newBuilder().setName("col5") - .setColumnLength(json.length) - .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8) - .setType(Query.Type.JSON)) - .addRows(Query.Row.newBuilder() - .addLengths(trimmedChar.length) - .addLengths(varchar.length) - .addLengths(opaqueBinary.length) - .addLengths(masqueradingBlob.length) - .addLengths(text.length) - .addLengths(json.length) - .setValues(value.toByteString())) - .build(); - - VitessConnection conn = getVitessConnection(); - VitessResultSet vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - assertEquals(trimmedCharStr, vitessResultSet.getObject(1)); - assertEquals(varcharStr, vitessResultSet.getObject(2)); - Assert.assertArrayEquals(opaqueBinary, (byte[]) vitessResultSet.getObject(3)); - assertEquals(masqueradingBlobStr, vitessResultSet.getObject(4)); - assertEquals(textStr, vitessResultSet.getObject(5)); - assertEquals(jsonStr, vitessResultSet.getObject(6)); - - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(6)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - - conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); - vitessResultSet = PowerMockito.spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); - vitessResultSet.next(); - - Assert.assertArrayEquals(trimmedChar, (byte[]) vitessResultSet.getObject(1)); - Assert.assertArrayEquals(varchar, (byte[]) vitessResultSet.getObject(2)); - Assert.assertArrayEquals(opaqueBinary, (byte[]) vitessResultSet.getObject(3)); - Assert.assertArrayEquals(masqueradingBlob, (byte[]) vitessResultSet.getObject(4)); - Assert.assertArrayEquals(text, (byte[]) vitessResultSet.getObject(5)); - Assert.assertArrayEquals(json, (byte[]) vitessResultSet.getObject(6)); - - PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)).invoke("convertBytesIfPossible", Matchers.any(byte[].class), Matchers.any(FieldWithMetadata.class)); - } - - @Test public void testGetClob() throws SQLException { - VitessResultSet vitessResultSet = new VitessResultSet( - new String[]{"clob"}, new Query.Type[]{Query.Type.VARCHAR}, - new String[][]{new String[] {"clobValue"}}, - new ConnectionProperties()); - Assert.assertTrue(vitessResultSet.next()); - - Clob clob = vitessResultSet.getClob(1); - assertEquals("clobValue", clob.getSubString(1, (int) clob.length())); - - clob = vitessResultSet.getClob("clob"); - assertEquals("clobValue", clob.getSubString(1, (int) clob.length())); - } + VitessResultSet vitessResultSet = new VitessResultSet(cursor); + assertEquals(false, vitessResultSet.next()); + } + + @Test + public void testNextWithNonZeroRows() throws Exception { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor); + assertEquals(true, vitessResultSet.next()); + assertEquals(false, vitessResultSet.next()); + } + + @Test + public void testgetString() throws SQLException { + Cursor cursor = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals("-50", vitessResultSet.getString(1)); + assertEquals("50", vitessResultSet.getString(2)); + assertEquals("-23000", vitessResultSet.getString(3)); + assertEquals("23000", vitessResultSet.getString(4)); + assertEquals("-100", vitessResultSet.getString(5)); + assertEquals("100", vitessResultSet.getString(6)); + assertEquals("-100", vitessResultSet.getString(7)); + assertEquals("100", vitessResultSet.getString(8)); + assertEquals("-1000", vitessResultSet.getString(9)); + assertEquals("1000", vitessResultSet.getString(10)); + assertEquals("24.52", vitessResultSet.getString(11)); + assertEquals("100.43", vitessResultSet.getString(12)); + assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString(13)); + assertEquals("2016-02-06", vitessResultSet.getString(14)); + assertEquals("12:34:56", vitessResultSet.getString(15)); + assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString(16)); + assertEquals("2016", vitessResultSet.getString(17)); + assertEquals("1234.56789", vitessResultSet.getString(18)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(19)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(20)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(21)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(22)); + assertEquals("N", vitessResultSet.getString(23)); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString(24)); + assertEquals("0", vitessResultSet.getString(25)); + assertEquals("val123", vitessResultSet.getString(26)); + assertEquals(null, vitessResultSet.getString(27)); + } + + @Test + public void getObjectUint64AsBigInteger() throws SQLException { + Cursor cursor = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + + assertEquals(new BigInteger("1000"), vitessResultSet.getObject(10)); + } + + @Test + public void getBigInteger() throws SQLException { + Cursor cursor = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + + assertEquals(new BigInteger("1000"), vitessResultSet.getBigInteger(10)); + } + + @Test + public void testgetBoolean() throws SQLException { + Cursor cursor = getCursorWithRows(); + Cursor cursorWithRowsAsNull = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(true, vitessResultSet.getBoolean(25)); + assertEquals(false, vitessResultSet.getBoolean(1)); + vitessResultSet = new VitessResultSet(cursorWithRowsAsNull, getVitessStatement()); + vitessResultSet.next(); + assertEquals(false, vitessResultSet.getBoolean(25)); + assertEquals(false, vitessResultSet.getBoolean(1)); + } + + @Test + public void testgetByte() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-50, vitessResultSet.getByte(1)); + assertEquals(1, vitessResultSet.getByte(25)); + } + + @Test + public void testgetShort() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-23000, vitessResultSet.getShort(3)); + } + + @Test + public void testgetInt() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-100, vitessResultSet.getInt(7)); + } + + @Test + public void testgetLong() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-1000, vitessResultSet.getInt(9)); + } + + @Test + public void testgetFloat() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(24.52f, vitessResultSet.getFloat(11), 0.001); + } + + @Test + public void testgetDouble() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(100.43, vitessResultSet.getFloat(12), 0.001); + } + + @Test + public void testBigDecimal() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new BigDecimal(BigInteger.valueOf(123456789), 5), + vitessResultSet.getBigDecimal(18)); + } + + @Test + public void testgetBytes() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + Assert.assertArrayEquals("HELLO TDS TEAM".getBytes("UTF-8"), vitessResultSet.getBytes(19)); + } + + @Test + public void testgetDate() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new java.sql.Date(116, 1, 6), vitessResultSet.getDate(14)); + } + + @Test + public void testgetTime() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new Time(12, 34, 56), vitessResultSet.getTime(15)); + } + + @Test + public void testgetTimestamp() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new Timestamp(116, 1, 6, 14, 15, 16, 0), vitessResultSet.getTimestamp(13)); + } + + @Test + public void testgetZeroTimestampGarble() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=garble", + new Properties()))); + vitessResultSet.next(); + assertEquals("0002-11-30 00:00:00.0", vitessResultSet.getTimestamp(28).toString()); + } + + @Test + public void testgetZeroTimestampConvertToNill() + throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=convertToNull", + new Properties()))); + vitessResultSet.next(); + Assert.assertNull(vitessResultSet.getTimestamp(28)); + } + + @Test + public void testgetZeroTimestampException() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=exception", + new Properties()))); + vitessResultSet.next(); + try { + vitessResultSet.getTimestamp(28); + Assert.fail("expected getTimestamp to throw an exception"); + } catch (SQLException e) { + } + } + + @Test + public void testgetZeroTimestampRound() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=round", + new Properties()))); + vitessResultSet.next(); + assertEquals("0001-01-01 00:00:00.0", vitessResultSet.getTimestamp(28).toString()); + } + + @Test + public void testgetZeroDateRound() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, new VitessStatement( + new VitessConnection( + "jdbc:vitess://locahost:9000/vt_keyspace/keyspace?zeroDateTimeBehavior=round", + new Properties()))); + vitessResultSet.next(); + assertEquals("0001-01-01", vitessResultSet.getDate(28).toString()); + } + + @Test + public void testgetStringbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals("-50", vitessResultSet.getString("col1")); + assertEquals("50", vitessResultSet.getString("col2")); + assertEquals("-23000", vitessResultSet.getString("col3")); + assertEquals("23000", vitessResultSet.getString("col4")); + assertEquals("-100", vitessResultSet.getString("col5")); + assertEquals("100", vitessResultSet.getString("col6")); + assertEquals("-100", vitessResultSet.getString("col7")); + assertEquals("100", vitessResultSet.getString("col8")); + assertEquals("-1000", vitessResultSet.getString("col9")); + assertEquals("1000", vitessResultSet.getString("col10")); + assertEquals("24.52", vitessResultSet.getString("col11")); + assertEquals("100.43", vitessResultSet.getString("col12")); + assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString("col13")); + assertEquals("2016-02-06", vitessResultSet.getString("col14")); + assertEquals("12:34:56", vitessResultSet.getString("col15")); + assertEquals("2016-02-06 14:15:16.0", vitessResultSet.getString("col16")); + assertEquals("2016", vitessResultSet.getString("col17")); + assertEquals("1234.56789", vitessResultSet.getString("col18")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col19")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col20")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col21")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col22")); + assertEquals("N", vitessResultSet.getString("col23")); + assertEquals("HELLO TDS TEAM", vitessResultSet.getString("col24")); + assertEquals("1", vitessResultSet.getString("col25")); + assertEquals("val123", vitessResultSet.getString("col26")); + assertEquals("val123", vitessResultSet.getString("col27")); + } + + @Test + public void testgetBooleanbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(true, vitessResultSet.getBoolean("col25")); + assertEquals(false, vitessResultSet.getBoolean("col1")); + } + + @Test + public void testgetBytebyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-50, vitessResultSet.getByte("col1")); + assertEquals(1, vitessResultSet.getByte("col25")); + } + + @Test + public void testgetShortbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-23000, vitessResultSet.getShort("col3")); + } + + @Test + public void testgetIntbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-100, vitessResultSet.getInt("col7")); + } + + @Test + public void testgetLongbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(-1000, vitessResultSet.getInt("col9")); + } + + @Test + public void testBigIntegerbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new BigInteger("1000"), vitessResultSet.getBigInteger("col10")); + } + + @Test + public void testgetFloatbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(24.52f, vitessResultSet.getFloat("col11"), 0.001); + } + + @Test + public void testgetDoublebyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(100.43, vitessResultSet.getFloat("col12"), 0.001); + } + + @Test + public void testBigDecimalbyColumnLabel() throws SQLException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new BigDecimal(BigInteger.valueOf(123456789), 5), + vitessResultSet.getBigDecimal("col18")); + } + + @Test + public void testgetBytesbyColumnLabel() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + Assert.assertArrayEquals("HELLO TDS TEAM".getBytes("UTF-8"), vitessResultSet.getBytes("col19")); + } + + @Test + public void testgetDatebyColumnLabel() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new java.sql.Date(116, 1, 6), vitessResultSet.getDate("col14")); + } + + @Test + public void testgetTimebyColumnLabel() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new Time(12, 34, 56), vitessResultSet.getTime("col15")); + } + + @Test + public void testgetTimestampbyColumnLabel() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + assertEquals(new Timestamp(116, 1, 6, 14, 15, 16, 0), vitessResultSet.getTimestamp("col13")); + } + + @Test + public void testgetAsciiStream() throws SQLException, UnsupportedEncodingException { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor); + vitessResultSet.next(); + // Need to implement AssertEquivalant + //Assert.assertEquals((InputStream)(new ByteArrayInputStream("HELLO TDS TEAM".getBytes())), + // vitessResultSet + // .getAsciiStream(19)); + } + + @Test + public void testGetBinaryStream() throws SQLException, IOException { + Cursor cursor = getCursorWithRowsAsNull(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + vitessResultSet.next(); + byte[] ba1 = new byte[128]; + new ByteArrayInputStream("HELLO TDS TEAM".getBytes()).read(ba1, 0, 128); + byte[] ba2 = new byte[128]; + vitessResultSet.getBinaryStream(19).read(ba2, 0, 128); + Assert.assertArrayEquals(ba1, ba2); + + byte[] ba3 = new byte[128]; + vitessResultSet.getBinaryStream(22).read(ba3, 0, 128); + Assert.assertArrayEquals(ba1, ba3); + + assertEquals(null, vitessResultSet.getBinaryStream(27)); + } + + @Test + public void testEnhancedFieldsFromCursor() throws Exception { + Cursor cursor = getCursorWithRows(); + VitessResultSet vitessResultSet = new VitessResultSet(cursor, getVitessStatement()); + assertEquals(cursor.getFields().size(), vitessResultSet.getFields().size()); + } + + @Test + public void testGetStringUsesEncoding() throws Exception { + VitessConnection conn = getVitessConnection(); + VitessResultSet resultOne = PowerMockito + .spy(new VitessResultSet(getCursorWithRows(), new VitessStatement(conn))); + resultOne.next(); + // test all ways to get to convertBytesToString + + // Verify that we're going through convertBytesToString for column types that return bytes + // (string-like), + // but not for those that return a real object + resultOne.getString("col21"); // is a string, should go through convert bytes + resultOne.getString("col13"); // is a datetime, should not + PowerMockito.verifyPrivate(resultOne, VerificationModeFactory.times(1)) + .invoke("convertBytesToString", Matchers.any(byte[].class), Matchers.anyString()); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + VitessResultSet resultTwo = PowerMockito + .spy(new VitessResultSet(getCursorWithRows(), new VitessStatement(conn))); + resultTwo.next(); + + // neither of these should go through convertBytesToString, because we didn't include all fields + resultTwo.getString("col21"); + resultTwo.getString("col13"); + PowerMockito.verifyPrivate(resultTwo, VerificationModeFactory.times(0)) + .invoke("convertBytesToString", Matchers.any(byte[].class), Matchers.anyString()); + } + + @Test + public void testGetObjectForBitValues() throws Exception { + VitessConnection conn = getVitessConnection(); + + ByteString.Output value = ByteString.newOutput(); + value.write(new byte[]{1}); + value.write(new byte[]{0}); + value.write(new byte[]{1, 2, 3, 4}); + + Query.QueryResult result = Query.QueryResult.newBuilder().addFields( + Query.Field.newBuilder().setName("col1").setColumnLength(1).setType(Query.Type.BIT)) + .addFields( + Query.Field.newBuilder().setName("col2").setColumnLength(1).setType(Query.Type.BIT)) + .addFields( + Query.Field.newBuilder().setName("col3").setColumnLength(4).setType(Query.Type.BIT)) + .addRows(Query.Row.newBuilder().addLengths(1).addLengths(1).addLengths(4) + .setValues(value.toByteString())).build(); + + VitessResultSet vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + assertEquals(true, vitessResultSet.getObject(1)); + assertEquals(false, vitessResultSet.getObject(2)); + Assert.assertArrayEquals(new byte[]{1, 2, 3, 4}, (byte[]) vitessResultSet.getObject(3)); + + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(3)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + Assert.assertArrayEquals(new byte[]{1}, (byte[]) vitessResultSet.getObject(1)); + Assert.assertArrayEquals(new byte[]{0}, (byte[]) vitessResultSet.getObject(2)); + Assert.assertArrayEquals(new byte[]{1, 2, 3, 4}, (byte[]) vitessResultSet.getObject(3)); + + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + } + + @Test + public void testGetObjectForVarBinLikeValues() throws Exception { + VitessConnection conn = getVitessConnection(); + + ByteString.Output value = ByteString.newOutput(); + + byte[] binary = new byte[]{1, 2, 3, 4}; + byte[] varbinary = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; + byte[] blob = new byte[MysqlDefs.LENGTH_BLOB]; + for (int i = 0; i < blob.length; i++) { + blob[i] = 1; + } + byte[] fakeGeometry = new byte[]{2, 3, 4}; + + value.write(binary); + value.write(varbinary); + value.write(blob); + value.write(fakeGeometry); + + Query.QueryResult result = Query.QueryResult.newBuilder().addFields( + Query.Field.newBuilder().setName("col1").setColumnLength(4) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary).setType(Query.Type.BINARY) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)).addFields( + Query.Field.newBuilder().setName("col2").setColumnLength(13) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary).setType(Query.Type.VARBINARY) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)).addFields( + Query.Field.newBuilder().setName("col3") // should go to LONGVARBINARY due to below settings + .setColumnLength(MysqlDefs.LENGTH_BLOB) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).setType(Query.Type.BLOB)).addFields( + Query.Field.newBuilder().setName("col4").setType(Query.Type.GEOMETRY) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary).setType(Query.Type.BINARY) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE)).addRows( + Query.Row.newBuilder().addLengths(4).addLengths(13).addLengths(MysqlDefs.LENGTH_BLOB) + .addLengths(3).setValues(value.toByteString())).build(); + + VitessResultSet vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + // All of these types should pass straight through, returning the direct bytes + Assert.assertArrayEquals(binary, (byte[]) vitessResultSet.getObject(1)); + Assert.assertArrayEquals(varbinary, (byte[]) vitessResultSet.getObject(2)); + Assert.assertArrayEquals(blob, (byte[]) vitessResultSet.getObject(3)); + Assert.assertArrayEquals(fakeGeometry, (byte[]) vitessResultSet.getObject(4)); + + // We should still call the function 4 times + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(4)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + // Same as above since this doesn't really do much but pass right through for the varbinary type + Assert.assertArrayEquals(binary, (byte[]) vitessResultSet.getObject(1)); + Assert.assertArrayEquals(varbinary, (byte[]) vitessResultSet.getObject(2)); + Assert.assertArrayEquals(blob, (byte[]) vitessResultSet.getObject(3)); + Assert.assertArrayEquals(fakeGeometry, (byte[]) vitessResultSet.getObject(4)); + + // Never call because not including all + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + } + + @Test + public void testGetObjectForStringLikeValues() throws Exception { + ByteString.Output value = ByteString.newOutput(); + + String trimmedCharStr = "wasting space"; + String varcharStr = "i have a variable length!"; + String masqueradingBlobStr = "look at me, im a blob"; + String textStr = "an enthralling string of TEXT in some foreign language"; + String jsonStr = "{\"status\": \"ok\"}"; + + int paddedCharColLength = 20; + byte[] trimmedChar = StringUtils.getBytes(trimmedCharStr, "UTF-16"); + byte[] varchar = StringUtils.getBytes(varcharStr, "UTF-8"); + byte[] masqueradingBlob = StringUtils.getBytes(masqueradingBlobStr, "US-ASCII"); + byte[] text = StringUtils.getBytes(textStr, "ISO8859_8"); + byte[] opaqueBinary = new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9}; + byte[] json = StringUtils.getBytes(jsonStr, "UTF-8"); + + value.write(trimmedChar); + value.write(varchar); + value.write(opaqueBinary); + value.write(masqueradingBlob); + value.write(text); + value.write(json); + + Query.QueryResult result = Query.QueryResult.newBuilder() + // This tests CHAR + .addFields(Query.Field.newBuilder().setName("col1").setColumnLength(paddedCharColLength) + .setCharset(/* utf-16 collation index from CharsetMapping */ 54) + .setType(Query.Type.CHAR)) + // This tests VARCHAR + .addFields(Query.Field.newBuilder().setName("col2").setColumnLength(varchar.length) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).setType(Query.Type.VARCHAR)) + // This tests VARCHAR that is an opaque binary + .addFields(Query.Field.newBuilder().setName("col2").setColumnLength(opaqueBinary.length) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_binary) + .setFlags(Query.MySqlFlag.BINARY_FLAG_VALUE).setType(Query.Type.VARCHAR)) + // This tests LONGVARCHAR + .addFields(Query.Field.newBuilder().setName("col3").setColumnLength(masqueradingBlob.length) + .setCharset(/* us-ascii collation index from CharsetMapping */11) + .setType(Query.Type.BLOB)) + // This tests TEXT, which falls through the default case of the switch + .addFields(Query.Field.newBuilder().setName("col4").setColumnLength(text.length) + .setCharset(/* corresponds to greek, from CharsetMapping */25).setType(Query.Type.TEXT)) + .addFields(Query.Field.newBuilder().setName("col5").setColumnLength(json.length) + .setCharset(CharsetMapping.MYSQL_COLLATION_INDEX_utf8).setType(Query.Type.JSON)) + .addRows(Query.Row.newBuilder().addLengths(trimmedChar.length).addLengths(varchar.length) + .addLengths(opaqueBinary.length).addLengths(masqueradingBlob.length) + .addLengths(text.length).addLengths(json.length).setValues(value.toByteString())) + .build(); + + VitessConnection conn = getVitessConnection(); + VitessResultSet vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + assertEquals(trimmedCharStr, vitessResultSet.getObject(1)); + assertEquals(varcharStr, vitessResultSet.getObject(2)); + Assert.assertArrayEquals(opaqueBinary, (byte[]) vitessResultSet.getObject(3)); + assertEquals(masqueradingBlobStr, vitessResultSet.getObject(4)); + assertEquals(textStr, vitessResultSet.getObject(5)); + assertEquals(jsonStr, vitessResultSet.getObject(6)); + + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(6)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + + conn.setIncludedFields(Query.ExecuteOptions.IncludedFields.TYPE_AND_NAME); + vitessResultSet = PowerMockito + .spy(new VitessResultSet(new SimpleCursor(result), new VitessStatement(conn))); + vitessResultSet.next(); + + Assert.assertArrayEquals(trimmedChar, (byte[]) vitessResultSet.getObject(1)); + Assert.assertArrayEquals(varchar, (byte[]) vitessResultSet.getObject(2)); + Assert.assertArrayEquals(opaqueBinary, (byte[]) vitessResultSet.getObject(3)); + Assert.assertArrayEquals(masqueradingBlob, (byte[]) vitessResultSet.getObject(4)); + Assert.assertArrayEquals(text, (byte[]) vitessResultSet.getObject(5)); + Assert.assertArrayEquals(json, (byte[]) vitessResultSet.getObject(6)); + + PowerMockito.verifyPrivate(vitessResultSet, VerificationModeFactory.times(0)) + .invoke("convertBytesIfPossible", Matchers.any(byte[].class), + Matchers.any(FieldWithMetadata.class)); + } + + @Test + public void testGetClob() throws SQLException { + VitessResultSet vitessResultSet = new VitessResultSet(new String[]{"clob"}, + new Query.Type[]{Query.Type.VARCHAR}, new String[][]{new String[]{"clobValue"}}, + new ConnectionProperties()); + Assert.assertTrue(vitessResultSet.next()); + + Clob clob = vitessResultSet.getClob(1); + assertEquals("clobValue", clob.getSubString(1, (int) clob.length())); + + clob = vitessResultSet.getClob("clob"); + assertEquals("clobValue", clob.getSubString(1, (int) clob.length())); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java index 2880d5ab3fe..4ea49adfcb2 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessStatementTest.java @@ -16,12 +16,20 @@ package io.vitess.jdbc; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mockito; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyList; +import static org.mockito.Matchers.anyMap; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.verify; +import static org.powermock.api.mockito.PowerMockito.doReturn; +import static org.powermock.api.mockito.PowerMockito.mock; +import static org.powermock.api.mockito.PowerMockito.when; import io.vitess.client.Context; import io.vitess.client.SQLFuture; @@ -41,697 +49,671 @@ import java.util.ArrayList; import java.util.List; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyList; -import static org.mockito.Matchers.anyMap; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.verify; -import static org.powermock.api.mockito.PowerMockito.doReturn; -import static org.powermock.api.mockito.PowerMockito.mock; -import static org.powermock.api.mockito.PowerMockito.when; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; /** * Created by harshit.gangal on 19/01/16. */ @RunWith(PowerMockRunner.class) -@PrepareForTest({VTGateConnection.class, - Vtrpc.RPCError.class}) +@PrepareForTest({VTGateConnection.class, Vtrpc.RPCError.class}) public class VitessStatementTest { - private String sqlSelect = "select 1 from test_table"; - private String sqlShow = "show tables"; - private String sqlUpdate = "update test_table set msg = null"; - private String sqlInsert = "insert into test_table(msg) values ('abc')"; - private String sqlUpsert = "insert into test_table(msg) values ('abc') on duplicate key update msg = 'def'"; - - - @Test - public void testGetConnection() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(mockConn, statement.getConnection()); + private String sqlSelect = "select 1 from test_table"; + private String sqlShow = "show tables"; + private String sqlUpdate = "update test_table set msg = null"; + private String sqlInsert = "insert into test_table(msg) values ('abc')"; + private String sqlUpsert = "insert into test_table(msg) values ('abc') on duplicate key update " + + "msg = 'def'"; + + + @Test + public void testGetConnection() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(mockConn, statement.getConnection()); + } + + @Test + public void testGetResultSet() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(null, statement.getResultSet()); + } + + @Test + public void testExecuteQuery() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockConn.isSimpleExecute()).thenReturn(true); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + //Empty Sql Statement + try { + statement.executeQuery(""); + fail("Should have thrown exception for empty sql"); + } catch (SQLException ex) { + assertEquals("SQL statement is not valid", ex.getMessage()); } - @Test - public void testGetResultSet() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(null, statement.getResultSet()); + ResultSet rs = statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + + //autocommit is false and not in transaction + when(mockConn.getAutoCommit()).thenReturn(false); + when(mockConn.isInTransaction()).thenReturn(false); + rs = statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + + //when returned cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + statement.executeQuery(sqlSelect); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); } - - @Test - public void testExecuteQuery() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), any( - VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockConn.isSimpleExecute()).thenReturn(true); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - //Empty Sql Statement - try { - statement.executeQuery(""); - fail("Should have thrown exception for empty sql"); - } catch (SQLException ex) { - assertEquals("SQL statement is not valid", ex.getMessage()); - } - - ResultSet rs = statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); - - //autocommit is false and not in transaction - when(mockConn.getAutoCommit()).thenReturn(false); - when(mockConn.isInTransaction()).thenReturn(false); - rs = statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); - - //when returned cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - statement.executeQuery(sqlSelect); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } + } + + @Test + public void testExecuteQueryWithStreamExecuteType() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.STREAM); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + //Empty Sql Statement + try { + statement.executeQuery(""); + fail("Should have thrown exception for empty sql"); + } catch (SQLException ex) { + assertEquals("SQL statement is not valid", ex.getMessage()); } - @Test - public void testExecuteQueryWithStreamExecuteType() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.STREAM); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - //Empty Sql Statement - try { - statement.executeQuery(""); - fail("Should have thrown exception for empty sql"); - } catch (SQLException ex) { - assertEquals("SQL statement is not valid", ex.getMessage()); - } - - //select on replica - ResultSet rs = statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); - - //show query - rs = statement.executeQuery(sqlShow); - assertEquals(-1, statement.getUpdateCount()); - - //select on master when tx is null and autocommit is false - when(mockConn.getAutoCommit()).thenReturn(false); - when(mockConn.isInTransaction()).thenReturn(false); - rs = statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); - - //when returned cursor is null - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(null); - try { - statement.executeQuery(sqlSelect); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } + //select on replica + ResultSet rs = statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + + //show query + rs = statement.executeQuery(sqlShow); + assertEquals(-1, statement.getUpdateCount()); + + //select on master when tx is null and autocommit is false + when(mockConn.getAutoCommit()).thenReturn(false); + when(mockConn.isInTransaction()).thenReturn(false); + rs = statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + + //when returned cursor is null + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(null); + try { + statement.executeQuery(sqlSelect); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); } - - @Test - public void testExecuteFetchSizeAsStreaming() throws SQLException { - testExecute(5, true, false, true); - testExecute(5, false, false, true); - testExecute(0, true, true, false); - testExecute(0, false, false, true); + } + + @Test + public void testExecuteFetchSizeAsStreaming() throws SQLException { + testExecute(5, true, false, true); + testExecute(5, false, false, true); + testExecute(0, true, true, false); + testExecute(0, false, false, true); + } + + private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRunExecute, + boolean shouldRunStreamExecute) throws SQLException { + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + + VitessConnection mockConn = mock(VitessConnection.class); + when(mockConn.isSimpleExecute()).thenReturn(simpleExecute); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockVtGateConn + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockCursor); + + VitessStatement statement = new VitessStatement(mockConn); + statement.setFetchSize(fetchSize); + statement.executeQuery(sqlSelect); + + if (shouldRunExecute) { + verify(mockVtGateConn, Mockito.times(2)) + .execute(any(Context.class), anyString(), anyMap(), any(VTSession.class)); } - private void testExecute(int fetchSize, boolean simpleExecute, boolean shouldRunExecute, boolean shouldRunStreamExecute) throws SQLException { - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - - VitessConnection mockConn = mock(VitessConnection.class); - when(mockConn.isSimpleExecute()).thenReturn(simpleExecute); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockVtGateConn - .streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockCursor); - - VitessStatement statement = new VitessStatement(mockConn); - statement.setFetchSize(fetchSize); - statement.executeQuery(sqlSelect); - - if (shouldRunExecute) { - verify(mockVtGateConn, Mockito.times(2)).execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class)); - } - - if (shouldRunStreamExecute) { - verify(mockVtGateConn).streamExecute(any(Context.class), anyString(), anyMap(), - any(VTSession.class)); - } + if (shouldRunStreamExecute) { + verify(mockVtGateConn) + .streamExecute(any(Context.class), anyString(), anyMap(), any(VTSession.class)); } - - @Test - public void testExecuteUpdate() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - List fieldList = mock(ArrayList.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - //executing dml on master - int updateCount = statement.executeUpdate(sqlUpdate); - assertEquals(0, updateCount); - - //tx is null & autoCommit is true - when(mockConn.getAutoCommit()).thenReturn(true); - updateCount = statement.executeUpdate(sqlUpdate); - assertEquals(0, updateCount); - - //cursor fields is not null - when(mockCursor.getFields()).thenReturn(fieldList); - when(fieldList.isEmpty()).thenReturn(false); - try { - statement.executeUpdate(sqlSelect); - fail("Should have thrown exception for field not null"); - } catch (SQLException ex) { - assertEquals("ResultSet generation is not allowed through this method", - ex.getMessage()); - } - - //cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - statement.executeUpdate(sqlUpdate); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } - - //read only - when(mockConn.isReadOnly()).thenReturn(true); - try { - statement.execute("UPDATE SET foo = 1 ON mytable WHERE id = 1"); - fail("Should have thrown exception for read only"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); - } - - //read only - when(mockConn.isReadOnly()).thenReturn(true); - try { - statement.executeBatch(); - fail("Should have thrown exception for read only"); - } catch (SQLException ex) { - assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); - } + } + + @Test + public void testExecuteUpdate() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + List fieldList = mock(ArrayList.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + //executing dml on master + int updateCount = statement.executeUpdate(sqlUpdate); + assertEquals(0, updateCount); + + //tx is null & autoCommit is true + when(mockConn.getAutoCommit()).thenReturn(true); + updateCount = statement.executeUpdate(sqlUpdate); + assertEquals(0, updateCount); + + //cursor fields is not null + when(mockCursor.getFields()).thenReturn(fieldList); + when(fieldList.isEmpty()).thenReturn(false); + try { + statement.executeUpdate(sqlSelect); + fail("Should have thrown exception for field not null"); + } catch (SQLException ex) { + assertEquals("ResultSet generation is not allowed through this method", ex.getMessage()); } - @Test - public void testExecute() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - List mockFieldList = PowerMockito.spy(new ArrayList<>()); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockConn.getAutoCommit()).thenReturn(true); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.SIMPLE); - when(mockConn.isSimpleExecute()).thenReturn(true); - - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(mockFieldList); - - VitessStatement statement = new VitessStatement(mockConn); - int fieldSize = 5; - when(mockCursor.getFields()).thenReturn(mockFieldList); - doReturn(fieldSize).when(mockFieldList).size(); - doReturn(false).when(mockFieldList).isEmpty(); - - boolean hasResultSet = statement.execute(sqlSelect); - assertTrue(hasResultSet); - assertNotNull(statement.getResultSet()); - - hasResultSet = statement.execute(sqlShow); - assertTrue(hasResultSet); - assertNotNull(statement.getResultSet()); - - int mockUpdateCount = 10; - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - when(mockCursor.getRowsAffected()).thenReturn((long) mockUpdateCount); - hasResultSet = statement.execute(sqlUpdate); - assertFalse(hasResultSet); - assertNull(statement.getResultSet()); - assertEquals(mockUpdateCount, statement.getUpdateCount()); - - //cursor is null - when(mockSqlFutureCursor.checkedGet()).thenReturn(null); - try { - statement.execute(sqlUpdate); - fail("Should have thrown exception for cursor null"); - } catch (SQLException ex) { - assertEquals("Failed to execute this method", ex.getMessage()); - } + //cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + statement.executeUpdate(sqlUpdate); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); } - @Test - public void testGetUpdateCount() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFuture = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFuture); - when(mockSqlFuture.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - when(mockCursor.getRowsAffected()).thenReturn(10L); - int updateCount = statement.executeUpdate(sqlUpdate); - assertEquals(10L, updateCount); - assertEquals(10L, statement.getUpdateCount()); - - // Truncated Update Count - when(mockCursor.getRowsAffected()) - .thenReturn((long) Integer.MAX_VALUE + 10); - updateCount = statement.executeUpdate(sqlUpdate); - assertEquals(Integer.MAX_VALUE, updateCount); - assertEquals(Integer.MAX_VALUE, statement.getUpdateCount()); - - when(mockConn.isSimpleExecute()).thenReturn(true); - statement.executeQuery(sqlSelect); - assertEquals(-1, statement.getUpdateCount()); + //read only + when(mockConn.isReadOnly()).thenReturn(true); + try { + statement.execute("UPDATE SET foo = 1 ON mytable WHERE id = 1"); + fail("Should have thrown exception for read only"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); } - @Test - public void testClose() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockConn.getExecuteType()) - .thenReturn(Constants.QueryExecuteType.SIMPLE); - when(mockConn.isSimpleExecute()).thenReturn(true); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - - VitessStatement statement = new VitessStatement(mockConn); - ResultSet rs = statement.executeQuery(sqlSelect); - statement.close(); - try { - statement.executeQuery(sqlSelect); - fail("Should have thrown exception for statement closed"); - } catch (SQLException ex) { - assertEquals("Statement is closed", ex.getMessage()); - } + //read only + when(mockConn.isReadOnly()).thenReturn(true); + try { + statement.executeBatch(); + fail("Should have thrown exception for read only"); + } catch (SQLException ex) { + assertEquals(Constants.SQLExceptionMessages.READ_ONLY, ex.getMessage()); } - - @Test - public void testGetMaxFieldSize() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(65535, statement.getMaxFieldSize()); + } + + @Test + public void testExecute() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + List mockFieldList = PowerMockito.spy(new ArrayList<>()); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockConn.getAutoCommit()).thenReturn(true); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.SIMPLE); + when(mockConn.isSimpleExecute()).thenReturn(true); + + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(mockFieldList); + + VitessStatement statement = new VitessStatement(mockConn); + int fieldSize = 5; + when(mockCursor.getFields()).thenReturn(mockFieldList); + doReturn(fieldSize).when(mockFieldList).size(); + doReturn(false).when(mockFieldList).isEmpty(); + + boolean hasResultSet = statement.execute(sqlSelect); + assertTrue(hasResultSet); + assertNotNull(statement.getResultSet()); + + hasResultSet = statement.execute(sqlShow); + assertTrue(hasResultSet); + assertNotNull(statement.getResultSet()); + + int mockUpdateCount = 10; + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + when(mockCursor.getRowsAffected()).thenReturn((long) mockUpdateCount); + hasResultSet = statement.execute(sqlUpdate); + assertFalse(hasResultSet); + assertNull(statement.getResultSet()); + assertEquals(mockUpdateCount, statement.getUpdateCount()); + + //cursor is null + when(mockSqlFutureCursor.checkedGet()).thenReturn(null); + try { + statement.execute(sqlUpdate); + fail("Should have thrown exception for cursor null"); + } catch (SQLException ex) { + assertEquals("Failed to execute this method", ex.getMessage()); } - - @Test - public void testGetMaxRows() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - - statement.setMaxRows(10); - assertEquals(10, statement.getMaxRows()); - - try { - statement.setMaxRows(-1); - fail("Should have thrown exception for wrong value"); - } catch (SQLException ex) { - assertEquals("Illegal value for max row", ex.getMessage()); - } - + } + + @Test + public void testGetUpdateCount() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFuture = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFuture); + when(mockSqlFuture.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + when(mockCursor.getRowsAffected()).thenReturn(10L); + int updateCount = statement.executeUpdate(sqlUpdate); + assertEquals(10L, updateCount); + assertEquals(10L, statement.getUpdateCount()); + + // Truncated Update Count + when(mockCursor.getRowsAffected()).thenReturn((long) Integer.MAX_VALUE + 10); + updateCount = statement.executeUpdate(sqlUpdate); + assertEquals(Integer.MAX_VALUE, updateCount); + assertEquals(Integer.MAX_VALUE, statement.getUpdateCount()); + + when(mockConn.isSimpleExecute()).thenReturn(true); + statement.executeQuery(sqlSelect); + assertEquals(-1, statement.getUpdateCount()); + } + + @Test + public void testClose() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockConn.getExecuteType()).thenReturn(Constants.QueryExecuteType.SIMPLE); + when(mockConn.isSimpleExecute()).thenReturn(true); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + + VitessStatement statement = new VitessStatement(mockConn); + ResultSet rs = statement.executeQuery(sqlSelect); + statement.close(); + try { + statement.executeQuery(sqlSelect); + fail("Should have thrown exception for statement closed"); + } catch (SQLException ex) { + assertEquals("Statement is closed", ex.getMessage()); } + } - @Test - public void testGetQueryTimeout() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - Mockito.when(mockConn.getTimeout()).thenReturn((long) Constants.DEFAULT_TIMEOUT); + @Test + public void testGetMaxFieldSize() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(30, statement.getQueryTimeout()); - } + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(65535, statement.getMaxFieldSize()); + } - @Test - public void testGetQueryTimeoutZeroDefault() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - Mockito.when(mockConn.getTimeout()).thenReturn(0L); + @Test + public void testGetMaxRows() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(0, statement.getQueryTimeout()); - } - - @Test - public void testSetQueryTimeout() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - Mockito.when(mockConn.getTimeout()).thenReturn((long) Constants.DEFAULT_TIMEOUT); - - VitessStatement statement = new VitessStatement(mockConn); - - int queryTimeout = 10; - statement.setQueryTimeout(queryTimeout); - assertEquals(queryTimeout, statement.getQueryTimeout()); - try { - queryTimeout = -1; - statement.setQueryTimeout(queryTimeout); - fail("Should have thrown exception for wrong value"); - } catch (SQLException ex) { - assertEquals("Illegal value for query timeout", ex.getMessage()); - } - - statement.setQueryTimeout(0); - assertEquals(30, statement.getQueryTimeout()); - } + VitessStatement statement = new VitessStatement(mockConn); - @Test - public void testGetWarnings() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); + statement.setMaxRows(10); + assertEquals(10, statement.getMaxRows()); - VitessStatement statement = new VitessStatement(mockConn); - assertNull(statement.getWarnings()); + try { + statement.setMaxRows(-1); + fail("Should have thrown exception for wrong value"); + } catch (SQLException ex) { + assertEquals("Illegal value for max row", ex.getMessage()); } - @Test - public void testGetFetchDirection() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); + } + + @Test + public void testGetQueryTimeout() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + Mockito.when(mockConn.getTimeout()).thenReturn((long) Constants.DEFAULT_TIMEOUT); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(30, statement.getQueryTimeout()); + } + + @Test + public void testGetQueryTimeoutZeroDefault() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + Mockito.when(mockConn.getTimeout()).thenReturn(0L); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(0, statement.getQueryTimeout()); + } + + @Test + public void testSetQueryTimeout() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + Mockito.when(mockConn.getTimeout()).thenReturn((long) Constants.DEFAULT_TIMEOUT); + + VitessStatement statement = new VitessStatement(mockConn); + + int queryTimeout = 10; + statement.setQueryTimeout(queryTimeout); + assertEquals(queryTimeout, statement.getQueryTimeout()); + try { + queryTimeout = -1; + statement.setQueryTimeout(queryTimeout); + fail("Should have thrown exception for wrong value"); + } catch (SQLException ex) { + assertEquals("Illegal value for query timeout", ex.getMessage()); } - @Test - public void testGetFetchSize() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(0, statement.getFetchSize()); + statement.setQueryTimeout(0); + assertEquals(30, statement.getQueryTimeout()); + } + + @Test + public void testGetWarnings() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertNull(statement.getWarnings()); + } + + @Test + public void testGetFetchDirection() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(ResultSet.FETCH_FORWARD, statement.getFetchDirection()); + } + + @Test + public void testGetFetchSize() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(0, statement.getFetchSize()); + } + + @Test + public void testGetResultSetConcurrency() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(ResultSet.CONCUR_READ_ONLY, statement.getResultSetConcurrency()); + } + + @Test + public void testGetResultSetType() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertEquals(ResultSet.TYPE_FORWARD_ONLY, statement.getResultSetType()); + } + + @Test + public void testIsClosed() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + + VitessStatement statement = new VitessStatement(mockConn); + assertFalse(statement.isClosed()); + statement.close(); + assertTrue(statement.isClosed()); + } + + @Test + public void testAutoGeneratedKeys() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockVtGateConn.execute(any(Context.class), anyString(), anyMap(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + VitessStatement statement = new VitessStatement(mockConn); + long expectedFirstGeneratedId = 121; + long[] expectedGeneratedIds = {121, 122, 123, 124, 125}; + int expectedAffectedRows = 5; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedAffectedRows)); + + //Executing Insert Statement + int updateCount = statement.executeUpdate(sqlInsert, Statement.RETURN_GENERATED_KEYS); + assertEquals(expectedAffectedRows, updateCount); + + ResultSet rs = statement.getGeneratedKeys(); + int i = 0; + while (rs.next()) { + long generatedId = rs.getLong(1); + assertEquals(expectedGeneratedIds[i++], generatedId); } - @Test - public void testGetResultSetConcurrency() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(ResultSet.CONCUR_READ_ONLY, statement.getResultSetConcurrency()); + //Fetching Generated Keys without notifying the driver + statement.executeUpdate(sqlInsert); + try { + statement.getGeneratedKeys(); + fail("Should have thrown exception for not setting autoGeneratedKey flag"); + } catch (SQLException ex) { + assertEquals("Generated keys not requested. You need to specify Statement" + + ".RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection" + + ".prepareStatement()", + ex.getMessage()); } - @Test - public void testGetResultSetType() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertEquals(ResultSet.TYPE_FORWARD_ONLY, statement.getResultSetType()); + //Fetching Generated Keys on update query + expectedFirstGeneratedId = 0; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + updateCount = statement.executeUpdate(sqlUpdate, Statement.RETURN_GENERATED_KEYS); + assertEquals(expectedAffectedRows, updateCount); + + rs = statement.getGeneratedKeys(); + assertFalse(rs.next()); + } + + @Test + public void testAddBatch() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + statement.addBatch(sqlInsert); + Field privateStringField = VitessStatement.class.getDeclaredField("batchedArgs"); + privateStringField.setAccessible(true); + assertEquals(sqlInsert, ((List) privateStringField.get(statement)).get(0)); + } + + @Test + public void testClearBatch() throws Exception { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + statement.addBatch(sqlInsert); + statement.clearBatch(); + Field privateStringField = VitessStatement.class.getDeclaredField("batchedArgs"); + privateStringField.setAccessible(true); + assertTrue(((List) privateStringField.get(statement)).isEmpty()); + } + + @Test + public void testExecuteBatch() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + int[] updateCounts = statement.executeBatch(); + assertEquals(0, updateCounts.length); + + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockConn.getAutoCommit()).thenReturn(true); + + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + when( + mockVtGateConn.executeBatch(any(Context.class), anyList(), anyList(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + + List mockCursorWithErrorList = new ArrayList<>(); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); + + CursorWithError mockCursorWithError1 = mock(CursorWithError.class); + when(mockCursorWithError1.getError()).thenReturn(null); + when(mockCursorWithError1.getCursor()).thenReturn(mock(Cursor.class)); + mockCursorWithErrorList.add(mockCursorWithError1); + + statement.addBatch(sqlUpdate); + updateCounts = statement.executeBatch(); + assertEquals(1, updateCounts.length); + + CursorWithError mockCursorWithError2 = mock(CursorWithError.class); + Vtrpc.RPCError rpcError = Vtrpc.RPCError.newBuilder() + .setMessage("statement execute batch error").build(); + when(mockCursorWithError2.getError()).thenReturn(rpcError); + mockCursorWithErrorList.add(mockCursorWithError2); + statement.addBatch(sqlUpdate); + statement.addBatch(sqlUpdate); + try { + statement.executeBatch(); + fail("Should have thrown Exception"); + } catch (BatchUpdateException ex) { + assertEquals(rpcError.toString(), ex.getMessage()); + assertEquals(2, ex.getUpdateCounts().length); + assertEquals(Statement.EXECUTE_FAILED, ex.getUpdateCounts()[1]); } - @Test - public void testIsClosed() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - - VitessStatement statement = new VitessStatement(mockConn); - assertFalse(statement.isClosed()); - statement.close(); - assertTrue(statement.isClosed()); + } + + @Test + public void testBatchGeneratedKeys() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockConn.getAutoCommit()).thenReturn(true); + + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + when( + mockVtGateConn.executeBatch(any(Context.class), anyList(), anyList(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + List mockCursorWithErrorList = new ArrayList<>(); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); + + CursorWithError mockCursorWithError = mock(CursorWithError.class); + when(mockCursorWithError.getError()).thenReturn(null); + when(mockCursorWithError.getCursor()).thenReturn(mockCursor); + mockCursorWithErrorList.add(mockCursorWithError); + + long expectedFirstGeneratedId = 121; + long[] expectedGeneratedIds = {121, 122, 123, 124, 125}; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedGeneratedIds.length)); + + statement.addBatch(sqlInsert); + statement.executeBatch(); + + ResultSet rs = statement.getGeneratedKeys(); + int i = 0; + while (rs.next()) { + long generatedId = rs.getLong(1); + assertEquals(expectedGeneratedIds[i++], generatedId); } - - @Test - public void testAutoGeneratedKeys() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockVtGateConn - .execute(any(Context.class), anyString(), anyMap(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - VitessStatement statement = new VitessStatement(mockConn); - long expectedFirstGeneratedId = 121; - long[] expectedGeneratedIds = {121, 122, 123, 124, 125}; - int expectedAffectedRows = 5; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - when(mockCursor.getRowsAffected()) - .thenReturn(Long.valueOf(expectedAffectedRows)); - - //Executing Insert Statement - int updateCount = statement.executeUpdate(sqlInsert, Statement.RETURN_GENERATED_KEYS); - assertEquals(expectedAffectedRows, updateCount); - - ResultSet rs = statement.getGeneratedKeys(); - int i = 0; - while (rs.next()) { - long generatedId = rs.getLong(1); - assertEquals(expectedGeneratedIds[i++], generatedId); - } - - //Fetching Generated Keys without notifying the driver - statement.executeUpdate(sqlInsert); - try { - statement.getGeneratedKeys(); - fail("Should have thrown exception for not setting autoGeneratedKey flag"); - } catch (SQLException ex) { - assertEquals("Generated keys not requested. You need to specify Statement" - + ".RETURN_GENERATED_KEYS to Statement.executeUpdate() or Connection.prepareStatement()", - ex.getMessage()); - } - - //Fetching Generated Keys on update query - expectedFirstGeneratedId = 0; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - updateCount = statement.executeUpdate(sqlUpdate, Statement.RETURN_GENERATED_KEYS); - assertEquals(expectedAffectedRows, updateCount); - - rs = statement.getGeneratedKeys(); - assertFalse(rs.next()); + } + + @Test + public void testBatchUpsertGeneratedKeys() throws SQLException { + VitessConnection mockConn = mock(VitessConnection.class); + VitessStatement statement = new VitessStatement(mockConn); + Cursor mockCursor = mock(Cursor.class); + SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); + + VTGateConnection mockVtGateConn = mock(VTGateConnection.class); + when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); + when(mockConn.getAutoCommit()).thenReturn(true); + + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); + when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); + + when( + mockVtGateConn.executeBatch(any(Context.class), anyList(), anyList(), any(VTSession.class))) + .thenReturn(mockSqlFutureCursor); + List mockCursorWithErrorList = new ArrayList<>(); + when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); + + CursorWithError mockCursorWithError = mock(CursorWithError.class); + when(mockCursorWithError.getError()).thenReturn(null); + when(mockCursorWithError.getCursor()).thenReturn(mockCursor); + mockCursorWithErrorList.add(mockCursorWithError); + + long expectedFirstGeneratedId = 121; + long[] expectedGeneratedIds = {121, 122}; + when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); + when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedGeneratedIds.length)); + + statement.addBatch(sqlUpsert); + statement.executeBatch(); + + ResultSet rs = statement.getGeneratedKeys(); + int i = 0; + while (rs.next()) { + long generatedId = rs.getLong(1); + assertEquals(expectedGeneratedIds[i], generatedId); + assertEquals(i, 0); // we should only have one + i++; } - @Test - public void testAddBatch() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - statement.addBatch(sqlInsert); - Field privateStringField = VitessStatement.class.getDeclaredField("batchedArgs"); - privateStringField.setAccessible(true); - assertEquals(sqlInsert, ((List) privateStringField.get(statement)).get(0)); - } - - @Test - public void testClearBatch() throws Exception { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - statement.addBatch(sqlInsert); - statement.clearBatch(); - Field privateStringField = VitessStatement.class.getDeclaredField("batchedArgs"); - privateStringField.setAccessible(true); - assertTrue(((List) privateStringField.get(statement)).isEmpty()); - } - - @Test - public void testExecuteBatch() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - int[] updateCounts = statement.executeBatch(); - assertEquals(0, updateCounts.length); - - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockConn.getAutoCommit()).thenReturn(true); - - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - when(mockVtGateConn - .executeBatch(any(Context.class), anyList(), anyList(), - any(VTSession.class))).thenReturn(mockSqlFutureCursor); - - List mockCursorWithErrorList = new ArrayList<>(); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); - - CursorWithError mockCursorWithError1 = mock(CursorWithError.class); - when(mockCursorWithError1.getError()).thenReturn(null); - when(mockCursorWithError1.getCursor()) - .thenReturn(mock(Cursor.class)); - mockCursorWithErrorList.add(mockCursorWithError1); - - statement.addBatch(sqlUpdate); - updateCounts = statement.executeBatch(); - assertEquals(1, updateCounts.length); - - CursorWithError mockCursorWithError2 = mock(CursorWithError.class); - Vtrpc.RPCError rpcError = Vtrpc.RPCError.newBuilder().setMessage("statement execute batch error").build(); - when(mockCursorWithError2.getError()) - .thenReturn(rpcError); - mockCursorWithErrorList.add(mockCursorWithError2); - statement.addBatch(sqlUpdate); - statement.addBatch(sqlUpdate); - try { - statement.executeBatch(); - fail("Should have thrown Exception"); - } catch (BatchUpdateException ex) { - assertEquals(rpcError.toString(), ex.getMessage()); - assertEquals(2, ex.getUpdateCounts().length); - assertEquals(Statement.EXECUTE_FAILED, ex.getUpdateCounts()[1]); - } + VitessStatement noUpdate = new VitessStatement(mockConn); + when(mockCursor.getInsertId()).thenReturn(0L); + when(mockCursor.getRowsAffected()).thenReturn(1L); - } - - @Test - public void testBatchGeneratedKeys() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockConn.getAutoCommit()).thenReturn(true); - - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - when(mockVtGateConn - .executeBatch(any(Context.class), - anyList(), - anyList(), - any(VTSession.class))) - .thenReturn(mockSqlFutureCursor); - List mockCursorWithErrorList = new ArrayList<>(); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); - - CursorWithError mockCursorWithError = mock(CursorWithError.class); - when(mockCursorWithError.getError()).thenReturn(null); - when(mockCursorWithError.getCursor()).thenReturn(mockCursor); - mockCursorWithErrorList.add(mockCursorWithError); - - long expectedFirstGeneratedId = 121; - long[] expectedGeneratedIds = {121, 122, 123, 124, 125}; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedGeneratedIds.length)); - - statement.addBatch(sqlInsert); - statement.executeBatch(); - - ResultSet rs = statement.getGeneratedKeys(); - int i = 0; - while (rs.next()) { - long generatedId = rs.getLong(1); - assertEquals(expectedGeneratedIds[i++], generatedId); - } - } + noUpdate.addBatch(sqlUpsert); + noUpdate.executeBatch(); - @Test - public void testBatchUpsertGeneratedKeys() throws SQLException { - VitessConnection mockConn = mock(VitessConnection.class); - VitessStatement statement = new VitessStatement(mockConn); - Cursor mockCursor = mock(Cursor.class); - SQLFuture mockSqlFutureCursor = mock(SQLFuture.class); - - VTGateConnection mockVtGateConn = mock(VTGateConnection.class); - when(mockConn.getVtGateConn()).thenReturn(mockVtGateConn); - when(mockConn.getAutoCommit()).thenReturn(true); - - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursor); - when(mockCursor.getFields()).thenReturn(Query.QueryResult.getDefaultInstance().getFieldsList()); - - when(mockVtGateConn - .executeBatch(any(Context.class), - anyList(), - anyList(), - any(VTSession.class))) - .thenReturn(mockSqlFutureCursor); - List mockCursorWithErrorList = new ArrayList<>(); - when(mockSqlFutureCursor.checkedGet()).thenReturn(mockCursorWithErrorList); - - CursorWithError mockCursorWithError = mock(CursorWithError.class); - when(mockCursorWithError.getError()).thenReturn(null); - when(mockCursorWithError.getCursor()).thenReturn(mockCursor); - mockCursorWithErrorList.add(mockCursorWithError); - - long expectedFirstGeneratedId = 121; - long[] expectedGeneratedIds = {121, 122}; - when(mockCursor.getInsertId()).thenReturn(expectedFirstGeneratedId); - when(mockCursor.getRowsAffected()).thenReturn(Long.valueOf(expectedGeneratedIds.length)); - - statement.addBatch(sqlUpsert); - statement.executeBatch(); - - ResultSet rs = statement.getGeneratedKeys(); - int i = 0; - while (rs.next()) { - long generatedId = rs.getLong(1); - assertEquals(expectedGeneratedIds[i], generatedId); - assertEquals(i, 0); // we should only have one - i++; - } - - VitessStatement noUpdate = new VitessStatement(mockConn); - when(mockCursor.getInsertId()).thenReturn(0L); - when(mockCursor.getRowsAffected()).thenReturn(1L); - - noUpdate.addBatch(sqlUpsert); - noUpdate.executeBatch(); - - ResultSet empty = noUpdate.getGeneratedKeys(); - assertFalse(empty.next()); - } + ResultSet empty = noUpdate.getGeneratedKeys(); + assertFalse(empty.next()); + } } diff --git a/java/jdbc/src/test/java/io/vitess/jdbc/VitessVTGateManagerTest.java b/java/jdbc/src/test/java/io/vitess/jdbc/VitessVTGateManagerTest.java index 86eb64f43d7..5509e50aa9a 100644 --- a/java/jdbc/src/test/java/io/vitess/jdbc/VitessVTGateManagerTest.java +++ b/java/jdbc/src/test/java/io/vitess/jdbc/VitessVTGateManagerTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,81 +16,90 @@ package io.vitess.jdbc; -import org.joda.time.Duration; -import org.junit.Assert; -import org.junit.Test; - import io.vitess.client.Context; import io.vitess.client.RpcClient; import io.vitess.client.VTGateConnection; import io.vitess.client.grpc.GrpcClientFactory; import io.vitess.proto.Vtrpc; +import org.joda.time.Duration; + import java.io.IOException; import java.lang.reflect.Field; import java.sql.SQLException; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; +import org.junit.Assert; +import org.junit.Test; + /** * Created by naveen.nahata on 29/02/16. */ public class VitessVTGateManagerTest { - public VTGateConnection getVtGateConn() { - Vtrpc.CallerID callerId = Vtrpc.CallerID.newBuilder().setPrincipal("username").build(); - Context ctx = - Context.getDefault().withDeadlineAfter(Duration.millis(500)).withCallerId(callerId); - RpcClient client = new GrpcClientFactory().create(ctx, "host:80"); - return new VTGateConnection(client); - } + public VTGateConnection getVtGateConn() { + Vtrpc.CallerID callerId = Vtrpc.CallerID.newBuilder().setPrincipal("username").build(); + Context ctx = Context.getDefault().withDeadlineAfter(Duration.millis(500)) + .withCallerId(callerId); + RpcClient client = new GrpcClientFactory().create(ctx, "host:80"); + return new VTGateConnection(client); + } - @Test public void testVtGateConnectionsConstructorMultipleVtGateConnections() - throws SQLException, NoSuchFieldException, IllegalAccessException, IOException { - VitessVTGateManager.close(); - Properties info = new Properties(); - info.setProperty("username", "user"); - VitessConnection connection = new VitessConnection( - "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,10.33.17" - + ".233:15991/shipment/shipment?tabletType=master", info); - VitessVTGateManager.VTGateConnections vtGateConnections = - new VitessVTGateManager.VTGateConnections(connection); + @Test + public void testVtGateConnectionsConstructorMultipleVtGateConnections() + throws SQLException, NoSuchFieldException, IllegalAccessException, IOException { + VitessVTGateManager.close(); + Properties info = new Properties(); + info.setProperty("username", "user"); + VitessConnection connection = new VitessConnection( + "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,10.33.17" + + ".233:15991/shipment/shipment?tabletType=master", info); + VitessVTGateManager.VTGateConnections vtGateConnections = + new VitessVTGateManager.VTGateConnections( + connection); - info.setProperty("username", "user"); - VitessConnection connection1 = new VitessConnection( - "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,11.33.17" - + ".233:15991/shipment/shipment?tabletType=master", info); - VitessVTGateManager.VTGateConnections vtGateConnections1 = - new VitessVTGateManager.VTGateConnections(connection1); + info.setProperty("username", "user"); + VitessConnection connection1 = new VitessConnection( + "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,11.33.17" + + ".233:15991/shipment/shipment?tabletType=master", info); + VitessVTGateManager.VTGateConnections vtGateConnections1 = + new VitessVTGateManager.VTGateConnections( + connection1); - Field privateMapField = VitessVTGateManager.class. - getDeclaredField("vtGateConnHashMap"); - privateMapField.setAccessible(true); - ConcurrentHashMap map = - (ConcurrentHashMap) privateMapField.get(VitessVTGateManager.class); - Assert.assertEquals(4, map.size()); - VitessVTGateManager.close(); - } + Field privateMapField = VitessVTGateManager.class. + getDeclaredField("vtGateConnHashMap"); + privateMapField.setAccessible(true); + ConcurrentHashMap map = (ConcurrentHashMap) privateMapField + .get(VitessVTGateManager.class); + Assert.assertEquals(4, map.size()); + VitessVTGateManager.close(); + } - @Test public void testVtGateConnectionsConstructor() - throws SQLException, NoSuchFieldException, IllegalAccessException, IOException { - VitessVTGateManager.close(); - Properties info = new Properties(); - info.setProperty("username", "user"); - VitessConnection connection = new VitessConnection( - "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,10.33.17" - + ".233:15991/shipment/shipment?tabletType=master", info); - VitessVTGateManager.VTGateConnections vtGateConnections = - new VitessVTGateManager.VTGateConnections(connection); - Assert.assertEquals(vtGateConnections.getVtGateConnInstance() instanceof VTGateConnection, true); - VTGateConnection vtGateConn = vtGateConnections.getVtGateConnInstance(); - Field privateMapField = VitessVTGateManager.class. - getDeclaredField("vtGateConnHashMap"); - privateMapField.setAccessible(true); - ConcurrentHashMap map = - (ConcurrentHashMap) privateMapField.get(VitessVTGateManager.class); - Assert.assertEquals(3, map.size()); - VitessVTGateManager.close(); - } + @Test + public void testVtGateConnectionsConstructor() + throws SQLException, NoSuchFieldException, IllegalAccessException, IOException { + VitessVTGateManager.close(); + Properties info = new Properties(); + info.setProperty("username", "user"); + VitessConnection connection = new VitessConnection( + "jdbc:vitess://10.33.17.231:15991:xyz,10.33.17.232:15991:xyz,10.33.17" + + ".233:15991/shipment/shipment?tabletType=master", info); + VitessVTGateManager.VTGateConnections vtGateConnections = + new VitessVTGateManager.VTGateConnections( + connection); + Assert + .assertEquals(vtGateConnections.getVtGateConnInstance() instanceof VTGateConnection, true); + VTGateConnection vtGateConn = vtGateConnections.getVtGateConnInstance(); + Field privateMapField = VitessVTGateManager.class. + getDeclaredField("vtGateConnHashMap"); + privateMapField.setAccessible(true); + ConcurrentHashMap map = (ConcurrentHashMap) privateMapField + .get(VitessVTGateManager.class); + Assert.assertEquals(3, map.size()); + VitessVTGateManager.close(); + } } diff --git a/java/jdbc/src/test/java/io/vitess/util/StringUtilsTest.java b/java/jdbc/src/test/java/io/vitess/util/StringUtilsTest.java index a76a9aacb3a..9b87e0fce20 100644 --- a/java/jdbc/src/test/java/io/vitess/util/StringUtilsTest.java +++ b/java/jdbc/src/test/java/io/vitess/util/StringUtilsTest.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -17,6 +17,7 @@ package io.vitess.util; import com.google.common.collect.Lists; + import org.junit.Assert; import org.junit.Test; @@ -40,10 +41,14 @@ public void quoteIdentifierTest() { Assert.assertEquals("'this is a test'", StringUtils.quoteIdentifier("this is a test", "'")); Assert.assertEquals("'this is a test'", StringUtils.quoteIdentifier("'this is a test'", "'")); Assert.assertEquals("'this is'' a test'", StringUtils.quoteIdentifier("this is' a test", "'")); - Assert.assertEquals("'this is'''' a test'", StringUtils.quoteIdentifier("this is'' a test", "'")); - Assert.assertEquals("'this is'' a test'", StringUtils.quoteIdentifier("'this is'' a test'", "'")); - Assert.assertEquals("'this is a ''test'''", StringUtils.quoteIdentifier("this is a 'test'", "'")); - Assert.assertEquals("'this is a ''test'''", StringUtils.quoteIdentifier("'this is a ''test'''", "'")); + Assert + .assertEquals("'this is'''' a test'", StringUtils.quoteIdentifier("this is'' a test", "'")); + Assert + .assertEquals("'this is'' a test'", StringUtils.quoteIdentifier("'this is'' a test'", "'")); + Assert + .assertEquals("'this is a ''test'''", StringUtils.quoteIdentifier("this is a 'test'", "'")); + Assert.assertEquals("'this is a ''test'''", + StringUtils.quoteIdentifier("'this is a ''test'''", "'")); Assert.assertEquals(null, StringUtils.quoteIdentifier(null, "'")); Assert.assertEquals("this is a test", StringUtils.quoteIdentifier("this is a test", "")); Assert.assertEquals("this is a test", StringUtils.quoteIdentifier("this is a test", " ")); @@ -54,16 +59,24 @@ public void unQuoteIdentifierTest() { Assert.assertEquals(null, StringUtils.unQuoteIdentifier(null, "'")); Assert.assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'this is a test'", "")); Assert.assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'this is a test'", " ")); - Assert.assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'this is a test'", "\"")); + Assert + .assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'this is a test'", "\"")); Assert.assertEquals("this is a test'", StringUtils.unQuoteIdentifier("this is a test'", "'")); Assert.assertEquals("this is a test", StringUtils.unQuoteIdentifier("'this is a test'", "'")); - Assert.assertEquals("this is 'a' test", StringUtils.unQuoteIdentifier("'this is ''a'' test'", "'")); - Assert.assertEquals("this is 'a'' test", StringUtils.unQuoteIdentifier("'this is ''a'''' test'", "'")); - Assert.assertEquals("'this is a test'", StringUtils.unQuoteIdentifier("'''this is a test'''", "'")); - Assert.assertEquals("this is a test", StringUtils.unQuoteIdentifier("``this is a test``", "``")); - Assert.assertEquals("``this is ``a test``", StringUtils.unQuoteIdentifier("``this is ``a test``", "``")); - Assert.assertEquals("this is ``a test", StringUtils.unQuoteIdentifier("``this is ````a test``", "``")); - Assert.assertEquals("'this is ''a' test'", StringUtils.unQuoteIdentifier("'this is ''a' test'", "'")); + Assert.assertEquals("this is 'a' test", + StringUtils.unQuoteIdentifier("'this is ''a'' test'", "'")); + Assert.assertEquals("this is 'a'' test", + StringUtils.unQuoteIdentifier("'this is ''a'''' test'", "'")); + Assert.assertEquals("'this is a test'", + StringUtils.unQuoteIdentifier("'''this is a test'''", "'")); + Assert + .assertEquals("this is a test", StringUtils.unQuoteIdentifier("``this is a test``", "``")); + Assert.assertEquals("``this is ``a test``", + StringUtils.unQuoteIdentifier("``this is ``a test``", "``")); + Assert.assertEquals("this is ``a test", + StringUtils.unQuoteIdentifier("``this is ````a test``", "``")); + Assert.assertEquals("'this is ''a' test'", + StringUtils.unQuoteIdentifier("'this is ''a' test'", "'")); } @Test @@ -74,9 +87,11 @@ public void indexOfIgnoreCaseTestDefault() { Assert.assertEquals(-1, StringUtils.indexOfIgnoreCase(8, "this is a test", "this", "`", "`")); Assert.assertEquals(7, StringUtils.indexOfIgnoreCase(0, "this is a test", " a ", "`", "`")); Assert.assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "this is `a` test", "a", "`", "`")); - Assert.assertEquals(10, StringUtils.indexOfIgnoreCase(0, "this is \\`a\\` test", "a", "`", "`")); + Assert + .assertEquals(10, StringUtils.indexOfIgnoreCase(0, "this is \\`a\\` test", "a", "`", "`")); Assert.assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "this `is \\`a` test", "a", "`", "`")); - Assert.assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "th'is' `is` a test", "is", "`'", "`'")); + Assert + .assertEquals(-1, StringUtils.indexOfIgnoreCase(0, "th'is' `is` a test", "is", "`'", "`'")); Assert.assertEquals(10, StringUtils.indexOfIgnoreCase(0, "this is a test", "TEST", "`", "`")); Assert.assertEquals(10, StringUtils.indexOfIgnoreCase(0, "this is ``a` test", "a", "`", "`")); @@ -103,26 +118,39 @@ public void splitTest() { } catch (IllegalArgumentException ignored) { // expected } - Assert.assertEquals(Lists.newArrayList("one", "two", "three"), StringUtils.split("one,two,three", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "`two,three`"), StringUtils.split("one,`two,three`", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "{tw{o,t}hree}"), StringUtils.split("one,{tw{o,t}hree}", ",", "{", "}")); - Assert.assertEquals(Lists.newArrayList("one", "/*two,three*/"), StringUtils.split("one,/*two,three*/", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "-- two,three\n", "four"), StringUtils.split("one,-- two,three\n,four", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "-- two,three\r\n", "four"), StringUtils.split("one,-- two,three\r\n,four", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "#two,three\n", "four"), StringUtils.split("one,#two,three\n,four", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "--;two", "three", "four"), StringUtils.split("one,--;two,three,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "two", "three"), + StringUtils.split("one,two,three", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "`two,three`"), + StringUtils.split("one,`two,three`", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "{tw{o,t}hree}"), + StringUtils.split("one,{tw{o,t}hree}", ",", "{", "}")); + Assert.assertEquals(Lists.newArrayList("one", "/*two,three*/"), + StringUtils.split("one,/*two,three*/", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "-- two,three\n", "four"), + StringUtils.split("one,-- two,three\n,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "-- two,three\r\n", "four"), + StringUtils.split("one,-- two,three\r\n,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "#two,three\n", "four"), + StringUtils.split("one,#two,three\n,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "--;two", "three", "four"), + StringUtils.split("one,--;two,three,four", ",", "`", "`")); // split doesn't use ALLOW_BACKSLASH_ESCAPE, so escaping delimiter doesn't work - Assert.assertEquals(Lists.newArrayList("one", "two\\", "three", "four"), StringUtils.split("one,two\\,three,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "two\\", "three", "four"), + StringUtils.split("one,two\\,three,four", ",", "`", "`")); // the following comment is a special non-comment block, and it should be split - Assert.assertEquals(Lists.newArrayList("one", "/*!50110 one", " two */two", "three", "four"), StringUtils.split("one,/*!50110 one, two */two,three,four", ",", "`", "`")); - Assert.assertEquals(Lists.newArrayList("one", "/*!5011 one", " two */two", "three", "four"), StringUtils.split("one,/*!5011 one, two */two,three,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "/*!50110 one", " two */two", "three", "four"), + StringUtils.split("one,/*!50110 one, two */two,three,four", ",", "`", "`")); + Assert.assertEquals(Lists.newArrayList("one", "/*!5011 one", " two */two", "three", "four"), + StringUtils.split("one,/*!5011 one, two */two,three,four", ",", "`", "`")); } @Test public void firstAlphaCharUcTest() { - Assert.assertEquals('S', StringUtils.firstAlphaCharUc("(select * from foo) union (select * from bar)", 0)); + Assert.assertEquals('S', + StringUtils.firstAlphaCharUc("(select * from foo) union (select * from bar)", 0)); Assert.assertEquals('R', StringUtils.firstAlphaCharUc("replace into table1 values()", 0)); Assert.assertEquals('S', StringUtils.firstAlphaCharUc("SET replication_speed='ludicrous'", 0)); - Assert.assertEquals('S', StringUtils.firstAlphaCharUc("/* leading comment */ select * from table2 ", 22)); + Assert.assertEquals('S', + StringUtils.firstAlphaCharUc("/* leading comment */ select * from table2 ", 22)); } } From 35372cdcb2215700b8e6c6fb0c892e9b27a2e34e Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Thu, 7 Feb 2019 10:19:38 -0500 Subject: [PATCH 029/196] jdbc: complete checkstyle Signed-off-by: Ze'ev Klapow --- java/checkstyle-suppression.xml | 2 + .../io/vitess/jdbc/ConnectionProperties.java | 2 +- .../io/vitess/jdbc/FieldWithMetadata.java | 2 +- .../java/io/vitess/jdbc/VitessConnection.java | 2 +- .../java/io/vitess/jdbc/VitessDriver.java | 4 +- .../java/io/vitess/jdbc/VitessJDBCUrl.java | 36 +-- .../jdbc/VitessMySQLDatabaseMetadata.java | 22 +- .../vitess/jdbc/VitessPreparedStatement.java | 237 +++++++++--------- .../java/io/vitess/jdbc/VitessResultSet.java | 181 ++++++------- .../vitess/jdbc/VitessResultSetMetaData.java | 6 +- .../java/io/vitess/jdbc/VitessStatement.java | 32 ++- .../io/vitess/jdbc/VitessVTGateManager.java | 4 +- 12 files changed, 271 insertions(+), 259 deletions(-) diff --git a/java/checkstyle-suppression.xml b/java/checkstyle-suppression.xml index ac41584523c..f6131902803 100644 --- a/java/checkstyle-suppression.xml +++ b/java/checkstyle-suppression.xml @@ -16,4 +16,6 @@ + + \ No newline at end of file diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java index 5d172808395..62d451ca9a7 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/ConnectionProperties.java @@ -295,7 +295,7 @@ private void checkConfiguredEncodingSupport() throws SQLException { try { String testString = "abc"; StringUtils.getBytes(testString, characterEncodingAsString); - } catch (UnsupportedEncodingException UE) { + } catch (UnsupportedEncodingException uee) { throw new SQLException("Unsupported character encoding: " + characterEncodingAsString); } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java index b86b2dd893e..1f1eca52c6f 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/FieldWithMetadata.java @@ -595,7 +595,7 @@ public String toString() { asString.append(this.encoding); asString.append("]"); return asString.toString(); - } catch (Throwable t) { + } catch (Throwable ignored) { return super.toString(); } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java index 88bf7e1eae3..1dac94c92a6 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessConnection.java @@ -85,7 +85,7 @@ public VitessConnection(String url, Properties connectionProperties) throws SQLE this.vtSession = new VTSession(this.getTarget(), this.getExecuteOptions()); } catch (Exception exc) { throw new SQLException( - Constants.SQLExceptionMessages.CONN_INIT_ERROR + " - " + e.getMessage(), exc); + Constants.SQLExceptionMessages.CONN_INIT_ERROR + " - " + exc.getMessage(), exc); } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java index 0cb46209e1d..ce6c96c9dd3 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessDriver.java @@ -41,9 +41,9 @@ public class VitessDriver implements Driver { static { try { DriverManager.registerDriver(new VitessDriver()); - } catch (SQLException e) { + } catch (SQLException exc) { throw new RuntimeException( - Constants.SQLExceptionMessages.INIT_FAILED + " : " + e.getErrorCode() + " - " + e + Constants.SQLExceptionMessages.INIT_FAILED + " : " + exc.getErrorCode() + " - " + exc .getMessage()); } } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java index 44814416bc5..c91c7a3342d 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessJDBCUrl.java @@ -117,21 +117,21 @@ public String toString() { */ public VitessJDBCUrl(String url, Properties info) throws SQLException { - /* URL pattern e.g. jdbc:vitess://username:password@ip1:port1,ip2:port2/keyspace/catalog? - property1=value1.. - m.group(1) = "vitess" - m.group(2) = "username:password@" - m.group(3) = "username" - m.group(4) = ":password" - m.group(5) = "password" - m.group(6) = "ip1:port1,ip2:port2" - m.group(7) = "/keyspace" - m.group(8) = "keyspace" - m.group(9) = "/catalog" - m.group(10) = "catalog" - m.group(11) = "?property1=value1.." - m.group(12) = "property1=value1.." - */ + /* URL pattern e.g. jdbc:vitess://username:password@ip1:port1,ip2:port2/keyspace/catalog? + property1=value1.. + m.group(1) = "vitess" + m.group(2) = "username:password@" + m.group(3) = "username" + m.group(4) = ":password" + m.group(5) = "password" + m.group(6) = "ip1:port1,ip2:port2" + m.group(7) = "/keyspace" + m.group(8) = "keyspace" + m.group(9) = "/catalog" + m.group(10) = "catalog" + m.group(11) = "?property1=value1.." + m.group(12) = "property1=value1.." + */ final Pattern p = Pattern.compile(Constants.URL_PATTERN); final Matcher m = p.matcher(url); @@ -246,9 +246,9 @@ private static List getURLHostInfos(String hostURLs) throws SQLExcepti StringTokenizer stringTokenizer = new StringTokenizer(hostURLs, ","); while (stringTokenizer.hasMoreTokens()) { String hostString = stringTokenizer.nextToken(); - /* - pattern = ip:port - */ + /* + pattern = ip:port + */ final Pattern p = Pattern.compile("([^/:]+):(\\d+)?"); final Matcher m = p.matcher(hostString); if (!m.find()) { diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java index 0c87ff34d0e..2a04e89aee1 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessMySQLDatabaseMetadata.java @@ -111,10 +111,10 @@ public class VitessMySQLDatabaseMetadata extends VitessDatabaseMetaData implemen "OF", "VIEW", "DOMAIN", "ON", "WHEN", "DOUBLE", "ONLY", "WHENEVER", "DROP", "OPEN", "WHERE", "ELSE", "OPTION", "WITH", "END", "OR", "WORK", "END-EXEC", "ORDER", "WRITE", "ESCAPE", "OUTER", "YEAR", "EXCEPT", "OUTPUT", "ZONE", "EXCEPTION"}; - TreeMap mySQLKeywordMap = new TreeMap(); + TreeMap mySqlKeywordMap = new TreeMap(); for (String allMySQLKeyword : allMySQLKeywords) { - mySQLKeywordMap.put(allMySQLKeyword, null); + mySqlKeywordMap.put(allMySQLKeyword, null); } HashMap sql92KeywordMap = new HashMap(sql92Keywords.length); @@ -126,11 +126,11 @@ public class VitessMySQLDatabaseMetadata extends VitessDatabaseMetaData implemen Iterator sql92KeywordIterator = sql92KeywordMap.keySet().iterator(); while (sql92KeywordIterator.hasNext()) { - mySQLKeywordMap.remove(sql92KeywordIterator.next()); + mySqlKeywordMap.remove(sql92KeywordIterator.next()); } StringBuffer keywordBuf = new StringBuffer(); - sql92KeywordIterator = mySQLKeywordMap.keySet().iterator(); + sql92KeywordIterator = mySqlKeywordMap.keySet().iterator(); if (sql92KeywordIterator.hasNext()) { keywordBuf.append(sql92KeywordIterator.next().toString()); } @@ -1396,9 +1396,14 @@ public boolean isWrapperFor(Class iface) throws SQLException { /** * Enumeration for Table Types */ - protected enum TableType {LOCAL_TEMPORARY("LOCAL TEMPORARY"), SYSTEM_TABLE( - "SYSTEM TABLE"), SYSTEM_VIEW("SYSTEM VIEW"), TABLE("TABLE", new String[]{"BASE TABLE"}), VIEW( - "VIEW"), UNKNOWN("UNKNOWN"); + protected enum TableType { + LOCAL_TEMPORARY("LOCAL TEMPORARY"), + SYSTEM_TABLE("SYSTEM TABLE"), + SYSTEM_VIEW("SYSTEM VIEW"), + TABLE("TABLE", new String[]{"BASE TABLE"}), + VIEW("VIEW"), + UNKNOWN("UNKNOWN"), + ; private String name; private byte[] nameAsBytes; @@ -1452,7 +1457,8 @@ boolean compliesWith(String tableTypeName) { } } return false; - }} + } + } /** diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java index eef8b6f2078..19142fd4884 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessPreparedStatement.java @@ -104,17 +104,15 @@ public VitessPreparedStatement(VitessConnection vitessConnection, String sql, in } public ResultSet executeQuery() throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - checkOpen(); closeOpenResultSetAndResetCount(); //Setting to default value this.generatedId = -1; - vtGateConn = this.vitessConnection.getVtGateConn(); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); + Cursor cursor; try { if (vitessConnection.isSimpleExecute() && this.fetchSize == 0) { checkAndBeginTransaction(); @@ -140,16 +138,14 @@ public ResultSet executeQuery() throws SQLException { } public int executeUpdate() throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - int truncatedUpdateCount; - checkOpen(); checkNotReadOnly(); closeOpenResultSetAndResetCount(); - vtGateConn = this.vitessConnection.getVtGateConn(); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); + int truncatedUpdateCount; + Cursor cursor; try { checkAndBeginTransaction(); Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); @@ -205,135 +201,136 @@ public void setNull(int parameterIndex, int sqlType) throws SQLException { this.bindVariables.put(Constants.LITERAL_V + parameterIndex, null); } - public void setBoolean(int parameterIndex, boolean x) throws SQLException { + public void setBoolean(int parameterIndex, boolean ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setByte(int parameterIndex, byte x) throws SQLException { + public void setByte(int parameterIndex, byte ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setShort(int parameterIndex, short x) throws SQLException { + public void setShort(int parameterIndex, short ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setInt(int parameterIndex, int x) throws SQLException { + public void setInt(int parameterIndex, int ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setLong(int parameterIndex, long x) throws SQLException { + public void setLong(int parameterIndex, long ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setFloat(int parameterIndex, float x) throws SQLException { + public void setFloat(int parameterIndex, float ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setDouble(int parameterIndex, double x) throws SQLException { + public void setDouble(int parameterIndex, double ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setBigDecimal(int parameterIndex, BigDecimal x) throws SQLException { + public void setBigDecimal(int parameterIndex, BigDecimal ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setBigInteger(int parameterIndex, BigInteger x) throws SQLException { + public void setBigInteger(int parameterIndex, BigInteger ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setString(int parameterIndex, String x) throws SQLException { + public void setString(int parameterIndex, String ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setBytes(int parameterIndex, byte[] x) throws SQLException { + public void setBytes(int parameterIndex, byte[] ignored) throws SQLException { checkOpen(); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, x); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, ignored); } - public void setDate(int parameterIndex, Date x) throws SQLException { + public void setDate(int parameterIndex, Date date) throws SQLException { checkOpen(); - String date = DateTime.formatDate(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); + String dateString = DateTime.formatDate(date); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, dateString); } - public void setTime(int parameterIndex, Time x) throws SQLException { + public void setTime(int parameterIndex, Time time) throws SQLException { checkOpen(); - String time = DateTime.formatTime(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); + String timeString = DateTime.formatTime(time); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeString); } - public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { + public void setTimestamp(int parameterIndex, Timestamp timestamp) throws SQLException { checkOpen(); - String timeStamp = DateTime.formatTimestamp(x); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); + String timestampString = DateTime.formatTimestamp(timestamp); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timestampString); } - public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException { + public void setDate(int parameterIndex, Date date, Calendar cal) throws SQLException { checkOpen(); - String date = DateTime.formatDate(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, date); + String formattedDate = DateTime.formatDate(date, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, formattedDate); } - public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException { + public void setTime(int parameterIndex, Time time, Calendar cal) throws SQLException { checkOpen(); - String time = DateTime.formatTime(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, time); + String formattedTime = DateTime.formatTime(time, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, formattedTime); } - public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) throws SQLException { + public void setTimestamp(int parameterIndex, Timestamp timestamp, Calendar cal) + throws SQLException { checkOpen(); - String timeStamp = DateTime.formatTimestamp(x, cal); - this.bindVariables.put(Constants.LITERAL_V + parameterIndex, timeStamp); + String formattedTimestamp = DateTime.formatTimestamp(timestamp, cal); + this.bindVariables.put(Constants.LITERAL_V + parameterIndex, formattedTimestamp); } - public void setObject(int parameterIndex, Object x) throws SQLException { - if (x == null) { + public void setObject(int parameterIndex, Object object) throws SQLException { + if (object == null) { setNull(parameterIndex, Types.NULL); - } else if (x instanceof String) { - setString(parameterIndex, (String) x); - } else if (x instanceof Short) { - setShort(parameterIndex, (Short) x); - } else if (x instanceof Integer) { - setInt(parameterIndex, (Integer) x); - } else if (x instanceof Long) { - setLong(parameterIndex, (Long) x); - } else if (x instanceof Float) { - setFloat(parameterIndex, (Float) x); - } else if (x instanceof Double) { - setDouble(parameterIndex, (Double) x); - } else if (x instanceof Boolean) { - setBoolean(parameterIndex, (Boolean) x); - } else if (x instanceof Byte) { - setByte(parameterIndex, (Byte) x); - } else if (x instanceof Character) { - setString(parameterIndex, String.valueOf(x)); - } else if (x instanceof Date) { - setDate(parameterIndex, (Date) x); - } else if (x instanceof Time) { - setTime(parameterIndex, (Time) x); - } else if (x instanceof Timestamp) { - setTimestamp(parameterIndex, (Timestamp) x); - } else if (x instanceof BigDecimal) { - setBigDecimal(parameterIndex, (BigDecimal) x); - } else if (x instanceof BigInteger) { - setBigInteger(parameterIndex, (BigInteger) x); - } else if (x instanceof byte[]) { - setBytes(parameterIndex, (byte[]) x); - } else if (getConnection().getTreatUtilDateAsTimestamp() && x instanceof java.util.Date) { - setTimestamp(parameterIndex, new Timestamp(((java.util.Date) x).getTime())); + } else if (object instanceof String) { + setString(parameterIndex, (String) object); + } else if (object instanceof Short) { + setShort(parameterIndex, (Short) object); + } else if (object instanceof Integer) { + setInt(parameterIndex, (Integer) object); + } else if (object instanceof Long) { + setLong(parameterIndex, (Long) object); + } else if (object instanceof Float) { + setFloat(parameterIndex, (Float) object); + } else if (object instanceof Double) { + setDouble(parameterIndex, (Double) object); + } else if (object instanceof Boolean) { + setBoolean(parameterIndex, (Boolean) object); + } else if (object instanceof Byte) { + setByte(parameterIndex, (Byte) object); + } else if (object instanceof Character) { + setString(parameterIndex, String.valueOf(object)); + } else if (object instanceof Date) { + setDate(parameterIndex, (Date) object); + } else if (object instanceof Time) { + setTime(parameterIndex, (Time) object); + } else if (object instanceof Timestamp) { + setTimestamp(parameterIndex, (Timestamp) object); + } else if (object instanceof BigDecimal) { + setBigDecimal(parameterIndex, (BigDecimal) object); + } else if (object instanceof BigInteger) { + setBigInteger(parameterIndex, (BigInteger) object); + } else if (object instanceof byte[]) { + setBytes(parameterIndex, (byte[]) object); + } else if (getConnection().getTreatUtilDateAsTimestamp() && object instanceof java.util.Date) { + setTimestamp(parameterIndex, new Timestamp(((java.util.Date) object).getTime())); } else { throw new SQLException( - Constants.SQLExceptionMessages.SQL_TYPE_INFER + x.getClass().getCanonicalName()); + Constants.SQLExceptionMessages.SQL_TYPE_INFER + object.getClass().getCanonicalName()); } } @@ -446,20 +443,20 @@ private int calculateParameterCount() throws SQLException { int statementStartPos = StringUtils.findStartOfStatement(sql); for (int i = statementStartPos; i < statementLength; ++i) { - char c = sql.charAt(i); + char curChar = sql.charAt(i); - if (c == '\\' && i < (statementLength - 1)) { + if (curChar == '\\' && i < (statementLength - 1)) { i++; continue; // next character is escaped } // are we in a quoted identifier? (only valid when the id is not inside a 'string') - if (!inQuotes && c == quotedIdentifierChar) { + if (!inQuotes && curChar == quotedIdentifierChar) { inQuotedId = !inQuotedId; } else if (!inQuotedId) { - // only respect quotes when not in a quoted identifier + //only respect quotes when not in a quoted identifier if (inQuotes) { - if (((c == '\'') || (c == '"')) && c == currentQuoteChar) { + if (((curChar == '\'') || (curChar == '"')) && curChar == currentQuoteChar) { if (i < (statementLength - 1) && sql.charAt(i + 1) == currentQuoteChar) { i++; continue; // inline quote escape @@ -469,35 +466,38 @@ private int calculateParameterCount() throws SQLException { currentQuoteChar = 0; } } else { - if (c == '#' || (c == '-' && (i + 1) < statementLength && sql.charAt(i + 1) == '-')) { + if (curChar == '#' + || (curChar == '-' + && (i + 1) < statementLength + && sql.charAt(i + 1) == '-')) { // comment, run out to end of statement, or newline, whichever comes first int endOfStmt = statementLength - 1; for (; i < endOfStmt; i++) { - c = sql.charAt(i); + curChar = sql.charAt(i); - if (c == '\r' || c == '\n') { + if (curChar == '\r' || curChar == '\n') { break; } } continue; - } else if (c == '/' && (i + 1) < statementLength) { + } else if (curChar == '/' && (i + 1) < statementLength) { // Comment? - char cNext = sql.charAt(i + 1); - if (cNext == '*') { + char nextChar = sql.charAt(i + 1); + if (nextChar == '*') { i += 2; for (int j = i; j < statementLength; j++) { i++; - cNext = sql.charAt(j); + nextChar = sql.charAt(j); - if (cNext == '*' && (j + 1) < statementLength) { + if (nextChar == '*' && (j + 1) < statementLength) { if (sql.charAt(j + 1) == '/') { i++; if (i < statementLength) { - c = sql.charAt(i); + curChar = sql.charAt(i); } break; // comment done @@ -505,14 +505,14 @@ private int calculateParameterCount() throws SQLException { } } } - } else if ((c == '\'') || (c == '"')) { + } else if ((curChar == '\'') || (curChar == '"')) { inQuotes = true; - currentQuoteChar = c; + currentQuoteChar = curChar; } } } - if ((c == '?') && !inQuotes && !inQuotedId) { + if ((curChar == '?') && !inQuotes && !inQuotedId) { statementCount++; } } @@ -525,12 +525,13 @@ public void setNull(int parameterIndex, int sqlType, String typeName) throws SQL Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException { + public void setAsciiStream(int parameterIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { + public void setBinaryStream(int parameterIndex, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -653,12 +654,14 @@ public void setObject(int parameterIndex, Object parameterObject, int targetSqlT } } - public void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { + public void setAsciiStream(int parameterIndex, InputStream ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { + public void setBinaryStream(int parameterIndex, InputStream ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -669,34 +672,35 @@ public void setCharacterStream(int parameterIndex, Reader reader, long length) Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException { + public void setUnicodeStream(int parameterIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setRef(int parameterIndex, Ref x) throws SQLException { + public void setRef(int parameterIndex, Ref ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setBlob(int parameterIndex, Blob x) throws SQLException { + public void setBlob(int parameterIndex, Blob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setClob(int parameterIndex, Clob x) throws SQLException { + public void setClob(int parameterIndex, Clob clob) throws SQLException { checkOpen(); - if (x.length() > Integer.MAX_VALUE) { + if (clob.length() > Integer.MAX_VALUE) { throw new SQLFeatureNotSupportedException( String.format("Clob size over %d not support", Integer.MAX_VALUE), Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } // Clob uses 1-based indexing! this.bindVariables - .put(Constants.LITERAL_V + parameterIndex, x.getSubString(1, (int) x.length())); + .put(Constants.LITERAL_V + parameterIndex, clob.getSubString(1, (int) clob.length())); } - public void setArray(int parameterIndex, Array x) throws SQLException { + public void setArray(int parameterIndex, Array ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -706,12 +710,12 @@ public ResultSetMetaData getMetaData() throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setURL(int parameterIndex, URL x) throws SQLException { + public void setURL(int parameterIndex, URL ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setRowId(int parameterIndex, RowId x) throws SQLException { + public void setRowId(int parameterIndex, RowId ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -753,12 +757,13 @@ public void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { + public void setAsciiStream(int parameterIndex, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException { + public void setBinaryStream(int parameterIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java index 7c025010612..4b026a5fa0c 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSet.java @@ -89,8 +89,8 @@ public VitessResultSet(Cursor cursor, VitessStatement vitessStatement) throws SQ try { this.fields = enhancedFieldsFromCursor( vitessStatement == null ? null : vitessStatement.getConnection()); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } catch (SQLException exc) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, exc); } this.currentRow = 0; if (null != vitessStatement) { @@ -116,9 +116,9 @@ public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, String[][ Query.Row.Builder queryRow = Query.Row.newBuilder(); StringBuilder sb = new StringBuilder(); - for (String aRowData : rowData) { - sb.append(aRowData); - queryRow.addLengths(aRowData.length()); + for (String singleRowData : rowData) { + sb.append(singleRowData); + queryRow.addLengths(singleRowData.length()); } queryRow.setValues(ByteString.copyFromUtf8(sb.toString())); queryResultBuilder.addRows(queryRow); @@ -129,8 +129,8 @@ public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, String[][ this.vitessStatement = null; try { this.fields = enhancedFieldsFromCursor(connection); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } catch (SQLException exc) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, exc); } this.currentRow = 0; } @@ -151,10 +151,10 @@ public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, Query.Row.Builder queryRow = Query.Row.newBuilder(); StringBuilder sb = new StringBuilder(); - for (String aRowData : rowData) { - if (null != aRowData) { - sb.append(aRowData); - queryRow.addLengths(aRowData.length()); + for (String singleRowData : rowData) { + if (null != singleRowData) { + sb.append(singleRowData); + queryRow.addLengths(singleRowData.length()); } else { queryRow.addLengths(-1); } @@ -167,8 +167,8 @@ public VitessResultSet(String[] columnNames, Query.Type[] columnTypes, this.vitessStatement = null; try { this.fields = enhancedFieldsFromCursor(connection); - } catch (SQLException e) { - throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, e); + } catch (SQLException exc) { + throw new SQLException(Constants.SQLExceptionMessages.RESULT_SET_INIT_ERROR, exc); } this.currentRow = 0; } @@ -203,7 +203,7 @@ public void close() throws SQLException { if (!this.closed) { try { this.cursor.close(); - } catch (Exception e) { + } catch (Exception exc) { throw new SQLException(Constants.SQLExceptionMessages.VITESS_CURSOR_CLOSE_ERROR); } finally { //Dereferencing all the objects @@ -249,9 +249,6 @@ public String getString(int columnIndex) throws SQLException { } public boolean getBoolean(int columnIndex) throws SQLException { - String boolString; - int bool; - preAccessor(columnIndex); if (isNull(columnIndex)) { @@ -265,7 +262,8 @@ public boolean getBoolean(int columnIndex) throws SQLException { return byteArrayToBoolean(columnIndex); } - boolString = this.getString(columnIndex); + int bool; + String boolString = this.getString(columnIndex); try { bool = Integer.valueOf(boolString); } catch (NumberFormatException nfe) { @@ -275,9 +273,6 @@ public boolean getBoolean(int columnIndex) throws SQLException { } public byte getByte(int columnIndex) throws SQLException { - String byteString; - byte value; - preAccessor(columnIndex); if (isNull(columnIndex)) { return 0; @@ -290,7 +285,8 @@ public byte getByte(int columnIndex) throws SQLException { return (byte) object; } - byteString = this.getString(columnIndex); + byte value; + String byteString = this.getString(columnIndex); try { value = Byte.parseByte(byteString); } catch (NumberFormatException nfe) { @@ -449,9 +445,6 @@ public BigInteger getBigInteger(int columnIndex) throws SQLException { } public byte[] getBytes(int columnIndex) throws SQLException { - String bytesString; - byte[] value; - preAccessor(columnIndex); if (isNull(columnIndex)) { return null; @@ -463,7 +456,8 @@ public byte[] getBytes(int columnIndex) throws SQLException { return (byte[]) object; } - bytesString = this.getString(columnIndex); + byte[] value; + String bytesString = this.getString(columnIndex); try { value = bytesString.getBytes(); } catch (Exception ex) { @@ -631,8 +625,8 @@ private String convertBytesToString(byte[] bytes, String encoding) throws SQLExc } else { try { return StringUtils.toString(bytes, 0, bytes.length, encoding); - } catch (UnsupportedEncodingException e) { - throw new SQLException("Unsupported character encoding: " + encoding, e); + } catch (UnsupportedEncodingException exc) { + throw new SQLException("Unsupported character encoding: " + encoding, exc); } } } @@ -998,92 +992,95 @@ public void updateNull(int columnIndex) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBoolean(int columnIndex, boolean x) throws SQLException { + public void updateBoolean(int columnIndex, boolean ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateByte(int columnIndex, byte x) throws SQLException { + public void updateByte(int columnIndex, byte ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateShort(int columnIndex, short x) throws SQLException { + public void updateShort(int columnIndex, short ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateInt(int columnIndex, int x) throws SQLException { + public void updateInt(int columnIndex, int ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateLong(int columnIndex, long x) throws SQLException { + public void updateLong(int columnIndex, long ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateFloat(int columnIndex, float x) throws SQLException { + public void updateFloat(int columnIndex, float ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateDouble(int columnIndex, double x) throws SQLException { + public void updateDouble(int columnIndex, double ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBigDecimal(int columnIndex, BigDecimal x) throws SQLException { + public void updateBigDecimal(int columnIndex, BigDecimal ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateString(int columnIndex, String x) throws SQLException { + public void updateString(int columnIndex, String ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBytes(int columnIndex, byte[] x) throws SQLException { + public void updateBytes(int columnIndex, byte[] ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateDate(int columnIndex, Date x) throws SQLException { + public void updateDate(int columnIndex, Date ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateTime(int columnIndex, Time x) throws SQLException { + public void updateTime(int columnIndex, Time ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateTimestamp(int columnIndex, Timestamp x) throws SQLException { + public void updateTimestamp(int columnIndex, Timestamp ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(int columnIndex, InputStream x, int length) throws SQLException { + public void updateAsciiStream(int columnIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(int columnIndex, InputStream x, int length) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateCharacterStream(int columnIndex, Reader x, int length) throws SQLException { + public void updateCharacterStream(int columnIndex, Reader ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateObject(int columnIndex, Object x, int scaleOrLength) throws SQLException { + public void updateObject(int columnIndex, Object ignored, int scaleOrLength) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateObject(int columnIndex, Object x) throws SQLException { + public void updateObject(int columnIndex, Object ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1093,77 +1090,78 @@ public void updateNull(String columnLabel) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBoolean(String columnLabel, boolean x) throws SQLException { + public void updateBoolean(String columnLabel, boolean ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateByte(String columnLabel, byte x) throws SQLException { + public void updateByte(String columnLabel, byte ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateShort(String columnLabel, short x) throws SQLException { + public void updateShort(String columnLabel, short ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateInt(String columnLabel, int x) throws SQLException { + public void updateInt(String columnLabel, int ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateLong(String columnLabel, long x) throws SQLException { + public void updateLong(String columnLabel, long ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateFloat(String columnLabel, float x) throws SQLException { + public void updateFloat(String columnLabel, float ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateDouble(String columnLabel, double x) throws SQLException { + public void updateDouble(String columnLabel, double ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBigDecimal(String columnLabel, BigDecimal x) throws SQLException { + public void updateBigDecimal(String columnLabel, BigDecimal ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateString(String columnLabel, String x) throws SQLException { + public void updateString(String columnLabel, String ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBytes(String columnLabel, byte[] x) throws SQLException { + public void updateBytes(String columnLabel, byte[] ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateDate(String columnLabel, Date x) throws SQLException { + public void updateDate(String columnLabel, Date ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateTime(String columnLabel, Time x) throws SQLException { + public void updateTime(String columnLabel, Time ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateTimestamp(String columnLabel, Timestamp x) throws SQLException { + public void updateTimestamp(String columnLabel, Timestamp ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(String columnLabel, InputStream x, int length) throws SQLException { + public void updateAsciiStream(String columnLabel, InputStream ignored, int length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(String columnLabel, InputStream x, int length) + public void updateBinaryStream(String columnLabel, InputStream ignored, int length) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); @@ -1175,12 +1173,13 @@ public void updateCharacterStream(String columnLabel, Reader reader, int length) Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateObject(String columnLabel, Object x, int scaleOrLength) throws SQLException { + public void updateObject(String columnLabel, Object ignored, int scaleOrLength) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateObject(String columnLabel, Object x) throws SQLException { + public void updateObject(String columnLabel, Object ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1285,42 +1284,42 @@ public URL getURL(String columnLabel) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateRef(int columnIndex, Ref x) throws SQLException { + public void updateRef(int columnIndex, Ref ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateRef(String columnLabel, Ref x) throws SQLException { + public void updateRef(String columnLabel, Ref ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBlob(int columnIndex, Blob x) throws SQLException { + public void updateBlob(int columnIndex, Blob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBlob(String columnLabel, Blob x) throws SQLException { + public void updateBlob(String columnLabel, Blob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateClob(int columnIndex, Clob x) throws SQLException { + public void updateClob(int columnIndex, Clob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateClob(String columnLabel, Clob x) throws SQLException { + public void updateClob(String columnLabel, Clob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateArray(int columnIndex, Array x) throws SQLException { + public void updateArray(int columnIndex, Array ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateArray(String columnLabel, Array x) throws SQLException { + public void updateArray(String columnLabel, Array ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1335,12 +1334,12 @@ public RowId getRowId(String columnLabel) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateRowId(int columnIndex, RowId x) throws SQLException { + public void updateRowId(int columnIndex, RowId ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateRowId(String columnLabel, RowId x) throws SQLException { + public void updateRowId(String columnLabel, RowId ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1350,22 +1349,22 @@ public int getHoldability() throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNString(int columnIndex, String nString) throws SQLException { + public void updateNString(int columnIndex, String ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNString(String columnLabel, String nString) throws SQLException { + public void updateNString(String columnLabel, String ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNClob(int columnIndex, NClob nClob) throws SQLException { + public void updateNClob(int columnIndex, NClob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNClob(String columnLabel, NClob nClob) throws SQLException { + public void updateNClob(String columnLabel, NClob ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1420,7 +1419,8 @@ public Reader getNCharacterStream(String columnLabel) throws SQLException { Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + public void updateNCharacterStream(int columnIndex, Reader ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1431,28 +1431,31 @@ public void updateNCharacterStream(String columnLabel, Reader reader, long lengt Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { + public void updateAsciiStream(int columnIndex, InputStream ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { + public void updateCharacterStream(int columnIndex, Reader ignored, long length) + throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(String columnLabel, InputStream x, long length) + public void updateAsciiStream(String columnLabel, InputStream ignored, long length) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(String columnLabel, InputStream x, long length) + public void updateBinaryStream(String columnLabel, InputStream ignored, long length) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); @@ -1496,7 +1499,7 @@ public void updateNClob(String columnLabel, Reader reader, long length) throws S Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { + public void updateNCharacterStream(int columnIndex, Reader ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -1506,27 +1509,27 @@ public void updateNCharacterStream(String columnLabel, Reader reader) throws SQL Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { + public void updateAsciiStream(int columnIndex, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { + public void updateCharacterStream(int columnIndex, Reader ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { + public void updateAsciiStream(String columnLabel, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } - public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { + public void updateBinaryStream(String columnLabel, InputStream ignored) throws SQLException { throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java index 93a260ebab5..eaa54e9d570 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessResultSetMetaData.java @@ -75,11 +75,11 @@ public boolean isCaseSensitive(int column) throws SQLException { try { String collationName = field.getCollation(); return collationName != null && !collationName.endsWith("_ci"); - } catch (SQLException e) { - if (e.getCause() instanceof ArrayIndexOutOfBoundsException) { + } catch (SQLException exc) { + if (exc.getCause() instanceof ArrayIndexOutOfBoundsException) { return false; } else { - throw e; + throw exc; } } default: diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java index de76f81038d..0ebc0cb0635 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessStatement.java @@ -92,9 +92,6 @@ public VitessStatement(VitessConnection vitessConnection, int resultSetType, * @return ResultSet */ public ResultSet executeQuery(String sql) throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - checkOpen(); checkSQLNullOrEmpty(sql); closeOpenResultSetAndResetCount(); @@ -107,8 +104,9 @@ public ResultSet executeQuery(String sql) throws SQLException { this.retrieveGeneratedKeys = false; this.generatedId = -1; - vtGateConn = this.vitessConnection.getVtGateConn(); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); + Cursor cursor; if ((vitessConnection.isSimpleExecute() && this.fetchSize == 0) || vitessConnection .isInTransaction()) { checkAndBeginTransaction(); @@ -202,14 +200,14 @@ public int getMaxFieldSize() throws SQLException { } public void setMaxFieldSize(int max) throws SQLException { - /* Currently not used - checkOpen(); - if (max < 0 || max > Constants.MAX_BUFFER_SIZE) { - throw new SQLException( - Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "max field size"); - } - this.maxFieldSize = max; - */ + /* Currently not used + checkOpen(); + if (max < 0 || max > Constants.MAX_BUFFER_SIZE) { + throw new SQLException( + Constants.SQLExceptionMessages.ILLEGAL_VALUE_FOR + "max field size"); + } + this.maxFieldSize = max; + */ throw new SQLFeatureNotSupportedException( Constants.SQLExceptionMessages.SQL_FEATURE_NOT_SUPPORTED); } @@ -386,10 +384,6 @@ public ResultSet getGeneratedKeys() throws SQLException { * @return Row Affected Count */ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - VTGateConnection vtGateConn; - Cursor cursor; - int truncatedUpdateCount; - checkOpen(); checkNotReadOnly(); checkSQLNullOrEmpty(sql); @@ -399,11 +393,12 @@ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException throw new SQLException(Constants.SQLExceptionMessages.METHOD_NOT_ALLOWED); } - vtGateConn = this.vitessConnection.getVtGateConn(); + VTGateConnection vtGateConn = this.vitessConnection.getVtGateConn(); checkAndBeginTransaction(); Context context = this.vitessConnection.createContext(this.queryTimeoutInMillis); - cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()).checkedGet(); + Cursor cursor = vtGateConn.execute(context, sql, null, vitessConnection.getVtSession()) + .checkedGet(); if (null == cursor) { throw new SQLException(Constants.SQLExceptionMessages.METHOD_CALL_FAILED); @@ -423,6 +418,7 @@ public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException this.resultCount = cursor.getRowsAffected(); + int truncatedUpdateCount; if (this.resultCount > Integer.MAX_VALUE) { truncatedUpdateCount = Integer.MAX_VALUE; } else { diff --git a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java index 6a5b496ee16..ea0113b17ae 100644 --- a/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java +++ b/java/jdbc/src/main/java/io/vitess/jdbc/VitessVTGateManager.java @@ -228,8 +228,8 @@ public static void close() throws SQLException { for (VTGateConnection vtGateConn : vtGateConnHashMap.values()) { try { vtGateConn.close(); - } catch (IOException e) { - exception = new SQLException(e.getMessage(), e); + } catch (IOException ioe) { + exception = new SQLException(ioe.getMessage(), ioe); } } vtGateConnHashMap.clear(); From a016a721ec3966d36419863035d7ce7086565b5d Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Thu, 7 Feb 2019 10:22:49 -0500 Subject: [PATCH 030/196] example: conform to checkstyle Signed-off-by: Ze'ev Klapow --- .../vitess/example/VitessClientExample.java | 98 ++++--- .../io/vitess/example/VitessJDBCExample.java | 265 +++++++++--------- 2 files changed, 181 insertions(+), 182 deletions(-) diff --git a/java/example/src/main/java/io/vitess/example/VitessClientExample.java b/java/example/src/main/java/io/vitess/example/VitessClientExample.java index 9c51ee42349..de5e95a3e43 100644 --- a/java/example/src/main/java/io/vitess/example/VitessClientExample.java +++ b/java/example/src/main/java/io/vitess/example/VitessClientExample.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -18,6 +18,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.primitives.UnsignedLong; + import io.vitess.client.Context; import io.vitess.client.RpcClient; import io.vitess.client.VTGateBlockingConnection; @@ -40,56 +41,53 @@ * examples/local/README.md file. */ public class VitessClientExample { - public static void main(String[] args) { - if (args.length != 1) { - System.out.println("usage: VitessClientExample "); - System.exit(1); - } - Context ctx = Context.getDefault().withDeadlineAfter(Duration.millis(5 * 1000)); - try (RpcClient client = new GrpcClientFactory().create(ctx, args[0]); - VTGateBlockingConnection conn = new VTGateBlockingConnection(client)) { - VTSession session = new VTSession("@master", ExecuteOptions.getDefaultInstance()); - // Insert some messages on random pages. - System.out.println("Inserting into master..."); - Random rand = new Random(); - for (int i = 0; i < 3; i++) { - Instant timeCreated = Instant.now(); - Map bindVars = - new ImmutableMap.Builder() - .put("page", rand.nextInt(100) + 1) - .put("time_created_ns", timeCreated.getMillis() * 1000000) - .put("message", "V is for speed") - .build(); + public static void main(String[] args) { + if (args.length != 1) { + System.out.println("usage: VitessClientExample "); + System.exit(1); + } + + Context ctx = Context.getDefault().withDeadlineAfter(Duration.millis(5 * 1000)); + try (RpcClient client = new GrpcClientFactory() + .create(ctx, args[0]); VTGateBlockingConnection conn = new VTGateBlockingConnection( + client)) { + VTSession session = new VTSession("@master", ExecuteOptions.getDefaultInstance()); + // Insert some messages on random pages. + System.out.println("Inserting into master..."); + Random rand = new Random(); + for (int i = 0; i < 3; i++) { + Instant timeCreated = Instant.now(); + Map bindVars = new ImmutableMap.Builder() + .put("page", rand.nextInt(100) + 1) + .put("time_created_ns", timeCreated.getMillis() * 1000000) + .put("message", "V is for speed").build(); - conn.execute(ctx, "begin", null, session); - conn.execute( - ctx, - "INSERT INTO messages (page,time_created_ns,message) VALUES (:page,:time_created_ns,:message)", - bindVars, session); - conn.execute(ctx, "commit", null, session); - } + conn.execute(ctx, "begin", null, session); + conn.execute(ctx, + "INSERT INTO messages (page,time_created_ns,message) VALUES (:page,:time_created_ns," + + ":message)", + bindVars, session); + conn.execute(ctx, "commit", null, session); + } - // Read it back from the master. - System.out.println("Reading from master..."); - try (Cursor cursor = - conn.execute( - ctx, - "SELECT page, time_created_ns, message FROM messages", - null, session)) { - Row row; - while ((row = cursor.next()) != null) { - UnsignedLong page = row.getULong("page"); - UnsignedLong timeCreated = row.getULong("time_created_ns"); - byte[] message = row.getBytes("message"); - System.out.format("(%s, %s, %s)\n", page, timeCreated, new String(message)); - } - } - } catch (Exception e) { - System.out.println("Vitess Java example failed."); - System.out.println("Error Details:"); - e.printStackTrace(); - System.exit(2); + // Read it back from the master. + System.out.println("Reading from master..."); + try (Cursor cursor = conn + .execute(ctx, "SELECT page, time_created_ns, message FROM messages", null, session)) { + Row row; + while ((row = cursor.next()) != null) { + UnsignedLong page = row.getULong("page"); + UnsignedLong timeCreated = row.getULong("time_created_ns"); + byte[] message = row.getBytes("message"); + System.out.format("(%s, %s, %s)\n", page, timeCreated, new String(message)); } + } + } catch (Exception exc) { + System.out.println("Vitess Java example failed."); + System.out.println("Error Details:"); + exc.printStackTrace(); + System.exit(2); } + } } diff --git a/java/example/src/main/java/io/vitess/example/VitessJDBCExample.java b/java/example/src/main/java/io/vitess/example/VitessJDBCExample.java index c8ac0fde363..1c6b18a17a9 100644 --- a/java/example/src/main/java/io/vitess/example/VitessJDBCExample.java +++ b/java/example/src/main/java/io/vitess/example/VitessJDBCExample.java @@ -1,12 +1,12 @@ /* * Copyright 2017 Google Inc. - * + * * 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. @@ -16,6 +16,8 @@ package io.vitess.example; +import org.joda.time.Instant; + import java.sql.BatchUpdateException; import java.sql.Connection; import java.sql.DriverManager; @@ -24,7 +26,6 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.Random; -import org.joda.time.Instant; /** * VitessJDBCExample.java is a sample for using the Vitess JDBC driver. @@ -33,140 +34,140 @@ * examples/local/README.md file. */ public class VitessJDBCExample { - public static void main(String[] args) throws Exception { - if (args.length != 1) { - System.out.println("usage: VitessJDBCExample "); - System.exit(1); - } - - // Connect to vtgate. - String dbURL = "jdbc:vitess://" + args[0]; - try (Connection conn = DriverManager.getConnection(dbURL, null)) { - // Setting AutoCommit to false as VTTablet was not up with enable-autocommit - // Not Required if enable-autocommit flag is set in VTTablet - conn.setAutoCommit(false); - - // Insert some messages on random pages. - System.out.println("Inserting into master..."); - insertData(conn); - - // To Commit Open Transaction - conn.commit(); - - // Read it back from master. - System.out.println("Reading from master..."); - readData(conn); - - // To Commit Open Transaction, - // as select was made on master with autocommit false a transaction was open - conn.commit(); - - // Read it back from replica. - dbURL += "?target=test_keyspace@replica"; - try (Connection connReplica = DriverManager.getConnection(dbURL, null)) { - System.out.println("Reading from replica..."); - readData(connReplica); - } - - // Execute DML Queries in a Batch - batchedQueries(conn); - - // To Commit Open Transaction - conn.commit(); - - } catch (Exception e) { - System.out.println("Vitess JDBC example failed."); - System.out.println("Error Details:"); - e.printStackTrace(); - System.exit(2); - } - } - private static void insertData(Connection conn) throws SQLException { - Random rand = new Random(); - try (PreparedStatement stmt = conn.prepareStatement( - "INSERT INTO messages (page,time_created_ns,message) VALUES (?,?,?)")) { - for (int i = 0; i < 3; i++) { - Instant timeCreated = Instant.now(); - int page = rand.nextInt(100) + 1; - stmt.setInt(1, page); - stmt.setLong(2, timeCreated.getMillis() * 1000000); - stmt.setString(3, "V is for speed"); - stmt.execute(); - } - } + public static void main(String[] args) throws Exception { + if (args.length != 1) { + System.out.println("usage: VitessJDBCExample "); + System.exit(1); } - private static void readData(Connection conn) throws SQLException { - String sql = "SELECT page, time_created_ns, message FROM messages"; - try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { - while (rs.next()) { - long page = rs.getLong("page"); - long timeCreated = rs.getLong("time_created_ns"); - String message = rs.getString("message"); - System.out.format("(%s, %s, %s)\n", page, timeCreated, message); - } - } + // Connect to vtgate. + String dbURL = "jdbc:vitess://" + args[0]; + try (Connection conn = DriverManager.getConnection(dbURL, null)) { + // Setting AutoCommit to false as VTTablet was not up with enable-autocommit + // Not Required if enable-autocommit flag is set in VTTablet + conn.setAutoCommit(false); + + // Insert some messages on random pages. + System.out.println("Inserting into master..."); + insertData(conn); + + // To Commit Open Transaction + conn.commit(); + + // Read it back from master. + System.out.println("Reading from master..."); + readData(conn); + + // To Commit Open Transaction, + // as select was made on master with autocommit false a transaction was open + conn.commit(); + + // Read it back from replica. + dbURL += "?target=test_keyspace@replica"; + try (Connection connReplica = DriverManager.getConnection(dbURL, null)) { + System.out.println("Reading from replica..."); + readData(connReplica); + } + + // Execute DML Queries in a Batch + batchedQueries(conn); + + // To Commit Open Transaction + conn.commit(); + + } catch (Exception exc) { + System.out.println("Vitess JDBC example failed."); + System.out.println("Error Details:"); + exc.printStackTrace(); + System.exit(2); + } + } + + private static void insertData(Connection conn) throws SQLException { + Random rand = new Random(); + try (PreparedStatement stmt = conn + .prepareStatement("INSERT INTO messages (page,time_created_ns,message) VALUES (?,?,?)")) { + for (int i = 0; i < 3; i++) { + Instant timeCreated = Instant.now(); + int page = rand.nextInt(100) + 1; + stmt.setInt(1, page); + stmt.setLong(2, timeCreated.getMillis() * 1000000); + stmt.setString(3, "V is for speed"); + stmt.execute(); + } + } + } + + private static void readData(Connection conn) throws SQLException { + String sql = "SELECT page, time_created_ns, message FROM messages"; + try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { + while (rs.next()) { + long page = rs.getLong("page"); + long timeCreated = rs.getLong("time_created_ns"); + String message = rs.getString("message"); + System.out.format("(%s, %s, %s)\n", page, timeCreated, message); + } + } + } + + private static void batchedQueries(Connection conn) throws SQLException { + Random rand = new Random(); + try (PreparedStatement stmt = conn + .prepareStatement("INSERT INTO messages (page,time_created_ns,message) VALUES (?,?,?)")) { + for (int i = 0; i < 3; i++) { + Instant timeCreated = Instant.now(); + int page = rand.nextInt(100) + 1; + stmt.setInt(1, page); + stmt.setLong(2, timeCreated.getMillis() * 1000000); + stmt.setString(3, "V is for speed"); + stmt.addBatch(); + } + int[] updateCounts; + try { + updateCounts = stmt.executeBatch(); + } catch (BatchUpdateException ex) { + updateCounts = ex.getUpdateCounts(); + } + if (null != updateCounts) { + evalBatchResult(updateCounts); + } } - private static void batchedQueries(Connection conn) throws SQLException { - Random rand = new Random(); - try (PreparedStatement stmt = conn.prepareStatement( - "INSERT INTO messages (page,time_created_ns,message) VALUES (?,?,?)")) { - for (int i = 0; i < 3; i++) { - Instant timeCreated = Instant.now(); - int page = rand.nextInt(100) + 1; - stmt.setInt(1, page); - stmt.setLong(2, timeCreated.getMillis() * 1000000); - stmt.setString(3, "V is for speed"); - stmt.addBatch(); - } - int[] updateCounts; - try { - updateCounts = stmt.executeBatch(); - } catch (BatchUpdateException ex) { - updateCounts = ex.getUpdateCounts(); - } - if (null != updateCounts) { - evalBatchResult(updateCounts); - } - } - - try (Statement stmt = conn.createStatement()) { - Instant timeCreated = Instant.now(); - int page = rand.nextInt(100) + 1; - System.out.println("Page selected for all dml operation: " + page); - stmt.addBatch( - "INSERT INTO messages (page,time_created_ns,message) VALUES (" + page + "," - + timeCreated.getMillis() * 1000000 + ",'V is for speed')"); - stmt.addBatch( - "UPDATE messages set message = 'V Batch is for more speed' where page = " + page); - stmt.addBatch("DELETE FROM messages where page = " + page); - int[] updateCounts; - try { - updateCounts = stmt.executeBatch(); - } catch (BatchUpdateException ex) { - updateCounts = ex.getUpdateCounts(); - } - if (null != updateCounts) { - evalBatchResult(updateCounts); - } - } - + try (Statement stmt = conn.createStatement()) { + Instant timeCreated = Instant.now(); + int page = rand.nextInt(100) + 1; + System.out.println("Page selected for all dml operation: " + page); + stmt.addBatch("INSERT INTO messages (page,time_created_ns,message) VALUES (" + page + "," + + timeCreated.getMillis() * 1000000 + ",'V is for speed')"); + stmt.addBatch( + "UPDATE messages set message = 'V Batch is for more speed' where page = " + page); + stmt.addBatch("DELETE FROM messages where page = " + page); + int[] updateCounts; + try { + updateCounts = stmt.executeBatch(); + } catch (BatchUpdateException ex) { + updateCounts = ex.getUpdateCounts(); + } + if (null != updateCounts) { + evalBatchResult(updateCounts); + } } - private static void evalBatchResult(int[] updateCounts) { - for (int i = 0; i < updateCounts.length; i++) { - switch (updateCounts[i]) { - case Statement.EXECUTE_FAILED: - System.out.println("execution failed"); - break; - case Statement.SUCCESS_NO_INFO: - System.out.println("execution success with no result"); - break; - default: - System.out.println("execution success with rows changed: " + updateCounts[i]); - } - } + } + + private static void evalBatchResult(int[] updateCounts) { + for (int i = 0; i < updateCounts.length; i++) { + switch (updateCounts[i]) { + case Statement.EXECUTE_FAILED: + System.out.println("execution failed"); + break; + case Statement.SUCCESS_NO_INFO: + System.out.println("execution success with no result"); + break; + default: + System.out.println("execution success with rows changed: " + updateCounts[i]); + } } + } } From b54bbd49463d3a206360c3e434946fac792409b7 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Thu, 7 Feb 2019 11:43:57 -0800 Subject: [PATCH 031/196] Fix some bugs in the original implementation of the srvkeyspace helpers Signed-off-by: Rafael Chacon --- go/vt/topo/shard.go | 41 ++++++---------- go/vt/topo/srv_keyspace.go | 96 ++++++++++++++++++-------------------- go/vt/vtctld/api.go | 1 - go/vt/wrangler/keyspace.go | 2 +- 4 files changed, 59 insertions(+), 81 deletions(-) diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index 86d4c44b978..31f5713a4a9 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -539,39 +539,24 @@ func (ts *Server) FindAllTabletAliasesInShardByCell(ctx context.Context, keyspac rec := concurrency.AllErrorRecorder{} result := make([]*topodatapb.TabletAlias, 0, len(resultAsMap)) for _, cell := range cells { - srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) - if err != nil { - return result, err - } - - shardInCell := func() bool { - for _, partition := range srvKeyspace.GetPartitions() { - for _, shardReference := range partition.ShardReferences { - if shardReference.GetName() == shard { - return true - } - } - } - return false - }() - - if shardInCell { - wg.Add(1) - go func(cell string) { - defer wg.Done() - sri, err := ts.GetShardReplication(ctx, cell, keyspace, shard) - if err != nil { - rec.RecordError(fmt.Errorf("GetShardReplication(%v, %v, %v) failed: %v", cell, keyspace, shard, err)) - return - } - + wg.Add(1) + go func(cell string) { + defer wg.Done() + sri, err := ts.GetShardReplication(ctx, cell, keyspace, shard) + switch { + case err == nil: mutex.Lock() for _, node := range sri.Nodes { resultAsMap[topoproto.TabletAliasString(node.TabletAlias)] = node.TabletAlias } mutex.Unlock() - }(cell) - } + case IsErrType(err, NoNode): + // There is no shard replication for this shard in this cell. NOOP + default: + rec.RecordError(fmt.Errorf("GetShardReplication(%v, %v, %v) failed: %v", cell, keyspace, shard, err)) + return + } + }(cell) } wg.Wait() err = nil diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index 5e6472fd6fc..8bbbc2810a2 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -139,13 +139,15 @@ func (ts *Server) GetShardServingCells(ctx context.Context, si *ShardInfo) (serv defer wg.Done() srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) switch { - case err != nil: + case err == nil: for _, partition := range srvKeyspace.GetPartitions() { for _, shardReference := range partition.ShardReferences { if shardReference.GetName() == si.ShardName() { - mu.Lock() - defer mu.Unlock() - servingCells = append(servingCells, cell) + func() { + mu.Lock() + defer mu.Unlock() + servingCells = append(servingCells, cell) + }() } } } @@ -174,7 +176,7 @@ func (ts *Server) GetShardServingTypes(ctx context.Context, si *ShardInfo) (serv wg := sync.WaitGroup{} rec := concurrency.AllErrorRecorder{} - servingTypes = make([]topodatapb.TabletType, len(cells)) + servingTypes = make([]topodatapb.TabletType, 0) var mu sync.Mutex for _, cell := range cells { wg.Add(1) @@ -182,24 +184,32 @@ func (ts *Server) GetShardServingTypes(ctx context.Context, si *ShardInfo) (serv defer wg.Done() srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) switch { - case err != nil: - for _, partition := range srvKeyspace.GetPartitions() { - for _, shardReference := range partition.ShardReferences { - if shardReference.GetName() == si.ShardName() { - mu.Lock() - defer mu.Unlock() - found := false - for _, servingType := range servingTypes { - if servingType == partition.ServedType { - found = true - } + case err == nil: + func() { + mu.Lock() + defer mu.Unlock() + for _, partition := range srvKeyspace.GetPartitions() { + // Check that served types hasn't been added already + // TODO MAKE SURE TO ADD TO TEST FOR THIS + partitionAlreadyAdded := false + for _, servingType := range servingTypes { + if servingType == partition.ServedType { + partitionAlreadyAdded = true + break } - if !found { - servingTypes = append(servingTypes, partition.ServedType) + } + + if !partitionAlreadyAdded { + for _, shardReference := range partition.ShardReferences { + if shardReference.GetName() == si.ShardName() { + servingTypes = append(servingTypes, partition.ServedType) + break + } } } + } - } + }() case IsErrType(err, NoNode): // NOOP return @@ -254,10 +264,6 @@ func (ts *Server) RemoveShardServingKeyspace(ctx context.Context, si *ShardInfo, return } - if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { - rec.RecordError(err) - return - } err = ts.UpdateSrvKeyspace(ctx, cell, si.keyspace, srvKeyspace) if err != nil { rec.RecordError(err) @@ -329,7 +335,7 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string shardTabletControl := &topodatapb.ShardTabletControl{ Name: si.ShardName(), KeyRange: si.KeyRange, - QueryServiceDisabled: true, + QueryServiceDisabled: disableQueryService, } partition.ShardTabletControls = append(partition.GetShardTabletControls(), shardTabletControl) } @@ -376,40 +382,28 @@ func (ts *Server) MigrateServedType(ctx context.Context, keyspace string, shards rec.RecordError(err) return } - for _, si := range shardsToAdd { - for _, partition := range srvKeyspace.GetPartitions() { - if partition.GetServedType() != tabletType { - continue - } - found := false - for _, shardReference := range partition.GetShardReferences() { - if shardReference.GetName() == si.ShardName() { - found = true - } - } + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } - if !found { - shardReference := &topodatapb.ShardReference{ - Name: si.ShardName(), - KeyRange: si.KeyRange, + shardReferences := partition.GetShardReferences()[:0] + for _, si := range shardsToRemove { + for _, shardReference := range shardReferences { + if shardReference.GetName() != si.ShardName() { + shardReferences = append(shardReferences, shardReference) } - partition.ShardReferences = append(partition.GetShardReferences(), shardReference) } } - } - for _, si := range shardsToRemove { - for _, partition := range srvKeyspace.GetPartitions() { - if partition.GetServedType() != tabletType { - continue - } - shardReferences := make([]*topodatapb.ShardReference, 0) - for _, shardReference := range partition.GetShardReferences() { - if shardReference.GetName() != si.ShardName() { - partition.ShardReferences = append(shardReferences, shardReference) - } + for _, si := range shardsToAdd { + shardReference := &topodatapb.ShardReference{ + Name: si.ShardName(), + KeyRange: si.KeyRange, } + shardReferences = append(shardReferences, shardReference) } + partition.ShardReferences = shardReferences } if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { diff --git a/go/vt/vtctld/api.go b/go/vt/vtctld/api.go index d5522e06beb..54da31b7653 100644 --- a/go/vt/vtctld/api.go +++ b/go/vt/vtctld/api.go @@ -327,7 +327,6 @@ func initAPI(ctx context.Context, ts *topo.Server, actions *ActionRepository, re } return result, nil } - log.Infof("Using findAllTablets with nil cells") result, err := ts.FindAllTabletAliasesInShard(ctx, keyspace, shard) if err != nil && !topo.IsErrType(err, topo.PartialResult) { return result, err diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index ee0b57e8a89..596382424d7 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -488,7 +488,7 @@ func (wr *Wrangler) replicaMigrateServedType(ctx context.Context, keyspace strin // Now update serving keyspace - if err = wr.ts.MigrateServedType(ctx, keyspace, fromShards, toShards, servedType, cells); err != nil { + if err = wr.ts.MigrateServedType(ctx, keyspace, toShards, fromShards, servedType, cells); err != nil { return err } From 2b0379112e13a1dce27f3680a38689e30ddc5866 Mon Sep 17 00:00:00 2001 From: deepthi Date: Thu, 7 Feb 2019 18:59:19 -0800 Subject: [PATCH 032/196] run bootstrap.sh on docker image if either vendor.json or bootstrap.sh has changed Signed-off-by: deepthi --- docker/test/run.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docker/test/run.sh b/docker/test/run.sh index fbc9d8ed89c..5ace5d5b701 100755 --- a/docker/test/run.sh +++ b/docker/test/run.sh @@ -177,6 +177,20 @@ copy_src_cmd="cp -R /tmp/src/!(vendor) ." # Git repository. copy_src_cmd=$(append_cmd "$copy_src_cmd" "cp -R /tmp/src/.git .") +run_bootstrap=0 +if [[ $(git diff-tree -r --name-only HEAD master | grep "vendor.json") ]]; then + copy_src_cmd=$(append_cmd "$copy_src_cmd" "mkdir -p vendor") + copy_src_cmd=$(append_cmd "$copy_src_cmd" "cp /tmp/src/vendor/vendor.json ./vendor") + run_bootstrap=1 +fi +if [[ $(git diff-tree -r --name-only HEAD master | grep "bootstrap.sh") ]]; then + run_bootstrap=1 +fi + +if [ $run_bootstrap -eq 1 ]; then + copy_src_cmd=$(append_cmd "$copy_src_cmd" "./bootstrap.sh") +fi + # Construct the command we will actually run. # # Uncomment the next line if you need to debug "bashcmd". From 4a410e80f75f396e3af30c68fdf2cfb46c485ade Mon Sep 17 00:00:00 2001 From: deepthi Date: Thu, 7 Feb 2019 20:59:54 -0800 Subject: [PATCH 033/196] run govendor/bootstrap.sh on docker image as needed Signed-off-by: deepthi --- docker/test/run.sh | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/docker/test/run.sh b/docker/test/run.sh index 5ace5d5b701..15b305d2206 100755 --- a/docker/test/run.sh +++ b/docker/test/run.sh @@ -162,7 +162,6 @@ esac # Construct "cp" command to copy the source code. # -# TODO(mberlin): Copy vendor/vendor.json file such that we can run a diff against the file on the image. # Copy the full source tree except: # - vendor # That's because these directories are already part of the image. @@ -172,24 +171,18 @@ esac # we do not move or overwrite the existing files while copying the other # directories. Therefore, the existing files do not count as changed and will # not be part of the new Docker layer of the cache image. -copy_src_cmd="cp -R /tmp/src/!(vendor) ." +copy_src_cmd="cp -R /tmp/src/!(vendor|bootstrap.sh) ." # Copy the .git directory because travis/check_make_proto.sh needs a working # Git repository. copy_src_cmd=$(append_cmd "$copy_src_cmd" "cp -R /tmp/src/.git .") -run_bootstrap=0 -if [[ $(git diff-tree -r --name-only HEAD master | grep "vendor.json") ]]; then - copy_src_cmd=$(append_cmd "$copy_src_cmd" "mkdir -p vendor") - copy_src_cmd=$(append_cmd "$copy_src_cmd" "cp /tmp/src/vendor/vendor.json ./vendor") - run_bootstrap=1 -fi -if [[ $(git diff-tree -r --name-only HEAD master | grep "bootstrap.sh") ]]; then - run_bootstrap=1 -fi - -if [ $run_bootstrap -eq 1 ]; then - copy_src_cmd=$(append_cmd "$copy_src_cmd" "./bootstrap.sh") -fi +# Copy vendor/vendor.json file if it changed +run_bootstrap_cmd="if [[ \$(diff -w vendor/vendor.json /tmp/src/vendor/vendor.json) ]]; then cp -f /tmp/src/vendor/vendor.json vendor/; sync_vendor=1; fi" +# Copy bootstrap.sh if it changed +run_bootstrap_cmd=$(append_cmd "$run_bootstrap_cmd" "if [[ \$(diff -w bootstrap.sh /tmp/src/bootstrap.sh) ]]; then cp -f /tmp/src/bootstrap.sh .; bootstrap=1; fi") +# run bootstrap.sh if necessary +run_bootstrap_cmd=$(append_cmd "$run_bootstrap_cmd" "if [[ -n \$bootstrap ]]; then ./bootstrap.sh; else if [[ -n \$sync_vendor ]]; then govendor sync; fi; fi") +copy_src_cmd=$(append_cmd "$copy_src_cmd" "$run_bootstrap_cmd") # Construct the command we will actually run. # From 98d1871ec9f5dc27b738acbec7a245f8407348bf Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Fri, 8 Feb 2019 10:35:52 -0500 Subject: [PATCH 034/196] check for negative timeout Signed-off-by: Ze'ev Klapow --- .../io/vitess/client/grpc/GrpcClient.java | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java index 61485b38b3b..c9998ea0519 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java @@ -20,10 +20,11 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; + import io.grpc.CallCredentials; +import io.grpc.InternalWithLogId; import io.grpc.ManagedChannel; import io.grpc.StatusRuntimeException; -import io.grpc.InternalWithLogId; import io.vitess.client.Context; import io.vitess.client.Proto; import io.vitess.client.RpcClient; @@ -65,6 +66,9 @@ import io.vitess.proto.grpc.VitessGrpc; import io.vitess.proto.grpc.VitessGrpc.VitessFutureStub; import io.vitess.proto.grpc.VitessGrpc.VitessStub; + +import org.joda.time.Duration; + import java.io.IOException; import java.sql.SQLException; import java.sql.SQLIntegrityConstraintViolationException; @@ -75,7 +79,6 @@ import java.sql.SQLTimeoutException; import java.sql.SQLTransientException; import java.util.concurrent.TimeUnit; -import org.joda.time.Duration; /** * GrpcClient is a gRPC-based implementation of Vitess RpcClient. @@ -102,7 +105,7 @@ public GrpcClient(ManagedChannel channel, Context context) { channelId = toChannelId(channel); asyncStub = VitessGrpc.newStub(channel); futureStub = VitessGrpc.newFutureStub(channel); - timeout = context.getTimeout() != null ? context.getTimeout() : DEFAULT_TIMEOUT; + timeout = getContextTimeoutOrDefault(context); } public GrpcClient(ManagedChannel channel, CallCredentials credentials, Context context) { @@ -110,7 +113,7 @@ public GrpcClient(ManagedChannel channel, CallCredentials credentials, Context c channelId = toChannelId(channel); asyncStub = VitessGrpc.newStub(channel).withCallCredentials(credentials); futureStub = VitessGrpc.newFutureStub(channel).withCallCredentials(credentials); - timeout = context.getTimeout() != null ? context.getTimeout() : DEFAULT_TIMEOUT; + timeout = getContextTimeoutOrDefault(context); } private String toChannelId(ManagedChannel channel) { @@ -345,4 +348,12 @@ public String toString() { channelId ); } + + private static Duration getContextTimeoutOrDefault(Context context) { + if (context.getTimeout() == null || context.getTimeout().getStandardSeconds() < 0) { + return DEFAULT_TIMEOUT; + } + + return context.getTimeout(); + } } From 26cb613c158c0e664e501e9ac633cee0692aa87b Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Fri, 8 Feb 2019 12:15:46 -0500 Subject: [PATCH 035/196] add precommit hook Signed-off-by: Ze'ev Klapow --- misc/git/hooks/checkstyle | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100755 misc/git/hooks/checkstyle diff --git a/misc/git/hooks/checkstyle b/misc/git/hooks/checkstyle new file mode 100755 index 00000000000..cc0ec070e7d --- /dev/null +++ b/misc/git/hooks/checkstyle @@ -0,0 +1,37 @@ +#!/bin/bash -e +function get_module() { + local path=$1; + while true; do + path=$(dirname $path); + if [ -f "$path/pom.xml" ]; then + echo "$path"; + return; + elif [[ "./" =~ "$path" ]]; then + return; + fi + done +} + +modules=(); + +for file in $(git diff --name-only --cached \*.java); do + module=$(get_module "$file"); + if [ "" != "$module" ] \ + && [[ ! " ${modules[@]} " =~ " $module " ]]; then + modules+=("$module"); + fi +done; + +if [ ${#modules[@]} -eq 0 ]; then + exit; +fi + +modules_arg=$(printf ",%s" "${modules[@]}"); +modules_arg=${modules_arg:1}; + +export MAVEN_OPTS="-client + -XX:+TieredCompilation + -XX:TieredStopAtLevel=1 + -Xverify:none"; + +mvn -q -pl "$modules_arg" checkstyle:check; From b5973f5723366f4066b5ff3cc1cd6245c777a596 Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Fri, 8 Feb 2019 12:41:04 -0500 Subject: [PATCH 036/196] fix checkstyle hook Signed-off-by: Ze'ev Klapow --- java/pom.xml | 2 +- misc/git/hooks/checkstyle | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/java/pom.xml b/java/pom.xml index ac05378c605..e127c984e0c 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -262,7 +262,7 @@ google_checks.xml checkstyle-suppression.xml true - false + true true warning diff --git a/misc/git/hooks/checkstyle b/misc/git/hooks/checkstyle index cc0ec070e7d..777dd512430 100755 --- a/misc/git/hooks/checkstyle +++ b/misc/git/hooks/checkstyle @@ -1,4 +1,7 @@ -#!/bin/bash -e +#!/bin/bash + +set -e + function get_module() { local path=$1; while true; do @@ -12,9 +15,11 @@ function get_module() { done } +cd java; + modules=(); -for file in $(git diff --name-only --cached \*.java); do +for file in $(git diff --relative --name-only --cached \*.java); do module=$(get_module "$file"); if [ "" != "$module" ] \ && [[ ! " ${modules[@]} " =~ " $module " ]]; then @@ -35,3 +40,5 @@ export MAVEN_OPTS="-client -Xverify:none"; mvn -q -pl "$modules_arg" checkstyle:check; + +cd -; From 947817c3f88c548aa6b786da32075d116464ea38 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Feb 2019 10:44:40 -0800 Subject: [PATCH 037/196] Bug fixes and cleanup * Some general code cleanup. * Discovered bug in cancelMasterMigration. When there are failures updating the topology, source shards will ended being assigned as nil. This will cause a panic reversing the migration. Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 36 ++++++++++++++++++++------------ go/vt/wrangler/keyspace.go | 42 ++++++++++++++++++++++++++++---------- 2 files changed, 54 insertions(+), 24 deletions(-) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index 8bbbc2810a2..d0944062422 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -131,7 +131,7 @@ func (ts *Server) GetShardServingCells(ctx context.Context, si *ShardInfo) (serv wg := sync.WaitGroup{} rec := concurrency.AllErrorRecorder{} - servingCells = make([]string, len(cells)) + servingCells = make([]string, 0) var mu sync.Mutex for _, cell := range cells { wg.Add(1) @@ -146,6 +146,12 @@ func (ts *Server) GetShardServingCells(ctx context.Context, si *ShardInfo) (serv func() { mu.Lock() defer mu.Unlock() + // Check that this cell hasn't been added already + for _, servingCell := range servingCells { + if servingCell == cell { + return + } + } servingCells = append(servingCells, cell) }() } @@ -289,11 +295,7 @@ func (ts *Server) RemoveShardServingKeyspace(ctx context.Context, si *ShardInfo, } // UpdateDisableQueryService will make sure the disableQueryService is -// set appropriately in the shard record. Note we don't support a lot -// of the corner cases: -// - we don't support DisableQueryService at the same time as BlacklistedTables, -// because it's not used in the same context (vertical vs horizontal sharding) -// This function should be called while holding the keyspace lock. +// set appropriately in tablet controls in srvKeyspace. func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string, disableQueryService bool) (err error) { if err = CheckKeyspaceLocked(ctx, keyspace); err != nil { return err @@ -311,18 +313,19 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string rec := concurrency.AllErrorRecorder{} for _, cell := range cells { wg.Add(1) - go func(cell, keyspace string) { + go func(cell string) { defer wg.Done() srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) if err != nil { rec.RecordError(err) return } - for _, si := range shards { - for _, partition := range srvKeyspace.GetPartitions() { - if partition.GetServedType() != tabletType { - continue - } + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } + + for _, si := range shards { found := false for _, tabletControl := range partition.GetShardTabletControls() { if tabletControl.GetName() == si.ShardName() { @@ -348,7 +351,7 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string return } - }(cell, keyspace) + }(cell) } wg.Wait() if rec.HasErrors() { @@ -383,6 +386,12 @@ func (ts *Server) MigrateServedType(ctx context.Context, keyspace string, shards return } for _, partition := range srvKeyspace.GetPartitions() { + + // We are finishing the migration, cleaning up tablet controls from the srvKeyspace + if tabletType == topodatapb.TabletType_MASTER { + partition.ShardTabletControls = nil + } + if partition.GetServedType() != tabletType { continue } @@ -403,6 +412,7 @@ func (ts *Server) MigrateServedType(ctx context.Context, keyspace string, shards } shardReferences = append(shardReferences, shardReference) } + partition.ShardReferences = shardReferences } diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index 596382424d7..3bbdab8f7a3 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -213,7 +213,7 @@ func (wr *Wrangler) cancelHorizontalResharding(ctx context.Context, keyspace, sh return err } } - destinationShards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { + updatedShard, err := wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { si.TabletControls = nil si.SourceShards = nil return nil @@ -221,6 +221,9 @@ func (wr *Wrangler) cancelHorizontalResharding(ctx context.Context, keyspace, sh if err != nil { return err } + + destinationShards[i] = updatedShard + if err := wr.RefreshTabletsByShard(ctx, si, nil, nil); err != nil { return err } @@ -506,18 +509,18 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string si := sourceShards[0] for _, srvKeyspace := range srvKeyspaces { - var types []string + var shardServedTypes []string for _, partition := range srvKeyspace.GetPartitions() { if partition.GetServedType() != topodatapb.TabletType_MASTER { for _, shardReference := range partition.GetShardReferences() { if shardReference.GetKeyRange() == si.GetKeyRange() { - types = append(types, partition.GetServedType().String()) + shardServedTypes = append(shardServedTypes, partition.GetServedType().String()) } } } } - if len(types) > 0 { - return fmt.Errorf("cannot migrate MASTER away from %v/%v until everything else is migrated. Make sure that the following types are migrated first: %v", si.Keyspace(), si.ShardName(), strings.Join(types, ", ")) + if len(shardServedTypes) > 0 { + return fmt.Errorf("cannot migrate MASTER away from %v/%v until everything else is migrated. Make sure that the following types are migrated first: %v", si.Keyspace(), si.ShardName(), strings.Join(shardServedTypes, ", ")) } } @@ -598,6 +601,7 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string // Similar to updateShardRecords, but we also remove SourceShards. destinationShards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { si.SourceShards = nil + si.IsMasterServing = true return nil }) if err != nil { @@ -624,11 +628,17 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string } } + // Update srvKeyspace now + if err = wr.ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_MASTER, nil); err != nil { + return err + } + event.DispatchUpdate(ev, "finished") return nil } func (wr *Wrangler) cancelMasterMigrateServedTypes(ctx context.Context, keyspace string, sourceShards []*topo.ShardInfo) { + wr.Logger().Infof("source shards cancelMasterMigrateServedTypes: %v", sourceShards) if err := wr.updateShardRecords(ctx, keyspace, sourceShards, nil, topodatapb.TabletType_MASTER, false, true); err != nil { wr.Logger().Errorf2(err, "failed to re-enable source masters") return @@ -723,8 +733,7 @@ func (wr *Wrangler) updateShardRecords(ctx context.Context, keyspace string, sha } for i, si := range shards { - - shards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { + updatedShard, err := wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { if clearSourceShards { si.SourceShards = nil } @@ -734,6 +743,9 @@ func (wr *Wrangler) updateShardRecords(ctx context.Context, keyspace string, sha if err != nil { return err } + + shards[i] = updatedShard + // For 'to' shards, refresh to make them serve. // The 'from' shards will be refreshed after traffic has migrated. if !isFrom { @@ -747,17 +759,25 @@ func (wr *Wrangler) updateShardRecords(ctx context.Context, keyspace string, sha // for all master tablet control records. func (wr *Wrangler) updateFrozenFlag(ctx context.Context, shards []*topo.ShardInfo, value bool) (err error) { for i, si := range shards { - shards[i], err = wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { + updatedShard, err := wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { tc := si.GetTabletControl(topodatapb.TabletType_MASTER) - if tc == nil { - return fmt.Errorf("unexpected: missing tablet control record for source %v/%v", si.Keyspace(), si.ShardName()) + if tc != nil { + tc.Frozen = value + return nil } - tc.Frozen = value + // This shard does not have a tablet control record, adding one to set frozen flag + tc = &topodatapb.Shard_TabletControl{ + TabletType: topodatapb.TabletType_MASTER, + Frozen: value, + } + si.TabletControls = []*topodatapb.Shard_TabletControl{tc} return nil }) if err != nil { return err } + + shards[i] = updatedShard } return nil } From 83f0ef79f142c9eeee36c41366977f0cd036a191 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Feb 2019 14:55:50 -0800 Subject: [PATCH 038/196] Update tests due to deprecated fields Signed-off-by: Rafael Chacon --- go/vt/srvtopo/resolver_test.go | 13 ------------- go/vt/topo/helpers/copy_test.go | 14 +------------- go/vt/topotools/shard_test.go | 4 ++-- 3 files changed, 3 insertions(+), 28 deletions(-) diff --git a/go/vt/srvtopo/resolver_test.go b/go/vt/srvtopo/resolver_test.go index 82a963d5037..f58e069a2a5 100644 --- a/go/vt/srvtopo/resolver_test.go +++ b/go/vt/srvtopo/resolver_test.go @@ -24,7 +24,6 @@ import ( "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/logutil" - "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/vttablet/queryservice" @@ -63,12 +62,6 @@ func initResolver(t *testing.T, name string) *Resolver { if err := ts.CreateShard(ctx, "sks", shard); err != nil { t.Fatalf("CreateShard(\"%v\") failed: %v", shard, err) } - if _, err := ts.UpdateShardFields(ctx, "sks", shard, func(si *topo.ShardInfo) error { - si.Shard.Cells = []string{"cell1"} - return nil - }); err != nil { - t.Fatalf("UpdateShardFields(\"%v\") failed: %v", shard, err) - } } // Create unsharded keyspace and shard. @@ -78,12 +71,6 @@ func initResolver(t *testing.T, name string) *Resolver { if err := ts.CreateShard(ctx, "uks", "0"); err != nil { t.Fatalf("CreateShard(0) failed: %v", err) } - if _, err := ts.UpdateShardFields(ctx, "uks", "0", func(si *topo.ShardInfo) error { - si.Shard.Cells = []string{"cell1"} - return nil - }); err != nil { - t.Fatalf("UpdateShardFields(0) failed: %v", err) - } // And rebuild both. for _, keyspace := range []string{"sks", "uks"} { diff --git a/go/vt/topo/helpers/copy_test.go b/go/vt/topo/helpers/copy_test.go index e067765e9d0..59d1df92822 100644 --- a/go/vt/topo/helpers/copy_test.go +++ b/go/vt/topo/helpers/copy_test.go @@ -42,12 +42,7 @@ func createSetup(ctx context.Context, t *testing.T) (*topo.Server, *topo.Server) if err := fromTS.CreateShard(ctx, "test_keyspace", "0"); err != nil { t.Fatalf("cannot create shard: %v", err) } - if _, err := fromTS.UpdateShardFields(ctx, "test_keyspace", "0", func(si *topo.ShardInfo) error { - si.Cells = []string{"test_cell"} - return nil - }); err != nil { - t.Fatalf("cannot update shard: %v", err) - } + tablet1 := &topodatapb.Tablet{ Alias: &topodatapb.TabletAlias{ Cell: "test_cell", @@ -120,13 +115,6 @@ func TestBasic(t *testing.T) { t.Fatalf("unexpected shards: %v", shards) } CopyShards(ctx, fromTS, toTS) - si, err := toTS.GetShard(ctx, "test_keyspace", "0") - if err != nil { - t.Fatalf("cannot read shard: %v", err) - } - if len(si.Shard.Cells) != 1 || si.Shard.Cells[0] != "test_cell" { - t.Fatalf("bad shard data: %v", *si.Shard) - } // check ShardReplication copy sr, err := fromTS.GetShardReplication(ctx, "test_cell", "test_keyspace", "0") diff --git a/go/vt/topotools/shard_test.go b/go/vt/topotools/shard_test.go index 70920f8698a..a2622709b59 100644 --- a/go/vt/topotools/shard_test.go +++ b/go/vt/topotools/shard_test.go @@ -77,7 +77,7 @@ func TestCreateShardCustomSharding(t *testing.T) { if si, err := ts.GetShard(ctx, keyspace, shard0); err != nil { t.Fatalf("GetShard(shard0) failed: %v", err) } else { - if len(si.ServedTypes) != 3 { + if !si.IsMasterServing { t.Fatalf("shard0 should have all 3 served types") } } @@ -90,7 +90,7 @@ func TestCreateShardCustomSharding(t *testing.T) { if si, err := ts.GetShard(ctx, keyspace, shard1); err != nil { t.Fatalf("GetShard(shard1) failed: %v", err) } else { - if len(si.ServedTypes) != 3 { + if !si.IsMasterServing { t.Fatalf("shard1 should have all 3 served types") } } From 59c7f657e3eb5d7e55c672a16548abc4f3a1dc1e Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Feb 2019 14:57:19 -0800 Subject: [PATCH 039/196] Update shard tests per refactor Signed-off-by: Rafael Chacon --- go/vt/topo/shard.go | 8 +- go/vt/topo/shard_test.go | 330 +++++++++++++++---------------------- go/vt/wrangler/keyspace.go | 17 +- 3 files changed, 155 insertions(+), 200 deletions(-) diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index 31f5713a4a9..8c05f7d88be 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -58,9 +58,9 @@ func addCells(left, right []string) []string { // removeCellsFromList will remove the cells from the provided list. It returns // the new list, and a boolean that indicates the returned list is empty. -func removeCellsFromList(cells, toRemove []string) []string { - leftoverCells := make([]string, 0, len(cells)) - for _, cell := range cells { +func removeCellsFromList(toRemove, fullList []string) []string { + leftoverCells := make([]string, 0) + for _, cell := range fullList { if !InCellList(cell, toRemove) { leftoverCells = append(leftoverCells, cell) } @@ -414,7 +414,7 @@ func (si *ShardInfo) UpdateSourceBlacklistedTables(ctx context.Context, tabletTy } func (si *ShardInfo) removeCellsFromTabletControl(tc *topodatapb.Shard_TabletControl, tabletType topodatapb.TabletType, cells []string) { - result := removeCellsFromList(tc.Cells, cells) + result := removeCellsFromList(cells, tc.Cells) if len(result) == 0 { // we don't have any cell left, we need to clear this record var tabletControls []*topodatapb.Shard_TabletControl diff --git a/go/vt/topo/shard_test.go b/go/vt/topo/shard_test.go index 9323f0c85c4..5fd27d172d5 100644 --- a/go/vt/topo/shard_test.go +++ b/go/vt/topo/shard_test.go @@ -57,6 +57,23 @@ func TestAddCells(t *testing.T) { } } +func TestRemoveCellsFromList(t *testing.T) { + var cells []string + allCells := []string{"first", "second", "third"} + + // remove from empty list should return allCells - what we remove + cells = removeCellsFromList([]string{"second"}, allCells) + if !reflect.DeepEqual(cells, []string{"first", "third"}) { + t.Fatalf("removeCells(full)-second failed: got %v", allCells) + } + + // removethe next two cells, should return empty list + cells = removeCellsFromList(cells, []string{"first", "third"}) + if len(cells) != 0 { + t.Fatalf("removeCells(full)-first-third is not empty: %v", cells) + } +} + func TestRemoveCells(t *testing.T) { var cells []string allCells := []string{"first", "second", "third"} @@ -86,9 +103,7 @@ func lockedKeyspaceContext(keyspace string) context.Context { } func TestUpdateSourceBlacklistedTables(t *testing.T) { - si := NewShardInfo("ks", "sh", &topodatapb.Shard{ - Cells: []string{"first", "second", "third"}, - }, nil) + si := NewShardInfo("ks", "sh", &topodatapb.Shard{}, nil) // check we enforce the keyspace lock ctx := context.Background() @@ -121,10 +136,6 @@ func TestUpdateSourceBlacklistedTables(t *testing.T) { if err := si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_RDONLY, []string{"second"}, false, []string{"t2", "t3"}); err == nil || err.Error() != "trying to use two different sets of blacklisted tables for shard ks/sh: [t1 t2] and [t2 t3]" { t.Fatalf("different table list should fail: %v", err) } - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_RDONLY, []string{"first"}, true); err == nil || err.Error() != "cannot safely alter DisableQueryService as BlacklistedTables is set" { - t.Fatalf("UpdateDisableQueryService should fail: %v", err) - } - // add another cell, see the list grow if err := si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_RDONLY, []string{"second"}, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControls, []*topodatapb.Shard_TabletControl{ { @@ -137,10 +148,10 @@ func TestUpdateSourceBlacklistedTables(t *testing.T) { } // add all cells, see the list grow to all - if err := si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_RDONLY, nil, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControls, []*topodatapb.Shard_TabletControl{ + if err := si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_RDONLY, []string{"first", "second", "third"}, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControls, []*topodatapb.Shard_TabletControl{ { TabletType: topodatapb.TabletType_RDONLY, - Cells: nil, + Cells: []string{"first", "second", "third"}, BlacklistedTables: []string{"t1", "t2"}, }, }) { @@ -159,189 +170,118 @@ func TestUpdateSourceBlacklistedTables(t *testing.T) { } } -func TestUpdateDisableQueryService(t *testing.T) { - si := NewShardInfo("ks", "sh", &topodatapb.Shard{ - Cells: []string{"first", "second", "third"}, - }, nil) - - // check we enforce the keyspace lock - ctx := context.Background() - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_RDONLY, nil, true); err == nil || err.Error() != "keyspace ks is not locked (no locksInfo)" { - t.Fatalf("unlocked keyspace produced wrong error: %v", err) - } - ctx = lockedKeyspaceContext("ks") - - // add one cell - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_RDONLY, []string{"first"}, true); err != nil || !reflect.DeepEqual(si.TabletControls, []*topodatapb.Shard_TabletControl{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: []string{"first"}, - DisableQueryService: true, - }, - }) { - t.Fatalf("one cell add failed: %v", si) - } - - // remove that cell, going back - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_RDONLY, []string{"first"}, false); err != nil || len(si.TabletControls) != 0 { - t.Fatalf("going back should have remove the record: %v %v", err, si) - } - - // re-add a cell, then another with a table list to - // make sure it fails - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_RDONLY, []string{"first"}, true); err != nil { - t.Fatalf("one cell add failed: %v", si) - } - if err := si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_RDONLY, []string{"second"}, false, []string{"t1", "t1"}); err == nil || err.Error() != "cannot safely alter BlacklistedTables as DisableQueryService is set for shard ks/sh" { - t.Fatalf("UpdateSourceBlacklistedTables should fail: %v", err) - } - - // add another cell, see the list grow - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_RDONLY, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.TabletControls, []*topodatapb.Shard_TabletControl{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: []string{"first", "second"}, - DisableQueryService: true, - }, - }) { - t.Fatalf("second cell add failed: %v", si) - } - - // add all cells, see the list grow to all - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_RDONLY, nil, true); err != nil || !reflect.DeepEqual(si.TabletControls, []*topodatapb.Shard_TabletControl{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: nil, - DisableQueryService: true, - }, - }) { - t.Fatalf("all cells add failed: %v", si) - } - - // remove one cell from the full list - if err := si.UpdateDisableQueryService(ctx, topodatapb.TabletType_RDONLY, []string{"second"}, false); err != nil || !reflect.DeepEqual(si.TabletControls, []*topodatapb.Shard_TabletControl{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: []string{"first", "third"}, - DisableQueryService: true, - }, - }) { - t.Fatalf("one cell removal from all failed: %v", si) - } -} - -func TestUpdateServedTypesMap(t *testing.T) { - si := NewShardInfo("ks", "sh", &topodatapb.Shard{ - Cells: []string{"first", "second", "third"}, - }, nil) - - // add all cells for rdonly - if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: nil, - }, - }) { - t.Fatalf("rdonly all cells add failed: %v", err) - } - - // add some cells for replica - if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, []string{"second"}, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: nil, - }, - { - TabletType: topodatapb.TabletType_REPLICA, - Cells: []string{"second"}, - }, - }) { - t.Fatalf("replica some cells add failed: %v", err) - } - - // remove some cells for rdonly - if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: []string{"first", "third"}, - }, - { - TabletType: topodatapb.TabletType_REPLICA, - Cells: []string{"second"}, - }, - }) { - t.Fatalf("remove some cells for rdonly failed: %v", err) - } - - // remove last cell for replica - if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: []string{"first", "third"}, - }, - }) { - t.Fatalf("remove last cell for replica failed: %v", err) - } - - // Migrate each serving type (add it to this shard). - // REPLICA - if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: []string{"first", "third"}, - }, - { - TabletType: topodatapb.TabletType_REPLICA, - Cells: nil, - }, - }) { - t.Fatalf("migrate replica failed: %v", err) - } - // RDONLY - if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: nil, - }, - { - TabletType: topodatapb.TabletType_REPLICA, - Cells: nil, - }, - }) { - t.Fatalf("migrate rdonly failed: %v", err) - } - // MASTER - if err := si.UpdateServedTypesMap(topodatapb.TabletType_MASTER, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ - { - TabletType: topodatapb.TabletType_RDONLY, - Cells: nil, - }, - { - TabletType: topodatapb.TabletType_REPLICA, - Cells: nil, - }, - { - TabletType: topodatapb.TabletType_MASTER, - Cells: nil, - }, - }) { - t.Fatalf("migrate master failed: %v", err) - } - - // Migrate each serving type away from this shard. - // RDONLY - if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, true); err != nil { - t.Fatalf("remove master failed: %v", err) - } - // REPLICA - if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, nil, true); err != nil { - t.Fatalf("remove master failed: %v", err) - } - // MASTER - if err := si.UpdateServedTypesMap(topodatapb.TabletType_MASTER, nil, true); err != nil { - t.Fatalf("remove master failed: %v", err) - } - if len(si.ServedTypes) != 0 { - t.Fatalf("expected empty map after removing all") - } -} +// func TestUpdateServedTypesMap(t *testing.T) { +// si := NewShardInfo("ks", "sh", &topodatapb.Shard{ +// Cells: []string{"first", "second", "third"}, +// }, nil) + +// // add all cells for rdonly +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ +// { +// TabletType: topodatapb.TabletType_RDONLY, +// Cells: nil, +// }, +// }) { +// t.Fatalf("rdonly all cells add failed: %v", err) +// } + +// // add some cells for replica +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, []string{"second"}, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ +// { +// TabletType: topodatapb.TabletType_RDONLY, +// Cells: nil, +// }, +// { +// TabletType: topodatapb.TabletType_REPLICA, +// Cells: []string{"second"}, +// }, +// }) { +// t.Fatalf("replica some cells add failed: %v", err) +// } + +// // remove some cells for rdonly +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ +// { +// TabletType: topodatapb.TabletType_RDONLY, +// Cells: []string{"first", "third"}, +// }, +// { +// TabletType: topodatapb.TabletType_REPLICA, +// Cells: []string{"second"}, +// }, +// }) { +// t.Fatalf("remove some cells for rdonly failed: %v", err) +// } + +// // remove last cell for replica +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ +// { +// TabletType: topodatapb.TabletType_RDONLY, +// Cells: []string{"first", "third"}, +// }, +// }) { +// t.Fatalf("remove last cell for replica failed: %v", err) +// } + +// // Migrate each serving type (add it to this shard). +// // REPLICA +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ +// { +// TabletType: topodatapb.TabletType_RDONLY, +// Cells: []string{"first", "third"}, +// }, +// { +// TabletType: topodatapb.TabletType_REPLICA, +// Cells: nil, +// }, +// }) { +// t.Fatalf("migrate replica failed: %v", err) +// } +// // RDONLY +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ +// { +// TabletType: topodatapb.TabletType_RDONLY, +// Cells: nil, +// }, +// { +// TabletType: topodatapb.TabletType_REPLICA, +// Cells: nil, +// }, +// }) { +// t.Fatalf("migrate rdonly failed: %v", err) +// } +// // MASTER +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_MASTER, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ +// { +// TabletType: topodatapb.TabletType_RDONLY, +// Cells: nil, +// }, +// { +// TabletType: topodatapb.TabletType_REPLICA, +// Cells: nil, +// }, +// { +// TabletType: topodatapb.TabletType_MASTER, +// Cells: nil, +// }, +// }) { +// t.Fatalf("migrate master failed: %v", err) +// } + +// // Migrate each serving type away from this shard. +// // RDONLY +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, true); err != nil { +// t.Fatalf("remove master failed: %v", err) +// } +// // REPLICA +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, nil, true); err != nil { +// t.Fatalf("remove master failed: %v", err) +// } +// // MASTER +// if err := si.UpdateServedTypesMap(topodatapb.TabletType_MASTER, nil, true); err != nil { +// t.Fatalf("remove master failed: %v", err) +// } +// if len(si.ServedTypes) != 0 { +// t.Fatalf("expected empty map after removing all") +// } +// } diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index 3bbdab8f7a3..efef1aabe7b 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -1071,6 +1071,15 @@ func (wr *Wrangler) replicaMigrateServedFrom(ctx context.Context, ki *topo.Keysp return err } + // The caller intents to update all cells in this case + var err error + if len(cells) == 0 { + cells, err = wr.ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + } + // Save the source shard (its blacklisted tables field has changed) event.DispatchUpdate(ev, "updating source shard") if _, err := wr.ts.UpdateShardFields(ctx, sourceShard.Keyspace(), sourceShard.ShardName(), func(si *topo.ShardInfo) error { @@ -1108,10 +1117,16 @@ func (wr *Wrangler) masterMigrateServedFrom(ctx context.Context, ki *topo.Keyspa return err } + // The caller intents to update all cells in this case + cells, err := wr.ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + // Update source shard (more blacklisted tables) event.DispatchUpdate(ev, "updating source shard") if _, err := wr.ts.UpdateShardFields(ctx, sourceShard.Keyspace(), sourceShard.ShardName(), func(si *topo.ShardInfo) error { - return si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_MASTER, nil, false, tables) + return si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_MASTER, cells, false, tables) }); err != nil { return err } From b4271d4e78aa0a5ffb956769d1121ad19609dff6 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Feb 2019 14:57:49 -0800 Subject: [PATCH 040/196] Update cell_info test due to refactor Signed-off-by: Rafael Chacon --- go/vt/topo/cell_info.go | 15 +++++++++------ go/vt/topo/server.go | 13 +++++++++---- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/go/vt/topo/cell_info.go b/go/vt/topo/cell_info.go index 946e0c8b4d5..0906dba8960 100644 --- a/go/vt/topo/cell_info.go +++ b/go/vt/topo/cell_info.go @@ -137,15 +137,18 @@ func (ts *Server) UpdateCellInfoFields(ctx context.Context, cell string, update // We first make sure no Shard record points to the cell. func (ts *Server) DeleteCellInfo(ctx context.Context, cell string) error { srvKeyspaces, err := ts.GetSrvKeyspaceNames(ctx, cell) - if err != nil { + switch { + case err == nil: + if len(srvKeyspaces) != 0 { + // TODO @rafael - implement this function and expose it via a vtctld command + return fmt.Errorf("cell %v has serving keyspaces. Before deleting, delete serving keyspace with: DeleteSrvKeyspaces", cell) + } + case IsErrType(err, NoNode): + // Nothing to do. + default: return fmt.Errorf("GetSrvKeyspaceNames() failed: %v", err) } - if len(srvKeyspaces) != 0 { - // TODO @rafael - implement this function and expose it via a vtctld command - return fmt.Errorf("cell %v has serving keyspaces. Before deleting, delete serving keyspace with: DeleteSrvKeyspaces", cell) - } - filePath := pathForCellInfo(cell) return ts.globalCell.Delete(ctx, filePath, nil) } diff --git a/go/vt/topo/server.go b/go/vt/topo/server.go index 6c4a07a2483..eb317f62ab1 100644 --- a/go/vt/topo/server.go +++ b/go/vt/topo/server.go @@ -257,12 +257,17 @@ func (ts *Server) ConnForCell(ctx context.Context, cell string) (Conn, error) { // Create the connection. conn, err = ts.factory.Create(cell, ci.ServerAddress, ci.Root) - if err != nil { + switch { + case err == nil: + conn = NewStatsConn(cell, conn) + ts.cells[cell] = conn + return conn, nil + case IsErrType(err, NoNode): + err = fmt.Errorf("failed to create topo connection to %v, %v: %v", ci.ServerAddress, ci.Root, err) + return nil, NewError(NoNode, err.Error()) + default: return nil, fmt.Errorf("failed to create topo connection to %v, %v: %v", ci.ServerAddress, ci.Root, err) } - conn = NewStatsConn(cell, conn) - ts.cells[cell] = conn - return conn, nil } // GetRegionByCell returns the region group this `cell` belongs to, if there's none, it returns the `cell` as region. From 0612020020299886bb9a5b04cd07d4341a825a35 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Feb 2019 15:50:13 -0800 Subject: [PATCH 041/196] Update vtctld tests Signed-off-by: Rafael Chacon --- go/vt/vtctld/api_test.go | 17 +++-------------- go/vt/vtctld/explorer_test.go | 4 +--- 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/go/vt/vtctld/api_test.go b/go/vt/vtctld/api_test.go index b217500ebd7..31f2739b277 100644 --- a/go/vt/vtctld/api_test.go +++ b/go/vt/vtctld/api_test.go @@ -27,7 +27,6 @@ import ( "golang.org/x/net/context" - "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" "vitess.io/vitess/go/vt/wrangler" @@ -51,17 +50,8 @@ func TestAPI(t *testing.T) { // Populate topo. Remove ServedTypes from shards to avoid ordering issues. ts.CreateKeyspace(ctx, "ks1", &topodatapb.Keyspace{ShardingColumnName: "shardcol"}) ts.CreateShard(ctx, "ks1", "-80") - ts.UpdateShardFields(ctx, "ks1", "-80", func(si *topo.ShardInfo) error { - si.Shard.Cells = cells - si.Shard.ServedTypes = nil - return nil - }) + ts.CreateShard(ctx, "ks1", "80-") - ts.UpdateShardFields(ctx, "ks1", "80-", func(si *topo.ShardInfo) error { - si.Shard.Cells = cells - si.Shard.ServedTypes = nil - return nil - }) tablet1 := topodatapb.Tablet{ Alias: &topodatapb.TabletAlias{Cell: "cell1", Uid: 100}, @@ -145,10 +135,9 @@ func TestAPI(t *testing.T) { "start": null, "end":"gA==" }, - "served_types": [], "source_shards": [], - "cells": ["cell1", "cell2"], - "tablet_controls": [] + "tablet_controls": [], + "is_master_serving": true }`}, {"GET", "shards/ks1/-DEAD", "", "404 page not found"}, {"POST", "shards/ks1/-80?action=TestShardAction", "", `{ diff --git a/go/vt/vtctld/explorer_test.go b/go/vt/vtctld/explorer_test.go index c2d77788ad1..3ecb0633d75 100644 --- a/go/vt/vtctld/explorer_test.go +++ b/go/vt/vtctld/explorer_test.go @@ -141,7 +141,7 @@ func TestHandlePathShard(t *testing.T) { input := path.Join("/global", "keyspaces", "test_keyspace", "shards", "-80", "Shard") cells := []string{"cell1", "cell2", "cell3"} keyspace := &topodatapb.Keyspace{} - want := "cells: \"cell1\"\ncells: \"cell2\"\ncells: \"cell3\"\n" + want := "is_master_serving: true\n" ctx := context.Background() ts := memorytopo.NewServer(cells...) @@ -153,8 +153,6 @@ func TestHandlePathShard(t *testing.T) { } if _, err := ts.UpdateShardFields(ctx, "test_keyspace", "-80", func(si *topo.ShardInfo) error { // Set cells, reset other fields so printout is easier to compare. - si.Shard.Cells = cells - si.ServedTypes = nil si.KeyRange = nil return nil }); err != nil { From 10df1d9dd4c8ccbc1d7afc008094a9fc24268a1e Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Feb 2019 16:45:40 -0800 Subject: [PATCH 042/196] Updates tabletmanager tests Signed-off-by: Rafael Chacon --- .../tabletmanager/healthcheck_test.go | 37 ++++++++++++------- .../tabletmanager/init_tablet_test.go | 21 +++++++++-- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/go/vt/vttablet/tabletmanager/healthcheck_test.go b/go/vt/vttablet/tabletmanager/healthcheck_test.go index 2084bd283a7..c5456080f7c 100644 --- a/go/vt/vttablet/tabletmanager/healthcheck_test.go +++ b/go/vt/vttablet/tabletmanager/healthcheck_test.go @@ -28,10 +28,12 @@ import ( "golang.org/x/net/context" "vitess.io/vitess/go/vt/health" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl/fakemysqldaemon" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" "vitess.io/vitess/go/vt/topo/topoproto" + "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/vttablet/tabletserver" "vitess.io/vitess/go/vt/vttablet/tabletservermock" @@ -524,15 +526,25 @@ func TestTabletControl(t *testing.T) { } // now update the shard - _, err = agent.TopoServer.UpdateShardFields(ctx, "test_keyspace", "0", func(si *topo.ShardInfo) error { - si.TabletControls = []*topodatapb.Shard_TabletControl{ - { - TabletType: topodatapb.TabletType_REPLICA, - DisableQueryService: true, - }, - } - return nil - }) + + si, err := agent.TopoServer.GetShard(ctx, "test_keyspace", "0") + if err != nil { + t.Fatalf("GetShard failed: %v", err) + } + + ctx, unlock, lockErr := agent.TopoServer.LockKeyspace(ctx, "test_keyspace", "UpdateDisableQueryService") + if lockErr != nil { + t.Fatalf("Couldn't lock keyspace for test") + } + defer unlock(&err) + + // Let's generate the keyspace graph we have partition information for this cell + err = topotools.RebuildKeyspaceLocked(ctx, logutil.NewConsoleLogger(), agent.TopoServer, "test_keyspace", []string{agent.TabletAlias.GetCell()}) + if err != nil { + t.Fatalf("RebuildKeyspaceLocked failed: %v", err) + } + + err = agent.TopoServer.UpdateDisableQueryService(ctx, "test_keyspace", []*topo.ShardInfo{si}, topodatapb.TabletType_REPLICA, nil, true) if err != nil { t.Fatalf("UpdateShardFields failed: %v", err) } @@ -647,12 +659,9 @@ func TestTabletControl(t *testing.T) { // now clear TabletControl, run health check, make sure we go // back healthy and serving. - _, err = agent.TopoServer.UpdateShardFields(ctx, "test_keyspace", "0", func(si *topo.ShardInfo) error { - si.TabletControls = nil - return nil - }) + err = agent.TopoServer.UpdateDisableQueryService(ctx, "test_keyspace", []*topo.ShardInfo{si}, topodatapb.TabletType_REPLICA, nil, false) if err != nil { - t.Fatalf("UpdateShardFields failed: %v", err) + t.Fatalf("UpdateDisableQueryService failed: %v", err) } // now refresh the tablet state, as the resharding process would do diff --git a/go/vt/vttablet/tabletmanager/init_tablet_test.go b/go/vt/vttablet/tabletmanager/init_tablet_test.go index 1171474637e..dbf23e17797 100644 --- a/go/vt/vttablet/tabletmanager/init_tablet_test.go +++ b/go/vt/vttablet/tabletmanager/init_tablet_test.go @@ -156,7 +156,7 @@ func TestInitTabletDoesNotUpdateReplicationDataForTabletInWrongShard(t *testing. t.Fatalf("InitTablet(type) should have failed, got nil") } - if _, err = ts.FindAllTabletAliasesInShard(ctx, "test_keyspace", "-d0"); err == nil { + if tablets, _ := ts.FindAllTabletAliasesInShard(ctx, "test_keyspace", "-d0"); len(tablets) != 0 { t.Fatalf("Tablet shouldn't be added to replication data") } } @@ -214,6 +214,15 @@ func TestInitTablet(t *testing.T) { Cell: "cell1", Uid: 2, } + + _, err := agent.TopoServer.GetSrvKeyspace(ctx, "cell1", "test_keyspace") + switch { + case topo.IsErrType(err, topo.NoNode): + // srvKeyspace should not be when tablets haven't been registered to this cell + default: + t.Fatalf("GetSrvKeyspace failed: %v", err) + } + agent.TabletAlias = tabletAlias if err := agent.InitTablet(port, gRPCPort); err != nil { t.Fatalf("InitTablet(type) failed: %v", err) @@ -222,9 +231,15 @@ func TestInitTablet(t *testing.T) { if err != nil { t.Fatalf("GetShard failed: %v", err) } - if len(si.Cells) != 1 || si.Cells[0] != "cell1" { - t.Errorf("shard.Cells not updated properly: %v", si) + + _, err = agent.TopoServer.GetSrvKeyspace(ctx, "cell1", "test_keyspace") + switch { + case err != nil: + // srvKeyspace should not be when tablets haven't been registered to this cell + default: + t.Errorf("Serving keyspace was not generated for cell: %v", si) } + ti, err := ts.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) From 6683b34f3f6ace515360832ce695707b5fb5a8d4 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Feb 2019 17:43:10 -0800 Subject: [PATCH 043/196] Fix some bugs that were surfaced by migrate served types tests Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 127 ++++++++++-------- go/vt/wrangler/keyspace.go | 17 +-- .../testlib/migrate_served_from_test.go | 7 +- .../testlib/migrate_served_types_test.go | 16 ++- .../testlib/reparent_external_test.go | 12 -- 5 files changed, 87 insertions(+), 92 deletions(-) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index d0944062422..e57ac94f678 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -316,41 +316,44 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string go func(cell string) { defer wg.Done() srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) - if err != nil { - rec.RecordError(err) - return - } - for _, partition := range srvKeyspace.GetPartitions() { - if partition.GetServedType() != tabletType { - continue - } + switch { + case err == nil: + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } - for _, si := range shards { - found := false - for _, tabletControl := range partition.GetShardTabletControls() { - if tabletControl.GetName() == si.ShardName() { - found = true - tabletControl.QueryServiceDisabled = disableQueryService + for _, si := range shards { + found := false + for _, tabletControl := range partition.GetShardTabletControls() { + if tabletControl.GetName() == si.ShardName() { + found = true + tabletControl.QueryServiceDisabled = disableQueryService + } } - } - if !found { - shardTabletControl := &topodatapb.ShardTabletControl{ - Name: si.ShardName(), - KeyRange: si.KeyRange, - QueryServiceDisabled: disableQueryService, + if !found { + shardTabletControl := &topodatapb.ShardTabletControl{ + Name: si.ShardName(), + KeyRange: si.KeyRange, + QueryServiceDisabled: disableQueryService, + } + partition.ShardTabletControls = append(partition.GetShardTabletControls(), shardTabletControl) } - partition.ShardTabletControls = append(partition.GetShardTabletControls(), shardTabletControl) } } - } - err = ts.UpdateSrvKeyspace(ctx, cell, keyspace, srvKeyspace) - if err != nil { + err = ts.UpdateSrvKeyspace(ctx, cell, keyspace, srvKeyspace) + if err != nil { + rec.RecordError(err) + return + } + case IsErrType(err, NoNode): + // NOOP + default: rec.RecordError(err) return } - }(cell) } wg.Wait() @@ -381,52 +384,58 @@ func (ts *Server) MigrateServedType(ctx context.Context, keyspace string, shards go func(cell, keyspace string) { defer wg.Done() srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) - if err != nil { - rec.RecordError(err) - return - } - for _, partition := range srvKeyspace.GetPartitions() { + switch { + case err == nil: + for _, partition := range srvKeyspace.GetPartitions() { - // We are finishing the migration, cleaning up tablet controls from the srvKeyspace - if tabletType == topodatapb.TabletType_MASTER { - partition.ShardTabletControls = nil - } + // We are finishing the migration, cleaning up tablet controls from the srvKeyspace + if tabletType == topodatapb.TabletType_MASTER { + partition.ShardTabletControls = nil + } - if partition.GetServedType() != tabletType { - continue - } + if partition.GetServedType() != tabletType { + continue + } - shardReferences := partition.GetShardReferences()[:0] - for _, si := range shardsToRemove { - for _, shardReference := range shardReferences { - if shardReference.GetName() != si.ShardName() { - shardReferences = append(shardReferences, shardReference) + shardReferences := partition.GetShardReferences()[:0] + for _, si := range shardsToRemove { + for _, shardReference := range shardReferences { + if shardReference.GetName() != si.ShardName() { + shardReferences = append(shardReferences, shardReference) + } } } - } - for _, si := range shardsToAdd { - shardReference := &topodatapb.ShardReference{ - Name: si.ShardName(), - KeyRange: si.KeyRange, + for _, si := range shardsToAdd { + shardReference := &topodatapb.ShardReference{ + Name: si.ShardName(), + KeyRange: si.KeyRange, + } + shardReferences = append(shardReferences, shardReference) } - shardReferences = append(shardReferences, shardReference) + + partition.ShardReferences = shardReferences } - partition.ShardReferences = shardReferences - } + if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { + rec.RecordError(err) + return + } - if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { - rec.RecordError(err) - return - } + err = ts.UpdateSrvKeyspace(ctx, cell, keyspace, srvKeyspace) + if err != nil { + rec.RecordError(err) + return + } - err = ts.UpdateSrvKeyspace(ctx, cell, keyspace, srvKeyspace) - if err != nil { - rec.RecordError(err) - return + case IsErrType(err, NoNode): + // Assuming this cell is not active, nothing to do. + default: + if err != nil { + rec.RecordError(err) + return + } } - }(cell, keyspace) } wg.Wait() diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index efef1aabe7b..3bbdab8f7a3 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -1071,15 +1071,6 @@ func (wr *Wrangler) replicaMigrateServedFrom(ctx context.Context, ki *topo.Keysp return err } - // The caller intents to update all cells in this case - var err error - if len(cells) == 0 { - cells, err = wr.ts.GetCellInfoNames(ctx) - if err != nil { - return err - } - } - // Save the source shard (its blacklisted tables field has changed) event.DispatchUpdate(ev, "updating source shard") if _, err := wr.ts.UpdateShardFields(ctx, sourceShard.Keyspace(), sourceShard.ShardName(), func(si *topo.ShardInfo) error { @@ -1117,16 +1108,10 @@ func (wr *Wrangler) masterMigrateServedFrom(ctx context.Context, ki *topo.Keyspa return err } - // The caller intents to update all cells in this case - cells, err := wr.ts.GetCellInfoNames(ctx) - if err != nil { - return err - } - // Update source shard (more blacklisted tables) event.DispatchUpdate(ev, "updating source shard") if _, err := wr.ts.UpdateShardFields(ctx, sourceShard.Keyspace(), sourceShard.ShardName(), func(si *topo.ShardInfo) error { - return si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_MASTER, cells, false, tables) + return si.UpdateSourceBlacklistedTables(ctx, topodatapb.TabletType_MASTER, nil, false, tables) }); err != nil { return err } diff --git a/go/vt/wrangler/testlib/migrate_served_from_test.go b/go/vt/wrangler/testlib/migrate_served_from_test.go index 303e820e5b5..bcf5fda6359 100644 --- a/go/vt/wrangler/testlib/migrate_served_from_test.go +++ b/go/vt/wrangler/testlib/migrate_served_from_test.go @@ -144,13 +144,14 @@ func TestMigrateServedFrom(t *testing.T) { if err != nil { t.Fatalf("GetShard failed: %v", err) } - if len(si.TabletControls) != 1 || !reflect.DeepEqual(si.TabletControls, []*topodatapb.Shard_TabletControl{ + expected := []*topodatapb.Shard_TabletControl{ { TabletType: topodatapb.TabletType_RDONLY, BlacklistedTables: []string{"gone1", "gone2"}, }, - }) { - t.Fatalf("rdonly type doesn't have right blacklisted tables") + } + if len(si.TabletControls) != 1 || !reflect.DeepEqual(si.TabletControls, expected) { + t.Fatalf("rdonly type doesn't have right blacklisted tables. Expected: %v, got: %v", expected, si.TabletControls) } // migrate replica over diff --git a/go/vt/wrangler/testlib/migrate_served_types_test.go b/go/vt/wrangler/testlib/migrate_served_types_test.go index e0e8b849420..96669177f7a 100644 --- a/go/vt/wrangler/testlib/migrate_served_types_test.go +++ b/go/vt/wrangler/testlib/migrate_served_types_test.go @@ -29,6 +29,7 @@ import ( "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/vttablet/tabletmanager/vreplication" "vitess.io/vitess/go/vt/vttablet/tmclient" "vitess.io/vitess/go/vt/wrangler" @@ -42,8 +43,14 @@ func checkShardServedTypes(t *testing.T, ts *topo.Server, shard string, expected if err != nil { t.Fatalf("GetShard failed: %v", err) } - if len(si.ServedTypes) != expected { - t.Fatalf("shard %v has wrong served types: %#v", shard, si.ServedTypes) + + servedTypes, err := ts.GetShardServingTypes(ctx, si) + if err != nil { + t.Fatalf("GetShard failed: %v", err) + } + + if len(servedTypes) != expected { + t.Fatalf("shard %v has wrong served types: got: %v, expected: %v", shard, len(servedTypes), expected) } } @@ -100,6 +107,11 @@ func TestMigrateServedTypes(t *testing.T) { dest2Rdonly := NewFakeTablet(t, wr, "cell1", 32, topodatapb.TabletType_RDONLY, nil, TabletKeyspaceShard(t, "ks", "80-")) + // Build keyspace graph + err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, "ks", []string{"cell1"}) + if err != nil { + t.Fatalf("RebuildKeyspaceLocked failed: %v", err) + } // double check the shards have the right served types checkShardServedTypes(t, ts, "0", 3) checkShardServedTypes(t, ts, "-80", 0) diff --git a/go/vt/wrangler/testlib/reparent_external_test.go b/go/vt/wrangler/testlib/reparent_external_test.go index 30ab319d053..c5a36675946 100644 --- a/go/vt/wrangler/testlib/reparent_external_test.go +++ b/go/vt/wrangler/testlib/reparent_external_test.go @@ -54,18 +54,6 @@ func TestTabletExternallyReparented(t *testing.T) { goodSlave2 := NewFakeTablet(t, wr, "cell2", 3, topodatapb.TabletType_REPLICA, nil) badSlave := NewFakeTablet(t, wr, "cell1", 4, topodatapb.TabletType_REPLICA, nil) - // Add a new Cell to the Shard, that doesn't map to any read topo cell, - // to simulate a data center being unreachable. - _, err := ts.UpdateShardFields(ctx, "test_keyspace", "0", func(si *topo.ShardInfo) error { - if !si.HasCell("cell666") { - si.Cells = append(si.Cells, "cell666") - } - return nil - }) - if err != nil { - t.Fatalf("UpdateShardFields failed: %v", err) - } - // Slightly unrelated test: make sure we can find the tablets // even with a datacenter being down. tabletMap, err := ts.GetTabletMapForShardByCell(ctx, "test_keyspace", "0", []string{"cell1"}) From 06cae331f6a9c093917ce3977c4ab5bab043969e Mon Sep 17 00:00:00 2001 From: David Weitzman Date: Mon, 4 Feb 2019 15:20:34 -0800 Subject: [PATCH 044/196] Eliminate flakiness for sync2.Batcher's unit test"> Signed-off-by: David Weitzman --- go/sync2/batcher.go | 16 +++++- go/sync2/batcher_flaky_test.go | 69 ---------------------- go/sync2/batcher_test.go | 101 +++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 70 deletions(-) delete mode 100644 go/sync2/batcher_flaky_test.go create mode 100644 go/sync2/batcher_test.go diff --git a/go/sync2/batcher.go b/go/sync2/batcher.go index 161531d927e..8e9e14434df 100644 --- a/go/sync2/batcher.go +++ b/go/sync2/batcher.go @@ -32,6 +32,7 @@ type Batcher struct { queue chan int waiters AtomicInt32 nextID AtomicInt32 + after func(time.Duration) <-chan time.Time } // NewBatcher returns a new Batcher @@ -41,6 +42,19 @@ func NewBatcher(interval time.Duration) *Batcher { queue: make(chan int), waiters: NewAtomicInt32(0), nextID: NewAtomicInt32(0), + after: time.After, + } +} + +// newBatcherForTest returns a Batcher for testing where time.After can +// be replaced by a fake alternative. +func newBatcherForTest(interval time.Duration, after func(time.Duration) <-chan time.Time) *Batcher { + return &Batcher{ + interval: interval, + queue: make(chan int), + waiters: NewAtomicInt32(0), + nextID: NewAtomicInt32(0), + after: after, } } @@ -56,7 +70,7 @@ func (b *Batcher) Wait() int { // newBatch starts a new batch func (b *Batcher) newBatch() { go func() { - time.Sleep(b.interval) + <-b.after(b.interval) id := b.nextID.Add(1) diff --git a/go/sync2/batcher_flaky_test.go b/go/sync2/batcher_flaky_test.go deleted file mode 100644 index 5fe89989c54..00000000000 --- a/go/sync2/batcher_flaky_test.go +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 agreedto 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 sync2 - -import ( - "testing" - "time" -) - -func expectBatch(testcase string, b *Batcher, want int, t *testing.T) { - id := b.Wait() - if id != want { - t.Errorf("%s: got %d, want %d", testcase, id, want) - } -} - -func TestBatcher(t *testing.T) { - interval := time.Duration(50 * time.Millisecond) - b := NewBatcher(interval) - - // test single waiter - go expectBatch("single waiter", b, 1, t) - time.Sleep(interval * 2) - - // multiple waiters all at once - go expectBatch("concurrent waiter", b, 2, t) - go expectBatch("concurrent waiter", b, 2, t) - go expectBatch("concurrent waiter", b, 2, t) - time.Sleep(interval * 2) - - // stagger the waiters out in time but cross two intervals - go expectBatch("staggered waiter", b, 3, t) - time.Sleep(interval / 5) - go expectBatch("staggered waiter", b, 3, t) - time.Sleep(interval / 5) - go expectBatch("staggered waiter", b, 3, t) - time.Sleep(interval / 5) - go expectBatch("staggered waiter", b, 3, t) - time.Sleep(interval / 5) - go expectBatch("staggered waiter", b, 3, t) - time.Sleep(interval / 5) - - go expectBatch("staggered waiter 2", b, 4, t) - time.Sleep(interval / 5) - go expectBatch("staggered waiter 2", b, 4, t) - time.Sleep(interval / 5) - go expectBatch("staggered waiter 2", b, 4, t) - time.Sleep(interval / 5) - go expectBatch("staggered waiter 2", b, 4, t) - time.Sleep(interval / 5) - go expectBatch("staggered waiter 2", b, 4, t) - time.Sleep(interval / 5) - - time.Sleep(interval * 2) -} diff --git a/go/sync2/batcher_test.go b/go/sync2/batcher_test.go new file mode 100644 index 00000000000..6e90c338507 --- /dev/null +++ b/go/sync2/batcher_test.go @@ -0,0 +1,101 @@ +/* +Copyright 2017 Google Inc. + +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 agreedto 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 sync2 + +import ( + "testing" + "time" +) + +// makeAfterFnWithLatch returns a fake alternative to time.After that blocks until +// the release function is called. The fake doesn't support having multiple concurrent +// calls to the After function, which is ok because Batcher should never do that. +func makeAfterFnWithLatch(t *testing.T) (func(time.Duration) <-chan time.Time, func()) { + latch := make(chan time.Time, 1) + afterFn := func(d time.Duration) <-chan time.Time { + return latch + } + + releaseFn := func() { + select { + case latch <- time.Now(): + default: + t.Errorf("Previous batch still hasn't been released") + } + } + return afterFn, releaseFn +} + +func TestBatcher(t *testing.T) { + interval := time.Duration(50 * time.Millisecond) + + afterFn, releaseBatch := makeAfterFnWithLatch(t) + b := newBatcherForTest(interval, afterFn) + + waitersFinished := NewAtomicInt32(0) + + startWaiter := func(testcase string, want int) { + go func() { + id := b.Wait() + if id != want { + t.Errorf("%s: got %d, want %d", testcase, id, want) + } + waitersFinished.Add(1) + }() + } + + awaitVal := func(name string, val *AtomicInt32, expected int32) { + for count := 0; val.Get() != expected; count++ { + time.Sleep(50 * time.Millisecond) + if count > 5 { + t.Errorf("Timed out waiting for %s to be %v", name, expected) + return + } + } + } + + awaitBatch := func(name string, n int32) { + // Wait for all the waiters to register + awaitVal("Batcher.waiters for "+name, &b.waiters, n) + // Release the batch and wait for the batcher to catch up. + if waitersFinished.Get() != 0 { + t.Errorf("Waiters finished before being released") + } + releaseBatch() + awaitVal("Batcher.waiters for "+name, &b.waiters, 0) + // Make sure the waiters actually run so they can verify their batch number. + awaitVal("waitersFinshed for "+name, &waitersFinished, n) + waitersFinished.Set(0) + } + + // test single waiter + startWaiter("single waiter", 1) + awaitBatch("single waiter", 1) + + // multiple waiters all at once + startWaiter("concurrent waiter", 2) + startWaiter("concurrent waiter", 2) + startWaiter("concurrent waiter", 2) + awaitBatch("concurrent waiter", 3) + + startWaiter("more waiters", 3) + startWaiter("more waiters", 3) + startWaiter("more waiters", 3) + startWaiter("more waiters", 3) + startWaiter("more waiters", 3) + awaitBatch("more waiters", 5) +} From 122617983b88264bd39979f285fab32a1eb2dccf Mon Sep 17 00:00:00 2001 From: zhoulin xie Date: Sun, 10 Feb 2019 18:18:32 +0800 Subject: [PATCH 045/196] Fix some typos in docs Signed-off-by: zhoulin xie --- doc/GettingStarted.md | 2 +- doc/meetups_notes/05-10-2018.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/GettingStarted.md b/doc/GettingStarted.md index f65f812a699..587156137a2 100644 --- a/doc/GettingStarted.md +++ b/doc/GettingStarted.md @@ -168,7 +168,7 @@ In addition, Vitess requires the software and libraries listed below. (install steps are below). 3. If Xcode is installed (with Console tools, which should be bundled automatically since the 7.1 version), all - the dev dependencies should be satisfied in this step. If no Xcode is present, it is necessery to install pkg-config. + the dev dependencies should be satisfied in this step. If no Xcode is present, it is necessary to install pkg-config. ``` sh brew install pkg-config diff --git a/doc/meetups_notes/05-10-2018.md b/doc/meetups_notes/05-10-2018.md index a9ad8677d05..4f9b0381055 100644 --- a/doc/meetups_notes/05-10-2018.md +++ b/doc/meetups_notes/05-10-2018.md @@ -33,7 +33,7 @@ * Should we require to add documentation for features as part of pull requests? - Not in the short term, it could discourage contributions from new comers. - - We should make easier for new comers to add documentation (add more structure and guidance in how to add documenation). + - We should make easier for new comers to add documentation (add more structure and guidance in how to add documentation). * We should be able to find a tech writer contractor that helps with editing / copy. * @zmagg knows tech writers that could help. They are remote. She will be making an intro to @jitten. * Some queries take a very long time without clear reason. From 3d8b48985a60e5cca5a658fedc0b3da3987468f2 Mon Sep 17 00:00:00 2001 From: kuba-- Date: Mon, 11 Feb 2019 16:53:13 +0100 Subject: [PATCH 046/196] Support bool as column type Signed-off-by: kuba-- --- go/vt/sqlparser/ast.go | 2 + go/vt/sqlparser/parse_test.go | 10 + go/vt/sqlparser/sql.go | 5627 ++++++++++++++++----------------- go/vt/sqlparser/sql.y | 9 + 4 files changed, 2834 insertions(+), 2814 deletions(-) diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index fa33181cc06..1fa69decebb 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -1170,6 +1170,8 @@ func (ct *ColumnType) SQLType() querypb.Type { return sqltypes.Uint64 } return sqltypes.Int64 + case keywordStrings[BOOL], keywordStrings[BOOLEAN]: + return sqltypes.Uint8 case keywordStrings[TEXT]: return sqltypes.Text case keywordStrings[TINYTEXT]: diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 4f4b29cbd88..1b71b1d85cd 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -966,6 +966,9 @@ var ( }, { input: "create table a (a int, b char, c garbage)", output: "create table a", + }, { + input: "create table a (b1 bool not null primary key, b2 boolean not null)", + output: "create table a (\n\tb1 bool not null primary key,\n\tb2 boolean not null\n)", }, { input: "alter vschema create vindex hash_vdx using hash", }, { @@ -2040,6 +2043,13 @@ func TestCreateTable(t *testing.T) { " stats_sample_pages 1,\n" + " tablespace tablespace_name storage disk,\n" + " tablespace tablespace_name\n", + + // boolean columns + "create table t (\n" + + " bi bigint not null primary key,\n" + + " b1 bool not null,\n" + + " b2 boolean\n" + + ")", } for _, sql := range validSQL { sql = strings.TrimSpace(sql) diff --git a/go/vt/sqlparser/sql.go b/go/vt/sqlparser/sql.go index c21cae51832..446f7e38514 100644 --- a/go/vt/sqlparser/sql.go +++ b/go/vt/sqlparser/sql.go @@ -640,1385 +640,1370 @@ var yyExca = [...]int{ 5, 29, -2, 4, -1, 37, - 159, 293, - 160, 293, - -2, 283, - -1, 267, - 112, 638, - -2, 634, + 159, 295, + 160, 295, + -2, 285, -1, 268, - 112, 639, - -2, 635, - -1, 333, - 82, 811, - -2, 60, + 112, 640, + -2, 636, + -1, 269, + 112, 641, + -2, 637, -1, 334, - 82, 768, + 82, 814, + -2, 60, + -1, 335, + 82, 771, -2, 61, - -1, 339, - 82, 747, - -2, 600, - -1, 341, - 82, 789, + -1, 340, + 82, 750, -2, 602, - -1, 610, - 1, 345, - 5, 345, - 12, 345, - 13, 345, - 14, 345, - 15, 345, - 17, 345, - 19, 345, - 30, 345, - 31, 345, - 42, 345, - 43, 345, - 44, 345, - 45, 345, - 46, 345, - 48, 345, - 49, 345, - 52, 345, - 53, 345, - 55, 345, - 56, 345, - 268, 345, - -2, 363, - -1, 613, + -1, 342, + 82, 792, + -2, 604, + -1, 611, + 1, 347, + 5, 347, + 12, 347, + 13, 347, + 14, 347, + 15, 347, + 17, 347, + 19, 347, + 30, 347, + 31, 347, + 42, 347, + 43, 347, + 44, 347, + 45, 347, + 46, 347, + 48, 347, + 49, 347, + 52, 347, + 53, 347, + 55, 347, + 56, 347, + 268, 347, + -2, 365, + -1, 614, 53, 43, 55, 43, -2, 45, - -1, 753, - 112, 641, - -2, 637, - -1, 974, + -1, 756, + 112, 643, + -2, 639, + -1, 977, 5, 30, - -2, 429, - -1, 1006, + -2, 431, + -1, 1009, 5, 29, - -2, 574, - -1, 1258, + -2, 576, + -1, 1261, 5, 30, - -2, 575, - -1, 1314, - 5, 29, -2, 577, - -1, 1395, + -1, 1317, + 5, 29, + -2, 579, + -1, 1398, 5, 30, - -2, 578, + -2, 580, } const yyPrivate = 57344 -const yyLast = 12925 +const yyLast = 12766 var yyAct = [...]int{ - 268, 1419, 1213, 1429, 1098, 1383, 272, 1009, 1291, 1326, - 860, 1027, 566, 298, 1153, 470, 1187, 837, 1154, 57, - 285, 856, 1010, 246, 1150, 1052, 835, 903, 939, 1278, - 565, 3, 81, 1033, 859, 1160, 208, 869, 1166, 208, - 1121, 237, 778, 338, 788, 718, 1069, 1078, 623, 966, - 873, 839, 824, 806, 498, 504, 785, 755, 607, 622, - 332, 606, 439, 817, 510, 518, 899, 208, 81, 270, - 948, 327, 208, 255, 208, 329, 56, 581, 1422, 1406, - 1417, 1393, 245, 335, 1414, 1214, 238, 239, 240, 241, - 1405, 1143, 244, 1392, 1250, 444, 1182, 1183, 624, 580, - 625, 922, 472, 203, 199, 200, 201, 1040, 259, 1181, - 1039, 61, 850, 1041, 492, 921, 851, 852, 243, 242, - 889, 1358, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 1060, 882, 542, 63, 64, 65, - 66, 67, 310, 926, 316, 317, 314, 315, 313, 312, - 311, 1281, 920, 488, 457, 195, 1297, 197, 318, 319, - 890, 489, 486, 487, 1233, 1231, 236, 1101, 474, 1100, - 476, 1416, 491, 481, 482, 1122, 693, 691, 468, 1413, - 1376, 1433, 1384, 1097, 787, 218, 818, 874, 458, 1437, - 446, 197, 1102, 1028, 1030, 1335, 208, 697, 684, 208, - 473, 475, 917, 914, 915, 208, 913, 1085, 1176, 231, - 692, 208, 1124, 1327, 81, 1175, 81, 1174, 81, 81, - 442, 81, 876, 81, 202, 876, 1329, 694, 449, 210, - 198, 933, 81, 1365, 932, 1261, 1083, 924, 927, 876, - 1094, 554, 555, 1108, 984, 1126, 1096, 1130, 960, 1125, - 196, 1123, 727, 522, 1053, 857, 1128, 464, 883, 517, - 211, 532, 81, 1199, 542, 1127, 542, 214, 440, 506, - 1029, 730, 731, 919, 719, 222, 217, 724, 1129, 1131, - 1374, 1344, 507, 979, 494, 495, 890, 1431, 471, 1164, - 1432, 440, 1430, 1359, 1328, 918, 1336, 1334, 516, 515, - 454, 626, 1145, 1084, 274, 1147, 1391, 220, 1089, 1086, - 1079, 1087, 1082, 230, 1200, 517, 1080, 1081, 875, 516, - 515, 875, 941, 807, 438, 208, 208, 208, 686, 1399, - 1088, 81, 1058, 516, 515, 875, 517, 81, 923, 212, - 872, 870, 1095, 871, 1093, 762, 335, 1379, 868, 874, - 517, 70, 605, 925, 1397, 720, 460, 461, 462, 760, - 761, 759, 515, 451, 508, 452, 224, 215, 453, 225, - 226, 227, 229, 512, 228, 234, 445, 1287, 517, 216, - 219, 1286, 213, 233, 232, 516, 515, 71, 1073, 584, - 586, 1438, 590, 592, 477, 595, 478, 479, 614, 480, - 940, 483, 517, 879, 1072, 807, 620, 993, 1061, 880, - 493, 583, 585, 587, 589, 591, 593, 594, 531, 530, - 540, 541, 533, 534, 535, 536, 537, 538, 539, 532, - 1439, 1375, 542, 535, 536, 537, 538, 539, 532, 208, - 779, 542, 780, 978, 81, 977, 745, 747, 748, 208, - 208, 81, 746, 447, 448, 208, 194, 1253, 208, 54, - 1308, 208, 516, 515, 1042, 208, 1043, 81, 81, 758, - 726, 967, 81, 81, 81, 81, 81, 81, 1284, 517, - 22, 1105, 81, 81, 533, 534, 535, 536, 537, 538, - 539, 532, 299, 51, 542, 531, 530, 540, 541, 533, - 534, 535, 536, 537, 538, 539, 532, 725, 706, 542, - 81, 957, 958, 959, 208, 1070, 1332, 1415, 497, 297, - 81, 324, 325, 1372, 516, 515, 1401, 497, 1341, 698, - 732, 1332, 1387, 1332, 497, 704, 1332, 1366, 752, 756, - 250, 517, 1332, 1331, 51, 1276, 1275, 1263, 497, 1260, - 497, 79, 251, 540, 541, 533, 534, 535, 536, 537, - 538, 539, 532, 1216, 81, 542, 753, 288, 287, 290, - 291, 292, 293, 1053, 552, 1048, 289, 294, 1206, 1205, - 797, 801, 734, 1202, 1203, 749, 808, 337, 1202, 1201, - 972, 497, 1340, 751, 821, 497, 1196, 81, 81, 792, - 790, 497, 1163, 781, 208, 703, 702, 687, 685, 682, - 24, 466, 208, 208, 633, 632, 208, 208, 459, 1034, - 81, 877, 683, 58, 782, 783, 1246, 497, 790, 690, - 610, 24, 1111, 81, 1004, 335, 1151, 1256, 1005, 1163, - 617, 804, 845, 1343, 1034, 707, 708, 988, 861, 821, - 709, 710, 711, 712, 713, 714, 814, 1204, 54, 1313, - 715, 716, 821, 972, 531, 530, 540, 541, 533, 534, - 535, 536, 537, 538, 539, 532, 972, 843, 542, 54, - 847, 848, 618, 986, 616, 208, 81, 1163, 81, 820, - 983, 987, 81, 81, 208, 208, 864, 208, 208, 1044, - 24, 208, 81, 981, 849, 844, 469, 616, 469, 905, - 469, 469, 998, 469, 821, 469, 997, 972, 208, 616, - 208, 208, 619, 208, 469, 728, 696, 985, 252, 54, - 1407, 1293, 884, 337, 982, 337, 1268, 337, 337, 904, - 337, 1192, 337, 752, 51, 901, 902, 980, 54, 1167, - 1168, 337, 1047, 900, 793, 794, 895, 894, 1099, 551, - 803, 907, 553, 1424, 1420, 1194, 1170, 1151, 891, 892, - 893, 753, 1074, 756, 1021, 722, 54, 700, 740, 1022, - 1173, 520, 1172, 813, 949, 815, 816, 950, 1018, 1017, - 564, 809, 568, 569, 570, 571, 572, 573, 574, 575, - 576, 1411, 579, 582, 582, 582, 588, 582, 582, 588, - 582, 596, 597, 598, 599, 600, 601, 962, 611, 256, - 257, 1404, 208, 208, 208, 208, 208, 1011, 1019, 1023, - 757, 830, 831, 1020, 208, 1107, 945, 208, 1409, 955, - 954, 208, 1065, 631, 467, 208, 1057, 1381, 1006, 1380, - 337, 826, 829, 830, 831, 827, 628, 828, 832, 992, - 81, 1167, 1168, 511, 909, 499, 911, 792, 1311, 1055, - 1045, 1035, 1049, 834, 1254, 861, 1289, 500, 509, 1036, - 937, 1013, 1014, 1012, 1016, 1024, 1015, 826, 829, 830, - 831, 827, 1032, 828, 832, 910, 699, 511, 1037, 1054, - 247, 885, 886, 887, 888, 253, 254, 1348, 81, 81, - 248, 1064, 58, 1066, 1067, 1068, 610, 896, 897, 898, - 610, 1347, 1050, 1051, 956, 530, 540, 541, 533, 534, - 535, 536, 537, 538, 539, 532, 469, 81, 542, 953, - 1295, 1034, 1071, 469, 490, 1426, 1425, 952, 717, 513, - 1426, 1362, 208, 1282, 1077, 723, 60, 62, 615, 469, - 469, 81, 1090, 337, 469, 469, 469, 469, 469, 469, - 337, 971, 55, 1, 469, 469, 1113, 1418, 1215, 1290, - 916, 1382, 1325, 1186, 1104, 867, 337, 337, 858, 990, - 69, 337, 337, 337, 337, 337, 337, 437, 68, 1373, - 1138, 337, 337, 866, 265, 865, 1062, 1063, 81, 81, - 1144, 1011, 1152, 1115, 1333, 1280, 878, 1120, 1114, 1155, - 1133, 1132, 1059, 881, 1193, 1056, 1378, 639, 753, 736, - 637, 638, 81, 636, 641, 640, 635, 496, 1157, 520, - 221, 330, 337, 1162, 833, 81, 51, 81, 81, 627, - 906, 514, 72, 1178, 1171, 1092, 1091, 1185, 912, 484, - 861, 568, 861, 485, 757, 223, 550, 1177, 951, 1180, - 1038, 336, 1158, 729, 503, 208, 1190, 1191, 1346, 1184, - 1294, 991, 577, 784, 1197, 1198, 1189, 1076, 805, 273, - 744, 286, 208, 799, 799, 283, 284, 735, 81, 799, - 1003, 81, 81, 208, 836, 524, 271, 263, 611, 81, - 609, 602, 208, 825, 823, 1103, 811, 812, 497, 822, - 1208, 1169, 1165, 608, 1113, 1110, 610, 610, 610, 610, - 610, 1249, 1209, 1220, 1211, 1357, 739, 26, 1222, 337, - 59, 610, 258, 19, 1221, 18, 17, 20, 16, 610, - 15, 14, 337, 455, 1229, 531, 530, 540, 541, 533, - 534, 535, 536, 537, 538, 539, 532, 30, 21, 542, - 1011, 13, 12, 11, 10, 1247, 9, 1255, 469, 8, - 469, 7, 1264, 6, 5, 81, 1265, 4, 249, 23, - 2, 0, 0, 81, 469, 1045, 0, 0, 0, 0, - 861, 0, 1274, 0, 0, 337, 0, 337, 81, 0, - 0, 928, 929, 0, 0, 81, 0, 0, 0, 0, - 0, 337, 0, 0, 0, 0, 0, 0, 0, 0, - 1292, 0, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 0, 961, 542, 337, 0, 531, - 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, - 532, 81, 81, 542, 81, 0, 0, 0, 0, 81, - 1155, 81, 81, 81, 208, 1312, 0, 81, 0, 0, - 556, 557, 558, 559, 560, 561, 562, 563, 1319, 0, - 1314, 1324, 0, 1330, 81, 0, 0, 0, 1320, 733, - 1321, 1322, 1323, 1337, 0, 1338, 0, 1339, 0, 0, - 1007, 1008, 0, 0, 611, 611, 611, 611, 611, 0, - 0, 0, 1283, 1345, 1285, 0, 0, 1155, 1363, 836, - 0, 1031, 0, 81, 0, 1371, 1370, 611, 0, 0, - 799, 0, 0, 0, 81, 81, 1364, 0, 1296, 0, - 0, 0, 1385, 0, 0, 1386, 0, 789, 791, 1292, - 861, 1389, 0, 0, 0, 0, 81, 0, 0, 1011, - 1394, 0, 0, 0, 0, 0, 0, 208, 0, 337, - 0, 1226, 1227, 0, 1228, 81, 1288, 1230, 0, 1232, - 0, 0, 1403, 0, 0, 0, 0, 0, 0, 0, - 0, 469, 0, 0, 0, 0, 1410, 1408, 81, 0, - 0, 0, 0, 0, 0, 0, 610, 0, 0, 0, - 1423, 0, 0, 0, 0, 0, 0, 1075, 337, 469, - 1434, 0, 0, 0, 0, 0, 0, 1412, 0, 0, - 0, 526, 0, 529, 1243, 497, 0, 1277, 0, 543, - 544, 545, 546, 547, 548, 549, 337, 527, 528, 525, - 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 0, 1252, 542, 0, 0, 0, 0, 0, - 337, 0, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 0, 0, 542, 0, 1156, 0, - 51, 0, 0, 0, 337, 0, 0, 0, 0, 0, - 0, 531, 530, 540, 541, 533, 534, 535, 536, 537, - 538, 539, 532, 0, 799, 542, 0, 1159, 1161, 754, - 0, 0, 763, 764, 765, 766, 767, 768, 769, 770, - 771, 772, 773, 774, 775, 776, 777, 0, 0, 0, - 0, 1161, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1244, 337, 0, 337, 1188, 0, 0, - 0, 0, 0, 969, 0, 0, 0, 970, 0, 0, - 0, 0, 0, 0, 974, 975, 976, 810, 0, 0, - 0, 0, 0, 0, 0, 989, 0, 0, 0, 0, - 995, 0, 996, 0, 611, 999, 1000, 1001, 1002, 0, - 0, 0, 0, 0, 0, 0, 0, 1212, 0, 612, - 1217, 1218, 0, 0, 0, 0, 0, 1026, 337, 0, - 0, 0, 1240, 497, 0, 0, 1248, 531, 530, 540, - 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, - 0, 542, 0, 0, 0, 205, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 1270, 1271, 1272, - 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 0, 799, 542, 0, 328, 0, 0, 0, - 502, 441, 0, 443, 1116, 0, 0, 0, 1237, 497, - 469, 0, 0, 0, 337, 0, 0, 0, 0, 261, - 0, 0, 1279, 0, 531, 530, 540, 541, 533, 534, - 535, 536, 537, 538, 539, 532, 206, 337, 542, 235, - 0, 0, 0, 0, 337, 0, 531, 530, 540, 541, - 533, 534, 535, 536, 537, 538, 539, 532, 0, 1156, - 542, 0, 1315, 0, 262, 0, 0, 206, 1241, 0, - 0, 0, 206, 1119, 206, 963, 964, 965, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1316, 1317, 1342, 1318, 0, 0, 0, 0, 1279, 0, - 1279, 1279, 1279, 1238, 0, 0, 1188, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1156, 0, 51, 0, - 0, 0, 0, 1279, 0, 450, 0, 0, 456, 0, - 0, 0, 0, 0, 463, 0, 0, 0, 0, 0, - 465, 0, 531, 530, 540, 541, 533, 534, 535, 536, - 537, 538, 539, 532, 0, 0, 542, 0, 0, 0, - 0, 0, 1377, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 337, 337, 0, 0, 531, 530, 540, - 541, 533, 534, 535, 536, 537, 538, 539, 532, 0, - 0, 542, 799, 0, 0, 1396, 206, 0, 0, 206, - 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, - 0, 206, 0, 0, 1402, 0, 1223, 0, 0, 1421, - 0, 0, 0, 1225, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1234, 1235, 1236, 1279, 1239, 0, - 0, 1242, 0, 1245, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 604, 0, 613, 0, 1257, 1258, - 1259, 0, 1262, 0, 0, 0, 0, 501, 505, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1273, - 0, 0, 1117, 1118, 523, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1134, 1135, 1136, 1137, 0, - 1139, 1140, 1141, 1142, 0, 0, 0, 0, 0, 968, - 0, 0, 1148, 1149, 0, 0, 0, 0, 0, 567, - 0, 0, 0, 0, 0, 206, 206, 206, 578, 531, - 530, 540, 541, 533, 534, 535, 536, 537, 538, 539, - 532, 0, 0, 542, 0, 0, 0, 0, 0, 0, - 0, 1307, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 634, 0, - 0, 0, 1195, 0, 0, 0, 0, 0, 688, 689, - 0, 0, 0, 0, 695, 0, 0, 328, 0, 0, - 701, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 0, 0, - 0, 1360, 1361, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1367, 1368, 1369, 0, 0, 0, 0, - 0, 1224, 0, 0, 0, 0, 0, 0, 0, 206, - 0, 0, 0, 741, 0, 0, 0, 0, 0, 206, - 206, 0, 0, 0, 0, 206, 0, 0, 206, 1390, - 0, 206, 0, 0, 0, 705, 1395, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1400, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 721, 0, 0, 0, 206, 0, 0, 0, 0, 0, - 0, 0, 0, 705, 0, 0, 0, 0, 0, 1435, - 1436, 0, 0, 819, 0, 742, 743, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 846, 0, 0, 0, - 0, 0, 1298, 1299, 0, 1300, 1301, 0, 1302, 1303, - 0, 1304, 1305, 1306, 0, 262, 0, 1309, 1310, 0, - 262, 262, 0, 0, 800, 800, 262, 0, 0, 0, - 800, 0, 0, 0, 0, 0, 0, 0, 567, 0, - 0, 795, 796, 0, 0, 0, 0, 0, 0, 262, - 262, 262, 262, 0, 206, 0, 0, 0, 0, 0, - 0, 0, 206, 841, 908, 0, 206, 206, 0, 0, - 0, 0, 0, 930, 931, 0, 934, 935, 0, 0, - 936, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 24, 25, 52, 27, 28, 0, 855, 938, 0, 0, - 0, 0, 944, 0, 0, 0, 0, 0, 0, 43, - 0, 0, 0, 0, 29, 48, 49, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 38, 206, 0, 0, 54, 0, - 0, 0, 0, 0, 206, 206, 0, 206, 206, 0, - 0, 206, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 206, 0, - 942, 943, 0, 206, 0, 0, 0, 0, 705, 0, - 0, 0, 0, 0, 0, 0, 1427, 0, 0, 0, - 262, 0, 0, 0, 0, 946, 947, 0, 505, 31, - 32, 34, 33, 36, 656, 50, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 37, 44, 45, 0, - 0, 46, 47, 35, 0, 0, 0, 262, 0, 0, - 0, 0, 0, 0, 0, 0, 39, 40, 0, 41, - 42, 0, 0, 0, 0, 262, 0, 0, 0, 0, - 973, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 800, 206, 206, 206, 206, 206, 994, 0, 0, - 0, 0, 644, 0, 1025, 0, 0, 206, 0, 0, - 0, 841, 0, 0, 0, 206, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 657, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1109, 0, 0, 0, 53, 0, 0, 0, 0, - 0, 670, 671, 672, 673, 674, 675, 676, 0, 677, - 678, 679, 680, 681, 658, 659, 660, 661, 642, 643, - 0, 0, 645, 0, 646, 647, 648, 649, 650, 651, - 652, 653, 654, 655, 662, 663, 664, 665, 666, 667, - 668, 669, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, - 0, 1106, 262, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 262, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 705, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1207, 800, 0, 0, 0, 0, - 0, 0, 0, 1146, 0, 0, 0, 0, 0, 0, - 0, 1210, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1219, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1179, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 206, 0, 0, 0, 0, 0, 0, - 0, 0, 206, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 800, 0, 0, 1251, 0, 0, - 0, 0, 0, 0, 0, 0, 567, 0, 0, 0, - 0, 0, 0, 0, 1266, 0, 0, 1267, 0, 0, - 1269, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 841, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 1398, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 800, 0, 0, 0, 1388, 567, 0, - 0, 0, 0, 0, 0, 425, 414, 206, 385, 428, - 363, 377, 436, 378, 379, 407, 349, 393, 138, 375, - 0, 366, 344, 372, 345, 364, 387, 102, 390, 362, - 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, - 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, - 429, 376, 405, 430, 0, 0, 0, 80, 0, 862, - 863, 0, 0, 0, 0, 0, 95, 0, 403, 424, - 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, - 369, 370, 1046, 0, 0, 0, 0, 0, 0, 388, - 392, 409, 382, 0, 0, 0, 0, 0, 0, 0, - 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, - 0, 386, 0, 0, 0, 353, 0, 368, 410, 0, - 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 417, 365, 373, 98, 371, 152, 140, 174, - 398, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 346, - 0, 159, 176, 193, 93, 361, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 357, 360, 355, 356, 394, 395, 431, 432, - 433, 411, 352, 0, 358, 359, 0, 415, 421, 422, - 397, 82, 0, 120, 190, 147, 105, 177, 425, 414, - 0, 385, 428, 363, 377, 436, 378, 379, 407, 349, - 393, 138, 375, 0, 366, 344, 372, 345, 364, 387, - 102, 390, 362, 416, 396, 427, 119, 434, 121, 401, - 0, 158, 130, 0, 0, 389, 418, 391, 412, 384, - 408, 354, 400, 429, 376, 405, 430, 0, 0, 0, - 80, 0, 862, 863, 0, 0, 0, 0, 0, 95, - 0, 403, 424, 374, 404, 406, 343, 402, 0, 347, - 350, 435, 420, 369, 370, 0, 0, 0, 0, 0, - 0, 0, 388, 392, 409, 382, 0, 0, 0, 0, - 0, 0, 0, 0, 367, 0, 399, 0, 0, 0, - 351, 348, 0, 0, 386, 0, 0, 0, 353, 0, - 368, 410, 0, 342, 108, 413, 419, 383, 209, 423, - 381, 380, 426, 145, 0, 161, 110, 118, 83, 89, - 0, 109, 136, 150, 154, 417, 365, 373, 98, 371, - 152, 140, 174, 398, 141, 151, 122, 166, 146, 173, - 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, - 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, - 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, - 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, - 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, - 133, 0, 346, 0, 159, 176, 193, 93, 361, 164, - 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, - 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, - 139, 153, 97, 175, 157, 357, 360, 355, 356, 394, - 395, 431, 432, 433, 411, 352, 0, 358, 359, 0, - 415, 421, 422, 397, 82, 0, 120, 190, 147, 105, - 177, 425, 414, 0, 385, 428, 363, 377, 436, 378, - 379, 407, 349, 393, 138, 375, 0, 366, 344, 372, - 345, 364, 387, 102, 390, 362, 416, 396, 427, 119, - 434, 121, 401, 0, 158, 130, 0, 0, 389, 418, - 391, 412, 384, 408, 354, 400, 429, 376, 405, 430, + 269, 1432, 1386, 567, 1101, 1012, 1216, 273, 1422, 863, + 1329, 1294, 1156, 1030, 1190, 1013, 286, 247, 840, 1153, + 892, 299, 1157, 906, 1281, 838, 942, 862, 872, 57, + 566, 3, 81, 1036, 1169, 1163, 209, 1124, 339, 209, + 791, 859, 238, 781, 1055, 788, 721, 969, 1072, 842, + 1081, 876, 809, 827, 624, 758, 607, 499, 505, 790, + 902, 623, 333, 820, 440, 511, 271, 209, 81, 951, + 519, 256, 209, 330, 209, 328, 56, 300, 51, 1425, + 1409, 1420, 246, 1396, 1417, 1217, 1408, 239, 240, 241, + 242, 1395, 1146, 245, 581, 1253, 445, 61, 1185, 1186, + 1184, 582, 608, 473, 260, 853, 925, 1361, 532, 531, + 541, 542, 534, 535, 536, 537, 538, 539, 540, 533, + 924, 493, 543, 63, 64, 65, 66, 67, 471, 51, + 204, 200, 201, 202, 886, 244, 311, 252, 317, 318, + 315, 316, 314, 313, 312, 854, 855, 625, 929, 626, + 243, 1125, 319, 320, 489, 1043, 1063, 923, 1042, 885, + 1284, 1044, 490, 487, 488, 196, 458, 198, 1300, 475, + 893, 477, 1236, 1234, 237, 482, 483, 1104, 1103, 492, + 696, 694, 1419, 1416, 1387, 1100, 821, 1379, 1127, 877, + 1330, 1440, 459, 1031, 1033, 447, 336, 209, 198, 1105, + 209, 474, 476, 1332, 700, 687, 209, 920, 917, 918, + 1088, 916, 209, 879, 695, 81, 1338, 81, 1179, 81, + 81, 1129, 81, 1133, 81, 1128, 1178, 1126, 1436, 275, + 1177, 443, 1131, 81, 1368, 879, 697, 450, 211, 1086, + 879, 1130, 927, 930, 199, 936, 555, 556, 935, 860, + 1264, 203, 1097, 1111, 1132, 1134, 987, 963, 1099, 730, + 197, 523, 465, 81, 1056, 1202, 543, 727, 944, 441, + 1032, 1331, 533, 518, 722, 543, 517, 516, 922, 1362, + 507, 1377, 1347, 508, 1167, 627, 495, 496, 810, 472, + 1148, 441, 470, 518, 470, 689, 470, 470, 893, 470, + 921, 470, 1382, 810, 1394, 996, 1087, 765, 1061, 878, + 470, 1092, 1089, 1082, 1090, 1085, 1203, 1339, 1337, 1083, + 1084, 763, 764, 762, 439, 513, 209, 209, 209, 1400, + 51, 878, 81, 1091, 1434, 1441, 878, 1435, 81, 1433, + 1290, 875, 873, 926, 874, 552, 943, 882, 554, 871, + 877, 509, 606, 883, 1098, 723, 1096, 516, 928, 455, + 536, 537, 538, 539, 540, 533, 1375, 1402, 543, 461, + 462, 463, 1289, 518, 1442, 1076, 565, 446, 569, 570, + 571, 572, 573, 574, 575, 576, 577, 70, 580, 583, + 583, 583, 589, 583, 583, 589, 583, 597, 598, 599, + 600, 601, 602, 615, 612, 621, 54, 584, 586, 588, + 590, 592, 594, 595, 585, 587, 761, 591, 593, 782, + 596, 783, 452, 71, 453, 1075, 1064, 454, 1378, 613, + 541, 542, 534, 535, 536, 537, 538, 539, 540, 533, + 209, 1045, 543, 1046, 981, 81, 980, 748, 750, 751, + 209, 209, 81, 749, 448, 449, 209, 22, 1311, 209, + 336, 195, 209, 517, 516, 206, 209, 1287, 81, 81, + 1108, 733, 734, 81, 81, 81, 81, 81, 81, 1073, + 518, 1219, 982, 81, 81, 534, 535, 536, 537, 538, + 539, 540, 533, 1056, 812, 543, 329, 498, 298, 1051, + 553, 442, 784, 444, 709, 706, 517, 516, 960, 961, + 962, 81, 705, 1150, 690, 209, 688, 251, 685, 517, + 516, 81, 470, 518, 467, 735, 325, 326, 460, 470, + 79, 1344, 517, 516, 701, 707, 518, 1335, 1418, 1404, + 498, 729, 1335, 1390, 1343, 470, 470, 1199, 759, 518, + 470, 470, 470, 470, 470, 470, 611, 1335, 498, 880, + 470, 470, 756, 1335, 1369, 81, 338, 531, 541, 542, + 534, 535, 536, 537, 538, 539, 540, 533, 728, 823, + 543, 737, 800, 804, 1335, 1334, 1279, 1278, 811, 1266, + 498, 752, 1166, 754, 1154, 517, 516, 1166, 81, 81, + 795, 1263, 498, 1102, 824, 209, 289, 288, 291, 292, + 293, 294, 518, 209, 209, 290, 295, 209, 209, 1209, + 1208, 81, 785, 786, 1205, 1206, 451, 1205, 1204, 457, + 796, 797, 51, 618, 81, 464, 806, 975, 498, 824, + 498, 466, 848, 807, 24, 24, 817, 569, 793, 498, + 634, 633, 755, 847, 793, 617, 1259, 1346, 1114, 816, + 1037, 818, 819, 1037, 24, 991, 989, 58, 1007, 894, + 895, 896, 1008, 1316, 824, 619, 1207, 617, 846, 1047, + 852, 986, 1001, 850, 851, 984, 1000, 975, 209, 81, + 839, 81, 54, 54, 612, 81, 81, 209, 209, 867, + 209, 209, 975, 824, 209, 81, 1166, 975, 908, 990, + 988, 617, 54, 338, 620, 338, 731, 338, 338, 699, + 338, 209, 338, 209, 209, 985, 209, 253, 910, 983, + 54, 338, 829, 832, 833, 834, 830, 1410, 831, 835, + 1296, 497, 904, 905, 743, 887, 1271, 907, 1195, 336, + 1170, 1171, 948, 1050, 903, 605, 760, 614, 898, 897, + 1427, 521, 864, 1423, 1197, 1173, 470, 1154, 470, 756, + 1077, 725, 703, 1176, 1026, 54, 833, 834, 888, 889, + 890, 891, 470, 1024, 759, 1175, 1022, 1021, 1025, 1020, + 952, 1023, 1414, 953, 899, 900, 901, 257, 258, 1407, + 1110, 512, 959, 532, 531, 541, 542, 534, 535, 536, + 537, 538, 539, 540, 533, 1412, 510, 543, 965, 958, + 957, 1068, 500, 632, 468, 209, 209, 209, 209, 209, + 338, 1014, 1384, 964, 501, 1060, 629, 209, 1383, 1314, + 209, 1058, 611, 1052, 209, 1257, 611, 1292, 209, 974, + 913, 1009, 702, 837, 254, 255, 970, 512, 956, 755, + 248, 995, 1351, 81, 249, 58, 955, 993, 1350, 635, + 795, 1298, 1048, 1038, 1037, 491, 1429, 1428, 1429, 691, + 692, 1015, 1039, 720, 1018, 698, 266, 514, 329, 1027, + 1365, 704, 1285, 1035, 726, 60, 62, 616, 1010, 1011, + 55, 1, 612, 612, 612, 612, 612, 1040, 1421, 1065, + 1066, 81, 81, 1218, 1293, 919, 1385, 839, 1328, 1034, + 1189, 1057, 870, 861, 69, 612, 1053, 1054, 1016, 1017, + 438, 1019, 68, 1376, 1067, 869, 1069, 1070, 1071, 868, + 81, 1336, 1283, 338, 744, 881, 1062, 1074, 884, 1196, + 338, 1059, 1381, 640, 638, 209, 639, 637, 1080, 642, + 641, 636, 222, 331, 81, 836, 338, 338, 1093, 628, + 909, 338, 338, 338, 338, 338, 338, 515, 72, 1095, + 1094, 338, 338, 915, 485, 486, 224, 551, 1107, 470, + 954, 864, 760, 1041, 829, 832, 833, 834, 830, 337, + 831, 835, 1161, 736, 1170, 1171, 732, 504, 1349, 739, + 1117, 81, 81, 1155, 1118, 1014, 1123, 470, 1297, 521, + 1136, 994, 338, 1147, 578, 1135, 756, 808, 274, 747, + 1158, 287, 284, 285, 822, 81, 738, 1006, 525, 272, + 264, 1160, 610, 603, 828, 826, 1165, 849, 81, 825, + 81, 81, 1172, 1174, 611, 611, 611, 611, 611, 1188, + 1168, 792, 794, 787, 609, 1113, 1181, 1252, 1360, 611, + 1180, 742, 1183, 802, 802, 1187, 26, 611, 209, 802, + 1192, 59, 259, 19, 18, 17, 1159, 20, 51, 16, + 15, 14, 1116, 456, 30, 209, 814, 815, 1193, 1194, + 21, 81, 13, 12, 81, 81, 209, 1200, 1201, 11, + 10, 9, 81, 8, 7, 209, 1141, 911, 6, 338, + 5, 4, 250, 23, 1211, 2, 933, 934, 0, 937, + 938, 0, 338, 939, 1223, 0, 1212, 0, 1214, 0, + 1225, 0, 0, 0, 0, 0, 0, 1224, 0, 0, + 941, 0, 0, 1232, 0, 947, 0, 0, 0, 0, + 0, 0, 0, 557, 558, 559, 560, 561, 562, 563, + 564, 0, 0, 0, 1014, 1258, 864, 0, 864, 0, + 0, 0, 1268, 0, 0, 0, 0, 338, 81, 338, + 0, 0, 612, 931, 932, 1267, 81, 1048, 0, 1277, + 0, 0, 0, 338, 0, 0, 0, 262, 0, 0, + 0, 81, 0, 0, 0, 0, 0, 0, 81, 0, + 0, 0, 0, 0, 1251, 1286, 0, 1288, 0, 338, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1116, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1299, 0, 0, 0, 1273, 1274, 1275, 0, 0, + 1229, 1230, 0, 1231, 81, 81, 1233, 81, 1235, 0, + 0, 0, 81, 0, 81, 81, 81, 209, 0, 972, + 81, 1158, 1315, 973, 0, 1322, 0, 0, 470, 0, + 977, 978, 979, 1317, 1333, 1327, 1323, 81, 1324, 1325, + 1326, 992, 1340, 0, 0, 0, 998, 0, 999, 0, + 0, 1002, 1003, 1004, 1005, 0, 864, 0, 0, 0, + 0, 1348, 802, 0, 0, 0, 1280, 0, 1341, 1366, + 1342, 0, 0, 1029, 0, 0, 81, 1159, 1158, 1374, + 1318, 1373, 0, 0, 611, 0, 1295, 81, 81, 1367, + 0, 0, 0, 0, 0, 1392, 0, 1389, 1388, 0, + 0, 338, 0, 0, 0, 0, 0, 0, 0, 81, + 1345, 1397, 0, 1014, 0, 0, 0, 0, 0, 0, + 209, 0, 0, 0, 1112, 0, 0, 0, 81, 0, + 219, 0, 0, 0, 1159, 1406, 51, 0, 0, 0, + 0, 1249, 498, 0, 0, 0, 0, 1411, 0, 1078, + 338, 81, 757, 1413, 232, 766, 767, 768, 769, 770, + 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, + 1426, 1437, 0, 0, 0, 1415, 0, 0, 338, 532, + 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, + 533, 0, 0, 543, 0, 0, 502, 506, 0, 0, + 0, 0, 338, 0, 0, 212, 0, 0, 0, 1122, + 813, 0, 215, 524, 0, 1295, 864, 0, 0, 0, + 223, 218, 0, 0, 0, 0, 338, 0, 0, 0, + 503, 0, 0, 469, 0, 0, 0, 1424, 0, 0, + 0, 0, 0, 0, 0, 0, 802, 1210, 568, 1162, + 1164, 0, 221, 0, 0, 0, 0, 579, 231, 0, + 0, 0, 0, 0, 1213, 0, 207, 0, 0, 236, + 0, 0, 0, 1164, 0, 1222, 0, 0, 0, 0, + 0, 0, 0, 0, 213, 0, 338, 0, 338, 1191, + 0, 0, 0, 0, 263, 0, 0, 207, 0, 0, + 0, 0, 207, 0, 207, 0, 0, 0, 0, 0, + 0, 225, 216, 0, 226, 227, 228, 230, 0, 229, + 235, 0, 0, 0, 217, 220, 0, 214, 234, 233, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1215, + 0, 0, 1220, 1221, 0, 0, 0, 0, 0, 0, + 338, 0, 1226, 0, 0, 0, 0, 0, 0, 1228, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1237, 1238, 1239, 0, 1242, 0, 0, 1245, 0, 1248, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 966, 967, 968, 0, 1260, 1261, 1262, 0, 1265, 0, + 0, 0, 0, 0, 0, 802, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1276, 1250, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 338, 207, 0, 0, + 207, 1246, 498, 0, 1282, 0, 207, 0, 0, 724, + 0, 0, 207, 0, 0, 0, 0, 0, 0, 338, + 478, 0, 479, 480, 0, 481, 338, 484, 0, 0, + 0, 0, 0, 0, 745, 746, 494, 0, 0, 532, + 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, + 533, 0, 0, 543, 0, 0, 0, 1310, 0, 0, + 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, + 540, 533, 1319, 1320, 543, 1321, 0, 0, 0, 0, + 1282, 0, 1282, 1282, 1282, 0, 0, 568, 1191, 0, + 798, 799, 0, 0, 1243, 498, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1282, 1352, 1353, 1354, 1355, + 1356, 1357, 1358, 1359, 0, 0, 0, 1363, 1364, 1401, + 0, 0, 0, 0, 0, 0, 207, 207, 207, 1370, + 1371, 1372, 532, 531, 541, 542, 534, 535, 536, 537, + 538, 539, 540, 533, 1380, 858, 543, 0, 0, 0, + 0, 0, 0, 0, 0, 338, 338, 0, 0, 0, + 0, 0, 0, 0, 0, 1393, 0, 1120, 1121, 0, + 0, 0, 1398, 0, 802, 0, 0, 1399, 0, 0, + 1137, 1138, 1139, 1140, 0, 1142, 1143, 1144, 1145, 0, + 1403, 0, 0, 0, 0, 0, 1405, 1151, 1152, 0, + 0, 0, 0, 0, 527, 0, 530, 0, 0, 0, + 0, 0, 544, 545, 546, 547, 548, 549, 550, 1282, + 528, 529, 526, 532, 531, 541, 542, 534, 535, 536, + 537, 538, 539, 540, 533, 1438, 1439, 543, 0, 0, + 207, 0, 0, 0, 0, 0, 949, 950, 686, 506, + 207, 207, 1240, 498, 0, 693, 207, 1198, 0, 207, + 0, 0, 207, 0, 0, 0, 708, 0, 0, 0, + 0, 710, 711, 0, 0, 0, 712, 713, 714, 715, + 716, 717, 0, 0, 0, 0, 718, 719, 0, 0, + 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, + 540, 533, 498, 0, 543, 0, 0, 0, 0, 1247, + 0, 976, 0, 0, 0, 207, 1227, 0, 0, 0, + 0, 0, 0, 0, 708, 0, 0, 0, 997, 0, + 0, 0, 0, 0, 1119, 0, 0, 0, 0, 532, + 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, + 533, 0, 0, 543, 532, 531, 541, 542, 534, 535, + 536, 537, 538, 539, 540, 533, 263, 0, 543, 0, + 0, 263, 263, 0, 0, 803, 803, 263, 0, 0, + 0, 803, 1256, 532, 531, 541, 542, 534, 535, 536, + 537, 538, 539, 540, 533, 0, 0, 543, 0, 0, + 263, 263, 263, 263, 0, 207, 0, 0, 0, 0, + 0, 0, 0, 207, 844, 0, 0, 207, 207, 0, + 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, + 540, 533, 1255, 0, 543, 0, 0, 1301, 1302, 0, + 1303, 1304, 0, 1305, 1306, 0, 1307, 1308, 1309, 0, + 0, 0, 1312, 1313, 0, 0, 0, 0, 0, 0, + 0, 0, 1109, 0, 0, 0, 0, 0, 0, 0, + 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, + 540, 533, 0, 0, 543, 1244, 0, 0, 207, 0, + 0, 0, 912, 0, 914, 0, 0, 207, 207, 0, + 207, 207, 0, 1241, 207, 0, 0, 0, 940, 0, + 0, 0, 0, 0, 1149, 0, 0, 0, 0, 0, + 0, 207, 0, 945, 946, 0, 207, 0, 0, 0, + 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 263, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1182, 0, 0, 657, 532, + 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, + 533, 0, 971, 543, 0, 0, 0, 532, 531, 541, + 542, 534, 535, 536, 537, 538, 539, 540, 533, 0, + 263, 543, 532, 531, 541, 542, 534, 535, 536, 537, + 538, 539, 540, 533, 0, 0, 543, 0, 263, 532, + 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, + 533, 1430, 0, 543, 803, 207, 207, 207, 207, 207, + 0, 0, 0, 0, 0, 0, 645, 1028, 0, 0, + 207, 0, 0, 0, 844, 0, 0, 0, 207, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1254, 0, + 0, 0, 0, 658, 0, 0, 0, 568, 0, 0, + 0, 0, 0, 0, 0, 1269, 0, 0, 1270, 0, + 0, 1272, 0, 0, 0, 671, 674, 675, 676, 677, + 678, 679, 0, 680, 681, 682, 683, 684, 659, 660, + 661, 662, 643, 644, 672, 1079, 646, 0, 647, 648, + 649, 650, 651, 652, 653, 654, 655, 656, 663, 664, + 665, 666, 667, 668, 669, 670, 0, 0, 0, 0, + 0, 0, 0, 1106, 0, 24, 25, 52, 27, 28, + 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, + 0, 0, 0, 0, 43, 263, 0, 0, 0, 29, + 48, 49, 0, 0, 0, 0, 263, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 708, 38, + 673, 0, 0, 54, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 803, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 31, 32, 34, 33, 36, 0, + 50, 0, 0, 0, 0, 0, 0, 0, 1391, 568, + 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, + 0, 37, 44, 45, 0, 0, 46, 47, 35, 0, + 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, + 0, 39, 40, 0, 41, 42, 207, 0, 0, 0, + 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 803, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1291, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 426, 415, 844, 386, 429, + 364, 378, 437, 379, 380, 408, 350, 394, 139, 376, + 0, 367, 345, 373, 346, 365, 388, 103, 391, 363, + 417, 397, 428, 120, 435, 122, 402, 0, 159, 131, + 0, 0, 390, 419, 392, 413, 385, 409, 355, 401, + 430, 377, 406, 431, 0, 0, 0, 80, 0, 865, + 866, 0, 0, 0, 0, 0, 96, 0, 404, 425, + 375, 405, 407, 344, 403, 0, 348, 351, 436, 421, + 370, 371, 1049, 0, 0, 0, 0, 0, 0, 389, + 393, 410, 383, 0, 0, 0, 803, 0, 0, 0, + 0, 368, 0, 400, 0, 0, 0, 352, 349, 0, + 207, 387, 0, 0, 0, 354, 0, 369, 411, 0, + 343, 109, 414, 420, 384, 210, 424, 382, 381, 427, + 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, + 151, 155, 418, 366, 374, 99, 372, 153, 141, 175, + 399, 142, 152, 123, 167, 147, 174, 182, 183, 164, + 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, + 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, + 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, + 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 347, + 0, 160, 177, 194, 94, 362, 165, 184, 185, 186, + 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, + 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, + 176, 158, 358, 361, 356, 357, 395, 396, 432, 433, + 434, 412, 353, 0, 359, 360, 0, 416, 422, 423, + 398, 82, 89, 121, 191, 148, 106, 178, 426, 415, + 0, 386, 429, 364, 378, 437, 379, 380, 408, 350, + 394, 139, 376, 0, 367, 345, 373, 346, 365, 388, + 103, 391, 363, 417, 397, 428, 120, 435, 122, 402, + 0, 159, 131, 0, 0, 390, 419, 392, 413, 385, + 409, 355, 401, 430, 377, 406, 431, 0, 0, 0, + 80, 0, 865, 866, 0, 0, 0, 0, 0, 96, + 0, 404, 425, 375, 405, 407, 344, 403, 0, 348, + 351, 436, 421, 370, 371, 0, 0, 0, 0, 0, + 0, 0, 389, 393, 410, 383, 0, 0, 0, 0, + 0, 0, 0, 0, 368, 0, 400, 0, 0, 0, + 352, 349, 0, 0, 387, 0, 0, 0, 354, 0, + 369, 411, 0, 343, 109, 414, 420, 384, 210, 424, + 382, 381, 427, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 418, 366, 374, 99, 372, + 153, 141, 175, 399, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 347, 0, 160, 177, 194, 94, 362, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 358, 361, 356, 357, 395, + 396, 432, 433, 434, 412, 353, 0, 359, 360, 0, + 416, 422, 423, 398, 82, 89, 121, 191, 148, 106, + 178, 426, 415, 0, 386, 429, 364, 378, 437, 379, + 380, 408, 350, 394, 139, 376, 0, 367, 345, 373, + 346, 365, 388, 103, 391, 363, 417, 397, 428, 120, + 435, 122, 402, 0, 159, 131, 0, 0, 390, 419, + 392, 413, 385, 409, 355, 401, 430, 377, 406, 431, 54, 0, 0, 80, 0, 0, 0, 0, 0, 0, - 0, 0, 95, 0, 403, 424, 374, 404, 406, 343, - 402, 0, 347, 350, 435, 420, 369, 370, 0, 0, - 0, 0, 0, 0, 0, 388, 392, 409, 382, 0, - 0, 0, 0, 0, 0, 0, 0, 367, 0, 399, - 0, 0, 0, 351, 348, 0, 0, 386, 0, 0, - 0, 353, 0, 368, 410, 0, 342, 108, 413, 419, - 383, 209, 423, 381, 380, 426, 145, 0, 161, 110, - 118, 83, 89, 0, 109, 136, 150, 154, 417, 365, - 373, 98, 371, 152, 140, 174, 398, 141, 151, 122, - 166, 146, 173, 181, 182, 163, 180, 189, 84, 162, - 172, 96, 155, 86, 170, 160, 128, 114, 115, 85, - 0, 149, 101, 106, 100, 137, 167, 168, 99, 192, - 90, 179, 88, 91, 178, 135, 165, 171, 129, 126, - 87, 169, 127, 125, 117, 104, 111, 143, 124, 144, - 112, 132, 131, 133, 0, 346, 0, 159, 176, 193, - 93, 361, 164, 183, 184, 185, 186, 187, 188, 0, - 0, 94, 107, 103, 142, 134, 92, 113, 156, 116, - 123, 148, 191, 139, 153, 97, 175, 157, 357, 360, - 355, 356, 394, 395, 431, 432, 433, 411, 352, 0, - 358, 359, 0, 415, 421, 422, 397, 82, 0, 120, - 190, 147, 105, 177, 425, 414, 0, 385, 428, 363, - 377, 436, 378, 379, 407, 349, 393, 138, 375, 0, - 366, 344, 372, 345, 364, 387, 102, 390, 362, 416, - 396, 427, 119, 434, 121, 401, 0, 158, 130, 0, - 0, 389, 418, 391, 412, 384, 408, 354, 400, 429, - 376, 405, 430, 0, 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 0, 95, 0, 403, 424, 374, - 404, 406, 343, 402, 0, 347, 350, 435, 420, 369, - 370, 0, 0, 0, 0, 0, 0, 0, 388, 392, - 409, 382, 0, 0, 0, 0, 0, 0, 1112, 0, - 367, 0, 399, 0, 0, 0, 351, 348, 0, 0, - 386, 0, 0, 0, 353, 0, 368, 410, 0, 342, - 108, 413, 419, 383, 209, 423, 381, 380, 426, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 417, 365, 373, 98, 371, 152, 140, 174, 398, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 346, 0, - 159, 176, 193, 93, 361, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 357, 360, 355, 356, 394, 395, 431, 432, 433, - 411, 352, 0, 358, 359, 0, 415, 421, 422, 397, - 82, 0, 120, 190, 147, 105, 177, 425, 414, 0, - 385, 428, 363, 377, 436, 378, 379, 407, 349, 393, - 138, 375, 0, 366, 344, 372, 345, 364, 387, 102, - 390, 362, 416, 396, 427, 119, 434, 121, 401, 0, - 158, 130, 0, 0, 389, 418, 391, 412, 384, 408, - 354, 400, 429, 376, 405, 430, 0, 0, 0, 267, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, - 403, 424, 374, 404, 406, 343, 402, 0, 347, 350, - 435, 420, 369, 370, 0, 0, 0, 0, 0, 0, - 0, 388, 392, 409, 382, 0, 0, 0, 0, 0, - 0, 750, 0, 367, 0, 399, 0, 0, 0, 351, - 348, 0, 0, 386, 0, 0, 0, 353, 0, 368, - 410, 0, 342, 108, 413, 419, 383, 209, 423, 381, - 380, 426, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 417, 365, 373, 98, 371, 152, - 140, 174, 398, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 346, 0, 159, 176, 193, 93, 361, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 357, 360, 355, 356, 394, 395, - 431, 432, 433, 411, 352, 0, 358, 359, 0, 415, - 421, 422, 397, 82, 0, 120, 190, 147, 105, 177, - 425, 414, 0, 385, 428, 363, 377, 436, 378, 379, - 407, 349, 393, 138, 375, 0, 366, 344, 372, 345, - 364, 387, 102, 390, 362, 416, 396, 427, 119, 434, - 121, 401, 0, 158, 130, 0, 0, 389, 418, 391, - 412, 384, 408, 354, 400, 429, 376, 405, 430, 0, + 0, 0, 96, 0, 404, 425, 375, 405, 407, 344, + 403, 0, 348, 351, 436, 421, 370, 371, 0, 0, + 0, 0, 0, 0, 0, 389, 393, 410, 383, 0, + 0, 0, 0, 0, 0, 0, 0, 368, 0, 400, + 0, 0, 0, 352, 349, 0, 0, 387, 0, 0, + 0, 354, 0, 369, 411, 0, 343, 109, 414, 420, + 384, 210, 424, 382, 381, 427, 146, 0, 162, 111, + 119, 83, 90, 0, 110, 137, 151, 155, 418, 366, + 374, 99, 372, 153, 141, 175, 399, 142, 152, 123, + 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, + 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, + 0, 150, 102, 107, 101, 138, 168, 169, 100, 193, + 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, + 87, 170, 128, 126, 118, 105, 112, 144, 125, 145, + 113, 133, 132, 134, 0, 347, 0, 160, 177, 194, + 94, 362, 165, 184, 185, 186, 187, 188, 189, 0, + 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, + 124, 149, 192, 140, 154, 98, 176, 158, 358, 361, + 356, 357, 395, 396, 432, 433, 434, 412, 353, 0, + 359, 360, 0, 416, 422, 423, 398, 82, 89, 121, + 191, 148, 106, 178, 426, 415, 0, 386, 429, 364, + 378, 437, 379, 380, 408, 350, 394, 139, 376, 0, + 367, 345, 373, 346, 365, 388, 103, 391, 363, 417, + 397, 428, 120, 435, 122, 402, 0, 159, 131, 0, + 0, 390, 419, 392, 413, 385, 409, 355, 401, 430, + 377, 406, 431, 0, 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 96, 0, 404, 425, 375, + 405, 407, 344, 403, 0, 348, 351, 436, 421, 370, + 371, 0, 0, 0, 0, 0, 0, 0, 389, 393, + 410, 383, 0, 0, 0, 0, 0, 0, 1115, 0, + 368, 0, 400, 0, 0, 0, 352, 349, 0, 0, + 387, 0, 0, 0, 354, 0, 369, 411, 0, 343, + 109, 414, 420, 384, 210, 424, 382, 381, 427, 146, + 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, + 155, 418, 366, 374, 99, 372, 153, 141, 175, 399, + 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, + 190, 84, 163, 173, 97, 156, 86, 171, 161, 129, + 115, 116, 85, 0, 150, 102, 107, 101, 138, 168, + 169, 100, 193, 91, 180, 88, 92, 179, 136, 166, + 172, 130, 127, 87, 170, 128, 126, 118, 105, 112, + 144, 125, 145, 113, 133, 132, 134, 0, 347, 0, + 160, 177, 194, 94, 362, 165, 184, 185, 186, 187, + 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, + 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, + 158, 358, 361, 356, 357, 395, 396, 432, 433, 434, + 412, 353, 0, 359, 360, 0, 416, 422, 423, 398, + 82, 89, 121, 191, 148, 106, 178, 426, 415, 0, + 386, 429, 364, 378, 437, 379, 380, 408, 350, 394, + 139, 376, 0, 367, 345, 373, 346, 365, 388, 103, + 391, 363, 417, 397, 428, 120, 435, 122, 402, 0, + 159, 131, 0, 0, 390, 419, 392, 413, 385, 409, + 355, 401, 430, 377, 406, 431, 0, 0, 0, 268, + 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, + 404, 425, 375, 405, 407, 344, 403, 0, 348, 351, + 436, 421, 370, 371, 0, 0, 0, 0, 0, 0, + 0, 389, 393, 410, 383, 0, 0, 0, 0, 0, + 0, 753, 0, 368, 0, 400, 0, 0, 0, 352, + 349, 0, 0, 387, 0, 0, 0, 354, 0, 369, + 411, 0, 343, 109, 414, 420, 384, 210, 424, 382, + 381, 427, 146, 0, 162, 111, 119, 83, 90, 0, + 110, 137, 151, 155, 418, 366, 374, 99, 372, 153, + 141, 175, 399, 142, 152, 123, 167, 147, 174, 182, + 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, + 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, + 101, 138, 168, 169, 100, 193, 91, 180, 88, 92, + 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, + 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, + 0, 347, 0, 160, 177, 194, 94, 362, 165, 184, + 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, + 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, + 154, 98, 176, 158, 358, 361, 356, 357, 395, 396, + 432, 433, 434, 412, 353, 0, 359, 360, 0, 416, + 422, 423, 398, 82, 89, 121, 191, 148, 106, 178, + 426, 415, 0, 386, 429, 364, 378, 437, 379, 380, + 408, 350, 394, 139, 376, 0, 367, 345, 373, 346, + 365, 388, 103, 391, 363, 417, 397, 428, 120, 435, + 122, 402, 0, 159, 131, 0, 0, 390, 419, 392, + 413, 385, 409, 355, 401, 430, 377, 406, 431, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, - 0, 95, 0, 403, 424, 374, 404, 406, 343, 402, - 0, 347, 350, 435, 420, 369, 370, 0, 0, 0, - 0, 0, 0, 0, 388, 392, 409, 382, 0, 0, - 0, 0, 0, 0, 0, 0, 367, 0, 399, 0, - 0, 0, 351, 348, 0, 0, 386, 0, 0, 0, - 353, 0, 368, 410, 0, 342, 108, 413, 419, 383, - 209, 423, 381, 380, 426, 145, 0, 161, 110, 118, - 83, 89, 0, 109, 136, 150, 154, 417, 365, 373, - 98, 371, 152, 140, 174, 398, 141, 151, 122, 166, - 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, - 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, - 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, - 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, - 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, - 132, 131, 133, 0, 346, 0, 159, 176, 193, 93, - 361, 164, 183, 184, 185, 186, 187, 188, 0, 0, - 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, - 148, 191, 139, 153, 97, 175, 157, 357, 360, 355, - 356, 394, 395, 431, 432, 433, 411, 352, 0, 358, - 359, 0, 415, 421, 422, 397, 82, 0, 120, 190, - 147, 105, 177, 425, 414, 0, 385, 428, 363, 377, - 436, 378, 379, 407, 349, 393, 138, 375, 0, 366, - 344, 372, 345, 364, 387, 102, 390, 362, 416, 396, - 427, 119, 434, 121, 401, 0, 158, 130, 0, 0, - 389, 418, 391, 412, 384, 408, 354, 400, 429, 376, - 405, 430, 0, 0, 0, 267, 0, 0, 0, 0, - 0, 0, 0, 0, 95, 0, 403, 424, 374, 404, - 406, 343, 402, 0, 347, 350, 435, 420, 369, 370, - 0, 0, 0, 0, 0, 0, 0, 388, 392, 409, - 382, 0, 0, 0, 0, 0, 0, 0, 0, 367, - 0, 399, 0, 0, 0, 351, 348, 0, 0, 386, - 0, 0, 0, 353, 0, 368, 410, 0, 342, 108, - 413, 419, 383, 209, 423, 381, 380, 426, 145, 0, - 161, 110, 118, 83, 89, 0, 109, 136, 150, 154, - 417, 365, 373, 98, 371, 152, 140, 174, 398, 141, - 151, 122, 166, 146, 173, 181, 182, 163, 180, 189, - 84, 162, 172, 96, 155, 86, 170, 160, 128, 114, - 115, 85, 0, 149, 101, 106, 100, 137, 167, 168, - 99, 192, 90, 179, 88, 91, 178, 135, 165, 171, - 129, 126, 87, 169, 127, 125, 117, 104, 111, 143, - 124, 144, 112, 132, 131, 133, 0, 346, 0, 159, - 176, 193, 93, 361, 164, 183, 184, 185, 186, 187, - 188, 0, 0, 94, 107, 103, 142, 134, 92, 113, - 156, 116, 123, 148, 191, 139, 153, 97, 175, 157, - 357, 360, 355, 356, 394, 395, 431, 432, 433, 411, - 352, 0, 358, 359, 0, 415, 421, 422, 397, 82, - 0, 120, 190, 147, 105, 177, 425, 414, 0, 385, - 428, 363, 377, 436, 378, 379, 407, 349, 393, 138, - 375, 0, 366, 344, 372, 345, 364, 387, 102, 390, - 362, 416, 396, 427, 119, 434, 121, 401, 0, 158, - 130, 0, 0, 389, 418, 391, 412, 384, 408, 354, - 400, 429, 376, 405, 430, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, 0, 95, 0, 403, - 424, 374, 404, 406, 343, 402, 0, 347, 350, 435, - 420, 369, 370, 0, 0, 0, 0, 0, 0, 0, - 388, 392, 409, 382, 0, 0, 0, 0, 0, 0, - 0, 0, 367, 0, 399, 0, 0, 0, 351, 348, - 0, 0, 386, 0, 0, 0, 353, 0, 368, 410, - 0, 342, 108, 413, 419, 383, 209, 423, 381, 380, - 426, 145, 0, 161, 110, 118, 83, 89, 0, 109, - 136, 150, 154, 417, 365, 373, 98, 371, 152, 140, - 174, 398, 141, 151, 122, 166, 146, 173, 181, 182, - 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, - 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, - 137, 167, 168, 99, 192, 90, 179, 88, 340, 178, - 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, - 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, - 346, 0, 159, 176, 193, 93, 361, 164, 183, 184, - 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, - 341, 339, 113, 156, 116, 123, 148, 191, 139, 153, - 97, 175, 157, 357, 360, 355, 356, 394, 395, 431, - 432, 433, 411, 352, 0, 358, 359, 0, 415, 421, - 422, 397, 82, 0, 120, 190, 147, 105, 177, 425, - 414, 0, 385, 428, 363, 377, 436, 378, 379, 407, - 349, 393, 138, 375, 0, 366, 344, 372, 345, 364, - 387, 102, 390, 362, 416, 396, 427, 119, 434, 121, - 401, 0, 158, 130, 0, 0, 389, 418, 391, 412, - 384, 408, 354, 400, 429, 376, 405, 430, 0, 0, - 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, - 95, 0, 403, 424, 374, 404, 406, 343, 402, 0, - 347, 350, 435, 420, 369, 370, 0, 0, 0, 0, - 0, 0, 0, 388, 392, 409, 382, 0, 0, 0, - 0, 0, 0, 0, 0, 367, 0, 399, 0, 0, - 0, 351, 348, 0, 0, 386, 0, 0, 0, 353, - 0, 368, 410, 0, 342, 108, 413, 419, 383, 209, - 423, 381, 380, 426, 145, 0, 161, 110, 118, 83, - 89, 0, 109, 136, 150, 154, 417, 365, 373, 98, - 371, 152, 140, 174, 398, 141, 151, 122, 166, 146, - 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, - 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, - 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, - 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, - 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, - 131, 133, 0, 346, 0, 159, 176, 193, 93, 361, - 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, - 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, - 191, 139, 153, 97, 175, 157, 357, 360, 355, 356, - 394, 395, 431, 432, 433, 411, 352, 0, 358, 359, - 0, 415, 421, 422, 397, 82, 0, 120, 190, 147, - 105, 177, 425, 414, 0, 385, 428, 363, 377, 436, - 378, 379, 407, 349, 393, 138, 375, 0, 366, 344, - 372, 345, 364, 387, 102, 390, 362, 416, 396, 427, - 119, 434, 121, 401, 0, 158, 130, 0, 0, 389, - 418, 391, 412, 384, 408, 354, 400, 429, 376, 405, - 430, 0, 0, 0, 80, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 403, 424, 374, 404, 406, - 343, 402, 0, 347, 350, 435, 420, 369, 370, 0, - 0, 0, 0, 0, 0, 0, 388, 392, 409, 382, - 0, 0, 0, 0, 0, 0, 0, 0, 367, 0, - 399, 0, 0, 0, 351, 348, 0, 0, 386, 0, - 0, 0, 353, 0, 368, 410, 0, 342, 108, 413, - 419, 383, 209, 423, 381, 380, 426, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 417, - 365, 373, 98, 371, 152, 140, 174, 398, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 621, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 340, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 346, 0, 159, 176, - 193, 93, 361, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 341, 339, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 357, - 360, 355, 356, 394, 395, 431, 432, 433, 411, 352, - 0, 358, 359, 0, 415, 421, 422, 397, 82, 0, - 120, 190, 147, 105, 177, 425, 414, 0, 385, 428, - 363, 377, 436, 378, 379, 407, 349, 393, 138, 375, - 0, 366, 344, 372, 345, 364, 387, 102, 390, 362, - 416, 396, 427, 119, 434, 121, 401, 0, 158, 130, - 0, 0, 389, 418, 391, 412, 384, 408, 354, 400, - 429, 376, 405, 430, 0, 0, 0, 80, 0, 0, - 0, 0, 0, 0, 0, 0, 95, 0, 403, 424, - 374, 404, 406, 343, 402, 0, 347, 350, 435, 420, - 369, 370, 0, 0, 0, 0, 0, 0, 0, 388, - 392, 409, 382, 0, 0, 0, 0, 0, 0, 0, - 0, 367, 0, 399, 0, 0, 0, 351, 348, 0, - 0, 386, 0, 0, 0, 353, 0, 368, 410, 0, - 342, 108, 413, 419, 383, 209, 423, 381, 380, 426, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 417, 365, 373, 98, 371, 152, 140, 174, - 398, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 331, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 340, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 346, - 0, 159, 176, 193, 93, 361, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 341, - 339, 334, 333, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 357, 360, 355, 356, 394, 395, 431, 432, - 433, 411, 352, 0, 358, 359, 0, 415, 421, 422, - 397, 82, 0, 120, 190, 147, 105, 177, 138, 0, - 0, 0, 0, 269, 0, 0, 0, 102, 0, 266, - 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, - 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, - 0, 0, 853, 0, 54, 0, 0, 267, 288, 287, - 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, - 296, 854, 0, 0, 264, 281, 0, 308, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 278, 279, 0, - 0, 0, 0, 322, 0, 280, 0, 0, 275, 276, - 277, 282, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 310, 321, 316, 317, 314, 315, 313, 312, - 311, 323, 302, 303, 304, 305, 307, 0, 318, 319, - 306, 82, 0, 120, 190, 147, 105, 177, 138, 0, - 0, 786, 0, 269, 0, 0, 0, 102, 0, 266, - 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, - 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 0, 267, 288, 287, - 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, - 296, 0, 0, 0, 264, 281, 0, 308, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 278, 279, 260, - 0, 0, 0, 322, 0, 280, 0, 0, 275, 276, - 277, 282, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 310, 321, 316, 317, 314, 315, 313, 312, - 311, 323, 302, 303, 304, 305, 307, 0, 318, 319, - 306, 82, 0, 120, 190, 147, 105, 177, 138, 0, - 0, 0, 0, 269, 0, 0, 0, 102, 0, 266, - 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, - 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 497, 267, 288, 287, - 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, - 296, 0, 0, 0, 264, 281, 0, 308, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 278, 279, 0, - 0, 0, 0, 322, 0, 280, 0, 0, 275, 276, - 277, 282, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 310, 321, 316, 317, 314, 315, 313, 312, - 311, 323, 302, 303, 304, 305, 307, 0, 318, 319, - 306, 82, 0, 120, 190, 147, 105, 177, 138, 0, - 0, 0, 0, 269, 0, 0, 0, 102, 0, 266, - 0, 0, 0, 119, 309, 121, 0, 0, 158, 130, - 0, 0, 0, 0, 300, 301, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 0, 267, 288, 287, - 290, 291, 292, 293, 0, 0, 95, 289, 294, 295, - 296, 0, 0, 0, 264, 281, 0, 308, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 278, 279, 260, - 0, 0, 0, 322, 0, 280, 0, 0, 275, 276, - 277, 282, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 320, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 310, 321, 316, 317, 314, 315, 313, 312, - 311, 323, 302, 303, 304, 305, 307, 24, 318, 319, - 306, 82, 0, 120, 190, 147, 105, 177, 0, 138, - 0, 0, 0, 0, 269, 0, 0, 0, 102, 0, - 266, 0, 0, 0, 119, 309, 121, 0, 0, 158, - 130, 0, 0, 0, 0, 300, 301, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 0, 267, 288, - 287, 290, 291, 292, 293, 0, 0, 95, 289, 294, - 295, 296, 0, 0, 0, 264, 281, 0, 308, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 278, 279, - 0, 0, 0, 0, 322, 0, 280, 0, 0, 275, - 276, 277, 282, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 108, 0, 0, 0, 209, 0, 0, 320, - 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, - 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, - 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, - 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, - 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, - 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, - 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, - 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, - 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, - 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, - 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, - 97, 175, 157, 310, 321, 316, 317, 314, 315, 313, - 312, 311, 323, 302, 303, 304, 305, 307, 0, 318, - 319, 306, 82, 0, 120, 190, 147, 105, 177, 138, - 0, 0, 0, 0, 269, 0, 0, 0, 102, 0, - 266, 0, 0, 0, 119, 309, 121, 0, 0, 158, - 130, 0, 0, 0, 0, 300, 301, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 0, 267, 288, - 287, 290, 291, 292, 293, 0, 0, 95, 289, 294, - 295, 296, 0, 0, 0, 264, 281, 0, 308, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 278, 279, - 0, 0, 0, 0, 322, 0, 280, 0, 0, 275, - 276, 277, 282, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 108, 0, 0, 0, 209, 0, 0, 320, - 0, 145, 0, 161, 110, 118, 83, 89, 0, 109, - 136, 150, 154, 0, 0, 0, 98, 0, 152, 140, - 174, 0, 141, 151, 122, 166, 146, 173, 181, 182, - 163, 180, 189, 84, 162, 172, 96, 155, 86, 170, - 160, 128, 114, 115, 85, 0, 149, 101, 106, 100, - 137, 167, 168, 99, 192, 90, 179, 88, 91, 178, - 135, 165, 171, 129, 126, 87, 169, 127, 125, 117, - 104, 111, 143, 124, 144, 112, 132, 131, 133, 0, - 0, 0, 159, 176, 193, 93, 0, 164, 183, 184, - 185, 186, 187, 188, 0, 0, 94, 107, 103, 142, - 134, 92, 113, 156, 116, 123, 148, 191, 139, 153, - 97, 175, 157, 310, 321, 316, 317, 314, 315, 313, - 312, 311, 323, 302, 303, 304, 305, 307, 0, 318, - 319, 306, 82, 138, 120, 190, 147, 105, 177, 0, - 0, 0, 102, 0, 0, 0, 0, 0, 119, 309, - 121, 0, 0, 158, 130, 0, 0, 0, 0, 300, - 301, 0, 0, 0, 0, 0, 0, 0, 0, 54, - 0, 0, 267, 288, 287, 290, 291, 292, 293, 0, - 0, 95, 289, 294, 295, 296, 0, 0, 0, 0, - 281, 0, 308, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 278, 279, 0, 0, 0, 0, 322, 0, - 280, 0, 0, 275, 276, 277, 282, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, - 209, 0, 0, 320, 0, 145, 0, 161, 110, 118, - 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, - 98, 0, 152, 140, 174, 1428, 141, 151, 122, 166, - 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, - 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, - 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, - 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, - 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, - 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, - 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, - 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, - 148, 191, 139, 153, 97, 175, 157, 310, 321, 316, - 317, 314, 315, 313, 312, 311, 323, 302, 303, 304, - 305, 307, 0, 318, 319, 306, 82, 138, 120, 190, - 147, 105, 177, 0, 0, 0, 102, 0, 0, 0, - 0, 0, 119, 309, 121, 0, 0, 158, 130, 0, - 0, 0, 0, 300, 301, 0, 0, 0, 0, 0, - 0, 0, 0, 54, 0, 497, 267, 288, 287, 290, - 291, 292, 293, 0, 0, 95, 289, 294, 295, 296, - 0, 0, 0, 0, 281, 0, 308, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 278, 279, 0, 0, - 0, 0, 322, 0, 280, 0, 0, 275, 276, 277, - 282, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 108, 0, 0, 0, 209, 0, 0, 320, 0, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 141, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, - 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 310, 321, 316, 317, 314, 315, 313, 312, 311, - 323, 302, 303, 304, 305, 307, 0, 318, 319, 306, - 82, 138, 120, 190, 147, 105, 177, 0, 0, 0, - 102, 0, 0, 0, 0, 0, 119, 309, 121, 0, - 0, 158, 130, 0, 0, 0, 0, 300, 301, 0, - 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, - 267, 288, 287, 290, 291, 292, 293, 0, 0, 95, - 289, 294, 295, 296, 0, 0, 0, 0, 281, 0, - 308, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 278, 279, 0, 0, 0, 0, 322, 0, 280, 0, - 0, 275, 276, 277, 282, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, - 0, 320, 0, 145, 0, 161, 110, 118, 83, 89, - 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, - 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, - 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, - 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, - 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, - 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, - 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, - 133, 0, 0, 0, 159, 176, 193, 93, 0, 164, - 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, - 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, - 139, 153, 97, 175, 157, 310, 321, 316, 317, 314, - 315, 313, 312, 311, 323, 302, 303, 304, 305, 307, - 0, 318, 319, 306, 82, 138, 120, 190, 147, 105, - 177, 0, 0, 0, 102, 0, 0, 0, 0, 0, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 531, 530, 540, 541, 533, 534, 535, 536, 537, 538, - 539, 532, 0, 0, 542, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 0, 0, 0, 519, 0, 0, 0, 82, 102, - 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 0, 404, 425, 375, 405, 407, 344, 403, + 0, 348, 351, 436, 421, 370, 371, 0, 0, 0, + 0, 0, 0, 0, 389, 393, 410, 383, 0, 0, + 0, 0, 0, 0, 0, 0, 368, 0, 400, 0, + 0, 0, 352, 349, 0, 0, 387, 0, 0, 0, + 354, 0, 369, 411, 0, 343, 109, 414, 420, 384, + 210, 424, 382, 381, 427, 146, 0, 162, 111, 119, + 83, 90, 0, 110, 137, 151, 155, 418, 366, 374, + 99, 372, 153, 141, 175, 399, 142, 152, 123, 167, + 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, + 97, 156, 86, 171, 161, 129, 115, 116, 85, 0, + 150, 102, 107, 101, 138, 168, 169, 100, 193, 91, + 180, 88, 92, 179, 136, 166, 172, 130, 127, 87, + 170, 128, 126, 118, 105, 112, 144, 125, 145, 113, + 133, 132, 134, 0, 347, 0, 160, 177, 194, 94, + 362, 165, 184, 185, 186, 187, 188, 189, 0, 0, + 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, + 149, 192, 140, 154, 98, 176, 158, 358, 361, 356, + 357, 395, 396, 432, 433, 434, 412, 353, 0, 359, + 360, 0, 416, 422, 423, 398, 82, 89, 121, 191, + 148, 106, 178, 426, 415, 0, 386, 429, 364, 378, + 437, 379, 380, 408, 350, 394, 139, 376, 0, 367, + 345, 373, 346, 365, 388, 103, 391, 363, 417, 397, + 428, 120, 435, 122, 402, 0, 159, 131, 0, 0, + 390, 419, 392, 413, 385, 409, 355, 401, 430, 377, + 406, 431, 0, 0, 0, 268, 0, 0, 0, 0, + 0, 0, 0, 0, 96, 0, 404, 425, 375, 405, + 407, 344, 403, 0, 348, 351, 436, 421, 370, 371, + 0, 0, 0, 0, 0, 0, 0, 389, 393, 410, + 383, 0, 0, 0, 0, 0, 0, 0, 0, 368, + 0, 400, 0, 0, 0, 352, 349, 0, 0, 387, + 0, 0, 0, 354, 0, 369, 411, 0, 343, 109, + 414, 420, 384, 210, 424, 382, 381, 427, 146, 0, + 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, + 418, 366, 374, 99, 372, 153, 141, 175, 399, 142, + 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, + 84, 163, 173, 97, 156, 86, 171, 161, 129, 115, + 116, 85, 0, 150, 102, 107, 101, 138, 168, 169, + 100, 193, 91, 180, 88, 92, 179, 136, 166, 172, + 130, 127, 87, 170, 128, 126, 118, 105, 112, 144, + 125, 145, 113, 133, 132, 134, 0, 347, 0, 160, + 177, 194, 94, 362, 165, 184, 185, 186, 187, 188, + 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, + 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, + 358, 361, 356, 357, 395, 396, 432, 433, 434, 412, + 353, 0, 359, 360, 0, 416, 422, 423, 398, 82, + 89, 121, 191, 148, 106, 178, 426, 415, 0, 386, + 429, 364, 378, 437, 379, 380, 408, 350, 394, 139, + 376, 0, 367, 345, 373, 346, 365, 388, 103, 391, + 363, 417, 397, 428, 120, 435, 122, 402, 0, 159, + 131, 0, 0, 390, 419, 392, 413, 385, 409, 355, + 401, 430, 377, 406, 431, 0, 0, 0, 80, 0, + 0, 0, 0, 0, 0, 0, 0, 96, 0, 404, + 425, 375, 405, 407, 344, 403, 0, 348, 351, 436, + 421, 370, 371, 0, 0, 0, 0, 0, 0, 0, + 389, 393, 410, 383, 0, 0, 0, 0, 0, 0, + 0, 0, 368, 0, 400, 0, 0, 0, 352, 349, + 0, 0, 387, 0, 0, 0, 354, 0, 369, 411, + 0, 343, 109, 414, 420, 384, 210, 424, 382, 381, + 427, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 418, 366, 374, 99, 372, 153, 141, + 175, 399, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 341, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 347, 0, 160, 177, 194, 94, 362, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 342, 340, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 358, 361, 356, 357, 395, 396, 432, + 433, 434, 412, 353, 0, 359, 360, 0, 416, 422, + 423, 398, 82, 89, 121, 191, 148, 106, 178, 426, + 415, 0, 386, 429, 364, 378, 437, 379, 380, 408, + 350, 394, 139, 376, 0, 367, 345, 373, 346, 365, + 388, 103, 391, 363, 417, 397, 428, 120, 435, 122, + 402, 0, 159, 131, 0, 0, 390, 419, 392, 413, + 385, 409, 355, 401, 430, 377, 406, 431, 0, 0, + 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, + 96, 0, 404, 425, 375, 405, 407, 344, 403, 0, + 348, 351, 436, 421, 370, 371, 0, 0, 0, 0, + 0, 0, 0, 389, 393, 410, 383, 0, 0, 0, + 0, 0, 0, 0, 0, 368, 0, 400, 0, 0, + 0, 352, 349, 0, 0, 387, 0, 0, 0, 354, + 0, 369, 411, 0, 343, 109, 414, 420, 384, 210, + 424, 382, 381, 427, 146, 0, 162, 111, 119, 83, + 90, 0, 110, 137, 151, 155, 418, 366, 374, 99, + 372, 153, 141, 175, 399, 142, 152, 123, 167, 147, + 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, + 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, + 102, 107, 101, 138, 168, 169, 100, 193, 91, 180, + 88, 92, 179, 136, 166, 172, 130, 127, 87, 170, + 128, 126, 118, 105, 112, 144, 125, 145, 113, 133, + 132, 134, 0, 347, 0, 160, 177, 194, 94, 362, + 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, + 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, + 192, 140, 154, 98, 176, 158, 358, 361, 356, 357, + 395, 396, 432, 433, 434, 412, 353, 0, 359, 360, + 0, 416, 422, 423, 398, 82, 89, 121, 191, 148, + 106, 178, 426, 415, 0, 386, 429, 364, 378, 437, + 379, 380, 408, 350, 394, 139, 376, 0, 367, 345, + 373, 346, 365, 388, 103, 391, 363, 417, 397, 428, + 120, 435, 122, 402, 0, 159, 131, 0, 0, 390, + 419, 392, 413, 385, 409, 355, 401, 430, 377, 406, + 431, 0, 0, 0, 80, 0, 0, 0, 0, 0, + 0, 0, 0, 96, 0, 404, 425, 375, 405, 407, + 344, 403, 0, 348, 351, 436, 421, 370, 371, 0, + 0, 0, 0, 0, 0, 0, 389, 393, 410, 383, + 0, 0, 0, 0, 0, 0, 0, 0, 368, 0, + 400, 0, 0, 0, 352, 349, 0, 0, 387, 0, + 0, 0, 354, 0, 369, 411, 0, 343, 109, 414, + 420, 384, 210, 424, 382, 381, 427, 146, 0, 162, + 111, 119, 83, 90, 0, 110, 137, 151, 155, 418, + 366, 374, 99, 372, 153, 141, 175, 399, 142, 152, + 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, + 163, 622, 97, 156, 86, 171, 161, 129, 115, 116, + 85, 0, 150, 102, 107, 101, 138, 168, 169, 100, + 193, 91, 180, 88, 341, 179, 136, 166, 172, 130, + 127, 87, 170, 128, 126, 118, 105, 112, 144, 125, + 145, 113, 133, 132, 134, 0, 347, 0, 160, 177, + 194, 94, 362, 165, 184, 185, 186, 187, 188, 189, + 0, 0, 95, 108, 104, 143, 342, 340, 114, 157, + 117, 124, 149, 192, 140, 154, 98, 176, 158, 358, + 361, 356, 357, 395, 396, 432, 433, 434, 412, 353, + 0, 359, 360, 0, 416, 422, 423, 398, 82, 89, + 121, 191, 148, 106, 178, 426, 415, 0, 386, 429, + 364, 378, 437, 379, 380, 408, 350, 394, 139, 376, + 0, 367, 345, 373, 346, 365, 388, 103, 391, 363, + 417, 397, 428, 120, 435, 122, 402, 0, 159, 131, + 0, 0, 390, 419, 392, 413, 385, 409, 355, 401, + 430, 377, 406, 431, 0, 0, 0, 80, 0, 0, + 0, 0, 0, 0, 0, 0, 96, 0, 404, 425, + 375, 405, 407, 344, 403, 0, 348, 351, 436, 421, + 370, 371, 0, 0, 0, 0, 0, 0, 0, 389, + 393, 410, 383, 0, 0, 0, 0, 0, 0, 0, + 0, 368, 0, 400, 0, 0, 0, 352, 349, 0, + 0, 387, 0, 0, 0, 354, 0, 369, 411, 0, + 343, 109, 414, 420, 384, 210, 424, 382, 381, 427, + 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, + 151, 155, 418, 366, 374, 99, 372, 153, 141, 175, + 399, 142, 152, 123, 167, 147, 174, 182, 183, 164, + 181, 190, 84, 163, 332, 97, 156, 86, 171, 161, + 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, + 168, 169, 100, 193, 91, 180, 88, 341, 179, 136, + 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 347, + 0, 160, 177, 194, 94, 362, 165, 184, 185, 186, + 187, 188, 189, 0, 0, 95, 108, 104, 143, 342, + 340, 335, 334, 117, 124, 149, 192, 140, 154, 98, + 176, 158, 358, 361, 356, 357, 395, 396, 432, 433, + 434, 412, 353, 0, 359, 360, 0, 416, 422, 423, + 398, 82, 89, 121, 191, 148, 106, 178, 139, 0, + 0, 0, 0, 270, 0, 0, 0, 103, 0, 267, + 0, 0, 0, 120, 310, 122, 0, 0, 159, 131, + 0, 0, 0, 0, 301, 302, 0, 0, 0, 0, + 0, 0, 856, 0, 54, 0, 0, 268, 289, 288, + 291, 292, 293, 294, 0, 0, 96, 290, 295, 296, + 297, 857, 0, 0, 265, 282, 0, 309, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 279, 280, 0, + 0, 0, 0, 323, 0, 281, 0, 0, 276, 277, + 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 109, 0, 0, 0, 210, 0, 0, 321, 0, + 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, + 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, + 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, + 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, + 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, + 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, + 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, + 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, + 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, + 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, + 176, 158, 311, 322, 317, 318, 315, 316, 314, 313, + 312, 324, 303, 304, 305, 306, 308, 0, 319, 320, + 307, 82, 89, 121, 191, 148, 106, 178, 139, 0, + 0, 789, 0, 270, 0, 0, 0, 103, 0, 267, + 0, 0, 0, 120, 310, 122, 0, 0, 159, 131, + 0, 0, 0, 0, 301, 302, 0, 0, 0, 0, + 0, 0, 0, 0, 54, 0, 0, 268, 289, 288, + 291, 292, 293, 294, 0, 0, 96, 290, 295, 296, + 297, 0, 0, 0, 265, 282, 0, 309, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 279, 280, 261, + 0, 0, 0, 323, 0, 281, 0, 0, 276, 277, + 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 109, 0, 0, 0, 210, 0, 0, 321, 0, + 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, + 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, + 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, + 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, + 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, + 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, + 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, + 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, + 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, + 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, + 176, 158, 311, 322, 317, 318, 315, 316, 314, 313, + 312, 324, 303, 304, 305, 306, 308, 0, 319, 320, + 307, 82, 89, 121, 191, 148, 106, 178, 139, 0, + 0, 0, 0, 270, 0, 0, 0, 103, 0, 267, + 0, 0, 0, 120, 310, 122, 0, 0, 159, 131, + 0, 0, 0, 0, 301, 302, 0, 0, 0, 0, + 0, 0, 0, 0, 54, 0, 498, 268, 289, 288, + 291, 292, 293, 294, 0, 0, 96, 290, 295, 296, + 297, 0, 0, 0, 265, 282, 0, 309, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 279, 280, 0, + 0, 0, 0, 323, 0, 281, 0, 0, 276, 277, + 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 109, 0, 0, 0, 210, 0, 0, 321, 0, + 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, + 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, + 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, + 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, + 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, + 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, + 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, + 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, + 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, + 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, + 176, 158, 311, 322, 317, 318, 315, 316, 314, 313, + 312, 324, 303, 304, 305, 306, 308, 0, 319, 320, + 307, 82, 89, 121, 191, 148, 106, 178, 139, 0, + 0, 0, 0, 270, 0, 0, 0, 103, 0, 267, + 0, 0, 0, 120, 310, 122, 0, 0, 159, 131, + 0, 0, 0, 0, 301, 302, 0, 0, 0, 0, + 0, 0, 0, 0, 54, 0, 0, 268, 289, 288, + 291, 292, 293, 294, 0, 0, 96, 290, 295, 296, + 297, 0, 0, 0, 265, 282, 0, 309, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 279, 280, 261, + 0, 0, 0, 323, 0, 281, 0, 0, 276, 277, + 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 109, 0, 0, 0, 210, 0, 0, 321, 0, + 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, + 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, + 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, + 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, + 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, + 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, + 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, + 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, + 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, + 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, + 176, 158, 311, 322, 317, 318, 315, 316, 314, 313, + 312, 324, 303, 304, 305, 306, 308, 24, 319, 320, + 307, 82, 89, 121, 191, 148, 106, 178, 0, 139, + 0, 0, 0, 0, 270, 0, 0, 0, 103, 0, + 267, 0, 0, 0, 120, 310, 122, 0, 0, 159, + 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, + 0, 0, 0, 0, 0, 54, 0, 0, 268, 289, + 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, + 296, 297, 0, 0, 0, 265, 282, 0, 309, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, + 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, + 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, + 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, + 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, + 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, + 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, + 0, 0, 0, 0, 270, 0, 0, 0, 103, 0, + 267, 0, 0, 0, 120, 310, 122, 0, 0, 159, + 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, + 0, 0, 0, 0, 0, 54, 0, 0, 268, 289, + 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, + 296, 297, 0, 0, 0, 265, 282, 0, 309, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, + 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, + 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, + 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, + 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, + 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, + 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, + 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, + 0, 0, 0, 0, 120, 310, 122, 0, 0, 159, + 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, + 0, 0, 0, 0, 0, 54, 0, 0, 268, 289, + 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, + 296, 297, 0, 0, 0, 0, 282, 0, 309, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, + 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, + 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, + 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, + 175, 1431, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, + 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, + 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, + 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, + 0, 0, 0, 0, 120, 310, 122, 0, 0, 159, + 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, + 0, 0, 0, 0, 0, 54, 0, 498, 268, 289, + 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, + 296, 297, 0, 0, 0, 0, 282, 0, 309, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, + 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, + 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, + 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, + 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, + 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, + 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, + 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, + 0, 0, 0, 0, 120, 310, 122, 0, 0, 159, + 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, + 0, 0, 0, 0, 0, 54, 0, 0, 268, 289, + 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, + 296, 297, 0, 0, 0, 0, 282, 0, 309, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, + 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, + 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, + 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, + 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, + 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, + 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, + 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, + 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, + 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, + 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 532, 531, 541, 542, 534, 535, + 536, 537, 538, 539, 540, 533, 0, 0, 543, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 0, 0, 0, 210, 0, 0, 0, + 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, + 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 82, 89, 121, 191, 148, 106, 178, 139, + 0, 0, 0, 520, 0, 0, 0, 0, 103, 0, + 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, + 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, + 522, 0, 0, 0, 0, 0, 0, 96, 0, 0, + 0, 0, 0, 517, 516, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 518, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 0, 0, 0, 210, 0, 0, 0, + 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, + 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 139, 0, 82, 89, 121, 191, 148, 106, 178, 103, + 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, + 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, - 0, 521, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 516, 515, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 517, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, - 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 74, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 76, - 77, 0, 73, 0, 0, 0, 78, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 0, 0, 0, 840, 0, 0, 0, 82, 102, - 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, - 0, 842, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 24, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 138, 0, 82, 0, 120, 190, 147, 105, 177, - 102, 0, 0, 0, 0, 0, 119, 0, 121, 0, - 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, + 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 109, 76, 77, 0, 73, 0, 0, + 0, 78, 146, 0, 162, 111, 119, 83, 90, 0, + 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, + 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, + 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, + 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, + 101, 138, 168, 169, 100, 193, 91, 180, 88, 92, + 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, + 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, + 0, 0, 0, 160, 177, 194, 94, 0, 165, 184, + 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, + 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, + 154, 98, 176, 158, 0, 75, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 82, 89, 121, 191, 148, 106, 178, + 139, 0, 0, 0, 843, 0, 0, 0, 0, 103, + 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, + 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, + 0, 845, 0, 0, 0, 0, 0, 0, 96, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 109, 0, 0, 0, 210, 0, 0, + 0, 0, 146, 0, 162, 111, 119, 83, 90, 0, + 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, + 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, + 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, + 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, + 101, 138, 168, 169, 100, 193, 91, 180, 88, 92, + 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, + 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, + 0, 0, 0, 160, 177, 194, 94, 0, 165, 184, + 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, + 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, + 154, 98, 176, 158, 0, 0, 0, 0, 0, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 139, 0, 82, 89, 121, 191, 148, 106, 178, + 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, + 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, - 80, 0, 0, 0, 0, 0, 0, 0, 0, 95, + 80, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 108, 0, 0, 0, 209, 0, - 0, 0, 0, 145, 0, 161, 110, 118, 83, 89, - 0, 109, 136, 150, 154, 0, 0, 0, 98, 0, - 152, 140, 174, 0, 141, 151, 122, 166, 146, 173, - 181, 182, 163, 180, 189, 84, 162, 172, 96, 155, - 86, 170, 160, 128, 114, 115, 85, 0, 149, 101, - 106, 100, 137, 167, 168, 99, 192, 90, 179, 88, - 91, 178, 135, 165, 171, 129, 126, 87, 169, 127, - 125, 117, 104, 111, 143, 124, 144, 112, 132, 131, - 133, 0, 0, 0, 159, 176, 193, 93, 0, 164, - 183, 184, 185, 186, 187, 188, 0, 0, 94, 107, - 103, 142, 134, 92, 113, 156, 116, 123, 148, 191, - 139, 153, 97, 175, 157, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, + 0, 0, 0, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, + 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 138, 0, 82, 0, 120, 190, 147, 105, - 177, 102, 0, 0, 0, 0, 0, 119, 0, 121, - 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, + 0, 0, 139, 0, 82, 89, 121, 191, 148, 106, + 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, + 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, - 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, - 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, + 0, 0, 0, 0, 146, 0, 162, 111, 119, 83, + 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, + 0, 153, 141, 175, 0, 142, 152, 123, 167, 147, + 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, + 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, + 102, 107, 101, 138, 168, 169, 100, 193, 91, 180, + 88, 92, 179, 136, 166, 172, 130, 127, 87, 170, + 128, 126, 118, 105, 112, 144, 125, 145, 113, 133, + 132, 134, 0, 0, 0, 160, 177, 194, 94, 0, + 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, + 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, + 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 82, 89, 121, 191, 148, + 106, 178, 139, 0, 0, 0, 843, 0, 0, 0, + 0, 103, 0, 0, 0, 0, 0, 120, 0, 122, + 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 208, 0, 845, 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, + 0, 0, 0, 0, 146, 0, 162, 111, 119, 83, + 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, + 0, 153, 141, 175, 0, 841, 152, 123, 167, 147, + 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, + 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, + 102, 107, 101, 138, 168, 169, 100, 193, 91, 180, + 88, 92, 179, 136, 166, 172, 130, 127, 87, 170, + 128, 126, 118, 105, 112, 144, 125, 145, 113, 133, + 132, 134, 0, 0, 0, 160, 177, 194, 94, 0, + 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, + 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, + 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 139, 0, 82, 89, 121, 191, 148, + 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, + 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 80, 0, 0, 740, 0, 0, 741, 0, + 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, + 210, 0, 0, 0, 0, 146, 0, 162, 111, 119, + 83, 90, 0, 110, 137, 151, 155, 0, 0, 0, + 99, 0, 153, 141, 175, 0, 142, 152, 123, 167, + 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, + 97, 156, 86, 171, 161, 129, 115, 116, 85, 0, + 150, 102, 107, 101, 138, 168, 169, 100, 193, 91, + 180, 88, 92, 179, 136, 166, 172, 130, 127, 87, + 170, 128, 126, 118, 105, 112, 144, 125, 145, 113, + 133, 132, 134, 0, 0, 0, 160, 177, 194, 94, + 0, 165, 184, 185, 186, 187, 188, 189, 0, 0, + 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, + 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 139, 0, 82, 89, 121, 191, + 148, 106, 178, 103, 0, 631, 0, 0, 0, 120, + 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 80, 0, 630, 0, 0, 0, 0, + 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, + 0, 210, 0, 0, 0, 0, 146, 0, 162, 111, + 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, + 0, 99, 0, 153, 141, 175, 0, 142, 152, 123, + 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, + 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, + 0, 150, 102, 107, 101, 138, 168, 169, 100, 193, + 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, + 87, 170, 128, 126, 118, 105, 112, 144, 125, 145, + 113, 133, 132, 134, 0, 0, 0, 160, 177, 194, + 94, 0, 165, 184, 185, 186, 187, 188, 189, 0, + 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, + 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 139, 0, 82, 89, 121, + 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, + 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 54, 0, 0, 208, 0, 0, 0, 0, 0, + 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, + 0, 0, 210, 0, 0, 0, 0, 146, 0, 162, + 111, 119, 83, 90, 0, 110, 137, 151, 155, 0, + 0, 0, 99, 0, 153, 141, 175, 0, 142, 152, + 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, + 163, 173, 97, 156, 86, 171, 161, 129, 115, 116, + 85, 0, 150, 102, 107, 101, 138, 168, 169, 100, + 193, 91, 180, 88, 92, 179, 136, 166, 172, 130, + 127, 87, 170, 128, 126, 118, 105, 112, 144, 125, + 145, 113, 133, 132, 134, 0, 0, 0, 160, 177, + 194, 94, 0, 165, 184, 185, 186, 187, 188, 189, + 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, + 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 139, 0, 82, 89, + 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, + 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, - 0, 0, 0, 0, 145, 0, 161, 110, 118, 83, - 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, - 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, - 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, - 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, - 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, - 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, - 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, - 131, 133, 0, 0, 0, 159, 176, 193, 93, 0, - 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, - 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, - 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 138, 0, 0, - 0, 840, 0, 0, 0, 82, 102, 120, 190, 147, - 105, 177, 119, 0, 121, 0, 0, 158, 130, 0, + 0, 0, 0, 0, 0, 208, 0, 845, 0, 0, + 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 207, 0, 842, 0, - 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, + 0, 0, 0, 210, 0, 0, 0, 0, 146, 0, + 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, + 0, 0, 0, 99, 0, 153, 141, 175, 0, 142, + 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, + 84, 163, 173, 97, 156, 86, 171, 161, 129, 115, + 116, 85, 0, 150, 102, 107, 101, 138, 168, 169, + 100, 193, 91, 180, 88, 92, 179, 136, 166, 172, + 130, 127, 87, 170, 128, 126, 118, 105, 112, 144, + 125, 145, 113, 133, 132, 134, 0, 0, 0, 160, + 177, 194, 94, 0, 165, 184, 185, 186, 187, 188, + 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, + 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 139, 0, 82, + 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, + 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 268, 0, 805, 0, + 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 108, 0, 0, 0, 209, 0, 0, 0, 0, 145, - 0, 161, 110, 118, 83, 89, 0, 109, 136, 150, - 154, 0, 0, 0, 98, 0, 152, 140, 174, 0, - 838, 151, 122, 166, 146, 173, 181, 182, 163, 180, - 189, 84, 162, 172, 96, 155, 86, 170, 160, 128, - 114, 115, 85, 0, 149, 101, 106, 100, 137, 167, - 168, 99, 192, 90, 179, 88, 91, 178, 135, 165, - 171, 129, 126, 87, 169, 127, 125, 117, 104, 111, - 143, 124, 144, 112, 132, 131, 133, 0, 0, 0, - 159, 176, 193, 93, 0, 164, 183, 184, 185, 186, - 187, 188, 0, 0, 94, 107, 103, 142, 134, 92, - 113, 156, 116, 123, 148, 191, 139, 153, 97, 175, - 157, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 138, 0, 0, 0, 0, 0, 0, 0, - 82, 102, 120, 190, 147, 105, 177, 119, 0, 121, - 0, 0, 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 80, 0, 0, 737, 0, 0, 738, 0, 0, - 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 109, 0, 0, 0, 210, 0, 0, 0, 0, 146, + 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, + 155, 0, 0, 0, 99, 0, 153, 141, 175, 0, + 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, + 190, 84, 163, 173, 97, 156, 86, 171, 161, 129, + 115, 116, 85, 0, 150, 102, 107, 101, 138, 168, + 169, 100, 193, 91, 180, 88, 92, 179, 136, 166, + 172, 130, 127, 87, 170, 128, 126, 118, 105, 112, + 144, 125, 145, 113, 133, 132, 134, 0, 0, 0, + 160, 177, 194, 94, 0, 165, 184, 185, 186, 187, + 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, + 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, + 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, + 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, + 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 108, 0, 0, 0, 209, - 0, 0, 0, 0, 145, 0, 161, 110, 118, 83, - 89, 0, 109, 136, 150, 154, 0, 0, 0, 98, - 0, 152, 140, 174, 0, 141, 151, 122, 166, 146, - 173, 181, 182, 163, 180, 189, 84, 162, 172, 96, - 155, 86, 170, 160, 128, 114, 115, 85, 0, 149, - 101, 106, 100, 137, 167, 168, 99, 192, 90, 179, - 88, 91, 178, 135, 165, 171, 129, 126, 87, 169, - 127, 125, 117, 104, 111, 143, 124, 144, 112, 132, - 131, 133, 0, 0, 0, 159, 176, 193, 93, 0, - 164, 183, 184, 185, 186, 187, 188, 0, 0, 94, - 107, 103, 142, 134, 92, 113, 156, 116, 123, 148, - 191, 139, 153, 97, 175, 157, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 138, 0, 82, 0, 120, 190, 147, - 105, 177, 102, 0, 630, 0, 0, 0, 119, 0, - 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 268, 0, 801, + 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 80, 0, 629, 0, 0, 0, 0, 0, - 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, - 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, - 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, - 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, - 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, - 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, - 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, - 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, - 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, - 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, - 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, - 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, - 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, - 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, - 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 0, 207, 0, 0, - 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 109, 0, 0, 0, 210, 0, 0, 0, 0, + 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, + 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, + 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, + 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, + 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, + 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, + 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, + 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, + 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, + 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, + 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, + 0, 82, 89, 121, 191, 148, 106, 178, 103, 0, + 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, + 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, + 522, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, - 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, - 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 207, 0, 842, 0, 0, 0, 0, 0, - 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 109, 0, 0, 0, 210, 0, 0, 0, + 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, + 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 139, 82, 89, 121, 191, 148, 106, 178, 604, + 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, + 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, - 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, - 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, - 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, - 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, - 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, - 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, - 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, - 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, - 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, - 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, - 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, - 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, - 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, - 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 267, 0, 802, - 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, + 208, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 138, 0, 0, 0, 0, 0, 0, - 0, 82, 102, 120, 190, 147, 105, 177, 119, 0, - 121, 0, 0, 158, 130, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 267, 0, 798, 0, 0, 0, 0, 0, - 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, + 0, 0, 0, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, + 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, + 0, 0, 139, 0, 82, 89, 121, 191, 148, 106, + 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, + 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 108, 0, 0, 0, - 209, 0, 0, 0, 0, 145, 0, 161, 110, 118, - 83, 89, 0, 109, 136, 150, 154, 0, 0, 0, - 98, 0, 152, 140, 174, 0, 141, 151, 122, 166, - 146, 173, 181, 182, 163, 180, 189, 84, 162, 172, - 96, 155, 86, 170, 160, 128, 114, 115, 85, 0, - 149, 101, 106, 100, 137, 167, 168, 99, 192, 90, - 179, 88, 91, 178, 135, 165, 171, 129, 126, 87, - 169, 127, 125, 117, 104, 111, 143, 124, 144, 112, - 132, 131, 133, 0, 0, 0, 159, 176, 193, 93, - 0, 164, 183, 184, 185, 186, 187, 188, 0, 0, - 94, 107, 103, 142, 134, 92, 113, 156, 116, 123, - 148, 191, 139, 153, 97, 175, 157, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, - 0, 0, 0, 0, 0, 0, 82, 102, 120, 190, - 147, 105, 177, 119, 0, 121, 0, 0, 158, 130, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 80, 0, 521, - 0, 0, 0, 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, + 0, 0, 0, 0, 146, 0, 162, 111, 119, 83, + 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, + 0, 153, 141, 175, 0, 142, 152, 123, 167, 147, + 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, + 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, + 102, 107, 101, 138, 168, 169, 100, 193, 91, 180, + 88, 92, 179, 136, 166, 172, 130, 127, 87, 170, + 128, 126, 118, 105, 112, 144, 125, 145, 113, 133, + 132, 134, 0, 0, 0, 160, 177, 194, 94, 0, + 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, + 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, + 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 139, 0, 82, 89, 121, 191, 148, + 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, + 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, + 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 108, 0, 0, 0, 209, 0, 0, 0, 0, - 145, 0, 161, 110, 118, 83, 89, 0, 109, 136, - 150, 154, 0, 0, 0, 98, 0, 152, 140, 174, - 0, 141, 151, 122, 166, 146, 173, 181, 182, 163, - 180, 189, 84, 162, 172, 96, 155, 86, 170, 160, - 128, 114, 115, 85, 0, 149, 101, 106, 100, 137, - 167, 168, 99, 192, 90, 179, 88, 91, 178, 135, - 165, 171, 129, 126, 87, 169, 127, 125, 117, 104, - 111, 143, 124, 144, 112, 132, 131, 133, 0, 0, - 0, 159, 176, 193, 93, 0, 164, 183, 184, 185, - 186, 187, 188, 0, 0, 94, 107, 103, 142, 134, - 92, 113, 156, 116, 123, 148, 191, 139, 153, 97, - 175, 157, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 82, 0, 120, 190, 147, 105, 177, 603, 102, - 0, 0, 0, 0, 0, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 109, 0, 205, 0, + 210, 0, 0, 0, 0, 146, 0, 162, 111, 119, + 83, 90, 0, 110, 137, 151, 155, 0, 0, 0, + 99, 0, 153, 141, 175, 0, 142, 152, 123, 167, + 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, + 97, 156, 86, 171, 161, 129, 115, 116, 85, 0, + 150, 102, 107, 101, 138, 168, 169, 100, 193, 91, + 180, 88, 92, 179, 136, 166, 172, 130, 127, 87, + 170, 128, 126, 118, 105, 112, 144, 125, 145, 113, + 133, 132, 134, 0, 0, 0, 160, 177, 194, 94, + 0, 165, 184, 185, 186, 187, 188, 189, 0, 0, + 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, + 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 139, 0, 82, 89, 121, 191, + 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, + 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, + 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 326, 0, - 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, - 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 207, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, + 0, 210, 0, 0, 0, 0, 146, 0, 162, 111, + 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, + 0, 99, 0, 153, 141, 175, 0, 142, 152, 123, + 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, + 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, + 0, 150, 102, 107, 101, 138, 168, 169, 100, 193, + 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, + 87, 170, 128, 126, 118, 105, 112, 144, 125, 145, + 113, 133, 132, 134, 0, 0, 0, 160, 177, 194, + 94, 0, 165, 184, 185, 186, 187, 188, 189, 0, + 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, + 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, - 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 204, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, - 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 138, 0, 0, 0, 0, 0, 0, 0, 82, 102, - 120, 190, 147, 105, 177, 119, 0, 121, 0, 0, - 158, 130, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 207, - 0, 0, 0, 0, 0, 0, 0, 0, 95, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 108, 0, 0, 0, 209, 0, 0, - 0, 0, 145, 0, 161, 110, 118, 83, 89, 0, - 109, 136, 150, 154, 0, 0, 0, 98, 0, 152, - 140, 174, 0, 141, 151, 122, 166, 146, 173, 181, - 182, 163, 180, 189, 84, 162, 172, 96, 155, 86, - 170, 160, 128, 114, 115, 85, 0, 149, 101, 106, - 100, 137, 167, 168, 99, 192, 90, 179, 88, 91, - 178, 135, 165, 171, 129, 126, 87, 169, 127, 125, - 117, 104, 111, 143, 124, 144, 112, 132, 131, 133, - 0, 0, 0, 159, 176, 193, 93, 0, 164, 183, - 184, 185, 186, 187, 188, 0, 0, 94, 107, 103, - 142, 134, 92, 113, 156, 116, 123, 148, 191, 139, - 153, 97, 175, 157, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 138, 0, 0, 0, 0, - 0, 0, 0, 82, 102, 120, 190, 147, 105, 177, - 119, 0, 121, 0, 0, 158, 130, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 267, 0, 0, 0, 0, 0, - 0, 0, 0, 95, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 108, 0, - 0, 0, 209, 0, 0, 0, 0, 145, 0, 161, - 110, 118, 83, 89, 0, 109, 136, 150, 154, 0, - 0, 0, 98, 0, 152, 140, 174, 0, 141, 151, - 122, 166, 146, 173, 181, 182, 163, 180, 189, 84, - 162, 172, 96, 155, 86, 170, 160, 128, 114, 115, - 85, 0, 149, 101, 106, 100, 137, 167, 168, 99, - 192, 90, 179, 88, 91, 178, 135, 165, 171, 129, - 126, 87, 169, 127, 125, 117, 104, 111, 143, 124, - 144, 112, 132, 131, 133, 0, 0, 0, 159, 176, - 193, 93, 0, 164, 183, 184, 185, 186, 187, 188, - 0, 0, 94, 107, 103, 142, 134, 92, 113, 156, - 116, 123, 148, 191, 139, 153, 97, 175, 157, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 82, 0, - 120, 190, 147, 105, 177, + 0, 0, 0, 0, 0, 139, 0, 82, 89, 121, + 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, + 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 208, 0, 0, 0, 0, 0, + 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, + 0, 0, 210, 0, 0, 0, 0, 146, 0, 162, + 111, 119, 83, 90, 0, 110, 137, 151, 155, 0, + 0, 0, 99, 0, 153, 141, 175, 0, 142, 152, + 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, + 163, 173, 97, 156, 86, 171, 161, 129, 115, 116, + 85, 0, 150, 102, 107, 101, 138, 168, 169, 100, + 193, 91, 180, 88, 92, 179, 136, 166, 172, 130, + 127, 87, 170, 128, 126, 118, 105, 112, 144, 125, + 145, 113, 133, 132, 134, 0, 0, 0, 160, 177, + 194, 94, 0, 165, 184, 185, 186, 187, 188, 189, + 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, + 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 139, 0, 82, 89, + 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, + 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 268, 0, 0, 0, 0, + 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, + 0, 0, 0, 210, 0, 0, 0, 0, 146, 0, + 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, + 0, 0, 0, 99, 0, 153, 141, 175, 0, 142, + 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, + 84, 163, 173, 97, 156, 86, 171, 161, 129, 115, + 116, 85, 0, 150, 102, 107, 101, 138, 168, 169, + 100, 193, 91, 180, 88, 92, 179, 136, 166, 172, + 130, 127, 87, 170, 128, 126, 118, 105, 112, 144, + 125, 145, 113, 133, 132, 134, 0, 0, 0, 160, + 177, 194, 94, 0, 165, 184, 185, 186, 187, 188, + 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, + 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, + 89, 121, 191, 148, 106, 178, } var yyPact = [...]int{ - 2324, -1000, -192, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 2429, -1000, -192, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 850, 890, -1000, -1000, -1000, -1000, -1000, -1000, + 333, 8382, 40, 121, 8, 11775, 115, 1357, 12257, -1000, + 10, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -66, -81, + -1000, 658, -1000, -1000, -1000, -1000, -1000, 843, 848, 721, + 834, 757, -1000, 6390, 71, 71, 11534, 5390, -1000, -1000, + 234, 12257, 107, 12257, -155, 67, 67, 67, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 897, 951, -1000, -1000, -1000, -1000, -1000, -1000, - 297, 8637, 30, 107, -19, 11952, 106, 152, 12422, -1000, - 2, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -97, -98, - -1000, 694, -1000, -1000, -1000, -1000, -1000, 883, 894, 722, - 885, 779, -1000, 6690, 64, 64, 11717, 5690, -1000, -1000, - 234, 12422, 96, 12422, -156, 62, 62, 62, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -2029,23 +2014,23 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 114, 12257, 307, -1000, 12257, + 64, 471, 64, 64, 64, 12257, -1000, 150, -1000, -1000, + -1000, 12257, 467, 794, 3286, 46, 3286, -1000, 3286, 3286, + -1000, 3286, 16, 3286, -62, 863, -1000, -1000, -1000, -1000, + -37, -1000, 3286, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 441, 803, 6891, 6891, + 850, -1000, 658, -1000, -1000, -1000, 780, -1000, -1000, 260, + 876, -1000, 8141, 149, -1000, 6891, 1820, 676, -1000, -1000, + 676, -1000, -1000, 133, -1000, -1000, 7641, 7641, 7641, 7641, + 7641, 7641, 7641, 7641, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 676, -1000, + 6641, 676, 676, 676, 676, 676, 676, 676, 676, 6891, + 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, + 676, 676, 676, 676, 676, 11293, 10087, 12257, 622, -1000, + 659, 5127, -86, -1000, -1000, -1000, 203, 9846, -1000, -1000, + -1000, 793, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 105, 12422, 248, -1000, 12422, 60, - 561, 60, 60, 60, 12422, -1000, 145, -1000, -1000, -1000, - 12422, 554, 814, 3586, 45, 3586, -1000, 3586, 3586, -1000, - 3586, 14, 3586, -63, 932, -1000, -1000, -1000, -1000, -44, - -1000, 3586, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 462, 846, 7191, 7191, 897, - -1000, 694, -1000, -1000, -1000, 842, -1000, -1000, 308, 938, - -1000, 8402, 141, -1000, 7191, 1367, 675, -1000, -1000, 675, - -1000, -1000, 128, -1000, -1000, 7923, 7923, 7923, 7923, 7923, - 7923, 7923, 7923, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 675, -1000, 6941, - 675, 675, 675, 675, 675, 675, 675, 675, 7191, 675, - 675, 675, 675, 675, 675, 675, 675, 675, 675, 675, - 675, 675, 675, 675, 11482, 10300, 12422, 629, -1000, 667, - 5427, -135, -1000, -1000, -1000, 219, 10065, -1000, -1000, -1000, - 813, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -2053,131 +2038,131 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 595, 12257, + -1000, 2218, -1000, 461, 3286, 80, 459, 221, 457, 12257, + 12257, 3286, 24, 57, 113, 12257, 664, 78, 12257, 829, + 720, 12257, 455, 448, -1000, 4864, -1000, 3286, 3286, -1000, + -1000, -1000, 3286, 3286, 3286, 3286, 3286, 3286, -1000, -1000, + -1000, -1000, 3286, 3286, -1000, 872, 263, -1000, -1000, -1000, + -1000, 6891, -1000, 719, -1000, -1000, -1000, -1000, -1000, -1000, + 885, 175, 523, 147, 661, -1000, 447, 843, 441, 757, + 9605, 701, -1000, -1000, 12257, -1000, 6891, 6891, 379, -1000, + 11051, -1000, -1000, 3812, 184, 7641, 352, 231, 7641, 7641, + 7641, 7641, 7641, 7641, 7641, 7641, 7641, 7641, 7641, 7641, + 7641, 7641, 7641, 362, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 445, -1000, 658, 548, 548, 159, 159, 159, + 159, 159, 159, 159, 7891, 5890, 441, 593, 204, 6641, + 6390, 6390, 6891, 6891, 10810, 10569, 6390, 836, 210, 204, + 12498, -1000, -1000, 7391, -1000, -1000, -1000, -1000, -1000, 441, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 12016, 12016, 6390, + 6390, 6390, 6390, 35, 12257, -1000, 549, 690, -1000, -1000, + -1000, 831, 9114, 9364, 35, 600, 10087, 12257, -1000, -1000, + 4601, 659, -86, 625, -1000, -129, -91, 5640, 142, -1000, + -1000, -1000, -1000, 3023, 212, 503, 279, -53, -1000, -1000, + -1000, 691, -1000, 691, 691, 691, 691, -17, -17, -17, + -17, -1000, -1000, -1000, -1000, -1000, 705, 704, -1000, 691, + 691, 691, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 559, 12422, -1000, - 2414, -1000, 552, 3586, 73, 551, 254, 550, 12422, 12422, - 3586, 20, 53, 104, 12422, 671, 71, 12422, 873, 725, - 12422, 549, 548, -1000, 5164, -1000, 3586, 3586, -1000, -1000, - -1000, 3586, 3586, 3586, 3586, 3586, 3586, -1000, -1000, -1000, - -1000, 3586, 3586, -1000, 937, 263, -1000, -1000, -1000, -1000, - 7191, -1000, 723, -1000, -1000, -1000, -1000, -1000, -1000, 946, - 185, 452, 140, 670, -1000, 247, 883, 462, 779, 9824, - 735, -1000, -1000, 12422, -1000, 7191, 7191, 378, -1000, 11240, - -1000, -1000, 4112, 170, 7923, 405, 269, 7923, 7923, 7923, - 7923, 7923, 7923, 7923, 7923, 7923, 7923, 7923, 7923, 7923, - 7923, 7923, 383, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 546, -1000, 694, 509, 509, 159, 159, 159, 159, - 159, 159, 159, 8167, 6190, 462, 545, 313, 6941, 6690, - 6690, 7191, 7191, 11005, 10770, 6690, 876, 245, 313, 12657, - -1000, -1000, 7679, -1000, -1000, -1000, -1000, -1000, 462, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 12187, 12187, 6690, 6690, - 6690, 6690, 35, 12422, -1000, 659, 845, -1000, -1000, -1000, - 851, 9354, 9589, 35, 652, 10300, 12422, -1000, -1000, 4901, - 667, -135, 649, -1000, -122, -120, 5940, 148, -1000, -1000, - -1000, -1000, 3323, 211, 565, 335, -77, -1000, -1000, -1000, - 678, -1000, 678, 678, 678, 678, -27, -27, -27, -27, - -1000, -1000, -1000, -1000, -1000, 703, 702, -1000, 678, 678, - 678, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 699, 699, 699, - 685, 685, 708, -1000, 12422, 3586, 872, 3586, -1000, 86, - -1000, 12187, 12187, 12422, 12422, 114, 12422, 12422, 664, -1000, - 12422, 3586, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 12422, 310, 12422, - 12422, 313, 12422, -1000, 798, 7191, 7191, 4638, 7191, -1000, - -1000, -1000, 846, -1000, 876, 928, -1000, 806, 805, 6690, - -1000, -1000, 170, 289, -1000, -1000, 443, -1000, -1000, -1000, - -1000, 136, 675, -1000, 1139, -1000, -1000, -1000, -1000, 405, - 7923, 7923, 7923, 325, 1139, 1926, 458, 831, 159, 334, - 334, 157, 157, 157, 157, 157, 387, 387, -1000, -1000, - -1000, 462, -1000, -1000, -1000, 462, 6690, 662, -1000, -1000, - 7191, -1000, 462, 535, 535, 390, 261, 692, 679, -1000, - 132, 672, 636, 535, 6690, 327, -1000, 7191, 462, -1000, - 1062, 661, 657, 535, 462, 535, 535, 604, 675, -1000, - 12657, 10300, 10300, 10300, 10300, 10300, -1000, 747, 746, -1000, - 786, 732, 787, 12422, -1000, 539, 9354, 143, 675, -1000, - 10535, -1000, -1000, 929, 10300, 607, -1000, -1000, 649, -135, - -128, -1000, -1000, -1000, -1000, 313, -1000, 407, 644, 3060, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 698, 518, -1000, - 844, 194, 197, 516, 841, -1000, -1000, -1000, 817, -1000, - 264, -79, -1000, -1000, 348, -27, -27, -1000, -1000, 148, - 812, 148, 148, 148, 456, 456, -1000, -1000, -1000, -1000, - 344, -1000, -1000, -1000, 328, -1000, 720, 12187, 3586, -1000, - -1000, -1000, -1000, 179, 179, 218, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 32, 705, -1000, - -1000, -1000, 12, 10, 66, -1000, 3586, -1000, 263, -1000, - 422, 7191, -1000, -1000, -1000, 796, 313, 313, 131, -1000, - -1000, 12422, -1000, -1000, -1000, -1000, 621, -1000, -1000, -1000, - 3849, 6690, -1000, 325, 1139, 1621, -1000, 7923, 7923, -1000, - -1000, 535, 6690, 313, -1000, -1000, -1000, 67, 383, 67, - 7923, 7923, 7923, 7923, 4638, 7923, 7923, 7923, 7923, -170, - 608, 221, -1000, 7191, 226, -1000, -1000, 7923, 7923, -1000, - -1000, -1000, -1000, 715, 12657, 675, -1000, 9113, 12187, 632, - -1000, 207, 845, 697, 714, 809, -1000, -1000, -1000, -1000, - 740, -1000, 738, -1000, -1000, -1000, -1000, -1000, 93, 91, - 84, 12187, -1000, 897, 7191, 607, -1000, -1000, -1000, -126, - -143, -1000, -1000, -1000, 3323, -1000, 3323, 12187, 49, -1000, - 516, 516, -1000, -1000, -1000, 687, 713, 7923, -1000, -1000, - -1000, 540, 148, 148, -1000, 206, -1000, -1000, -1000, 533, - -1000, 528, 602, 523, 12422, -1000, -1000, -1000, -1000, -1000, + 700, 700, 700, 693, 693, 675, -1000, 12257, 3286, 827, + 3286, -1000, 91, -1000, 12016, 12016, 12257, 12257, 128, 12257, + 12257, 656, -1000, 12257, 3286, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, 12422, -1000, -1000, -1000, -1000, -1000, 12187, -179, 506, - 12187, 12187, 12422, -1000, 310, -1000, 313, -1000, 4375, -1000, - 929, 10300, -1000, -1000, 462, -1000, 7923, 1139, 1139, -1000, - -1000, 462, 678, 678, -1000, 678, 685, -1000, 678, -7, - 678, -8, 462, 462, 1643, 1774, 1577, 1739, -1000, 1389, - 1544, 571, 1156, 675, -163, -1000, 313, 7191, 1418, 402, - -1000, 847, 584, 582, -1000, -1000, 6440, 462, 494, 123, - 492, -1000, 897, 12657, 7191, -1000, -1000, 7191, 682, -1000, - 7191, -1000, -1000, -1000, 675, 675, 675, 492, 883, 313, - -1000, -1000, -1000, -1000, 3060, -1000, 490, -1000, 678, -1000, - -1000, -1000, 12187, -58, 944, 1139, -1000, -1000, -1000, -1000, - -1000, -27, 419, -27, 321, -1000, 317, 3586, -1000, -1000, - -1000, -1000, 850, -1000, 4375, -1000, -1000, 677, -1000, -1000, - -1000, 927, 594, -1000, 1139, -1000, -1000, 99, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 7923, 7923, -1000, - 7923, 7923, -1000, 7923, 7923, -1000, 7923, 7923, 7923, 462, - 401, 313, 7923, 7923, 840, -1000, 675, -1000, -1000, 625, - 12187, 12187, -1000, 12187, 883, -1000, 313, 313, 12187, 313, - 12187, 12187, 12187, 8872, -1000, 160, 12187, -1000, 487, -1000, - 167, -1000, -100, 148, -1000, 148, 536, 472, -1000, 675, - 588, -1000, 199, 12187, 907, 891, -1000, -1000, 1062, 1062, - 1062, 1062, 1062, 1062, 1062, 1062, 29, -1000, -1000, 1062, - 1062, 942, -1000, 675, -1000, 694, 121, -1000, -1000, -1000, - 481, 478, 478, 478, 143, 160, -1000, 466, 198, 372, - -1000, 40, 12187, 281, 821, -1000, 819, -1000, -1000, -1000, - -1000, -1000, 31, 4375, 3323, 476, -1000, 7191, 7191, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 462, 44, -184, - -1000, -1000, 12657, 582, 462, 12187, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, 294, -1000, -1000, 12422, -1000, -1000, 270, - -1000, -1000, 471, -1000, 12187, -1000, -1000, 705, 313, 573, - -1000, 782, -173, -187, 547, -1000, -1000, -1000, 676, -1000, - -1000, 31, 804, -179, -1000, 762, -1000, 12187, -1000, 26, - -1000, -180, 461, 17, -185, 712, 675, -188, 711, -1000, - 936, 7435, -1000, -1000, 941, 151, 151, 1062, 462, -1000, - -1000, -1000, 54, 362, -1000, -1000, -1000, -1000, -1000, -1000, + 12257, 256, 12257, 12257, 204, 12257, -1000, 714, 6891, 6891, + 4338, 6891, -1000, -1000, -1000, 803, -1000, 836, 847, -1000, + 786, 785, 6390, -1000, -1000, 184, 284, -1000, -1000, 440, + -1000, -1000, -1000, -1000, 145, 676, -1000, 2206, -1000, -1000, + -1000, -1000, 352, 7641, 7641, 7641, 710, 2206, 2189, 335, + 473, 159, 261, 261, 168, 168, 168, 168, 168, 388, + 388, -1000, -1000, -1000, 441, -1000, -1000, -1000, 441, 6390, + 632, -1000, -1000, 6891, -1000, 441, 582, 582, 391, 460, + 674, 670, -1000, 144, 655, 654, 582, 6390, 225, -1000, + 6891, 441, -1000, 1936, 631, 627, 582, 441, 582, 582, + 638, 676, -1000, 12498, 10087, 10087, 10087, 10087, 10087, -1000, + 747, 745, -1000, 744, 741, 732, 12257, -1000, 584, 9114, + 143, 676, -1000, 10328, -1000, -1000, 862, 10087, 648, -1000, + -1000, 625, -86, -80, -1000, -1000, -1000, -1000, 204, -1000, + 384, 624, 2760, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 699, 442, -1000, 815, 185, 207, 436, 813, -1000, -1000, + -1000, 806, -1000, 240, -57, -1000, -1000, 366, -17, -17, + -1000, -1000, 142, 791, 142, 142, 142, 420, 420, -1000, + -1000, -1000, -1000, 365, -1000, -1000, -1000, 315, -1000, 718, + 12016, 3286, -1000, -1000, -1000, -1000, 182, 182, 230, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 34, 550, -1000, -1000, -1000, 21, 20, 73, -1000, 3286, + -1000, 263, -1000, 411, 6891, -1000, -1000, -1000, 761, 204, + 204, 141, -1000, -1000, 12257, -1000, -1000, -1000, -1000, 647, + -1000, -1000, -1000, 3549, 6390, -1000, 710, 2206, 1951, -1000, + 7641, 7641, -1000, -1000, 582, 6390, 204, -1000, -1000, -1000, + 43, 362, 43, 7641, 7641, 7641, 7641, 4338, 7641, 7641, + 7641, 7641, -169, 652, 209, -1000, 6891, 434, -1000, -1000, + 7641, 7641, -1000, -1000, -1000, -1000, 715, 12498, 676, -1000, + 8873, 12016, 651, -1000, 202, 690, 698, 713, 952, -1000, + -1000, -1000, -1000, 743, -1000, 731, -1000, -1000, -1000, -1000, + -1000, 106, 102, 94, 12016, -1000, 850, 6891, 648, -1000, + -1000, -1000, -135, -141, -1000, -1000, -1000, 3023, -1000, 3023, + 12016, 51, -1000, 436, 436, -1000, -1000, -1000, 694, 712, + 7641, -1000, -1000, -1000, 491, 142, 142, -1000, 208, -1000, + -1000, -1000, 572, -1000, 569, 621, 564, 12257, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 12257, -1000, -1000, -1000, -1000, -1000, + 12016, -179, 424, 12016, 12016, 12257, -1000, 256, -1000, 204, + -1000, 4075, -1000, 862, 10087, -1000, -1000, 441, -1000, 7641, + 2206, 2206, -1000, -1000, 441, 691, 691, -1000, 691, 693, + -1000, 691, 1, 691, 0, 441, 441, 1887, 2174, 1729, + 2156, -1000, 1636, 1980, 1346, 1657, 676, -162, -1000, 204, + 6891, 2067, 2017, -1000, 818, 542, 601, -1000, -1000, 6140, + 441, 546, 138, 534, -1000, 850, 12498, 6891, -1000, -1000, + 6891, 692, -1000, 6891, -1000, -1000, -1000, 676, 676, 676, + 534, 843, 204, -1000, -1000, -1000, -1000, 2760, -1000, 531, + -1000, 691, -1000, -1000, -1000, 12016, -49, 883, 2206, -1000, + -1000, -1000, -1000, -1000, -17, 408, -17, 312, -1000, 280, + 3286, -1000, -1000, -1000, -1000, 821, -1000, 4075, -1000, -1000, + 686, -1000, -1000, -1000, 858, 619, -1000, 2206, -1000, -1000, + 111, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 7641, 7641, -1000, 7641, 7641, -1000, 7641, 7641, -1000, 7641, + 7641, 7641, 441, 399, 204, 7641, 7641, 811, -1000, 676, + -1000, -1000, 639, 12016, 12016, -1000, 12016, 843, -1000, 204, + 204, 12016, 204, 12016, 12016, 12016, 8632, -1000, 137, 12016, + -1000, 529, -1000, 188, -1000, -106, 142, -1000, 142, 488, + 475, -1000, 676, 602, -1000, 200, 12016, 854, 846, -1000, + -1000, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 15, + -1000, -1000, 1936, 1936, 881, -1000, 676, -1000, 658, 122, + -1000, -1000, -1000, 508, 502, 502, 502, 143, 137, -1000, + 309, 199, 369, -1000, 47, 12016, 236, 810, -1000, 804, + -1000, -1000, -1000, -1000, -1000, 33, 4075, 3023, 487, -1000, + 6891, 6891, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 441, 42, -182, -1000, -1000, 12498, 601, 441, 12016, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 269, -1000, -1000, 12257, + -1000, -1000, 308, -1000, -1000, 484, -1000, 12016, -1000, -1000, + 550, 204, 599, -1000, 760, -177, -186, 537, -1000, -1000, + -1000, 683, -1000, -1000, 33, 781, -179, -1000, 753, -1000, + 12016, -1000, 30, -1000, -180, 482, 28, -184, 711, 676, + -187, 708, -1000, 867, 7141, -1000, -1000, 869, 198, 198, + 1936, 441, -1000, -1000, -1000, 56, 306, -1000, -1000, -1000, + -1000, -1000, -1000, } var yyPgo = [...]int{ - 0, 1190, 30, 480, 1189, 1188, 1187, 1184, 1183, 1181, - 1179, 1176, 1174, 1173, 1172, 1171, 1168, 1167, 1153, 1151, - 1150, 1148, 1147, 1146, 1145, 1143, 111, 1142, 1140, 1137, - 64, 1136, 73, 1135, 1131, 49, 184, 56, 44, 1709, - 1125, 26, 61, 58, 1123, 38, 1122, 1121, 71, 1119, - 52, 1114, 1113, 1619, 1111, 1110, 11, 33, 1107, 1106, - 1105, 1100, 69, 1004, 1097, 1096, 20, 1095, 1091, 77, - 1090, 57, 12, 14, 13, 18, 1089, 304, 6, 1088, - 53, 1082, 1081, 1080, 1078, 19, 1074, 55, 1073, 23, - 54, 1072, 29, 63, 35, 24, 7, 75, 59, 1071, - 22, 60, 48, 1070, 1068, 456, 1066, 1065, 45, 1063, - 1059, 28, 154, 376, 1058, 1056, 1055, 1052, 43, 0, - 519, 15, 65, 1051, 1050, 1049, 1690, 70, 51, 17, - 1044, 41, 178, 42, 1041, 1040, 40, 1036, 1035, 1034, - 1033, 1031, 1030, 1027, 258, 1026, 1025, 1024, 120, 21, - 1023, 1022, 66, 27, 1016, 1015, 1014, 46, 62, 1005, - 1003, 50, 25, 999, 998, 997, 990, 988, 34, 10, - 985, 16, 983, 9, 982, 37, 981, 5, 980, 8, - 979, 2, 978, 4, 47, 3, 977, 1, 973, 972, - 492, 791, 958, 957, 99, + 0, 1125, 30, 457, 1123, 1122, 1121, 1120, 1118, 1114, + 1113, 1111, 1110, 1109, 1103, 1102, 1100, 1094, 1093, 1091, + 1090, 1089, 1087, 1085, 1084, 1083, 97, 1082, 1081, 1076, + 65, 1071, 71, 1068, 1067, 47, 59, 45, 40, 1207, + 1065, 25, 56, 102, 1064, 34, 1060, 1052, 75, 1049, + 53, 1045, 1044, 429, 1043, 1042, 13, 33, 1040, 1039, + 1038, 1037, 66, 886, 1036, 1033, 16, 1032, 1031, 101, + 1029, 55, 3, 12, 21, 22, 1028, 229, 7, 1027, + 52, 1024, 1021, 1018, 1008, 29, 1007, 58, 1006, 17, + 57, 1002, 24, 63, 35, 19, 5, 73, 61, 999, + 15, 62, 54, 993, 990, 461, 987, 986, 46, 985, + 984, 26, 166, 377, 983, 980, 979, 978, 38, 0, + 498, 128, 70, 977, 970, 969, 1490, 69, 49, 18, + 965, 42, 1493, 43, 963, 962, 37, 961, 960, 959, + 957, 956, 954, 953, 134, 952, 951, 949, 20, 41, + 948, 946, 60, 23, 945, 942, 941, 48, 64, 939, + 935, 51, 44, 933, 932, 930, 924, 923, 27, 9, + 922, 14, 920, 10, 918, 28, 916, 2, 915, 11, + 914, 6, 913, 4, 50, 1, 908, 8, 901, 900, + 77, 494, 897, 896, 94, } var yyR1 = [...]int{ @@ -2190,62 +2175,62 @@ var yyR1 = [...]int{ 134, 134, 11, 11, 11, 11, 11, 11, 11, 183, 183, 182, 181, 181, 180, 180, 179, 17, 164, 166, 166, 165, 165, 165, 165, 158, 137, 137, 137, 137, - 140, 140, 138, 138, 138, 138, 138, 138, 138, 139, - 139, 139, 139, 139, 141, 141, 141, 141, 141, 142, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 142, 143, 143, 143, 143, 143, 143, - 143, 143, 157, 157, 144, 144, 152, 152, 153, 153, - 153, 150, 150, 151, 151, 154, 154, 154, 146, 146, - 147, 147, 155, 155, 148, 148, 148, 149, 149, 149, - 156, 156, 156, 156, 156, 145, 145, 159, 159, 174, - 174, 173, 173, 173, 163, 163, 170, 170, 170, 170, - 170, 161, 161, 162, 162, 172, 172, 171, 160, 160, - 175, 175, 175, 175, 186, 187, 185, 185, 185, 185, - 185, 167, 167, 167, 168, 168, 168, 169, 169, 169, - 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 184, 184, 184, 184, 184, 184, 184, - 184, 184, 184, 184, 178, 176, 176, 177, 177, 13, - 18, 18, 14, 14, 14, 14, 14, 15, 15, 19, + 140, 140, 138, 138, 138, 138, 138, 138, 138, 138, + 138, 139, 139, 139, 139, 139, 141, 141, 141, 141, + 141, 142, 142, 142, 142, 142, 142, 142, 142, 142, + 142, 142, 142, 142, 142, 142, 143, 143, 143, 143, + 143, 143, 143, 143, 157, 157, 144, 144, 152, 152, + 153, 153, 153, 150, 150, 151, 151, 154, 154, 154, + 146, 146, 147, 147, 155, 155, 148, 148, 148, 149, + 149, 149, 156, 156, 156, 156, 156, 145, 145, 159, + 159, 174, 174, 173, 173, 173, 163, 163, 170, 170, + 170, 170, 170, 161, 161, 162, 162, 172, 172, 171, + 160, 160, 175, 175, 175, 175, 186, 187, 185, 185, + 185, 185, 185, 167, 167, 167, 168, 168, 168, 169, + 169, 169, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 184, 184, 184, 184, 184, + 184, 184, 184, 184, 184, 184, 178, 176, 176, 177, + 177, 13, 18, 18, 14, 14, 14, 14, 14, 15, + 15, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, - 20, 109, 109, 107, 107, 110, 110, 108, 108, 108, - 111, 111, 111, 135, 135, 135, 21, 21, 23, 23, - 24, 25, 22, 22, 22, 22, 22, 22, 22, 16, - 193, 26, 27, 27, 28, 28, 28, 32, 32, 32, - 30, 30, 31, 31, 37, 37, 36, 36, 38, 38, - 38, 38, 123, 123, 123, 122, 122, 40, 40, 41, - 41, 42, 42, 43, 43, 43, 43, 55, 55, 92, - 92, 94, 94, 44, 44, 44, 44, 45, 45, 46, - 46, 47, 47, 130, 130, 129, 129, 129, 128, 128, - 49, 49, 49, 51, 50, 50, 50, 50, 52, 52, - 54, 54, 53, 53, 56, 56, 56, 56, 57, 57, - 39, 39, 39, 39, 39, 39, 39, 106, 106, 59, - 59, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 70, 70, 70, 70, 70, 70, 60, 60, 60, - 60, 60, 60, 60, 35, 35, 71, 71, 71, 77, - 72, 72, 63, 63, 63, 63, 63, 63, 63, 63, + 20, 20, 20, 109, 109, 107, 107, 110, 110, 108, + 108, 108, 111, 111, 111, 135, 135, 135, 21, 21, + 23, 23, 24, 25, 22, 22, 22, 22, 22, 22, + 22, 16, 193, 26, 27, 27, 28, 28, 28, 32, + 32, 32, 30, 30, 31, 31, 37, 37, 36, 36, + 38, 38, 38, 38, 123, 123, 123, 122, 122, 40, + 40, 41, 41, 42, 42, 43, 43, 43, 43, 55, + 55, 92, 92, 94, 94, 44, 44, 44, 44, 45, + 45, 46, 46, 47, 47, 130, 130, 129, 129, 129, + 128, 128, 49, 49, 49, 51, 50, 50, 50, 50, + 52, 52, 54, 54, 53, 53, 56, 56, 56, 56, + 57, 57, 39, 39, 39, 39, 39, 39, 39, 106, + 106, 59, 59, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 70, 70, 70, 70, 70, 70, 60, + 60, 60, 60, 60, 60, 60, 35, 35, 71, 71, + 71, 77, 72, 72, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, 63, - 63, 63, 63, 63, 67, 67, 67, 65, 65, 65, + 63, 63, 63, 63, 63, 63, 67, 67, 67, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, - 65, 65, 65, 65, 65, 65, 65, 65, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, 66, - 66, 66, 66, 66, 194, 194, 69, 68, 68, 68, - 68, 33, 33, 33, 33, 33, 133, 133, 136, 136, + 66, 66, 66, 66, 66, 66, 194, 194, 69, 68, + 68, 68, 68, 33, 33, 33, 33, 33, 133, 133, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, - 136, 81, 81, 34, 34, 79, 79, 80, 82, 82, - 78, 78, 78, 62, 62, 62, 62, 62, 62, 62, - 62, 64, 64, 64, 83, 83, 84, 84, 85, 85, - 86, 86, 87, 88, 88, 88, 89, 89, 89, 89, - 90, 90, 90, 61, 61, 61, 61, 61, 61, 91, - 91, 91, 91, 95, 95, 73, 73, 75, 75, 74, - 76, 96, 96, 100, 97, 97, 101, 101, 101, 101, - 99, 99, 99, 125, 125, 125, 104, 104, 112, 112, - 113, 113, 105, 105, 114, 114, 114, 114, 114, 114, - 114, 114, 114, 114, 115, 115, 115, 116, 116, 117, - 117, 117, 124, 124, 120, 120, 121, 121, 126, 126, - 127, 127, 118, 118, 118, 118, 118, 118, 118, 118, + 136, 136, 136, 81, 81, 34, 34, 79, 79, 80, + 82, 82, 78, 78, 78, 62, 62, 62, 62, 62, + 62, 62, 62, 64, 64, 64, 83, 83, 84, 84, + 85, 85, 86, 86, 87, 88, 88, 88, 89, 89, + 89, 89, 90, 90, 90, 61, 61, 61, 61, 61, + 61, 91, 91, 91, 91, 95, 95, 73, 73, 75, + 75, 74, 76, 96, 96, 100, 97, 97, 101, 101, + 101, 101, 99, 99, 99, 125, 125, 125, 104, 104, + 112, 112, 113, 113, 105, 105, 114, 114, 114, 114, + 114, 114, 114, 114, 114, 114, 115, 115, 115, 116, + 116, 117, 117, 117, 124, 124, 120, 120, 121, 121, + 126, 126, 127, 127, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, @@ -2254,7 +2239,7 @@ var yyR1 = [...]int{ 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, 118, - 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, + 118, 118, 118, 118, 118, 118, 118, 118, 118, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, @@ -2266,7 +2251,7 @@ var yyR1 = [...]int{ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, - 190, 191, 131, 132, 132, 132, + 119, 119, 119, 190, 191, 131, 132, 132, 132, } var yyR2 = [...]int{ @@ -2279,61 +2264,61 @@ var yyR2 = [...]int{ 1, 1, 2, 2, 8, 4, 6, 5, 5, 0, 2, 1, 0, 2, 1, 3, 3, 4, 4, 2, 4, 1, 3, 3, 3, 8, 3, 1, 1, 1, - 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 2, 2, 2, 2, 1, 2, 2, 2, 1, 4, - 4, 2, 2, 3, 3, 3, 3, 1, 1, 1, - 1, 1, 6, 6, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 0, 3, 0, 5, 0, 3, - 5, 0, 1, 0, 1, 0, 1, 2, 0, 2, - 0, 3, 0, 1, 0, 3, 3, 0, 2, 2, - 0, 2, 1, 2, 1, 0, 2, 5, 4, 1, - 2, 2, 3, 2, 0, 1, 2, 3, 3, 2, - 2, 1, 1, 0, 1, 1, 3, 2, 3, 1, - 10, 11, 11, 12, 3, 3, 1, 1, 2, 2, - 2, 0, 1, 3, 1, 2, 3, 1, 1, 1, - 6, 7, 7, 7, 7, 4, 5, 7, 5, 5, - 5, 12, 7, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 7, 1, 3, 8, 8, 3, - 3, 5, 4, 6, 5, 4, 4, 3, 2, 3, - 4, 4, 3, 4, 4, 4, 4, 4, 4, 3, - 2, 3, 3, 2, 3, 4, 3, 7, 5, 4, - 2, 4, 2, 2, 2, 2, 3, 3, 5, 2, - 3, 1, 1, 0, 1, 1, 1, 0, 2, 2, - 0, 2, 2, 0, 1, 1, 2, 1, 1, 2, - 1, 1, 2, 2, 2, 2, 2, 3, 3, 2, - 0, 2, 0, 2, 1, 2, 2, 0, 1, 1, - 0, 1, 0, 1, 0, 1, 1, 3, 1, 2, - 3, 5, 0, 1, 2, 1, 1, 0, 2, 1, - 3, 1, 1, 1, 3, 1, 3, 3, 7, 1, - 3, 1, 3, 4, 4, 4, 3, 2, 4, 0, - 1, 0, 2, 0, 1, 0, 1, 2, 1, 1, - 1, 2, 2, 1, 2, 3, 2, 3, 2, 2, - 2, 1, 1, 3, 0, 5, 5, 5, 0, 2, - 1, 3, 3, 2, 3, 1, 2, 0, 3, 1, - 1, 3, 3, 4, 4, 5, 3, 4, 5, 6, - 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, - 1, 1, 1, 1, 0, 2, 1, 1, 1, 3, - 1, 3, 1, 1, 1, 1, 1, 3, 3, 3, + 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, + 1, 4, 4, 2, 2, 3, 3, 3, 3, 1, + 1, 1, 1, 1, 6, 6, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 0, 3, 0, 5, + 0, 3, 5, 0, 1, 0, 1, 0, 1, 2, + 0, 2, 0, 3, 0, 1, 0, 3, 3, 0, + 2, 2, 0, 2, 1, 2, 1, 0, 2, 5, + 4, 1, 2, 2, 3, 2, 0, 1, 2, 3, + 3, 2, 2, 1, 1, 0, 1, 1, 3, 2, + 3, 1, 10, 11, 11, 12, 3, 3, 1, 1, + 2, 2, 2, 0, 1, 3, 1, 2, 3, 1, + 1, 1, 6, 7, 7, 7, 7, 4, 5, 7, + 5, 5, 5, 12, 7, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7, 1, 3, 8, + 8, 3, 3, 5, 4, 6, 5, 4, 4, 3, + 2, 3, 4, 4, 3, 4, 4, 4, 4, 4, + 4, 3, 2, 3, 3, 2, 3, 4, 3, 7, + 5, 4, 2, 4, 2, 2, 2, 2, 3, 3, + 5, 2, 3, 1, 1, 0, 1, 1, 1, 0, + 2, 2, 0, 2, 2, 0, 1, 1, 2, 1, + 1, 2, 1, 1, 2, 2, 2, 2, 2, 3, + 3, 2, 0, 2, 0, 2, 1, 2, 2, 0, + 1, 1, 0, 1, 0, 1, 0, 1, 1, 3, + 1, 2, 3, 5, 0, 1, 2, 1, 1, 0, + 2, 1, 3, 1, 1, 1, 3, 1, 3, 3, + 7, 1, 3, 1, 3, 4, 4, 4, 3, 2, + 4, 0, 1, 0, 2, 0, 1, 0, 1, 2, + 1, 1, 1, 2, 2, 1, 2, 3, 2, 3, + 2, 2, 2, 1, 1, 3, 0, 5, 5, 5, + 0, 2, 1, 3, 3, 2, 3, 1, 2, 0, + 3, 1, 1, 3, 3, 4, 4, 5, 3, 4, + 5, 6, 2, 1, 2, 1, 2, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 0, 2, 1, 1, + 1, 3, 1, 3, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 3, 3, 2, 2, 2, 2, 2, 2, 2, 3, - 1, 1, 1, 1, 4, 5, 6, 4, 4, 6, - 6, 6, 6, 8, 8, 6, 8, 8, 6, 8, - 8, 6, 8, 8, 9, 7, 5, 4, 2, 2, + 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, + 2, 3, 1, 1, 1, 1, 4, 5, 6, 4, + 4, 6, 6, 6, 6, 8, 8, 6, 8, 8, + 6, 8, 8, 6, 8, 8, 9, 7, 5, 4, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 8, 8, 0, 2, 3, 4, 4, 4, - 4, 0, 3, 4, 7, 3, 1, 1, 2, 3, - 3, 1, 2, 2, 1, 2, 1, 2, 2, 1, - 2, 0, 1, 0, 2, 1, 2, 4, 0, 2, - 1, 3, 5, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 2, 2, 0, 3, 0, 2, 0, 3, - 1, 3, 2, 0, 1, 1, 0, 2, 4, 4, - 0, 2, 4, 2, 1, 3, 5, 4, 6, 1, - 3, 3, 5, 0, 5, 1, 3, 1, 2, 3, - 1, 1, 3, 3, 1, 3, 3, 3, 3, 3, - 1, 2, 1, 1, 1, 1, 1, 1, 0, 2, - 0, 3, 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, - 1, 1, 0, 2, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 8, 8, 0, 2, 3, 4, + 4, 4, 4, 0, 3, 4, 7, 3, 1, 1, + 2, 3, 3, 1, 2, 2, 1, 2, 1, 2, + 2, 1, 2, 0, 1, 0, 2, 1, 2, 4, + 0, 2, 1, 3, 5, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 2, 2, 0, 3, 0, 2, + 0, 3, 1, 3, 2, 0, 1, 1, 0, 2, + 4, 4, 0, 2, 4, 2, 1, 3, 5, 4, + 6, 1, 3, 3, 5, 0, 5, 1, 3, 1, + 2, 3, 1, 1, 3, 3, 1, 3, 3, 3, + 3, 3, 1, 2, 1, 1, 1, 1, 1, 1, + 0, 2, 0, 3, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, + 1, 0, 1, 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -2355,7 +2340,7 @@ var yyR2 = [...]int{ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 1, 1, } var yyChk = [...]int{ @@ -2367,289 +2352,291 @@ var yyChk = [...]int{ 121, -190, 8, 251, 54, -189, 268, -85, 15, -28, 5, -26, -193, -26, -26, -26, -26, -26, -164, -166, 54, 90, -117, 125, 72, 243, 122, 123, 129, -120, - 57, -119, 261, 135, 162, 173, 167, 194, 186, 136, - 184, 187, 230, 214, 225, 66, 165, 239, 145, 182, - 178, 176, 27, 227, 199, 266, 177, 226, 121, 138, - 133, 200, 204, 231, 171, 172, 233, 198, 134, 33, - 263, 35, 153, 234, 202, 197, 193, 196, 170, 192, - 39, 206, 205, 207, 229, 189, 139, 179, 18, 237, - 148, 151, 228, 201, 203, 130, 155, 265, 235, 175, - 140, 152, 147, 238, 141, 166, 232, 241, 38, 211, - 169, 132, 163, 159, 216, 190, 154, 180, 181, 195, - 168, 191, 164, 156, 149, 240, 212, 267, 188, 185, - 160, 157, 158, 217, 218, 219, 220, 221, 222, 161, - 264, 236, 183, 213, -105, 125, 220, 127, 123, 123, - 124, 125, 243, 122, 123, -53, -126, 57, -119, 125, - 123, 108, 187, 230, 115, 215, 227, 124, 33, 228, - 155, -135, 123, -107, 214, 217, 218, 219, 222, 220, - 161, 57, 232, 231, 223, -126, 164, -131, -131, -131, - -131, -131, 216, 216, -131, -2, -89, 17, 16, -5, - -3, -190, 6, 20, 21, -32, 40, 41, -27, -38, - 99, -39, -126, -58, 74, -63, 29, 57, -119, 23, - -62, -59, -78, -76, -77, 108, 109, 110, 97, 98, - 105, 75, 111, -67, -65, -66, -68, 59, 58, 67, - 60, 61, 62, 63, 68, 69, 70, -120, -74, -190, - 44, 45, 252, 253, 254, 255, 260, 256, 77, 34, - 242, 250, 249, 248, 246, 247, 244, 245, 258, 259, - 128, 243, 103, 251, -105, -105, 11, -48, -53, -97, - -134, 164, -101, 232, 231, -121, -99, -120, -118, 230, - 187, 229, 120, 73, 22, 24, 209, 76, 108, 16, - 77, 107, 252, 115, 48, 244, 245, 242, 254, 255, - 243, 215, 29, 10, 25, 143, 21, 101, 117, 80, - 81, 146, 23, 144, 70, 19, 51, 11, 13, 14, - 128, 127, 92, 124, 46, 8, 111, 26, 89, 42, - 28, 44, 90, 17, 246, 247, 31, 260, 150, 103, - 49, 36, 74, 68, 71, 52, 72, 15, 47, 91, - 118, 251, 45, 122, 6, 257, 30, 142, 43, 123, - 79, 258, 259, 126, 69, 5, 129, 32, 9, 50, - 53, 248, 249, 250, 34, 78, 12, -165, 90, -158, - 57, -53, 124, -53, 251, -113, 128, -113, -113, 123, - -53, 115, 117, 120, 52, -18, -53, -112, 128, 57, - -112, -112, -112, -53, 112, -53, 57, 30, -132, -190, - -121, 243, 57, 155, 123, 156, 125, -132, -132, -132, - -132, 159, 160, -132, -110, -109, 225, 226, 216, 224, - 12, 216, 158, -132, -131, -131, -191, 56, -90, 19, - 31, -39, -126, -86, -87, -39, -85, -2, -26, 36, - -30, 21, 65, 11, -123, 73, 72, 89, -122, 22, - -120, 59, 112, -39, -60, 92, 74, 90, 91, 76, - 94, 93, 104, 97, 98, 99, 100, 101, 102, 103, - 95, 96, 107, 82, 83, 84, 85, 86, 87, 88, - -106, -190, -77, -190, 113, 114, -63, -63, -63, -63, - -63, -63, -63, -63, -190, -2, -72, -39, -190, -190, - -190, -190, -190, -190, -190, -190, -190, -81, -39, -190, - -194, -69, -190, -194, -69, -194, -69, -194, -190, -194, - -69, -194, -69, -194, -194, -69, -190, -190, -190, -190, - -190, -190, -54, 26, -53, -41, -42, -43, -44, -55, - -77, -190, -53, -53, -48, -192, 55, 11, 53, 55, - -97, 164, -98, -102, 233, 235, 82, -125, -120, 59, - 29, 30, 56, 55, -53, -137, -140, -142, -141, -143, - -138, -139, 184, 185, 108, 188, 190, 191, 192, 193, - 194, 195, 196, 197, 198, 199, 30, 145, 180, 181, - 182, 183, 200, 201, 202, 203, 204, 205, 206, 207, - 167, 168, 169, 170, 171, 172, 173, 175, 176, 177, - 178, 179, 57, -132, 125, 57, 74, 57, -53, -53, - -132, 157, 157, 123, 123, -53, 55, 126, -48, 23, - 52, -53, 57, 57, -127, -126, -118, -132, -132, -132, - -132, -132, -132, -132, -132, -132, -132, 11, -108, 11, - 92, -39, 52, 9, 92, 55, 18, 112, 55, -88, - 24, 25, -89, -191, -32, -64, -120, 60, 63, -31, - 43, -53, -39, -39, -70, 68, 74, 69, 70, -122, - 99, -127, -121, -118, -63, -71, -74, -77, 64, 92, - 90, 91, 76, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -63, -133, 57, - 59, 57, -62, -62, -120, -37, 21, -36, -38, -191, - 55, -191, -2, -36, -36, -39, -39, -78, 59, -120, - -126, -78, 59, -36, -30, -79, -80, 78, -78, -191, - -63, -120, -120, -36, -37, -36, -36, -93, 151, -53, - 30, 55, -49, -51, -50, -52, 42, 46, 48, 43, - 44, 45, 49, -130, 22, -41, -190, -129, 151, -128, - 22, -126, 59, -93, 53, -41, -53, -101, -98, 55, - 234, 236, 237, 52, 71, -39, -149, 107, -167, -168, - -169, -121, 59, 60, -158, -159, -160, -170, 137, -175, - 130, 132, 129, -161, 138, 124, 28, 56, -154, 68, - 74, -150, 212, -144, 54, -144, -144, -144, -144, -148, - 187, -148, -148, -148, 54, 54, -144, -144, -144, -152, - 54, -152, -152, -153, 54, -153, -124, 53, -53, -132, - 23, -132, -114, 120, 117, 118, -178, 116, 209, 187, - 66, 29, 15, 252, 151, 267, 57, 152, -120, -120, - -53, -53, 120, 117, -53, -53, -53, -132, -53, -111, - 90, 12, -126, -126, -53, 38, -39, -39, -127, -87, - -90, -104, 19, 11, 34, 34, -36, 68, 69, 70, - 112, -190, -71, -63, -63, -63, -35, 146, 73, -191, - -191, -36, 55, -39, -191, -191, -191, 55, 53, 22, - 55, 11, 55, 11, 112, 55, 11, 55, 11, -191, - -36, -82, -80, 80, -39, -191, -191, 55, 55, -191, - -191, -191, -191, -61, 30, 34, -2, -190, -190, -96, - -100, -78, -42, -43, -43, -42, -43, 42, 42, 42, - 47, 42, 47, 42, -50, -126, -191, -56, 50, 127, - 51, -190, -128, -57, 12, -41, -57, -102, -103, 238, - 235, 241, 57, 59, 55, -169, 82, 54, 57, 28, - -161, -161, -162, 57, -162, 28, -146, 29, 68, -151, - 213, 60, -148, -148, -149, 30, -149, -149, -149, -157, - 59, -157, 60, 60, 52, -120, -132, -131, -184, 131, - 137, 138, 133, 57, 124, 28, 130, 132, 151, 129, - -184, -115, -116, 126, 22, 124, 28, 151, -183, 53, - 157, 157, 126, -132, -108, 59, -39, 39, 112, -53, - -40, 11, 99, -121, -37, -35, 73, -63, -63, -191, - -38, -136, 108, 184, 145, 182, 178, 198, 189, 211, - 180, 212, -133, -136, -63, -63, -63, -63, -121, -63, - -63, -63, -63, 261, -85, 81, -39, 79, -63, -63, - -95, 52, -96, -73, -75, -74, -190, -2, -91, -120, - -94, -120, -57, 55, 82, -46, -45, 52, 53, -47, - 52, -45, 42, 42, 124, 124, 124, -94, -85, -39, - -57, 235, 239, 240, -168, -169, -172, -171, -120, -175, - -162, -162, 54, -147, 52, -63, 56, -149, -149, 57, - 108, 56, 55, 56, 55, 56, 55, -53, -131, -131, - -53, -131, -120, -181, 264, -182, 57, -120, -120, -53, - -111, -57, -41, -191, -63, -191, -144, -144, -144, -153, - -144, 172, -144, 172, -191, -191, -191, 55, 19, -191, - 55, 19, -191, 55, 19, -191, 55, 19, -190, -34, - 257, -39, 55, 55, 27, -95, 55, -191, -191, -191, - 55, 112, -191, 55, -85, -100, -39, -39, 54, -39, - -190, -190, -190, -191, -89, 56, 55, -144, -92, -120, - -155, 209, 9, -148, 59, -148, 60, 60, -132, 26, - -180, -179, -121, 54, -83, 13, -148, 57, -63, -63, - -63, -63, -63, -63, -63, -63, -63, -191, 59, -63, - -63, 28, -75, 34, -2, -190, -120, -120, -120, -89, - -92, -92, -92, -92, -129, -174, -173, 53, 134, 66, - -171, 56, 55, -156, 130, 28, 129, -66, -149, -149, - 56, 56, -190, 55, 82, -92, -84, 14, 16, -191, - -191, -191, -191, -191, -191, -191, -191, -33, 92, 264, - -191, -191, 9, -73, -2, 112, 56, -191, -191, -191, - -56, -173, 57, -163, 82, 59, 140, -120, -145, 66, - 28, 28, -176, -177, 151, -179, -169, 56, -39, -72, - -191, 262, 49, 265, -96, -191, -120, 60, -53, 59, - -191, 55, -120, -183, 39, 263, 266, 54, -177, 34, - -181, 39, -92, 153, 264, 56, 154, 265, -186, -187, - 52, -190, 266, -187, 52, 10, 9, -63, 150, -185, - 141, 136, 139, 30, -185, -191, -191, 135, 29, 68, + 57, -119, 261, 135, 162, 173, 167, 194, 186, 262, + 136, 184, 187, 230, 214, 225, 66, 165, 239, 145, + 182, 178, 176, 27, 227, 199, 266, 177, 226, 121, + 138, 133, 200, 204, 231, 171, 172, 233, 198, 134, + 33, 263, 35, 153, 234, 202, 197, 193, 196, 170, + 192, 39, 206, 205, 207, 229, 189, 139, 179, 18, + 237, 148, 151, 228, 201, 203, 130, 155, 265, 235, + 175, 140, 152, 147, 238, 141, 166, 232, 241, 38, + 211, 169, 132, 163, 159, 216, 190, 154, 180, 181, + 195, 168, 191, 164, 156, 149, 240, 212, 267, 188, + 185, 160, 157, 158, 217, 218, 219, 220, 221, 222, + 161, 264, 236, 183, 213, -105, 125, 220, 127, 123, + 123, 124, 125, 243, 122, 123, -53, -126, 57, -119, + 125, 123, 108, 187, 230, 115, 215, 227, 124, 33, + 228, 155, -135, 123, -107, 214, 217, 218, 219, 222, + 220, 161, 57, 232, 231, 223, -126, 164, -131, -131, + -131, -131, -131, 216, 216, -131, -2, -89, 17, 16, + -5, -3, -190, 6, 20, 21, -32, 40, 41, -27, + -38, 99, -39, -126, -58, 74, -63, 29, 57, -119, + 23, -62, -59, -78, -76, -77, 108, 109, 110, 97, + 98, 105, 75, 111, -67, -65, -66, -68, 59, 58, + 67, 60, 61, 62, 63, 68, 69, 70, -120, -74, + -190, 44, 45, 252, 253, 254, 255, 260, 256, 77, + 34, 242, 250, 249, 248, 246, 247, 244, 245, 258, + 259, 128, 243, 103, 251, -105, -105, 11, -48, -53, + -97, -134, 164, -101, 232, 231, -121, -99, -120, -118, + 230, 187, 229, 120, 73, 22, 24, 209, 76, 108, + 16, 77, 107, 252, 115, 48, 244, 245, 242, 254, + 255, 243, 215, 29, 10, 25, 143, 21, 101, 117, + 80, 81, 146, 23, 144, 70, 19, 51, 11, 13, + 14, 128, 127, 92, 124, 46, 8, 111, 26, 89, + 42, 28, 44, 90, 17, 246, 247, 31, 260, 150, + 103, 49, 36, 74, 68, 71, 52, 72, 15, 47, + 91, 118, 251, 45, 122, 6, 257, 30, 142, 43, + 123, 79, 258, 259, 126, 69, 5, 129, 32, 9, + 50, 53, 248, 249, 250, 34, 78, 12, -165, 90, + -158, 57, -53, 124, -53, 251, -113, 128, -113, -113, + 123, -53, 115, 117, 120, 52, -18, -53, -112, 128, + 57, -112, -112, -112, -53, 112, -53, 57, 30, -132, + -190, -121, 243, 57, 155, 123, 156, 125, -132, -132, + -132, -132, 159, 160, -132, -110, -109, 225, 226, 216, + 224, 12, 216, 158, -132, -131, -131, -191, 56, -90, + 19, 31, -39, -126, -86, -87, -39, -85, -2, -26, + 36, -30, 21, 65, 11, -123, 73, 72, 89, -122, + 22, -120, 59, 112, -39, -60, 92, 74, 90, 91, + 76, 94, 93, 104, 97, 98, 99, 100, 101, 102, + 103, 95, 96, 107, 82, 83, 84, 85, 86, 87, + 88, -106, -190, -77, -190, 113, 114, -63, -63, -63, + -63, -63, -63, -63, -63, -190, -2, -72, -39, -190, + -190, -190, -190, -190, -190, -190, -190, -190, -81, -39, + -190, -194, -69, -190, -194, -69, -194, -69, -194, -190, + -194, -69, -194, -69, -194, -194, -69, -190, -190, -190, + -190, -190, -190, -54, 26, -53, -41, -42, -43, -44, + -55, -77, -190, -53, -53, -48, -192, 55, 11, 53, + 55, -97, 164, -98, -102, 233, 235, 82, -125, -120, + 59, 29, 30, 56, 55, -53, -137, -140, -142, -141, + -143, -138, -139, 184, 185, 108, 188, 190, 191, 192, + 193, 194, 195, 196, 197, 198, 199, 30, 145, 180, + 181, 182, 183, 200, 201, 202, 203, 204, 205, 206, + 207, 167, 186, 262, 168, 169, 170, 171, 172, 173, + 175, 176, 177, 178, 179, 57, -132, 125, 57, 74, + 57, -53, -53, -132, 157, 157, 123, 123, -53, 55, + 126, -48, 23, 52, -53, 57, 57, -127, -126, -118, + -132, -132, -132, -132, -132, -132, -132, -132, -132, -132, + 11, -108, 11, 92, -39, 52, 9, 92, 55, 18, + 112, 55, -88, 24, 25, -89, -191, -32, -64, -120, + 60, 63, -31, 43, -53, -39, -39, -70, 68, 74, + 69, 70, -122, 99, -127, -121, -118, -63, -71, -74, + -77, 64, 92, 90, 91, 76, -63, -63, -63, -63, + -63, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -63, -133, 57, 59, 57, -62, -62, -120, -37, 21, + -36, -38, -191, 55, -191, -2, -36, -36, -39, -39, + -78, 59, -120, -126, -78, 59, -36, -30, -79, -80, + 78, -78, -191, -63, -120, -120, -36, -37, -36, -36, + -93, 151, -53, 30, 55, -49, -51, -50, -52, 42, + 46, 48, 43, 44, 45, 49, -130, 22, -41, -190, + -129, 151, -128, 22, -126, 59, -93, 53, -41, -53, + -101, -98, 55, 234, 236, 237, 52, 71, -39, -149, + 107, -167, -168, -169, -121, 59, 60, -158, -159, -160, + -170, 137, -175, 130, 132, 129, -161, 138, 124, 28, + 56, -154, 68, 74, -150, 212, -144, 54, -144, -144, + -144, -144, -148, 187, -148, -148, -148, 54, 54, -144, + -144, -144, -152, 54, -152, -152, -153, 54, -153, -124, + 53, -53, -132, 23, -132, -114, 120, 117, 118, -178, + 116, 209, 187, 66, 29, 15, 252, 151, 267, 57, + 152, -120, -120, -53, -53, 120, 117, -53, -53, -53, + -132, -53, -111, 90, 12, -126, -126, -53, 38, -39, + -39, -127, -87, -90, -104, 19, 11, 34, 34, -36, + 68, 69, 70, 112, -190, -71, -63, -63, -63, -35, + 146, 73, -191, -191, -36, 55, -39, -191, -191, -191, + 55, 53, 22, 55, 11, 55, 11, 112, 55, 11, + 55, 11, -191, -36, -82, -80, 80, -39, -191, -191, + 55, 55, -191, -191, -191, -191, -61, 30, 34, -2, + -190, -190, -96, -100, -78, -42, -43, -43, -42, -43, + 42, 42, 42, 47, 42, 47, 42, -50, -126, -191, + -56, 50, 127, 51, -190, -128, -57, 12, -41, -57, + -102, -103, 238, 235, 241, 57, 59, 55, -169, 82, + 54, 57, 28, -161, -161, -162, 57, -162, 28, -146, + 29, 68, -151, 213, 60, -148, -148, -149, 30, -149, + -149, -149, -157, 59, -157, 60, 60, 52, -120, -132, + -131, -184, 131, 137, 138, 133, 57, 124, 28, 130, + 132, 151, 129, -184, -115, -116, 126, 22, 124, 28, + 151, -183, 53, 157, 157, 126, -132, -108, 59, -39, + 39, 112, -53, -40, 11, 99, -121, -37, -35, 73, + -63, -63, -191, -38, -136, 108, 184, 145, 182, 178, + 198, 189, 211, 180, 212, -133, -136, -63, -63, -63, + -63, -121, -63, -63, -63, -63, 261, -85, 81, -39, + 79, -63, -63, -95, 52, -96, -73, -75, -74, -190, + -2, -91, -120, -94, -120, -57, 55, 82, -46, -45, + 52, 53, -47, 52, -45, 42, 42, 124, 124, 124, + -94, -85, -39, -57, 235, 239, 240, -168, -169, -172, + -171, -120, -175, -162, -162, 54, -147, 52, -63, 56, + -149, -149, 57, 108, 56, 55, 56, 55, 56, 55, + -53, -131, -131, -53, -131, -120, -181, 264, -182, 57, + -120, -120, -53, -111, -57, -41, -191, -63, -191, -144, + -144, -144, -153, -144, 172, -144, 172, -191, -191, -191, + 55, 19, -191, 55, 19, -191, 55, 19, -191, 55, + 19, -190, -34, 257, -39, 55, 55, 27, -95, 55, + -191, -191, -191, 55, 112, -191, 55, -85, -100, -39, + -39, 54, -39, -190, -190, -190, -191, -89, 56, 55, + -144, -92, -120, -155, 209, 9, -148, 59, -148, 60, + 60, -132, 26, -180, -179, -121, 54, -83, 13, -148, + 57, -63, -63, -63, -63, -63, -63, -63, -63, -63, + -191, 59, -63, -63, 28, -75, 34, -2, -190, -120, + -120, -120, -89, -92, -92, -92, -92, -129, -174, -173, + 53, 134, 66, -171, 56, 55, -156, 130, 28, 129, + -66, -149, -149, 56, 56, -190, 55, 82, -92, -84, + 14, 16, -191, -191, -191, -191, -191, -191, -191, -191, + -33, 92, 264, -191, -191, 9, -73, -2, 112, 56, + -191, -191, -191, -56, -173, 57, -163, 82, 59, 140, + -120, -145, 66, 28, 28, -176, -177, 151, -179, -169, + 56, -39, -72, -191, 262, 49, 265, -96, -191, -120, + 60, -53, 59, -191, 55, -120, -183, 39, 263, 266, + 54, -177, 34, -181, 39, -92, 153, 264, 56, 154, + 265, -186, -187, 52, -190, 266, -187, 52, 10, 9, + -63, 150, -185, 141, 136, 139, 30, -185, -191, -191, + 135, 29, 68, } var yyDef = [...]int{ 23, -2, 2, -2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, - 21, 22, 558, 0, 310, 310, 310, 310, 310, 310, - 0, 629, 612, 0, 0, 0, 0, -2, 297, 298, - 0, 300, 301, 852, 852, 852, 852, 852, 0, 0, - 852, 0, 35, 36, 850, 1, 3, 566, 0, 0, - 314, 317, 312, 0, 612, 612, 0, 0, 62, 63, - 0, 0, 0, 836, 0, 610, 610, 610, 630, 631, - 634, 635, 737, 738, 739, 740, 741, 742, 743, 744, - 745, 746, 747, 748, 749, 750, 751, 752, 753, 754, - 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, - 765, 766, 767, 768, 769, 770, 771, 772, 773, 774, - 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, - 785, 786, 787, 788, 789, 790, 791, 792, 793, 794, - 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, - 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, - 815, 816, 817, 818, 819, 820, 821, 822, 823, 824, - 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, - 835, 837, 838, 839, 840, 841, 842, 843, 844, 845, - 846, 847, 848, 849, 0, 0, 0, 613, 0, 608, - 0, 608, 608, 608, 0, 248, 382, 638, 639, 836, - 0, 0, 0, 853, 0, 853, 260, 853, 853, 263, - 853, 0, 853, 0, 270, 272, 273, 274, 275, 0, - 279, 853, 294, 295, 284, 296, 299, 302, 303, 304, - 305, 306, 852, 852, 309, 29, 570, 0, 0, 558, - 31, 0, 310, 315, 316, 320, 318, 319, 311, 0, - 328, 332, 0, 390, 0, 395, 397, -2, -2, 0, - 432, 433, 434, 435, 436, 0, 0, 0, 0, 0, - 0, 0, 0, 460, 461, 462, 463, 543, 544, 545, - 546, 547, 548, 549, 550, 399, 400, 540, 590, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 531, 0, - 504, 504, 504, 504, 504, 504, 504, 504, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 43, 47, - 0, 827, 594, -2, -2, 0, 0, 636, 637, -2, - 746, -2, 642, 643, 644, 645, 646, 647, 648, 649, - 650, 651, 652, 653, 654, 655, 656, 657, 658, 659, - 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, - 670, 671, 672, 673, 674, 675, 676, 677, 678, 679, - 680, 681, 682, 683, 684, 685, 686, 687, 688, 689, - 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, - 700, 701, 702, 703, 704, 705, 706, 707, 708, 709, - 710, 711, 712, 713, 714, 715, 716, 717, 718, 719, - 720, 721, 722, 723, 724, 725, 726, 727, 728, 729, - 730, 731, 732, 733, 734, 735, 736, 0, 0, 81, - 0, 79, 0, 853, 0, 0, 0, 0, 0, 0, - 853, 0, 0, 0, 0, 239, 0, 0, 0, 0, - 0, 0, 0, 247, 0, 249, 853, 853, 252, 854, - 855, 853, 853, 853, 853, 853, 853, 259, 261, 262, - 264, 853, 853, 266, 0, 287, 285, 286, 281, 282, - 0, 276, 277, 280, 307, 308, 30, 851, 24, 0, - 0, 567, 0, 559, 560, 563, 566, 29, 317, 0, - 322, 321, 313, 0, 329, 0, 0, 0, 333, 0, - 335, 336, 0, 393, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 417, 418, 419, 420, 421, 422, 423, - 396, 0, 410, 0, 0, 0, 452, 453, 454, 455, - 456, 457, 458, 0, 324, 29, 0, 430, 0, 0, - 0, 0, 0, 0, 0, 0, 320, 0, 532, 0, - 488, 496, 0, 489, 497, 490, 498, 491, 0, 492, - 499, 493, 500, 494, 495, 501, 0, 0, 0, 324, - 0, 0, 45, 0, 381, 0, 339, 341, 342, 343, - -2, 0, 365, -2, 0, 0, 0, 41, 42, 0, - 48, 827, 50, 51, 0, 0, 0, 157, 603, 604, - 605, 601, 201, 0, 0, 145, 141, 87, 88, 89, - 134, 91, 134, 134, 134, 134, 154, 154, 154, 154, - 117, 118, 119, 120, 121, 0, 0, 104, 134, 134, - 134, 108, 124, 125, 126, 127, 128, 129, 130, 131, - 92, 93, 94, 95, 96, 97, 98, 136, 136, 136, - 138, 138, 632, 65, 0, 853, 0, 853, 77, 0, - 215, 0, 0, 0, 0, 0, 0, 0, 242, 609, - 0, 853, 245, 246, 383, 640, 641, 250, 251, 253, - 254, 255, 256, 257, 258, 265, 269, 0, 290, 0, - 0, 271, 0, 571, 0, 0, 0, 0, 0, 562, - 564, 565, 570, 32, 320, 0, 551, 0, 0, 0, - 323, 27, 391, 392, 394, 411, 0, 413, 415, 334, - 330, 0, 541, -2, 401, 402, 426, 427, 428, 0, - 0, 0, 0, 424, 406, 0, 437, 438, 439, 440, - 441, 442, 443, 444, 445, 446, 447, 448, 451, 516, - 517, 0, 449, 450, 459, 0, 0, 325, 326, 429, - 0, 589, 29, 0, 0, 0, 0, 0, 0, 540, - 0, 0, 0, 0, 0, 538, 535, 0, 0, 505, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 380, - 0, 0, 0, 0, 0, 0, 370, 0, 0, 373, - 0, 0, 0, 0, 364, 0, 0, 384, 796, 366, - 0, 368, 369, 388, 0, 388, 44, 595, 49, 0, - 0, 54, 55, 596, 597, 598, 599, 0, 78, 202, - 204, 207, 208, 209, 82, 83, 84, 0, 0, 189, - 0, 0, 183, 183, 0, 181, 182, 80, 148, 146, - 0, 143, 142, 90, 0, 154, 154, 111, 112, 157, - 0, 157, 157, 157, 0, 0, 105, 106, 107, 99, - 0, 100, 101, 102, 0, 103, 0, 0, 853, 67, - 611, 68, 852, 0, 0, 624, 216, 614, 615, 616, - 617, 618, 619, 620, 621, 622, 623, 0, 69, 218, - 220, 219, 0, 0, 0, 240, 853, 244, 287, 268, - 0, 0, 288, 289, 278, 0, 568, 569, 0, 561, - 25, 0, 606, 607, 552, 553, 337, 412, 414, 416, - 0, 324, 403, 424, 407, 0, 404, 0, 0, 398, - 464, 0, 0, 431, -2, 467, 468, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 558, 0, 536, 0, 0, 487, 506, 0, 0, 507, - 508, 509, 510, 583, 0, 0, -2, 0, 0, 388, - 591, 0, 340, 359, 361, 0, 356, 371, 372, 374, - 0, 376, 0, 378, 379, 344, 346, 347, 0, 0, - 0, 0, 367, 558, 0, 388, 40, 52, 53, 0, - 0, 59, 158, 159, 0, 205, 0, 0, 0, 176, - 183, 183, 179, 184, 180, 0, 150, 0, 147, 86, - 144, 0, 157, 157, 113, 0, 114, 115, 116, 0, - 132, 0, 0, 0, 0, 633, 66, 210, 852, 223, - 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 852, 0, 852, 625, 626, 627, 628, 0, 72, 0, - 0, 0, 0, 243, 290, 291, 292, 572, 0, 26, - 388, 0, 331, 542, 0, 405, 0, 425, 408, 465, - 327, 0, 134, 134, 521, 134, 138, 524, 134, 526, - 134, 529, 0, 0, 0, 0, 0, 0, 541, 0, - 0, 0, 0, 0, 533, 486, 539, 0, 0, 0, - 33, 0, 583, 573, 585, 587, 0, 29, 0, 579, - 0, 351, 558, 0, 0, 353, 360, 0, 0, 354, - 0, 355, 375, 377, 0, 0, 0, 0, 566, 389, - 39, 56, 57, 58, 203, 206, 0, 185, 134, 188, - 177, 178, 0, 152, 0, 149, 135, 109, 110, 155, - 156, 154, 0, 154, 0, 139, 0, 853, 211, 212, - 213, 214, 0, 217, 0, 70, 71, 0, 222, 241, - 267, 554, 338, 466, 409, 469, 518, 154, 522, 523, - 525, 527, 528, 530, 471, 470, 472, 0, 0, 478, - 0, 0, 475, 0, 0, 481, 0, 0, 0, 0, - 0, 537, 0, 0, 0, 34, 0, 588, -2, 0, - 0, 0, 46, 0, 566, 592, 593, 357, 0, 362, - 0, 0, 0, 365, 38, 168, 0, 187, 0, 349, - 160, 153, 0, 157, 133, 157, 0, 0, 64, 0, - 73, 74, 0, 0, 556, 0, 519, 520, 0, 0, - 0, 0, 0, 0, 0, 0, 511, 485, 534, 0, - 0, 0, 586, 0, -2, 0, 581, 580, 352, 37, - 0, 0, 0, 0, 384, 167, 169, 0, 174, 0, - 186, 0, 0, 165, 0, 162, 164, 151, 122, 123, - 137, 140, 0, 0, 0, 0, 28, 0, 0, 473, - 474, 479, 480, 476, 477, 482, 483, 0, 0, 0, - 502, 503, 0, 576, 29, 0, 358, 385, 386, 387, - 348, 170, 171, 0, 175, 173, 0, 350, 85, 0, - 161, 163, 0, 235, 0, 75, 76, 69, 557, 555, - 484, 0, 0, 0, 584, -2, 582, 172, 0, 166, - 234, 0, 0, 72, 512, 0, 515, 0, 236, 0, - 221, 513, 0, 0, 0, 190, 0, 0, 191, 192, - 0, 0, 514, 193, 0, 0, 0, 0, 0, 194, - 196, 197, 0, 0, 195, 237, 238, 198, 199, 200, + 21, 22, 560, 0, 312, 312, 312, 312, 312, 312, + 0, 631, 614, 0, 0, 0, 0, -2, 299, 300, + 0, 302, 303, 855, 855, 855, 855, 855, 0, 0, + 855, 0, 35, 36, 853, 1, 3, 568, 0, 0, + 316, 319, 314, 0, 614, 614, 0, 0, 62, 63, + 0, 0, 0, 839, 0, 612, 612, 612, 632, 633, + 636, 637, 739, 740, 741, 742, 743, 744, 745, 746, + 747, 748, 749, 750, 751, 752, 753, 754, 755, 756, + 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, + 767, 768, 769, 770, 771, 772, 773, 774, 775, 776, + 777, 778, 779, 780, 781, 782, 783, 784, 785, 786, + 787, 788, 789, 790, 791, 792, 793, 794, 795, 796, + 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, + 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, + 817, 818, 819, 820, 821, 822, 823, 824, 825, 826, + 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, + 837, 838, 840, 841, 842, 843, 844, 845, 846, 847, + 848, 849, 850, 851, 852, 0, 0, 0, 615, 0, + 610, 0, 610, 610, 610, 0, 250, 384, 640, 641, + 839, 0, 0, 0, 856, 0, 856, 262, 856, 856, + 265, 856, 0, 856, 0, 272, 274, 275, 276, 277, + 0, 281, 856, 296, 297, 286, 298, 301, 304, 305, + 306, 307, 308, 855, 855, 311, 29, 572, 0, 0, + 560, 31, 0, 312, 317, 318, 322, 320, 321, 313, + 0, 330, 334, 0, 392, 0, 397, 399, -2, -2, + 0, 434, 435, 436, 437, 438, 0, 0, 0, 0, + 0, 0, 0, 0, 462, 463, 464, 465, 545, 546, + 547, 548, 549, 550, 551, 552, 401, 402, 542, 592, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 533, + 0, 506, 506, 506, 506, 506, 506, 506, 506, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, + 47, 0, 830, 596, -2, -2, 0, 0, 638, 639, + -2, 749, -2, 644, 645, 646, 647, 648, 649, 650, + 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, + 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, + 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, + 681, 682, 683, 684, 685, 686, 687, 688, 689, 690, + 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, + 701, 702, 703, 704, 705, 706, 707, 708, 709, 710, + 711, 712, 713, 714, 715, 716, 717, 718, 719, 720, + 721, 722, 723, 724, 725, 726, 727, 728, 729, 730, + 731, 732, 733, 734, 735, 736, 737, 738, 0, 0, + 81, 0, 79, 0, 856, 0, 0, 0, 0, 0, + 0, 856, 0, 0, 0, 0, 241, 0, 0, 0, + 0, 0, 0, 0, 249, 0, 251, 856, 856, 254, + 857, 858, 856, 856, 856, 856, 856, 856, 261, 263, + 264, 266, 856, 856, 268, 0, 289, 287, 288, 283, + 284, 0, 278, 279, 282, 309, 310, 30, 854, 24, + 0, 0, 569, 0, 561, 562, 565, 568, 29, 319, + 0, 324, 323, 315, 0, 331, 0, 0, 0, 335, + 0, 337, 338, 0, 395, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 419, 420, 421, 422, 423, 424, + 425, 398, 0, 412, 0, 0, 0, 454, 455, 456, + 457, 458, 459, 460, 0, 326, 29, 0, 432, 0, + 0, 0, 0, 0, 0, 0, 0, 322, 0, 534, + 0, 490, 498, 0, 491, 499, 492, 500, 493, 0, + 494, 501, 495, 502, 496, 497, 503, 0, 0, 0, + 326, 0, 0, 45, 0, 383, 0, 341, 343, 344, + 345, -2, 0, 367, -2, 0, 0, 0, 41, 42, + 0, 48, 830, 50, 51, 0, 0, 0, 159, 605, + 606, 607, 603, 203, 0, 0, 147, 143, 87, 88, + 89, 136, 91, 136, 136, 136, 136, 156, 156, 156, + 156, 119, 120, 121, 122, 123, 0, 0, 106, 136, + 136, 136, 110, 126, 127, 128, 129, 130, 131, 132, + 133, 92, 93, 94, 95, 96, 97, 98, 99, 100, + 138, 138, 138, 140, 140, 634, 65, 0, 856, 0, + 856, 77, 0, 217, 0, 0, 0, 0, 0, 0, + 0, 244, 611, 0, 856, 247, 248, 385, 642, 643, + 252, 253, 255, 256, 257, 258, 259, 260, 267, 271, + 0, 292, 0, 0, 273, 0, 573, 0, 0, 0, + 0, 0, 564, 566, 567, 572, 32, 322, 0, 553, + 0, 0, 0, 325, 27, 393, 394, 396, 413, 0, + 415, 417, 336, 332, 0, 543, -2, 403, 404, 428, + 429, 430, 0, 0, 0, 0, 426, 408, 0, 439, + 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, + 450, 453, 518, 519, 0, 451, 452, 461, 0, 0, + 327, 328, 431, 0, 591, 29, 0, 0, 0, 0, + 0, 0, 542, 0, 0, 0, 0, 0, 540, 537, + 0, 0, 507, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 382, 0, 0, 0, 0, 0, 0, 372, + 0, 0, 375, 0, 0, 0, 0, 366, 0, 0, + 386, 799, 368, 0, 370, 371, 390, 0, 390, 44, + 597, 49, 0, 0, 54, 55, 598, 599, 600, 601, + 0, 78, 204, 206, 209, 210, 211, 82, 83, 84, + 0, 0, 191, 0, 0, 185, 185, 0, 183, 184, + 80, 150, 148, 0, 145, 144, 90, 0, 156, 156, + 113, 114, 159, 0, 159, 159, 159, 0, 0, 107, + 108, 109, 101, 0, 102, 103, 104, 0, 105, 0, + 0, 856, 67, 613, 68, 855, 0, 0, 626, 218, + 616, 617, 618, 619, 620, 621, 622, 623, 624, 625, + 0, 69, 220, 222, 221, 0, 0, 0, 242, 856, + 246, 289, 270, 0, 0, 290, 291, 280, 0, 570, + 571, 0, 563, 25, 0, 608, 609, 554, 555, 339, + 414, 416, 418, 0, 326, 405, 426, 409, 0, 406, + 0, 0, 400, 466, 0, 0, 433, -2, 469, 470, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 560, 0, 538, 0, 0, 489, 508, + 0, 0, 509, 510, 511, 512, 585, 0, 0, -2, + 0, 0, 390, 593, 0, 342, 361, 363, 0, 358, + 373, 374, 376, 0, 378, 0, 380, 381, 346, 348, + 349, 0, 0, 0, 0, 369, 560, 0, 390, 40, + 52, 53, 0, 0, 59, 160, 161, 0, 207, 0, + 0, 0, 178, 185, 185, 181, 186, 182, 0, 152, + 0, 149, 86, 146, 0, 159, 159, 115, 0, 116, + 117, 118, 0, 134, 0, 0, 0, 0, 635, 66, + 212, 855, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 855, 0, 855, 627, 628, 629, 630, + 0, 72, 0, 0, 0, 0, 245, 292, 293, 294, + 574, 0, 26, 390, 0, 333, 544, 0, 407, 0, + 427, 410, 467, 329, 0, 136, 136, 523, 136, 140, + 526, 136, 528, 136, 531, 0, 0, 0, 0, 0, + 0, 543, 0, 0, 0, 0, 0, 535, 488, 541, + 0, 0, 0, 33, 0, 585, 575, 587, 589, 0, + 29, 0, 581, 0, 353, 560, 0, 0, 355, 362, + 0, 0, 356, 0, 357, 377, 379, 0, 0, 0, + 0, 568, 391, 39, 56, 57, 58, 205, 208, 0, + 187, 136, 190, 179, 180, 0, 154, 0, 151, 137, + 111, 112, 157, 158, 156, 0, 156, 0, 141, 0, + 856, 213, 214, 215, 216, 0, 219, 0, 70, 71, + 0, 224, 243, 269, 556, 340, 468, 411, 471, 520, + 156, 524, 525, 527, 529, 530, 532, 473, 472, 474, + 0, 0, 480, 0, 0, 477, 0, 0, 483, 0, + 0, 0, 0, 0, 539, 0, 0, 0, 34, 0, + 590, -2, 0, 0, 0, 46, 0, 568, 594, 595, + 359, 0, 364, 0, 0, 0, 367, 38, 170, 0, + 189, 0, 351, 162, 155, 0, 159, 135, 159, 0, + 0, 64, 0, 73, 74, 0, 0, 558, 0, 521, + 522, 0, 0, 0, 0, 0, 0, 0, 0, 513, + 487, 536, 0, 0, 0, 588, 0, -2, 0, 583, + 582, 354, 37, 0, 0, 0, 0, 386, 169, 171, + 0, 176, 0, 188, 0, 0, 167, 0, 164, 166, + 153, 124, 125, 139, 142, 0, 0, 0, 0, 28, + 0, 0, 475, 476, 481, 482, 478, 479, 484, 485, + 0, 0, 0, 504, 505, 0, 578, 29, 0, 360, + 387, 388, 389, 350, 172, 173, 0, 177, 175, 0, + 352, 85, 0, 163, 165, 0, 237, 0, 75, 76, + 69, 559, 557, 486, 0, 0, 0, 586, -2, 584, + 174, 0, 168, 236, 0, 0, 72, 514, 0, 517, + 0, 238, 0, 223, 515, 0, 0, 0, 192, 0, + 0, 193, 194, 0, 0, 516, 195, 0, 0, 0, + 0, 0, 196, 198, 199, 0, 0, 197, 239, 240, + 200, 201, 202, } var yyTok1 = [...]int{ @@ -3531,24 +3518,20 @@ yydefault: yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 99: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:735 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:733 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length - yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale } case 100: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:741 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:737 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} - yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length - yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale } case 101: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:747 +//line sql.y:743 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3556,7 +3539,7 @@ yydefault: } case 102: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:753 +//line sql.y:749 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length @@ -3564,29 +3547,33 @@ yydefault: } case 103: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:759 +//line sql.y:755 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale } case 104: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:767 + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:761 { yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length + yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale } case 105: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:771 +//line sql.y:767 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + yyVAL.columnType.Length = yyDollar[2].LengthScaleOption.Length + yyVAL.columnType.Scale = yyDollar[2].LengthScaleOption.Scale } case 106: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:775 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 107: yyDollar = yyS[yypt-2 : yypt+1] @@ -3595,46 +3582,46 @@ yydefault: yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 108: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:783 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 109: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:789 + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:787 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 110: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:793 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:791 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 111: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:797 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} } case 112: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:801 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: yyDollar[3].str, Collate: yyDollar[4].str} } case 113: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:805 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 114: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:809 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } case 115: yyDollar = yyS[yypt-3 : yypt+1] @@ -3649,16 +3636,16 @@ yydefault: yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 117: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:821 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 118: - yyDollar = yyS[yypt-1 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:825 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), Charset: yyDollar[2].str, Collate: yyDollar[3].str} } case 119: yyDollar = yyS[yypt-1 : yypt+1] @@ -3679,28 +3666,28 @@ yydefault: yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 122: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:841 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 123: - yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:846 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:845 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} } case 124: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:852 + yyDollar = yyS[yypt-6 : yypt+1] +//line sql.y:849 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} } case 125: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:856 + yyDollar = yyS[yypt-6 : yypt+1] +//line sql.y:854 { - yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes), EnumValues: yyDollar[3].strs, Charset: yyDollar[5].str, Collate: yyDollar[6].str} } case 126: yyDollar = yyS[yypt-1 : yypt+1] @@ -3740,529 +3727,541 @@ yydefault: } case 132: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:886 +//line sql.y:884 + { + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + } + case 133: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:888 + { + yyVAL.columnType = ColumnType{Type: string(yyDollar[1].bytes)} + } + case 134: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:894 { yyVAL.strs = make([]string, 0, 4) yyVAL.strs = append(yyVAL.strs, "'"+string(yyDollar[1].bytes)+"'") } - case 133: + case 135: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:891 +//line sql.y:899 { yyVAL.strs = append(yyDollar[1].strs, "'"+string(yyDollar[3].bytes)+"'") } - case 134: + case 136: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:896 +//line sql.y:904 { yyVAL.sqlVal = nil } - case 135: + case 137: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:900 +//line sql.y:908 { yyVAL.sqlVal = NewIntVal(yyDollar[2].bytes) } - case 136: + case 138: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:905 +//line sql.y:913 { yyVAL.LengthScaleOption = LengthScaleOption{} } - case 137: + case 139: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:909 +//line sql.y:917 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), Scale: NewIntVal(yyDollar[4].bytes), } } - case 138: + case 140: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:917 +//line sql.y:925 { yyVAL.LengthScaleOption = LengthScaleOption{} } - case 139: + case 141: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:921 +//line sql.y:929 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), } } - case 140: + case 142: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:927 +//line sql.y:935 { yyVAL.LengthScaleOption = LengthScaleOption{ Length: NewIntVal(yyDollar[2].bytes), Scale: NewIntVal(yyDollar[4].bytes), } } - case 141: + case 143: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:935 +//line sql.y:943 { yyVAL.boolVal = BoolVal(false) } - case 142: + case 144: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:939 +//line sql.y:947 { yyVAL.boolVal = BoolVal(true) } - case 143: + case 145: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:944 +//line sql.y:952 { yyVAL.boolVal = BoolVal(false) } - case 144: + case 146: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:948 +//line sql.y:956 { yyVAL.boolVal = BoolVal(true) } - case 145: + case 147: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:954 +//line sql.y:962 { yyVAL.boolVal = BoolVal(false) } - case 146: + case 148: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:958 +//line sql.y:966 { yyVAL.boolVal = BoolVal(false) } - case 147: + case 149: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:962 +//line sql.y:970 { yyVAL.boolVal = BoolVal(true) } - case 148: + case 150: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:967 +//line sql.y:975 { yyVAL.optVal = nil } - case 149: + case 151: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:971 +//line sql.y:979 { yyVAL.optVal = yyDollar[2].expr } - case 150: + case 152: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:976 +//line sql.y:984 { yyVAL.optVal = nil } - case 151: + case 153: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:980 +//line sql.y:988 { yyVAL.optVal = yyDollar[3].expr } - case 152: + case 154: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:985 +//line sql.y:993 { yyVAL.boolVal = BoolVal(false) } - case 153: + case 155: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:989 +//line sql.y:997 { yyVAL.boolVal = BoolVal(true) } - case 154: + case 156: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:994 +//line sql.y:1002 { yyVAL.str = "" } - case 155: + case 157: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:998 +//line sql.y:1006 { yyVAL.str = string(yyDollar[3].bytes) } - case 156: + case 158: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1002 +//line sql.y:1010 { yyVAL.str = string(yyDollar[3].bytes) } - case 157: + case 159: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1007 +//line sql.y:1015 { yyVAL.str = "" } - case 158: + case 160: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1011 +//line sql.y:1019 { yyVAL.str = string(yyDollar[2].bytes) } - case 159: + case 161: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1015 +//line sql.y:1023 { yyVAL.str = string(yyDollar[2].bytes) } - case 160: + case 162: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1020 +//line sql.y:1028 { yyVAL.colKeyOpt = colKeyNone } - case 161: + case 163: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1024 +//line sql.y:1032 { yyVAL.colKeyOpt = colKeyPrimary } - case 162: + case 164: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1028 +//line sql.y:1036 { yyVAL.colKeyOpt = colKey } - case 163: + case 165: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1032 +//line sql.y:1040 { yyVAL.colKeyOpt = colKeyUniqueKey } - case 164: + case 166: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1036 +//line sql.y:1044 { yyVAL.colKeyOpt = colKeyUnique } - case 165: + case 167: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1041 +//line sql.y:1049 { yyVAL.sqlVal = nil } - case 166: + case 168: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1045 +//line sql.y:1053 { yyVAL.sqlVal = NewStrVal(yyDollar[2].bytes) } - case 167: + case 169: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1051 +//line sql.y:1059 { yyVAL.indexDefinition = &IndexDefinition{Info: yyDollar[1].indexInfo, Columns: yyDollar[3].indexColumns, Options: yyDollar[5].indexOptions} } - case 168: + case 170: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1055 +//line sql.y:1063 { yyVAL.indexDefinition = &IndexDefinition{Info: yyDollar[1].indexInfo, Columns: yyDollar[3].indexColumns} } - case 169: + case 171: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1061 +//line sql.y:1069 { yyVAL.indexOptions = []*IndexOption{yyDollar[1].indexOption} } - case 170: + case 172: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1065 +//line sql.y:1073 { yyVAL.indexOptions = append(yyVAL.indexOptions, yyDollar[2].indexOption) } - case 171: + case 173: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1071 +//line sql.y:1079 { yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Using: string(yyDollar[2].bytes)} } - case 172: + case 174: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1075 +//line sql.y:1083 { // should not be string yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Value: NewIntVal(yyDollar[3].bytes)} } - case 173: + case 175: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1080 +//line sql.y:1088 { yyVAL.indexOption = &IndexOption{Name: string(yyDollar[1].bytes), Value: NewStrVal(yyDollar[2].bytes)} } - case 174: + case 176: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1086 +//line sql.y:1094 { yyVAL.str = "" } - case 175: + case 177: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1090 +//line sql.y:1098 { yyVAL.str = string(yyDollar[1].bytes) } - case 176: + case 178: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1096 +//line sql.y:1104 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].bytes), Name: NewColIdent("PRIMARY"), Primary: true, Unique: true} } - case 177: + case 179: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1100 +//line sql.y:1108 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(yyDollar[3].str), Spatial: true, Unique: false} } - case 178: + case 180: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1104 +//line sql.y:1112 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes) + " " + string(yyDollar[2].str), Name: NewColIdent(yyDollar[3].str), Unique: true} } - case 179: + case 181: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1108 +//line sql.y:1116 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].bytes), Name: NewColIdent(yyDollar[2].str), Unique: true} } - case 180: + case 182: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1112 +//line sql.y:1120 { yyVAL.indexInfo = &IndexInfo{Type: string(yyDollar[1].str), Name: NewColIdent(yyDollar[2].str), Unique: false} } - case 181: + case 183: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1118 +//line sql.y:1126 { yyVAL.str = string(yyDollar[1].bytes) } - case 182: + case 184: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1122 +//line sql.y:1130 { yyVAL.str = string(yyDollar[1].bytes) } - case 183: + case 185: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1127 +//line sql.y:1135 { yyVAL.str = "" } - case 184: + case 186: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1131 +//line sql.y:1139 { yyVAL.str = string(yyDollar[1].bytes) } - case 185: + case 187: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1137 +//line sql.y:1145 { yyVAL.indexColumns = []*IndexColumn{yyDollar[1].indexColumn} } - case 186: + case 188: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1141 +//line sql.y:1149 { yyVAL.indexColumns = append(yyVAL.indexColumns, yyDollar[3].indexColumn) } - case 187: + case 189: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1147 +//line sql.y:1155 { yyVAL.indexColumn = &IndexColumn{Column: yyDollar[1].colIdent, Length: yyDollar[2].sqlVal} } - case 188: + case 190: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1153 +//line sql.y:1161 { yyVAL.constraintDefinition = &ConstraintDefinition{Name: string(yyDollar[2].bytes), Details: yyDollar[3].constraintInfo} } - case 189: + case 191: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1157 +//line sql.y:1165 { yyVAL.constraintDefinition = &ConstraintDefinition{Details: yyDollar[1].constraintInfo} } - case 190: + case 192: yyDollar = yyS[yypt-10 : yypt+1] -//line sql.y:1164 +//line sql.y:1172 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns} } - case 191: + case 193: yyDollar = yyS[yypt-11 : yypt+1] -//line sql.y:1168 +//line sql.y:1176 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnDelete: yyDollar[11].ReferenceAction} } - case 192: + case 194: yyDollar = yyS[yypt-11 : yypt+1] -//line sql.y:1172 +//line sql.y:1180 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnUpdate: yyDollar[11].ReferenceAction} } - case 193: + case 195: yyDollar = yyS[yypt-12 : yypt+1] -//line sql.y:1176 +//line sql.y:1184 { yyVAL.constraintInfo = &ForeignKeyDefinition{Source: yyDollar[4].columns, ReferencedTable: yyDollar[7].tableName, ReferencedColumns: yyDollar[9].columns, OnDelete: yyDollar[11].ReferenceAction, OnUpdate: yyDollar[12].ReferenceAction} } - case 194: + case 196: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1182 +//line sql.y:1190 { yyVAL.ReferenceAction = yyDollar[3].ReferenceAction } - case 195: + case 197: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1188 +//line sql.y:1196 { yyVAL.ReferenceAction = yyDollar[3].ReferenceAction } - case 196: + case 198: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1194 +//line sql.y:1202 { yyVAL.ReferenceAction = Restrict } - case 197: + case 199: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1198 +//line sql.y:1206 { yyVAL.ReferenceAction = Cascade } - case 198: + case 200: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1202 +//line sql.y:1210 { yyVAL.ReferenceAction = NoAction } - case 199: + case 201: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1206 +//line sql.y:1214 { yyVAL.ReferenceAction = SetDefault } - case 200: + case 202: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1210 +//line sql.y:1218 { yyVAL.ReferenceAction = SetNull } - case 201: + case 203: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1215 +//line sql.y:1223 { yyVAL.str = "" } - case 202: + case 204: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1219 +//line sql.y:1227 { yyVAL.str = " " + string(yyDollar[1].str) } - case 203: + case 205: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1223 +//line sql.y:1231 { yyVAL.str = string(yyDollar[1].str) + ", " + string(yyDollar[3].str) } - case 204: + case 206: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1231 +//line sql.y:1239 { yyVAL.str = yyDollar[1].str } - case 205: + case 207: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1235 +//line sql.y:1243 { yyVAL.str = yyDollar[1].str + " " + yyDollar[2].str } - case 206: + case 208: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1239 +//line sql.y:1247 { yyVAL.str = yyDollar[1].str + "=" + yyDollar[3].str } - case 207: + case 209: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1245 +//line sql.y:1253 { yyVAL.str = yyDollar[1].colIdent.String() } - case 208: + case 210: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1249 +//line sql.y:1257 { yyVAL.str = "'" + string(yyDollar[1].bytes) + "'" } - case 209: + case 211: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1253 +//line sql.y:1261 { yyVAL.str = string(yyDollar[1].bytes) } - case 210: + case 212: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:1259 +//line sql.y:1267 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName} } - case 211: + case 213: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1263 +//line sql.y:1271 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName} } - case 212: + case 214: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1267 +//line sql.y:1275 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName} } - case 213: + case 215: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1271 +//line sql.y:1279 { // Change this to a rename statement yyVAL.statement = &DDL{Action: RenameStr, FromTables: TableNames{yyDollar[4].tableName}, ToTables: TableNames{yyDollar[7].tableName}} } - case 214: + case 216: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1276 +//line sql.y:1284 { // Rename an index can just be an alter yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName} } - case 215: + case 217: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1281 +//line sql.y:1289 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[3].tableName.ToViewName()} } - case 216: + case 218: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1285 +//line sql.y:1293 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[4].tableName, PartitionSpec: yyDollar[5].partSpec} } - case 217: + case 219: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1289 +//line sql.y:1297 { yyVAL.statement = &DDL{Action: CreateVindexStr, VindexSpec: &VindexSpec{ Name: yyDollar[5].colIdent, @@ -4270,29 +4269,29 @@ yydefault: Params: yyDollar[7].vindexParams, }} } - case 218: + case 220: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1297 +//line sql.y:1305 { yyVAL.statement = &DDL{Action: DropVindexStr, VindexSpec: &VindexSpec{ Name: yyDollar[5].colIdent, }} } - case 219: + case 221: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1303 +//line sql.y:1311 { yyVAL.statement = &DDL{Action: AddVschemaTableStr, Table: yyDollar[5].tableName} } - case 220: + case 222: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1307 +//line sql.y:1315 { yyVAL.statement = &DDL{Action: DropVschemaTableStr, Table: yyDollar[5].tableName} } - case 221: + case 223: yyDollar = yyS[yypt-12 : yypt+1] -//line sql.y:1311 +//line sql.y:1319 { yyVAL.statement = &DDL{ Action: AddColVindexStr, @@ -4305,9 +4304,9 @@ yydefault: VindexCols: yyDollar[9].columns, } } - case 222: + case 224: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1324 +//line sql.y:1332 { yyVAL.statement = &DDL{ Action: DropColVindexStr, @@ -4317,59 +4316,59 @@ yydefault: }, } } - case 234: + case 236: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1349 +//line sql.y:1357 { yyVAL.partSpec = &PartitionSpec{Action: ReorganizeStr, Name: yyDollar[3].colIdent, Definitions: yyDollar[6].partDefs} } - case 235: + case 237: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1355 +//line sql.y:1363 { yyVAL.partDefs = []*PartitionDefinition{yyDollar[1].partDef} } - case 236: + case 238: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1359 +//line sql.y:1367 { yyVAL.partDefs = append(yyDollar[1].partDefs, yyDollar[3].partDef) } - case 237: + case 239: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:1365 +//line sql.y:1373 { yyVAL.partDef = &PartitionDefinition{Name: yyDollar[2].colIdent, Limit: yyDollar[7].expr} } - case 238: + case 240: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:1369 +//line sql.y:1377 { yyVAL.partDef = &PartitionDefinition{Name: yyDollar[2].colIdent, Maxvalue: true} } - case 239: + case 241: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1375 +//line sql.y:1383 { yyVAL.statement = yyDollar[3].ddl } - case 240: + case 242: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1381 +//line sql.y:1389 { yyVAL.ddl = &DDL{Action: RenameStr, FromTables: TableNames{yyDollar[1].tableName}, ToTables: TableNames{yyDollar[3].tableName}} } - case 241: + case 243: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1385 +//line sql.y:1393 { yyVAL.ddl = yyDollar[1].ddl yyVAL.ddl.FromTables = append(yyVAL.ddl.FromTables, yyDollar[3].tableName) yyVAL.ddl.ToTables = append(yyVAL.ddl.ToTables, yyDollar[5].tableName) } - case 242: + case 244: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1393 +//line sql.y:1401 { var exists bool if yyDollar[3].byt != 0 { @@ -4377,16 +4376,16 @@ yydefault: } yyVAL.statement = &DDL{Action: DropStr, FromTables: yyDollar[4].tableNames, IfExists: exists} } - case 243: + case 245: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:1401 +//line sql.y:1409 { // Change this to an alter statement yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[5].tableName} } - case 244: + case 246: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1406 +//line sql.y:1414 { var exists bool if yyDollar[3].byt != 0 { @@ -4394,69 +4393,57 @@ yydefault: } yyVAL.statement = &DDL{Action: DropStr, FromTables: TableNames{yyDollar[4].tableName.ToViewName()}, IfExists: exists} } - case 245: + case 247: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1414 +//line sql.y:1422 { yyVAL.statement = &DBDDL{Action: DropStr, DBName: string(yyDollar[4].bytes)} } - case 246: + case 248: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1418 +//line sql.y:1426 { yyVAL.statement = &DBDDL{Action: DropStr, DBName: string(yyDollar[4].bytes)} } - case 247: + case 249: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1424 +//line sql.y:1432 { yyVAL.statement = &DDL{Action: TruncateStr, Table: yyDollar[3].tableName} } - case 248: + case 250: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1428 +//line sql.y:1436 { yyVAL.statement = &DDL{Action: TruncateStr, Table: yyDollar[2].tableName} } - case 249: + case 251: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1433 +//line sql.y:1441 { yyVAL.statement = &DDL{Action: AlterStr, Table: yyDollar[3].tableName} } - case 250: + case 252: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1439 +//line sql.y:1447 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 251: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1444 - { - yyVAL.statement = &Show{Type: CharsetStr} - } - case 252: - yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1448 - { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} - } case 253: yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:1452 { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} + yyVAL.statement = &Show{Type: CharsetStr} } case 254: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1457 + yyDollar = yyS[yypt-3 : yypt+1] +//line sql.y:1456 { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} + yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } case 255: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1461 +//line sql.y:1460 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } @@ -4479,16 +4466,16 @@ yydefault: yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } case 259: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:1477 { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} + yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } case 260: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:1481 { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} + yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } case 261: yyDollar = yyS[yypt-3 : yypt+1] @@ -4497,13 +4484,13 @@ yydefault: yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } case 262: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:1489 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } case 263: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:1493 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} @@ -4515,10 +4502,10 @@ yydefault: yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } case 265: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:1501 { - yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} + yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } case 266: yyDollar = yyS[yypt-3 : yypt+1] @@ -4527,15 +4514,27 @@ yydefault: yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } case 267: - yyDollar = yyS[yypt-7 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:1509 + { + yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} + } + case 268: + yyDollar = yyS[yypt-3 : yypt+1] +//line sql.y:1513 + { + yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} + } + case 269: + yyDollar = yyS[yypt-7 : yypt+1] +//line sql.y:1517 { showTablesOpt := &ShowTablesOpt{Full: yyDollar[2].str, DbName: yyDollar[6].str, Filter: yyDollar[7].showFilter} yyVAL.statement = &Show{Type: string(yyDollar[3].str), ShowTablesOpt: showTablesOpt, OnTable: yyDollar[5].tableName} } - case 268: + case 270: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1514 +//line sql.y:1522 { // this is ugly, but I couldn't find a better way for now if yyDollar[3].str == "processlist" { @@ -4545,650 +4544,650 @@ yydefault: yyVAL.statement = &Show{Type: yyDollar[3].str, ShowTablesOpt: showTablesOpt} } } - case 269: + case 271: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1524 +//line sql.y:1532 { yyVAL.statement = &Show{Scope: yyDollar[2].str, Type: string(yyDollar[3].bytes)} } - case 270: + case 272: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1528 +//line sql.y:1536 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 271: + case 273: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1532 +//line sql.y:1540 { // Cannot dereference $4 directly, or else the parser stackcannot be pooled. See yyParsePooled showCollationFilterOpt := yyDollar[4].expr yyVAL.statement = &Show{Type: string(yyDollar[2].bytes), ShowCollationFilterOpt: &showCollationFilterOpt} } - case 272: + case 274: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1538 +//line sql.y:1546 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 273: + case 275: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1542 +//line sql.y:1550 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 274: + case 276: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1546 +//line sql.y:1554 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 275: + case 277: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1550 +//line sql.y:1558 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 276: + case 278: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1554 +//line sql.y:1562 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 277: + case 279: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1558 +//line sql.y:1566 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} } - case 278: + case 280: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1562 +//line sql.y:1570 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes), OnTable: yyDollar[5].tableName} } - case 279: + case 281: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1566 +//line sql.y:1574 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 280: + case 282: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1576 +//line sql.y:1584 { yyVAL.statement = &Show{Type: string(yyDollar[2].bytes)} } - case 281: + case 283: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1582 +//line sql.y:1590 { yyVAL.str = string(yyDollar[1].bytes) } - case 282: + case 284: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1586 +//line sql.y:1594 { yyVAL.str = string(yyDollar[1].bytes) } - case 283: + case 285: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1592 +//line sql.y:1600 { yyVAL.str = "" } - case 284: + case 286: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1596 +//line sql.y:1604 { yyVAL.str = "full " } - case 285: + case 287: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1602 +//line sql.y:1610 { yyVAL.str = string(yyDollar[1].bytes) } - case 286: + case 288: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1606 +//line sql.y:1614 { yyVAL.str = string(yyDollar[1].bytes) } - case 287: + case 289: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1612 +//line sql.y:1620 { yyVAL.str = "" } - case 288: + case 290: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1616 +//line sql.y:1624 { yyVAL.str = yyDollar[2].tableIdent.v } - case 289: + case 291: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1620 +//line sql.y:1628 { yyVAL.str = yyDollar[2].tableIdent.v } - case 290: + case 292: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1626 +//line sql.y:1634 { yyVAL.showFilter = nil } - case 291: + case 293: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1630 +//line sql.y:1638 { yyVAL.showFilter = &ShowFilter{Like: string(yyDollar[2].bytes)} } - case 292: + case 294: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1634 +//line sql.y:1642 { yyVAL.showFilter = &ShowFilter{Filter: yyDollar[2].expr} } - case 293: + case 295: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1640 +//line sql.y:1648 { yyVAL.str = "" } - case 294: + case 296: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1644 +//line sql.y:1652 { yyVAL.str = SessionStr } - case 295: + case 297: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1648 +//line sql.y:1656 { yyVAL.str = GlobalStr } - case 296: + case 298: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1654 +//line sql.y:1662 { yyVAL.statement = &Use{DBName: yyDollar[2].tableIdent} } - case 297: + case 299: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1658 +//line sql.y:1666 { yyVAL.statement = &Use{DBName: TableIdent{v: ""}} } - case 298: + case 300: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1664 +//line sql.y:1672 { yyVAL.statement = &Begin{} } - case 299: + case 301: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1668 +//line sql.y:1676 { yyVAL.statement = &Begin{} } - case 300: + case 302: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1674 +//line sql.y:1682 { yyVAL.statement = &Commit{} } - case 301: + case 303: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1680 +//line sql.y:1688 { yyVAL.statement = &Rollback{} } - case 302: + case 304: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1686 +//line sql.y:1694 { yyVAL.statement = &OtherRead{} } - case 303: + case 305: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1690 +//line sql.y:1698 { yyVAL.statement = &OtherRead{} } - case 304: + case 306: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1694 +//line sql.y:1702 { yyVAL.statement = &OtherRead{} } - case 305: + case 307: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1698 +//line sql.y:1706 { yyVAL.statement = &OtherAdmin{} } - case 306: + case 308: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1702 +//line sql.y:1710 { yyVAL.statement = &OtherAdmin{} } - case 307: + case 309: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1706 +//line sql.y:1714 { yyVAL.statement = &OtherAdmin{} } - case 308: + case 310: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1710 +//line sql.y:1718 { yyVAL.statement = &OtherAdmin{} } - case 309: + case 311: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1716 +//line sql.y:1724 { yyVAL.statement = &DDL{Action: FlushStr} } - case 310: + case 312: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1720 +//line sql.y:1728 { setAllowComments(yylex, true) } - case 311: + case 313: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1724 +//line sql.y:1732 { yyVAL.bytes2 = yyDollar[2].bytes2 setAllowComments(yylex, false) } - case 312: + case 314: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1730 +//line sql.y:1738 { yyVAL.bytes2 = nil } - case 313: + case 315: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1734 +//line sql.y:1742 { yyVAL.bytes2 = append(yyDollar[1].bytes2, yyDollar[2].bytes) } - case 314: + case 316: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1740 +//line sql.y:1748 { yyVAL.str = UnionStr } - case 315: + case 317: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1744 +//line sql.y:1752 { yyVAL.str = UnionAllStr } - case 316: + case 318: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1748 +//line sql.y:1756 { yyVAL.str = UnionDistinctStr } - case 317: + case 319: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1753 +//line sql.y:1761 { yyVAL.str = "" } - case 318: + case 320: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1757 +//line sql.y:1765 { yyVAL.str = SQLNoCacheStr } - case 319: + case 321: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1761 +//line sql.y:1769 { yyVAL.str = SQLCacheStr } - case 320: + case 322: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1766 +//line sql.y:1774 { yyVAL.str = "" } - case 321: + case 323: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1770 +//line sql.y:1778 { yyVAL.str = DistinctStr } - case 322: + case 324: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1775 +//line sql.y:1783 { yyVAL.str = "" } - case 323: + case 325: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1779 +//line sql.y:1787 { yyVAL.str = StraightJoinHint } - case 324: + case 326: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1784 +//line sql.y:1792 { yyVAL.selectExprs = nil } - case 325: + case 327: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1788 +//line sql.y:1796 { yyVAL.selectExprs = yyDollar[1].selectExprs } - case 326: + case 328: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1794 +//line sql.y:1802 { yyVAL.selectExprs = SelectExprs{yyDollar[1].selectExpr} } - case 327: + case 329: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1798 +//line sql.y:1806 { yyVAL.selectExprs = append(yyVAL.selectExprs, yyDollar[3].selectExpr) } - case 328: + case 330: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1804 +//line sql.y:1812 { yyVAL.selectExpr = &StarExpr{} } - case 329: + case 331: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1808 +//line sql.y:1816 { yyVAL.selectExpr = &AliasedExpr{Expr: yyDollar[1].expr, As: yyDollar[2].colIdent} } - case 330: + case 332: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1812 +//line sql.y:1820 { yyVAL.selectExpr = &StarExpr{TableName: TableName{Name: yyDollar[1].tableIdent}} } - case 331: + case 333: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:1816 +//line sql.y:1824 { yyVAL.selectExpr = &StarExpr{TableName: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}} } - case 332: + case 334: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1821 +//line sql.y:1829 { yyVAL.colIdent = ColIdent{} } - case 333: + case 335: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1825 +//line sql.y:1833 { yyVAL.colIdent = yyDollar[1].colIdent } - case 334: + case 336: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1829 +//line sql.y:1837 { yyVAL.colIdent = yyDollar[2].colIdent } - case 336: + case 338: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1836 +//line sql.y:1844 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 337: + case 339: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1841 +//line sql.y:1849 { yyVAL.tableExprs = TableExprs{&AliasedTableExpr{Expr: TableName{Name: NewTableIdent("dual")}}} } - case 338: + case 340: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1845 +//line sql.y:1853 { yyVAL.tableExprs = yyDollar[2].tableExprs } - case 339: + case 341: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1851 +//line sql.y:1859 { yyVAL.tableExprs = TableExprs{yyDollar[1].tableExpr} } - case 340: + case 342: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1855 +//line sql.y:1863 { yyVAL.tableExprs = append(yyVAL.tableExprs, yyDollar[3].tableExpr) } - case 343: + case 345: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1865 +//line sql.y:1873 { yyVAL.tableExpr = yyDollar[1].aliasedTableName } - case 344: + case 346: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1869 +//line sql.y:1877 { yyVAL.tableExpr = &AliasedTableExpr{Expr: yyDollar[1].subquery, As: yyDollar[3].tableIdent} } - case 345: + case 347: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1873 +//line sql.y:1881 { // missed alias for subquery yylex.Error("Every derived table must have its own alias") return 1 } - case 346: + case 348: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1879 +//line sql.y:1887 { yyVAL.tableExpr = &ParenTableExpr{Exprs: yyDollar[2].tableExprs} } - case 347: + case 349: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1885 +//line sql.y:1893 { yyVAL.aliasedTableName = &AliasedTableExpr{Expr: yyDollar[1].tableName, As: yyDollar[2].tableIdent, Hints: yyDollar[3].indexHints} } - case 348: + case 350: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:1889 +//line sql.y:1897 { yyVAL.aliasedTableName = &AliasedTableExpr{Expr: yyDollar[1].tableName, Partitions: yyDollar[4].partitions, As: yyDollar[6].tableIdent, Hints: yyDollar[7].indexHints} } - case 349: + case 351: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1895 +//line sql.y:1903 { yyVAL.columns = Columns{yyDollar[1].colIdent} } - case 350: + case 352: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1899 +//line sql.y:1907 { yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) } - case 351: + case 353: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1905 +//line sql.y:1913 { yyVAL.partitions = Partitions{yyDollar[1].colIdent} } - case 352: + case 354: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1909 +//line sql.y:1917 { yyVAL.partitions = append(yyVAL.partitions, yyDollar[3].colIdent) } - case 353: + case 355: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1922 +//line sql.y:1930 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 354: + case 356: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1926 +//line sql.y:1934 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 355: + case 357: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1930 +//line sql.y:1938 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr, Condition: yyDollar[4].joinCondition} } - case 356: + case 358: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:1934 +//line sql.y:1942 { yyVAL.tableExpr = &JoinTableExpr{LeftExpr: yyDollar[1].tableExpr, Join: yyDollar[2].str, RightExpr: yyDollar[3].tableExpr} } - case 357: + case 359: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1940 +//line sql.y:1948 { yyVAL.joinCondition = JoinCondition{On: yyDollar[2].expr} } - case 358: + case 360: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:1942 +//line sql.y:1950 { yyVAL.joinCondition = JoinCondition{Using: yyDollar[3].columns} } - case 359: + case 361: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1946 +//line sql.y:1954 { yyVAL.joinCondition = JoinCondition{} } - case 360: + case 362: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1948 +//line sql.y:1956 { yyVAL.joinCondition = yyDollar[1].joinCondition } - case 361: + case 363: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1952 +//line sql.y:1960 { yyVAL.joinCondition = JoinCondition{} } - case 362: + case 364: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1954 +//line sql.y:1962 { yyVAL.joinCondition = JoinCondition{On: yyDollar[2].expr} } - case 363: + case 365: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1957 +//line sql.y:1965 { yyVAL.empty = struct{}{} } - case 364: + case 366: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1959 +//line sql.y:1967 { yyVAL.empty = struct{}{} } - case 365: + case 367: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:1962 +//line sql.y:1970 { yyVAL.tableIdent = NewTableIdent("") } - case 366: + case 368: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1966 +//line sql.y:1974 { yyVAL.tableIdent = yyDollar[1].tableIdent } - case 367: + case 369: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1970 +//line sql.y:1978 { yyVAL.tableIdent = yyDollar[2].tableIdent } - case 369: + case 371: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1977 +//line sql.y:1985 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 370: + case 372: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1983 +//line sql.y:1991 { yyVAL.str = JoinStr } - case 371: + case 373: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1987 +//line sql.y:1995 { yyVAL.str = JoinStr } - case 372: + case 374: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:1991 +//line sql.y:1999 { yyVAL.str = JoinStr } - case 373: + case 375: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:1997 +//line sql.y:2005 { yyVAL.str = StraightJoinStr } - case 374: + case 376: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2003 +//line sql.y:2011 { yyVAL.str = LeftJoinStr } - case 375: + case 377: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2007 +//line sql.y:2015 { yyVAL.str = LeftJoinStr } - case 376: + case 378: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2011 +//line sql.y:2019 { yyVAL.str = RightJoinStr } - case 377: + case 379: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2015 +//line sql.y:2023 { yyVAL.str = RightJoinStr } - case 378: + case 380: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2021 +//line sql.y:2029 { yyVAL.str = NaturalJoinStr } - case 379: + case 381: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2025 +//line sql.y:2033 { if yyDollar[2].str == LeftJoinStr { yyVAL.str = NaturalLeftJoinStr @@ -5196,459 +5195,459 @@ yydefault: yyVAL.str = NaturalRightJoinStr } } - case 380: + case 382: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2035 +//line sql.y:2043 { yyVAL.tableName = yyDollar[2].tableName } - case 381: + case 383: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2039 +//line sql.y:2047 { yyVAL.tableName = yyDollar[1].tableName } - case 382: + case 384: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2045 +//line sql.y:2053 { yyVAL.tableName = TableName{Name: yyDollar[1].tableIdent} } - case 383: + case 385: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2049 +//line sql.y:2057 { yyVAL.tableName = TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent} } - case 384: + case 386: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2054 +//line sql.y:2062 { yyVAL.indexHints = nil } - case 385: + case 387: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2058 +//line sql.y:2066 { yyVAL.indexHints = &IndexHints{Type: UseStr, Indexes: yyDollar[4].columns} } - case 386: + case 388: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2062 +//line sql.y:2070 { yyVAL.indexHints = &IndexHints{Type: IgnoreStr, Indexes: yyDollar[4].columns} } - case 387: + case 389: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2066 +//line sql.y:2074 { yyVAL.indexHints = &IndexHints{Type: ForceStr, Indexes: yyDollar[4].columns} } - case 388: + case 390: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2071 +//line sql.y:2079 { yyVAL.expr = nil } - case 389: + case 391: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2075 +//line sql.y:2083 { yyVAL.expr = yyDollar[2].expr } - case 390: + case 392: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2081 +//line sql.y:2089 { yyVAL.expr = yyDollar[1].expr } - case 391: + case 393: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2085 +//line sql.y:2093 { yyVAL.expr = &AndExpr{Left: yyDollar[1].expr, Right: yyDollar[3].expr} } - case 392: + case 394: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2089 +//line sql.y:2097 { yyVAL.expr = &OrExpr{Left: yyDollar[1].expr, Right: yyDollar[3].expr} } - case 393: + case 395: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2093 +//line sql.y:2101 { yyVAL.expr = &NotExpr{Expr: yyDollar[2].expr} } - case 394: + case 396: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2097 +//line sql.y:2105 { yyVAL.expr = &IsExpr{Operator: yyDollar[3].str, Expr: yyDollar[1].expr} } - case 395: + case 397: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2101 +//line sql.y:2109 { yyVAL.expr = yyDollar[1].expr } - case 396: + case 398: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2105 +//line sql.y:2113 { yyVAL.expr = &Default{ColName: yyDollar[2].str} } - case 397: + case 399: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2111 +//line sql.y:2119 { yyVAL.str = "" } - case 398: + case 400: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2115 +//line sql.y:2123 { yyVAL.str = string(yyDollar[2].bytes) } - case 399: + case 401: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2121 +//line sql.y:2129 { yyVAL.boolVal = BoolVal(true) } - case 400: + case 402: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2125 +//line sql.y:2133 { yyVAL.boolVal = BoolVal(false) } - case 401: + case 403: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2131 +//line sql.y:2139 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: yyDollar[2].str, Right: yyDollar[3].expr} } - case 402: + case 404: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2135 +//line sql.y:2143 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: InStr, Right: yyDollar[3].colTuple} } - case 403: + case 405: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2139 +//line sql.y:2147 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotInStr, Right: yyDollar[4].colTuple} } - case 404: + case 406: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2143 +//line sql.y:2151 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: LikeStr, Right: yyDollar[3].expr, Escape: yyDollar[4].expr} } - case 405: + case 407: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2147 +//line sql.y:2155 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotLikeStr, Right: yyDollar[4].expr, Escape: yyDollar[5].expr} } - case 406: + case 408: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2151 +//line sql.y:2159 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: RegexpStr, Right: yyDollar[3].expr} } - case 407: + case 409: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2155 +//line sql.y:2163 { yyVAL.expr = &ComparisonExpr{Left: yyDollar[1].expr, Operator: NotRegexpStr, Right: yyDollar[4].expr} } - case 408: + case 410: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2159 +//line sql.y:2167 { yyVAL.expr = &RangeCond{Left: yyDollar[1].expr, Operator: BetweenStr, From: yyDollar[3].expr, To: yyDollar[5].expr} } - case 409: + case 411: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2163 +//line sql.y:2171 { yyVAL.expr = &RangeCond{Left: yyDollar[1].expr, Operator: NotBetweenStr, From: yyDollar[4].expr, To: yyDollar[6].expr} } - case 410: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2167 - { - yyVAL.expr = &ExistsExpr{Subquery: yyDollar[2].subquery} - } - case 411: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2173 - { - yyVAL.str = IsNullStr - } case 412: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2177 +//line sql.y:2175 { - yyVAL.str = IsNotNullStr + yyVAL.expr = &ExistsExpr{Subquery: yyDollar[2].subquery} } case 413: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2181 { - yyVAL.str = IsTrueStr + yyVAL.str = IsNullStr } case 414: yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:2185 { - yyVAL.str = IsNotTrueStr + yyVAL.str = IsNotNullStr } case 415: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2189 { - yyVAL.str = IsFalseStr + yyVAL.str = IsTrueStr } case 416: yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:2193 { - yyVAL.str = IsNotFalseStr + yyVAL.str = IsNotTrueStr } case 417: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2199 +//line sql.y:2197 { - yyVAL.str = EqualStr + yyVAL.str = IsFalseStr } case 418: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2203 + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2201 { - yyVAL.str = LessThanStr + yyVAL.str = IsNotFalseStr } case 419: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2207 { - yyVAL.str = GreaterThanStr + yyVAL.str = EqualStr } case 420: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2211 { - yyVAL.str = LessEqualStr + yyVAL.str = LessThanStr } case 421: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2215 { - yyVAL.str = GreaterEqualStr + yyVAL.str = GreaterThanStr } case 422: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2219 { - yyVAL.str = NotEqualStr + yyVAL.str = LessEqualStr } case 423: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2223 { - yyVAL.str = NullSafeEqualStr + yyVAL.str = GreaterEqualStr } case 424: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2228 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:2227 { - yyVAL.expr = nil + yyVAL.str = NotEqualStr } case 425: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2232 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:2231 { - yyVAL.expr = yyDollar[2].expr + yyVAL.str = NullSafeEqualStr } case 426: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2238 + yyDollar = yyS[yypt-0 : yypt+1] +//line sql.y:2236 { - yyVAL.colTuple = yyDollar[1].valTuple + yyVAL.expr = nil } case 427: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2242 + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2240 { - yyVAL.colTuple = yyDollar[1].subquery + yyVAL.expr = yyDollar[2].expr } case 428: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2246 { - yyVAL.colTuple = ListArg(yyDollar[1].bytes) + yyVAL.colTuple = yyDollar[1].valTuple } case 429: - yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2252 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:2250 { - yyVAL.subquery = &Subquery{yyDollar[2].selStmt} + yyVAL.colTuple = yyDollar[1].subquery } case 430: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2258 +//line sql.y:2254 { - yyVAL.exprs = Exprs{yyDollar[1].expr} + yyVAL.colTuple = ListArg(yyDollar[1].bytes) } case 431: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2262 +//line sql.y:2260 { - yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) + yyVAL.subquery = &Subquery{yyDollar[2].selStmt} } case 432: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2268 +//line sql.y:2266 { - yyVAL.expr = yyDollar[1].expr + yyVAL.exprs = Exprs{yyDollar[1].expr} } case 433: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2272 + yyDollar = yyS[yypt-3 : yypt+1] +//line sql.y:2270 { - yyVAL.expr = yyDollar[1].boolVal + yyVAL.exprs = append(yyDollar[1].exprs, yyDollar[3].expr) } case 434: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2276 { - yyVAL.expr = yyDollar[1].colName + yyVAL.expr = yyDollar[1].expr } case 435: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2280 { - yyVAL.expr = yyDollar[1].expr + yyVAL.expr = yyDollar[1].boolVal } case 436: yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2284 { - yyVAL.expr = yyDollar[1].subquery + yyVAL.expr = yyDollar[1].colName } case 437: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2288 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitAndStr, Right: yyDollar[3].expr} + yyVAL.expr = yyDollar[1].expr } case 438: - yyDollar = yyS[yypt-3 : yypt+1] + yyDollar = yyS[yypt-1 : yypt+1] //line sql.y:2292 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitOrStr, Right: yyDollar[3].expr} + yyVAL.expr = yyDollar[1].subquery } case 439: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2296 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitXorStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitAndStr, Right: yyDollar[3].expr} } case 440: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2300 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: PlusStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitOrStr, Right: yyDollar[3].expr} } case 441: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2304 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MinusStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: BitXorStr, Right: yyDollar[3].expr} } case 442: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2308 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MultStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: PlusStr, Right: yyDollar[3].expr} } case 443: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2312 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: DivStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MinusStr, Right: yyDollar[3].expr} } case 444: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2316 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: IntDivStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: MultStr, Right: yyDollar[3].expr} } case 445: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2320 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: DivStr, Right: yyDollar[3].expr} } case 446: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2324 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: IntDivStr, Right: yyDollar[3].expr} } case 447: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2328 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftLeftStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} } case 448: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2332 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftRightStr, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ModStr, Right: yyDollar[3].expr} } case 449: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2336 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONExtractOp, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftLeftStr, Right: yyDollar[3].expr} } case 450: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2340 { - yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONUnquoteExtractOp, Right: yyDollar[3].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].expr, Operator: ShiftRightStr, Right: yyDollar[3].expr} } case 451: yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2344 { - yyVAL.expr = &CollateExpr{Expr: yyDollar[1].expr, Charset: yyDollar[3].str} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONExtractOp, Right: yyDollar[3].expr} } case 452: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2348 { - yyVAL.expr = &UnaryExpr{Operator: BinaryStr, Expr: yyDollar[2].expr} + yyVAL.expr = &BinaryExpr{Left: yyDollar[1].colName, Operator: JSONUnquoteExtractOp, Right: yyDollar[3].expr} } case 453: - yyDollar = yyS[yypt-2 : yypt+1] + yyDollar = yyS[yypt-3 : yypt+1] //line sql.y:2352 { - yyVAL.expr = &UnaryExpr{Operator: UBinaryStr, Expr: yyDollar[2].expr} + yyVAL.expr = &CollateExpr{Expr: yyDollar[1].expr, Charset: yyDollar[3].str} } case 454: yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:2356 { - yyVAL.expr = &UnaryExpr{Operator: Utf8mb4Str, Expr: yyDollar[2].expr} + yyVAL.expr = &UnaryExpr{Operator: BinaryStr, Expr: yyDollar[2].expr} } case 455: yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:2360 + { + yyVAL.expr = &UnaryExpr{Operator: UBinaryStr, Expr: yyDollar[2].expr} + } + case 456: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2364 + { + yyVAL.expr = &UnaryExpr{Operator: Utf8mb4Str, Expr: yyDollar[2].expr} + } + case 457: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2368 { if num, ok := yyDollar[2].expr.(*SQLVal); ok && num.Type == IntVal { yyVAL.expr = num @@ -5656,9 +5655,9 @@ yydefault: yyVAL.expr = &UnaryExpr{Operator: UPlusStr, Expr: yyDollar[2].expr} } } - case 456: + case 458: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2368 +//line sql.y:2376 { if num, ok := yyDollar[2].expr.(*SQLVal); ok && num.Type == IntVal { // Handle double negative @@ -5672,21 +5671,21 @@ yydefault: yyVAL.expr = &UnaryExpr{Operator: UMinusStr, Expr: yyDollar[2].expr} } } - case 457: + case 459: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2382 +//line sql.y:2390 { yyVAL.expr = &UnaryExpr{Operator: TildaStr, Expr: yyDollar[2].expr} } - case 458: + case 460: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2386 +//line sql.y:2394 { yyVAL.expr = &UnaryExpr{Operator: BangStr, Expr: yyDollar[2].expr} } - case 459: + case 461: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2390 +//line sql.y:2398 { // This rule prevents the usage of INTERVAL // as a function. If support is needed for that, @@ -5694,77 +5693,65 @@ yydefault: // will be non-trivial because of grammar conflicts. yyVAL.expr = &IntervalExpr{Expr: yyDollar[2].expr, Unit: yyDollar[3].colIdent.String()} } - case 464: + case 466: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2408 +//line sql.y:2416 { yyVAL.expr = &FuncExpr{Name: yyDollar[1].colIdent, Exprs: yyDollar[3].selectExprs} } - case 465: + case 467: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2412 +//line sql.y:2420 { yyVAL.expr = &FuncExpr{Name: yyDollar[1].colIdent, Distinct: true, Exprs: yyDollar[4].selectExprs} } - case 466: + case 468: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2416 +//line sql.y:2424 { yyVAL.expr = &FuncExpr{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].colIdent, Exprs: yyDollar[5].selectExprs} } - case 467: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2426 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("left"), Exprs: yyDollar[3].selectExprs} - } - case 468: - yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2430 - { - yyVAL.expr = &FuncExpr{Name: NewColIdent("right"), Exprs: yyDollar[3].selectExprs} - } case 469: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:2434 { - yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} + yyVAL.expr = &FuncExpr{Name: NewColIdent("left"), Exprs: yyDollar[3].selectExprs} } case 470: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:2438 { - yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} + yyVAL.expr = &FuncExpr{Name: NewColIdent("right"), Exprs: yyDollar[3].selectExprs} } case 471: yyDollar = yyS[yypt-6 : yypt+1] //line sql.y:2442 { - yyVAL.expr = &ConvertUsingExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].str} + yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} } case 472: yyDollar = yyS[yypt-6 : yypt+1] //line sql.y:2446 { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} + yyVAL.expr = &ConvertExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].convertType} } case 473: - yyDollar = yyS[yypt-8 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] //line sql.y:2450 { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} + yyVAL.expr = &ConvertUsingExpr{Expr: yyDollar[3].expr, Type: yyDollar[5].str} } case 474: - yyDollar = yyS[yypt-8 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] //line sql.y:2454 { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} + yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} } case 475: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] //line sql.y:2458 { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} + yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } case 476: yyDollar = yyS[yypt-8 : yypt+1] @@ -5773,34 +5760,34 @@ yydefault: yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } case 477: - yyDollar = yyS[yypt-8 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] //line sql.y:2466 { - yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} + yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: nil} } case 478: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] //line sql.y:2470 { - yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: nil} + yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } case 479: yyDollar = yyS[yypt-8 : yypt+1] //line sql.y:2474 { - yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} + yyVAL.expr = &SubstrExpr{Name: yyDollar[3].colName, From: yyDollar[5].expr, To: yyDollar[7].expr} } case 480: - yyDollar = yyS[yypt-8 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] //line sql.y:2478 { - yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} + yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: nil} } case 481: - yyDollar = yyS[yypt-6 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] //line sql.y:2482 { - yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: nil} + yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} } case 482: yyDollar = yyS[yypt-8 : yypt+1] @@ -5809,406 +5796,418 @@ yydefault: yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} } case 483: - yyDollar = yyS[yypt-8 : yypt+1] + yyDollar = yyS[yypt-6 : yypt+1] //line sql.y:2490 { - yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} + yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: nil} } case 484: - yyDollar = yyS[yypt-9 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] //line sql.y:2494 { - yyVAL.expr = &MatchExpr{Columns: yyDollar[3].selectExprs, Expr: yyDollar[7].expr, Option: yyDollar[8].str} + yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} } case 485: - yyDollar = yyS[yypt-7 : yypt+1] + yyDollar = yyS[yypt-8 : yypt+1] //line sql.y:2498 { - yyVAL.expr = &GroupConcatExpr{Distinct: yyDollar[3].str, Exprs: yyDollar[4].selectExprs, OrderBy: yyDollar[5].orderBy, Separator: yyDollar[6].str} + yyVAL.expr = &SubstrExpr{StrVal: NewStrVal(yyDollar[3].bytes), From: yyDollar[5].expr, To: yyDollar[7].expr} } case 486: - yyDollar = yyS[yypt-5 : yypt+1] + yyDollar = yyS[yypt-9 : yypt+1] //line sql.y:2502 { - yyVAL.expr = &CaseExpr{Expr: yyDollar[2].expr, Whens: yyDollar[3].whens, Else: yyDollar[4].expr} + yyVAL.expr = &MatchExpr{Columns: yyDollar[3].selectExprs, Expr: yyDollar[7].expr, Option: yyDollar[8].str} } case 487: - yyDollar = yyS[yypt-4 : yypt+1] + yyDollar = yyS[yypt-7 : yypt+1] //line sql.y:2506 { - yyVAL.expr = &ValuesFuncExpr{Name: yyDollar[3].colName} + yyVAL.expr = &GroupConcatExpr{Distinct: yyDollar[3].str, Exprs: yyDollar[4].selectExprs, OrderBy: yyDollar[5].orderBy, Separator: yyDollar[6].str} } case 488: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2516 + yyDollar = yyS[yypt-5 : yypt+1] +//line sql.y:2510 { - yyVAL.expr = &FuncExpr{Name: NewColIdent("current_timestamp")} + yyVAL.expr = &CaseExpr{Expr: yyDollar[2].expr, Whens: yyDollar[3].whens, Else: yyDollar[4].expr} } case 489: - yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2520 + yyDollar = yyS[yypt-4 : yypt+1] +//line sql.y:2514 { - yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_timestamp")} + yyVAL.expr = &ValuesFuncExpr{Name: yyDollar[3].colName} } case 490: yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:2524 { - yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_time")} + yyVAL.expr = &FuncExpr{Name: NewColIdent("current_timestamp")} } case 491: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2529 +//line sql.y:2528 { - yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_date")} + yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_timestamp")} } case 492: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2534 +//line sql.y:2532 { - yyVAL.expr = &FuncExpr{Name: NewColIdent("localtime")} + yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_time")} } case 493: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2539 +//line sql.y:2537 { - yyVAL.expr = &FuncExpr{Name: NewColIdent("localtimestamp")} + yyVAL.expr = &FuncExpr{Name: NewColIdent("utc_date")} } case 494: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2545 +//line sql.y:2542 { - yyVAL.expr = &FuncExpr{Name: NewColIdent("current_date")} + yyVAL.expr = &FuncExpr{Name: NewColIdent("localtime")} } case 495: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2550 +//line sql.y:2547 { - yyVAL.expr = &FuncExpr{Name: NewColIdent("current_time")} + yyVAL.expr = &FuncExpr{Name: NewColIdent("localtimestamp")} } case 496: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2555 +//line sql.y:2553 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_timestamp"), Fsp: yyDollar[2].expr} + yyVAL.expr = &FuncExpr{Name: NewColIdent("current_date")} } case 497: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2559 +//line sql.y:2558 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_timestamp"), Fsp: yyDollar[2].expr} + yyVAL.expr = &FuncExpr{Name: NewColIdent("current_time")} } case 498: yyDollar = yyS[yypt-2 : yypt+1] //line sql.y:2563 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_time"), Fsp: yyDollar[2].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_timestamp"), Fsp: yyDollar[2].expr} } case 499: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2568 +//line sql.y:2567 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtime"), Fsp: yyDollar[2].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_timestamp"), Fsp: yyDollar[2].expr} } case 500: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2573 +//line sql.y:2571 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtimestamp"), Fsp: yyDollar[2].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("utc_time"), Fsp: yyDollar[2].expr} } case 501: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2578 +//line sql.y:2576 { - yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_time"), Fsp: yyDollar[2].expr} + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtime"), Fsp: yyDollar[2].expr} } case 502: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2581 + { + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("localtimestamp"), Fsp: yyDollar[2].expr} + } + case 503: + yyDollar = yyS[yypt-2 : yypt+1] +//line sql.y:2586 + { + yyVAL.expr = &CurTimeFuncExpr{Name: NewColIdent("current_time"), Fsp: yyDollar[2].expr} + } + case 504: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2582 +//line sql.y:2590 { yyVAL.expr = &TimestampFuncExpr{Name: string("timestampadd"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].expr, Expr2: yyDollar[7].expr} } - case 503: + case 505: yyDollar = yyS[yypt-8 : yypt+1] -//line sql.y:2586 +//line sql.y:2594 { yyVAL.expr = &TimestampFuncExpr{Name: string("timestampdiff"), Unit: yyDollar[3].colIdent.String(), Expr1: yyDollar[5].expr, Expr2: yyDollar[7].expr} } - case 506: + case 508: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2596 +//line sql.y:2604 { yyVAL.expr = yyDollar[2].expr } - case 507: + case 509: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2606 +//line sql.y:2614 { yyVAL.expr = &FuncExpr{Name: NewColIdent("if"), Exprs: yyDollar[3].selectExprs} } - case 508: + case 510: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2610 +//line sql.y:2618 { yyVAL.expr = &FuncExpr{Name: NewColIdent("database"), Exprs: yyDollar[3].selectExprs} } - case 509: + case 511: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2614 +//line sql.y:2622 { yyVAL.expr = &FuncExpr{Name: NewColIdent("mod"), Exprs: yyDollar[3].selectExprs} } - case 510: + case 512: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2618 +//line sql.y:2626 { yyVAL.expr = &FuncExpr{Name: NewColIdent("replace"), Exprs: yyDollar[3].selectExprs} } - case 511: + case 513: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2624 +//line sql.y:2632 { yyVAL.str = "" } - case 512: + case 514: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2628 +//line sql.y:2636 { yyVAL.str = BooleanModeStr } - case 513: + case 515: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2632 +//line sql.y:2640 { yyVAL.str = NaturalLanguageModeStr } - case 514: + case 516: yyDollar = yyS[yypt-7 : yypt+1] -//line sql.y:2636 +//line sql.y:2644 { yyVAL.str = NaturalLanguageModeWithQueryExpansionStr } - case 515: + case 517: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2640 +//line sql.y:2648 { yyVAL.str = QueryExpansionStr } - case 516: + case 518: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2646 +//line sql.y:2654 { yyVAL.str = string(yyDollar[1].bytes) } - case 517: + case 519: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2650 +//line sql.y:2658 { yyVAL.str = string(yyDollar[1].bytes) } - case 518: + case 520: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2656 +//line sql.y:2664 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } - case 519: + case 521: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2660 +//line sql.y:2668 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: yyDollar[3].str, Operator: CharacterSetStr} } - case 520: + case 522: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2664 +//line sql.y:2672 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal, Charset: string(yyDollar[3].bytes)} } - case 521: + case 523: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2668 +//line sql.y:2676 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 522: + case 524: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2672 +//line sql.y:2680 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } - case 523: + case 525: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2676 +//line sql.y:2684 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} yyVAL.convertType.Length = yyDollar[2].LengthScaleOption.Length yyVAL.convertType.Scale = yyDollar[2].LengthScaleOption.Scale } - case 524: + case 526: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2682 +//line sql.y:2690 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 525: + case 527: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2686 +//line sql.y:2694 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } - case 526: + case 528: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2690 +//line sql.y:2698 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 527: + case 529: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2694 +//line sql.y:2702 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 528: + case 530: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2698 +//line sql.y:2706 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes), Length: yyDollar[2].sqlVal} } - case 529: + case 531: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2702 +//line sql.y:2710 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 530: + case 532: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2706 +//line sql.y:2714 { yyVAL.convertType = &ConvertType{Type: string(yyDollar[1].bytes)} } - case 531: + case 533: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2711 +//line sql.y:2719 { yyVAL.expr = nil } - case 532: + case 534: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2715 +//line sql.y:2723 { yyVAL.expr = yyDollar[1].expr } - case 533: + case 535: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2720 +//line sql.y:2728 { yyVAL.str = string("") } - case 534: + case 536: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2724 +//line sql.y:2732 { yyVAL.str = " separator '" + string(yyDollar[2].bytes) + "'" } - case 535: + case 537: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2730 +//line sql.y:2738 { yyVAL.whens = []*When{yyDollar[1].when} } - case 536: + case 538: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2734 +//line sql.y:2742 { yyVAL.whens = append(yyDollar[1].whens, yyDollar[2].when) } - case 537: + case 539: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2740 +//line sql.y:2748 { yyVAL.when = &When{Cond: yyDollar[2].expr, Val: yyDollar[4].expr} } - case 538: + case 540: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2745 +//line sql.y:2753 { yyVAL.expr = nil } - case 539: + case 541: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2749 +//line sql.y:2757 { yyVAL.expr = yyDollar[2].expr } - case 540: + case 542: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2755 +//line sql.y:2763 { yyVAL.colName = &ColName{Name: yyDollar[1].colIdent} } - case 541: + case 543: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2759 +//line sql.y:2767 { yyVAL.colName = &ColName{Qualifier: TableName{Name: yyDollar[1].tableIdent}, Name: yyDollar[3].colIdent} } - case 542: + case 544: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2763 +//line sql.y:2771 { yyVAL.colName = &ColName{Qualifier: TableName{Qualifier: yyDollar[1].tableIdent, Name: yyDollar[3].tableIdent}, Name: yyDollar[5].colIdent} } - case 543: + case 545: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2769 +//line sql.y:2777 { yyVAL.expr = NewStrVal(yyDollar[1].bytes) } - case 544: + case 546: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2773 +//line sql.y:2781 { yyVAL.expr = NewHexVal(yyDollar[1].bytes) } - case 545: + case 547: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2777 +//line sql.y:2785 { yyVAL.expr = NewBitVal(yyDollar[1].bytes) } - case 546: + case 548: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2781 +//line sql.y:2789 { yyVAL.expr = NewIntVal(yyDollar[1].bytes) } - case 547: + case 549: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2785 +//line sql.y:2793 { yyVAL.expr = NewFloatVal(yyDollar[1].bytes) } - case 548: + case 550: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2789 +//line sql.y:2797 { yyVAL.expr = NewHexNum(yyDollar[1].bytes) } - case 549: + case 551: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2793 +//line sql.y:2801 { yyVAL.expr = NewValArg(yyDollar[1].bytes) } - case 550: + case 552: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2797 +//line sql.y:2805 { yyVAL.expr = &NullVal{} } - case 551: + case 553: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2803 +//line sql.y:2811 { // TODO(sougou): Deprecate this construct. if yyDollar[1].colIdent.Lowered() != "value" { @@ -6217,239 +6216,239 @@ yydefault: } yyVAL.expr = NewIntVal([]byte("1")) } - case 552: + case 554: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2812 +//line sql.y:2820 { yyVAL.expr = NewIntVal(yyDollar[1].bytes) } - case 553: + case 555: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2816 +//line sql.y:2824 { yyVAL.expr = NewValArg(yyDollar[1].bytes) } - case 554: + case 556: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2821 +//line sql.y:2829 { yyVAL.exprs = nil } - case 555: + case 557: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2825 +//line sql.y:2833 { yyVAL.exprs = yyDollar[3].exprs } - case 556: + case 558: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2830 +//line sql.y:2838 { yyVAL.expr = nil } - case 557: + case 559: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2834 +//line sql.y:2842 { yyVAL.expr = yyDollar[2].expr } - case 558: + case 560: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2839 +//line sql.y:2847 { yyVAL.orderBy = nil } - case 559: + case 561: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2843 +//line sql.y:2851 { yyVAL.orderBy = yyDollar[3].orderBy } - case 560: + case 562: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2849 +//line sql.y:2857 { yyVAL.orderBy = OrderBy{yyDollar[1].order} } - case 561: + case 563: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2853 +//line sql.y:2861 { yyVAL.orderBy = append(yyDollar[1].orderBy, yyDollar[3].order) } - case 562: + case 564: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2859 +//line sql.y:2867 { yyVAL.order = &Order{Expr: yyDollar[1].expr, Direction: yyDollar[2].str} } - case 563: + case 565: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2864 +//line sql.y:2872 { yyVAL.str = AscScr } - case 564: + case 566: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2868 +//line sql.y:2876 { yyVAL.str = AscScr } - case 565: + case 567: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2872 +//line sql.y:2880 { yyVAL.str = DescScr } - case 566: + case 568: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2877 +//line sql.y:2885 { yyVAL.limit = nil } - case 567: + case 569: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2881 +//line sql.y:2889 { yyVAL.limit = &Limit{Rowcount: yyDollar[2].expr} } - case 568: + case 570: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2885 +//line sql.y:2893 { yyVAL.limit = &Limit{Offset: yyDollar[2].expr, Rowcount: yyDollar[4].expr} } - case 569: + case 571: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2889 +//line sql.y:2897 { yyVAL.limit = &Limit{Offset: yyDollar[4].expr, Rowcount: yyDollar[2].expr} } - case 570: + case 572: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2894 +//line sql.y:2902 { yyVAL.str = "" } - case 571: + case 573: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2898 +//line sql.y:2906 { yyVAL.str = ForUpdateStr } - case 572: + case 574: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2902 +//line sql.y:2910 { yyVAL.str = ShareModeStr } - case 573: + case 575: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2915 +//line sql.y:2923 { yyVAL.ins = &Insert{Rows: yyDollar[2].values} } - case 574: + case 576: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2919 +//line sql.y:2927 { yyVAL.ins = &Insert{Rows: yyDollar[1].selStmt} } - case 575: + case 577: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2923 +//line sql.y:2931 { // Drop the redundant parenthesis. yyVAL.ins = &Insert{Rows: yyDollar[2].selStmt} } - case 576: + case 578: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2928 +//line sql.y:2936 { yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].values} } - case 577: + case 579: yyDollar = yyS[yypt-4 : yypt+1] -//line sql.y:2932 +//line sql.y:2940 { yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[4].selStmt} } - case 578: + case 580: yyDollar = yyS[yypt-6 : yypt+1] -//line sql.y:2936 +//line sql.y:2944 { // Drop the redundant parenthesis. yyVAL.ins = &Insert{Columns: yyDollar[2].columns, Rows: yyDollar[5].selStmt} } - case 579: + case 581: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2943 +//line sql.y:2951 { yyVAL.columns = Columns{yyDollar[1].colIdent} } - case 580: + case 582: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2947 +//line sql.y:2955 { yyVAL.columns = Columns{yyDollar[3].colIdent} } - case 581: + case 583: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2951 +//line sql.y:2959 { yyVAL.columns = append(yyVAL.columns, yyDollar[3].colIdent) } - case 582: + case 584: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2955 +//line sql.y:2963 { yyVAL.columns = append(yyVAL.columns, yyDollar[5].colIdent) } - case 583: + case 585: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:2960 +//line sql.y:2968 { yyVAL.updateExprs = nil } - case 584: + case 586: yyDollar = yyS[yypt-5 : yypt+1] -//line sql.y:2964 +//line sql.y:2972 { yyVAL.updateExprs = yyDollar[5].updateExprs } - case 585: + case 587: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2970 +//line sql.y:2978 { yyVAL.values = Values{yyDollar[1].valTuple} } - case 586: + case 588: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2974 +//line sql.y:2982 { yyVAL.values = append(yyDollar[1].values, yyDollar[3].valTuple) } - case 587: + case 589: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2980 +//line sql.y:2988 { yyVAL.valTuple = yyDollar[1].valTuple } - case 588: + case 590: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:2984 +//line sql.y:2992 { yyVAL.valTuple = ValTuple{} } - case 589: + case 591: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:2990 +//line sql.y:2998 { yyVAL.valTuple = ValTuple(yyDollar[2].exprs) } - case 590: + case 592: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:2996 +//line sql.y:3004 { if len(yyDollar[1].valTuple) == 1 { yyVAL.expr = &ParenExpr{yyDollar[1].valTuple[0]} @@ -6457,312 +6456,312 @@ yydefault: yyVAL.expr = yyDollar[1].valTuple } } - case 591: + case 593: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3006 +//line sql.y:3014 { yyVAL.updateExprs = UpdateExprs{yyDollar[1].updateExpr} } - case 592: + case 594: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3010 +//line sql.y:3018 { yyVAL.updateExprs = append(yyDollar[1].updateExprs, yyDollar[3].updateExpr) } - case 593: + case 595: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3016 +//line sql.y:3024 { yyVAL.updateExpr = &UpdateExpr{Name: yyDollar[1].colName, Expr: yyDollar[3].expr} } - case 594: + case 596: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3022 +//line sql.y:3030 { yyVAL.setExprs = SetExprs{yyDollar[1].setExpr} } - case 595: + case 597: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3026 +//line sql.y:3034 { yyVAL.setExprs = append(yyDollar[1].setExprs, yyDollar[3].setExpr) } - case 596: + case 598: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3032 +//line sql.y:3040 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: NewStrVal([]byte("on"))} } - case 597: + case 599: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3036 +//line sql.y:3044 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: NewStrVal([]byte("off"))} } - case 598: + case 600: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3040 +//line sql.y:3048 { yyVAL.setExpr = &SetExpr{Name: yyDollar[1].colIdent, Expr: yyDollar[3].expr} } - case 599: + case 601: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3044 +//line sql.y:3052 { yyVAL.setExpr = &SetExpr{Name: NewColIdent(string(yyDollar[1].bytes)), Expr: yyDollar[2].expr} } - case 601: + case 603: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3051 +//line sql.y:3059 { yyVAL.bytes = []byte("charset") } - case 603: + case 605: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3058 +//line sql.y:3066 { yyVAL.expr = NewStrVal([]byte(yyDollar[1].colIdent.String())) } - case 604: + case 606: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3062 +//line sql.y:3070 { yyVAL.expr = NewStrVal(yyDollar[1].bytes) } - case 605: + case 607: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3066 +//line sql.y:3074 { yyVAL.expr = &Default{} } - case 608: + case 610: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3075 +//line sql.y:3083 { yyVAL.byt = 0 } - case 609: + case 611: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3077 +//line sql.y:3085 { yyVAL.byt = 1 } - case 610: + case 612: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3080 +//line sql.y:3088 { yyVAL.empty = struct{}{} } - case 611: + case 613: yyDollar = yyS[yypt-3 : yypt+1] -//line sql.y:3082 +//line sql.y:3090 { yyVAL.empty = struct{}{} } - case 612: + case 614: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3085 +//line sql.y:3093 { yyVAL.str = "" } - case 613: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3087 - { - yyVAL.str = IgnoreStr - } - case 614: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3091 - { - yyVAL.empty = struct{}{} - } case 615: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3093 +//line sql.y:3095 { - yyVAL.empty = struct{}{} + yyVAL.str = IgnoreStr } case 616: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3095 +//line sql.y:3099 { yyVAL.empty = struct{}{} } case 617: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3097 +//line sql.y:3101 { yyVAL.empty = struct{}{} } case 618: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3099 +//line sql.y:3103 { yyVAL.empty = struct{}{} } case 619: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3101 +//line sql.y:3105 { yyVAL.empty = struct{}{} } case 620: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3103 +//line sql.y:3107 { yyVAL.empty = struct{}{} } case 621: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3105 +//line sql.y:3109 { yyVAL.empty = struct{}{} } case 622: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3107 +//line sql.y:3111 { yyVAL.empty = struct{}{} } case 623: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3109 +//line sql.y:3113 { yyVAL.empty = struct{}{} } case 624: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3112 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:3115 { yyVAL.empty = struct{}{} } case 625: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3114 +//line sql.y:3117 { yyVAL.empty = struct{}{} } case 626: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3116 + yyDollar = yyS[yypt-0 : yypt+1] +//line sql.y:3120 { yyVAL.empty = struct{}{} } case 627: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3120 +//line sql.y:3122 { yyVAL.empty = struct{}{} } case 628: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3122 +//line sql.y:3124 { yyVAL.empty = struct{}{} } case 629: - yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3125 + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:3128 { yyVAL.empty = struct{}{} } case 630: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3127 +//line sql.y:3130 { yyVAL.empty = struct{}{} } case 631: - yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3129 + yyDollar = yyS[yypt-0 : yypt+1] +//line sql.y:3133 { yyVAL.empty = struct{}{} } case 632: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:3135 + { + yyVAL.empty = struct{}{} + } + case 633: + yyDollar = yyS[yypt-1 : yypt+1] +//line sql.y:3137 + { + yyVAL.empty = struct{}{} + } + case 634: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3132 +//line sql.y:3140 { yyVAL.colIdent = ColIdent{} } - case 633: + case 635: yyDollar = yyS[yypt-2 : yypt+1] -//line sql.y:3134 +//line sql.y:3142 { yyVAL.colIdent = yyDollar[2].colIdent } - case 634: + case 636: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3138 +//line sql.y:3146 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 635: + case 637: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3142 +//line sql.y:3150 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 637: + case 639: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3149 +//line sql.y:3157 { yyVAL.colIdent = NewColIdent(string(yyDollar[1].bytes)) } - case 638: + case 640: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3155 +//line sql.y:3163 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 639: + case 641: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3159 +//line sql.y:3167 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 641: + case 643: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3166 +//line sql.y:3174 { yyVAL.tableIdent = NewTableIdent(string(yyDollar[1].bytes)) } - case 850: + case 853: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3400 +//line sql.y:3409 { if incNesting(yylex) { yylex.Error("max nesting level reached") return 1 } } - case 851: + case 854: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3409 +//line sql.y:3418 { decNesting(yylex) } - case 852: + case 855: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3414 +//line sql.y:3423 { skipToEnd(yylex) } - case 853: + case 856: yyDollar = yyS[yypt-0 : yypt+1] -//line sql.y:3419 +//line sql.y:3428 { skipToEnd(yylex) } - case 854: + case 857: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3423 +//line sql.y:3432 { skipToEnd(yylex) } - case 855: + case 858: yyDollar = yyS[yypt-1 : yypt+1] -//line sql.y:3427 +//line sql.y:3436 { skipToEnd(yylex) } diff --git a/go/vt/sqlparser/sql.y b/go/vt/sqlparser/sql.y index 33816225ed7..149781ad6f1 100644 --- a/go/vt/sqlparser/sql.y +++ b/go/vt/sqlparser/sql.y @@ -705,6 +705,14 @@ int_type: { $$ = ColumnType{Type: string($1)} } +| BOOL + { + $$ = ColumnType{Type: string($1)} + } +| BOOLEAN + { + $$ = ColumnType{Type: string($1)} + } | TINYINT { $$ = ColumnType{Type: string($1)} @@ -3288,6 +3296,7 @@ non_reserved_keyword: | BIT | BLOB | BOOL +| BOOLEAN | CASCADE | CHAR | CHARACTER From 4d48a17138ebf8c65bf8dd88116e861b2f4f2184 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Mon, 11 Feb 2019 10:41:51 -0800 Subject: [PATCH 047/196] Fix wrangler tests. Mostly generate SrvKeyspace before running them Signed-off-by: Rafael Chacon --- go/vt/wrangler/testlib/reparent_external_test.go | 12 ++++++++++-- go/vt/wrangler/testlib/shard_test.go | 7 +++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/go/vt/wrangler/testlib/reparent_external_test.go b/go/vt/wrangler/testlib/reparent_external_test.go index c5a36675946..fff7aeae52f 100644 --- a/go/vt/wrangler/testlib/reparent_external_test.go +++ b/go/vt/wrangler/testlib/reparent_external_test.go @@ -54,6 +54,12 @@ func TestTabletExternallyReparented(t *testing.T) { goodSlave2 := NewFakeTablet(t, wr, "cell2", 3, topodatapb.TabletType_REPLICA, nil) badSlave := NewFakeTablet(t, wr, "cell1", 4, topodatapb.TabletType_REPLICA, nil) + // Build keyspace graph + err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, oldMaster.Tablet.Keyspace, []string{"cell1", "cell2"}) + if err != nil { + t.Fatalf("RebuildKeyspaceLocked failed: %v", err) + } + // Slightly unrelated test: make sure we can find the tablets // even with a datacenter being down. tabletMap, err := ts.GetTabletMapForShardByCell(ctx, "test_keyspace", "0", []string{"cell1"}) @@ -80,9 +86,11 @@ func TestTabletExternallyReparented(t *testing.T) { t.Fatalf("FindTabletByHostAndPort(master) worked in cell2: %v %v", err, master) } + // Get tablet map for all cells. If there were to be failures talking to local cells, this will return the tablet map + // and forward a partial result error tabletMap, err = ts.GetTabletMapForShard(ctx, "test_keyspace", "0") - if !topo.IsErrType(err, topo.PartialResult) { - t.Fatalf("GetTabletMapForShard should have returned ErrPartialResult but got: %v", err) + if err != nil { + t.Fatalf("GetTabletMapForShard should nil but got: %v", err) } master, err = topotools.FindTabletByHostAndPort(tabletMap, oldMaster.Tablet.Hostname, "vt", oldMaster.Tablet.PortMap["vt"]) if err != nil || !topoproto.TabletAliasEqual(master, oldMaster.Tablet.Alias) { diff --git a/go/vt/wrangler/testlib/shard_test.go b/go/vt/wrangler/testlib/shard_test.go index 19f85228fc9..449382e85a1 100644 --- a/go/vt/wrangler/testlib/shard_test.go +++ b/go/vt/wrangler/testlib/shard_test.go @@ -25,6 +25,7 @@ import ( "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/vttablet/tmclient" "vitess.io/vitess/go/vt/wrangler" @@ -43,6 +44,12 @@ func TestDeleteShardCleanup(t *testing.T) { slave := NewFakeTablet(t, wr, "cell1", 1, topodatapb.TabletType_REPLICA, nil) remoteSlave := NewFakeTablet(t, wr, "cell2", 2, topodatapb.TabletType_REPLICA, nil) + // Build keyspace graph + err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, master.Tablet.Keyspace, []string{"cell1", "cell2"}) + if err != nil { + t.Fatalf("RebuildKeyspaceLocked failed: %v", err) + } + // Delete the ShardReplication record in cell2 if err := ts.DeleteShardReplication(ctx, "cell2", remoteSlave.Tablet.Keyspace, remoteSlave.Tablet.Shard); err != nil { t.Fatalf("DeleteShardReplication failed: %v", err) From 31114e14d84e14a1d464bfc75a5a21462bd8d6fb Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Mon, 11 Feb 2019 12:06:59 -0800 Subject: [PATCH 048/196] Fix vtctlient_test VtCombo was not initializing shard or serving keyspace graph. Now that serving data is derived from here, we need to make sure that this gets called before gates can serve traffic. Signed-off-by: Rafael Chacon --- go/cmd/vtcombo/main.go | 10 ++++++++++ go/vt/vtcombo/tablet_map.go | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/go/cmd/vtcombo/main.go b/go/cmd/vtcombo/main.go index 3265b36c381..90c2bde61bc 100644 --- a/go/cmd/vtcombo/main.go +++ b/go/cmd/vtcombo/main.go @@ -33,11 +33,13 @@ import ( "vitess.io/vitess/go/vt/dbconfigs" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl" "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/srvtopo" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" + "vitess.io/vitess/go/vt/topotools" "vitess.io/vitess/go/vt/vtcombo" "vitess.io/vitess/go/vt/vtctld" "vitess.io/vitess/go/vt/vtgate" @@ -108,6 +110,14 @@ func main() { exit.Return(1) } + // Now that we have fully initialized the tablets, rebuild the keyspace graph. This is what would normally happen in InitTablet. + for _, ks := range tpb.Keyspaces { + err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, ks.GetName(), tpb.Cells) + if err != nil { + log.Fatalf("Couldn't build srv keyspace for (%v: %v). Got error: %v", ks, tpb.Cells, err) + } + } + // vtgate configuration and init resilientServer := srvtopo.NewResilientServer(ts, "ResilientSrvTopoServer") healthCheck := discovery.NewHealthCheck(1*time.Millisecond /*retryDelay*/, 1*time.Hour /*healthCheckTimeout*/) diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index 6e3abbddec3..072772fe212 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -160,6 +160,10 @@ func InitTabletMap(ts *topo.Server, tpb *vttestpb.VTTestTopology, mysqld mysqlct // iterate through the shards for _, spb := range kpb.Shards { shard := spb.Name + ts.CreateShard(ctx, keyspace, shard) + if err != nil { + return fmt.Errorf("CreateShard(%v:%v) failed: %v", keyspace, shard, err) + } for _, cell := range tpb.Cells { dbname := spb.DbNameOverride From afe1e17a8ec6c1171d38b8e171f7c7ba49834e37 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Mon, 11 Feb 2019 13:01:42 -0800 Subject: [PATCH 049/196] Re-add existent semantics where no cells provided means all cells Signed-off-by: Rafael Chacon --- go/vt/topotools/rebuild_keyspace.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index c55e58dae91..54880b8b13b 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -57,6 +57,14 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser return err } + // The caller intents to update all cells in this case + if len(cells) == 0 { + cells, err = ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + } + shards, err := ts.FindAllShardsInKeyspace(ctx, keyspace) if err != nil { return err From 950c3164e936eca37e8f0c0745b7e24d0af07d27 Mon Sep 17 00:00:00 2001 From: deepthi Date: Mon, 11 Feb 2019 17:51:23 -0800 Subject: [PATCH 050/196] use Get/PutObjectWithContext Signed-off-by: deepthi --- go/vt/mysqlctl/cephbackupstorage/ceph.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/mysqlctl/cephbackupstorage/ceph.go b/go/vt/mysqlctl/cephbackupstorage/ceph.go index 683a5af9b0b..d047f4af0e3 100644 --- a/go/vt/mysqlctl/cephbackupstorage/ceph.go +++ b/go/vt/mysqlctl/cephbackupstorage/ceph.go @@ -88,7 +88,7 @@ func (bh *CephBackupHandle) AddFile(ctx context.Context, filename string, filesi // Give PutObject() the read end of the pipe. object := objName(bh.dir, bh.name, filename) - _, err := bh.client.PutObject(bucket, object, reader, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"}) + _, err := bh.client.PutObjectWithContext(ctx, bucket, object, reader, -1, minio.PutObjectOptions{ContentType: "application/octet-stream"}) if err != nil { // Signal the writer that an error occurred, in case it's not done writing yet. reader.CloseWithError(err) @@ -126,7 +126,7 @@ func (bh *CephBackupHandle) ReadFile(ctx context.Context, filename string) (io.R // ceph bucket name bucket := alterBucketName(bh.dir) object := objName(bh.dir, bh.name, filename) - return bh.client.GetObject(bucket, object, minio.GetObjectOptions{}) + return bh.client.GetObjectWithContext(ctx, bucket, object, minio.GetObjectOptions{}) } // CephBackupStorage implements BackupStorage for Ceph Cloud Storage. From 14a0387dd477ff8b2514a3e930fd07eb03e9586f Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Tue, 12 Feb 2019 01:20:51 -0500 Subject: [PATCH 051/196] Using the import () Signed-off-by: xichengliudui --- go/sqltypes/event_token.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/go/sqltypes/event_token.go b/go/sqltypes/event_token.go index c7c5884edf0..d0fa5717901 100644 --- a/go/sqltypes/event_token.go +++ b/go/sqltypes/event_token.go @@ -16,7 +16,9 @@ limitations under the License. package sqltypes -import querypb "vitess.io/vitess/go/vt/proto/query" +import ( + querypb "vitess.io/vitess/go/vt/proto/query" +) // EventTokenMinimum returns an event token that is guaranteed to // happen before both provided EventToken objects. Note it doesn't From 3b5e117b4c32bf09472e9cfc79df76ff4dcc2160 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Mon, 11 Feb 2019 22:48:46 -0800 Subject: [PATCH 052/196] Fix bugs discovered by test in MigrateServedFrom Signed-off-by: Rafael Chacon --- go/vt/topotools/rebuild_keyspace.go | 16 +++-- go/vt/vtctl/vtctl.go | 5 +- go/vt/wrangler/keyspace.go | 7 ++- .../testlib/migrate_served_from_test.go | 60 ++++++++++++++++++- test/vertical_split.py | 4 +- 5 files changed, 79 insertions(+), 13 deletions(-) diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index 54880b8b13b..087cea832d9 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -18,6 +18,7 @@ package topotools import ( "fmt" + "reflect" "sync" "golang.org/x/net/context" @@ -76,20 +77,27 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser // srvKeyspaceMap is a map: // key: cell // value: topo.SrvKeyspace object being built + // We only build this in two scenarios: + // - The object does not exist. + // - ServedFrom changed. srvKeyspaceMap := make(map[string]*topodatapb.SrvKeyspace) for _, cell := range cells { - _, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) switch { case err == nil: - // NOOP - case topo.IsErrType(err, topo.NoNode): - if _, ok := srvKeyspaceMap[cell]; !ok { + if !reflect.DeepEqual(srvKeyspace.ServedFrom, ki.ComputeCellServedFrom(cell)) { srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ ShardingColumnName: ki.ShardingColumnName, ShardingColumnType: ki.ShardingColumnType, ServedFrom: ki.ComputeCellServedFrom(cell), } } + case topo.IsErrType(err, topo.NoNode): + srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ + ShardingColumnName: ki.ShardingColumnName, + ShardingColumnType: ki.ShardingColumnType, + ServedFrom: ki.ComputeCellServedFrom(cell), + } default: // Couldn't get srvKeyspace, not log.Warningf("Couldn't get srvKeyspace for cell %v, skip rebuilding", cell) diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index eda5a4ed114..310efdcab72 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -1319,8 +1319,9 @@ func commandSetShardTabletControl(ctx context.Context, wr *wrangler.Wrangler, su cells = strings.Split(*cellsStr, ",") } - if len(blacklistedTables) > 0 { - return wr.SetShardTabletControl(ctx, keyspace, shard, tabletType, cells, *remove, blacklistedTables) + err = wr.SetShardTabletControl(ctx, keyspace, shard, tabletType, cells, *remove, blacklistedTables) + if err != nil { + return err } return wr.UpdateDisableQueryService(ctx, keyspace, shard, tabletType, cells, *disableQueryService) } diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index 3bbdab8f7a3..df96ae26cfb 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -1018,8 +1018,11 @@ func (wr *Wrangler) migrateServedFromLocked(ctx context.Context, ki *topo.Keyspa if reverse { ki.UpdateServedFromMap(servedType, cells, destinationShard.SourceShards[0].Keyspace, false, nil) } else { - // Check with Sugi, I think in this world, there is no longer the concept of a destinationShard.Cells, so it must be think as all cells all the time. - ki.UpdateServedFromMap(servedType, cells, destinationShard.SourceShards[0].Keyspace, true, nil) + destinationShardcells, err := wr.ts.GetShardServingCells(ctx, destinationShard) + if err != nil { + return err + } + ki.UpdateServedFromMap(servedType, cells, destinationShard.SourceShards[0].Keyspace, true, destinationShardcells) } // re-read and check the destination shard diff --git a/go/vt/wrangler/testlib/migrate_served_from_test.go b/go/vt/wrangler/testlib/migrate_served_from_test.go index bcf5fda6359..7388600aead 100644 --- a/go/vt/wrangler/testlib/migrate_served_from_test.go +++ b/go/vt/wrangler/testlib/migrate_served_from_test.go @@ -125,9 +125,9 @@ func TestMigrateServedFrom(t *testing.T) { t.Fatalf("SourceShardAdd failed: %v", err) } - // migrate rdonly over - if err := vp.Run([]string{"MigrateServedFrom", "dest/0", "rdonly"}); err != nil { - t.Fatalf("MigrateServedFrom(rdonly) failed: %v", err) + // migrate rdonly over in a cell + if err := vp.Run([]string{"MigrateServedFrom", "--cells", "cell1", "dest/0", "rdonly"}); err != nil { + t.Fatalf("MigrateServedFrom(rdonly) cell2 failed: %v", err) } // check it's gone from keyspace @@ -145,6 +145,60 @@ func TestMigrateServedFrom(t *testing.T) { t.Fatalf("GetShard failed: %v", err) } expected := []*topodatapb.Shard_TabletControl{ + { + TabletType: topodatapb.TabletType_RDONLY, + Cells: []string{"cell1"}, + BlacklistedTables: []string{"gone1", "gone2"}, + }, + } + if len(si.TabletControls) != 1 || !reflect.DeepEqual(si.TabletControls, expected) { + t.Fatalf("rdonly type doesn't have right blacklisted tables. Expected: %v, got: %v", expected, si.TabletControls) + } + + // migrate rdonly reverse cell + if err := vp.Run([]string{"MigrateServedFrom", "--cells", "cell1", "--reverse", "dest/0", "rdonly"}); err != nil { + t.Fatalf("MigrateServedFrom(rdonly) cell2 failed: %v", err) + } + + // check it's gone from keyspace + ki, err = ts.GetKeyspace(ctx, "dest") + if err != nil { + t.Fatalf("GetKeyspace failed: %v", err) + } + if len(ki.ServedFroms) != 3 { + t.Fatalf("bad initial dest ServedFroms: %v", ki.ServedFroms) + } + + // check the source shard has the right blacklisted tables + si, err = ts.GetShard(ctx, "source", "0") + if err != nil { + t.Fatalf("GetShard failed: %v", err) + } + + if len(si.TabletControls) != 0 { + t.Fatalf("rdonly type doesn't have right blacklisted tables. Expected: nil, got: %v", si.TabletControls) + } + + // Now migrate rdonly over + if err := vp.Run([]string{"MigrateServedFrom", "dest/0", "rdonly"}); err != nil { + t.Fatalf("MigrateServedFrom(rdonly) failed: %v", err) + } + + // check it's gone from keyspace + ki, err = ts.GetKeyspace(ctx, "dest") + if err != nil { + t.Fatalf("GetKeyspace failed: %v", err) + } + if len(ki.ServedFroms) != 2 || ki.GetServedFrom(topodatapb.TabletType_RDONLY) != nil { + t.Fatalf("bad initial dest ServedFroms: %v", ki.ServedFroms) + } + + // check the source shard has the right blacklisted tables + si, err = ts.GetShard(ctx, "source", "0") + if err != nil { + t.Fatalf("GetShard failed: %v", err) + } + expected = []*topodatapb.Shard_TabletControl{ { TabletType: topodatapb.TabletType_RDONLY, BlacklistedTables: []string{"gone1", "gone2"}, diff --git a/test/vertical_split.py b/test/vertical_split.py index 4f9d64b64e0..91149160022 100755 --- a/test/vertical_split.py +++ b/test/vertical_split.py @@ -523,10 +523,10 @@ def test_vertical_split(self): for ksf in keyspace_json['served_froms']: if ksf['tablet_type'] == topodata_pb2.RDONLY: found = True - self.assertEqual(ksf['cells'], ['test_nj']) + self.assertEqual(sorted(ksf['cells']), ['test_ca', 'test_nj']) self.assertTrue(found) utils.run_vtctl(['SetKeyspaceServedFrom', '-source=source_keyspace', - '-remove', '-cells=test_nj', 'destination_keyspace', + '-remove', '-cells=test_nj,test_ca', 'destination_keyspace', 'rdonly'], auto_log=True) keyspace_json = utils.run_vtctl_json( ['GetKeyspace', 'destination_keyspace']) From 4e163e81b235928c32d8c51f8ccbb4aad8cc199a Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Tue, 12 Feb 2019 01:48:01 -0500 Subject: [PATCH 053/196] Fix small errors in printing Signed-off-by: xichengliudui --- vagrant-scripts/vagrant-bashrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vagrant-scripts/vagrant-bashrc b/vagrant-scripts/vagrant-bashrc index adff78e8c54..27b1828450c 100644 --- a/vagrant-scripts/vagrant-bashrc +++ b/vagrant-scripts/vagrant-bashrc @@ -3,7 +3,7 @@ seed_file=$HOME/.vitess_bootstrap_done if [ ! -f $seed_file ]; then - printf "\nVM Vitess hasn't been build in this VM. Downloading and setting up vitess deps. \n" + printf "\nVM Vitess hasn't been built in this VM. Downloading and setting up vitess deps. \n" ./vagrant-scripts/vitess/build.sh touch $seed_file fi From faf4628b02802088fa377de03a1ed67680645121 Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Tue, 12 Feb 2019 13:25:15 -0500 Subject: [PATCH 054/196] Use the import () way Signed-off-by: xichengliudui --- go/bytes2/buffer_test.go | 4 +++- go/cmd/vtgateclienttest/services/services.go | 4 +++- go/cmd/vtqueryserver/plugin_grpcqueryservice.go | 3 ++- go/cmd/vttablet/plugin_zk2topo.go | 3 ++- go/cmd/vtworker/plugin_zk2topo.go | 3 ++- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/go/bytes2/buffer_test.go b/go/bytes2/buffer_test.go index 6f3b102f7ce..2c44f6a8eab 100644 --- a/go/bytes2/buffer_test.go +++ b/go/bytes2/buffer_test.go @@ -16,7 +16,9 @@ limitations under the License. package bytes2 -import "testing" +import ( + "testing" +) func TestBuffer(t *testing.T) { b := NewBuffer(nil) diff --git a/go/cmd/vtgateclienttest/services/services.go b/go/cmd/vtgateclienttest/services/services.go index 3513919fbc9..9cf9d5a34c6 100644 --- a/go/cmd/vtgateclienttest/services/services.go +++ b/go/cmd/vtgateclienttest/services/services.go @@ -17,7 +17,9 @@ limitations under the License. // Package services exposes all the services for the vtgateclienttest binary. package services -import "vitess.io/vitess/go/vt/vtgate/vtgateservice" +import ( + "vitess.io/vitess/go/vt/vtgate/vtgateservice" +) // CreateServices creates the implementation chain of all the test cases func CreateServices() vtgateservice.VTGateService { diff --git a/go/cmd/vtqueryserver/plugin_grpcqueryservice.go b/go/cmd/vtqueryserver/plugin_grpcqueryservice.go index cdfae2b4b3b..60478f80ad7 100644 --- a/go/cmd/vtqueryserver/plugin_grpcqueryservice.go +++ b/go/cmd/vtqueryserver/plugin_grpcqueryservice.go @@ -16,13 +16,14 @@ limitations under the License. package main +// Imports and register the gRPC queryservice server + import ( "vitess.io/vitess/go/vt/servenv" "vitess.io/vitess/go/vt/vttablet/grpcqueryservice" "vitess.io/vitess/go/vt/vttablet/tabletserver" ) -// Imports and register the gRPC queryservice server func init() { tabletserver.RegisterFunctions = append(tabletserver.RegisterFunctions, func(qsc tabletserver.Controller) { diff --git a/go/cmd/vttablet/plugin_zk2topo.go b/go/cmd/vttablet/plugin_zk2topo.go index 82e91f1a224..c75a764c432 100644 --- a/go/cmd/vttablet/plugin_zk2topo.go +++ b/go/cmd/vttablet/plugin_zk2topo.go @@ -16,7 +16,8 @@ limitations under the License. package main +// Imports and register the zk2 TopologyServer + import ( - // Imports and register the zk2 TopologyServer _ "vitess.io/vitess/go/vt/topo/zk2topo" ) diff --git a/go/cmd/vtworker/plugin_zk2topo.go b/go/cmd/vtworker/plugin_zk2topo.go index 82e91f1a224..c75a764c432 100644 --- a/go/cmd/vtworker/plugin_zk2topo.go +++ b/go/cmd/vtworker/plugin_zk2topo.go @@ -16,7 +16,8 @@ limitations under the License. package main +// Imports and register the zk2 TopologyServer + import ( - // Imports and register the zk2 TopologyServer _ "vitess.io/vitess/go/vt/topo/zk2topo" ) From 30c8a93abb17ad7cab2a0670025f4ee69ce724f9 Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Tue, 12 Feb 2019 13:52:05 -0500 Subject: [PATCH 055/196] Use the import () way Signed-off-by: xichengliudui --- go/hack/hack_test.go | 4 +++- go/mysql/binlog_event_make.go | 4 +++- go/mysql/slave_status_test.go | 4 +++- go/stats/kebab_case_converter_test.go | 4 +++- go/stats/snake_case_converter_test.go | 4 +++- go/vt/tableacl/role_test.go | 4 +++- go/vt/throttler/fake_rates_history_test.go | 4 +++- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/go/hack/hack_test.go b/go/hack/hack_test.go index d8208c6fe4f..5417cb63810 100644 --- a/go/hack/hack_test.go +++ b/go/hack/hack_test.go @@ -16,7 +16,9 @@ limitations under the License. package hack -import "testing" +import ( + "testing" +) func TestStringArena(t *testing.T) { sarena := NewStringArena(10) diff --git a/go/mysql/binlog_event_make.go b/go/mysql/binlog_event_make.go index b898c0a4dce..343d97da1fd 100644 --- a/go/mysql/binlog_event_make.go +++ b/go/mysql/binlog_event_make.go @@ -16,7 +16,9 @@ limitations under the License. package mysql -import "encoding/binary" +import ( + "encoding/binary" +) // This file contains utility methods to create binlog replication // packets. They are mostly used for testing. diff --git a/go/mysql/slave_status_test.go b/go/mysql/slave_status_test.go index ee3b6c6cccc..79334da8008 100644 --- a/go/mysql/slave_status_test.go +++ b/go/mysql/slave_status_test.go @@ -16,7 +16,9 @@ limitations under the License. package mysql -import "testing" +import ( + "testing" +) func TestStatusSlaveRunning(t *testing.T) { input := &SlaveStatus{ diff --git a/go/stats/kebab_case_converter_test.go b/go/stats/kebab_case_converter_test.go index 5715b733af0..a8617f15ec1 100644 --- a/go/stats/kebab_case_converter_test.go +++ b/go/stats/kebab_case_converter_test.go @@ -16,7 +16,9 @@ limitations under the License. package stats -import "testing" +import ( + "testing" +) func TestToKebabCase(t *testing.T) { var kebabCaseTest = []struct{ input, output string }{ diff --git a/go/stats/snake_case_converter_test.go b/go/stats/snake_case_converter_test.go index bcd4194ac79..1334f5a82f2 100644 --- a/go/stats/snake_case_converter_test.go +++ b/go/stats/snake_case_converter_test.go @@ -16,7 +16,9 @@ limitations under the License. package stats -import "testing" +import ( + "testing" +) func TestToSnakeCase(t *testing.T) { var snakeCaseTest = []struct{ input, output string }{ diff --git a/go/vt/tableacl/role_test.go b/go/vt/tableacl/role_test.go index 1198837bd01..c6f501f5272 100644 --- a/go/vt/tableacl/role_test.go +++ b/go/vt/tableacl/role_test.go @@ -16,7 +16,9 @@ limitations under the License. package tableacl -import "testing" +import ( + "testing" +) func TestRoleName(t *testing.T) { if READER.Name() != roleNames[READER] { diff --git a/go/vt/throttler/fake_rates_history_test.go b/go/vt/throttler/fake_rates_history_test.go index 8caed8fdb37..14c1d3eddcd 100644 --- a/go/vt/throttler/fake_rates_history_test.go +++ b/go/vt/throttler/fake_rates_history_test.go @@ -16,7 +16,9 @@ limitations under the License. package throttler -import "time" +import ( + "time" +) // fakeRatesHistory simplifies faking the actual throttler rate for each // 1 second interval. With the add() method up to a given time all missing From 7aa60d56da28f4c893cb95e1f714f02be6362f4e Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Tue, 12 Feb 2019 14:01:54 -0500 Subject: [PATCH 056/196] Use the import () way Signed-off-by: xichengliudui --- go/vt/automation/id_generator.go | 6 ++++-- go/vt/tableacl/role.go | 4 +++- go/vt/throttler/aggregated_interval_history.go | 4 +++- go/vt/throttler/max_rate_module.go | 4 +++- go/vt/throttler/record.go | 4 +++- go/vt/topo/errors.go | 4 +++- go/vt/topo/events/tablet_change.go | 4 +++- go/vt/vtgate/buffer/variables.go | 4 +++- go/vt/worker/events/split.go | 4 +++- 9 files changed, 28 insertions(+), 10 deletions(-) diff --git a/go/vt/automation/id_generator.go b/go/vt/automation/id_generator.go index cc8c37f8654..233cf7ca66c 100644 --- a/go/vt/automation/id_generator.go +++ b/go/vt/automation/id_generator.go @@ -16,8 +16,10 @@ limitations under the License. package automation -import "strconv" -import "sync/atomic" +import ( + "strconv" + "sync/atomic" +) // IDGenerator generates unique task and cluster operation IDs. type IDGenerator struct { diff --git a/go/vt/tableacl/role.go b/go/vt/tableacl/role.go index 9ec9828ae80..5d87387352e 100644 --- a/go/vt/tableacl/role.go +++ b/go/vt/tableacl/role.go @@ -16,7 +16,9 @@ limitations under the License. package tableacl -import "strings" +import ( + "strings" +) // Role defines the level of access on a table type Role int diff --git a/go/vt/throttler/aggregated_interval_history.go b/go/vt/throttler/aggregated_interval_history.go index 9147c747f16..5816f0aa60a 100644 --- a/go/vt/throttler/aggregated_interval_history.go +++ b/go/vt/throttler/aggregated_interval_history.go @@ -16,7 +16,9 @@ limitations under the License. package throttler -import "time" +import ( + "time" +) // aggregatedIntervalHistory aggregates data across multiple "intervalHistory" // instances. An instance should be mapped to a thread. diff --git a/go/vt/throttler/max_rate_module.go b/go/vt/throttler/max_rate_module.go index f078a23bbe1..9c7efaf4531 100644 --- a/go/vt/throttler/max_rate_module.go +++ b/go/vt/throttler/max_rate_module.go @@ -16,7 +16,9 @@ limitations under the License. package throttler -import "vitess.io/vitess/go/sync2" +import ( + "vitess.io/vitess/go/sync2" +) // MaxRateModule allows to set and retrieve a maximum rate limit. // It implements the Module interface. diff --git a/go/vt/throttler/record.go b/go/vt/throttler/record.go index d86ee4ab44b..308e5dfb6fb 100644 --- a/go/vt/throttler/record.go +++ b/go/vt/throttler/record.go @@ -16,7 +16,9 @@ limitations under the License. package throttler -import "time" +import ( + "time" +) // record is a single observation. type record struct { diff --git a/go/vt/topo/errors.go b/go/vt/topo/errors.go index a0bf8ad8dde..9b34035f214 100644 --- a/go/vt/topo/errors.go +++ b/go/vt/topo/errors.go @@ -16,7 +16,9 @@ limitations under the License. package topo -import "fmt" +import ( + "fmt" +) // ErrorCode is the error code for topo errors. type ErrorCode int diff --git a/go/vt/topo/events/tablet_change.go b/go/vt/topo/events/tablet_change.go index e3bf2e7b1d4..2ba092525f9 100644 --- a/go/vt/topo/events/tablet_change.go +++ b/go/vt/topo/events/tablet_change.go @@ -16,7 +16,9 @@ limitations under the License. package events -import topodatapb "vitess.io/vitess/go/vt/proto/topodata" +import ( + topodatapb "vitess.io/vitess/go/vt/proto/topodata" +) // TabletChange is an event that describes changes to a tablet's topo record. // It is triggered when the CURRENT process changes ANY tablet's record. diff --git a/go/vt/vtgate/buffer/variables.go b/go/vt/vtgate/buffer/variables.go index a8e3ee960bb..c718f9ba8bf 100644 --- a/go/vt/vtgate/buffer/variables.go +++ b/go/vt/vtgate/buffer/variables.go @@ -16,7 +16,9 @@ limitations under the License. package buffer -import "vitess.io/vitess/go/stats" +import ( + "vitess.io/vitess/go/stats" +) // This file contains all status variables which can be used to monitor the // buffer. diff --git a/go/vt/worker/events/split.go b/go/vt/worker/events/split.go index 2f8d8d66feb..6ba419f6e99 100644 --- a/go/vt/worker/events/split.go +++ b/go/vt/worker/events/split.go @@ -16,7 +16,9 @@ limitations under the License. package events -import base "vitess.io/vitess/go/vt/events" +import ( + base "vitess.io/vitess/go/vt/events" +) // SplitClone is an event that describes a single step in a horizontal // split clone. From b4bf8070ad8d75ca59056b43d3b907a8e7a71a8b Mon Sep 17 00:00:00 2001 From: Ze'ev Klapow Date: Tue, 12 Feb 2019 14:10:17 -0500 Subject: [PATCH 057/196] fix violations Signed-off-by: Ze'ev Klapow --- .../src/main/java/io/vitess/client/grpc/GrpcClient.java | 2 +- .../src/main/java/io/vitess/client/grpc/GrpcClientFactory.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java index 11b8266e02c..cf8f8cdc94f 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClient.java @@ -129,7 +129,7 @@ public void close() throws IOException { // Now we try hard shutdown channel.shutdownNow(); } - } catch (InterruptedException e) { + } catch (InterruptedException exc) { Thread.currentThread().interrupt(); } diff --git a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java index 2a4b9c62f01..f04511039df 100644 --- a/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java +++ b/java/grpc-client/src/main/java/io/vitess/client/grpc/GrpcClientFactory.java @@ -98,7 +98,8 @@ public RpcClient create(Context ctx, String target) { channel.nameResolverFactory(nameResolverFactory); } return callCredentials != null - ? new GrpcClient(channel.build(), callCredentials, ctx) : new GrpcClient(channel.build(), ctx); + ? new GrpcClient(channel.build(), callCredentials, ctx) + : new GrpcClient(channel.build(), ctx); } /** From 0a3f28bccfe45d41c5d167e80d31b9dfe579e7d7 Mon Sep 17 00:00:00 2001 From: David Weitzman Date: Tue, 12 Feb 2019 18:03:46 -0800 Subject: [PATCH 058/196] Prefer predefined constants for mysql errors Signed-off-by: David Weitzman --- go/vt/binlog/binlogplayer/binlog_player.go | 2 +- go/vt/mysqlctl/query.go | 4 ++-- go/vt/vttablet/tabletmanager/vreplication/vplayer.go | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/go/vt/binlog/binlogplayer/binlog_player.go b/go/vt/binlog/binlogplayer/binlog_player.go index f66256cc668..ceff67eebf5 100644 --- a/go/vt/binlog/binlogplayer/binlog_player.go +++ b/go/vt/binlog/binlogplayer/binlog_player.go @@ -397,7 +397,7 @@ func (blp *BinlogPlayer) processTransaction(tx *binlogdatapb.BinlogTransaction) if _, err = blp.exec(string(stmt.Sql)); err == nil { continue } - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == 1213 { + if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERLockDeadlock { // Deadlock: ask for retry log.Infof("Deadlock: %v", err) if err = blp.dbClient.Rollback(); err != nil { diff --git a/go/vt/mysqlctl/query.go b/go/vt/mysqlctl/query.go index 76fc1fa09e4..a5757d2a999 100644 --- a/go/vt/mysqlctl/query.go +++ b/go/vt/mysqlctl/query.go @@ -30,7 +30,7 @@ import ( ) // getPoolReconnect gets a connection from a pool, tests it, and reconnects if -// it gets errno 2006. +// the connection is lost. func getPoolReconnect(ctx context.Context, pool *dbconnpool.ConnectionPool) (*dbconnpool.PooledDBConnection, error) { conn, err := pool.Get(ctx) if err != nil { @@ -39,7 +39,7 @@ func getPoolReconnect(ctx context.Context, pool *dbconnpool.ConnectionPool) (*db // Run a test query to see if this connection is still good. if _, err := conn.ExecuteFetch("SELECT 1", 1, false); err != nil { // If we get a connection error, try to reconnect. - if sqlErr, ok := err.(*mysql.SQLError); ok && (sqlErr.Number() == 2006 || sqlErr.Number() == 2013) { + if sqlErr, ok := err.(*mysql.SQLError); ok && (sqlErr.Number() == mysql.CRServerGone || sqlErr.Number() == mysql.CRServerLost) { if err := conn.Reconnect(); err != nil { conn.Recycle() return nil, err diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index fd4bc4746e9..1add35a937c 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -609,8 +609,7 @@ func (vp *vplayer) exec(ctx context.Context, sql string) error { vp.stats.Timings.Record("query", time.Now()) _, err := vp.dbClient.ExecuteFetch(sql, 0) for err != nil { - // 1213: deadlock, 1205: lock wait timeout - if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == 1213 || sqlErr.Number() == 1205 { + if sqlErr, ok := err.(*mysql.SQLError); ok && sqlErr.Number() == mysql.ERLockDeadlock || sqlErr.Number() == mysql.ERLockWaitTimeout { log.Infof("retryable error: %v, waiting for %v and retrying", sqlErr, dbLockRetryDelay) if err := vp.dbClient.Rollback(); err != nil { return err From f94a71fb680ffc9e2c3ce40fd118bb63c14cd071 Mon Sep 17 00:00:00 2001 From: Derek Perkins Date: Tue, 12 Feb 2019 22:58:59 -0700 Subject: [PATCH 059/196] planbuilder: fix message inserts w/PassthroughDMLs Signed-off-by: Derek Perkins --- .../vttablet/tabletserver/planbuilder/dml.go | 14 +++++--- .../planbuilder/testdata/exec_cases.txt | 34 +++++++++++++++++++ 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/go/vt/vttablet/tabletserver/planbuilder/dml.go b/go/vt/vttablet/tabletserver/planbuilder/dml.go index c1cadcc4d73..5e67140fa72 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/dml.go +++ b/go/vt/vttablet/tabletserver/planbuilder/dml.go @@ -323,13 +323,17 @@ func analyzeInsert(ins *sqlparser.Insert, tables map[string]*schema.Table) (plan } table, tableErr := plan.setTable(tableName, tables) - // In passthrough dml mode, allow the operation even if the - // table is unknown in the schema. - if PassthroughDMLs { + switch { + case tableErr == nil && table.Type == schema.Message: + // message inserts need to continue being strict, even in passthrough dml mode, + // because field defaults are set here + + case PassthroughDMLs: + // In passthrough dml mode, allow the operation even if the + // table is unknown in the schema. return plan, nil - } - if tableErr != nil { + case tableErr != nil: return nil, tableErr } diff --git a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt index 9a60c082c79..b23e26fa529 100644 --- a/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt +++ b/go/vt/vttablet/tabletserver/planbuilder/testdata/exec_cases.txt @@ -974,6 +974,23 @@ options:PassthroughDMLs "PKValues": [[1], [2]] } +# message insert with time_scheduled specified with PassthroughDMLs +options:PassthroughDMLs +"insert into msg(time_scheduled, id, message) values(1, 2, 'aa')" +{ + "PlanID": "INSERT_MESSAGE", + "TableName": "msg", + "Permissions": [ + { + "TableName": "msg", + "Role": 1 + } + ], + "FullQuery": "insert into msg(time_scheduled, id, message) values (1, 2, 'aa')", + "OuterQuery": "insert into msg(time_scheduled, id, message, time_next, time_created, epoch) values (1, 2, 'aa', 1, :#time_now, 0)", + "PKValues": [[1], [2]] +} + # message insert with no time_schedule "insert into msg(id, message) values(2, 'aa')" { @@ -990,6 +1007,23 @@ options:PassthroughDMLs "PKValues": [[":#time_now"], [2]] } +# message insert with no time_schedule with PassthroughDMLs +options:PassthroughDMLs +"insert into msg(id, message) values(2, 'aa')" +{ + "PlanID": "INSERT_MESSAGE", + "TableName": "msg", + "Permissions": [ + { + "TableName": "msg", + "Role": 1 + } + ], + "FullQuery": "insert into msg(id, message) values (2, 'aa')", + "OuterQuery": "insert into msg(id, message, time_scheduled, time_next, time_created, epoch) values (2, 'aa', :#time_now, :#time_now, :#time_now, 0)", + "PKValues": [[":#time_now"], [2]] +} + # message multi-value insert "insert into msg(time_scheduled, id, message) values(1, 2, 'aa'), (3, 4, 'bb')" { From 9bbae994072a5e1d9ca985d179ba172a696b9bf7 Mon Sep 17 00:00:00 2001 From: Kim Bao Long Date: Wed, 13 Feb 2019 16:05:12 +0700 Subject: [PATCH 060/196] Fix small errors in printing Signed-off-by: Kim Bao Long --- go/vt/schemamanager/schemamanager_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/schemamanager/schemamanager_test.go b/go/vt/schemamanager/schemamanager_test.go index 18a44a006b3..38047f82222 100644 --- a/go/vt/schemamanager/schemamanager_test.go +++ b/go/vt/schemamanager/schemamanager_test.go @@ -59,7 +59,7 @@ func TestSchemaManagerControllerOpenFail(t *testing.T) { err := Run(ctx, controller, newFakeExecutor(t)) if err != errControllerOpen { - t.Fatalf("controller.Open fail, shoud get error: %v, but get error: %v", + t.Fatalf("controller.Open fail, should get error: %v, but get error: %v", errControllerOpen, err) } } @@ -70,7 +70,7 @@ func TestSchemaManagerControllerReadFail(t *testing.T) { ctx := context.Background() err := Run(ctx, controller, newFakeExecutor(t)) if err != errControllerRead { - t.Fatalf("controller.Read fail, shoud get error: %v, but get error: %v", + t.Fatalf("controller.Read fail, should get error: %v, but get error: %v", errControllerRead, err) } if !controller.onReadFailTriggered { From f8116b70f38edfa13c11cfd4437222ca9e355f3f Mon Sep 17 00:00:00 2001 From: Leo Xuzhang Lin Date: Wed, 13 Feb 2019 14:59:11 -0500 Subject: [PATCH 061/196] healthcheck: Cache regions in tablet_stats_cache Signed-off-by: Leo Xuzhang Lin --- go/vt/discovery/tablet_stats_cache.go | 36 +++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/go/vt/discovery/tablet_stats_cache.go b/go/vt/discovery/tablet_stats_cache.go index 7fa1809e5ce..f3bbe453ea2 100644 --- a/go/vt/discovery/tablet_stats_cache.go +++ b/go/vt/discovery/tablet_stats_cache.go @@ -56,6 +56,8 @@ type TabletStatsCache struct { entries map[string]map[string]map[topodatapb.TabletType]*tabletStatsCacheEntry // tsm is a helper to broadcast aggregate stats. tsm srvtopo.TargetStatsMultiplexer + // cellRegions is a cache of cell regions + cellRegions map[string]string } // tabletStatsCacheEntry is the per keyspace/shard/tabletType @@ -134,6 +136,7 @@ func newTabletStatsCache(hc HealthCheck, ts *topo.Server, cell string, setListen aggregatesChan: make(chan []*srvtopo.TargetStatsEntry, 100), entries: make(map[string]map[string]map[topodatapb.TabletType]*tabletStatsCacheEntry), tsm: srvtopo.NewTargetStatsMultiplexer(), + cellRegions: make(map[string]string), } if setListener { @@ -193,13 +196,36 @@ func (tc *TabletStatsCache) getOrCreateEntry(target *querypb.Target) *tabletStat return e } -func (tc *TabletStatsCache) getRegionByCell(cell string) string { - return topo.GetRegionByCell(context.Background(), tc.ts, cell) +func (tc *TabletStatsCache) getRegionByCell(cell string) (string, bool) { + tc.mu.RLock() + defer tc.mu.RUnlock() + if region, ok := tc.cellRegions[cell]; ok { + return region, true + } + return "", false +} + +func (tc *TabletStatsCache) getOrCreateRegionByCell(cell string) string { + // Fast path + if region, ok := tc.getRegionByCell(cell); ok { + return region + } + + // Slow path + tc.mu.Lock() + defer tc.mu.Unlock() + + region := topo.GetRegionByCell(context.Background(), tc.ts, cell) + tc.cellRegions[cell] = region + + return region } // StatsUpdate is part of the HealthCheckStatsListener interface. func (tc *TabletStatsCache) StatsUpdate(ts *TabletStats) { - if ts.Target.TabletType != topodatapb.TabletType_MASTER && ts.Tablet.Alias.Cell != tc.cell && tc.getRegionByCell(ts.Tablet.Alias.Cell) != tc.getRegionByCell(tc.cell) { + if ts.Target.TabletType != topodatapb.TabletType_MASTER && + ts.Tablet.Alias.Cell != tc.cell && + tc.getOrCreateRegionByCell(ts.Tablet.Alias.Cell) != tc.getOrCreateRegionByCell(tc.cell) { // this is for a non-master tablet in a different cell and a different region, drop it return } @@ -270,7 +296,7 @@ func (tc *TabletStatsCache) StatsUpdate(ts *TabletStats) { func (tc *TabletStatsCache) makeAggregateMap(stats []*TabletStats) map[string]*querypb.AggregateStats { result := make(map[string]*querypb.AggregateStats) for _, ts := range stats { - region := tc.getRegionByCell(ts.Tablet.Alias.Cell) + region := tc.getOrCreateRegionByCell(ts.Tablet.Alias.Cell) agg, ok := result[region] if !ok { agg = &querypb.AggregateStats{ @@ -363,7 +389,7 @@ func (tc *TabletStatsCache) GetAggregateStats(target *querypb.Target) (*querypb. return agg, nil } } - targetRegion := tc.getRegionByCell(target.Cell) + targetRegion := tc.getOrCreateRegionByCell(target.Cell) agg, ok := e.aggregates[targetRegion] if !ok { return nil, topo.NewError(topo.NoNode, topotools.TargetIdent(target)) From f49d9e07c357e0ae8a4e762aa4e56b29247cf8ed Mon Sep 17 00:00:00 2001 From: Leo Xuzhang Lin Date: Wed, 13 Feb 2019 16:44:48 -0500 Subject: [PATCH 062/196] Have a single method for region Signed-off-by: Leo Xuzhang Lin --- go/vt/discovery/tablet_stats_cache.go | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/go/vt/discovery/tablet_stats_cache.go b/go/vt/discovery/tablet_stats_cache.go index f3bbe453ea2..db8b6780bce 100644 --- a/go/vt/discovery/tablet_stats_cache.go +++ b/go/vt/discovery/tablet_stats_cache.go @@ -196,25 +196,14 @@ func (tc *TabletStatsCache) getOrCreateEntry(target *querypb.Target) *tabletStat return e } -func (tc *TabletStatsCache) getRegionByCell(cell string) (string, bool) { - tc.mu.RLock() - defer tc.mu.RUnlock() - if region, ok := tc.cellRegions[cell]; ok { - return region, true - } - return "", false -} +func (tc *TabletStatsCache) getRegionByCell(cell string) string { + tc.mu.Lock() + defer tc.mu.Unlock() -func (tc *TabletStatsCache) getOrCreateRegionByCell(cell string) string { - // Fast path - if region, ok := tc.getRegionByCell(cell); ok { + if region, ok := tc.cellRegions[cell]; ok { return region } - // Slow path - tc.mu.Lock() - defer tc.mu.Unlock() - region := topo.GetRegionByCell(context.Background(), tc.ts, cell) tc.cellRegions[cell] = region @@ -225,7 +214,7 @@ func (tc *TabletStatsCache) getOrCreateRegionByCell(cell string) string { func (tc *TabletStatsCache) StatsUpdate(ts *TabletStats) { if ts.Target.TabletType != topodatapb.TabletType_MASTER && ts.Tablet.Alias.Cell != tc.cell && - tc.getOrCreateRegionByCell(ts.Tablet.Alias.Cell) != tc.getOrCreateRegionByCell(tc.cell) { + tc.getRegionByCell(ts.Tablet.Alias.Cell) != tc.getRegionByCell(tc.cell) { // this is for a non-master tablet in a different cell and a different region, drop it return } @@ -296,7 +285,7 @@ func (tc *TabletStatsCache) StatsUpdate(ts *TabletStats) { func (tc *TabletStatsCache) makeAggregateMap(stats []*TabletStats) map[string]*querypb.AggregateStats { result := make(map[string]*querypb.AggregateStats) for _, ts := range stats { - region := tc.getOrCreateRegionByCell(ts.Tablet.Alias.Cell) + region := tc.getRegionByCell(ts.Tablet.Alias.Cell) agg, ok := result[region] if !ok { agg = &querypb.AggregateStats{ @@ -389,7 +378,7 @@ func (tc *TabletStatsCache) GetAggregateStats(target *querypb.Target) (*querypb. return agg, nil } } - targetRegion := tc.getOrCreateRegionByCell(target.Cell) + targetRegion := tc.getRegionByCell(target.Cell) agg, ok := e.aggregates[targetRegion] if !ok { return nil, topo.NewError(topo.NoNode, topotools.TargetIdent(target)) From 7092679c93d773364a29aa9a51c4c5a0552c43b1 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Wed, 13 Feb 2019 14:51:58 -0800 Subject: [PATCH 063/196] Fix bugs in new srvKeyspace functions. Update tests to reflect new changes Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 38 ++++++++++++++------ go/vt/vttablet/tabletmanager/state_change.go | 11 ++++-- go/vt/worker/legacy_split_clone.go | 2 +- go/vt/wrangler/keyspace.go | 5 +-- go/vt/wrangler/shard.go | 6 ++++ test/legacy_resharding.py | 10 ++++-- test/utils.py | 20 ++++++----- 7 files changed, 65 insertions(+), 27 deletions(-) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index e57ac94f678..86c9e43d284 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -28,6 +28,7 @@ import ( "golang.org/x/net/context" "vitess.io/vitess/go/vt/concurrency" + "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/topo/topoproto" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -326,7 +327,7 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string for _, si := range shards { found := false for _, tabletControl := range partition.GetShardTabletControls() { - if tabletControl.GetName() == si.ShardName() { + if key.KeyRangeEqual(tabletControl.GetKeyRange(), si.GetKeyRange()) { found = true tabletControl.QueryServiceDisabled = disableQueryService } @@ -397,21 +398,38 @@ func (ts *Server) MigrateServedType(ctx context.Context, keyspace string, shards continue } - shardReferences := partition.GetShardReferences()[:0] - for _, si := range shardsToRemove { - for _, shardReference := range shardReferences { - if shardReference.GetName() != si.ShardName() { - shardReferences = append(shardReferences, shardReference) + shardReferences := make([]*topodatapb.ShardReference, 0) + + for _, shardReference := range partition.GetShardReferences() { + inShardsToRemove := false + for _, si := range shardsToRemove { + if key.KeyRangeEqual(shardReference.GetKeyRange(), si.GetKeyRange()) { + inShardsToRemove = true + break } } + + if !inShardsToRemove { + shardReferences = append(shardReferences, shardReference) + } } for _, si := range shardsToAdd { - shardReference := &topodatapb.ShardReference{ - Name: si.ShardName(), - KeyRange: si.KeyRange, + alreadyAdded := false + for _, shardReference := range partition.GetShardReferences() { + if key.KeyRangeEqual(shardReference.GetKeyRange(), si.GetKeyRange()) { + alreadyAdded = true + break + } + } + + if !alreadyAdded { + shardReference := &topodatapb.ShardReference{ + Name: si.ShardName(), + KeyRange: si.KeyRange, + } + shardReferences = append(shardReferences, shardReference) } - shardReferences = append(shardReferences, shardReference) } partition.ShardReferences = shardReferences diff --git a/go/vt/vttablet/tabletmanager/state_change.go b/go/vt/vttablet/tabletmanager/state_change.go index 0b815ac22da..9ca5a39d39c 100644 --- a/go/vt/vttablet/tabletmanager/state_change.go +++ b/go/vt/vttablet/tabletmanager/state_change.go @@ -30,6 +30,7 @@ import ( "vitess.io/vitess/go/event" "vitess.io/vitess/go/trace" + "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/mysqlctl" "vitess.io/vitess/go/vt/topo" @@ -223,12 +224,18 @@ func (agent *ActionAgent) changeCallback(ctx context.Context, oldTablet, newTabl } else { for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != newTablet.Type { + continue + } + for _, tabletControl := range partition.GetShardTabletControls() { - if tabletControl.Name == newTablet.Shard { + if key.KeyRangeEqual(tabletControl.GetKeyRange(), newTablet.GetKeyRange()) { + log.Infof("This is the partition tabletControl KeyRange: %v newtabletKeyRange: %v changed: %v", tabletControl.GetName(), newTablet.GetShard(), tabletControl.QueryServiceDisabled) if tabletControl.QueryServiceDisabled { allowQuery = false - disallowQueryReason = "SrvKeyspace.QueryServiceEnabled set to false" + disallowQueryReason = "TabletControl.DisableQueryService set" } + break } } } diff --git a/go/vt/worker/legacy_split_clone.go b/go/vt/worker/legacy_split_clone.go index a510ee57728..3627be77839 100644 --- a/go/vt/worker/legacy_split_clone.go +++ b/go/vt/worker/legacy_split_clone.go @@ -618,7 +618,7 @@ func (scw *LegacySplitCloneWorker) copy(ctx context.Context) error { destinationWaitGroup.Add(1) go func(keyspace, shard string, kr *topodatapb.KeyRange) { defer destinationWaitGroup.Done() - scw.wr.Logger().Infof("Making and populating vreplication table") + scw.wr.Logger().Infof("Making and populating vreplication table for %v/%v", keyspace, shard) exc := newExecutor(scw.wr, scw.tsc, nil, keyspace, shard, 0) for shardIndex, src := range scw.sourceShards { diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index df96ae26cfb..8c58d435d65 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -29,6 +29,7 @@ import ( "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/discovery" + "vitess.io/vitess/go/vt/key" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" topodatapb "vitess.io/vitess/go/vt/proto/topodata" vschemapb "vitess.io/vitess/go/vt/proto/vschema" @@ -479,7 +480,7 @@ func (wr *Wrangler) replicaMigrateServedType(ctx context.Context, keyspace strin // Check and update all source shard records. // Enable query service if needed event.DispatchUpdate(ev, "updating shards to migrate from") - if err = wr.updateShardRecords(ctx, keyspace, fromShards, cells, servedType, true, false); err != nil { + if err = wr.updateShardRecords(ctx, keyspace, fromShards, cells, servedType, true /* isFrom */, false /* clearSourceShards */); err != nil { return err } @@ -513,7 +514,7 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string for _, partition := range srvKeyspace.GetPartitions() { if partition.GetServedType() != topodatapb.TabletType_MASTER { for _, shardReference := range partition.GetShardReferences() { - if shardReference.GetKeyRange() == si.GetKeyRange() { + if key.KeyRangeEqual(shardReference.GetKeyRange(), si.GetKeyRange()) { shardServedTypes = append(shardServedTypes, partition.GetServedType().String()) } } diff --git a/go/vt/wrangler/shard.go b/go/vt/wrangler/shard.go index 9b6601cef95..d17de7d5314 100644 --- a/go/vt/wrangler/shard.go +++ b/go/vt/wrangler/shard.go @@ -300,6 +300,12 @@ func (wr *Wrangler) RemoveShardCell(ctx context.Context, keyspace, shard, cell s // now we can update the shard wr.Logger().Infof("Removing cell %v from SrvKeyspace %v/%v", cell, keyspace, shard) + // lock the keyspace + ctx, unlock, lockErr := wr.ts.LockKeyspace(ctx, keyspace, "Locking keyspace to remove shard from SrvKeyspace") + if lockErr != nil { + return lockErr + } + defer unlock(&err) return wr.ts.RemoveShardServingKeyspace(ctx, shardInfo, shardServingCells) } diff --git a/test/legacy_resharding.py b/test/legacy_resharding.py index 4f0ecd41998..a80e5a01e5c 100755 --- a/test/legacy_resharding.py +++ b/test/legacy_resharding.py @@ -527,7 +527,7 @@ def test_resharding(self): utils.check_tablet_query_service(self, shard_1_rdonly1, False, True) # then serve replica from the split shards - destination_shards = ['test_keyspace/80-c0', 'test_keyspace/c0-'] + destination_shards = ['80-c0', 'c0-'] utils.run_vtctl(['MigrateServedTypes', 'test_keyspace/80-', 'replica'], auto_log=True) @@ -549,7 +549,9 @@ def test_resharding(self): # Destination tablets would have query service disabled for other # reasons than the migration, so check the shard record instead of # the tablets directly. - utils.check_shard_query_services(self, destination_shards, + utils.check_shard_query_services(self, 'test_nj', 'test_keyspace', destination_shards, + topodata_pb2.REPLICA, False) + utils.check_shard_query_services(self, 'test_ny', 'test_keyspace', destination_shards, topodata_pb2.REPLICA, False) utils.check_srv_keyspace('test_nj', 'test_keyspace', 'Partitions(master): -80 80-\n' @@ -566,7 +568,9 @@ def test_resharding(self): # Destination tablets would have query service disabled for other # reasons than the migration, so check the shard record instead of # the tablets directly - utils.check_shard_query_services(self, destination_shards, + utils.check_shard_query_services(self, 'test_nj', 'test_keyspace', destination_shards, + topodata_pb2.REPLICA, True) + utils.check_shard_query_services(self, 'test_ny', 'test_keyspace', destination_shards, topodata_pb2.REPLICA, True) utils.check_srv_keyspace('test_nj', 'test_keyspace', 'Partitions(master): -80 80-\n' diff --git a/test/utils.py b/test/utils.py index 2bae9fa3ebf..7b4a576d2d5 100644 --- a/test/utils.py +++ b/test/utils.py @@ -1079,17 +1079,19 @@ def check_srv_keyspace(cell, keyspace, expected, keyspace_id_type='uint64', def check_shard_query_service( - testcase, shard_name, tablet_type, expected_state): + testcase, cell, keyspace, shard_name, tablet_type, expected_state): """Checks DisableQueryService in the shard record's TabletControlMap.""" # We assume that query service should be enabled unless # DisableQueryService is explicitly True query_service_enabled = True - tablet_controls = run_vtctl_json( - ['GetShard', shard_name]).get('tablet_controls') - if tablet_controls: - for tc in tablet_controls: - if tc['tablet_type'] == tablet_type: - if tc.get('disable_query_service', False): + ks = run_vtctl_json(['GetSrvKeyspace', cell, keyspace]) + for partition in ks['partitions']: + tablet_type = topodata_pb2.TabletType.Name(partition['served_type']) + if tablet_type != tablet_type: + continue + for shard in partition['shard_tablet_controls']: + if shard['name'] == shard_name: + if shard['query_service_disabled']: query_service_enabled = False testcase.assertEqual( @@ -1102,10 +1104,10 @@ def check_shard_query_service( def check_shard_query_services( - testcase, shard_names, tablet_type, expected_state): + testcase, cell, keyspace, shard_names, tablet_type, expected_state): for shard_name in shard_names: check_shard_query_service( - testcase, shard_name, tablet_type, expected_state) + testcase, cell, keyspace, shard_name, tablet_type, expected_state) def check_tablet_query_service( From 64c7c6101f462fb0e339e5ee8ded12424cc3a27e Mon Sep 17 00:00:00 2001 From: Leo Xuzhang Lin Date: Wed, 13 Feb 2019 17:52:04 -0500 Subject: [PATCH 064/196] Alloc cellRegions in test Signed-off-by: Leo Xuzhang Lin --- go/vt/discovery/tablet_stats_cache_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/go/vt/discovery/tablet_stats_cache_test.go b/go/vt/discovery/tablet_stats_cache_test.go index cfc9ba21d3b..8bc5e8caafd 100644 --- a/go/vt/discovery/tablet_stats_cache_test.go +++ b/go/vt/discovery/tablet_stats_cache_test.go @@ -38,8 +38,9 @@ func TestTabletStatsCache(t *testing.T) { // HealthCheck object, so we can't call NewTabletStatsCache. // So we just construct this object here. tsc := &TabletStatsCache{ - cell: "cell", - entries: make(map[string]map[string]map[topodatapb.TabletType]*tabletStatsCacheEntry), + cell: "cell", + entries: make(map[string]map[string]map[topodatapb.TabletType]*tabletStatsCacheEntry), + cellRegions: make(map[string]string), } // empty From 68965cfffc0d585cd3fba23d45b61d9e7822d0ca Mon Sep 17 00:00:00 2001 From: Vu Cong Tuan Date: Thu, 14 Feb 2019 09:40:56 +0700 Subject: [PATCH 065/196] Update deprecated links in doc Signed-off-by: Vu Cong Tuan --- doc/GettingStartedKubernetes.md | 18 +++++++++--------- doc/ServerConfiguration.md | 2 +- doc/ShardingKubernetes.md | 2 +- doc/ShardingKubernetesWorkflow.md | 2 +- doc/VitessOverview.md | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/doc/GettingStartedKubernetes.md b/doc/GettingStartedKubernetes.md index 318c659ce5d..cc1f763cab8 100644 --- a/doc/GettingStartedKubernetes.md +++ b/doc/GettingStartedKubernetes.md @@ -1,9 +1,9 @@ -This page explains how to run Vitess on [Kubernetes](http://kubernetes.io). +This page explains how to run Vitess on [Kubernetes](https://kubernetes.io). It also gives the steps to start a Kubernetes cluster with [Google Container Engine](https://cloud.google.com/container-engine/). If you already have Kubernetes v1.0+ running in one of the other -[supported platforms](http://kubernetes.io/docs/getting-started-guides/), +[supported platforms](https://kubernetes.io/docs/setup/pick-right-solution/), you can skip the `gcloud` steps. The `kubectl` steps will apply to any Kubernetes cluster. @@ -230,7 +230,7 @@ $ export KUBECTL=/example/path/to/google-cloud-sdk/bin/kubectl and the other is for a [local cell]({% link overview/concepts.md %}#cell-data-center) called *test*. You can check the status of the - [pods](http://kubernetes.io/v1.1/docs/user-guide/pods.html) + [pods](https://kubernetes.io/docs/concepts/workloads/pods/) in the cluster by running: ``` sh @@ -308,8 +308,8 @@ $ export KUBECTL=/example/path/to/google-cloud-sdk/bin/kubectl To enable RPC access into the Kubernetes cluster, we'll again use `kubectl` to set up an authenticated tunnel. Unlike the HTTP proxy we used for the web UI, this time we need raw [port forwarding] - (http://kubernetes.io/v1.1/docs/user-guide/kubectl/kubectl_port-forward.html) - for vtctld's [gRPC](http://grpc.io) port. + (https://kubernetes.io/docs/tasks/access-application-cluster/port-forward-access-application-cluster/) + for vtctld's [gRPC](https://grpc.io) port. Since the tunnel needs to target a particular vtctld pod name, we've provided the `kvtctl.sh` script, which uses `kubectl` to @@ -357,7 +357,7 @@ $ export KUBECTL=/example/path/to/google-cloud-sdk/bin/kubectl `vttablet` and `mysqld` processes, running on the same host. We enforce this coupling in Kubernetes by putting the respective containers for vttablet and mysqld inside a single - [pod](http://kubernetes.io/v1.1/docs/user-guide/pods.html). + [pod](https://kubernetes.io/docs/concepts/workloads/pods/). Run the following script to launch the vttablet pods, which also include mysqld: @@ -530,7 +530,7 @@ $ export KUBECTL=/example/path/to/google-cloud-sdk/bin/kubectl query to the correct `vttablet`. In Kubernetes, a `vtgate` service distributes connections to a pool of `vtgate` pods. The pods are curated by a [replication controller] - (http://kubernetes.io/v1.1/docs/user-guide/replication-controller.html). + (https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller/). ``` sh vitess/examples/kubernetes$ ./vtgate-up.sh @@ -563,11 +563,11 @@ As with the `vtctld` service, by default the GuestBook app is not accessible from outside Kubernetes. In this case, since this is a user-facing frontend, we set `type: LoadBalancer` in the GuestBook service definition, which tells Kubernetes to create a public -[load balancer](http://kubernetes.io/v1.1/docs/user-guide/services.html#type-loadbalancer) +[load balancer](https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/) using the API for whatever platform your Kubernetes cluster is in. You also need to [allow access through your platform's firewall] -(http://kubernetes.io/v1.1/docs/user-guide/services-firewalls.html). +(https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/). ``` sh # For example, to open port 80 in the GCE firewall: diff --git a/doc/ServerConfiguration.md b/doc/ServerConfiguration.md index 32f19087208..b1f00d12360 100644 --- a/doc/ServerConfiguration.md +++ b/doc/ServerConfiguration.md @@ -24,7 +24,7 @@ config files](https://github.com/vitessio/vitess/blob/312064b96ac0070d9f8990e57a To customize the `my.cnf`, you can either add overrides in an additional `EXTRA_MY_CNF` file, or modify the files in `$VTROOT/config/mycnf` before distributing to your servers. In Kubernetes, you can use a -[ConfigMap](http://kubernetes.io/docs/user-guide/configmap/) to overwrite +[ConfigMap](https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/) to overwrite the entire `$VTROOT/config/mycnf` directory with your custom versions, rather than baking them into a custom container image. diff --git a/doc/ShardingKubernetes.md b/doc/ShardingKubernetes.md index 3a6314c93a8..2181b2e004c 100644 --- a/doc/ShardingKubernetes.md +++ b/doc/ShardingKubernetes.md @@ -1,6 +1,6 @@ This guide walks you through the process of sharding an existing unsharded Vitess [keyspace]({% link overview/concepts.md %}#keyspace) in -[Kubernetes](http://kubernetes.io/). +[Kubernetes](https://kubernetes.io/). ## Prerequisites diff --git a/doc/ShardingKubernetesWorkflow.md b/doc/ShardingKubernetesWorkflow.md index 444604a5073..a428861c9ef 100644 --- a/doc/ShardingKubernetesWorkflow.md +++ b/doc/ShardingKubernetesWorkflow.md @@ -1,6 +1,6 @@ This guide shows you an example about how to apply range-based sharding process in an existing unsharded Vitess [keyspace]({% link overview/concepts.md %}#keyspace) -in [Kubernetes](http://kubernetes.io/) using the horizontal resharding workflow. +in [Kubernetes](https://kubernetes.io/) using the horizontal resharding workflow. In this example, we will reshard from 1 shard "0" into 2 shards "-80" and "80-". We will follow a process similar to the general [Horizontal Sharding guide]({% link user-guide/horizontal-sharding-workflow.md %}) diff --git a/doc/VitessOverview.md b/doc/VitessOverview.md index 9b014b909a1..9258e981623 100644 --- a/doc/VitessOverview.md +++ b/doc/VitessOverview.md @@ -174,11 +174,11 @@ Vitess also includes the following tools: ## Vitess on Kubernetes -[Kubernetes](http://kubernetes.io/) is an open-source orchestration system for Docker containers, and Vitess can run as a Kubernetes-aware cloud native distributed database. +[Kubernetes](https://kubernetes.io/) is an open-source orchestration system for Docker containers, and Vitess can run as a Kubernetes-aware cloud native distributed database. Kubernetes handles scheduling onto nodes in a compute cluster, actively manages workloads on those nodes, and groups containers comprising an application for easy management and discovery. This provides an analogous open-source environment to the way Vitess runs in YouTube, -on the [predecessor to Kubernetes](http://blog.kubernetes.io/2015/04/borg-predecessor-to-kubernetes.html). +on the [predecessor to Kubernetes](https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes/). The easiest way to run Vitess is via Kubernetes. However, it's not a requirement, and other types of deployment are used as well. From 4966399ee3f6280f893cf8204e36d55b26c8258c Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Wed, 13 Feb 2019 20:03:55 -0800 Subject: [PATCH 066/196] Fix small errors There are many wrong typos that need to be fixed. Signed-off-by: Nguyen Hai Truong --- doc/Contributing.md | 2 +- doc/DesignDocs.md | 2 +- doc/HorizontalReshardingWorkflowGuide.md | 2 +- doc/SeparatingVttabletMysql.md | 2 +- doc/Upgrading.md | 2 +- go/vt/proto/query/query.pb.go | 2 +- proto/query.proto | 2 +- test/initial_sharding.py | 2 +- test/legacy_resharding.py | 2 +- test/merge_sharding.py | 2 +- test/resharding.py | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/Contributing.md b/doc/Contributing.md index a5a116e9322..5c49727a920 100644 --- a/doc/Contributing.md +++ b/doc/Contributing.md @@ -34,7 +34,7 @@ A readability reviewer ensures that the reviewee is writing idiomatic code and f While there's no Go style guide, there is a set of recommendations in the Go community which add up to an implicit style guide. To make sure you're writing idiomatic Go code, please read the following documents: -* Go Readablity slides: https://talks.golang.org/2014/readability.slide +* Go Readability slides: https://talks.golang.org/2014/readability.slide * Talk about Go readability with many specific examples. * "Effective Go": https://golang.org/doc/effective_go.html * Recommendations for writing good Go code. diff --git a/doc/DesignDocs.md b/doc/DesignDocs.md index 748e83b15a3..f4d06fa0f59 100644 --- a/doc/DesignDocs.md +++ b/doc/DesignDocs.md @@ -2,4 +2,4 @@ The pages below this navigation entry "Design Docs" represent the design conside that went behind some of the features implemented. They may not be necessarily up-to-date. Also, some of the ideas here may just be experimental proposals, and it's possible -that such ideas might have been abandonned or not implemented yet. +that such ideas might have been abandoned or not implemented yet. diff --git a/doc/HorizontalReshardingWorkflowGuide.md b/doc/HorizontalReshardingWorkflowGuide.md index a287e194664..ff3eb8b0809 100644 --- a/doc/HorizontalReshardingWorkflowGuide.md +++ b/doc/HorizontalReshardingWorkflowGuide.md @@ -142,7 +142,7 @@ workflow. A "Retry" button will be enabled under the task node if the task failed (click the task node if your job get stuck but don't see the Retry button). Click this button if you have fixed the bugs and want to retry the failed task. You can -retry as many times as you want if the task continuelly failed. The workflow +retry as many times as you want if the task continually failed. The workflow can continue from your failure point once it is fixed. For example, you might forget to bring up a vtworker process. The task which diff --git a/doc/SeparatingVttabletMysql.md b/doc/SeparatingVttabletMysql.md index 0ddaeecdfa8..e98e610517f 100644 --- a/doc/SeparatingVttabletMysql.md +++ b/doc/SeparatingVttabletMysql.md @@ -26,7 +26,7 @@ The following adjustments need to be made to VTTablet command line parameters: * Disable restores / backups, by not passing any backup command line parameters. Specifically, `-restore_from_backup` and - `-backup_storage_implementation` shoud not be set. + `-backup_storage_implementation` should not be set. Since master management and replication are not handled by Vitess, we just need to make sure the tablet type in the topology is correct before running diff --git a/doc/Upgrading.md b/doc/Upgrading.md index 625c61aaafa..f9acb603760 100644 --- a/doc/Upgrading.md +++ b/doc/Upgrading.md @@ -26,7 +26,7 @@ Please use this upgrade order (unless otherwise noted in the release notes): - vtgate - application code which links client libraries -*vtctld* is listed first to make sure that you can still adminstrate Vitess - or if not find out as soon as possible. +*vtctld* is listed first to make sure that you can still administrate Vitess - or if not find out as soon as possible. ## Canary Testing diff --git a/go/vt/proto/query/query.pb.go b/go/vt/proto/query/query.pb.go index 34f04da29f9..f821d65e994 100644 --- a/go/vt/proto/query/query.pb.go +++ b/go/vt/proto/query/query.pb.go @@ -854,7 +854,7 @@ type ExecuteOptions struct { // vitess also sets a rowcount limit on queries, the smallest value wins. SqlSelectLimit int64 `protobuf:"varint,8,opt,name=sql_select_limit,json=sqlSelectLimit,proto3" json:"sql_select_limit,omitempty"` TransactionIsolation ExecuteOptions_TransactionIsolation `protobuf:"varint,9,opt,name=transaction_isolation,json=transactionIsolation,proto3,enum=query.ExecuteOptions_TransactionIsolation" json:"transaction_isolation,omitempty"` - // skip_query_plan_cache specifies if the query plan shoud be cached by vitess. + // skip_query_plan_cache specifies if the query plan should be cached by vitess. // By default all query plans are cached. SkipQueryPlanCache bool `protobuf:"varint,10,opt,name=skip_query_plan_cache,json=skipQueryPlanCache,proto3" json:"skip_query_plan_cache,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` diff --git a/proto/query.proto b/proto/query.proto index 53525325378..5fdb91d4ed9 100644 --- a/proto/query.proto +++ b/proto/query.proto @@ -296,7 +296,7 @@ message ExecuteOptions { TransactionIsolation transaction_isolation = 9; - // skip_query_plan_cache specifies if the query plan shoud be cached by vitess. + // skip_query_plan_cache specifies if the query plan should be cached by vitess. // By default all query plans are cached. bool skip_query_plan_cache = 10; } diff --git a/test/initial_sharding.py b/test/initial_sharding.py index cb4fb3428b7..5c639def51b 100755 --- a/test/initial_sharding.py +++ b/test/initial_sharding.py @@ -631,7 +631,7 @@ def test_resharding(self): utils.run_vtctl(['DeleteTablet', '-allow_master', shard_master.tablet_alias], auto_log=True) - # rebuild the serving graph, all mentions of the old shards shoud be gone + # rebuild the serving graph, all mentions of the old shards should be gone utils.run_vtctl(['RebuildKeyspaceGraph', 'test_keyspace'], auto_log=True) # delete the original shard diff --git a/test/legacy_resharding.py b/test/legacy_resharding.py index 4f0ecd41998..9e57261507d 100755 --- a/test/legacy_resharding.py +++ b/test/legacy_resharding.py @@ -622,7 +622,7 @@ def test_resharding(self): utils.run_vtctl(['DeleteTablet', '-allow_master', shard_1_master.tablet_alias], auto_log=True) - # rebuild the serving graph, all mentions of the old shards shoud be gone + # rebuild the serving graph, all mentions of the old shards should be gone utils.run_vtctl( ['RebuildKeyspaceGraph', 'test_keyspace'], auto_log=True) diff --git a/test/merge_sharding.py b/test/merge_sharding.py index 72e71e4dbfd..8a424b4bd0c 100755 --- a/test/merge_sharding.py +++ b/test/merge_sharding.py @@ -452,7 +452,7 @@ def test_merge_sharding(self): utils.run_vtctl(['DeleteShard', 'test_keyspace/-40'], auto_log=True) utils.run_vtctl(['DeleteShard', 'test_keyspace/40-80'], auto_log=True) - # rebuild the serving graph, all mentions of the old shards shoud be gone + # rebuild the serving graph, all mentions of the old shards should be gone utils.run_vtctl(['RebuildKeyspaceGraph', 'test_keyspace'], auto_log=True) # kill everything else diff --git a/test/resharding.py b/test/resharding.py index a942c6dd466..39010a8c51c 100755 --- a/test/resharding.py +++ b/test/resharding.py @@ -1214,7 +1214,7 @@ def test_resharding(self): utils.run_vtctl(['DeleteTablet', '-allow_master', shard_1_master.tablet_alias], auto_log=True) - # rebuild the serving graph, all mentions of the old shards shoud be gone + # rebuild the serving graph, all mentions of the old shards should be gone utils.run_vtctl( ['RebuildKeyspaceGraph', 'test_keyspace'], auto_log=True) From a8dd1810653e8819fa2d7e20e5d561dcc10d14a7 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Wed, 13 Feb 2019 22:21:22 -0800 Subject: [PATCH 067/196] Fix issue with bad dns zookeeper test * I think this test was passing by luck because we didn't have any real operations that interacted with that cell. Given the global topology refactor part of this PR, this has changed and now this breaks. * I think the regression happened when samuel/go-zookeeper was introduced, but this was never discovered. This test was originally introduced in: https://github.com/vitessio/vitess/commit/c685aaf2430a0721a46878ff3fe5b8934095235e Signed-off-by: Rafael Chacon --- go/vt/topo/shard.go | 2 +- test/tabletmanager.py | 7 +------ test/tabletmanager2.py | 7 +------ test/topo_flavor/zk2.py | 4 +--- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index 8c05f7d88be..850250c5f9d 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -512,7 +512,7 @@ func (ts *Server) FindAllTabletAliasesInShardByCell(ctx context.Context, keyspac ctx = trace.NewContext(ctx, span) var err error - // The caller intents to update all cells in this case + // The caller intents to all cells if len(cells) == 0 { cells, err = ts.GetCellInfoNames(ctx) if err != nil { diff --git a/test/tabletmanager.py b/test/tabletmanager.py index 1956cf9d245..14dd99ed6a6 100755 --- a/test/tabletmanager.py +++ b/test/tabletmanager.py @@ -46,12 +46,7 @@ def setUpModule(): try: topo_flavor = environment.topo_server().flavor() - if topo_flavor == 'zk2': - # This is a one-off test to make sure our 'zk2' implementation - # behave with a server that is not DNS-resolveable. - environment.topo_server().setup(add_bad_host=True) - else: - environment.topo_server().setup() + environment.topo_server().setup() # start mysql instance external to the test setup_procs = [ diff --git a/test/tabletmanager2.py b/test/tabletmanager2.py index e65af1f1f92..b2d4ba87899 100755 --- a/test/tabletmanager2.py +++ b/test/tabletmanager2.py @@ -56,12 +56,7 @@ def setUp(self): try: topo_flavor = environment.topo_server().flavor() - if topo_flavor == 'zk2': - # This is a one-off test to make sure our 'zk2' implementation - # behave with a server that is not DNS-resolveable. - environment.topo_server().setup(add_bad_host=True) - else: - environment.topo_server().setup() + environment.topo_server().setup() # start mysql instance external to the test setup_procs = [ diff --git a/test/topo_flavor/zk2.py b/test/topo_flavor/zk2.py index b460bcd8b56..e3695b14612 100644 --- a/test/topo_flavor/zk2.py +++ b/test/topo_flavor/zk2.py @@ -40,7 +40,7 @@ def assign_ports(self): self.addr = 'localhost:%d' % (self.zk_port_base + 2) self.ports_assigned = True - def setup(self, add_bad_host=False): + def setup(self): from environment import run, binary_args, vtlogroot # pylint: disable=g-import-not-at-top,g-multiple-import import utils # pylint: disable=g-import-not-at-top @@ -60,8 +60,6 @@ def setup(self, add_bad_host=False): '-server_address', self.addr, 'test_ny']) ca_addr = self.addr - if add_bad_host: - ca_addr += ',does.not.exists:1234' # Use UpdateCellInfo for this one, more coverage. utils.run_vtctl_vtctl(['UpdateCellInfo', '-root', '/test_ca', From eb7157b6194fe2a8a394f838a3a481c00a7595c8 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Thu, 14 Feb 2019 13:16:40 -0800 Subject: [PATCH 068/196] Cleanup deprecated tests Signed-off-by: Rafael Chacon --- go/vt/topo/helpers/copy_test.go | 1 - go/vt/topo/shard.go | 37 --------- go/vt/topo/shard_test.go | 116 ---------------------------- go/vt/topotools/rebuild_keyspace.go | 1 - 4 files changed, 155 deletions(-) diff --git a/go/vt/topo/helpers/copy_test.go b/go/vt/topo/helpers/copy_test.go index 59d1df92822..218249fe5e8 100644 --- a/go/vt/topo/helpers/copy_test.go +++ b/go/vt/topo/helpers/copy_test.go @@ -42,7 +42,6 @@ func createSetup(ctx context.Context, t *testing.T) (*topo.Server, *topo.Server) if err := fromTS.CreateShard(ctx, "test_keyspace", "0"); err != nil { t.Fatalf("cannot create shard: %v", err) } - tablet1 := &topodatapb.Tablet{ Alias: &topodatapb.TabletAlias{ Cell: "test_cell", diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index 850250c5f9d..76d05808f3f 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -429,43 +429,6 @@ func (si *ShardInfo) removeCellsFromTabletControl(tc *topodatapb.Shard_TabletCon } } -// UpdateServedTypesMap handles ServedTypesMap. It can add or remove cells. -// func (si *ShardInfo) UpdateServedTypesMap(tabletType topodatapb.TabletType, cells []string, remove bool) error { -// sst := si.GetServedType(tabletType) - -// if remove { -// if sst == nil { -// // nothing to remove -// return nil -// } -// result, emptyList := removeCells(sst.Cells, cells, si.Cells) -// if emptyList { -// // we don't have any cell left, we need to clear this record -// var servedTypes []*topodatapb.Shard_ServedType -// for _, st := range si.ServedTypes { -// if st.TabletType != tabletType { -// servedTypes = append(servedTypes, st) -// } -// } -// si.ServedTypes = servedTypes -// return nil -// } -// sst.Cells = result -// return nil -// } - -// // add -// if sst == nil { -// si.ServedTypes = append(si.ServedTypes, &topodatapb.Shard_ServedType{ -// TabletType: tabletType, -// Cells: cells, -// }) -// return nil -// } -// sst.Cells = addCells(sst.Cells, cells) -// return nil -// } - // // Utility functions for shards // diff --git a/go/vt/topo/shard_test.go b/go/vt/topo/shard_test.go index 5fd27d172d5..cd7e843f1e2 100644 --- a/go/vt/topo/shard_test.go +++ b/go/vt/topo/shard_test.go @@ -169,119 +169,3 @@ func TestUpdateSourceBlacklistedTables(t *testing.T) { t.Fatalf("one cell removal from all failed: %v", si) } } - -// func TestUpdateServedTypesMap(t *testing.T) { -// si := NewShardInfo("ks", "sh", &topodatapb.Shard{ -// Cells: []string{"first", "second", "third"}, -// }, nil) - -// // add all cells for rdonly -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ -// { -// TabletType: topodatapb.TabletType_RDONLY, -// Cells: nil, -// }, -// }) { -// t.Fatalf("rdonly all cells add failed: %v", err) -// } - -// // add some cells for replica -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, []string{"second"}, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ -// { -// TabletType: topodatapb.TabletType_RDONLY, -// Cells: nil, -// }, -// { -// TabletType: topodatapb.TabletType_REPLICA, -// Cells: []string{"second"}, -// }, -// }) { -// t.Fatalf("replica some cells add failed: %v", err) -// } - -// // remove some cells for rdonly -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ -// { -// TabletType: topodatapb.TabletType_RDONLY, -// Cells: []string{"first", "third"}, -// }, -// { -// TabletType: topodatapb.TabletType_REPLICA, -// Cells: []string{"second"}, -// }, -// }) { -// t.Fatalf("remove some cells for rdonly failed: %v", err) -// } - -// // remove last cell for replica -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ -// { -// TabletType: topodatapb.TabletType_RDONLY, -// Cells: []string{"first", "third"}, -// }, -// }) { -// t.Fatalf("remove last cell for replica failed: %v", err) -// } - -// // Migrate each serving type (add it to this shard). -// // REPLICA -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ -// { -// TabletType: topodatapb.TabletType_RDONLY, -// Cells: []string{"first", "third"}, -// }, -// { -// TabletType: topodatapb.TabletType_REPLICA, -// Cells: nil, -// }, -// }) { -// t.Fatalf("migrate replica failed: %v", err) -// } -// // RDONLY -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ -// { -// TabletType: topodatapb.TabletType_RDONLY, -// Cells: nil, -// }, -// { -// TabletType: topodatapb.TabletType_REPLICA, -// Cells: nil, -// }, -// }) { -// t.Fatalf("migrate rdonly failed: %v", err) -// } -// // MASTER -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_MASTER, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*topodatapb.Shard_ServedType{ -// { -// TabletType: topodatapb.TabletType_RDONLY, -// Cells: nil, -// }, -// { -// TabletType: topodatapb.TabletType_REPLICA, -// Cells: nil, -// }, -// { -// TabletType: topodatapb.TabletType_MASTER, -// Cells: nil, -// }, -// }) { -// t.Fatalf("migrate master failed: %v", err) -// } - -// // Migrate each serving type away from this shard. -// // RDONLY -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_RDONLY, nil, true); err != nil { -// t.Fatalf("remove master failed: %v", err) -// } -// // REPLICA -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_REPLICA, nil, true); err != nil { -// t.Fatalf("remove master failed: %v", err) -// } -// // MASTER -// if err := si.UpdateServedTypesMap(topodatapb.TabletType_MASTER, nil, true); err != nil { -// t.Fatalf("remove master failed: %v", err) -// } -// if len(si.ServedTypes) != 0 { -// t.Fatalf("expected empty map after removing all") -// } -// } diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index 087cea832d9..485cd566c11 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -112,7 +112,6 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser // - sort the shards in the list by range // - check the ranges are compatible (no hole, covers everything) for cell, srvKeyspace := range srvKeyspaceMap { - // this is not an error for _, si := range shards { if !si.IsMasterServing { continue From 0b26cc0c9d258ef68776a6939a3df03b2e35f8b9 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Thu, 14 Feb 2019 16:27:42 -0800 Subject: [PATCH 069/196] project: add MAITAINERS.md Most of these maintainers already have the necessary approval and merge privileges. I'll add the rest once this PR goes through. I've also removed some text in a few files that were blatantly outdated. Also removed the now outdated pullapprove. Signed-off-by: Sugu Sougoumarane --- .pullapprove.yml | 23 ----------------------- CONTRIBUTING.md | 21 --------------------- MAINTAINERS.md | 38 ++++++++++++++++++++++++++++++++++++++ doc/Contributing.md | 28 +++------------------------- 4 files changed, 41 insertions(+), 69 deletions(-) delete mode 100644 .pullapprove.yml create mode 100644 MAINTAINERS.md diff --git a/.pullapprove.yml b/.pullapprove.yml deleted file mode 100644 index b631441723e..00000000000 --- a/.pullapprove.yml +++ /dev/null @@ -1,23 +0,0 @@ -version: 2 - -group_defaults: - approve_by_comment: - enabled: true - approve_regex: ':lgtm:|^(LGTM|lgtm)' - reset_on_push: - enabled: false - -groups: - vitess-eng: - required: 1 - users: - - alainjobart - - AndyDiamondstein - - bbeaudreault - - demmer - - enisoc - - mberlin-bot - - michael-berlin - - pivanof - - sougou - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 91be041af9a..19a34df79ad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,25 +1,5 @@ # Contributing to Vitess -## Before you contribute - -### Individual contributor - -Before we can use your code, you must sign the -[Google Individual Contributor License Agreement](https://cla.developers.google.com/about/google-individual) -(CLA), which you can do online. The CLA is necessary mainly because you own the -copyright to your changes, even after your contribution becomes part of our -codebase, so we need your permission to use and distribute your code. We also -need to be sure of various other things—for instance that you'll tell us if you -know that your code infringes on other people's patents. You don't have to sign -the CLA until after you've submitted your code for review and a member has -approved it, but you must do it before we can put your code into our codebase. - -### Corporate contributor - -Contributions made by corporations are covered by a different agreement than -the one above, the -[Software Grant and Corporate Contributor License Agreement](https://cla.developers.google.com/about/google-corporate). - ## Workflow For all contributors, we recommend the standard [GitHub flow](https://guides.github.com/introduction/flow/) @@ -35,4 +15,3 @@ to let everyone know what you're planning to work on, and to track progress and * How to make yourself familiar with Go and Vitess. * How to go through the GitHub workflow. * What to look for during code reviews. - diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 00000000000..6013c82c344 --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,38 @@ +This page lists all active maintainers and their areas of expertise. This can be used for routing PRs, questions, etc. to the right place. + +The following is the full list, alphabetically ordered. + +* Dan Kozlowski ([dkhenry](https://github.com/dkhenry)) koz@planetscale.com +* David Weitzman ([dweitzman](https://github.com/dweitzman)) dweitzman@pinterest.com +* Deepthi Sigireddi ([deepthi](https://github.com/deepthi)) deepthi@planetscale.com +* Derek Perkins ([derekperkins](https://github.com/derekperkins)) derek@nozzle.io +* Harshit Gangal ([harshit-gangal](https://github.com/harshit-gangal) harshit.gangal@gmail.com +* Jon Tirsen ([tirsen]((https://github.com/tirsen)) jontirsen@squareup.com +* Leo X. Lin ([leoxlin](https://github.com/leoxlin)) llin@hubspot.com +* Michael Demmer ([demmer](https://github.com/demmer)) mdemmer@slack-corp.com +* Michael Pawliszyn ([mpawliszyn](https://github.com/mpawliszyn)) mikepaw@squareup.com +* Rafael Chacon ([rafael]((https://github.com/rafael)) rchacon@slack-corp.com +* Sugu Sougoumarane ([sougou](https://github.com/sougou)) sougou@planetscale.com + +## Areas of expertise + +### General Vitess +sougou, demmmer, rafael, dweitzman, tirsen + +### Builds +dkhenry + +### Resharding +sougou, rafael, tirsen, dweitzman + +### Parser +sougou, dweitzman, deepthi + +### Backups +deepthi, rafael + +### Java +mpawliszyn, leoxlin, harshit-gangal + +### Kubernetes +derekperkins, dkhenry diff --git a/doc/Contributing.md b/doc/Contributing.md index a5a116e9322..b5168ad1fde 100644 --- a/doc/Contributing.md +++ b/doc/Contributing.md @@ -2,8 +2,6 @@ You want to contribute to Vitess? That's awesome! -In the past we have reviewed and accepted many external contributions. Examples are the Java JDBC driver, the PHP PDO driver or vtgate v3 improvements. - We're looking forward to any contribution! Before you start larger contributions, make sure to reach out first and discuss your plans with us. This page describes for new contributors how to make yourself familiar with Vitess and the programming language Go. @@ -27,10 +25,6 @@ It's a lot of fun and demonstrates how simple it is to write Go code. ### Go Readability -Internally at Google, code reviews are subject to an additional "readability" review. - -A readability reviewer ensures that the reviewee is writing idiomatic code and following the programming language's style guide. - While there's no Go style guide, there is a set of recommendations in the Go community which add up to an implicit style guide. To make sure you're writing idiomatic Go code, please read the following documents: @@ -54,22 +48,6 @@ In our opinion, the song "Write in Go" from ScaleAbility, a Google acapella band ## Learning Vitess -Before diving into the Vitess codebase, make yourself familiar with the system and run it yourself: - -* Read the [What is Vitess](/overview/) page, in particular the architecture section. - -* Read the [Vitess concepts]({% link overview/concepts.md %}) and the [Sharding]({% link user-guide/sharding.md %}) page. - - * We also recommend to look at our [latest presentations]({% link resources/presentations.md %}). They contain many illustrations which help understanding how Vitess works in detail. - - * After studying the pages, try to answer the following question (click expand to see the answer): -
    - - Let's assume a keyspace with 256 range-based shards: What is the name of the first, the second and the last shard? - - -01, 01-02, ff- -
    - -* Go through the [Vitess Kubernetes tutorial](/getting-started/). - - * While going through the tutorial, look back at the [architecture](/overview/#architecture) and match the processes you start in Kubernetes with the boxes in the diagram. +Vitess is a complex distributed system. There are a few design docs in the `/doc` section. The best way to ramp up on vitess is by starting to use it. +Then, you can dive into the code to see how the various parts work. For questions, the best place to get them answered is by asking on the slack channel. +You can sign up to the channel by clicking on the top right link at vitess.io. From 48d18390fbd1fff8d951f127a5d3b2ff17987493 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Thu, 14 Feb 2019 16:38:33 -0800 Subject: [PATCH 070/196] project: fix typo Signed-off-by: Sugu Sougoumarane --- MAINTAINERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index 6013c82c344..a69b7ab59f1 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -17,7 +17,7 @@ The following is the full list, alphabetically ordered. ## Areas of expertise ### General Vitess -sougou, demmmer, rafael, dweitzman, tirsen +sougou, demmer, rafael, dweitzman, tirsen ### Builds dkhenry From d435735fbab3a6551f8e6347cd2b3c1cfe34ad4a Mon Sep 17 00:00:00 2001 From: Aaron Young Date: Fri, 15 Feb 2019 09:00:53 -0500 Subject: [PATCH 071/196] Check for no scanners specified when createing consistent transactions Signed-off-by: Aaron Young --- go/vt/worker/diff_utils.go | 6 ++++++ go/vt/worker/split_clone.go | 3 +++ 2 files changed, 9 insertions(+) diff --git a/go/vt/worker/diff_utils.go b/go/vt/worker/diff_utils.go index 4ff6ebc92ad..304f8024993 100644 --- a/go/vt/worker/diff_utils.go +++ b/go/vt/worker/diff_utils.go @@ -26,6 +26,8 @@ import ( "strings" "time" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/tmclient" "vitess.io/vitess/go/vt/wrangler" @@ -743,6 +745,10 @@ func CreateConsistentTableScanners(ctx context.Context, tablet *topo.TabletInfo, // CreateConsistentTransactions creates a number of consistent snapshot transactions, // all starting from the same spot in the tx log func CreateConsistentTransactions(ctx context.Context, tablet *topo.TabletInfo, wr *wrangler.Wrangler, cleaner *wrangler.Cleaner, numberOfScanners int) ([]int64, string, error) { + if numberOfScanners < 1 { + return nil, "", vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "need more than zero scanners: %d", numberOfScanners) + } + tm := tmclient.NewTabletManagerClient() defer tm.Close() diff --git a/go/vt/worker/split_clone.go b/go/vt/worker/split_clone.go index bead11591cf..d3e32e6e1d5 100644 --- a/go/vt/worker/split_clone.go +++ b/go/vt/worker/split_clone.go @@ -797,6 +797,9 @@ func (scw *SplitCloneWorker) findTransactionalSources(ctx context.Context) error // stop replication and create transactions to work on txs, gtid, err := CreateConsistentTransactions(ctx, ti, scw.wr, scw.cleaner, scw.sourceReaderCount) + if err != nil { + return vterrors.Wrapf(err, "error creating consistent transactions") + } scw.wr.Logger().Infof("created %v transactions", len(txs)) scw.lastPos = gtid scw.transactions = txs From b370a3116e76cb7c2eeb2d343efb253ec128c0c4 Mon Sep 17 00:00:00 2001 From: Chris Radcliffe Date: Fri, 15 Feb 2019 11:08:23 -0800 Subject: [PATCH 072/196] Changed the comment to refer to "the mysql client" rather than vtctlclient Signed-off-by: Chris Radcliffe A simple change to clarify the purpose of the script: "vtctlclient" becomes "the mysql client". --- examples/helm/kmysql.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/helm/kmysql.sh b/examples/helm/kmysql.sh index d2a07e4cb84..eb9d5c5c68a 100755 --- a/examples/helm/kmysql.sh +++ b/examples/helm/kmysql.sh @@ -14,7 +14,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -# This is a convenience script to run vtctlclient against the local example. +# This is a convenience script to run the mysql client against the local example. host=$(minikube service vtgate-zone1 --format "{{.IP}}" | tail -n 1) port=$(minikube service vtgate-zone1 --format "{{.Port}}" | tail -n 1) From 5402ad01082ff705114b2b51da0ba2d5e89726bb Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 15 Feb 2019 14:16:36 -0800 Subject: [PATCH 073/196] Fix bugs in v2 sharding tests Signed-off-by: Rafael Chacon --- go/vt/topotools/rebuild_keyspace.go | 12 ++++++++++-- test/initial_sharding.py | 5 +++-- test/resharding.py | 10 +++++++--- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index 485cd566c11..ba07098bdb1 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -92,6 +92,14 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser ServedFrom: ki.ComputeCellServedFrom(cell), } } + if ki.ShardingColumnType != topodatapb.KeyspaceIdType_UNSET { + srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ + ShardingColumnName: ki.ShardingColumnName, + ShardingColumnType: ki.ShardingColumnType, + ServedFrom: ki.ComputeCellServedFrom(cell), + } + } + case topo.IsErrType(err, topo.NoNode): srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ ShardingColumnName: ki.ShardingColumnName, @@ -105,10 +113,11 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser } + servedTypes := []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY} + // for each entry in the srvKeyspaceMap map, we do the following: // - get the Shard structures for each shard / cell // - if not present, build an empty one from global Shard - // - compute the union of the db types (replica, master, ...) // - sort the shards in the list by range // - check the ranges are compatible (no hole, covers everything) for cell, srvKeyspace := range srvKeyspaceMap { @@ -116,7 +125,6 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser if !si.IsMasterServing { continue } - servedTypes := []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY} // for each type this shard is supposed to serve, // add it to srvKeyspace.Partitions for _, tabletType := range servedTypes { diff --git a/test/initial_sharding.py b/test/initial_sharding.py index cb4fb3428b7..62a210ca5a1 100755 --- a/test/initial_sharding.py +++ b/test/initial_sharding.py @@ -631,11 +631,12 @@ def test_resharding(self): utils.run_vtctl(['DeleteTablet', '-allow_master', shard_master.tablet_alias], auto_log=True) + # delete the original shard + utils.run_vtctl(['DeleteShard', 'test_keyspace/0'], auto_log=True) + # rebuild the serving graph, all mentions of the old shards shoud be gone utils.run_vtctl(['RebuildKeyspaceGraph', 'test_keyspace'], auto_log=True) - # delete the original shard - utils.run_vtctl(['DeleteShard', 'test_keyspace/0'], auto_log=True) # kill everything else tablet.kill_tablets([shard_0_master, shard_0_replica, shard_0_rdonly1, diff --git a/test/resharding.py b/test/resharding.py index a942c6dd466..7bd8f8d2949 100755 --- a/test/resharding.py +++ b/test/resharding.py @@ -1015,7 +1015,7 @@ def test_resharding(self): 'test_keyspace/80-', 'rdonly'], auto_log=True) # then serve replica from the split shards - destination_shards = ['test_keyspace/80-c0', 'test_keyspace/c0-'] + destination_shards = ['80-c0', 'c0-'] utils.run_vtctl(['MigrateServedTypes', 'test_keyspace/80-', 'replica'], auto_log=True) @@ -1037,7 +1037,9 @@ def test_resharding(self): # Destination tablets would have query service disabled for other # reasons than the migration, so check the shard record instead of # the tablets directly. - utils.check_shard_query_services(self, destination_shards, + utils.check_shard_query_services(self, 'test_nj', 'test_keyspace', destination_shards, + topodata_pb2.REPLICA, False) + utils.check_shard_query_services(self, 'test_ny', 'test_keyspace', destination_shards, topodata_pb2.REPLICA, False) utils.check_srv_keyspace('test_nj', 'test_keyspace', 'Partitions(master): -80 80-\n' @@ -1054,7 +1056,9 @@ def test_resharding(self): # Destination tablets would have query service disabled for other # reasons than the migration, so check the shard record instead of # the tablets directly - utils.check_shard_query_services(self, destination_shards, + utils.check_shard_query_services(self, 'test_nj', 'test_keyspace', destination_shards, + topodata_pb2.REPLICA, True) + utils.check_shard_query_services(self, 'test_ny', 'test_keyspace', destination_shards, topodata_pb2.REPLICA, True) utils.check_srv_keyspace('test_nj', 'test_keyspace', 'Partitions(master): -80 80-\n' From 0f1f26be248e7c7dea38bc5516b9bc149e3d3890 Mon Sep 17 00:00:00 2001 From: deepthi Date: Fri, 15 Feb 2019 14:54:39 -0800 Subject: [PATCH 074/196] remove unsupported case from tests Signed-off-by: deepthi --- data/test/vtgate/postprocess_cases.txt | 39 -------------------------- 1 file changed, 39 deletions(-) diff --git a/data/test/vtgate/postprocess_cases.txt b/data/test/vtgate/postprocess_cases.txt index 6a63e85c0ad..594deb8e290 100644 --- a/data/test/vtgate/postprocess_cases.txt +++ b/data/test/vtgate/postprocess_cases.txt @@ -476,45 +476,6 @@ } } -# ORDER BY non-key column from second table for implicit join FAILS!! -"select user.col1 a, user.col2 b, music.col3 c from user, music where user.id = music.id and user.id = 1 order by c" -{ - "Original": "select user.col1 a, user.col2 b, music.col3 c from user, music where user.id = music.id and user.id = 1 order by c", - "Instructions": { - "Opcode": "Join", - "Left": { - "Opcode": "SelectEqualUnique", - "Keyspace": { - "Name": "user", - "Sharded": true - }, - "Query": "select user.col1 a, user.col2 b, user.id from user where user.id = 1", - "FieldQuery": "select user.col1 a, user.col2 b, user.id from user where 1 != 1", - "Vindex": "user_index", - "Values": [1] - }, - "Right": { - "Opcode": "SelectEqualUnique", - "Keyspace": { - "Name": "user", - "Sharded": true - }, - "Query": "select music.col3 c from music where music.id = :user_id order by c", - "FieldQuery": "select music.col3 c from music where 1 != 1", - "Vindex": "music_user_map", - "Values": [":user_id"] - }, - "Cols": [ - -1, - -2, - 1 - ], - "Vars": { - "user_id": 2 - } - } -} - # ORDER BY NULL after pull-out subquery "select col from user where col in (select col2 from user) order by null" { From 5eda4cf416085b552f7c0bcbb7ef2b194497eb37 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 15 Feb 2019 18:05:09 -0800 Subject: [PATCH 075/196] Fixes uncovered by integration tests Signed-off-by: Rafael Chacon --- go/vt/vtctl/vtctl.go | 5 ++++- go/vt/wrangler/keyspace.go | 7 ++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index 310efdcab72..e1a81ba537b 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -1323,7 +1323,10 @@ func commandSetShardTabletControl(ctx context.Context, wr *wrangler.Wrangler, su if err != nil { return err } - return wr.UpdateDisableQueryService(ctx, keyspace, shard, tabletType, cells, *disableQueryService) + if !*remove && len(blacklistedTables) == 0 { + return wr.UpdateDisableQueryService(ctx, keyspace, shard, tabletType, cells, *disableQueryService) + } + return nil } func commandSourceShardDelete(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index 8c58d435d65..cd359d62414 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -608,11 +608,13 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string if err != nil { return err } - } // Enable query service - wr.ts.UpdateDisableQueryService(ctx, keyspace, destinationShards, topodatapb.TabletType_MASTER, nil, false) + err = wr.ts.UpdateDisableQueryService(ctx, keyspace, destinationShards, topodatapb.TabletType_MASTER, nil, false) + if err != nil { + return err + } event.DispatchUpdate(ev, "setting destination masters read-write") if err := wr.refreshMasters(ctx, destinationShards); err != nil { @@ -728,7 +730,6 @@ func (wr *Wrangler) startReverseReplication(ctx context.Context, sourceShards [] // updateShardRecords updates the shard records based on 'from' or 'to' direction. func (wr *Wrangler) updateShardRecords(ctx context.Context, keyspace string, shards []*topo.ShardInfo, cells []string, servedType topodatapb.TabletType, isFrom bool, clearSourceShards bool) (err error) { err = wr.ts.UpdateDisableQueryService(ctx, keyspace, shards, servedType, cells, isFrom /* disable */) - if err != nil { return err } From 1b0b81ac81eb825d89a8f1113045b061f100e765 Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Wed, 13 Feb 2019 20:50:15 -0800 Subject: [PATCH 076/196] Adding copyright headers Signed-off-by: Nguyen Hai Truong --- go/bucketpool/bucketpool.go | 16 ++++++++++++++++ go/bucketpool/bucketpool_test.go | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/go/bucketpool/bucketpool.go b/go/bucketpool/bucketpool.go index be0ec18aa7d..7839142cb67 100644 --- a/go/bucketpool/bucketpool.go +++ b/go/bucketpool/bucketpool.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Vitess 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 bucketpool import ( diff --git a/go/bucketpool/bucketpool_test.go b/go/bucketpool/bucketpool_test.go index a7e2cf0e75c..26084e95f27 100644 --- a/go/bucketpool/bucketpool_test.go +++ b/go/bucketpool/bucketpool_test.go @@ -1,3 +1,19 @@ +/* +Copyright 2019 The Vitess 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 bucketpool import ( From 979cc79b9c82d973985abd6c68816240d9c9f36b Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 15 Feb 2019 18:31:06 -0800 Subject: [PATCH 077/196] More test fixes Signed-off-by: Rafael Chacon --- go/vt/wrangler/keyspace.go | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index cd359d62414..6f8869475ff 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -621,6 +621,22 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string return err } + // Update srvKeyspace now + if err = wr.ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_MASTER, nil); err != nil { + return err + } + + // Make sure that from now on source shards have IsMasterServing set to false + for _, si := range sourceShards { + _, err := wr.ts.UpdateShardFields(ctx, si.Keyspace(), si.ShardName(), func(si *topo.ShardInfo) error { + si.IsMasterServing = false + return nil + }) + if err != nil { + return err + } + } + if reverseReplication { if err := wr.startReverseReplication(ctx, sourceShards); err != nil { return err @@ -631,11 +647,6 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string } } - // Update srvKeyspace now - if err = wr.ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_MASTER, nil); err != nil { - return err - } - event.DispatchUpdate(ev, "finished") return nil } From de49d79051e13080ff3048bdafc4bb910cbefbdb Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 15 Feb 2019 18:34:49 -0800 Subject: [PATCH 078/196] Revert change to test now that underlying fix have been solved Signed-off-by: Rafael Chacon --- test/initial_sharding.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/test/initial_sharding.py b/test/initial_sharding.py index 62a210ca5a1..cb4fb3428b7 100755 --- a/test/initial_sharding.py +++ b/test/initial_sharding.py @@ -631,12 +631,11 @@ def test_resharding(self): utils.run_vtctl(['DeleteTablet', '-allow_master', shard_master.tablet_alias], auto_log=True) - # delete the original shard - utils.run_vtctl(['DeleteShard', 'test_keyspace/0'], auto_log=True) - # rebuild the serving graph, all mentions of the old shards shoud be gone utils.run_vtctl(['RebuildKeyspaceGraph', 'test_keyspace'], auto_log=True) + # delete the original shard + utils.run_vtctl(['DeleteShard', 'test_keyspace/0'], auto_log=True) # kill everything else tablet.kill_tablets([shard_0_master, shard_0_replica, shard_0_rdonly1, From 577ca974413004c009047ec22497ff145f6bc2f5 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Sun, 3 Feb 2019 21:25:22 -0800 Subject: [PATCH 079/196] vplayer: move query generation to TablePlan Signed-off-by: Sugu Sougoumarane --- .../tabletmanager/vreplication/player_plan.go | 206 ++++++++++++++++-- .../tabletmanager/vreplication/vplayer.go | 167 +------------- 2 files changed, 189 insertions(+), 184 deletions(-) diff --git a/go/vt/vttablet/tabletmanager/vreplication/player_plan.go b/go/vt/vttablet/tabletmanager/vreplication/player_plan.go index 77ecde44d5d..cc3ba11e5f7 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/player_plan.go +++ b/go/vt/vttablet/tabletmanager/vreplication/player_plan.go @@ -20,6 +20,7 @@ import ( "fmt" "strings" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/sqlparser" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" @@ -37,7 +38,7 @@ type PlayerPlan struct { // while analyzing the inital stream request. A tentative plan is built // without knowing the table info. The second incarnation is built when // we receive the field info for a table. At that time, we copy the -// original TablePlan into a separtae map and populate the Fields and +// original TablePlan into a separate map and populate the Fields and // PKCols members. type TablePlan struct { Name string @@ -48,15 +49,6 @@ type TablePlan struct { PKCols []*ColExpr `json:",omitempty"` } -func (tp *TablePlan) findCol(name sqlparser.ColIdent) *ColExpr { - for _, cExpr := range tp.ColExprs { - if cExpr.ColName.Equal(name) { - return cExpr - } - } - return nil -} - // ColExpr describes the processing to be performed to // compute the value of the target table column. type ColExpr struct { @@ -98,12 +90,12 @@ func buildPlayerPlan(filter *binlogdatapb.Filter) (*PlayerPlan, error) { plan.VStreamFilter.Rules[i] = rule continue } - sendRule, tplan, err := buildTablePlan(rule) + sendRule, tp, err := buildTablePlan(rule) if err != nil { return nil, err } plan.VStreamFilter.Rules[i] = sendRule - plan.TablePlans[sendRule.Match] = tplan + plan.TablePlans[sendRule.Match] = tp } return plan, nil } @@ -143,7 +135,7 @@ func buildTablePlan(rule *binlogdatapb.Rule) (*binlogdatapb.Rule, *TablePlan, er return sendRule, &TablePlan{Name: rule.Match}, nil } - tplan := &TablePlan{ + tp := &TablePlan{ Name: rule.Match, } sendSelect := &sqlparser.Select{ @@ -159,17 +151,17 @@ func buildTablePlan(rule *binlogdatapb.Rule) (*binlogdatapb.Rule, *TablePlan, er sendSelect.SelectExprs = append(sendSelect.SelectExprs, selExpr) cExpr.ColNum = len(sendSelect.SelectExprs) - 1 } - tplan.ColExprs = append(tplan.ColExprs, cExpr) + tp.ColExprs = append(tp.ColExprs, cExpr) } if sel.GroupBy != nil { - if err := analyzeGroupBy(sel.GroupBy, tplan); err != nil { + if err := analyzeGroupBy(sel.GroupBy, tp); err != nil { return nil, nil, err } - tplan.OnInsert = InsertIgnore - for _, cExpr := range tplan.ColExprs { + tp.OnInsert = InsertIgnore + for _, cExpr := range tp.ColExprs { if !cExpr.IsGrouped { - tplan.OnInsert = InsertOndup + tp.OnInsert = InsertOndup break } } @@ -178,7 +170,7 @@ func buildTablePlan(rule *binlogdatapb.Rule) (*binlogdatapb.Rule, *TablePlan, er Match: fromTable.String(), Filter: sqlparser.String(sendSelect), } - return sendRule, tplan, nil + return sendRule, tp, nil } func analyzeExpr(selExpr sqlparser.SelectExpr) (sqlparser.SelectExpr, *ColExpr, error) { @@ -226,13 +218,13 @@ func analyzeExpr(selExpr sqlparser.SelectExpr) (sqlparser.SelectExpr, *ColExpr, } } -func analyzeGroupBy(groupBy sqlparser.GroupBy, tplan *TablePlan) error { +func analyzeGroupBy(groupBy sqlparser.GroupBy, tp *TablePlan) error { for _, expr := range groupBy { colname, ok := expr.(*sqlparser.ColName) if !ok { return fmt.Errorf("unexpected: %v", sqlparser.String(expr)) } - cExpr := tplan.findCol(colname.Name) + cExpr := tp.FindCol(colname.Name) if cExpr == nil { return fmt.Errorf("group by expression does not reference an alias in the select list: %v", sqlparser.String(expr)) } @@ -243,3 +235,175 @@ func analyzeGroupBy(groupBy sqlparser.GroupBy, tplan *TablePlan) error { } return nil } + +//-------------------------------------------------------------- +// TablePlan support functions. + +// FindCol finds the ColExpr. It returns nil if not found. +func (tp *TablePlan) FindCol(name sqlparser.ColIdent) *ColExpr { + for _, cExpr := range tp.ColExprs { + if cExpr.ColName.Equal(name) { + return cExpr + } + } + return nil +} + +// GenerateStatement must be called only after Fields and PKCols have been populated. +func (tp *TablePlan) GenerateStatement(rowChange *binlogdatapb.RowChange) string { + // MakeRowTrusted is needed here because because Proto3ToResult is not convenient. + var before, after []sqltypes.Value + if rowChange.Before != nil { + before = sqltypes.MakeRowTrusted(tp.Fields, rowChange.Before) + } + if rowChange.After != nil { + after = sqltypes.MakeRowTrusted(tp.Fields, rowChange.After) + } + var query string + switch { + case before == nil && after != nil: + query = tp.generateInsert(after) + case before != nil && after != nil: + query = tp.generateUpdate(before, after) + case before != nil && after == nil: + query = tp.generateDelete(before) + case before == nil && after == nil: + // unreachable + } + return query +} + +func (tp *TablePlan) generateInsert(after []sqltypes.Value) string { + sql := sqlparser.NewTrackedBuffer(nil) + if tp.OnInsert == InsertIgnore { + sql.Myprintf("insert ignore into %v set ", sqlparser.NewTableIdent(tp.Name)) + } else { + sql.Myprintf("insert into %v set ", sqlparser.NewTableIdent(tp.Name)) + } + tp.generateInsertValues(sql, after) + if tp.OnInsert == InsertOndup { + sql.Myprintf(" on duplicate key update ") + _ = tp.generateUpdateValues(sql, nil, after) + } + return sql.String() +} + +func (tp *TablePlan) generateUpdate(before, after []sqltypes.Value) string { + if tp.OnInsert == InsertIgnore { + return tp.generateInsert(after) + } + sql := sqlparser.NewTrackedBuffer(nil) + sql.Myprintf("update %v set ", sqlparser.NewTableIdent(tp.Name)) + if ok := tp.generateUpdateValues(sql, before, after); !ok { + return "" + } + sql.Myprintf(" where ") + tp.generateWhereValues(sql, before) + return sql.String() +} + +func (tp *TablePlan) generateDelete(before []sqltypes.Value) string { + sql := sqlparser.NewTrackedBuffer(nil) + switch tp.OnInsert { + case InsertOndup: + return tp.generateUpdate(before, nil) + case InsertIgnore: + return "" + default: // insertNormal + sql.Myprintf("delete from %v where ", sqlparser.NewTableIdent(tp.Name)) + tp.generateWhereValues(sql, before) + } + return sql.String() +} + +func (tp *TablePlan) generateInsertValues(sql *sqlparser.TrackedBuffer, after []sqltypes.Value) { + separator := "" + for _, cExpr := range tp.ColExprs { + sql.Myprintf("%s%v=", separator, cExpr.ColName) + separator = ", " + if cExpr.Operation == OpCount { + sql.WriteString("1") + } else { + if cExpr.Operation == OpSum && after[cExpr.ColNum].IsNull() { + sql.WriteString("0") + } else { + encodeValue(sql, after[cExpr.ColNum]) + } + } + } +} + +// generateUpdateValues returns true if at least one value was set. Otherwise, it returns false. +func (tp *TablePlan) generateUpdateValues(sql *sqlparser.TrackedBuffer, before, after []sqltypes.Value) bool { + separator := "" + hasSet := false + for _, cExpr := range tp.ColExprs { + if cExpr.IsGrouped { + continue + } + if len(before) != 0 && len(after) != 0 { + if cExpr.Operation == OpCount { + continue + } + bef := before[cExpr.ColNum] + aft := after[cExpr.ColNum] + // If both are null, there's no change + if bef.IsNull() && aft.IsNull() { + continue + } + // If any one of them is null, something has changed. + if bef.IsNull() || aft.IsNull() { + goto mustSet + } + // Compare content only if none are null. + if bef.ToString() == aft.ToString() { + continue + } + } + mustSet: + sql.Myprintf("%s%v=", separator, cExpr.ColName) + separator = ", " + hasSet = true + if cExpr.Operation == OpCount || cExpr.Operation == OpSum { + sql.Myprintf("%v", cExpr.ColName) + } + if len(before) != 0 { + switch cExpr.Operation { + case OpNone: + if len(after) == 0 { + sql.WriteString("NULL") + } + case OpCount: + sql.WriteString("-1") + case OpSum: + if !before[cExpr.ColNum].IsNull() { + sql.WriteString("-") + encodeValue(sql, before[cExpr.ColNum]) + } + } + } + if len(after) != 0 { + switch cExpr.Operation { + case OpNone: + encodeValue(sql, after[cExpr.ColNum]) + case OpCount: + sql.WriteString("+1") + case OpSum: + if !after[cExpr.ColNum].IsNull() { + sql.WriteString("+") + encodeValue(sql, after[cExpr.ColNum]) + } + } + } + } + return hasSet +} + +func (tp *TablePlan) generateWhereValues(sql *sqlparser.TrackedBuffer, before []sqltypes.Value) { + separator := "" + for _, cExpr := range tp.PKCols { + sql.Myprintf("%s%v=", separator, cExpr.ColName) + separator = " and " + encodeValue(sql, before[cExpr.ColNum]) + } +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index 1add35a937c..84ce8e3df88 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -426,172 +426,13 @@ func (vp *vplayer) applyRowEvent(ctx context.Context, rowEvent *binlogdatapb.Row return fmt.Errorf("unexpected event on table %s", rowEvent.TableName) } for _, change := range rowEvent.RowChanges { - if err := vp.applyRowChange(ctx, tplan, change); err != nil { - return err - } - } - return nil -} - -func (vp *vplayer) applyRowChange(ctx context.Context, tplan *TablePlan, rowChange *binlogdatapb.RowChange) error { - // MakeRowTrusted is needed here because because Proto3ToResult is not convenient. - var before, after []sqltypes.Value - if rowChange.Before != nil { - before = sqltypes.MakeRowTrusted(tplan.Fields, rowChange.Before) - } - if rowChange.After != nil { - after = sqltypes.MakeRowTrusted(tplan.Fields, rowChange.After) - } - var query string - switch { - case before == nil && after != nil: - query = vp.generateInsert(tplan, after) - case before != nil && after != nil: - query = vp.generateUpdate(tplan, before, after) - case before != nil && after == nil: - query = vp.generateDelete(tplan, before) - case before == nil && after == nil: - // unreachable - } - if query == "" { - return nil - } - return vp.exec(ctx, query) -} - -func (vp *vplayer) generateInsert(tplan *TablePlan, after []sqltypes.Value) string { - sql := sqlparser.NewTrackedBuffer(nil) - if tplan.OnInsert == InsertIgnore { - sql.Myprintf("insert ignore into %v set ", sqlparser.NewTableIdent(tplan.Name)) - } else { - sql.Myprintf("insert into %v set ", sqlparser.NewTableIdent(tplan.Name)) - } - vp.writeInsertValues(sql, tplan, after) - if tplan.OnInsert == InsertOndup { - sql.Myprintf(" on duplicate key update ") - _ = vp.writeUpdateValues(sql, tplan, nil, after) - } - return sql.String() -} - -func (vp *vplayer) generateUpdate(tplan *TablePlan, before, after []sqltypes.Value) string { - if tplan.OnInsert == InsertIgnore { - return vp.generateInsert(tplan, after) - } - sql := sqlparser.NewTrackedBuffer(nil) - sql.Myprintf("update %v set ", sqlparser.NewTableIdent(tplan.Name)) - if ok := vp.writeUpdateValues(sql, tplan, before, after); !ok { - return "" - } - sql.Myprintf(" where ") - vp.writeWhereValues(sql, tplan, before) - return sql.String() -} - -func (vp *vplayer) generateDelete(tplan *TablePlan, before []sqltypes.Value) string { - sql := sqlparser.NewTrackedBuffer(nil) - switch tplan.OnInsert { - case InsertOndup: - return vp.generateUpdate(tplan, before, nil) - case InsertIgnore: - return "" - default: // insertNormal - sql.Myprintf("delete from %v where ", sqlparser.NewTableIdent(tplan.Name)) - vp.writeWhereValues(sql, tplan, before) - } - return sql.String() -} - -func (vp *vplayer) writeInsertValues(sql *sqlparser.TrackedBuffer, tplan *TablePlan, after []sqltypes.Value) { - separator := "" - for _, cExpr := range tplan.ColExprs { - sql.Myprintf("%s%v=", separator, cExpr.ColName) - separator = ", " - if cExpr.Operation == OpCount { - sql.WriteString("1") - } else { - if cExpr.Operation == OpSum && after[cExpr.ColNum].IsNull() { - sql.WriteString("0") - } else { - encodeValue(sql, after[cExpr.ColNum]) - } - } - } -} - -// writeUpdateValues returns true if at least one value was set. Otherwise, it returns false. -func (vp *vplayer) writeUpdateValues(sql *sqlparser.TrackedBuffer, tplan *TablePlan, before, after []sqltypes.Value) bool { - separator := "" - hasSet := false - for _, cExpr := range tplan.ColExprs { - if cExpr.IsGrouped { - continue - } - if len(before) != 0 && len(after) != 0 { - if cExpr.Operation == OpCount { - continue - } - bef := before[cExpr.ColNum] - aft := after[cExpr.ColNum] - // If both are null, there's no change - if bef.IsNull() && aft.IsNull() { - continue - } - // If any one of them is null, something has changed. - if bef.IsNull() || aft.IsNull() { - goto mustSet - } - // Compare content only if none are null. - if bef.ToString() == aft.ToString() { - continue - } - } - mustSet: - sql.Myprintf("%s%v=", separator, cExpr.ColName) - separator = ", " - hasSet = true - if cExpr.Operation == OpCount || cExpr.Operation == OpSum { - sql.Myprintf("%v", cExpr.ColName) - } - if len(before) != 0 { - switch cExpr.Operation { - case OpNone: - if len(after) == 0 { - sql.WriteString("NULL") - } - case OpCount: - sql.WriteString("-1") - case OpSum: - if !before[cExpr.ColNum].IsNull() { - sql.WriteString("-") - encodeValue(sql, before[cExpr.ColNum]) - } - } - } - if len(after) != 0 { - switch cExpr.Operation { - case OpNone: - encodeValue(sql, after[cExpr.ColNum]) - case OpCount: - sql.WriteString("+1") - case OpSum: - if !after[cExpr.ColNum].IsNull() { - sql.WriteString("+") - encodeValue(sql, after[cExpr.ColNum]) - } + if query := tplan.GenerateStatement(change); query != "" { + if err := vp.exec(ctx, query); err != nil { + return err } } } - return hasSet -} - -func (vp *vplayer) writeWhereValues(sql *sqlparser.TrackedBuffer, tplan *TablePlan, before []sqltypes.Value) { - separator := "" - for _, cExpr := range tplan.PKCols { - sql.Myprintf("%s%v=", separator, cExpr.ColName) - separator = " and " - encodeValue(sql, before[cExpr.ColNum]) - } + return nil } func (vp *vplayer) updatePos(ts int64) error { From ccb28139663a9d8bbd560f5e977e91dccfdefce9 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Sun, 3 Feb 2019 22:16:03 -0800 Subject: [PATCH 080/196] vplayer: add stats tracking Signed-off-by: Sugu Sougoumarane --- .../vreplication/retryable_client.go | 84 ---------------- .../tabletmanager/vreplication/vdbclient.go | 99 +++++++++++++++++++ .../tabletmanager/vreplication/vplayer.go | 8 +- 3 files changed, 105 insertions(+), 86 deletions(-) delete mode 100644 go/vt/vttablet/tabletmanager/vreplication/retryable_client.go create mode 100644 go/vt/vttablet/tabletmanager/vreplication/vdbclient.go diff --git a/go/vt/vttablet/tabletmanager/vreplication/retryable_client.go b/go/vt/vttablet/tabletmanager/vreplication/retryable_client.go deleted file mode 100644 index f5e8eaa4efc..00000000000 --- a/go/vt/vttablet/tabletmanager/vreplication/retryable_client.go +++ /dev/null @@ -1,84 +0,0 @@ -/* -Copyright 2019 The Vitess 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 vreplication - -import ( - "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/vt/binlog/binlogplayer" -) - -// retryableClient is a wrapper on binlogplayer.DBClient. -// It allows us to retry a failed transactions on lock errors. -type retryableClient struct { - binlogplayer.DBClient - InTransaction bool - queries []string -} - -func (rt *retryableClient) Begin() error { - if rt.InTransaction { - return nil - } - if err := rt.DBClient.Begin(); err != nil { - return err - } - rt.queries = append(rt.queries, "begin") - rt.InTransaction = true - return nil -} - -func (rt *retryableClient) Commit() error { - if err := rt.DBClient.Commit(); err != nil { - return err - } - rt.InTransaction = false - rt.queries = nil - return nil -} - -func (rt *retryableClient) Rollback() error { - if err := rt.DBClient.Rollback(); err != nil { - return err - } - rt.InTransaction = false - // Don't reset queries to allow for vplayer to retry. - return nil -} - -func (rt *retryableClient) ExecuteFetch(query string, maxrows int) (*sqltypes.Result, error) { - if !rt.InTransaction { - rt.queries = []string{query} - } else { - rt.queries = append(rt.queries, query) - } - return rt.DBClient.ExecuteFetch(query, maxrows) -} - -func (rt *retryableClient) Retry() error { - for _, q := range rt.queries { - if q == "begin" { - if err := rt.Begin(); err != nil { - return err - } - continue - } - if _, err := rt.DBClient.ExecuteFetch(q, 10000); err != nil { - return err - } - } - return nil -} diff --git a/go/vt/vttablet/tabletmanager/vreplication/vdbclient.go b/go/vt/vttablet/tabletmanager/vreplication/vdbclient.go new file mode 100644 index 00000000000..dcfa3220df6 --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/vdbclient.go @@ -0,0 +1,99 @@ +/* +Copyright 2019 The Vitess 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 vreplication + +import ( + "time" + + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/binlog/binlogplayer" +) + +// vdbClient is a wrapper on binlogplayer.DBClient. +// It allows us to retry a failed transactions on lock errors. +type vdbClient struct { + binlogplayer.DBClient + stats *binlogplayer.Stats + InTransaction bool + startTime time.Time + queries []string +} + +func newVDBClient(dbclient binlogplayer.DBClient, stats *binlogplayer.Stats) *vdbClient { + return &vdbClient{ + DBClient: dbclient, + stats: stats, + } +} + +func (vc *vdbClient) Begin() error { + if vc.InTransaction { + return nil + } + if err := vc.DBClient.Begin(); err != nil { + return err + } + vc.queries = append(vc.queries, "begin") + vc.InTransaction = true + vc.startTime = time.Now() + return nil +} + +func (vc *vdbClient) Commit() error { + if err := vc.DBClient.Commit(); err != nil { + return err + } + vc.InTransaction = false + vc.queries = nil + vc.stats.Timings.Record(binlogplayer.BlplTransaction, vc.startTime) + return nil +} + +func (vc *vdbClient) Rollback() error { + if err := vc.DBClient.Rollback(); err != nil { + return err + } + vc.InTransaction = false + // Don't reset queries to allow for vplayer to retry. + return nil +} + +func (vc *vdbClient) ExecuteFetch(query string, maxrows int) (*sqltypes.Result, error) { + defer vc.stats.Timings.Record(binlogplayer.BlplQuery, time.Now()) + + if !vc.InTransaction { + vc.queries = []string{query} + } else { + vc.queries = append(vc.queries, query) + } + return vc.DBClient.ExecuteFetch(query, maxrows) +} + +func (vc *vdbClient) Retry() error { + for _, q := range vc.queries { + if q == "begin" { + if err := vc.Begin(); err != nil { + return err + } + continue + } + if _, err := vc.DBClient.ExecuteFetch(q, 10000); err != nil { + return err + } + } + return nil +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index 84ce8e3df88..f8a0520d868 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -50,7 +50,7 @@ type vplayer struct { source *binlogdatapb.BinlogSource sourceTablet *topodatapb.Tablet stats *binlogplayer.Stats - dbClient *retryableClient + dbClient *vdbClient // mysqld is used to fetch the local schema. mysqld mysqlctl.MysqlDaemon @@ -76,7 +76,7 @@ func newVPlayer(id uint32, source *binlogdatapb.BinlogSource, sourceTablet *topo source: source, sourceTablet: sourceTablet, stats: stats, - dbClient: &retryableClient{DBClient: dbClient}, + dbClient: newVDBClient(dbClient, stats), mysqld: mysqld, timeLastSaved: time.Now(), tplans: make(map[string]*TablePlan), @@ -443,6 +443,10 @@ func (vp *vplayer) updatePos(ts int64) error { } vp.unsavedGTID = nil vp.timeLastSaved = time.Now() + vp.stats.SetLastPosition(vp.pos) + if ts != 0 { + vp.stats.SecondsBehindMaster.Set(vp.timeLastSaved.Unix() - ts) + } return nil } From e832f3f0026220fbae3faba52c50d603a9db01e0 Mon Sep 17 00:00:00 2001 From: huynq0911 Date: Sat, 16 Feb 2019 12:20:01 +0700 Subject: [PATCH 081/196] Update deprecated links Update deprecated links in TwoPhaseCommitDesign.md Signed-off-by: huynq0911 --- doc/TwoPhaseCommitDesign.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/TwoPhaseCommitDesign.md b/doc/TwoPhaseCommitDesign.md index 312a031f2d7..a79099ab3a1 100644 --- a/doc/TwoPhaseCommitDesign.md +++ b/doc/TwoPhaseCommitDesign.md @@ -19,7 +19,11 @@ This document intends to address the above concerns with some practical trade-of Although MySQL supports the XA protocol, it’s been unusable due to bugs. Version 5.7 claims to have fixed them all, but the more common versions in use are 5.6 and below, and we need to make 2PC work for those versions also. Even at 5.7, we still have to contend with the chattiness of XA, and the fact that it’s unused code. +<<<<<<< Updated upstream The most critical component of the 2PC protocol is the ‘Prepare’ functionality. There is actually a way to implement Prepare on top of a transactional system. This is explained in a [Vitess Blog](http://blog.vitess.io/2016/06/distributed-transactions-in-vitess_7.html), which will be used as foundation for this design. +======= +The most critical component of the 2PC protocol is the ‘Prepare’ functionality. There is actually a way to implement Prepare on top of a transactional system. This is explained in a [Vitess Blog](https://vitess.io/blog/2016-06-07-distributed-transactions-in-vitess/), which will be used as foundation for this design. +>>>>>>> Stashed changes Familiarity with the blog and the [2PC algorithm](http://c2.com/cgi/wiki?TwoPhaseCommit) are required to understand the rest of the document. @@ -32,7 +36,11 @@ Vitess will add a few variations to the traditional 2PC algorithm: * The Coordinator will be stateless and will orchestrate the work. VTGates are the perfect fit for this role. * One of the VTTablets will be designated as the Metadata Manager (MM). It will be used to store the metadata and perform the necessary state transitions. * If we designate one of the participant VTTablets to be the MM, then that database can avoid the prepare phase: If you assume there are N participants, the typical explanation says that you perform prepares from 1->N, and then commit from 1->N. If we instead went from 1->N for prepare, and N->1 for commit. Then the N’th database would perform a Prepare->Decide to commit->Commit. Instead, we execute the DML needed to transition the metadata state to ‘Decide to Commit’ as part of the app transaction, and commit it. If the commit fails, then it’s treated as the prepare having failed. If the commit succeeds, then it’s treated as all three operations having succeeded. +<<<<<<< Updated upstream * The Prepare functionality will be implemented as explained in the [blog](http://blog.vitess.io/2016/06/distributed-transactions-in-vitess_7.html). +======= +* The Prepare functionality will be implemented as explained in the [blog](https://vitess.io/blog/2016-06-07-distributed-transactions-in-vitess/). +>>>>>>> Stashed changes Combining the above changes allows us to keep the most common use case efficient: A transaction that affects only one database incurs no additional cost due to 2PC. @@ -146,7 +154,11 @@ The DTID will be generated by taking the VTID of the MM and prefixing it with th ## Prepare API +<<<<<<< Updated upstream The Prepare API will be provided by VTTablet, and will follow the guidelines of the [blog](http://blog.vitess.io/2016/06/distributed-transactions-in-vitess_7.html). It’s essentially three functions: Prepare, CommitPrepared and RollbackPrepared. +======= +The Prepare API will be provided by VTTablet, and will follow the guidelines of the [blog](https://vitess.io/blog/2016-06-07-distributed-transactions-in-vitess/). It’s essentially three functions: Prepare, CommitPrepared and RollbackPrepared. +>>>>>>> Stashed changes ### Statement list and state From 1898eba2df5936356b3b0d613b464392ddbd503f Mon Sep 17 00:00:00 2001 From: huynq0911 Date: Sat, 16 Feb 2019 10:35:47 +0700 Subject: [PATCH 082/196] Change http to https for security links For security, we should change http into https links. This PR also update deprecated links Signed-off-by: huynq0911 --- ADOPTERS.md | 24 +++++++++---------- CONTRIBUTING.md | 2 +- doc/Concepts.md | 2 +- doc/GettingStarted.md | 8 +++---- doc/GettingStartedKubernetes.md | 4 ++-- doc/Monitoring.md | 4 ++-- doc/ScalabilityPhilosophy.md | 2 +- doc/ScalingMySQL.md | 2 +- doc/SchemaSwap.md | 2 +- doc/TestingOnARamDisk.md | 2 +- doc/TopologyService.md | 2 +- doc/Upgrading.md | 4 ++-- doc/UserGuideIntroduction.md | 4 ++-- doc/V3HighLevelDesign.md | 2 +- doc/VitessOverview.md | 2 +- doc/VitessReplication.md | 2 +- doc/VtExplain.md | 2 +- doc/internal/Overview.md | 2 +- doc/internal/PublishWebsite.md | 2 +- doc/internal/ReleaseInstructions.md | 6 ++--- doc/meetups_notes/06-14-2018.md | 2 +- doc/vtctlReference.md | 2 +- docker/README.md | 4 ++-- examples/kubernetes/README.md | 6 ++--- go/README.md | 2 +- helm/README.md | 4 ++-- helm/vitess/README.md | 2 +- .../src/main/java/io/vitess/hadoop/README.md | 2 +- vitess.io/resources/presentations.md | 4 ++-- vitess.io/resources/roadmap.md | 2 +- vitess.io/terms/index.md | 2 +- web/vtctld2/README.md | 2 +- 32 files changed, 57 insertions(+), 57 deletions(-) diff --git a/ADOPTERS.md b/ADOPTERS.md index 11ee7b0efdf..c629ca5fccc 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -1,14 +1,14 @@ This is an alphabetical list of known adopters of Vitess. Some have already gone into production, and others are at various stages of testing. -* [YouTube](http://youtube.com) -* [Axon](http://axon.com) -* [BetterCloud](http://bettercloud.com) -* [FlipKart](http://flipkart.com) -* [HubSpot](http://product.hubspot.com/) -* [JD](http://jd.com/) -* [Nozzle](http://nozzle.io) -* [Pixel Federation](http://pixelfederation.com) -* [Quiz of Kings](http://quizofkings.com) -* [Slack](http://slack.com) -* [Square](http://square.com) -* [Stitch Labs](http://stitchlabs.com) +* [YouTube](https://youtube.com) +* [Axon](https://axon.com) +* [BetterCloud](https://bettercloud.com) +* [FlipKart](https://flipkart.com) +* [HubSpot](https://product.hubspot.com/) +* [JD](https://jd.com/) +* [Nozzle](https://nozzle.io) +* [Pixel Federation](https://pixelfederation.com) +* [Quiz of Kings](https://quizofkings.com) +* [Slack](https://slack.com) +* [Square](https://square.com) +* [Stitch Labs](https://stitchlabs.com) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 19a34df79ad..271010b8304 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ to let everyone know what you're planning to work on, and to track progress and ## Guidance for Novice Vitess Developers -**Please read [vitess.io/contributing/](http://vitess.io/contributing/)** where we provide more information: +**Please read [vitess.io/contributing/](https://vitess.io/contributing/)** where we provide more information: * How to make yourself familiar with Go and Vitess. * How to go through the GitHub workflow. diff --git a/doc/Concepts.md b/doc/Concepts.md index 6bcb36b92c2..acb87277522 100644 --- a/doc/Concepts.md +++ b/doc/Concepts.md @@ -3,7 +3,7 @@ This document defines common Vitess concepts and terminology. ## Keyspace A *keyspace* is a logical database. In the unsharded case, it maps directly -to a MySQL database name. If [sharded](http://en.wikipedia.org/wiki/Shard_(database_architecture)), +to a MySQL database name. If [sharded](https://en.wikipedia.org/wiki/Shard_(database_architecture)), a keyspace maps to multiple MySQL databases. However, it appears as a single database to the application. diff --git a/doc/GettingStarted.md b/doc/GettingStarted.md index 587156137a2..12737aca7af 100644 --- a/doc/GettingStarted.md +++ b/doc/GettingStarted.md @@ -73,10 +73,10 @@ OS X 10.11 (El Capitan) should work as well, the installation instructions are b In addition, Vitess requires the software and libraries listed below. -1. [Install Go 1.11+](http://golang.org/doc/install). +1. [Install Go 1.11+](https://golang.org/doc/install). 2. Install [MariaDB 10.0](https://downloads.mariadb.org/) or - [MySQL 5.6](http://dev.mysql.com/downloads/mysql). You can use any + [MySQL 5.6](https://dev.mysql.com/downloads/mysql). You can use any installation method (src/bin/rpm/deb), but be sure to include the client development headers (`libmariadbclient-dev` or `libmysqlclient-dev`). @@ -155,7 +155,7 @@ In addition, Vitess requires the software and libraries listed below. #### OS X -1. [Install Homebrew](http://brew.sh/). If your /usr/local directory is not empty and you never used Homebrew before, +1. [Install Homebrew](https://brew.sh/). If your /usr/local directory is not empty and you never used Homebrew before, it will be [mandatory](https://github.com/Homebrew/homebrew/blob/master/share/doc/homebrew/El_Capitan_and_Homebrew.md) to run the following command: @@ -365,7 +365,7 @@ lock service. ZooKeeper is included in the Vitess distribution. Check the system-wide `file-max` setting as well as user-specific `ulimit` values. We recommend setting them above 100K to be safe. - The exact [procedure](http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/) + The exact [procedure](https://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/) may vary depending on your Linux distribution. 1. **Configure environment variables** diff --git a/doc/GettingStartedKubernetes.md b/doc/GettingStartedKubernetes.md index cc1f763cab8..9c1c2550327 100644 --- a/doc/GettingStartedKubernetes.md +++ b/doc/GettingStartedKubernetes.md @@ -19,7 +19,7 @@ The following sections explain how to set these up in your environment. ### Install Go 1.11+ -You need to install [Go 1.11+](http://golang.org/doc/install) to build the +You need to install [Go 1.11+](https://golang.org/doc/install) to build the `vtctlclient` tool, which issues commands to Vitess. After installing Go, make sure your `GOPATH` environment @@ -30,7 +30,7 @@ directory to which your non-root user has write access. In addition, make sure that `$GOPATH/bin` is included in your `$PATH`. More information about setting up a Go workspace can be found at -[How to Write Go Code](http://golang.org/doc/code.html#Organization). +[How to Write Go Code](https://golang.org/doc/code.html#Organization). ### Build and install vtctlclient diff --git a/doc/Monitoring.md b/doc/Monitoring.md index 3864ea87266..aa1a163d17a 100644 --- a/doc/Monitoring.md +++ b/doc/Monitoring.md @@ -14,7 +14,7 @@ Viewing a status page can be useful since it works out of the box, but it only p ### 2. Pull-based metrics system -Vitess uses Go’s [expvar package](http://golang.org/pkg/expvar/) to expose various metrics, with the expectation that a user can configure a pull-based metrics system to ingest those metrics. Metrics are published to `http://:/debug/vars` as JSON key-value pairs, which should be easy for any metrics system to parse. +Vitess uses Go’s [expvar package](https://golang.org/pkg/expvar/) to expose various metrics, with the expectation that a user can configure a pull-based metrics system to ingest those metrics. Metrics are published to `http://:/debug/vars` as JSON key-value pairs, which should be easy for any metrics system to parse. Scraping Vitess variables is a good way to integrate Vitess into an existing monitoring system, and is useful for building up detailed monitoring dashboards. It is also the officially supported way for monitoring Vitess. @@ -32,7 +32,7 @@ Once you’ve written the backend plug-in, you also need to register the plug-in You can then specify that Vitess should publish stats to the backend that you’re targeting by using the `--stats_backend` flag. -Connecting Vitess to a push-based metrics system can be useful if you’re already running a push-based system that you would like to integrate into. More discussion on using a push vs pull based monitoring system can be seen here: [http://www.boxever.com/push-vs-pull-for-monitoring](http://www.boxever.com/push-vs-pull-for-monitoring) +Connecting Vitess to a push-based metrics system can be useful if you’re already running a push-based system that you would like to integrate into. More discussion on using a push vs pull based monitoring system can be seen here: [http://www.boxever.com/push-vs-pull-for-monitoring](https://www.boxever.com/push-vs-pull-for-monitoring) ## Monitoring with Kubernetes diff --git a/doc/ScalabilityPhilosophy.md b/doc/ScalabilityPhilosophy.md index f709a416e48..20a5f0caf7d 100644 --- a/doc/ScalabilityPhilosophy.md +++ b/doc/ScalabilityPhilosophy.md @@ -16,7 +16,7 @@ the assignment of servers and ports is abstracted away from the administrator. On baremetal, the operator still has these responsibilities. We provide sample configs to help you [get started on Kubernetes](/getting-started/) -since it's the most similar to Borg (the [predecessor to Kubernetes](http://blog.kubernetes.io/2015/04/borg-predecessor-to-kubernetes.html) +since it's the most similar to Borg (the [predecessor to Kubernetes](https://blog.kubernetes.io/2015/04/borg-predecessor-to-kubernetes.html) on which Vitess now runs in YouTube). If you're more familiar with alternatives like Mesos, Swarm, Nomad, or DC/OS, we'd welcome your contribution of sample configs for Vitess. diff --git a/doc/ScalingMySQL.md b/doc/ScalingMySQL.md index 45b2544388b..deef192c8b3 100644 --- a/doc/ScalingMySQL.md +++ b/doc/ScalingMySQL.md @@ -70,7 +70,7 @@ Setting up these components directly -- for example, writing your own topology s Obviously, your application needs to be able to call your database. So, we'll jump straight to explaining how you'd modify your application to connect to your database through vtgate. -As of Release 2.1, VTGate supports the MySQL protocol. So, the application only needs to change where it connects to. For those using Java or Go, we additionally provide libraries that can communicate to VTGate using [gRPC](http://www.grpc.io/). Using the provided libraries allow you to send queries with bind variables, which is not inherently possible through the MySQL protocol. +As of Release 2.1, VTGate supports the MySQL protocol. So, the application only needs to change where it connects to. For those using Java or Go, we additionally provide libraries that can communicate to VTGate using [gRPC](https://www.grpc.io/). Using the provided libraries allow you to send queries with bind variables, which is not inherently possible through the MySQL protocol. #### Unit testing database interactions diff --git a/doc/SchemaSwap.md b/doc/SchemaSwap.md index 5dc24f0957a..a893761464d 100644 --- a/doc/SchemaSwap.md +++ b/doc/SchemaSwap.md @@ -13,7 +13,7 @@ ApplySchema]({% link user-guide/schema-management.md %}) instead. One solution to realize such long-running schema changes is to use a temporary table and keep it in sync with triggers as [originally proposed by -Shlomi](http://code.openark.org/blog/mysql/online-alter-table-now-available-in-openark-kit) +Shlomi](https://code.openark.org/blog/mysql/online-alter-table-now-available-in-openark-kit) and further refined by others ([Percona's pt-online-schema-change](https://www.percona.com/doc/percona-toolkit/2.2/pt-online-schema-change.html), [Square's Shift](https://github.com/square/shift)). diff --git a/doc/TestingOnARamDisk.md b/doc/TestingOnARamDisk.md index f768fe6ec8e..1adb82cf273 100644 --- a/doc/TestingOnARamDisk.md +++ b/doc/TestingOnARamDisk.md @@ -1,6 +1,6 @@ # Testing On A Ramdisk -The `integration_test` testsuite contains tests that may time-out if run against a slow disk. If your workspace lives on hard disk (as opposed to [SSD](http://en.wikipedia.org/wiki/Solid-state_drive)), it is recommended that you run tests using a [ramdisk](http://en.wikipedia.org/wiki/RAM_drive). +The `integration_test` testsuite contains tests that may time-out if run against a slow disk. If your workspace lives on hard disk (as opposed to [SSD](https://en.wikipedia.org/wiki/Solid-state_drive)), it is recommended that you run tests using a [ramdisk](https://en.wikipedia.org/wiki/RAM_drive). # Setup diff --git a/doc/TopologyService.md b/doc/TopologyService.md index cb8a222131b..0cf4d7ecbfe 100644 --- a/doc/TopologyService.md +++ b/doc/TopologyService.md @@ -6,7 +6,7 @@ store small pieces of configuration data about the Vitess cluster, and provide cluster-wide locks. It also supports watches, and master election. Concretely, the Topology Service features are implemented by -a [Lock Server](http://en.wikipedia.org/wiki/Distributed_lock_manager), referred +a [Lock Server](https://en.wikipedia.org/wiki/Distributed_lock_manager), referred to as Topology Server in the rest of this document. We use a plug-in implementation and we support multiple Lock Servers (Zookeeper, etcd, Consul, …) as backends for the service. diff --git a/doc/Upgrading.md b/doc/Upgrading.md index f9acb603760..04723da9ded 100644 --- a/doc/Upgrading.md +++ b/doc/Upgrading.md @@ -6,7 +6,7 @@ Generally speaking, upgrading Vitess is a safe and easy process because it is ex ## Compatibility -Our versioning strategy is based on [Semantic Versioning](http://semver.org/). +Our versioning strategy is based on [Semantic Versioning](https://semver.org/). Vitess version numbers follow the format `MAJOR.MINOR.PATCH`. We guarantee compatibility when upgrading to a newer **patch** or **minor** version. @@ -30,7 +30,7 @@ Please use this upgrade order (unless otherwise noted in the release notes): ## Canary Testing -Within the vtgate and vttablet components, we recommend to [canary](http://martinfowler.com/bliki/CanaryRelease.html) single instances, keyspaces and cells. Upgraded canary instances can "bake" for several hours or days to verify that the upgrade did not introduce a regression. Eventually, you can upgrade the remaining instances. +Within the vtgate and vttablet components, we recommend to [canary](https://martinfowler.com/bliki/CanaryRelease.html) single instances, keyspaces and cells. Upgraded canary instances can "bake" for several hours or days to verify that the upgrade did not introduce a regression. Eventually, you can upgrade the remaining instances. ## Rolling Upgrades diff --git a/doc/UserGuideIntroduction.md b/doc/UserGuideIntroduction.md index a72dded0c06..261abfa46ef 100644 --- a/doc/UserGuideIntroduction.md +++ b/doc/UserGuideIntroduction.md @@ -5,7 +5,7 @@ Other Linux distributions should work as well. ## Database support -Vitess supports [MySQL 5.6](http://dev.mysql.com/doc/refman/5.6/en/), +Vitess supports [MySQL 5.6](https://dev.mysql.com/doc/refman/5.6/en/), [MariaDB 10.0](https://downloads.mariadb.org/mariadb/10.0.21/), and any newer versions like MySQL 5.7, etc. Vitess also supports Percona's variations of these versions. @@ -56,7 +56,7 @@ VTGate understands the MySQL binary protocol. So, any client that can directly talk to MySQL can also use Vitess. Additionally, VTGate exposes its functionality through a -[gRPC](http://www.grpc.io/) API which has support for multiple languages. +[gRPC](https://www.grpc.io/) API which has support for multiple languages. Accessing Vitess through gRPC has some minor advantages over the MySQL protocol: diff --git a/doc/V3HighLevelDesign.md b/doc/V3HighLevelDesign.md index b599f7e89ba..ca6909716e0 100644 --- a/doc/V3HighLevelDesign.md +++ b/doc/V3HighLevelDesign.md @@ -301,7 +301,7 @@ You’ll see how these operands are used in the description of the operators. ## The operators -If one were to ask what are the minimal set of primitives needed to serve SQL queries, we can use [relational algebra](http://www.tutorialspoint.com/dbms/relational_algebra.htm) as starting point. But databases have extended beyond those basic operations. They allow duplicate tuples and ordering. So, here’s a more practical set: +If one were to ask what are the minimal set of primitives needed to serve SQL queries, we can use [relational algebra](https://www.tutorialspoint.com/dbms/relational_algebra.htm) as starting point. But databases have extended beyond those basic operations. They allow duplicate tuples and ordering. So, here’s a more practical set: 1. Scan (FROM). 2. Join: Join two results as cross-product (JOIN). diff --git a/doc/VitessOverview.md b/doc/VitessOverview.md index 9258e981623..dc66784b9da 100644 --- a/doc/VitessOverview.md +++ b/doc/VitessOverview.md @@ -127,7 +127,7 @@ The diagram below illustrates Vitess' components: The [Topology Service]({% link user-guide/topology-service.md %}) is a metadata store that contains information about running servers, the sharding scheme, and the replication graph. The topology is backed by a consistent data store. You can explore the topology using **vtctl** (command-line) and **vtctld** (web). -In Kubernetes, the data store is [etcd](https://github.com/coreos/etcd). Vitess source code also ships with [Apache ZooKeeper](http://zookeeper.apache.org/) support. +In Kubernetes, the data store is [etcd](https://github.com/coreos/etcd). Vitess source code also ships with [Apache ZooKeeper](https://zookeeper.apache.org/) support. ### vtgate diff --git a/doc/VitessReplication.md b/doc/VitessReplication.md index fe06568b0cb..7e7ad213c91 100644 --- a/doc/VitessReplication.md +++ b/doc/VitessReplication.md @@ -139,7 +139,7 @@ Thus, you can survive sudden master failure without losing any transactions that were reported to clients as completed. In MySQL 5.7+, this guarantee is strengthened slightly to preventing loss of any transactions that were ever **committed** on the original master, eliminating so-called -[phantom reads](http://bugs.mysql.com/bug.php?id=62174). +[phantom reads](https://bugs.mysql.com/bug.php?id=62174). On the other hand these behaviors also give a requirement that each shard must have at least 2 tablets with type *replica* (with addition of the master that diff --git a/doc/VtExplain.md b/doc/VtExplain.md index cb90924eb32..b6bec78f78a 100644 --- a/doc/VtExplain.md +++ b/doc/VtExplain.md @@ -5,7 +5,7 @@ The vtexplain tool provides information about how Vitess will execute a statemen ## Prerequisites You'll need to build the `vtexplain` binary in your environment. -To find instructions on how to build this binary please refer to this [guide](http://vitess.io/getting-started/local-instance.html#manual-build). +To find instructions on how to build this binary please refer to this [guide](https://vitess.io/getting-started/local-instance.html#manual-build). ## Explaining a Query diff --git a/doc/internal/Overview.md b/doc/internal/Overview.md index 130b147ada8..e1cb74e4ddd 100644 --- a/doc/internal/Overview.md +++ b/doc/internal/Overview.md @@ -1,5 +1,5 @@ # Internal Documentation -The documents in this category document internal processes which are taken care of by the Vitess Team e.g. re-publishing the website [vitess.io](http://vitess.io) or creating a new release. +The documents in this category document internal processes which are taken care of by the Vitess Team e.g. re-publishing the website [vitess.io](https://vitess.io) or creating a new release. We have put them here to increase transparency and make it easy for others to follow and improve processes. diff --git a/doc/internal/PublishWebsite.md b/doc/internal/PublishWebsite.md index 66ee9f3d5f9..9d36f1b7ba9 100644 --- a/doc/internal/PublishWebsite.md +++ b/doc/internal/PublishWebsite.md @@ -2,7 +2,7 @@ ## Overview -Our website [vitess.io](http://vitess.io) are static HTML pages which are +Our website [vitess.io](https://vitess.io) are static HTML pages which are generated by [Jekyll](https://github.com/jekyll/jekyll) from Markdown files located in the [`doc/`](https://github.com/vitessio/vitess/tree/master/doc) directory. diff --git a/doc/internal/ReleaseInstructions.md b/doc/internal/ReleaseInstructions.md index f44fa8c2c47..327ad442a91 100644 --- a/doc/internal/ReleaseInstructions.md +++ b/doc/internal/ReleaseInstructions.md @@ -5,7 +5,7 @@ This page describes the steps for cutting a new [open source release] ## Versioning -Our versioning strategy is based on [Semantic Versioning](http://semver.org/). +Our versioning strategy is based on [Semantic Versioning](https://semver.org/). ### Major Release (vX) @@ -193,13 +193,13 @@ Therefore, file a JIRA ticket with Sonatype to get added ([example for a differe **Set up GPG** -Follow [Sonatype's GPG instructions](http://central.sonatype.org/pages/working-with-pgp-signatures.html). +Follow [Sonatype's GPG instructions](https://central.sonatype.org/pages/working-with-pgp-signatures.html). Install `gpg-agent` (needed below) e.g. on Ubuntu via: `sudo apt-get install gnupg-agent` **Login configuration** -Create the `settings.xml` in the `$HOME/.m2/` directory as described in their [instructions](http://central.sonatype.org/pages/apache-maven.html). +Create the `settings.xml` in the `$HOME/.m2/` directory as described in their [instructions](https://central.sonatype.org/pages/apache-maven.html). ### Deploy & Release diff --git a/doc/meetups_notes/06-14-2018.md b/doc/meetups_notes/06-14-2018.md index 0a3a2ba853e..67348fe2656 100644 --- a/doc/meetups_notes/06-14-2018.md +++ b/doc/meetups_notes/06-14-2018.md @@ -56,7 +56,7 @@ Meeting started at 8am PDT on Zoom. ### New Vitess Logo / Logo Changes -We kicked off the meeting talking about the first agenda item, *Vitess's new logo*. The new logo was mooted in the first place because of its current similarites to [Vivid IT Corp](http://www.vividitcorp.com/). +We kicked off the meeting talking about the first agenda item, *Vitess's new logo*. The new logo was mooted in the first place because of its current similarites to [Vivid IT Corp](https://www.vividitcorp.com/). Based on [logos](https://docs.google.com/forms/d/e/1FAIpQLScp5hGY98vpRMxs3oRT8c-XJ_b04ei6uCFiYiQe3nDunFbyuw/viewform) created with CNCF's help, logos 1 and 4 got the highest no of votes. diff --git a/doc/vtctlReference.md b/doc/vtctlReference.md index cb946962586..75e14860f5c 100644 --- a/doc/vtctlReference.md +++ b/doc/vtctlReference.md @@ -2343,7 +2343,7 @@ Blocks the action queue on the specified tablet for the specified amount of time #### Arguments * <tablet alias> – Required. A Tablet Alias uniquely identifies a vttablet. The argument value is in the format <cell name>-<uid>. -* <duration> – Required. The amount of time that the action queue should be blocked. The value is a string that contains a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms" or "1h45m". See the definition of the Go language's ParseDuration function for more details. Note that, in practice, the value should be a positively signed value. +* <duration> – Required. The amount of time that the action queue should be blocked. The value is a string that contains a possibly signed sequence of decimal numbers, each with optional fraction and a unit suffix, such as "300ms" or "1h45m". See the definition of the Go language's ParseDuration function for more details. Note that, in practice, the value should be a positively signed value. #### Errors diff --git a/docker/README.md b/docker/README.md index 1e5edfc923a..0b0e47d19fe 100644 --- a/docker/README.md +++ b/docker/README.md @@ -39,7 +39,7 @@ All these Vitess images include a specific MySQL/MariaDB version ("flavor"). * We provide Dockerfile files for multiple flavors (`Dockerfile.`). * As of April 2017, the following flavors are supported: `mariadb`, `mysql56`, `mysql57`, `percona`(56), `percona57` * On Docker Hub we publish only images with MySQL 5.7 to minimize maintenance overhead and avoid confusion. - * If you need an image for a different flavor, it is very easy to build it yourself. See the [Custom Docker Build instructions](http://vitess.io/getting-started/docker-build/). + * If you need an image for a different flavor, it is very easy to build it yourself. See the [Custom Docker Build instructions](https://vitess.io/getting-started/docker-build/). If you are looking for a stable version of Vitess, use the **lite** image with a fixed version. If you are looking for the latest Vitess code in binary form, use the "latest" tag of the **base** image. @@ -56,5 +56,5 @@ These images are used by the Vitess project for internal workflows and testing i | Image | How (When) Updated | Description | | --- | --- | --- | -| **publish-site** | manual | Contains [Jekyll](https://jekyllrb.com/) which we use to generate our [vitess.io](http://vitess.io) website from the Markdown files located in [doc/](https://github.com/vitessio/vitess/tree/master/doc). | +| **publish-site** | manual | Contains [Jekyll](https://jekyllrb.com/) which we use to generate our [vitess.io](https://vitess.io) website from the Markdown files located in [doc/](https://github.com/vitessio/vitess/tree/master/doc). | | **keytar** | manual | Keytar is a Vitess testing framework to run our Kubernetes cluster tests. Dockerfile is located in [`test/cluster/keytar/`](https://github.com/vitessio/vitess/tree/master/test/cluster/keytar). | diff --git a/examples/kubernetes/README.md b/examples/kubernetes/README.md index 559f9538072..cd142ac140c 100644 --- a/examples/kubernetes/README.md +++ b/examples/kubernetes/README.md @@ -1,8 +1,8 @@ # Vitess on Kubernetes This directory contains an example configuration for running Vitess on -[Kubernetes](http://kubernetes.io/). +[Kubernetes](https://kubernetes.io/). -See the [Vitess on Kubernetes](http://vitess.io/getting-started/) -and [Sharding in Kubernetes](http://vitess.io/user-guide/sharding-kubernetes/) +See the [Vitess on Kubernetes](https://vitess.io/getting-started/) +and [Sharding in Kubernetes](https://vitess.io/user-guide/sharding-kubernetes/) guides for instructions on using these files. diff --git a/go/README.md b/go/README.md index abb68292b7f..fc6efdde602 100644 --- a/go/README.md +++ b/go/README.md @@ -4,7 +4,7 @@ Most of the packages at the top level are general-purpose and are suitable for use outside Vitess. Packages that are specific to Vitess are in the *vt* subdirectory. Binaries are in the *cmd* subdirectory. -Please see [GoDoc](http://godoc.org/vitess.io/vitess/go) for +Please see [GoDoc](https://godoc.org/vitess.io/vitess/go) for a listing of the packages and their purposes. vt/proto contains the compiled protos for go, one per each directory. diff --git a/helm/README.md b/helm/README.md index 7bbe2cbe65b..1677ee0b637 100644 --- a/helm/README.md +++ b/helm/README.md @@ -1,8 +1,8 @@ # Helm Charts This directory contains [Helm](https://github.com/kubernetes/helm) -charts for running [Vitess](http://vitess.io) on -[Kubernetes](http://kubernetes.io). +charts for running [Vitess](https://vitess.io) on +[Kubernetes](https://kubernetes.io). Note that this is not in the `examples` directory because these are the sources for canonical packages that we plan to publish to the official diff --git a/helm/vitess/README.md b/helm/vitess/README.md index 4b8154ed531..481ad44be72 100644 --- a/helm/vitess/README.md +++ b/helm/vitess/README.md @@ -1,6 +1,6 @@ # Vitess -[Vitess](http://vitess.io) is a database clustering system for horizontal +[Vitess](https://vitess.io) is a database clustering system for horizontal scaling of MySQL. It is an open-source project started at YouTube, and has been used there since 2011. diff --git a/java/hadoop/src/main/java/io/vitess/hadoop/README.md b/java/hadoop/src/main/java/io/vitess/hadoop/README.md index 65334894384..fe88bdc650e 100644 --- a/java/hadoop/src/main/java/io/vitess/hadoop/README.md +++ b/java/hadoop/src/main/java/io/vitess/hadoop/README.md @@ -14,7 +14,7 @@ primary key (id)) Engine=InnoDB; Let's say we want to write a MapReduce job that imports this table from Vitess to HDFS where each row is turned into a CSV record in HDFS. -We can use [VitessInputFormat](https://github.com/vitessio/vitess/blob/master/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java), an implementation of Hadoop's [InputFormat](http://hadoop.apache.org/docs/stable/api/org/apache/hadoop/mapred/InputFormat.html), for that. With VitessInputFormat, rows from the source table are streamed to the mapper task. Each input record has a [NullWritable](https://hadoop.apache.org/docs/r2.2.0/api/org/apache/hadoop/io/NullWritable.html) key (no key, really), and [RowWritable](https://github.com/vitessio/vitess/blob/master/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java) as value, which is a writable implementation for the entire row's contents. +We can use [VitessInputFormat](https://github.com/vitessio/vitess/blob/master/java/hadoop/src/main/java/io/vitess/hadoop/VitessInputFormat.java), an implementation of Hadoop's [InputFormat](https://hadoop.apache.org/docs/stable/api/org/apache/hadoop/mapred/InputFormat.html), for that. With VitessInputFormat, rows from the source table are streamed to the mapper task. Each input record has a [NullWritable](https://hadoop.apache.org/docs/r2.2.0/api/org/apache/hadoop/io/NullWritable.html) key (no key, really), and [RowWritable](https://github.com/vitessio/vitess/blob/master/java/hadoop/src/main/java/io/vitess/hadoop/RowWritable.java) as value, which is a writable implementation for the entire row's contents. Here is an example implementation of our mapper, which transforms each row into a CSV Text. diff --git a/vitess.io/resources/presentations.md b/vitess.io/resources/presentations.md index 2c37d17ec70..c866d09e0bc 100644 --- a/vitess.io/resources/presentations.md +++ b/vitess.io/resources/presentations.md @@ -29,7 +29,7 @@ make all of this possible. ## CoreOS Meetup, January 2016 Vitess team member [Anthony Yeh](https://github.com/enisoc)'s talk at -the [January 2016 CoreOS Meetup](http://www.meetup.com/coreos/events/228233948/) +the [January 2016 CoreOS Meetup](https://www.meetup.com/coreos/events/228233948/) discussed challenges and techniques for running distributed databases within Kubernetes, followed by a deep dive into the design trade-offs of the [Vitess on Kubernetes](https://github.com/vitessio/vitess/tree/master/examples/kubernetes) @@ -42,7 +42,7 @@ deployment templates. Vitess team member [Anthony Yeh](https://github.com/enisoc)'s talk at Oracle OpenWorld 2015 focused on -what the [Cloud Native Computing](http://cncf.io) paradigm means when +what the [Cloud Native Computing](https://cncf.io) paradigm means when applied to MySQL in the cloud. The talk also included a deep dive into [transparent, live resharding] ({% link user-guide/sharding.md %}#resharding), one of the key diff --git a/vitess.io/resources/roadmap.md b/vitess.io/resources/roadmap.md index f3bd11c8fcd..7a9d679712f 100644 --- a/vitess.io/resources/roadmap.md +++ b/vitess.io/resources/roadmap.md @@ -83,7 +83,7 @@ following core features: `zk2` and `etcd2` implementations will remain, so please migrate after upgrade to Vitess 2.1. -* Added support for [Consul](http://consul.io) topology service client. +* Added support for [Consul](https://consul.io) topology service client. * Initial version of the Master Buffering feature. It allows for buffering master traffic while a failover is in progress, and trade downtime with diff --git a/vitess.io/terms/index.md b/vitess.io/terms/index.md index 33c473002f7..1c29f6813bc 100644 --- a/vitess.io/terms/index.md +++ b/vitess.io/terms/index.md @@ -34,7 +34,7 @@ All of this information is not linked to anything that is personally identifiabl ### Cookies and Web Beacons -When you visit this site "convenience" cookies are stored on your computer when you submit a comment to help you log in faster to [Disqus](http://disqus.com) the next time you leave a comment. +When you visit this site "convenience" cookies are stored on your computer when you submit a comment to help you log in faster to [Disqus](https://disqus.com) the next time you leave a comment. Third-party advertisers may also place and read cookies on your browser and/or use web beacons to collect information. This site has no access or control over these cookies. You should review the respective privacy policies on any and all third-party ad servers for more information regarding their practices and how to opt-out. diff --git a/web/vtctld2/README.md b/web/vtctld2/README.md index 9574678a475..a5fea7f2606 100644 --- a/web/vtctld2/README.md +++ b/web/vtctld2/README.md @@ -28,7 +28,7 @@ Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github. ## Running end-to-end tests -Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). +Run `ng e2e` to execute the end-to-end tests via [Protractor](https://www.protractortest.org/). Before running the tests make sure you are serving the app via `ng serve`. ## Deploying to Github Pages From 121c9672cd3bf6e2a1511e59eab915c5c549b332 Mon Sep 17 00:00:00 2001 From: huynq0911 Date: Sat, 16 Feb 2019 12:40:20 +0700 Subject: [PATCH 083/196] Update deprecated links Update deprecated links Signed-off-by: huynq0911 --- doc/ScalabilityPhilosophy.md | 2 +- doc/TwoPhaseCommitDesign.md | 12 ------------ doc/VtExplain.md | 2 +- examples/kubernetes/README.md | 4 +--- 4 files changed, 3 insertions(+), 17 deletions(-) diff --git a/doc/ScalabilityPhilosophy.md b/doc/ScalabilityPhilosophy.md index 20a5f0caf7d..d955bbbe01e 100644 --- a/doc/ScalabilityPhilosophy.md +++ b/doc/ScalabilityPhilosophy.md @@ -16,7 +16,7 @@ the assignment of servers and ports is abstracted away from the administrator. On baremetal, the operator still has these responsibilities. We provide sample configs to help you [get started on Kubernetes](/getting-started/) -since it's the most similar to Borg (the [predecessor to Kubernetes](https://blog.kubernetes.io/2015/04/borg-predecessor-to-kubernetes.html) +since it's the most similar to Borg (the [predecessor to Kubernetes](https://kubernetes.io/blog/2015/04/borg-predecessor-to-kubernetes/) on which Vitess now runs in YouTube). If you're more familiar with alternatives like Mesos, Swarm, Nomad, or DC/OS, we'd welcome your contribution of sample configs for Vitess. diff --git a/doc/TwoPhaseCommitDesign.md b/doc/TwoPhaseCommitDesign.md index a79099ab3a1..75bfc0a9b7a 100644 --- a/doc/TwoPhaseCommitDesign.md +++ b/doc/TwoPhaseCommitDesign.md @@ -19,11 +19,7 @@ This document intends to address the above concerns with some practical trade-of Although MySQL supports the XA protocol, it’s been unusable due to bugs. Version 5.7 claims to have fixed them all, but the more common versions in use are 5.6 and below, and we need to make 2PC work for those versions also. Even at 5.7, we still have to contend with the chattiness of XA, and the fact that it’s unused code. -<<<<<<< Updated upstream -The most critical component of the 2PC protocol is the ‘Prepare’ functionality. There is actually a way to implement Prepare on top of a transactional system. This is explained in a [Vitess Blog](http://blog.vitess.io/2016/06/distributed-transactions-in-vitess_7.html), which will be used as foundation for this design. -======= The most critical component of the 2PC protocol is the ‘Prepare’ functionality. There is actually a way to implement Prepare on top of a transactional system. This is explained in a [Vitess Blog](https://vitess.io/blog/2016-06-07-distributed-transactions-in-vitess/), which will be used as foundation for this design. ->>>>>>> Stashed changes Familiarity with the blog and the [2PC algorithm](http://c2.com/cgi/wiki?TwoPhaseCommit) are required to understand the rest of the document. @@ -36,11 +32,7 @@ Vitess will add a few variations to the traditional 2PC algorithm: * The Coordinator will be stateless and will orchestrate the work. VTGates are the perfect fit for this role. * One of the VTTablets will be designated as the Metadata Manager (MM). It will be used to store the metadata and perform the necessary state transitions. * If we designate one of the participant VTTablets to be the MM, then that database can avoid the prepare phase: If you assume there are N participants, the typical explanation says that you perform prepares from 1->N, and then commit from 1->N. If we instead went from 1->N for prepare, and N->1 for commit. Then the N’th database would perform a Prepare->Decide to commit->Commit. Instead, we execute the DML needed to transition the metadata state to ‘Decide to Commit’ as part of the app transaction, and commit it. If the commit fails, then it’s treated as the prepare having failed. If the commit succeeds, then it’s treated as all three operations having succeeded. -<<<<<<< Updated upstream -* The Prepare functionality will be implemented as explained in the [blog](http://blog.vitess.io/2016/06/distributed-transactions-in-vitess_7.html). -======= * The Prepare functionality will be implemented as explained in the [blog](https://vitess.io/blog/2016-06-07-distributed-transactions-in-vitess/). ->>>>>>> Stashed changes Combining the above changes allows us to keep the most common use case efficient: A transaction that affects only one database incurs no additional cost due to 2PC. @@ -154,11 +146,7 @@ The DTID will be generated by taking the VTID of the MM and prefixing it with th ## Prepare API -<<<<<<< Updated upstream -The Prepare API will be provided by VTTablet, and will follow the guidelines of the [blog](http://blog.vitess.io/2016/06/distributed-transactions-in-vitess_7.html). It’s essentially three functions: Prepare, CommitPrepared and RollbackPrepared. -======= The Prepare API will be provided by VTTablet, and will follow the guidelines of the [blog](https://vitess.io/blog/2016-06-07-distributed-transactions-in-vitess/). It’s essentially three functions: Prepare, CommitPrepared and RollbackPrepared. ->>>>>>> Stashed changes ### Statement list and state diff --git a/doc/VtExplain.md b/doc/VtExplain.md index b6bec78f78a..22e916b50b4 100644 --- a/doc/VtExplain.md +++ b/doc/VtExplain.md @@ -5,7 +5,7 @@ The vtexplain tool provides information about how Vitess will execute a statemen ## Prerequisites You'll need to build the `vtexplain` binary in your environment. -To find instructions on how to build this binary please refer to this [guide](https://vitess.io/getting-started/local-instance.html#manual-build). +To find instructions on how to build this binary please refer to this [guide](https://vitess.io/docs/tutorials/local/). ## Explaining a Query diff --git a/examples/kubernetes/README.md b/examples/kubernetes/README.md index cd142ac140c..a4ea12366cd 100644 --- a/examples/kubernetes/README.md +++ b/examples/kubernetes/README.md @@ -3,6 +3,4 @@ This directory contains an example configuration for running Vitess on [Kubernetes](https://kubernetes.io/). -See the [Vitess on Kubernetes](https://vitess.io/getting-started/) -and [Sharding in Kubernetes](https://vitess.io/user-guide/sharding-kubernetes/) -guides for instructions on using these files. +See the [Vitess on Kubernetes](https://vitess.io/docs/tutorials/kubernetes/) \ No newline at end of file From bd0d967f034f257ac0812ee04d6b5fe078fa39f1 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Sat, 16 Feb 2019 13:03:48 -0800 Subject: [PATCH 084/196] Fix resharding test Signed-off-by: Rafael Chacon --- go/vt/wrangler/keyspace.go | 2 +- test/resharding.py | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index 6f8869475ff..16e7cf00e03 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -783,7 +783,7 @@ func (wr *Wrangler) updateFrozenFlag(ctx context.Context, shards []*topo.ShardIn TabletType: topodatapb.TabletType_MASTER, Frozen: value, } - si.TabletControls = []*topodatapb.Shard_TabletControl{tc} + si.TabletControls = append(si.TabletControls, tc) return nil }) if err != nil { diff --git a/test/resharding.py b/test/resharding.py index 7bd8f8d2949..d5127a3e364 100755 --- a/test/resharding.py +++ b/test/resharding.py @@ -1148,22 +1148,18 @@ def test_resharding(self): utils.check_tablet_query_service(self, shard_1_master, True, False) # sabotage master migration and make it fail in an unfinished state + # Check that source master not serving, because this failure is past the + # point of no return. utils.run_vtctl(['SetShardTabletControl', '-blacklisted_tables=t', 'test_keyspace/c0-', 'master'], auto_log=True) utils.run_vtctl(['MigrateServedTypes', 'test_keyspace/80-', 'master'], auto_log=True, expect_fail=True) - # remove sabotage, but make it fail early. This should not result - # in the source master serving, because this failure is past the - # point of no return. - utils.run_vtctl(['SetShardTabletControl', '-blacklisted_tables=t', - '-remove', 'test_keyspace/c0-', 'master'], auto_log=True) - utils.run_vtctl(['MigrateServedTypes', - '-filtered_replication_wait_time', '0s', - 'test_keyspace/80-', 'master'], - auto_log=True, expect_fail=True) utils.check_tablet_query_service(self, shard_1_master, False, True) + # remove sabotage + utils.run_vtctl(['SetShardTabletControl', '-blacklisted_tables=t', + '-remove', 'test_keyspace/c0-', 'master'], auto_log=True) # do the migration that's expected to succeed utils.run_vtctl(['MigrateServedTypes', 'test_keyspace/80-', 'master'], auto_log=True) From 8694ae85884612a49af47907d603b3e59e36938a Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Sat, 16 Feb 2019 13:05:18 -0800 Subject: [PATCH 085/196] Fixed bug in srv_keyspace. Adds validations that were missed during migration Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index 86c9e43d284..4bd015af80b 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -310,6 +310,26 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string } } + for _, shard := range shards { + for _, tc := range shard.TabletControls { + if len(tc.BlacklistedTables) > 0 { + return fmt.Errorf("cannot safely alter DisableQueryService as BlacklistedTables is set for shard %v", shard) + } + } + } + + if !disableQueryService { + for _, si := range shards { + tc := si.GetTabletControl(tabletType) + if tc == nil { + continue + } + if tc.Frozen { + return fmt.Errorf("migrate has gone past the point of no return, cannot re-enable serving for %v/%v", si.keyspace, si.shardName) + } + } + } + wg := sync.WaitGroup{} rec := concurrency.AllErrorRecorder{} for _, cell := range cells { @@ -574,7 +594,7 @@ func OrderAndCheckPartitions(cell string, srvKeyspace *topodatapb.SrvKeyspace) e func ShardIsServing(srvKeyspace *topodatapb.SrvKeyspace, shard *topodatapb.Shard) bool { for _, partition := range srvKeyspace.GetPartitions() { for _, shardReference := range partition.GetShardReferences() { - if shardReference.GetKeyRange() == shard.KeyRange { + if key.KeyRangeEqual(shardReference.GetKeyRange(), shard.GetKeyRange()) { return true } } From 3478e976708ce544bc42b1194e05cae37d83b098 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Sat, 16 Feb 2019 13:34:11 -0800 Subject: [PATCH 086/196] Adds utility function to check if query service disabled is set in a shard Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 47 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index 4bd015af80b..46a22783bc3 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -532,6 +532,53 @@ func (ts *Server) GetSrvKeyspaceAllCells(ctx context.Context, keyspace string) ( return srvKeyspaces, nil } +// IsShardQueryServiceDisabled returns served types for given shard across all cells +func (ts *Server) IsShardQueryServiceDisabled(ctx context.Context, si *ShardInfo) (queryServiceDisabled bool, err error) { + cells, err := ts.GetCellInfoNames(ctx) + if err != nil { + return queryServiceDisabled, err + } + + wg := sync.WaitGroup{} + rec := concurrency.AllErrorRecorder{} + var mu sync.Mutex + for _, cell := range cells { + wg.Add(1) + go func(cell, keyspace string) { + defer wg.Done() + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) + switch { + case err == nil: + func() { + mu.Lock() + defer mu.Unlock() + if queryServiceDisabled { + return + } + for _, partition := range srvKeyspace.GetPartitions() { + for _, shardReference := range partition.ShardReferences { + if shardReference.GetName() == si.ShardName() { + } + } + + } + }() + case IsErrType(err, NoNode): + // NOOP + return + default: + rec.RecordError(err) + return + } + }(cell, si.Keyspace()) + } + wg.Wait() + if rec.HasErrors() { + return queryServiceDisabled, NewError(PartialResult, rec.Error().Error()) + } + return queryServiceDisabled, nil +} + // GetSrvKeyspace returns the SrvKeyspace for a cell/keyspace. func (ts *Server) GetSrvKeyspace(ctx context.Context, cell, keyspace string) (*topodatapb.SrvKeyspace, error) { conn, err := ts.ConnForCell(ctx, cell) From f4cd023d1d0f0b30df3104ddb166ab00a7f2d689 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Sat, 16 Feb 2019 14:22:31 -0800 Subject: [PATCH 087/196] Fixes for custom sharding Signed-off-by: Rafael Chacon --- go/vt/topotools/rebuild_keyspace.go | 39 ++++++----------------------- test/custom_sharding.py | 4 +-- 2 files changed, 9 insertions(+), 34 deletions(-) diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index ba07098bdb1..3f99606abcb 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -18,7 +18,6 @@ package topotools import ( "fmt" - "reflect" "sync" "golang.org/x/net/context" @@ -71,46 +70,22 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser return err } + // This is safe to rebuild as long there are not srvKeyspaces with tablet controls set. + // TODO: Add this validation. + // Build the list of cells to work on: we get the union // of all the Cells of all the Shards, limited to the provided cells. // // srvKeyspaceMap is a map: // key: cell // value: topo.SrvKeyspace object being built - // We only build this in two scenarios: - // - The object does not exist. - // - ServedFrom changed. srvKeyspaceMap := make(map[string]*topodatapb.SrvKeyspace) for _, cell := range cells { - srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) - switch { - case err == nil: - if !reflect.DeepEqual(srvKeyspace.ServedFrom, ki.ComputeCellServedFrom(cell)) { - srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ - ShardingColumnName: ki.ShardingColumnName, - ShardingColumnType: ki.ShardingColumnType, - ServedFrom: ki.ComputeCellServedFrom(cell), - } - } - if ki.ShardingColumnType != topodatapb.KeyspaceIdType_UNSET { - srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ - ShardingColumnName: ki.ShardingColumnName, - ShardingColumnType: ki.ShardingColumnType, - ServedFrom: ki.ComputeCellServedFrom(cell), - } - } - - case topo.IsErrType(err, topo.NoNode): - srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ - ShardingColumnName: ki.ShardingColumnName, - ShardingColumnType: ki.ShardingColumnType, - ServedFrom: ki.ComputeCellServedFrom(cell), - } - default: - // Couldn't get srvKeyspace, not - log.Warningf("Couldn't get srvKeyspace for cell %v, skip rebuilding", cell) + srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ + ShardingColumnName: ki.ShardingColumnName, + ShardingColumnType: ki.ShardingColumnType, + ServedFrom: ki.ComputeCellServedFrom(cell), } - } servedTypes := []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY} diff --git a/test/custom_sharding.py b/test/custom_sharding.py index f496e143b1e..b571e2f278c 100755 --- a/test/custom_sharding.py +++ b/test/custom_sharding.py @@ -151,7 +151,7 @@ def test_custom_end_to_end(self): self._check_shards_count_in_srv_keyspace(1) s = utils.run_vtctl_json(['GetShard', 'test_keyspace/0']) - self.assertEqual(len(s['served_types']), 3) + self.assertEqual(s['is_master_serving'], True) # create a table on shard 0 sql = '''create table data( @@ -191,7 +191,7 @@ def test_custom_end_to_end(self): t.wait_for_vttablet_state('NOT_SERVING') s = utils.run_vtctl_json(['GetShard', 'test_keyspace/1']) - self.assertEqual(len(s['served_types']), 3) + self.assertEqual(s['is_master_serving'], True) utils.run_vtctl(['InitShardMaster', '-force', 'test_keyspace/1', shard_1_master.tablet_alias], auto_log=True) From d8afcf05a3a916281f30bfdcbd628ea83c9debc6 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Sat, 16 Feb 2019 15:19:34 -0800 Subject: [PATCH 088/196] This test does not longer makes sense. We don't have cells in shards anymore Signed-off-by: Rafael Chacon --- test/reparent.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/test/reparent.py b/test/reparent.py index 5f1f07a30b5..ba8758a0ef0 100755 --- a/test/reparent.py +++ b/test/reparent.py @@ -213,9 +213,6 @@ def test_reparent_cross_cell(self, shard_id='0'): # Start up a master mysql and vttablet tablet_62344.init_tablet('replica', 'test_keyspace', shard_id, start=True, wait_for_start=False) - shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/' + shard_id]) - self.assertEqual(shard['cells'], ['test_nj'], - 'wrong list of cell in Shard: %s' % str(shard['cells'])) # Create a few slaves for testing reparenting. Won't be healthy # as replication is not running. @@ -227,10 +224,6 @@ def test_reparent_cross_cell(self, shard_id='0'): wait_for_start=False) for t in [tablet_62344, tablet_62044, tablet_41983, tablet_31981]: t.wait_for_vttablet_state('NOT_SERVING') - shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/' + shard_id]) - self.assertEqual( - shard['cells'], ['test_nj', 'test_ny'], - 'wrong list of cell in Shard: %s' % str(shard['cells'])) # Force the slaves to reparent assuming that all the datasets are # identical. @@ -271,9 +264,6 @@ def _test_reparent_graceful(self, shard_id): # Start up a master mysql and vttablet tablet_62344.init_tablet('replica', 'test_keyspace', shard_id, start=True) - shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/' + shard_id]) - self.assertEqual(shard['cells'], ['test_nj'], - 'wrong list of cell in Shard: %s' % str(shard['cells'])) # Create a few slaves for testing reparenting. tablet_62044.init_tablet('replica', 'test_keyspace', shard_id, start=True, From b05e8cdfcdb7b7404ea3d73c37b865b519a10f78 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Sat, 16 Feb 2019 18:36:34 -0800 Subject: [PATCH 089/196] Remove deprecated assertion Signed-off-by: Rafael Chacon --- test/reparent.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/reparent.py b/test/reparent.py index ba8758a0ef0..67bf2f7cae0 100755 --- a/test/reparent.py +++ b/test/reparent.py @@ -274,9 +274,6 @@ def _test_reparent_graceful(self, shard_id): wait_for_start=False) for t in [tablet_62044, tablet_41983, tablet_31981]: t.wait_for_vttablet_state('NOT_SERVING') - shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/' + shard_id]) - self.assertEqual(shard['cells'], ['test_nj', 'test_ny'], - 'wrong list of cell in Shard: %s' % str(shard['cells'])) # Force the slaves to reparent assuming that all the datasets are # identical. From b607d6439cdadf5e136a3dc07bf3f9a18e7dae18 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Sun, 17 Feb 2019 15:00:50 -0800 Subject: [PATCH 090/196] codegen: use strings.Builder instead of hack For the sake of efficiency, we used to 'hack' some places by coercing a []byte into a string. This hack is now officially encapsulated safely by strings.Builder. The last place where we're still using hack.String is in sqltypes.Value. That will require some thinking. I've also deleted code for other hacks that we don't use any more. Signed-off-by: Sugu Sougoumarane --- go/hack/hack.go | 42 +------------- go/hack/hack_test.go | 55 ------------------ go/vt/binlog/binlog_streamer.go | 6 +- go/vt/sqlparser/ast.go | 5 +- go/vt/sqlparser/ast_test.go | 2 +- go/vt/sqlparser/encodable.go | 12 ++-- go/vt/sqlparser/encodable_test.go | 4 +- go/vt/sqlparser/parsed_query.go | 19 ++++--- go/vt/sqlparser/tracked_buffer.go | 6 +- go/vt/vtexplain/vtexplain.go | 3 +- go/vt/vtgate/planbuilder/insert.go | 2 +- go/vt/vttablet/heartbeat/reader.go | 3 +- go/vt/vttablet/heartbeat/writer.go | 3 +- go/vt/vttablet/tabletserver/codex.go | 4 +- go/vt/vttablet/tabletserver/codex_test.go | 2 +- go/vt/vttablet/tabletserver/query_executor.go | 57 ++++++++++--------- go/vt/vttablet/tabletserver/tabletserver.go | 19 +++---- go/vt/vttablet/tabletserver/twopc.go | 17 +++--- 18 files changed, 82 insertions(+), 179 deletions(-) diff --git a/go/hack/hack.go b/go/hack/hack.go index e6344ad99d6..763a180a99b 100644 --- a/go/hack/hack.go +++ b/go/hack/hack.go @@ -23,53 +23,13 @@ import ( "unsafe" ) -// StringArena lets you consolidate allocations for a group of strings -// that have similar life length -type StringArena struct { - buf []byte - str string -} - -// NewStringArena creates an arena of the specified size. -func NewStringArena(size int) *StringArena { - sa := &StringArena{buf: make([]byte, 0, size)} - pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&sa.buf)) - pstring := (*reflect.StringHeader)(unsafe.Pointer(&sa.str)) - pstring.Data = pbytes.Data - pstring.Len = pbytes.Cap - return sa -} - -// NewString copies a byte slice into the arena and returns it as a string. -// If the arena is full, it returns a traditional go string. -func (sa *StringArena) NewString(b []byte) string { - if len(b) == 0 { - return "" - } - if len(sa.buf)+len(b) > cap(sa.buf) { - return string(b) - } - start := len(sa.buf) - sa.buf = append(sa.buf, b...) - return sa.str[start : start+len(b)] -} - -// SpaceLeft returns the amount of space left in the arena. -func (sa *StringArena) SpaceLeft() int { - return cap(sa.buf) - len(sa.buf) -} - // String force casts a []byte to a string. // USE AT YOUR OWN RISK func String(b []byte) (s string) { if len(b) == 0 { return "" } - pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - pstring := (*reflect.StringHeader)(unsafe.Pointer(&s)) - pstring.Data = pbytes.Data - pstring.Len = pbytes.Len - return + return *(*string)(unsafe.Pointer(&b)) } // StringPointer returns &s[0], which is not allowed in go diff --git a/go/hack/hack_test.go b/go/hack/hack_test.go index 5417cb63810..d34bb8d2301 100644 --- a/go/hack/hack_test.go +++ b/go/hack/hack_test.go @@ -20,61 +20,6 @@ import ( "testing" ) -func TestStringArena(t *testing.T) { - sarena := NewStringArena(10) - - s0 := sarena.NewString(nil) - checkint(t, len(sarena.buf), 0) - checkint(t, sarena.SpaceLeft(), 10) - checkstring(t, s0, "") - - s1 := sarena.NewString([]byte("01234")) - checkint(t, len(sarena.buf), 5) - checkint(t, sarena.SpaceLeft(), 5) - checkstring(t, s1, "01234") - - s2 := sarena.NewString([]byte("5678")) - checkint(t, len(sarena.buf), 9) - checkint(t, sarena.SpaceLeft(), 1) - checkstring(t, s2, "5678") - - // s3 will be allocated outside of sarena - s3 := sarena.NewString([]byte("ab")) - checkint(t, len(sarena.buf), 9) - checkint(t, sarena.SpaceLeft(), 1) - checkstring(t, s3, "ab") - - // s4 should still fit in sarena - s4 := sarena.NewString([]byte("9")) - checkint(t, len(sarena.buf), 10) - checkint(t, sarena.SpaceLeft(), 0) - checkstring(t, s4, "9") - - sarena.buf[0] = 'A' - checkstring(t, s1, "A1234") - - sarena.buf[5] = 'B' - checkstring(t, s2, "B678") - - sarena.buf[9] = 'C' - // s3 will not change - checkstring(t, s3, "ab") - checkstring(t, s4, "C") - checkstring(t, sarena.str, "A1234B678C") -} - -func checkstring(t *testing.T, actual, expected string) { - if actual != expected { - t.Errorf("received %s, expecting %s", actual, expected) - } -} - -func checkint(t *testing.T, actual, expected int) { - if actual != expected { - t.Errorf("received %d, expecting %d", actual, expected) - } -} - func TestByteToString(t *testing.T) { v1 := []byte("1234") if s := String(v1); s != "1234" { diff --git a/go/vt/binlog/binlog_streamer.go b/go/vt/binlog/binlog_streamer.go index c64cb5ba460..77b7d02f5d8 100644 --- a/go/vt/binlog/binlog_streamer.go +++ b/go/vt/binlog/binlog_streamer.go @@ -625,7 +625,7 @@ func (bls *Streamer) appendInserts(statements []FullBinlogStatement, tce *tableC statement := &binlogdatapb.BinlogTransaction_Statement{ Category: binlogdatapb.BinlogTransaction_Statement_BL_INSERT, - Sql: sql.Bytes(), + Sql: []byte(sql.String()), } statements = append(statements, FullBinlogStatement{ Statement: statement, @@ -668,7 +668,7 @@ func (bls *Streamer) appendUpdates(statements []FullBinlogStatement, tce *tableC update := &binlogdatapb.BinlogTransaction_Statement{ Category: binlogdatapb.BinlogTransaction_Statement_BL_UPDATE, - Sql: sql.Bytes(), + Sql: []byte(sql.String()), } statements = append(statements, FullBinlogStatement{ Statement: update, @@ -704,7 +704,7 @@ func (bls *Streamer) appendDeletes(statements []FullBinlogStatement, tce *tableC statement := &binlogdatapb.BinlogTransaction_Statement{ Category: binlogdatapb.BinlogTransaction_Statement_BL_DELETE, - Sql: sql.Bytes(), + Sql: []byte(sql.String()), } statements = append(statements, FullBinlogStatement{ Statement: statement, diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index 1fa69decebb..93d8c745524 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -17,7 +17,6 @@ limitations under the License. package sqlparser import ( - "bytes" "encoding/hex" "encoding/json" "errors" @@ -265,9 +264,9 @@ func String(node SQLNode) string { } // Append appends the SQLNode to the buffer. -func Append(buf *bytes.Buffer, node SQLNode) { +func Append(buf *strings.Builder, node SQLNode) { tbuf := &TrackedBuffer{ - Buffer: buf, + Builder: buf, } node.Format(tbuf) } diff --git a/go/vt/sqlparser/ast_test.go b/go/vt/sqlparser/ast_test.go index cf66c254001..f717b7add48 100644 --- a/go/vt/sqlparser/ast_test.go +++ b/go/vt/sqlparser/ast_test.go @@ -33,7 +33,7 @@ func TestAppend(t *testing.T) { if err != nil { t.Error(err) } - var b bytes.Buffer + var b strings.Builder Append(&b, tree) got := b.String() want := query diff --git a/go/vt/sqlparser/encodable.go b/go/vt/sqlparser/encodable.go index a9f620c05e2..2c74c6bbeaf 100644 --- a/go/vt/sqlparser/encodable.go +++ b/go/vt/sqlparser/encodable.go @@ -17,7 +17,7 @@ limitations under the License. package sqlparser import ( - "bytes" + "strings" "vitess.io/vitess/go/sqltypes" ) @@ -27,7 +27,7 @@ import ( // Encodable defines the interface for types that can // be custom-encoded into SQL. type Encodable interface { - EncodeSQL(buf *bytes.Buffer) + EncodeSQL(buf *strings.Builder) } // InsertValues is a custom SQL encoder for the values of @@ -35,7 +35,7 @@ type Encodable interface { type InsertValues [][]sqltypes.Value // EncodeSQL performs the SQL encoding for InsertValues. -func (iv InsertValues) EncodeSQL(buf *bytes.Buffer) { +func (iv InsertValues) EncodeSQL(buf *strings.Builder) { for i, rows := range iv { if i != 0 { buf.WriteString(", ") @@ -60,7 +60,7 @@ type TupleEqualityList struct { // EncodeSQL generates the where clause constraints for the tuple // equality. -func (tpl *TupleEqualityList) EncodeSQL(buf *bytes.Buffer) { +func (tpl *TupleEqualityList) EncodeSQL(buf *strings.Builder) { if len(tpl.Columns) == 1 { tpl.encodeAsIn(buf) return @@ -68,7 +68,7 @@ func (tpl *TupleEqualityList) EncodeSQL(buf *bytes.Buffer) { tpl.encodeAsEquality(buf) } -func (tpl *TupleEqualityList) encodeAsIn(buf *bytes.Buffer) { +func (tpl *TupleEqualityList) encodeAsIn(buf *strings.Builder) { Append(buf, tpl.Columns[0]) buf.WriteString(" in (") for i, r := range tpl.Rows { @@ -80,7 +80,7 @@ func (tpl *TupleEqualityList) encodeAsIn(buf *bytes.Buffer) { buf.WriteByte(')') } -func (tpl *TupleEqualityList) encodeAsEquality(buf *bytes.Buffer) { +func (tpl *TupleEqualityList) encodeAsEquality(buf *strings.Builder) { for i, r := range tpl.Rows { if i != 0 { buf.WriteString(" or ") diff --git a/go/vt/sqlparser/encodable_test.go b/go/vt/sqlparser/encodable_test.go index 3d8710ce8eb..222ecb99726 100644 --- a/go/vt/sqlparser/encodable_test.go +++ b/go/vt/sqlparser/encodable_test.go @@ -17,7 +17,7 @@ limitations under the License. package sqlparser import ( - "bytes" + "strings" "testing" "vitess.io/vitess/go/sqltypes" @@ -64,7 +64,7 @@ func TestEncodable(t *testing.T) { out: "(pk1 = 1 and pk2 = 'aa') or (pk1 = 2 and pk2 = 'bb')", }} for _, tcase := range tcases { - buf := new(bytes.Buffer) + buf := new(strings.Builder) tcase.in.EncodeSQL(buf) if out := buf.String(); out != tcase.out { t.Errorf("EncodeSQL(%v): %s, want %s", tcase.in, out, tcase.out) diff --git a/go/vt/sqlparser/parsed_query.go b/go/vt/sqlparser/parsed_query.go index 47adf1aaf66..8fcce8c98aa 100644 --- a/go/vt/sqlparser/parsed_query.go +++ b/go/vt/sqlparser/parsed_query.go @@ -17,9 +17,9 @@ limitations under the License. package sqlparser import ( - "bytes" "encoding/json" "fmt" + "strings" "vitess.io/vitess/go/sqltypes" @@ -47,28 +47,29 @@ func NewParsedQuery(node SQLNode) *ParsedQuery { // GenerateQuery generates a query by substituting the specified // bindVariables. The extras parameter specifies special parameters // that can perform custom encoding. -func (pq *ParsedQuery) GenerateQuery(bindVariables map[string]*querypb.BindVariable, extras map[string]Encodable) ([]byte, error) { +func (pq *ParsedQuery) GenerateQuery(bindVariables map[string]*querypb.BindVariable, extras map[string]Encodable) (string, error) { if len(pq.bindLocations) == 0 { - return []byte(pq.Query), nil + return pq.Query, nil } - buf := bytes.NewBuffer(make([]byte, 0, len(pq.Query))) + var buf strings.Builder + buf.Grow(len(pq.Query)) current := 0 for _, loc := range pq.bindLocations { buf.WriteString(pq.Query[current:loc.offset]) name := pq.Query[loc.offset : loc.offset+loc.length] if encodable, ok := extras[name[1:]]; ok { - encodable.EncodeSQL(buf) + encodable.EncodeSQL(&buf) } else { supplied, _, err := FetchBindVar(name, bindVariables) if err != nil { - return nil, err + return "", err } - EncodeValue(buf, supplied) + EncodeValue(&buf, supplied) } current = loc.offset + loc.length } buf.WriteString(pq.Query[current:]) - return buf.Bytes(), nil + return buf.String(), nil } // MarshalJSON is a custom JSON marshaler for ParsedQuery. @@ -78,7 +79,7 @@ func (pq *ParsedQuery) MarshalJSON() ([]byte, error) { } // EncodeValue encodes one bind variable value into the query. -func EncodeValue(buf *bytes.Buffer, value *querypb.BindVariable) { +func EncodeValue(buf *strings.Builder, value *querypb.BindVariable) { if value.Type != querypb.Type_TUPLE { // Since we already check for TUPLE, we don't expect an error. v, _ := sqltypes.BindVariableToValue(value) diff --git a/go/vt/sqlparser/tracked_buffer.go b/go/vt/sqlparser/tracked_buffer.go index ec421a5fb8c..f14751f96be 100644 --- a/go/vt/sqlparser/tracked_buffer.go +++ b/go/vt/sqlparser/tracked_buffer.go @@ -17,8 +17,8 @@ limitations under the License. package sqlparser import ( - "bytes" "fmt" + "strings" ) // NodeFormatter defines the signature of a custom node formatter @@ -33,7 +33,7 @@ type NodeFormatter func(buf *TrackedBuffer, node SQLNode) // But you can supply a different formatting function if you // want to generate a query that's different from the default. type TrackedBuffer struct { - *bytes.Buffer + *strings.Builder bindLocations []bindLocation nodeFormatter NodeFormatter } @@ -41,7 +41,7 @@ type TrackedBuffer struct { // NewTrackedBuffer creates a new TrackedBuffer. func NewTrackedBuffer(nodeFormatter NodeFormatter) *TrackedBuffer { return &TrackedBuffer{ - Buffer: new(bytes.Buffer), + Builder: new(strings.Builder), nodeFormatter: nodeFormatter, } } diff --git a/go/vt/vtexplain/vtexplain.go b/go/vt/vtexplain/vtexplain.go index 9cc92cb24fa..f97edad17f6 100644 --- a/go/vt/vtexplain/vtexplain.go +++ b/go/vt/vtexplain/vtexplain.go @@ -24,6 +24,7 @@ import ( "flag" "fmt" "sort" + "strings" "time" "vitess.io/vitess/go/jsonutil" @@ -102,7 +103,7 @@ func (tq *TabletQuery) MarshalJSON() ([]byte, error) { // Convert Bindvars to strings for nicer output bindVars := make(map[string]string) for k, v := range tq.BindVars { - var b bytes.Buffer + var b strings.Builder sqlparser.EncodeValue(&b, v) bindVars[k] = b.String() } diff --git a/go/vt/vtgate/planbuilder/insert.go b/go/vt/vtgate/planbuilder/insert.go index 5bef6cde7e4..2e3624bd884 100644 --- a/go/vt/vtgate/planbuilder/insert.go +++ b/go/vt/vtgate/planbuilder/insert.go @@ -183,7 +183,7 @@ func generateInsertShardedQuery(node *sqlparser.Insert, eins *engine.Insert, val for rowNum, val := range valueTuples { midBuf.Myprintf("%v", val) eins.Mid[rowNum] = midBuf.String() - midBuf.Truncate(0) + midBuf.Reset() } suffixBuf.Myprintf("%v", node.OnDup) eins.Suffix = suffixBuf.String() diff --git a/go/vt/vttablet/heartbeat/reader.go b/go/vt/vttablet/heartbeat/reader.go index b0eb91728d9..883023bf607 100644 --- a/go/vt/vttablet/heartbeat/reader.go +++ b/go/vt/vttablet/heartbeat/reader.go @@ -25,7 +25,6 @@ import ( "golang.org/x/net/context" - "vitess.io/vitess/go/hack" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/timer" @@ -202,7 +201,7 @@ func (r *Reader) bindHeartbeatFetch() (string, error) { if err != nil { return "", err } - return hack.String(bound), nil + return bound, nil } // parseHeartbeatResult turns a raw result into the timestamp for processing. diff --git a/go/vt/vttablet/heartbeat/writer.go b/go/vt/vttablet/heartbeat/writer.go index 9d5ee58a772..ca1333c3b4f 100644 --- a/go/vt/vttablet/heartbeat/writer.go +++ b/go/vt/vttablet/heartbeat/writer.go @@ -25,7 +25,6 @@ import ( "golang.org/x/net/context" - "vitess.io/vitess/go/hack" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/sqltypes" @@ -198,7 +197,7 @@ func (w *Writer) bindHeartbeatVars(query string) (string, error) { if err != nil { return "", err } - return hack.String(bound), nil + return bound, nil } // writeHeartbeat updates the heartbeat row for this tablet with the current time in nanoseconds. diff --git a/go/vt/vttablet/tabletserver/codex.go b/go/vt/vttablet/tabletserver/codex.go index 65bb7712c07..ac55b2a6c46 100644 --- a/go/vt/vttablet/tabletserver/codex.go +++ b/go/vt/vttablet/tabletserver/codex.go @@ -121,7 +121,7 @@ func validateValue(col *schema.TableColumn, value sqltypes.Value) error { return nil } -func buildStreamComment(table *schema.Table, pkValueList [][]sqltypes.Value, secondaryList [][]sqltypes.Value) []byte { +func buildStreamComment(table *schema.Table, pkValueList [][]sqltypes.Value, secondaryList [][]sqltypes.Value) string { buf := sqlparser.NewTrackedBuffer(nil) buf.Myprintf(" /* _stream %v (", table.Name) // We assume the first index exists, and is the pk @@ -132,7 +132,7 @@ func buildStreamComment(table *schema.Table, pkValueList [][]sqltypes.Value, sec buildPKValueList(buf, table, pkValueList) buildPKValueList(buf, table, secondaryList) buf.WriteString("; */") - return buf.Bytes() + return buf.String() } func buildPKValueList(buf *sqlparser.TrackedBuffer, table *schema.Table, pkValueList [][]sqltypes.Value) { diff --git a/go/vt/vttablet/tabletserver/codex_test.go b/go/vt/vttablet/tabletserver/codex_test.go index 2a8040406b6..1393ccbef57 100644 --- a/go/vt/vttablet/tabletserver/codex_test.go +++ b/go/vt/vttablet/tabletserver/codex_test.go @@ -184,7 +184,7 @@ func TestCodexBuildStreamComment(t *testing.T) { pk2SecVal := sqltypes.NewVarChar("xyz") secondaryPKValues := []sqltypes.PlanValue{{}, {Value: pk2SecVal}} secondaryList, _ := buildSecondaryList(table, pkList, secondaryPKValues, bindVars) - want := []byte(" /* _stream `Table` (pk1 pk2 ) (1 'YWJj' ) (1 'eHl6' ); */") + want := " /* _stream `Table` (pk1 pk2 ) (1 'YWJj' ) (1 'eHl6' ); */" got := buildStreamComment(table, pkList, secondaryList) if !reflect.DeepEqual(got, want) { t.Fatalf("case 1 failed, got\n%s, want\n%s", got, want) diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index 6e8747e952c..079486b8db2 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -25,7 +25,6 @@ import ( "golang.org/x/net/context" - "vitess.io/vitess/go/hack" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/trace" @@ -131,7 +130,7 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { if !qre.tsv.qe.allowUnsafeDMLs && (qre.tsv.qe.binlogFormat != connpool.BinlogFormatRow) { return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: cannot identify primary key of statement") } - return qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, nil, true, true) + return qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, "", true, true) case planbuilder.PlanInsertPK: return qre.execInsertPK(conn) case planbuilder.PlanInsertMessage: @@ -147,7 +146,7 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { case planbuilder.PlanUpsertPK: return qre.execUpsertPK(conn) case planbuilder.PlanSet: - return qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, nil, true, true) + return qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, "", true, true) case planbuilder.PlanPassSelect, planbuilder.PlanSelectLock, planbuilder.PlanSelectImpossible: return qre.execDirect(conn) default: @@ -242,7 +241,7 @@ func (qre *QueryExecutor) Stream(callback func(*sqltypes.Result) error) error { qre.tsv.qe.streamQList.Add(qd) defer qre.tsv.qe.streamQList.Remove(qd) - return qre.streamFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, callback) + return qre.streamFetch(conn, qre.plan.FullQuery, qre.bindVars, "", callback) } // MessageStream streams messages from a message table. @@ -281,7 +280,7 @@ func (qre *QueryExecutor) execDmlAutoCommit() (reply *sqltypes.Result, err error if !qre.tsv.qe.allowUnsafeDMLs && (qre.tsv.qe.binlogFormat != connpool.BinlogFormatRow) { return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: cannot identify primary key of statement") } - reply, err = qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, nil, true, true) + reply, err = qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, "", true, true) case planbuilder.PlanInsertPK: reply, err = qre.execInsertPK(conn) case planbuilder.PlanInsertMessage: @@ -413,7 +412,7 @@ func (qre *QueryExecutor) execDDL() (*sqltypes.Result, error) { sql := qre.query var err error if qre.plan.FullQuery != nil { - sql, _, err = qre.generateFinalSQL(qre.plan.FullQuery, qre.bindVars, nil, nil) + sql, _, err = qre.generateFinalSQL(qre.plan.FullQuery, qre.bindVars, nil, "") if err != nil { return nil, err } @@ -527,14 +526,14 @@ func (qre *QueryExecutor) execNextval() (*sqltypes.Result, error) { // execDirect is for reads inside transactions. Always send to MySQL. func (qre *QueryExecutor) execDirect(conn *TxConnection) (*sqltypes.Result, error) { if qre.plan.Fields != nil { - result, err := qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, nil, true, false) + result, err := qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, "", true, false) if err != nil { return nil, err } result.Fields = qre.plan.Fields return result, nil } - return qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, nil, true, false) + return qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, "", true, false) } // execSelect sends a query to mysql only if another identical query is not running. Otherwise, it waits and @@ -555,7 +554,7 @@ func (qre *QueryExecutor) execSelect() (*sqltypes.Result, error) { return nil, err } defer conn.Recycle() - return qre.dbConnFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, true) + return qre.dbConnFetch(conn, qre.plan.FullQuery, qre.bindVars, "", true) } func (qre *QueryExecutor) execInsertPK(conn *TxConnection) (*sqltypes.Result, error) { @@ -609,7 +608,7 @@ func (qre *QueryExecutor) execInsertMessage(conn *TxConnection) (*sqltypes.Resul if err != nil { return nil, err } - readback, err := qre.txFetch(conn, loadMessages, qre.bindVars, extras, nil, true, false) + readback, err := qre.txFetch(conn, loadMessages, qre.bindVars, extras, "", true, false) if err != nil { return nil, err } @@ -629,7 +628,7 @@ func (qre *QueryExecutor) execInsertMessage(conn *TxConnection) (*sqltypes.Resul } func (qre *QueryExecutor) execInsertSubquery(conn *TxConnection) (*sqltypes.Result, error) { - innerResult, err := qre.txFetch(conn, qre.plan.Subquery, qre.bindVars, nil, nil, true, false) + innerResult, err := qre.txFetch(conn, qre.plan.Subquery, qre.bindVars, nil, "", true, false) if err != nil { return nil, err } @@ -656,7 +655,7 @@ func (qre *QueryExecutor) execInsertSubquery(conn *TxConnection) (*sqltypes.Resu } func (qre *QueryExecutor) execInsertPKRows(conn *TxConnection, extras map[string]sqlparser.Encodable, pkRows [][]sqltypes.Value) (*sqltypes.Result, error) { - var bsc []byte + var bsc string // Build comments only if we're not in RBR mode. if qre.tsv.qe.binlogFormat != connpool.BinlogFormatRow { secondaryList, err := buildSecondaryList(qre.plan.Table, pkRows, qre.plan.SecondaryPKValues, qre.bindVars) @@ -671,7 +670,7 @@ func (qre *QueryExecutor) execInsertPKRows(conn *TxConnection, extras map[string func (qre *QueryExecutor) execUpsertPK(conn *TxConnection) (*sqltypes.Result, error) { // For RBR, upserts are passed through. if qre.tsv.qe.binlogFormat == connpool.BinlogFormatRow { - return qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, nil, true, true) + return qre.txFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, "", true, true) } // For statement or mixed mode, we have to split into two ops. @@ -720,7 +719,7 @@ func (qre *QueryExecutor) execDMLPK(conn *TxConnection) (*sqltypes.Result, error } func (qre *QueryExecutor) execDMLSubquery(conn *TxConnection) (*sqltypes.Result, error) { - innerResult, err := qre.txFetch(conn, qre.plan.Subquery, qre.bindVars, nil, nil, true, false) + innerResult, err := qre.txFetch(conn, qre.plan.Subquery, qre.bindVars, nil, "", true, false) if err != nil { return nil, err } @@ -748,7 +747,7 @@ func (qre *QueryExecutor) execDMLPKRows(conn *TxConnection, query *sqlparser.Par if secondaryList != nil { secondaryList = secondaryList[i:end] } - var bsc []byte + var bsc string // Build comments only if we're not in RBR mode. if qre.tsv.qe.binlogFormat != connpool.BinlogFormatRow { bsc = buildStreamComment(qre.plan.Table, pkRows, secondaryList) @@ -787,7 +786,7 @@ func (qre *QueryExecutor) execSet() (*sqltypes.Result, error) { return nil, err } defer conn.Recycle() - return qre.dbConnFetch(conn, qre.plan.FullQuery, qre.bindVars, nil, false) + return qre.dbConnFetch(conn, qre.plan.FullQuery, qre.bindVars, "", false) } func (qre *QueryExecutor) getConn() (*connpool.DBConn, error) { @@ -825,7 +824,7 @@ func (qre *QueryExecutor) getStreamConn() (*connpool.DBConn, error) { } func (qre *QueryExecutor) qFetch(logStats *tabletenv.LogStats, parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { - sql, sqlWithoutComments, err := qre.generateFinalSQL(parsedQuery, bindVars, nil, nil) + sql, sqlWithoutComments, err := qre.generateFinalSQL(parsedQuery, bindVars, nil, "") if err != nil { return nil, err } @@ -865,7 +864,7 @@ func (qre *QueryExecutor) qFetch(logStats *tabletenv.LogStats, parsedQuery *sqlp } // txFetch fetches from a TxConnection. -func (qre *QueryExecutor) txFetch(conn *TxConnection, parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable, extras map[string]sqlparser.Encodable, buildStreamComment []byte, wantfields, record bool) (*sqltypes.Result, error) { +func (qre *QueryExecutor) txFetch(conn *TxConnection, parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable, extras map[string]sqlparser.Encodable, buildStreamComment string, wantfields, record bool) (*sqltypes.Result, error) { sql, _, err := qre.generateFinalSQL(parsedQuery, bindVars, extras, buildStreamComment) if err != nil { return nil, err @@ -882,7 +881,7 @@ func (qre *QueryExecutor) txFetch(conn *TxConnection, parsedQuery *sqlparser.Par } // dbConnFetch fetches from a connpool.DBConn. -func (qre *QueryExecutor) dbConnFetch(conn *connpool.DBConn, parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable, buildStreamComment []byte, wantfields bool) (*sqltypes.Result, error) { +func (qre *QueryExecutor) dbConnFetch(conn *connpool.DBConn, parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable, buildStreamComment string, wantfields bool) (*sqltypes.Result, error) { sql, _, err := qre.generateFinalSQL(parsedQuery, bindVars, nil, buildStreamComment) if err != nil { return nil, err @@ -891,7 +890,7 @@ func (qre *QueryExecutor) dbConnFetch(conn *connpool.DBConn, parsedQuery *sqlpar } // streamFetch performs a streaming fetch. -func (qre *QueryExecutor) streamFetch(conn *connpool.DBConn, parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable, buildStreamComment []byte, callback func(*sqltypes.Result) error) error { +func (qre *QueryExecutor) streamFetch(conn *connpool.DBConn, parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable, buildStreamComment string, callback func(*sqltypes.Result) error) error { sql, _, err := qre.generateFinalSQL(parsedQuery, bindVars, nil, buildStreamComment) if err != nil { return err @@ -899,22 +898,24 @@ func (qre *QueryExecutor) streamFetch(conn *connpool.DBConn, parsedQuery *sqlpar return qre.execStreamSQL(conn, sql, callback) } -func (qre *QueryExecutor) generateFinalSQL(parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable, extras map[string]sqlparser.Encodable, buildStreamComment []byte) (string, string, error) { +func (qre *QueryExecutor) generateFinalSQL(parsedQuery *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable, extras map[string]sqlparser.Encodable, buildStreamComment string) (string, string, error) { bindVars["#maxLimit"] = sqltypes.Int64BindVariable(qre.getLimit(parsedQuery)) - var sql []byte - sql = append(sql, qre.marginComments.Leading...) + var buf strings.Builder + buf.WriteString(qre.marginComments.Leading) query, err := parsedQuery.GenerateQuery(bindVars, extras) if err != nil { return "", "", vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%s", err) } - sql = append(sql, query...) - if buildStreamComment != nil { - sql = append(sql, buildStreamComment...) + buf.WriteString(query) + if buildStreamComment != "" { + buf.WriteString(buildStreamComment) } - fullSQL := append(sql, qre.marginComments.Trailing...) - return hack.String(fullSQL), hack.String(sql), nil + withoutComments := buf.String() + buf.WriteString(qre.marginComments.Trailing) + fullSQL := buf.String() + return fullSQL, withoutComments, nil } func (qre *QueryExecutor) getLimit(query *sqlparser.ParsedQuery) int64 { diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index 2b2a4ad6a98..01e7082258a 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -32,7 +32,6 @@ import ( "golang.org/x/net/context" "vitess.io/vitess/go/acl" - "vitess.io/vitess/go/hack" "vitess.io/vitess/go/history" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" @@ -152,12 +151,12 @@ type TabletServer struct { // for health checks. This does not affect how queries are served. // target specifies the primary target type, and also allow specifies // secondary types that should be additionally allowed. - mu sync.Mutex - state int64 - lameduck sync2.AtomicInt32 - target querypb.Target - alsoAllow []topodatapb.TabletType - requests sync.WaitGroup + mu sync.Mutex + state int64 + lameduck sync2.AtomicInt32 + target querypb.Target + alsoAllow []topodatapb.TabletType + requests sync.WaitGroup // The following variables should be initialized only once // before starting the tabletserver. @@ -229,7 +228,7 @@ type TxPoolController interface { AcceptReadOnly() error // InitDBConfig must be called before Init. - InitDBConfig(dbcfgs *dbconfigs.DBConfigs) + InitDBConfig(dbcfgs *dbconfigs.DBConfigs) // Init must be called once when vttablet starts for setting // up the metadata tables. @@ -1200,7 +1199,7 @@ func (tsv *TabletServer) computeTxSerializerKey(ctx context.Context, logStats *t } // Example: table1 where id = 1 and sub_id = 2 - key := fmt.Sprintf("%s%s", tableName, hack.String(where)) + key := fmt.Sprintf("%s%s", tableName, where) return key, tableName.String() } @@ -1766,7 +1765,7 @@ func (se *splitQuerySQLExecuter) SQLExecute( se.conn, parsedQuery, sqltypes.CopyBindVariables(bindVariables), - nil, /* buildStreamComment */ + "", /* buildStreamComment */ true, /* wantfields */ ) } diff --git a/go/vt/vttablet/tabletserver/twopc.go b/go/vt/vttablet/tabletserver/twopc.go index 292c47594bd..c86adb75e05 100644 --- a/go/vt/vttablet/tabletserver/twopc.go +++ b/go/vt/vttablet/tabletserver/twopc.go @@ -22,7 +22,6 @@ import ( "golang.org/x/net/context" - "vitess.io/vitess/go/hack" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/sqltypes" @@ -233,11 +232,11 @@ func (tpc *TwoPC) SaveRedo(ctx context.Context, conn *TxConnection, dtid string, extras := map[string]sqlparser.Encodable{ "vals": sqlparser.InsertValues(rows), } - b, err := tpc.insertRedoStmt.GenerateQuery(nil, extras) + q, err := tpc.insertRedoStmt.GenerateQuery(nil, extras) if err != nil { return err } - _, err = conn.Exec(ctx, hack.String(b), 1, false) + _, err = conn.Exec(ctx, q, 1, false) return err } @@ -361,11 +360,11 @@ func (tpc *TwoPC) CreateTransaction(ctx context.Context, conn *TxConnection, dti extras := map[string]sqlparser.Encodable{ "vals": sqlparser.InsertValues(rows), } - b, err := tpc.insertParticipants.GenerateQuery(nil, extras) + q, err := tpc.insertParticipants.GenerateQuery(nil, extras) if err != nil { return err } - _, err = conn.Exec(ctx, hack.String(b), 1, false) + _, err = conn.Exec(ctx, q, 1, false) return err } @@ -533,17 +532,17 @@ func (tpc *TwoPC) ReadAllTransactions(ctx context.Context) ([]*DistributedTx, er } func (tpc *TwoPC) exec(ctx context.Context, conn *TxConnection, pq *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { - b, err := pq.GenerateQuery(bindVars, nil) + q, err := pq.GenerateQuery(bindVars, nil) if err != nil { return nil, err } - return conn.Exec(ctx, hack.String(b), 1, false) + return conn.Exec(ctx, q, 1, false) } func (tpc *TwoPC) read(ctx context.Context, conn *connpool.DBConn, pq *sqlparser.ParsedQuery, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { - b, err := pq.GenerateQuery(bindVars, nil) + q, err := pq.GenerateQuery(bindVars, nil) if err != nil { return nil, err } - return conn.Exec(ctx, hack.String(b), 10000, false) + return conn.Exec(ctx, q, 10000, false) } From 41767d84fbd699d8a39dfa8223cb6fec4a306ac6 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Tue, 12 Feb 2019 22:35:58 -0800 Subject: [PATCH 091/196] vreplication: improved lag tracking The new lag tracking introduces the following changes: * VStreamer sends its current time along with every event. This allows for VPlayer to correct for any clock skew that may exist between the two machines. This results in a more accurate calculation of lag. * If there are no events to send for a period of time, VStreamer sends a heartbeat event. This allows us VPlayer to essentially know for sure that it's still caught up. * If VPlayer receives no event for its wait period, then it updates the SecondsBehindMaster stat to indicate that it's actually falling behind. The VStreamer timeout for heartbeat is set slightly lower than the VPlayer idle timeout. This ensures that Vplayer won't timeout exactly when it's about to receive the heartbeat event. Signed-off-by: Sugu Sougoumarane --- go/vt/proto/binlogdata/binlogdata.pb.go | 282 +++++++++--------- .../tabletmanager/vreplication/vplayer.go | 26 +- .../tabletserver/vstreamer/vstreamer.go | 33 +- .../tabletserver/vstreamer/vstreamer_test.go | 2 + proto/binlogdata.proto | 3 + py/vtproto/binlogdata_pb2.py | 32 +- 6 files changed, 226 insertions(+), 152 deletions(-) diff --git a/go/vt/proto/binlogdata/binlogdata.pb.go b/go/vt/proto/binlogdata/binlogdata.pb.go index 2683321fd16..87f39855ed3 100644 --- a/go/vt/proto/binlogdata/binlogdata.pb.go +++ b/go/vt/proto/binlogdata/binlogdata.pb.go @@ -48,7 +48,7 @@ func (x OnDDLAction) String() string { return proto.EnumName(OnDDLAction_name, int32(x)) } func (OnDDLAction) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{0} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{0} } // VEventType enumerates the event types. @@ -57,20 +57,21 @@ func (OnDDLAction) EnumDescriptor() ([]byte, []int) { type VEventType int32 const ( - VEventType_UNKNOWN VEventType = 0 - VEventType_GTID VEventType = 1 - VEventType_BEGIN VEventType = 2 - VEventType_COMMIT VEventType = 3 - VEventType_ROLLBACK VEventType = 4 - VEventType_DDL VEventType = 5 - VEventType_INSERT VEventType = 6 - VEventType_REPLACE VEventType = 7 - VEventType_UPDATE VEventType = 8 - VEventType_DELETE VEventType = 9 - VEventType_SET VEventType = 10 - VEventType_OTHER VEventType = 11 - VEventType_ROW VEventType = 12 - VEventType_FIELD VEventType = 13 + VEventType_UNKNOWN VEventType = 0 + VEventType_GTID VEventType = 1 + VEventType_BEGIN VEventType = 2 + VEventType_COMMIT VEventType = 3 + VEventType_ROLLBACK VEventType = 4 + VEventType_DDL VEventType = 5 + VEventType_INSERT VEventType = 6 + VEventType_REPLACE VEventType = 7 + VEventType_UPDATE VEventType = 8 + VEventType_DELETE VEventType = 9 + VEventType_SET VEventType = 10 + VEventType_OTHER VEventType = 11 + VEventType_ROW VEventType = 12 + VEventType_FIELD VEventType = 13 + VEventType_HEARTBEAT VEventType = 14 ) var VEventType_name = map[int32]string{ @@ -88,29 +89,31 @@ var VEventType_name = map[int32]string{ 11: "OTHER", 12: "ROW", 13: "FIELD", + 14: "HEARTBEAT", } var VEventType_value = map[string]int32{ - "UNKNOWN": 0, - "GTID": 1, - "BEGIN": 2, - "COMMIT": 3, - "ROLLBACK": 4, - "DDL": 5, - "INSERT": 6, - "REPLACE": 7, - "UPDATE": 8, - "DELETE": 9, - "SET": 10, - "OTHER": 11, - "ROW": 12, - "FIELD": 13, + "UNKNOWN": 0, + "GTID": 1, + "BEGIN": 2, + "COMMIT": 3, + "ROLLBACK": 4, + "DDL": 5, + "INSERT": 6, + "REPLACE": 7, + "UPDATE": 8, + "DELETE": 9, + "SET": 10, + "OTHER": 11, + "ROW": 12, + "FIELD": 13, + "HEARTBEAT": 14, } func (x VEventType) String() string { return proto.EnumName(VEventType_name, int32(x)) } func (VEventType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{1} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{1} } type BinlogTransaction_Statement_Category int32 @@ -158,7 +161,7 @@ func (x BinlogTransaction_Statement_Category) String() string { return proto.EnumName(BinlogTransaction_Statement_Category_name, int32(x)) } func (BinlogTransaction_Statement_Category) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{1, 0, 0} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{1, 0, 0} } // Charset is the per-statement charset info from a QUERY_EVENT binlog entry. @@ -178,7 +181,7 @@ func (m *Charset) Reset() { *m = Charset{} } func (m *Charset) String() string { return proto.CompactTextString(m) } func (*Charset) ProtoMessage() {} func (*Charset) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{0} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{0} } func (m *Charset) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Charset.Unmarshal(m, b) @@ -235,7 +238,7 @@ func (m *BinlogTransaction) Reset() { *m = BinlogTransaction{} } func (m *BinlogTransaction) String() string { return proto.CompactTextString(m) } func (*BinlogTransaction) ProtoMessage() {} func (*BinlogTransaction) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{1} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{1} } func (m *BinlogTransaction) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BinlogTransaction.Unmarshal(m, b) @@ -285,7 +288,7 @@ func (m *BinlogTransaction_Statement) Reset() { *m = BinlogTransaction_S func (m *BinlogTransaction_Statement) String() string { return proto.CompactTextString(m) } func (*BinlogTransaction_Statement) ProtoMessage() {} func (*BinlogTransaction_Statement) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{1, 0} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{1, 0} } func (m *BinlogTransaction_Statement) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BinlogTransaction_Statement.Unmarshal(m, b) @@ -343,7 +346,7 @@ func (m *StreamKeyRangeRequest) Reset() { *m = StreamKeyRangeRequest{} } func (m *StreamKeyRangeRequest) String() string { return proto.CompactTextString(m) } func (*StreamKeyRangeRequest) ProtoMessage() {} func (*StreamKeyRangeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{2} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{2} } func (m *StreamKeyRangeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamKeyRangeRequest.Unmarshal(m, b) @@ -396,7 +399,7 @@ func (m *StreamKeyRangeResponse) Reset() { *m = StreamKeyRangeResponse{} func (m *StreamKeyRangeResponse) String() string { return proto.CompactTextString(m) } func (*StreamKeyRangeResponse) ProtoMessage() {} func (*StreamKeyRangeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{3} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{3} } func (m *StreamKeyRangeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamKeyRangeResponse.Unmarshal(m, b) @@ -440,7 +443,7 @@ func (m *StreamTablesRequest) Reset() { *m = StreamTablesRequest{} } func (m *StreamTablesRequest) String() string { return proto.CompactTextString(m) } func (*StreamTablesRequest) ProtoMessage() {} func (*StreamTablesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{4} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{4} } func (m *StreamTablesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamTablesRequest.Unmarshal(m, b) @@ -493,7 +496,7 @@ func (m *StreamTablesResponse) Reset() { *m = StreamTablesResponse{} } func (m *StreamTablesResponse) String() string { return proto.CompactTextString(m) } func (*StreamTablesResponse) ProtoMessage() {} func (*StreamTablesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{5} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{5} } func (m *StreamTablesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamTablesResponse.Unmarshal(m, b) @@ -538,7 +541,7 @@ func (m *Rule) Reset() { *m = Rule{} } func (m *Rule) String() string { return proto.CompactTextString(m) } func (*Rule) ProtoMessage() {} func (*Rule) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{6} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{6} } func (m *Rule) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Rule.Unmarshal(m, b) @@ -585,7 +588,7 @@ func (m *Filter) Reset() { *m = Filter{} } func (m *Filter) String() string { return proto.CompactTextString(m) } func (*Filter) ProtoMessage() {} func (*Filter) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{7} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{7} } func (m *Filter) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Filter.Unmarshal(m, b) @@ -640,7 +643,7 @@ func (m *BinlogSource) Reset() { *m = BinlogSource{} } func (m *BinlogSource) String() string { return proto.CompactTextString(m) } func (*BinlogSource) ProtoMessage() {} func (*BinlogSource) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{8} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{8} } func (m *BinlogSource) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BinlogSource.Unmarshal(m, b) @@ -722,7 +725,7 @@ func (m *RowChange) Reset() { *m = RowChange{} } func (m *RowChange) String() string { return proto.CompactTextString(m) } func (*RowChange) ProtoMessage() {} func (*RowChange) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{9} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{9} } func (m *RowChange) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RowChange.Unmarshal(m, b) @@ -769,7 +772,7 @@ func (m *RowEvent) Reset() { *m = RowEvent{} } func (m *RowEvent) String() string { return proto.CompactTextString(m) } func (*RowEvent) ProtoMessage() {} func (*RowEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{10} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{10} } func (m *RowEvent) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RowEvent.Unmarshal(m, b) @@ -815,7 +818,7 @@ func (m *FieldEvent) Reset() { *m = FieldEvent{} } func (m *FieldEvent) String() string { return proto.CompactTextString(m) } func (*FieldEvent) ProtoMessage() {} func (*FieldEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{11} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{11} } func (m *FieldEvent) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_FieldEvent.Unmarshal(m, b) @@ -851,22 +854,24 @@ func (m *FieldEvent) GetFields() []*query.Field { // VEvent represents a vstream event type VEvent struct { - Type VEventType `protobuf:"varint,1,opt,name=type,proto3,enum=binlogdata.VEventType" json:"type,omitempty"` - Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Gtid string `protobuf:"bytes,3,opt,name=gtid,proto3" json:"gtid,omitempty"` - Ddl string `protobuf:"bytes,4,opt,name=ddl,proto3" json:"ddl,omitempty"` - RowEvent *RowEvent `protobuf:"bytes,5,opt,name=row_event,json=rowEvent,proto3" json:"row_event,omitempty"` - FieldEvent *FieldEvent `protobuf:"bytes,6,opt,name=field_event,json=fieldEvent,proto3" json:"field_event,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Type VEventType `protobuf:"varint,1,opt,name=type,proto3,enum=binlogdata.VEventType" json:"type,omitempty"` + Timestamp int64 `protobuf:"varint,2,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Gtid string `protobuf:"bytes,3,opt,name=gtid,proto3" json:"gtid,omitempty"` + Ddl string `protobuf:"bytes,4,opt,name=ddl,proto3" json:"ddl,omitempty"` + RowEvent *RowEvent `protobuf:"bytes,5,opt,name=row_event,json=rowEvent,proto3" json:"row_event,omitempty"` + FieldEvent *FieldEvent `protobuf:"bytes,6,opt,name=field_event,json=fieldEvent,proto3" json:"field_event,omitempty"` + // current_time specifies the current time to handle clock skew. + CurrentTime int64 `protobuf:"varint,20,opt,name=current_time,json=currentTime,proto3" json:"current_time,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *VEvent) Reset() { *m = VEvent{} } func (m *VEvent) String() string { return proto.CompactTextString(m) } func (*VEvent) ProtoMessage() {} func (*VEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{12} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{12} } func (m *VEvent) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VEvent.Unmarshal(m, b) @@ -928,6 +933,13 @@ func (m *VEvent) GetFieldEvent() *FieldEvent { return nil } +func (m *VEvent) GetCurrentTime() int64 { + if m != nil { + return m.CurrentTime + } + return 0 +} + // VStreamRequest is the payload for VStream type VStreamRequest struct { EffectiveCallerId *vtrpc.CallerID `protobuf:"bytes,1,opt,name=effective_caller_id,json=effectiveCallerId,proto3" json:"effective_caller_id,omitempty"` @@ -944,7 +956,7 @@ func (m *VStreamRequest) Reset() { *m = VStreamRequest{} } func (m *VStreamRequest) String() string { return proto.CompactTextString(m) } func (*VStreamRequest) ProtoMessage() {} func (*VStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{13} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{13} } func (m *VStreamRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VStreamRequest.Unmarshal(m, b) @@ -1011,7 +1023,7 @@ func (m *VStreamResponse) Reset() { *m = VStreamResponse{} } func (m *VStreamResponse) String() string { return proto.CompactTextString(m) } func (*VStreamResponse) ProtoMessage() {} func (*VStreamResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_binlogdata_6d214635eb8c538c, []int{14} + return fileDescriptor_binlogdata_60517ed2deb82a7b, []int{14} } func (m *VStreamResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VStreamResponse.Unmarshal(m, b) @@ -1060,82 +1072,84 @@ func init() { proto.RegisterEnum("binlogdata.BinlogTransaction_Statement_Category", BinlogTransaction_Statement_Category_name, BinlogTransaction_Statement_Category_value) } -func init() { proto.RegisterFile("binlogdata.proto", fileDescriptor_binlogdata_6d214635eb8c538c) } - -var fileDescriptor_binlogdata_6d214635eb8c538c = []byte{ - // 1184 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x5b, 0x6e, 0xdb, 0x56, - 0x13, 0x8e, 0x44, 0x8a, 0x12, 0x87, 0x8e, 0x4d, 0x1f, 0x5f, 0x7e, 0xc1, 0xf8, 0x03, 0x18, 0x44, - 0xdb, 0xb8, 0x06, 0x2a, 0xa7, 0xea, 0xed, 0xa9, 0x2d, 0x2c, 0x91, 0x71, 0x95, 0xd0, 0x92, 0x73, - 0xcc, 0x24, 0x45, 0x5e, 0x08, 0x9a, 0x3c, 0xb2, 0x09, 0x53, 0xa4, 0x4c, 0x1e, 0xcb, 0xd5, 0x0a, - 0xba, 0x80, 0xbe, 0x76, 0x03, 0xed, 0x42, 0xba, 0x92, 0x76, 0x1f, 0xc5, 0xb9, 0x90, 0x92, 0x1c, - 0xa0, 0x71, 0x1f, 0xfa, 0x36, 0xf7, 0x33, 0xf3, 0xcd, 0x70, 0x86, 0x60, 0x5e, 0xc4, 0x69, 0x92, - 0x5d, 0x46, 0x01, 0x0d, 0x3a, 0xd3, 0x3c, 0xa3, 0x19, 0x82, 0x85, 0x64, 0xcf, 0x98, 0xd1, 0x7c, - 0x1a, 0x0a, 0xc5, 0x9e, 0x71, 0x73, 0x4b, 0xf2, 0xb9, 0x64, 0xd6, 0x69, 0x36, 0xcd, 0x16, 0x5e, - 0xd6, 0x29, 0x34, 0xfb, 0x57, 0x41, 0x5e, 0x10, 0x8a, 0x76, 0x41, 0x0b, 0x93, 0x98, 0xa4, 0xb4, - 0x5d, 0xdb, 0xaf, 0x1d, 0x34, 0xb0, 0xe4, 0x10, 0x02, 0x35, 0xcc, 0xd2, 0xb4, 0x5d, 0xe7, 0x52, - 0x4e, 0x33, 0xdb, 0x82, 0xe4, 0x33, 0x92, 0xb7, 0x15, 0x61, 0x2b, 0x38, 0xeb, 0x2f, 0x05, 0x36, - 0x7b, 0x3c, 0x0f, 0x2f, 0x0f, 0xd2, 0x22, 0x08, 0x69, 0x9c, 0xa5, 0xe8, 0x04, 0xa0, 0xa0, 0x01, - 0x25, 0x13, 0x92, 0xd2, 0xa2, 0x5d, 0xdb, 0x57, 0x0e, 0x8c, 0xee, 0xd3, 0xce, 0x52, 0x05, 0xef, - 0xb9, 0x74, 0xce, 0x4b, 0x7b, 0xbc, 0xe4, 0x8a, 0xba, 0x60, 0x90, 0x19, 0x49, 0xa9, 0x4f, 0xb3, - 0x6b, 0x92, 0xb6, 0xd5, 0xfd, 0xda, 0x81, 0xd1, 0xdd, 0xec, 0x88, 0x02, 0x1d, 0xa6, 0xf1, 0x98, - 0x02, 0x03, 0xa9, 0xe8, 0xbd, 0x3f, 0xea, 0xa0, 0x57, 0xd1, 0x90, 0x0b, 0xad, 0x30, 0xa0, 0xe4, - 0x32, 0xcb, 0xe7, 0xbc, 0xcc, 0xf5, 0xee, 0xb3, 0x07, 0x26, 0xd2, 0xe9, 0x4b, 0x3f, 0x5c, 0x45, - 0x40, 0x9f, 0x41, 0x33, 0x14, 0xe8, 0x71, 0x74, 0x8c, 0xee, 0xd6, 0x72, 0x30, 0x09, 0x2c, 0x2e, - 0x6d, 0x90, 0x09, 0x4a, 0x71, 0x93, 0x70, 0xc8, 0xd6, 0x30, 0x23, 0xad, 0xdf, 0x6a, 0xd0, 0x2a, - 0xe3, 0xa2, 0x2d, 0xd8, 0xe8, 0xb9, 0xfe, 0xeb, 0x21, 0x76, 0xfa, 0xa3, 0x93, 0xe1, 0xe0, 0x9d, - 0x63, 0x9b, 0x8f, 0xd0, 0x1a, 0xb4, 0x7a, 0xae, 0xdf, 0x73, 0x4e, 0x06, 0x43, 0xb3, 0x86, 0x1e, - 0x83, 0xde, 0x73, 0xfd, 0xfe, 0xe8, 0xf4, 0x74, 0xe0, 0x99, 0x75, 0xb4, 0x01, 0x46, 0xcf, 0xf5, - 0xf1, 0xc8, 0x75, 0x7b, 0xc7, 0xfd, 0x97, 0xa6, 0x82, 0x76, 0x60, 0xb3, 0xe7, 0xfa, 0xf6, 0xa9, - 0xeb, 0xdb, 0xce, 0x19, 0x76, 0xfa, 0xc7, 0x9e, 0x63, 0x9b, 0x2a, 0x02, 0xd0, 0x98, 0xd8, 0x76, - 0xcd, 0x86, 0xa4, 0xcf, 0x1d, 0xcf, 0xd4, 0x64, 0xb8, 0xc1, 0xf0, 0xdc, 0xc1, 0x9e, 0xd9, 0x94, - 0xec, 0xeb, 0x33, 0xfb, 0xd8, 0x73, 0xcc, 0x96, 0x64, 0x6d, 0xc7, 0x75, 0x3c, 0xc7, 0xd4, 0x5f, - 0xa8, 0xad, 0xba, 0xa9, 0xbc, 0x50, 0x5b, 0x8a, 0xa9, 0x5a, 0xbf, 0xd4, 0x60, 0xe7, 0x9c, 0xe6, - 0x24, 0x98, 0xbc, 0x24, 0x73, 0x1c, 0xa4, 0x97, 0x04, 0x93, 0x9b, 0x5b, 0x52, 0x50, 0xb4, 0x07, - 0xad, 0x69, 0x56, 0xc4, 0x0c, 0x3b, 0x0e, 0xb0, 0x8e, 0x2b, 0x1e, 0x1d, 0x81, 0x7e, 0x4d, 0xe6, - 0x7e, 0xce, 0xec, 0x25, 0x60, 0xa8, 0x53, 0x0d, 0x64, 0x15, 0xa9, 0x75, 0x2d, 0xa9, 0x65, 0x7c, - 0x95, 0x0f, 0xe3, 0x6b, 0x8d, 0x61, 0xf7, 0x7e, 0x52, 0xc5, 0x34, 0x4b, 0x0b, 0x82, 0x5c, 0x40, - 0xc2, 0xd1, 0xa7, 0x8b, 0xde, 0xf2, 0xfc, 0x8c, 0xee, 0x93, 0x7f, 0x1c, 0x00, 0xbc, 0x79, 0x71, - 0x5f, 0x64, 0xfd, 0x04, 0x5b, 0xe2, 0x1d, 0x2f, 0xb8, 0x48, 0x48, 0xf1, 0x90, 0xd2, 0x77, 0x41, - 0xa3, 0xdc, 0xb8, 0x5d, 0xdf, 0x57, 0x0e, 0x74, 0x2c, 0xb9, 0x7f, 0x5b, 0x61, 0x04, 0xdb, 0xab, - 0x2f, 0xff, 0x27, 0xf5, 0x7d, 0x09, 0x2a, 0xbe, 0x4d, 0x08, 0xda, 0x86, 0xc6, 0x24, 0xa0, 0xe1, - 0x95, 0xac, 0x46, 0x30, 0xac, 0x94, 0x71, 0x9c, 0x50, 0x92, 0xf3, 0x16, 0xea, 0x58, 0x72, 0xd6, - 0x33, 0xd0, 0x9e, 0x73, 0x0a, 0x7d, 0x02, 0x8d, 0xfc, 0x96, 0xd5, 0x2a, 0x3e, 0x75, 0x73, 0x39, - 0x01, 0x16, 0x18, 0x0b, 0xb5, 0xf5, 0x6b, 0x1d, 0xd6, 0x44, 0x42, 0xe7, 0xd9, 0x6d, 0x1e, 0x12, - 0x86, 0xe0, 0x35, 0x99, 0x17, 0xd3, 0x20, 0x24, 0x25, 0x82, 0x25, 0xcf, 0x92, 0x29, 0xae, 0x82, - 0x3c, 0x92, 0xaf, 0x0a, 0x06, 0x7d, 0x05, 0x06, 0x47, 0x92, 0xfa, 0x74, 0x3e, 0x25, 0x1c, 0xc3, - 0xf5, 0xee, 0xf6, 0x62, 0xa8, 0x38, 0x4e, 0xd4, 0x9b, 0x4f, 0x09, 0x06, 0x5a, 0xd1, 0xab, 0x93, - 0xa8, 0x3e, 0x60, 0x12, 0x17, 0xfd, 0x6b, 0xac, 0xf4, 0xef, 0xb0, 0x02, 0x43, 0x93, 0x51, 0x96, - 0x6a, 0x15, 0x70, 0x94, 0x00, 0xa1, 0x0e, 0x68, 0x59, 0xea, 0x47, 0x51, 0xd2, 0x6e, 0xf2, 0x34, - 0xff, 0xb7, 0x6c, 0x3b, 0x4a, 0x6d, 0xdb, 0x3d, 0x16, 0x2d, 0x69, 0x64, 0xa9, 0x1d, 0x25, 0xd6, - 0x2b, 0xd0, 0x71, 0x76, 0xd7, 0xbf, 0xe2, 0x09, 0x58, 0xa0, 0x5d, 0x90, 0x71, 0x96, 0x13, 0xd9, - 0x55, 0x90, 0x5b, 0x0f, 0x67, 0x77, 0x58, 0x6a, 0xd0, 0x3e, 0x34, 0x82, 0x71, 0xd9, 0x98, 0x55, - 0x13, 0xa1, 0xb0, 0x02, 0x68, 0xe1, 0xec, 0x8e, 0x6f, 0x4a, 0xf4, 0x04, 0x04, 0x22, 0x7e, 0x1a, - 0x4c, 0x4a, 0xb8, 0x75, 0x2e, 0x19, 0x06, 0x13, 0x82, 0xbe, 0x06, 0x23, 0xcf, 0xee, 0xfc, 0x90, - 0x3f, 0x2f, 0xc6, 0xd6, 0xe8, 0xee, 0xac, 0xb4, 0xb2, 0x4c, 0x0e, 0x43, 0x5e, 0x92, 0x85, 0xf5, - 0x0a, 0xe0, 0x79, 0x4c, 0x92, 0xe8, 0x41, 0x8f, 0x7c, 0xc4, 0xe0, 0x23, 0x49, 0x54, 0xc6, 0x5f, - 0x93, 0x29, 0xf3, 0x08, 0x58, 0xea, 0xac, 0x3f, 0x6b, 0xa0, 0xbd, 0x11, 0xf1, 0x0e, 0x41, 0xe5, - 0x8d, 0x16, 0xbb, 0x7b, 0x77, 0x39, 0x1d, 0x61, 0xc1, 0x5b, 0xcd, 0x6d, 0xd0, 0xff, 0x41, 0xa7, - 0xf1, 0x84, 0x14, 0x34, 0x98, 0x4c, 0x39, 0x24, 0x0a, 0x5e, 0x08, 0xd8, 0x59, 0xbb, 0xa4, 0x71, - 0xc4, 0x47, 0x46, 0xc7, 0x9c, 0x66, 0x0b, 0x9a, 0xb5, 0x47, 0xe5, 0x22, 0x46, 0xa2, 0xcf, 0x41, - 0x67, 0x28, 0xf0, 0x7b, 0xd2, 0x6e, 0x70, 0x58, 0xb7, 0xef, 0x61, 0xc0, 0x9f, 0xc5, 0xad, 0xbc, - 0xc4, 0xf5, 0x1b, 0x30, 0x78, 0xde, 0xd2, 0x49, 0xcc, 0xc5, 0xee, 0xea, 0x5c, 0x94, 0xf8, 0x60, - 0x18, 0x57, 0xb4, 0xf5, 0x73, 0x1d, 0xd6, 0xdf, 0x88, 0xcf, 0xbb, 0x5c, 0x29, 0xdf, 0xc3, 0x16, - 0x19, 0x8f, 0x49, 0x48, 0xe3, 0x19, 0xf1, 0xc3, 0x20, 0x49, 0x48, 0xee, 0xc7, 0x91, 0x1c, 0x81, - 0x8d, 0x8e, 0x38, 0xf3, 0x7d, 0x2e, 0x1f, 0xd8, 0x78, 0xb3, 0xb2, 0x95, 0xa2, 0x08, 0x39, 0xb0, - 0x15, 0x4f, 0x26, 0x24, 0x8a, 0x03, 0xba, 0x1c, 0x40, 0x0c, 0xc8, 0x8e, 0x44, 0xfb, 0x8d, 0x77, - 0x12, 0x50, 0xb2, 0x08, 0x53, 0x79, 0x54, 0x61, 0x3e, 0x66, 0xe3, 0x9f, 0x5f, 0x56, 0x5b, 0xea, - 0xb1, 0xf4, 0xf4, 0xb8, 0x10, 0x4b, 0xe5, 0xca, 0x06, 0x54, 0xef, 0x6d, 0xc0, 0xc5, 0x97, 0xd2, - 0xf8, 0xd0, 0x97, 0x62, 0x7d, 0x0b, 0x1b, 0x15, 0x10, 0x72, 0xc3, 0x1d, 0x82, 0xc6, 0xf1, 0x2c, - 0x97, 0x0a, 0x7a, 0xbf, 0xf5, 0x58, 0x5a, 0x1c, 0x7e, 0x07, 0xc6, 0xd2, 0xe7, 0xc4, 0x2e, 0xde, - 0xe0, 0x64, 0x38, 0xc2, 0x8e, 0xf9, 0x08, 0xb5, 0x40, 0x3d, 0xf7, 0x46, 0x67, 0x66, 0x8d, 0x51, - 0xce, 0x8f, 0x4e, 0x5f, 0x5c, 0x51, 0x46, 0xf9, 0xd2, 0x48, 0x39, 0xfc, 0xbd, 0x06, 0xb0, 0x98, - 0x26, 0x64, 0x40, 0xf3, 0xf5, 0xf0, 0xe5, 0x70, 0xf4, 0x76, 0x28, 0x02, 0x9c, 0x78, 0x03, 0xdb, - 0xac, 0x21, 0x1d, 0x1a, 0xe2, 0x2c, 0xd7, 0xd9, 0x0b, 0xf2, 0x26, 0x2b, 0xec, 0x60, 0x57, 0x07, - 0x59, 0x45, 0x4d, 0x50, 0xaa, 0xb3, 0x2b, 0xef, 0xac, 0xc6, 0x02, 0x62, 0xe7, 0xcc, 0x3d, 0xee, - 0x3b, 0x66, 0x93, 0x29, 0xaa, 0x8b, 0x0b, 0xa0, 0x95, 0xe7, 0x96, 0x79, 0xb2, 0x23, 0x0d, 0xec, - 0x9d, 0x91, 0xf7, 0x83, 0x83, 0x4d, 0x83, 0xc9, 0xf0, 0xe8, 0xad, 0xb9, 0xc6, 0x64, 0xcf, 0x07, - 0x8e, 0x6b, 0x9b, 0x8f, 0x7b, 0x9f, 0xbe, 0x7b, 0x3a, 0x8b, 0x29, 0x29, 0x8a, 0x4e, 0x9c, 0x1d, - 0x09, 0xea, 0xe8, 0x32, 0x3b, 0x9a, 0xd1, 0x23, 0xfe, 0x87, 0x77, 0xb4, 0x80, 0xe9, 0x42, 0xe3, - 0x92, 0x2f, 0xfe, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x68, 0xbd, 0x20, 0x05, 0x3d, 0x0a, 0x00, 0x00, +func init() { proto.RegisterFile("binlogdata.proto", fileDescriptor_binlogdata_60517ed2deb82a7b) } + +var fileDescriptor_binlogdata_60517ed2deb82a7b = []byte{ + // 1215 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0x5d, 0x6e, 0xdb, 0x46, + 0x10, 0x8e, 0x44, 0x8a, 0x12, 0x87, 0x8e, 0x4d, 0xaf, 0x7f, 0x2a, 0x18, 0x0d, 0xe0, 0x12, 0x6d, + 0xe3, 0x1a, 0xa8, 0x9c, 0xaa, 0x7f, 0x4f, 0x6d, 0x21, 0x89, 0x8c, 0xa3, 0x84, 0x96, 0x9c, 0x35, + 0x93, 0x14, 0x79, 0x21, 0x68, 0x72, 0x65, 0x13, 0xa6, 0x48, 0x85, 0x5c, 0xdb, 0xd5, 0x09, 0x7a, + 0x80, 0xbe, 0xf6, 0x02, 0x3d, 0x42, 0x2f, 0xd0, 0x9b, 0xf4, 0x1e, 0xc5, 0xfe, 0x90, 0x92, 0x1c, + 0xa0, 0x71, 0x1f, 0xfa, 0x36, 0xff, 0x3b, 0xf3, 0xcd, 0x70, 0x86, 0x60, 0x9e, 0xc7, 0x69, 0x92, + 0x5d, 0x44, 0x01, 0x0d, 0x3a, 0xb3, 0x3c, 0xa3, 0x19, 0x82, 0x85, 0x64, 0xcf, 0xb8, 0xa1, 0xf9, + 0x2c, 0x14, 0x8a, 0x3d, 0xe3, 0xdd, 0x35, 0xc9, 0xe7, 0x92, 0x59, 0xa7, 0xd9, 0x2c, 0x5b, 0x78, + 0x59, 0x27, 0xd0, 0x1c, 0x5c, 0x06, 0x79, 0x41, 0x28, 0xda, 0x05, 0x2d, 0x4c, 0x62, 0x92, 0xd2, + 0x76, 0x6d, 0xbf, 0x76, 0xd0, 0xc0, 0x92, 0x43, 0x08, 0xd4, 0x30, 0x4b, 0xd3, 0x76, 0x9d, 0x4b, + 0x39, 0xcd, 0x6c, 0x0b, 0x92, 0xdf, 0x90, 0xbc, 0xad, 0x08, 0x5b, 0xc1, 0x59, 0x7f, 0x2b, 0xb0, + 0xd9, 0xe7, 0x79, 0x78, 0x79, 0x90, 0x16, 0x41, 0x48, 0xe3, 0x2c, 0x45, 0xc7, 0x00, 0x05, 0x0d, + 0x28, 0x99, 0x92, 0x94, 0x16, 0xed, 0xda, 0xbe, 0x72, 0x60, 0x74, 0x1f, 0x77, 0x96, 0x2a, 0x78, + 0xcf, 0xa5, 0x73, 0x56, 0xda, 0xe3, 0x25, 0x57, 0xd4, 0x05, 0x83, 0xdc, 0x90, 0x94, 0xfa, 0x34, + 0xbb, 0x22, 0x69, 0x5b, 0xdd, 0xaf, 0x1d, 0x18, 0xdd, 0xcd, 0x8e, 0x28, 0xd0, 0x61, 0x1a, 0x8f, + 0x29, 0x30, 0x90, 0x8a, 0xde, 0xfb, 0xab, 0x0e, 0x7a, 0x15, 0x0d, 0xb9, 0xd0, 0x0a, 0x03, 0x4a, + 0x2e, 0xb2, 0x7c, 0xce, 0xcb, 0x5c, 0xef, 0x3e, 0xb9, 0x67, 0x22, 0x9d, 0x81, 0xf4, 0xc3, 0x55, + 0x04, 0xf4, 0x25, 0x34, 0x43, 0x81, 0x1e, 0x47, 0xc7, 0xe8, 0x6e, 0x2d, 0x07, 0x93, 0xc0, 0xe2, + 0xd2, 0x06, 0x99, 0xa0, 0x14, 0xef, 0x12, 0x0e, 0xd9, 0x1a, 0x66, 0xa4, 0xf5, 0x47, 0x0d, 0x5a, + 0x65, 0x5c, 0xb4, 0x05, 0x1b, 0x7d, 0xd7, 0x7f, 0x35, 0xc2, 0xce, 0x60, 0x7c, 0x3c, 0x1a, 0xbe, + 0x75, 0x6c, 0xf3, 0x01, 0x5a, 0x83, 0x56, 0xdf, 0xf5, 0xfb, 0xce, 0xf1, 0x70, 0x64, 0xd6, 0xd0, + 0x43, 0xd0, 0xfb, 0xae, 0x3f, 0x18, 0x9f, 0x9c, 0x0c, 0x3d, 0xb3, 0x8e, 0x36, 0xc0, 0xe8, 0xbb, + 0x3e, 0x1e, 0xbb, 0x6e, 0xbf, 0x37, 0x78, 0x61, 0x2a, 0x68, 0x07, 0x36, 0xfb, 0xae, 0x6f, 0x9f, + 0xb8, 0xbe, 0xed, 0x9c, 0x62, 0x67, 0xd0, 0xf3, 0x1c, 0xdb, 0x54, 0x11, 0x80, 0xc6, 0xc4, 0xb6, + 0x6b, 0x36, 0x24, 0x7d, 0xe6, 0x78, 0xa6, 0x26, 0xc3, 0x0d, 0x47, 0x67, 0x0e, 0xf6, 0xcc, 0xa6, + 0x64, 0x5f, 0x9d, 0xda, 0x3d, 0xcf, 0x31, 0x5b, 0x92, 0xb5, 0x1d, 0xd7, 0xf1, 0x1c, 0x53, 0x7f, + 0xae, 0xb6, 0xea, 0xa6, 0xf2, 0x5c, 0x6d, 0x29, 0xa6, 0x6a, 0xfd, 0x56, 0x83, 0x9d, 0x33, 0x9a, + 0x93, 0x60, 0xfa, 0x82, 0xcc, 0x71, 0x90, 0x5e, 0x10, 0x4c, 0xde, 0x5d, 0x93, 0x82, 0xa2, 0x3d, + 0x68, 0xcd, 0xb2, 0x22, 0x66, 0xd8, 0x71, 0x80, 0x75, 0x5c, 0xf1, 0xe8, 0x08, 0xf4, 0x2b, 0x32, + 0xf7, 0x73, 0x66, 0x2f, 0x01, 0x43, 0x9d, 0x6a, 0x20, 0xab, 0x48, 0xad, 0x2b, 0x49, 0x2d, 0xe3, + 0xab, 0x7c, 0x18, 0x5f, 0x6b, 0x02, 0xbb, 0x77, 0x93, 0x2a, 0x66, 0x59, 0x5a, 0x10, 0xe4, 0x02, + 0x12, 0x8e, 0x3e, 0x5d, 0xf4, 0x96, 0xe7, 0x67, 0x74, 0x1f, 0xfd, 0xeb, 0x00, 0xe0, 0xcd, 0xf3, + 0xbb, 0x22, 0xeb, 0x17, 0xd8, 0x12, 0xef, 0x78, 0xc1, 0x79, 0x42, 0x8a, 0xfb, 0x94, 0xbe, 0x0b, + 0x1a, 0xe5, 0xc6, 0xed, 0xfa, 0xbe, 0x72, 0xa0, 0x63, 0xc9, 0xfd, 0xd7, 0x0a, 0x23, 0xd8, 0x5e, + 0x7d, 0xf9, 0x7f, 0xa9, 0xef, 0x1b, 0x50, 0xf1, 0x75, 0x42, 0xd0, 0x36, 0x34, 0xa6, 0x01, 0x0d, + 0x2f, 0x65, 0x35, 0x82, 0x61, 0xa5, 0x4c, 0xe2, 0x84, 0x92, 0x9c, 0xb7, 0x50, 0xc7, 0x92, 0xb3, + 0x9e, 0x80, 0xf6, 0x94, 0x53, 0xe8, 0x73, 0x68, 0xe4, 0xd7, 0xac, 0x56, 0xf1, 0xa9, 0x9b, 0xcb, + 0x09, 0xb0, 0xc0, 0x58, 0xa8, 0xad, 0xdf, 0xeb, 0xb0, 0x26, 0x12, 0x3a, 0xcb, 0xae, 0xf3, 0x90, + 0x30, 0x04, 0xaf, 0xc8, 0xbc, 0x98, 0x05, 0x21, 0x29, 0x11, 0x2c, 0x79, 0x96, 0x4c, 0x71, 0x19, + 0xe4, 0x91, 0x7c, 0x55, 0x30, 0xe8, 0x5b, 0x30, 0x38, 0x92, 0xd4, 0xa7, 0xf3, 0x19, 0xe1, 0x18, + 0xae, 0x77, 0xb7, 0x17, 0x43, 0xc5, 0x71, 0xa2, 0xde, 0x7c, 0x46, 0x30, 0xd0, 0x8a, 0x5e, 0x9d, + 0x44, 0xf5, 0x1e, 0x93, 0xb8, 0xe8, 0x5f, 0x63, 0xa5, 0x7f, 0x87, 0x15, 0x18, 0x9a, 0x8c, 0xb2, + 0x54, 0xab, 0x80, 0xa3, 0x04, 0x08, 0x75, 0x40, 0xcb, 0x52, 0x3f, 0x8a, 0x92, 0x76, 0x93, 0xa7, + 0xf9, 0xd1, 0xb2, 0xed, 0x38, 0xb5, 0x6d, 0xb7, 0x27, 0x5a, 0xd2, 0xc8, 0x52, 0x3b, 0x4a, 0xac, + 0x97, 0xa0, 0xe3, 0xec, 0x76, 0x70, 0xc9, 0x13, 0xb0, 0x40, 0x3b, 0x27, 0x93, 0x2c, 0x27, 0xb2, + 0xab, 0x20, 0xb7, 0x1e, 0xce, 0x6e, 0xb1, 0xd4, 0xa0, 0x7d, 0x68, 0x04, 0x93, 0xb2, 0x31, 0xab, + 0x26, 0x42, 0x61, 0x05, 0xd0, 0xc2, 0xd9, 0x2d, 0xdf, 0x94, 0xe8, 0x11, 0x08, 0x44, 0xfc, 0x34, + 0x98, 0x96, 0x70, 0xeb, 0x5c, 0x32, 0x0a, 0xa6, 0x04, 0x7d, 0x07, 0x46, 0x9e, 0xdd, 0xfa, 0x21, + 0x7f, 0x5e, 0x8c, 0xad, 0xd1, 0xdd, 0x59, 0x69, 0x65, 0x99, 0x1c, 0x86, 0xbc, 0x24, 0x0b, 0xeb, + 0x25, 0xc0, 0xd3, 0x98, 0x24, 0xd1, 0xbd, 0x1e, 0xf9, 0x94, 0xc1, 0x47, 0x92, 0xa8, 0x8c, 0xbf, + 0x26, 0x53, 0xe6, 0x11, 0xb0, 0xd4, 0x59, 0xbf, 0xd6, 0x41, 0x7b, 0x2d, 0xe2, 0x1d, 0x82, 0xca, + 0x1b, 0x2d, 0x76, 0xf7, 0xee, 0x72, 0x3a, 0xc2, 0x82, 0xb7, 0x9a, 0xdb, 0xa0, 0x8f, 0x41, 0xa7, + 0xf1, 0x94, 0x14, 0x34, 0x98, 0xce, 0x38, 0x24, 0x0a, 0x5e, 0x08, 0xd8, 0x59, 0xbb, 0xa0, 0x71, + 0xc4, 0x47, 0x46, 0xc7, 0x9c, 0x66, 0x0b, 0x9a, 0xb5, 0x47, 0xe5, 0x22, 0x46, 0xa2, 0xaf, 0x40, + 0x67, 0x28, 0xf0, 0x7b, 0xd2, 0x6e, 0x70, 0x58, 0xb7, 0xef, 0x60, 0xc0, 0x9f, 0xc5, 0xad, 0xbc, + 0xc4, 0xf5, 0x7b, 0x30, 0x78, 0xde, 0xd2, 0x49, 0xcc, 0xc5, 0xee, 0xea, 0x5c, 0x94, 0xf8, 0x60, + 0x98, 0x2c, 0xb0, 0xfa, 0x04, 0xd6, 0xc2, 0xeb, 0x3c, 0xe7, 0xf7, 0x2d, 0x9e, 0x92, 0xf6, 0x36, + 0x4f, 0xd9, 0x90, 0x32, 0x2f, 0x9e, 0x12, 0x86, 0xc4, 0xfa, 0x6b, 0xb1, 0x01, 0xca, 0xad, 0xf3, + 0x13, 0x6c, 0x91, 0xc9, 0x84, 0x84, 0x34, 0xbe, 0x21, 0x7e, 0x18, 0x24, 0x09, 0xc9, 0xfd, 0x38, + 0x92, 0x53, 0xb2, 0xd1, 0x11, 0x7f, 0x02, 0x03, 0x2e, 0x1f, 0xda, 0x78, 0xb3, 0xb2, 0x95, 0xa2, + 0x08, 0x39, 0xb0, 0x15, 0x4f, 0xa7, 0x24, 0x8a, 0x03, 0xba, 0x1c, 0x40, 0xcc, 0xd0, 0x8e, 0x6c, + 0xc8, 0x6b, 0xef, 0x38, 0xa0, 0x64, 0x11, 0xa6, 0xf2, 0xa8, 0xc2, 0x7c, 0xc6, 0xbe, 0x90, 0xfc, + 0xa2, 0x5a, 0x64, 0x0f, 0xa5, 0xa7, 0xc7, 0x85, 0x58, 0x2a, 0x57, 0x96, 0xa4, 0x7a, 0x67, 0x49, + 0x2e, 0x3e, 0xa6, 0xc6, 0x87, 0x3e, 0x26, 0xeb, 0x07, 0xd8, 0xa8, 0x80, 0x90, 0x4b, 0xf0, 0x10, + 0x34, 0x0e, 0x79, 0xb9, 0x77, 0xd0, 0xfb, 0xd3, 0x81, 0xa5, 0xc5, 0xe1, 0x8f, 0x60, 0x2c, 0x7d, + 0x71, 0xec, 0x28, 0x0e, 0x8f, 0x47, 0x63, 0xec, 0x98, 0x0f, 0x50, 0x0b, 0xd4, 0x33, 0x6f, 0x7c, + 0x6a, 0xd6, 0x18, 0xe5, 0xfc, 0xec, 0x0c, 0xc4, 0xa1, 0x65, 0x94, 0x2f, 0x8d, 0x94, 0xc3, 0x3f, + 0x6b, 0x00, 0x8b, 0x81, 0x43, 0x06, 0x34, 0x5f, 0x8d, 0x5e, 0x8c, 0xc6, 0x6f, 0x46, 0x22, 0xc0, + 0xb1, 0x37, 0xb4, 0xcd, 0x1a, 0xd2, 0xa1, 0x21, 0x2e, 0x77, 0x9d, 0xbd, 0x20, 0xcf, 0xb6, 0xc2, + 0x6e, 0x7a, 0x75, 0xb3, 0x55, 0xd4, 0x04, 0xa5, 0xba, 0xcc, 0xf2, 0x14, 0x6b, 0x2c, 0x20, 0x76, + 0x4e, 0xdd, 0xde, 0xc0, 0x31, 0x9b, 0x4c, 0x51, 0x1d, 0x65, 0x00, 0xad, 0xbc, 0xc8, 0xcc, 0x93, + 0xdd, 0x71, 0x60, 0xef, 0x8c, 0xbd, 0x67, 0x0e, 0x36, 0x0d, 0x26, 0xc3, 0xe3, 0x37, 0xe6, 0x1a, + 0x93, 0x3d, 0x1d, 0x3a, 0xae, 0x6d, 0x3e, 0x64, 0x87, 0xfc, 0x99, 0xd3, 0xc3, 0x5e, 0xdf, 0xe9, + 0x79, 0xe6, 0x7a, 0xff, 0x8b, 0xb7, 0x8f, 0x6f, 0x62, 0x4a, 0x8a, 0xa2, 0x13, 0x67, 0x47, 0x82, + 0x3a, 0xba, 0xc8, 0x8e, 0x6e, 0xe8, 0x11, 0xff, 0x27, 0x3c, 0x5a, 0xa0, 0x76, 0xae, 0x71, 0xc9, + 0xd7, 0xff, 0x04, 0x00, 0x00, 0xff, 0xff, 0x0e, 0xe3, 0x8a, 0xa5, 0x6f, 0x0a, 0x00, 0x00, } diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index f8a0520d868..a181bcf8569 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -39,7 +39,10 @@ import ( ) var ( - idleTimeout = 1 * time.Second + // idleTimeout is set to slightly above 1s, compared to heartbeatTime + // set by VStreamer at slightly below 1s. This minimizes conflicts + // between the two timeouts. + idleTimeout = 1100 * time.Millisecond dbLockRetryDelay = 1 * time.Second relayLogMaxSize = 10000 relayLogMaxItems = 1000 @@ -61,7 +64,11 @@ type vplayer struct { unsavedGTID *binlogdatapb.VEvent // timeLastSaved is set every time a GTID is saved. timeLastSaved time.Time - stopPos mysql.Position + // lastTimestampNs is the last timestamp seen so far. + lastTimestampNs int64 + // timeOffsetNs keeps track of the time offset w.r.t. source tablet. + timeOffsetNs int64 + stopPos mysql.Position // pplan is built based on the source Filter at the beginning. pplan *PlayerPlan @@ -197,6 +204,11 @@ func (vp *vplayer) applyEvents(ctx context.Context, relay *relayLog) error { if err != nil { return err } + // No events were received. Update SecondsBehindMaster. + if len(items) == 0 { + behind := time.Now().UnixNano() - vp.lastTimestampNs - vp.timeOffsetNs + vp.stats.SecondsBehindMaster.Set(behind / 1e9) + } // Filtered replication often ends up receiving a large number of empty transactions. // This is required because the player needs to know the latest position of the source. // This allows it to stop at that position if requested. @@ -221,6 +233,11 @@ func (vp *vplayer) applyEvents(ctx context.Context, relay *relayLog) error { } for i, events := range items { for j, event := range events { + if event.Timestamp != 0 { + vp.lastTimestampNs = event.Timestamp * 1e9 + vp.timeOffsetNs = time.Now().UnixNano() - event.CurrentTime + vp.stats.SecondsBehindMaster.Set(event.CurrentTime/1e9 - event.Timestamp) + } mustSave := false switch event.Type { case binlogdatapb.VEventType_COMMIT: @@ -354,6 +371,8 @@ func (vp *vplayer) applyEvent(ctx context.Context, event *binlogdatapb.VEvent, m return err } } + case binlogdatapb.VEventType_HEARTBEAT: + // No-op: heartbeat timings are calculated in outer loop. } return nil } @@ -444,9 +463,6 @@ func (vp *vplayer) updatePos(ts int64) error { vp.unsavedGTID = nil vp.timeLastSaved = time.Now() vp.stats.SetLastPosition(vp.pos) - if ts != 0 { - vp.stats.SecondsBehindMaster.Set(vp.timeLastSaved.Unix() - ts) - } return nil } diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go index 4bf378d9f81..6923e0c8b04 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer.go @@ -21,6 +21,7 @@ import ( "flag" "fmt" "io" + "time" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" @@ -36,6 +37,11 @@ import ( var packetSize = flag.Int("vstream_packet_size", 10000, "Suggested packet size for VReplication streamer. This is used only as a recommendation. The actual packet size may be more or less than this amount.") +// heartbeatTime is set to slightly below 1s, compared to idleTimeout +// set by VPlayer at slightly above 1s. This minimizes conflicts +// between the two timeouts. +var heartbeatTime = 900 * time.Millisecond + type vstreamer struct { ctx context.Context cancel func() @@ -132,9 +138,8 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog case binlogdatapb.VEventType_GTID, binlogdatapb.VEventType_BEGIN, binlogdatapb.VEventType_FIELD: // We never have to send GTID, BEGIN or FIELD events on their own. bufferedEvents = append(bufferedEvents, vevent) - case binlogdatapb.VEventType_COMMIT, binlogdatapb.VEventType_DDL: - // COMMIT and DDL are terminal. There may be no more events after - // these for a long time. So, we have to send whatever we have. + case binlogdatapb.VEventType_COMMIT, binlogdatapb.VEventType_DDL, binlogdatapb.VEventType_HEARTBEAT: + // COMMIT, DDL and HEARTBEAT must be immediately sent. bufferedEvents = append(bufferedEvents, vevent) vevents := bufferedEvents bufferedEvents = nil @@ -167,7 +172,16 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog } // Main loop: calls bufferAndTransmit as events arrive. + timer := time.NewTimer(heartbeatTime) + defer timer.Stop() for { + timer.Reset(heartbeatTime) + // Drain event if timer fired before reset. + select { + case <-timer.C: + default: + } + select { case ev, ok := <-events: if !ok { @@ -196,6 +210,18 @@ func (vs *vstreamer) parseEvents(ctx context.Context, events <-chan mysql.Binlog } case <-ctx.Done(): return nil + case <-timer.C: + now := time.Now().UnixNano() + if err := bufferAndTransmit(&binlogdatapb.VEvent{ + Type: binlogdatapb.VEventType_HEARTBEAT, + Timestamp: now / 1e9, + CurrentTime: now, + }); err != nil { + if err == io.EOF { + return nil + } + return fmt.Errorf("error sending event: %v", err) + } } } } @@ -392,6 +418,7 @@ func (vs *vstreamer) parseEvent(ev mysql.BinlogEvent) ([]*binlogdatapb.VEvent, e } for _, vevent := range vevents { vevent.Timestamp = int64(ev.Timestamp()) + vevent.CurrentTime = time.Now().UnixNano() } return vevents, nil } diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go index 517e19534ac..2aac52449b5 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go @@ -919,6 +919,8 @@ func expectLog(ctx context.Context, t *testing.T, input interface{}, ch <-chan [ t.Fatalf("%v: evs\n%v, want\n%v", input, evs, wantset) } for i, want := range wantset { + // CurrentTime is not testable. + evs[i].CurrentTime = 0 switch want { case "gtid|begin": if evs[i].Type != binlogdatapb.VEventType_GTID && evs[i].Type != binlogdatapb.VEventType_BEGIN { diff --git a/proto/binlogdata.proto b/proto/binlogdata.proto index a1471e44f5c..4942198823a 100644 --- a/proto/binlogdata.proto +++ b/proto/binlogdata.proto @@ -185,6 +185,7 @@ enum VEventType { OTHER = 11; ROW = 12; FIELD = 13; + HEARTBEAT = 14; } // RowChange represents one row change @@ -212,6 +213,8 @@ message VEvent { string ddl = 4; RowEvent row_event = 5; FieldEvent field_event = 6; + // current_time specifies the current time to handle clock skew. + int64 current_time = 20; } // VStreamRequest is the payload for VStream diff --git a/py/vtproto/binlogdata_pb2.py b/py/vtproto/binlogdata_pb2.py index e586658b98d..fe5c3d42e8c 100644 --- a/py/vtproto/binlogdata_pb2.py +++ b/py/vtproto/binlogdata_pb2.py @@ -23,7 +23,7 @@ package='binlogdata', syntax='proto3', serialized_options=_b('Z\'vitess.io/vitess/go/vt/proto/binlogdata'), - serialized_pb=_b('\n\x10\x62inlogdata.proto\x12\nbinlogdata\x1a\x0bvtrpc.proto\x1a\x0bquery.proto\x1a\x0etopodata.proto\"7\n\x07\x43harset\x12\x0e\n\x06\x63lient\x18\x01 \x01(\x05\x12\x0c\n\x04\x63onn\x18\x02 \x01(\x05\x12\x0e\n\x06server\x18\x03 \x01(\x05\"\xb5\x03\n\x11\x42inlogTransaction\x12;\n\nstatements\x18\x01 \x03(\x0b\x32\'.binlogdata.BinlogTransaction.Statement\x12&\n\x0b\x65vent_token\x18\x04 \x01(\x0b\x32\x11.query.EventToken\x1a\xae\x02\n\tStatement\x12\x42\n\x08\x63\x61tegory\x18\x01 \x01(\x0e\x32\x30.binlogdata.BinlogTransaction.Statement.Category\x12$\n\x07\x63harset\x18\x02 \x01(\x0b\x32\x13.binlogdata.Charset\x12\x0b\n\x03sql\x18\x03 \x01(\x0c\"\xa9\x01\n\x08\x43\x61tegory\x12\x13\n\x0f\x42L_UNRECOGNIZED\x10\x00\x12\x0c\n\x08\x42L_BEGIN\x10\x01\x12\r\n\tBL_COMMIT\x10\x02\x12\x0f\n\x0b\x42L_ROLLBACK\x10\x03\x12\x15\n\x11\x42L_DML_DEPRECATED\x10\x04\x12\n\n\x06\x42L_DDL\x10\x05\x12\n\n\x06\x42L_SET\x10\x06\x12\r\n\tBL_INSERT\x10\x07\x12\r\n\tBL_UPDATE\x10\x08\x12\r\n\tBL_DELETE\x10\tJ\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04\"v\n\x15StreamKeyRangeRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12$\n\x07\x63harset\x18\x03 \x01(\x0b\x32\x13.binlogdata.Charset\"S\n\x16StreamKeyRangeResponse\x12\x39\n\x12\x62inlog_transaction\x18\x01 \x01(\x0b\x32\x1d.binlogdata.BinlogTransaction\"]\n\x13StreamTablesRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x0e\n\x06tables\x18\x02 \x03(\t\x12$\n\x07\x63harset\x18\x03 \x01(\x0b\x32\x13.binlogdata.Charset\"Q\n\x14StreamTablesResponse\x12\x39\n\x12\x62inlog_transaction\x18\x01 \x01(\x0b\x32\x1d.binlogdata.BinlogTransaction\"%\n\x04Rule\x12\r\n\x05match\x18\x01 \x01(\t\x12\x0e\n\x06\x66ilter\x18\x02 \x01(\t\")\n\x06\x46ilter\x12\x1f\n\x05rules\x18\x01 \x03(\x0b\x32\x10.binlogdata.Rule\"\xde\x01\n\x0c\x42inlogSource\x12\x10\n\x08keyspace\x18\x01 \x01(\t\x12\r\n\x05shard\x18\x02 \x01(\t\x12)\n\x0btablet_type\x18\x03 \x01(\x0e\x32\x14.topodata.TabletType\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\t\x12\"\n\x06\x66ilter\x18\x06 \x01(\x0b\x32\x12.binlogdata.Filter\x12\'\n\x06on_ddl\x18\x07 \x01(\x0e\x32\x17.binlogdata.OnDDLAction\"B\n\tRowChange\x12\x1a\n\x06\x62\x65\x66ore\x18\x01 \x01(\x0b\x32\n.query.Row\x12\x19\n\x05\x61\x66ter\x18\x02 \x01(\x0b\x32\n.query.Row\"J\n\x08RowEvent\x12\x12\n\ntable_name\x18\x01 \x01(\t\x12*\n\x0brow_changes\x18\x02 \x03(\x0b\x32\x15.binlogdata.RowChange\">\n\nFieldEvent\x12\x12\n\ntable_name\x18\x01 \x01(\t\x12\x1c\n\x06\x66ields\x18\x02 \x03(\x0b\x32\x0c.query.Field\"\xb2\x01\n\x06VEvent\x12$\n\x04type\x18\x01 \x01(\x0e\x32\x16.binlogdata.VEventType\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\x12\x0c\n\x04gtid\x18\x03 \x01(\t\x12\x0b\n\x03\x64\x64l\x18\x04 \x01(\t\x12\'\n\trow_event\x18\x05 \x01(\x0b\x32\x14.binlogdata.RowEvent\x12+\n\x0b\x66ield_event\x18\x06 \x01(\x0b\x32\x16.binlogdata.FieldEvent\"\xc7\x01\n\x0eVStreamRequest\x12,\n\x13\x65\x66\x66\x65\x63tive_caller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x32\n\x13immediate_caller_id\x18\x02 \x01(\x0b\x32\x15.query.VTGateCallerID\x12\x1d\n\x06target\x18\x03 \x01(\x0b\x32\r.query.Target\x12\x10\n\x08position\x18\x04 \x01(\t\x12\"\n\x06\x66ilter\x18\x05 \x01(\x0b\x32\x12.binlogdata.Filter\"5\n\x0fVStreamResponse\x12\"\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x12.binlogdata.VEvent*>\n\x0bOnDDLAction\x12\n\n\x06IGNORE\x10\x00\x12\x08\n\x04STOP\x10\x01\x12\x08\n\x04\x45XEC\x10\x02\x12\x0f\n\x0b\x45XEC_IGNORE\x10\x03*\xaa\x01\n\nVEventType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04GTID\x10\x01\x12\t\n\x05\x42\x45GIN\x10\x02\x12\n\n\x06\x43OMMIT\x10\x03\x12\x0c\n\x08ROLLBACK\x10\x04\x12\x07\n\x03\x44\x44L\x10\x05\x12\n\n\x06INSERT\x10\x06\x12\x0b\n\x07REPLACE\x10\x07\x12\n\n\x06UPDATE\x10\x08\x12\n\n\x06\x44\x45LETE\x10\t\x12\x07\n\x03SET\x10\n\x12\t\n\x05OTHER\x10\x0b\x12\x07\n\x03ROW\x10\x0c\x12\t\n\x05\x46IELD\x10\rB)Z\'vitess.io/vitess/go/vt/proto/binlogdatab\x06proto3') + serialized_pb=_b('\n\x10\x62inlogdata.proto\x12\nbinlogdata\x1a\x0bvtrpc.proto\x1a\x0bquery.proto\x1a\x0etopodata.proto\"7\n\x07\x43harset\x12\x0e\n\x06\x63lient\x18\x01 \x01(\x05\x12\x0c\n\x04\x63onn\x18\x02 \x01(\x05\x12\x0e\n\x06server\x18\x03 \x01(\x05\"\xb5\x03\n\x11\x42inlogTransaction\x12;\n\nstatements\x18\x01 \x03(\x0b\x32\'.binlogdata.BinlogTransaction.Statement\x12&\n\x0b\x65vent_token\x18\x04 \x01(\x0b\x32\x11.query.EventToken\x1a\xae\x02\n\tStatement\x12\x42\n\x08\x63\x61tegory\x18\x01 \x01(\x0e\x32\x30.binlogdata.BinlogTransaction.Statement.Category\x12$\n\x07\x63harset\x18\x02 \x01(\x0b\x32\x13.binlogdata.Charset\x12\x0b\n\x03sql\x18\x03 \x01(\x0c\"\xa9\x01\n\x08\x43\x61tegory\x12\x13\n\x0f\x42L_UNRECOGNIZED\x10\x00\x12\x0c\n\x08\x42L_BEGIN\x10\x01\x12\r\n\tBL_COMMIT\x10\x02\x12\x0f\n\x0b\x42L_ROLLBACK\x10\x03\x12\x15\n\x11\x42L_DML_DEPRECATED\x10\x04\x12\n\n\x06\x42L_DDL\x10\x05\x12\n\n\x06\x42L_SET\x10\x06\x12\r\n\tBL_INSERT\x10\x07\x12\r\n\tBL_UPDATE\x10\x08\x12\r\n\tBL_DELETE\x10\tJ\x04\x08\x02\x10\x03J\x04\x08\x03\x10\x04\"v\n\x15StreamKeyRangeRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12$\n\x07\x63harset\x18\x03 \x01(\x0b\x32\x13.binlogdata.Charset\"S\n\x16StreamKeyRangeResponse\x12\x39\n\x12\x62inlog_transaction\x18\x01 \x01(\x0b\x32\x1d.binlogdata.BinlogTransaction\"]\n\x13StreamTablesRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x0e\n\x06tables\x18\x02 \x03(\t\x12$\n\x07\x63harset\x18\x03 \x01(\x0b\x32\x13.binlogdata.Charset\"Q\n\x14StreamTablesResponse\x12\x39\n\x12\x62inlog_transaction\x18\x01 \x01(\x0b\x32\x1d.binlogdata.BinlogTransaction\"%\n\x04Rule\x12\r\n\x05match\x18\x01 \x01(\t\x12\x0e\n\x06\x66ilter\x18\x02 \x01(\t\")\n\x06\x46ilter\x12\x1f\n\x05rules\x18\x01 \x03(\x0b\x32\x10.binlogdata.Rule\"\xde\x01\n\x0c\x42inlogSource\x12\x10\n\x08keyspace\x18\x01 \x01(\t\x12\r\n\x05shard\x18\x02 \x01(\t\x12)\n\x0btablet_type\x18\x03 \x01(\x0e\x32\x14.topodata.TabletType\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\t\x12\"\n\x06\x66ilter\x18\x06 \x01(\x0b\x32\x12.binlogdata.Filter\x12\'\n\x06on_ddl\x18\x07 \x01(\x0e\x32\x17.binlogdata.OnDDLAction\"B\n\tRowChange\x12\x1a\n\x06\x62\x65\x66ore\x18\x01 \x01(\x0b\x32\n.query.Row\x12\x19\n\x05\x61\x66ter\x18\x02 \x01(\x0b\x32\n.query.Row\"J\n\x08RowEvent\x12\x12\n\ntable_name\x18\x01 \x01(\t\x12*\n\x0brow_changes\x18\x02 \x03(\x0b\x32\x15.binlogdata.RowChange\">\n\nFieldEvent\x12\x12\n\ntable_name\x18\x01 \x01(\t\x12\x1c\n\x06\x66ields\x18\x02 \x03(\x0b\x32\x0c.query.Field\"\xc8\x01\n\x06VEvent\x12$\n\x04type\x18\x01 \x01(\x0e\x32\x16.binlogdata.VEventType\x12\x11\n\ttimestamp\x18\x02 \x01(\x03\x12\x0c\n\x04gtid\x18\x03 \x01(\t\x12\x0b\n\x03\x64\x64l\x18\x04 \x01(\t\x12\'\n\trow_event\x18\x05 \x01(\x0b\x32\x14.binlogdata.RowEvent\x12+\n\x0b\x66ield_event\x18\x06 \x01(\x0b\x32\x16.binlogdata.FieldEvent\x12\x14\n\x0c\x63urrent_time\x18\x14 \x01(\x03\"\xc7\x01\n\x0eVStreamRequest\x12,\n\x13\x65\x66\x66\x65\x63tive_caller_id\x18\x01 \x01(\x0b\x32\x0f.vtrpc.CallerID\x12\x32\n\x13immediate_caller_id\x18\x02 \x01(\x0b\x32\x15.query.VTGateCallerID\x12\x1d\n\x06target\x18\x03 \x01(\x0b\x32\r.query.Target\x12\x10\n\x08position\x18\x04 \x01(\t\x12\"\n\x06\x66ilter\x18\x05 \x01(\x0b\x32\x12.binlogdata.Filter\"5\n\x0fVStreamResponse\x12\"\n\x06\x65vents\x18\x01 \x03(\x0b\x32\x12.binlogdata.VEvent*>\n\x0bOnDDLAction\x12\n\n\x06IGNORE\x10\x00\x12\x08\n\x04STOP\x10\x01\x12\x08\n\x04\x45XEC\x10\x02\x12\x0f\n\x0b\x45XEC_IGNORE\x10\x03*\xb9\x01\n\nVEventType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\x08\n\x04GTID\x10\x01\x12\t\n\x05\x42\x45GIN\x10\x02\x12\n\n\x06\x43OMMIT\x10\x03\x12\x0c\n\x08ROLLBACK\x10\x04\x12\x07\n\x03\x44\x44L\x10\x05\x12\n\n\x06INSERT\x10\x06\x12\x0b\n\x07REPLACE\x10\x07\x12\n\n\x06UPDATE\x10\x08\x12\n\n\x06\x44\x45LETE\x10\t\x12\x07\n\x03SET\x10\n\x12\t\n\x05OTHER\x10\x0b\x12\x07\n\x03ROW\x10\x0c\x12\t\n\x05\x46IELD\x10\r\x12\r\n\tHEARTBEAT\x10\x0e\x42)Z\'vitess.io/vitess/go/vt/proto/binlogdatab\x06proto3') , dependencies=[vtrpc__pb2.DESCRIPTOR,query__pb2.DESCRIPTOR,topodata__pb2.DESCRIPTOR,]) @@ -52,8 +52,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=1907, - serialized_end=1969, + serialized_start=1929, + serialized_end=1991, ) _sym_db.RegisterEnumDescriptor(_ONDDLACTION) @@ -120,11 +120,15 @@ name='FIELD', index=13, number=13, serialized_options=None, type=None), + _descriptor.EnumValueDescriptor( + name='HEARTBEAT', index=14, number=14, + serialized_options=None, + type=None), ], containing_type=None, serialized_options=None, - serialized_start=1972, - serialized_end=2142, + serialized_start=1994, + serialized_end=2179, ) _sym_db.RegisterEnumDescriptor(_VEVENTTYPE) @@ -147,6 +151,7 @@ OTHER = 11 ROW = 12 FIELD = 13 +HEARTBEAT = 14 _BINLOGTRANSACTION_STATEMENT_CATEGORY = _descriptor.EnumDescriptor( @@ -789,6 +794,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='current_time', full_name='binlogdata.VEvent.current_time', index=6, + number=20, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -802,7 +814,7 @@ oneofs=[ ], serialized_start=1470, - serialized_end=1648, + serialized_end=1670, ) @@ -860,8 +872,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1651, - serialized_end=1850, + serialized_start=1673, + serialized_end=1872, ) @@ -891,8 +903,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1852, - serialized_end=1905, + serialized_start=1874, + serialized_end=1927, ) _BINLOGTRANSACTION_STATEMENT.fields_by_name['category'].enum_type = _BINLOGTRANSACTION_STATEMENT_CATEGORY From e141810b2d505cbe44494ce6ac01a2f6af018208 Mon Sep 17 00:00:00 2001 From: Vu Cong Tuan Date: Mon, 18 Feb 2019 15:24:09 +0700 Subject: [PATCH 092/196] Replace 404 links in doc Signed-off-by: Vu Cong Tuan --- doc/GettingStartedKubernetes.md | 2 +- doc/ReplicatoinLagBasedThrottlingOfTransactions.md | 2 +- doc/ServerConfiguration.md | 2 +- doc/V3HighLevelDesign.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/GettingStartedKubernetes.md b/doc/GettingStartedKubernetes.md index 9c1c2550327..cdc311cd585 100644 --- a/doc/GettingStartedKubernetes.md +++ b/doc/GettingStartedKubernetes.md @@ -706,7 +706,7 @@ x509: failed to load system roots and no roots provided It usually means that your Kubernetes nodes are running a host OS that puts root certificates in a different place than our configuration expects by default (for example, Fedora). See the comments in the -[etcd controller template](https://github.com/vitessio/vitess/blob/master/examples/kubernetes/etcd-controller-template.yaml) +[etcd controller template](https://github.com/kubernetes/examples/blob/master/staging/storage/vitess/etcd-controller-template.yaml) for examples of how to set the right location for your host OS. You'll also need to adjust the same certificate path settings in the `vtctld` and `vttablet` templates. diff --git a/doc/ReplicatoinLagBasedThrottlingOfTransactions.md b/doc/ReplicatoinLagBasedThrottlingOfTransactions.md index 97d8500876f..42eed5db19e 100644 --- a/doc/ReplicatoinLagBasedThrottlingOfTransactions.md +++ b/doc/ReplicatoinLagBasedThrottlingOfTransactions.md @@ -25,7 +25,7 @@ A text-format representation of the [throttlerdata.Configuration](https://githu that contains configuration options for the throttler. The most important fields in that message are *target_replication_lag_sec* and *max_replication_lag_sec* that specify the desired limits on the replication lag. See the comments in the protocol definition file for more details. -If this is not specified a [default](https://github.com/vitessio/vitess/blob/master/go/vt/tabletserver/tabletenv/config.go) configuration will be used. +If this is not specified a [default](https://github.com/vitessio/vitess/tree/master/go/vt/vttablet/tabletserver/tabletenv/config.go) configuration will be used. * *tx-throttler-healthcheck-cells* diff --git a/doc/ServerConfiguration.md b/doc/ServerConfiguration.md index b1f00d12360..570fa14ac13 100644 --- a/doc/ServerConfiguration.md +++ b/doc/ServerConfiguration.md @@ -504,7 +504,7 @@ This URL prints out a simple "ok" or “not ok” string that can be used to che #### /querylogz, /debug/querylog, /txlogz, /debug/txlog -* /debug/querylog is a never-ending stream of currently executing queries with verbose information about each query. This URL can generate a lot of data because it streams every query processed by VTTablet. The details are as per this function: [https://github.com/vitessio/vitess/blob/master/go/vt/tabletserver/logstats.go#L202](https://github.com/vitessio/vitess/blob/master/go/vt/tabletserver/logstats.go#L202) +* /debug/querylog is a never-ending stream of currently executing queries with verbose information about each query. This URL can generate a lot of data because it streams every query processed by VTTablet. The details are as per this function: [https://github.com/vitessio/vitess/tree/master/go/vt/vttablet/tabletserver/tabletenv/logstats.go#L202](https://github.com/vitessio/vitess/tree/master/go/vt/vttablet/tabletserver/tabletenv/logstats.go#L202) * /querylogz is a limited human readable version of /debug/querylog. It prints the next 300 queries by default. The limit can be specified with a limit=N parameter on the URL. * /txlogz is like /querylogz, but for transactions. * /debug/txlog is the JSON counterpart to /txlogz. diff --git a/doc/V3HighLevelDesign.md b/doc/V3HighLevelDesign.md index ca6909716e0..b0ba3268a7b 100644 --- a/doc/V3HighLevelDesign.md +++ b/doc/V3HighLevelDesign.md @@ -1194,7 +1194,7 @@ The overall strategy is as follows: In order to align ourselves with our priorities, we’ll start off with a limited set of primitives, and then we can expand from there. -VTGate already has `Route` and `RouteMerge` as primitives. To this list, let’s add `Join` and `LeftJoin`. Using these primitives, we should be able to cover priorities 1-3 (mentioned in the [Prioritization](https://github.com/vitessio/vitess/blob/sugudoc/doc/V3HighLevelDesign.md#prioritization) section). So, any constructs that will require VTGate to do additional work will not be supported. Here’s a recap of what each primitive must do: +VTGate already has `Route` and `RouteMerge` as primitives. To this list, let’s add `Join` and `LeftJoin`. Using these primitives, we should be able to cover priorities 1-3 (mentioned in the [Prioritization](https://github.com/vitessio/vitess/blob/master/doc/V3HighLevelDesign.md#prioritization) section). So, any constructs that will require VTGate to do additional work will not be supported. Here’s a recap of what each primitive must do: * `Route`: Sends a query to a single shard or unsharded keyspace. * `RouteMerge`: Sends a (mostly) identical query to multiple shards and returns the combined results in no particular order. From 49a99c9e9927cd4667b51e6ae1e84fac34f79c05 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Mon, 18 Feb 2019 13:44:04 -0800 Subject: [PATCH 093/196] Fix bugs uncovered by tests and add some more tests to resharding integration test Signed-off-by: Rafael Chacon --- go/vt/vttablet/tabletmanager/state_change.go | 1 - go/vt/wrangler/keyspace.go | 13 ++++---- test/resharding.py | 33 +++++++++++++++++--- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/go/vt/vttablet/tabletmanager/state_change.go b/go/vt/vttablet/tabletmanager/state_change.go index 9ca5a39d39c..62b1e2c2e2f 100644 --- a/go/vt/vttablet/tabletmanager/state_change.go +++ b/go/vt/vttablet/tabletmanager/state_change.go @@ -230,7 +230,6 @@ func (agent *ActionAgent) changeCallback(ctx context.Context, oldTablet, newTabl for _, tabletControl := range partition.GetShardTabletControls() { if key.KeyRangeEqual(tabletControl.GetKeyRange(), newTablet.GetKeyRange()) { - log.Infof("This is the partition tabletControl KeyRange: %v newtabletKeyRange: %v changed: %v", tabletControl.GetName(), newTablet.GetShard(), tabletControl.QueryServiceDisabled) if tabletControl.QueryServiceDisabled { allowQuery = false disallowQueryReason = "TabletControl.DisableQueryService set" diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index 16e7cf00e03..7d32a535380 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -588,6 +588,13 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string // Destination shards need different handling than what updateShardRecords does. event.DispatchUpdate(ev, "updating destination shards") + + // Enable query service + err = wr.ts.UpdateDisableQueryService(ctx, keyspace, destinationShards, topodatapb.TabletType_MASTER, nil, false) + if err != nil { + return err + } + for i, si := range destinationShards { ti, err := wr.ts.GetTablet(ctx, si.MasterAlias) if err != nil { @@ -610,12 +617,6 @@ func (wr *Wrangler) masterMigrateServedType(ctx context.Context, keyspace string } } - // Enable query service - err = wr.ts.UpdateDisableQueryService(ctx, keyspace, destinationShards, topodatapb.TabletType_MASTER, nil, false) - if err != nil { - return err - } - event.DispatchUpdate(ev, "setting destination masters read-write") if err := wr.refreshMasters(ctx, destinationShards); err != nil { return err diff --git a/test/resharding.py b/test/resharding.py index d5127a3e364..3963142588a 100755 --- a/test/resharding.py +++ b/test/resharding.py @@ -1147,19 +1147,39 @@ def test_resharding(self): sharding_column_name='custom_ksid_col') utils.check_tablet_query_service(self, shard_1_master, True, False) - # sabotage master migration and make it fail in an unfinished state - # Check that source master not serving, because this failure is past the - # point of no return. + # sabotage master migration and make it fail in an unfinished state. utils.run_vtctl(['SetShardTabletControl', '-blacklisted_tables=t', 'test_keyspace/c0-', 'master'], auto_log=True) utils.run_vtctl(['MigrateServedTypes', 'test_keyspace/80-', 'master'], auto_log=True, expect_fail=True) + # Query service is disabled in source shard as failure occurred after point of no return utils.check_tablet_query_service(self, shard_1_master, False, True) - # remove sabotage + # Global topology records should not change as migration did not succeed + shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/80-']) + self.assertEqual(shard['is_master_serving'], True, 'source shards should be set in destination shard') + + shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/c0-']) + self.assertEqual(len(shard['source_shards']), 1, 'source shards should be set in destination shard') + self.assertEqual(shard['is_master_serving'], False, 'source shards should be set in destination shard') + + shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/80-c0']) + self.assertEqual(len(shard['source_shards']), 1, 'source shards should be set in destination shard') + self.assertEqual(shard['is_master_serving'], False, 'source shards should be set in destination shard') + + # remove sabotage, but make it fail early. This should not result + # in the source master serving, because this failure is past the + # point of no return. utils.run_vtctl(['SetShardTabletControl', '-blacklisted_tables=t', '-remove', 'test_keyspace/c0-', 'master'], auto_log=True) + utils.run_vtctl(['MigrateServedTypes', + '-filtered_replication_wait_time', '0s', + 'test_keyspace/80-', 'master'], + auto_log=True, expect_fail=True) + + utils.check_tablet_query_service(self, shard_1_master, False, True) + # do the migration that's expected to succeed utils.run_vtctl(['MigrateServedTypes', 'test_keyspace/80-', 'master'], auto_log=True) @@ -1171,6 +1191,11 @@ def test_resharding(self): sharding_column_name='custom_ksid_col') utils.check_tablet_query_service(self, shard_1_master, False, True) + # check destination shards are serving + + utils.check_tablet_query_service(self, shard_2_master, True, False) + utils.check_tablet_query_service(self, shard_3_master, True, False) + # check the binlog players are gone now self.check_no_binlog_player(shard_2_master) self.check_no_binlog_player(shard_3_master) From 9272b1cd73242a534d82869898fcf652e7750e9f Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Mon, 18 Feb 2019 18:26:00 -0800 Subject: [PATCH 094/196] Add ServedType for backwards compatiblilty * Also adds more validations and tests when rebuilding serving keyspace Signed-off-by: Rafael Chacon --- go/vt/proto/topodata/topodata.pb.go | 255 +++++++++++++++++----------- go/vt/proto/vtgate/vtgate.pb.go | 106 ++++++------ go/vt/topo/shard.go | 10 ++ go/vt/topotools/rebuild_keyspace.go | 19 ++- proto/topodata.proto | 15 +- py/vtproto/topodata_pb2.py | 123 ++++++++++---- test/resharding.py | 7 + 7 files changed, 348 insertions(+), 187 deletions(-) diff --git a/go/vt/proto/topodata/topodata.pb.go b/go/vt/proto/topodata/topodata.pb.go index 15392dced19..2c9a5415926 100644 --- a/go/vt/proto/topodata/topodata.pb.go +++ b/go/vt/proto/topodata/topodata.pb.go @@ -48,7 +48,7 @@ func (x KeyspaceIdType) String() string { return proto.EnumName(KeyspaceIdType_name, int32(x)) } func (KeyspaceIdType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{0} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{0} } // TabletType represents the type of a given tablet. @@ -117,7 +117,7 @@ func (x TabletType) String() string { return proto.EnumName(TabletType_name, int32(x)) } func (TabletType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{1} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{1} } // KeyRange describes a range of sharding keys, when range-based @@ -134,7 +134,7 @@ func (m *KeyRange) Reset() { *m = KeyRange{} } func (m *KeyRange) String() string { return proto.CompactTextString(m) } func (*KeyRange) ProtoMessage() {} func (*KeyRange) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{0} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{0} } func (m *KeyRange) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_KeyRange.Unmarshal(m, b) @@ -184,7 +184,7 @@ func (m *TabletAlias) Reset() { *m = TabletAlias{} } func (m *TabletAlias) String() string { return proto.CompactTextString(m) } func (*TabletAlias) ProtoMessage() {} func (*TabletAlias) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{1} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{1} } func (m *TabletAlias) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletAlias.Unmarshal(m, b) @@ -260,7 +260,7 @@ func (m *Tablet) Reset() { *m = Tablet{} } func (m *Tablet) String() string { return proto.CompactTextString(m) } func (*Tablet) ProtoMessage() {} func (*Tablet) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{2} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{2} } func (m *Tablet) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Tablet.Unmarshal(m, b) @@ -372,6 +372,10 @@ type Shard struct { // helpful to have it decomposed here. // Once set at creation time, it is never changed. KeyRange *KeyRange `protobuf:"bytes,2,opt,name=key_range,json=keyRange,proto3" json:"key_range,omitempty"` + // served_types has at most one entry per TabletType + // This field is in the process of being deprecated in favor of + // is_master_serving. Keeping for backwards compatibility purposes. + ServedTypes []*Shard_ServedType `protobuf:"bytes,3,rep,name=served_types,json=servedTypes,proto3" json:"served_types,omitempty"` // SourceShards is the list of shards we're replicating from, // using filtered replication. // The keyspace lock is always taken when changing this. @@ -391,7 +395,7 @@ func (m *Shard) Reset() { *m = Shard{} } func (m *Shard) String() string { return proto.CompactTextString(m) } func (*Shard) ProtoMessage() {} func (*Shard) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{3} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{3} } func (m *Shard) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Shard.Unmarshal(m, b) @@ -425,6 +429,13 @@ func (m *Shard) GetKeyRange() *KeyRange { return nil } +func (m *Shard) GetServedTypes() []*Shard_ServedType { + if m != nil { + return m.ServedTypes + } + return nil +} + func (m *Shard) GetSourceShards() []*Shard_SourceShard { if m != nil { return m.SourceShards @@ -446,6 +457,53 @@ func (m *Shard) GetIsMasterServing() bool { return false } +// ServedType is an entry in the served_types +type Shard_ServedType struct { + TabletType TabletType `protobuf:"varint,1,opt,name=tablet_type,json=tabletType,proto3,enum=topodata.TabletType" json:"tablet_type,omitempty"` + Cells []string `protobuf:"bytes,2,rep,name=cells,proto3" json:"cells,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *Shard_ServedType) Reset() { *m = Shard_ServedType{} } +func (m *Shard_ServedType) String() string { return proto.CompactTextString(m) } +func (*Shard_ServedType) ProtoMessage() {} +func (*Shard_ServedType) Descriptor() ([]byte, []int) { + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{3, 0} +} +func (m *Shard_ServedType) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_Shard_ServedType.Unmarshal(m, b) +} +func (m *Shard_ServedType) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_Shard_ServedType.Marshal(b, m, deterministic) +} +func (dst *Shard_ServedType) XXX_Merge(src proto.Message) { + xxx_messageInfo_Shard_ServedType.Merge(dst, src) +} +func (m *Shard_ServedType) XXX_Size() int { + return xxx_messageInfo_Shard_ServedType.Size(m) +} +func (m *Shard_ServedType) XXX_DiscardUnknown() { + xxx_messageInfo_Shard_ServedType.DiscardUnknown(m) +} + +var xxx_messageInfo_Shard_ServedType proto.InternalMessageInfo + +func (m *Shard_ServedType) GetTabletType() TabletType { + if m != nil { + return m.TabletType + } + return TabletType_UNKNOWN +} + +func (m *Shard_ServedType) GetCells() []string { + if m != nil { + return m.Cells + } + return nil +} + // SourceShard represents a data source for filtered replication // accross shards. When this is used in a destination shard, the master // of that shard will run filtered replication. @@ -469,7 +527,7 @@ func (m *Shard_SourceShard) Reset() { *m = Shard_SourceShard{} } func (m *Shard_SourceShard) String() string { return proto.CompactTextString(m) } func (*Shard_SourceShard) ProtoMessage() {} func (*Shard_SourceShard) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{3, 0} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{3, 1} } func (m *Shard_SourceShard) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Shard_SourceShard.Unmarshal(m, b) @@ -542,7 +600,7 @@ func (m *Shard_TabletControl) Reset() { *m = Shard_TabletControl{} } func (m *Shard_TabletControl) String() string { return proto.CompactTextString(m) } func (*Shard_TabletControl) ProtoMessage() {} func (*Shard_TabletControl) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{3, 1} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{3, 2} } func (m *Shard_TabletControl) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Shard_TabletControl.Unmarshal(m, b) @@ -610,7 +668,7 @@ func (m *Keyspace) Reset() { *m = Keyspace{} } func (m *Keyspace) String() string { return proto.CompactTextString(m) } func (*Keyspace) ProtoMessage() {} func (*Keyspace) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{4} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{4} } func (m *Keyspace) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Keyspace.Unmarshal(m, b) @@ -669,7 +727,7 @@ func (m *Keyspace_ServedFrom) Reset() { *m = Keyspace_ServedFrom{} } func (m *Keyspace_ServedFrom) String() string { return proto.CompactTextString(m) } func (*Keyspace_ServedFrom) ProtoMessage() {} func (*Keyspace_ServedFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{4, 0} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{4, 0} } func (m *Keyspace_ServedFrom) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Keyspace_ServedFrom.Unmarshal(m, b) @@ -725,7 +783,7 @@ func (m *ShardReplication) Reset() { *m = ShardReplication{} } func (m *ShardReplication) String() string { return proto.CompactTextString(m) } func (*ShardReplication) ProtoMessage() {} func (*ShardReplication) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{5} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{5} } func (m *ShardReplication) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShardReplication.Unmarshal(m, b) @@ -764,7 +822,7 @@ func (m *ShardReplication_Node) Reset() { *m = ShardReplication_Node{} } func (m *ShardReplication_Node) String() string { return proto.CompactTextString(m) } func (*ShardReplication_Node) ProtoMessage() {} func (*ShardReplication_Node) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{5, 0} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{5, 0} } func (m *ShardReplication_Node) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShardReplication_Node.Unmarshal(m, b) @@ -805,7 +863,7 @@ func (m *ShardReference) Reset() { *m = ShardReference{} } func (m *ShardReference) String() string { return proto.CompactTextString(m) } func (*ShardReference) ProtoMessage() {} func (*ShardReference) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{6} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{6} } func (m *ShardReference) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShardReference.Unmarshal(m, b) @@ -855,7 +913,7 @@ func (m *ShardTabletControl) Reset() { *m = ShardTabletControl{} } func (m *ShardTabletControl) String() string { return proto.CompactTextString(m) } func (*ShardTabletControl) ProtoMessage() {} func (*ShardTabletControl) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{7} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{7} } func (m *ShardTabletControl) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ShardTabletControl.Unmarshal(m, b) @@ -913,7 +971,7 @@ func (m *SrvKeyspace) Reset() { *m = SrvKeyspace{} } func (m *SrvKeyspace) String() string { return proto.CompactTextString(m) } func (*SrvKeyspace) ProtoMessage() {} func (*SrvKeyspace) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{8} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{8} } func (m *SrvKeyspace) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SrvKeyspace.Unmarshal(m, b) @@ -977,7 +1035,7 @@ func (m *SrvKeyspace_KeyspacePartition) Reset() { *m = SrvKeyspace_Keysp func (m *SrvKeyspace_KeyspacePartition) String() string { return proto.CompactTextString(m) } func (*SrvKeyspace_KeyspacePartition) ProtoMessage() {} func (*SrvKeyspace_KeyspacePartition) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{8, 0} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{8, 0} } func (m *SrvKeyspace_KeyspacePartition) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SrvKeyspace_KeyspacePartition.Unmarshal(m, b) @@ -1034,7 +1092,7 @@ func (m *SrvKeyspace_ServedFrom) Reset() { *m = SrvKeyspace_ServedFrom{} func (m *SrvKeyspace_ServedFrom) String() string { return proto.CompactTextString(m) } func (*SrvKeyspace_ServedFrom) ProtoMessage() {} func (*SrvKeyspace_ServedFrom) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{8, 1} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{8, 1} } func (m *SrvKeyspace_ServedFrom) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SrvKeyspace_ServedFrom.Unmarshal(m, b) @@ -1092,7 +1150,7 @@ func (m *CellInfo) Reset() { *m = CellInfo{} } func (m *CellInfo) String() string { return proto.CompactTextString(m) } func (*CellInfo) ProtoMessage() {} func (*CellInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_topodata_42e6e5b7e6808654, []int{9} + return fileDescriptor_topodata_e30d0a39cbb15c1e, []int{9} } func (m *CellInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CellInfo.Unmarshal(m, b) @@ -1140,6 +1198,7 @@ func init() { proto.RegisterMapType((map[string]int32)(nil), "topodata.Tablet.PortMapEntry") proto.RegisterMapType((map[string]string)(nil), "topodata.Tablet.TagsEntry") proto.RegisterType((*Shard)(nil), "topodata.Shard") + proto.RegisterType((*Shard_ServedType)(nil), "topodata.Shard.ServedType") proto.RegisterType((*Shard_SourceShard)(nil), "topodata.Shard.SourceShard") proto.RegisterType((*Shard_TabletControl)(nil), "topodata.Shard.TabletControl") proto.RegisterType((*Keyspace)(nil), "topodata.Keyspace") @@ -1156,83 +1215,85 @@ func init() { proto.RegisterEnum("topodata.TabletType", TabletType_name, TabletType_value) } -func init() { proto.RegisterFile("topodata.proto", fileDescriptor_topodata_42e6e5b7e6808654) } - -var fileDescriptor_topodata_42e6e5b7e6808654 = []byte{ - // 1192 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x56, 0xef, 0x6e, 0x1b, 0x45, - 0x10, 0xe7, 0xec, 0xb3, 0x73, 0x9e, 0x73, 0x9c, 0xeb, 0x92, 0x56, 0x27, 0x43, 0x45, 0x64, 0xa9, - 0xc2, 0x2a, 0xc2, 0x41, 0x69, 0x0b, 0x51, 0x3f, 0xd5, 0x75, 0x5c, 0x9a, 0xb6, 0x71, 0xac, 0xb5, - 0x23, 0x28, 0x12, 0x3a, 0x5d, 0x7c, 0x1b, 0xf7, 0x94, 0xf3, 0xad, 0xbb, 0xbb, 0x89, 0x64, 0x5e, - 0x81, 0x0f, 0xf0, 0x99, 0x37, 0xe0, 0x11, 0x78, 0x02, 0x9e, 0x03, 0xde, 0x03, 0x09, 0xed, 0xec, - 0xd9, 0x3e, 0x3b, 0xb4, 0x4d, 0x51, 0xbf, 0x58, 0x33, 0x3b, 0x7f, 0x76, 0x66, 0xf6, 0xf7, 0x9b, - 0x33, 0xd4, 0x14, 0x9f, 0xf2, 0x28, 0x54, 0x61, 0x6b, 0x2a, 0xb8, 0xe2, 0xc4, 0x99, 0xeb, 0x8d, - 0x3d, 0x70, 0x9e, 0xb3, 0x19, 0x0d, 0xd3, 0x31, 0x23, 0xdb, 0x50, 0x92, 0x2a, 0x14, 0xca, 0xb7, - 0x76, 0xac, 0x66, 0x95, 0x1a, 0x85, 0x78, 0x50, 0x64, 0x69, 0xe4, 0x17, 0xf0, 0x4c, 0x8b, 0x8d, - 0x7b, 0xe0, 0x0e, 0xc3, 0xd3, 0x84, 0xa9, 0x76, 0x12, 0x87, 0x92, 0x10, 0xb0, 0x47, 0x2c, 0x49, - 0x30, 0xaa, 0x42, 0x51, 0xd6, 0x41, 0x17, 0xb1, 0x09, 0xda, 0xa4, 0x5a, 0x6c, 0xfc, 0x61, 0x43, - 0xd9, 0x44, 0x91, 0x2f, 0xa0, 0x14, 0xea, 0x48, 0x8c, 0x70, 0xf7, 0x6e, 0xb6, 0x16, 0xd5, 0xe5, - 0xd2, 0x52, 0xe3, 0x43, 0xea, 0xe0, 0xbc, 0xe2, 0x52, 0xa5, 0xe1, 0x84, 0x61, 0xba, 0x0a, 0x5d, - 0xe8, 0x64, 0x1f, 0x9c, 0x29, 0x17, 0x2a, 0x98, 0x84, 0x53, 0xdf, 0xde, 0x29, 0x36, 0xdd, 0xbd, - 0xdb, 0xeb, 0xb9, 0x5a, 0x7d, 0x2e, 0xd4, 0x51, 0x38, 0xed, 0xa6, 0x4a, 0xcc, 0xe8, 0xc6, 0xd4, - 0x68, 0x3a, 0xeb, 0x39, 0x9b, 0xc9, 0x69, 0x38, 0x62, 0x7e, 0xc9, 0x64, 0x9d, 0xeb, 0x38, 0x86, - 0x57, 0xa1, 0x88, 0xfc, 0x32, 0x1a, 0x8c, 0x42, 0x76, 0xa1, 0x72, 0xce, 0x66, 0x81, 0xd0, 0x93, - 0xf2, 0x37, 0xb0, 0x70, 0xb2, 0xbc, 0x6c, 0x3e, 0x43, 0x4c, 0x63, 0xa6, 0xd9, 0x04, 0x5b, 0xcd, - 0xa6, 0xcc, 0x77, 0x76, 0xac, 0x66, 0x6d, 0x6f, 0x7b, 0xbd, 0xb0, 0xe1, 0x6c, 0xca, 0x28, 0x7a, - 0x90, 0x26, 0x78, 0xd1, 0x69, 0xa0, 0x3b, 0x0a, 0xf8, 0x25, 0x13, 0x22, 0x8e, 0x98, 0x5f, 0xc1, - 0xbb, 0x6b, 0xd1, 0x69, 0x2f, 0x9c, 0xb0, 0xe3, 0xec, 0x94, 0xb4, 0xc0, 0x56, 0xe1, 0x58, 0xfa, - 0x80, 0xcd, 0xd6, 0xaf, 0x34, 0x3b, 0x0c, 0xc7, 0xd2, 0x74, 0x8a, 0x7e, 0xe4, 0x0e, 0xd4, 0x26, - 0x33, 0xf9, 0x3a, 0x09, 0x16, 0x23, 0xac, 0x62, 0xde, 0x4d, 0x3c, 0x7d, 0x3a, 0x9f, 0xe3, 0x6d, - 0x00, 0xe3, 0xa6, 0xc7, 0xe3, 0x6f, 0xee, 0x58, 0xcd, 0x12, 0xad, 0xe0, 0x89, 0x9e, 0x5e, 0xfd, - 0x21, 0x54, 0xf3, 0x53, 0xd4, 0x8f, 0x7b, 0xce, 0x66, 0xd9, 0x7b, 0x6b, 0x51, 0x8f, 0xec, 0x32, - 0x4c, 0x2e, 0xcc, 0x0b, 0x95, 0xa8, 0x51, 0x1e, 0x16, 0xf6, 0xad, 0xfa, 0x37, 0x50, 0x59, 0x14, - 0xf5, 0xae, 0xc0, 0x4a, 0x2e, 0xf0, 0x99, 0xed, 0x14, 0x3d, 0xfb, 0x99, 0xed, 0xb8, 0x5e, 0xb5, - 0xf1, 0x8f, 0x0d, 0xa5, 0x01, 0xbe, 0xc2, 0x3e, 0x54, 0x27, 0xa1, 0x54, 0x4c, 0x04, 0xd7, 0x40, - 0x90, 0x6b, 0x5c, 0x0d, 0x4a, 0x57, 0xde, 0xaf, 0x70, 0x8d, 0xf7, 0x7b, 0x04, 0x9b, 0x92, 0x5f, - 0x88, 0x11, 0x0b, 0x10, 0x00, 0x32, 0x43, 0xd8, 0x27, 0xcb, 0x20, 0x2c, 0xa9, 0x35, 0x40, 0x27, - 0x94, 0x69, 0x55, 0x2e, 0x15, 0x49, 0x9e, 0xc0, 0x96, 0xc2, 0x72, 0x82, 0x11, 0x4f, 0x95, 0xe0, - 0x89, 0xf4, 0xcb, 0xeb, 0x28, 0x35, 0x39, 0x4c, 0xd5, 0x1d, 0xe3, 0x45, 0x6b, 0x2a, 0xaf, 0x4a, - 0x72, 0x17, 0x6e, 0xc4, 0x32, 0xc8, 0xfa, 0x96, 0x4c, 0x5c, 0xc6, 0xe9, 0x18, 0x21, 0xe8, 0xd0, - 0xad, 0x58, 0x1e, 0xe1, 0xf9, 0xc0, 0x1c, 0xd7, 0x7f, 0xb3, 0xc0, 0xcd, 0x55, 0x34, 0x27, 0xa2, - 0xb5, 0x20, 0xe2, 0x0a, 0xf4, 0x0b, 0x6f, 0x82, 0x7e, 0xf1, 0x8d, 0xd0, 0xb7, 0xaf, 0x31, 0xba, - 0x5b, 0x50, 0xc6, 0x16, 0xa4, 0x5f, 0xda, 0x29, 0x36, 0x2b, 0x34, 0xd3, 0xea, 0xbf, 0x5b, 0xb0, - 0xb9, 0xd2, 0x2a, 0x79, 0x00, 0x6e, 0x36, 0x22, 0xe4, 0x8a, 0xf5, 0x16, 0xae, 0x80, 0x5a, 0xc8, - 0xba, 0x4e, 0xbd, 0x66, 0xa4, 0x5f, 0xc0, 0xfc, 0x46, 0x21, 0x5f, 0x02, 0x39, 0x4d, 0xc2, 0xd1, - 0x79, 0x12, 0x4b, 0xc5, 0xa2, 0x20, 0x2b, 0xc1, 0x46, 0x97, 0x1b, 0x39, 0x0b, 0x26, 0x95, 0xba, - 0xca, 0x33, 0xc1, 0x7f, 0x62, 0x29, 0x6e, 0x00, 0x87, 0x66, 0xda, 0x02, 0x79, 0xe6, 0xb7, 0xe4, - 0x95, 0x1b, 0x7f, 0x16, 0x70, 0x4b, 0x9a, 0x19, 0x7d, 0x05, 0xdb, 0x38, 0x96, 0x38, 0x1d, 0x07, - 0x23, 0x9e, 0x5c, 0x4c, 0x52, 0xa4, 0x6e, 0x86, 0x6a, 0x32, 0xb7, 0x75, 0xd0, 0xa4, 0xd9, 0x4b, - 0x9e, 0x5d, 0x8d, 0xc0, 0x6e, 0x0b, 0xd8, 0xad, 0xbf, 0x32, 0x4a, 0xbc, 0xe3, 0x30, 0xc2, 0x8e, - 0xd7, 0x72, 0x61, 0xe7, 0x8f, 0xa0, 0xaa, 0x11, 0xc0, 0xa2, 0xe0, 0x4c, 0xf0, 0x89, 0xbc, 0xba, - 0xf6, 0xe6, 0x39, 0x5a, 0x03, 0x74, 0x7b, 0x22, 0xf8, 0x84, 0xba, 0x72, 0x21, 0xcb, 0xfa, 0x05, - 0xc0, 0xd2, 0xf4, 0x61, 0x1f, 0x20, 0x0f, 0xad, 0xe2, 0x2a, 0xb4, 0xcc, 0x3c, 0x1b, 0x3f, 0x5b, - 0xe0, 0x19, 0xaa, 0xb0, 0x69, 0x12, 0x8f, 0x42, 0x15, 0xf3, 0x94, 0x3c, 0x80, 0x52, 0xca, 0x23, - 0xa6, 0xd9, 0xac, 0x9b, 0xf9, 0x6c, 0x8d, 0x1d, 0x39, 0xd7, 0x56, 0x8f, 0x47, 0x8c, 0x1a, 0xef, - 0xfa, 0x23, 0xb0, 0xb5, 0xaa, 0x77, 0x42, 0xd6, 0xc2, 0x75, 0x76, 0x82, 0x5a, 0x2a, 0x8d, 0x13, - 0xa8, 0x65, 0x37, 0x9c, 0x31, 0xc1, 0xd2, 0x11, 0xd3, 0xdf, 0xb2, 0xdc, 0x63, 0xa2, 0xfc, 0xde, - 0x9b, 0xa3, 0xf1, 0x8b, 0x05, 0x04, 0xf3, 0xae, 0x62, 0xfd, 0x43, 0xe4, 0x26, 0xf7, 0xe1, 0xd6, - 0xeb, 0x0b, 0x26, 0x66, 0x66, 0x0f, 0x8c, 0x58, 0x10, 0xc5, 0x52, 0xdf, 0x62, 0x28, 0xeb, 0xd0, - 0x6d, 0xb4, 0x0e, 0x8c, 0xf1, 0x20, 0xb3, 0x35, 0xfe, 0xb6, 0xc1, 0x1d, 0x88, 0xcb, 0x05, 0x86, - 0xbf, 0x05, 0x98, 0x86, 0x42, 0xc5, 0x7a, 0xa6, 0xf3, 0xb1, 0x7f, 0x9e, 0x1b, 0xfb, 0xd2, 0x75, - 0x81, 0xa7, 0xfe, 0xdc, 0x9f, 0xe6, 0x42, 0xdf, 0x48, 0x86, 0xc2, 0x7b, 0x93, 0xa1, 0xf8, 0x3f, - 0xc8, 0xd0, 0x06, 0x37, 0x47, 0x86, 0x8c, 0x0b, 0x3b, 0xff, 0xdd, 0x47, 0x8e, 0x0e, 0xb0, 0xa4, - 0x43, 0xfd, 0x2f, 0x0b, 0x6e, 0x5c, 0x69, 0x51, 0xb3, 0x22, 0x4b, 0xfc, 0x6e, 0x56, 0x18, 0x47, - 0xac, 0xa7, 0x03, 0x1e, 0x56, 0x19, 0x88, 0x39, 0xa0, 0x0c, 0x41, 0xdc, 0x7c, 0x5f, 0xab, 0x88, - 0xa3, 0x5b, 0x72, 0x45, 0x97, 0xa4, 0x0f, 0x37, 0x4d, 0x92, 0xf5, 0x6f, 0x47, 0x11, 0x33, 0x7d, - 0xba, 0x96, 0x69, 0xf5, 0xd3, 0xf1, 0xb1, 0xbc, 0x72, 0x26, 0xeb, 0xc1, 0x87, 0x60, 0xfc, 0x5b, - 0x3e, 0x1b, 0xd9, 0x96, 0xfc, 0x11, 0x9c, 0x0e, 0x4b, 0x92, 0xc3, 0xf4, 0x8c, 0xeb, 0x3f, 0x1e, - 0x38, 0x17, 0x11, 0x84, 0x51, 0x24, 0x98, 0x94, 0x19, 0xea, 0x37, 0xcd, 0x69, 0xdb, 0x1c, 0x6a, - 0x4a, 0x08, 0xce, 0x55, 0x96, 0x10, 0x65, 0xbd, 0x96, 0x05, 0x1b, 0xc7, 0x3c, 0xcd, 0x56, 0x48, - 0xa6, 0xdd, 0xdd, 0x83, 0xda, 0x2a, 0x24, 0x48, 0x05, 0x4a, 0x27, 0xbd, 0x41, 0x77, 0xe8, 0x7d, - 0x44, 0x00, 0xca, 0x27, 0x87, 0xbd, 0xe1, 0xd7, 0xf7, 0x3d, 0x4b, 0x1f, 0x3f, 0x7e, 0x39, 0xec, - 0x0e, 0xbc, 0xc2, 0xdd, 0x5f, 0x2d, 0x80, 0x65, 0x3f, 0xc4, 0x85, 0x8d, 0x93, 0xde, 0xf3, 0xde, - 0xf1, 0x77, 0x3d, 0x13, 0x72, 0xd4, 0x1e, 0x0c, 0xbb, 0xd4, 0xb3, 0xb4, 0x81, 0x76, 0xfb, 0x2f, - 0x0e, 0x3b, 0x6d, 0xaf, 0xa0, 0x0d, 0xf4, 0xe0, 0xb8, 0xf7, 0xe2, 0xa5, 0x57, 0xc4, 0x5c, 0xed, - 0x61, 0xe7, 0xa9, 0x11, 0x07, 0xfd, 0x36, 0xed, 0x7a, 0x36, 0xf1, 0xa0, 0xda, 0xfd, 0xbe, 0xdf, - 0xa5, 0x87, 0x47, 0xdd, 0xde, 0xb0, 0xfd, 0xc2, 0x2b, 0xe9, 0x98, 0xc7, 0xed, 0xce, 0xf3, 0x93, - 0xbe, 0x57, 0x36, 0xc9, 0x06, 0xc3, 0x63, 0xda, 0xf5, 0x36, 0xb4, 0x72, 0x40, 0xdb, 0x87, 0xbd, - 0xee, 0x81, 0xe7, 0xd4, 0x0b, 0x9e, 0xf5, 0x78, 0x1f, 0xb6, 0x62, 0xde, 0xba, 0x8c, 0x15, 0x93, - 0xd2, 0xfc, 0x1b, 0xff, 0xe1, 0x4e, 0xa6, 0xc5, 0x7c, 0xd7, 0x48, 0xbb, 0x63, 0xbe, 0x7b, 0xa9, - 0x76, 0xd1, 0xba, 0x3b, 0x7f, 0x98, 0xd3, 0x32, 0xea, 0xf7, 0xfe, 0x0d, 0x00, 0x00, 0xff, 0xff, - 0xed, 0x99, 0x0d, 0x60, 0xcd, 0x0b, 0x00, 0x00, +func init() { proto.RegisterFile("topodata.proto", fileDescriptor_topodata_e30d0a39cbb15c1e) } + +var fileDescriptor_topodata_e30d0a39cbb15c1e = []byte{ + // 1217 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x57, 0xe1, 0x6e, 0x1b, 0x45, + 0x10, 0xe6, 0xec, 0xb3, 0x63, 0x8f, 0x1d, 0xe7, 0xba, 0xa4, 0xd5, 0xe9, 0xa0, 0x22, 0xb2, 0x54, + 0x11, 0x15, 0xe1, 0xa0, 0xb4, 0x85, 0xa8, 0x12, 0x52, 0x5d, 0xc7, 0xa5, 0x69, 0x1b, 0xc7, 0x5a, + 0x3b, 0x82, 0x22, 0xa1, 0xd3, 0xc5, 0xb7, 0x71, 0x4f, 0x39, 0xdf, 0xba, 0xbb, 0x9b, 0x48, 0xe6, + 0x15, 0xf8, 0x01, 0xfc, 0xe5, 0x0d, 0x78, 0x04, 0x9e, 0x80, 0xe7, 0x80, 0x27, 0x41, 0x3b, 0x7b, + 0x67, 0x9f, 0x1d, 0x1a, 0x52, 0x94, 0x7f, 0x33, 0xbb, 0x33, 0x73, 0x33, 0xdf, 0xcc, 0x37, 0x6b, + 0x43, 0x43, 0xf1, 0x29, 0x0f, 0x03, 0x15, 0xb4, 0xa6, 0x82, 0x2b, 0x4e, 0x2a, 0x99, 0xde, 0xdc, + 0x85, 0xca, 0x4b, 0x36, 0xa3, 0x41, 0x32, 0x66, 0x64, 0x13, 0x4a, 0x52, 0x05, 0x42, 0xb9, 0xd6, + 0x96, 0xb5, 0x5d, 0xa7, 0x46, 0x21, 0x0e, 0x14, 0x59, 0x12, 0xba, 0x05, 0x3c, 0xd3, 0x62, 0xf3, + 0x01, 0xd4, 0x86, 0xc1, 0x49, 0xcc, 0x54, 0x3b, 0x8e, 0x02, 0x49, 0x08, 0xd8, 0x23, 0x16, 0xc7, + 0xe8, 0x55, 0xa5, 0x28, 0x6b, 0xa7, 0xf3, 0xc8, 0x38, 0xad, 0x53, 0x2d, 0x36, 0xff, 0xb0, 0xa1, + 0x6c, 0xbc, 0xc8, 0x67, 0x50, 0x0a, 0xb4, 0x27, 0x7a, 0xd4, 0x76, 0x6f, 0xb7, 0xe6, 0xd9, 0xe5, + 0xc2, 0x52, 0x63, 0x43, 0x3c, 0xa8, 0xbc, 0xe1, 0x52, 0x25, 0xc1, 0x84, 0x61, 0xb8, 0x2a, 0x9d, + 0xeb, 0x64, 0x0f, 0x2a, 0x53, 0x2e, 0x94, 0x3f, 0x09, 0xa6, 0xae, 0xbd, 0x55, 0xdc, 0xae, 0xed, + 0xde, 0x5d, 0x8d, 0xd5, 0xea, 0x73, 0xa1, 0x0e, 0x83, 0x69, 0x37, 0x51, 0x62, 0x46, 0xd7, 0xa6, + 0x46, 0xd3, 0x51, 0xcf, 0xd8, 0x4c, 0x4e, 0x83, 0x11, 0x73, 0x4b, 0x26, 0x6a, 0xa6, 0x23, 0x0c, + 0x6f, 0x02, 0x11, 0xba, 0x65, 0xbc, 0x30, 0x0a, 0xd9, 0x81, 0xea, 0x19, 0x9b, 0xf9, 0x42, 0x23, + 0xe5, 0xae, 0x61, 0xe2, 0x64, 0xf1, 0xb1, 0x0c, 0x43, 0x0c, 0x63, 0xd0, 0xdc, 0x06, 0x5b, 0xcd, + 0xa6, 0xcc, 0xad, 0x6c, 0x59, 0xdb, 0x8d, 0xdd, 0xcd, 0xd5, 0xc4, 0x86, 0xb3, 0x29, 0xa3, 0x68, + 0x41, 0xb6, 0xc1, 0x09, 0x4f, 0x7c, 0x5d, 0x91, 0xcf, 0x2f, 0x98, 0x10, 0x51, 0xc8, 0xdc, 0x2a, + 0x7e, 0xbb, 0x11, 0x9e, 0xf4, 0x82, 0x09, 0x3b, 0x4a, 0x4f, 0x49, 0x0b, 0x6c, 0x15, 0x8c, 0xa5, + 0x0b, 0x58, 0xac, 0x77, 0xa9, 0xd8, 0x61, 0x30, 0x96, 0xa6, 0x52, 0xb4, 0x23, 0xf7, 0xa0, 0x31, + 0x99, 0xc9, 0xb7, 0xb1, 0x3f, 0x87, 0xb0, 0x8e, 0x71, 0xd7, 0xf1, 0xf4, 0x79, 0x86, 0xe3, 0x5d, + 0x00, 0x63, 0xa6, 0xe1, 0x71, 0xd7, 0xb7, 0xac, 0xed, 0x12, 0xad, 0xe2, 0x89, 0x46, 0xcf, 0x7b, + 0x0c, 0xf5, 0x3c, 0x8a, 0xba, 0xb9, 0x67, 0x6c, 0x96, 0xf6, 0x5b, 0x8b, 0x1a, 0xb2, 0x8b, 0x20, + 0x3e, 0x37, 0x1d, 0x2a, 0x51, 0xa3, 0x3c, 0x2e, 0xec, 0x59, 0xde, 0x57, 0x50, 0x9d, 0x27, 0xf5, + 0x5f, 0x8e, 0xd5, 0x9c, 0xe3, 0x0b, 0xbb, 0x52, 0x74, 0xec, 0x17, 0x76, 0xa5, 0xe6, 0xd4, 0x9b, + 0xbf, 0x96, 0xa1, 0x34, 0xc0, 0x2e, 0xec, 0x41, 0x7d, 0x12, 0x48, 0xc5, 0x84, 0x7f, 0x8d, 0x09, + 0xaa, 0x19, 0x53, 0x33, 0xa5, 0x4b, 0xfd, 0x2b, 0x5c, 0xa3, 0x7f, 0x5f, 0x43, 0x5d, 0x32, 0x71, + 0xc1, 0x42, 0x5f, 0x37, 0x49, 0xba, 0xc5, 0x55, 0xcc, 0x31, 0xa3, 0xd6, 0x00, 0x6d, 0xb0, 0x9b, + 0x35, 0x39, 0x97, 0x25, 0x79, 0x02, 0xeb, 0x92, 0x9f, 0x8b, 0x11, 0xf3, 0x71, 0x7e, 0x64, 0x3a, + 0xa0, 0x1f, 0x5d, 0xf2, 0x47, 0x23, 0x94, 0x69, 0x5d, 0x2e, 0x14, 0x49, 0x9e, 0xc1, 0x86, 0xc2, + 0x6a, 0xfc, 0x11, 0x4f, 0x94, 0xe0, 0xb1, 0x74, 0xcb, 0xab, 0x43, 0x6e, 0x62, 0x98, 0xa2, 0x3b, + 0xc6, 0x8a, 0x36, 0x54, 0x5e, 0x95, 0xe4, 0x3e, 0xdc, 0x8a, 0xa4, 0x9f, 0xc2, 0xa6, 0x53, 0x8c, + 0x92, 0x31, 0x4e, 0x70, 0x85, 0x6e, 0x44, 0xf2, 0x10, 0xcf, 0x07, 0xe6, 0xd8, 0x7b, 0x0d, 0xb0, + 0x28, 0x88, 0x3c, 0x82, 0x5a, 0x9a, 0x01, 0x4e, 0xb2, 0x75, 0xc5, 0x24, 0x83, 0x9a, 0xcb, 0xba, + 0xa9, 0x7a, 0x09, 0x48, 0xb7, 0xb0, 0x55, 0xd4, 0x4d, 0x45, 0xc5, 0xfb, 0xcd, 0x82, 0x5a, 0xae, + 0xd8, 0x6c, 0x45, 0x58, 0xf3, 0x15, 0xb1, 0x44, 0xca, 0xc2, 0xbb, 0x48, 0x59, 0x7c, 0x27, 0x29, + 0xed, 0x6b, 0x34, 0xf5, 0x0e, 0x94, 0x31, 0x51, 0xe9, 0x96, 0x30, 0xb7, 0x54, 0xf3, 0x7e, 0xb7, + 0x60, 0x7d, 0x09, 0xc5, 0x1b, 0xad, 0x9d, 0x7c, 0x0e, 0xe4, 0x24, 0x0e, 0x46, 0x67, 0x71, 0x24, + 0x95, 0x1e, 0x28, 0x93, 0x82, 0x8d, 0x26, 0xb7, 0x72, 0x37, 0x18, 0x54, 0xea, 0x2c, 0x4f, 0x05, + 0xff, 0x91, 0x25, 0xb8, 0x9b, 0x2a, 0x34, 0xd5, 0xe6, 0x9c, 0x28, 0x39, 0xe5, 0xe6, 0x9f, 0x05, + 0xdc, 0xdc, 0x06, 0x9d, 0x2f, 0x60, 0x13, 0x01, 0x89, 0x92, 0xb1, 0x3f, 0xe2, 0xf1, 0xf9, 0x24, + 0xc1, 0x75, 0x92, 0x32, 0x8d, 0x64, 0x77, 0x1d, 0xbc, 0xd2, 0x1b, 0x85, 0xbc, 0xb8, 0xec, 0x81, + 0x75, 0x16, 0xb0, 0x4e, 0x77, 0x09, 0x44, 0xfc, 0xc6, 0x81, 0x99, 0xf1, 0x95, 0x58, 0x58, 0xf3, + 0x93, 0x39, 0x53, 0x4e, 0x05, 0x9f, 0xc8, 0xcb, 0xab, 0x38, 0x8b, 0x91, 0x92, 0xe5, 0x99, 0xe0, + 0x93, 0x8c, 0x2c, 0x5a, 0x96, 0xde, 0x79, 0x36, 0x76, 0x5a, 0xbd, 0x59, 0xe8, 0xf3, 0x43, 0x55, + 0x5c, 0x1e, 0x2a, 0x83, 0x67, 0xf3, 0x27, 0x0b, 0x1c, 0xc3, 0x3f, 0x36, 0x8d, 0xa3, 0x51, 0xa0, + 0x22, 0x9e, 0x90, 0x47, 0x50, 0x4a, 0x78, 0xc8, 0xf4, 0x86, 0xd1, 0xc5, 0x7c, 0xb2, 0x42, 0xb9, + 0x9c, 0x69, 0xab, 0xc7, 0x43, 0x46, 0x8d, 0xb5, 0xf7, 0x04, 0x6c, 0xad, 0xea, 0x3d, 0x95, 0x96, + 0x70, 0x9d, 0x3d, 0xa5, 0x16, 0x4a, 0xf3, 0x18, 0x1a, 0xe9, 0x17, 0x4e, 0x99, 0x60, 0xc9, 0x88, + 0xe9, 0xf7, 0x35, 0xd7, 0x4c, 0x94, 0xdf, 0x7b, 0x9b, 0x35, 0x7f, 0xb6, 0x80, 0x60, 0xdc, 0xe5, + 0x29, 0xbf, 0x89, 0xd8, 0xe4, 0x21, 0xdc, 0x79, 0x7b, 0xce, 0xc4, 0xcc, 0x2c, 0x97, 0x11, 0xf3, + 0xc3, 0x48, 0xea, 0xaf, 0x18, 0xb2, 0x56, 0xe8, 0x26, 0xde, 0x0e, 0xcc, 0xe5, 0x7e, 0x7a, 0xd7, + 0xfc, 0xdb, 0x86, 0xda, 0x40, 0x5c, 0xcc, 0x67, 0xf8, 0x1b, 0x80, 0x69, 0x20, 0x54, 0xa4, 0x31, + 0xcd, 0x60, 0xff, 0x34, 0x07, 0xfb, 0xc2, 0x74, 0x3e, 0x4f, 0xfd, 0xcc, 0x9e, 0xe6, 0x5c, 0xdf, + 0x49, 0x86, 0xc2, 0x7b, 0x93, 0xa1, 0xf8, 0x3f, 0xc8, 0xd0, 0x86, 0x5a, 0x8e, 0x0c, 0x29, 0x17, + 0xb6, 0xfe, 0xbd, 0x8e, 0x1c, 0x1d, 0x60, 0x41, 0x07, 0xef, 0x2f, 0x0b, 0x6e, 0x5d, 0x2a, 0x51, + 0xb3, 0x22, 0xf7, 0x1e, 0x5d, 0xcd, 0x8a, 0xc5, 0x43, 0x44, 0x3a, 0xe0, 0x60, 0x96, 0xbe, 0xc8, + 0x06, 0xca, 0x10, 0xa4, 0x96, 0xaf, 0x6b, 0x79, 0xe2, 0xe8, 0x86, 0x5c, 0xd2, 0x25, 0xe9, 0xc3, + 0x6d, 0x13, 0x64, 0xf5, 0x41, 0x32, 0x8f, 0xe2, 0xc7, 0x2b, 0x91, 0x96, 0xdf, 0xa3, 0x0f, 0xe5, + 0xa5, 0x33, 0xe9, 0xf9, 0x37, 0xc1, 0xf8, 0x2b, 0x1e, 0x8c, 0x74, 0x4b, 0xfe, 0x00, 0x95, 0x0e, + 0x8b, 0xe3, 0x83, 0xe4, 0x94, 0xeb, 0x1f, 0x43, 0x88, 0x8b, 0xf0, 0x83, 0x30, 0x14, 0x4c, 0xca, + 0x74, 0xea, 0xd7, 0xcd, 0x69, 0xdb, 0x1c, 0x6a, 0x4a, 0x08, 0xce, 0x55, 0x1a, 0x10, 0x65, 0xbd, + 0x90, 0x05, 0x1b, 0x47, 0x3c, 0x49, 0x57, 0x48, 0xaa, 0xdd, 0xdf, 0x85, 0xc6, 0xf2, 0x48, 0x90, + 0x2a, 0x94, 0x8e, 0x7b, 0x83, 0xee, 0xd0, 0xf9, 0x80, 0x00, 0x94, 0x8f, 0x0f, 0x7a, 0xc3, 0x2f, + 0x1f, 0x3a, 0x96, 0x3e, 0x7e, 0xfa, 0x7a, 0xd8, 0x1d, 0x38, 0x85, 0xfb, 0xbf, 0x58, 0x00, 0x8b, + 0x7a, 0x48, 0x0d, 0xd6, 0x8e, 0x7b, 0x2f, 0x7b, 0x47, 0xdf, 0xf6, 0x8c, 0xcb, 0x61, 0x7b, 0x30, + 0xec, 0x52, 0xc7, 0xd2, 0x17, 0xb4, 0xdb, 0x7f, 0x75, 0xd0, 0x69, 0x3b, 0x05, 0x7d, 0x41, 0xf7, + 0x8f, 0x7a, 0xaf, 0x5e, 0x3b, 0x45, 0x8c, 0xd5, 0x1e, 0x76, 0x9e, 0x1b, 0x71, 0xd0, 0x6f, 0xd3, + 0xae, 0x63, 0x13, 0x07, 0xea, 0xdd, 0xef, 0xfa, 0x5d, 0x7a, 0x70, 0xd8, 0xed, 0x0d, 0xdb, 0xaf, + 0x9c, 0x92, 0xf6, 0x79, 0xda, 0xee, 0xbc, 0x3c, 0xee, 0x3b, 0x65, 0x13, 0x6c, 0x30, 0x3c, 0xa2, + 0x5d, 0x67, 0x4d, 0x2b, 0xfb, 0xb4, 0x7d, 0xd0, 0xeb, 0xee, 0x3b, 0x15, 0xaf, 0xe0, 0x58, 0x4f, + 0xf7, 0x60, 0x23, 0xe2, 0xad, 0x8b, 0x48, 0x31, 0x29, 0xcd, 0x3f, 0x84, 0xef, 0xef, 0xa5, 0x5a, + 0xc4, 0x77, 0x8c, 0xb4, 0x33, 0xe6, 0x3b, 0x17, 0x6a, 0x07, 0x6f, 0x77, 0xb2, 0xc6, 0x9c, 0x94, + 0x51, 0x7f, 0xf0, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd2, 0x59, 0xb6, 0xea, 0x61, 0x0c, 0x00, + 0x00, } diff --git a/go/vt/proto/vtgate/vtgate.pb.go b/go/vt/proto/vtgate/vtgate.pb.go index ae204d1e8ac..e57b87e3dc0 100644 --- a/go/vt/proto/vtgate/vtgate.pb.go +++ b/go/vt/proto/vtgate/vtgate.pb.go @@ -53,7 +53,7 @@ func (x TransactionMode) String() string { return proto.EnumName(TransactionMode_name, int32(x)) } func (TransactionMode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{0} } // Session objects are exchanged like cookies through various @@ -98,7 +98,7 @@ func (m *Session) Reset() { *m = Session{} } func (m *Session) String() string { return proto.CompactTextString(m) } func (*Session) ProtoMessage() {} func (*Session) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{0} } func (m *Session) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Session.Unmarshal(m, b) @@ -186,7 +186,7 @@ func (m *Session_ShardSession) Reset() { *m = Session_ShardSession{} } func (m *Session_ShardSession) String() string { return proto.CompactTextString(m) } func (*Session_ShardSession) ProtoMessage() {} func (*Session_ShardSession) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{0, 0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{0, 0} } func (m *Session_ShardSession) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Session_ShardSession.Unmarshal(m, b) @@ -244,7 +244,7 @@ func (m *ExecuteRequest) Reset() { *m = ExecuteRequest{} } func (m *ExecuteRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteRequest) ProtoMessage() {} func (*ExecuteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{1} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{1} } func (m *ExecuteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteRequest.Unmarshal(m, b) @@ -332,7 +332,7 @@ func (m *ExecuteResponse) Reset() { *m = ExecuteResponse{} } func (m *ExecuteResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteResponse) ProtoMessage() {} func (*ExecuteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{2} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{2} } func (m *ExecuteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteResponse.Unmarshal(m, b) @@ -402,7 +402,7 @@ func (m *ExecuteShardsRequest) Reset() { *m = ExecuteShardsRequest{} } func (m *ExecuteShardsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteShardsRequest) ProtoMessage() {} func (*ExecuteShardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{3} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{3} } func (m *ExecuteShardsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteShardsRequest.Unmarshal(m, b) @@ -497,7 +497,7 @@ func (m *ExecuteShardsResponse) Reset() { *m = ExecuteShardsResponse{} } func (m *ExecuteShardsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteShardsResponse) ProtoMessage() {} func (*ExecuteShardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{4} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{4} } func (m *ExecuteShardsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteShardsResponse.Unmarshal(m, b) @@ -568,7 +568,7 @@ func (m *ExecuteKeyspaceIdsRequest) Reset() { *m = ExecuteKeyspaceIdsReq func (m *ExecuteKeyspaceIdsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteKeyspaceIdsRequest) ProtoMessage() {} func (*ExecuteKeyspaceIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{5} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{5} } func (m *ExecuteKeyspaceIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteKeyspaceIdsRequest.Unmarshal(m, b) @@ -663,7 +663,7 @@ func (m *ExecuteKeyspaceIdsResponse) Reset() { *m = ExecuteKeyspaceIdsRe func (m *ExecuteKeyspaceIdsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteKeyspaceIdsResponse) ProtoMessage() {} func (*ExecuteKeyspaceIdsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{6} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{6} } func (m *ExecuteKeyspaceIdsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteKeyspaceIdsResponse.Unmarshal(m, b) @@ -734,7 +734,7 @@ func (m *ExecuteKeyRangesRequest) Reset() { *m = ExecuteKeyRangesRequest func (m *ExecuteKeyRangesRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteKeyRangesRequest) ProtoMessage() {} func (*ExecuteKeyRangesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{7} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{7} } func (m *ExecuteKeyRangesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteKeyRangesRequest.Unmarshal(m, b) @@ -829,7 +829,7 @@ func (m *ExecuteKeyRangesResponse) Reset() { *m = ExecuteKeyRangesRespon func (m *ExecuteKeyRangesResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteKeyRangesResponse) ProtoMessage() {} func (*ExecuteKeyRangesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{8} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{8} } func (m *ExecuteKeyRangesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteKeyRangesResponse.Unmarshal(m, b) @@ -902,7 +902,7 @@ func (m *ExecuteEntityIdsRequest) Reset() { *m = ExecuteEntityIdsRequest func (m *ExecuteEntityIdsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteEntityIdsRequest) ProtoMessage() {} func (*ExecuteEntityIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{9} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{9} } func (m *ExecuteEntityIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteEntityIdsRequest.Unmarshal(m, b) @@ -1001,7 +1001,7 @@ func (m *ExecuteEntityIdsRequest_EntityId) Reset() { *m = ExecuteEntityI func (m *ExecuteEntityIdsRequest_EntityId) String() string { return proto.CompactTextString(m) } func (*ExecuteEntityIdsRequest_EntityId) ProtoMessage() {} func (*ExecuteEntityIdsRequest_EntityId) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{9, 0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{9, 0} } func (m *ExecuteEntityIdsRequest_EntityId) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteEntityIdsRequest_EntityId.Unmarshal(m, b) @@ -1061,7 +1061,7 @@ func (m *ExecuteEntityIdsResponse) Reset() { *m = ExecuteEntityIdsRespon func (m *ExecuteEntityIdsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteEntityIdsResponse) ProtoMessage() {} func (*ExecuteEntityIdsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{10} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{10} } func (m *ExecuteEntityIdsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteEntityIdsResponse.Unmarshal(m, b) @@ -1126,7 +1126,7 @@ func (m *ExecuteBatchRequest) Reset() { *m = ExecuteBatchRequest{} } func (m *ExecuteBatchRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchRequest) ProtoMessage() {} func (*ExecuteBatchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{11} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{11} } func (m *ExecuteBatchRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchRequest.Unmarshal(m, b) @@ -1214,7 +1214,7 @@ func (m *ExecuteBatchResponse) Reset() { *m = ExecuteBatchResponse{} } func (m *ExecuteBatchResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchResponse) ProtoMessage() {} func (*ExecuteBatchResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{12} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{12} } func (m *ExecuteBatchResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchResponse.Unmarshal(m, b) @@ -1274,7 +1274,7 @@ func (m *BoundShardQuery) Reset() { *m = BoundShardQuery{} } func (m *BoundShardQuery) String() string { return proto.CompactTextString(m) } func (*BoundShardQuery) ProtoMessage() {} func (*BoundShardQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{13} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{13} } func (m *BoundShardQuery) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BoundShardQuery.Unmarshal(m, b) @@ -1342,7 +1342,7 @@ func (m *ExecuteBatchShardsRequest) Reset() { *m = ExecuteBatchShardsReq func (m *ExecuteBatchShardsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchShardsRequest) ProtoMessage() {} func (*ExecuteBatchShardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{14} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{14} } func (m *ExecuteBatchShardsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchShardsRequest.Unmarshal(m, b) @@ -1423,7 +1423,7 @@ func (m *ExecuteBatchShardsResponse) Reset() { *m = ExecuteBatchShardsRe func (m *ExecuteBatchShardsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchShardsResponse) ProtoMessage() {} func (*ExecuteBatchShardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{15} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{15} } func (m *ExecuteBatchShardsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchShardsResponse.Unmarshal(m, b) @@ -1484,7 +1484,7 @@ func (m *BoundKeyspaceIdQuery) Reset() { *m = BoundKeyspaceIdQuery{} } func (m *BoundKeyspaceIdQuery) String() string { return proto.CompactTextString(m) } func (*BoundKeyspaceIdQuery) ProtoMessage() {} func (*BoundKeyspaceIdQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{16} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{16} } func (m *BoundKeyspaceIdQuery) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BoundKeyspaceIdQuery.Unmarshal(m, b) @@ -1551,7 +1551,7 @@ func (m *ExecuteBatchKeyspaceIdsRequest) Reset() { *m = ExecuteBatchKeys func (m *ExecuteBatchKeyspaceIdsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchKeyspaceIdsRequest) ProtoMessage() {} func (*ExecuteBatchKeyspaceIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{17} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{17} } func (m *ExecuteBatchKeyspaceIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchKeyspaceIdsRequest.Unmarshal(m, b) @@ -1632,7 +1632,7 @@ func (m *ExecuteBatchKeyspaceIdsResponse) Reset() { *m = ExecuteBatchKey func (m *ExecuteBatchKeyspaceIdsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchKeyspaceIdsResponse) ProtoMessage() {} func (*ExecuteBatchKeyspaceIdsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{18} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{18} } func (m *ExecuteBatchKeyspaceIdsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchKeyspaceIdsResponse.Unmarshal(m, b) @@ -1696,7 +1696,7 @@ func (m *StreamExecuteRequest) Reset() { *m = StreamExecuteRequest{} } func (m *StreamExecuteRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteRequest) ProtoMessage() {} func (*StreamExecuteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{19} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{19} } func (m *StreamExecuteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteRequest.Unmarshal(m, b) @@ -1775,7 +1775,7 @@ func (m *StreamExecuteResponse) Reset() { *m = StreamExecuteResponse{} } func (m *StreamExecuteResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteResponse) ProtoMessage() {} func (*StreamExecuteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{20} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{20} } func (m *StreamExecuteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteResponse.Unmarshal(m, b) @@ -1826,7 +1826,7 @@ func (m *StreamExecuteShardsRequest) Reset() { *m = StreamExecuteShardsR func (m *StreamExecuteShardsRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteShardsRequest) ProtoMessage() {} func (*StreamExecuteShardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{21} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{21} } func (m *StreamExecuteShardsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteShardsRequest.Unmarshal(m, b) @@ -1903,7 +1903,7 @@ func (m *StreamExecuteShardsResponse) Reset() { *m = StreamExecuteShards func (m *StreamExecuteShardsResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteShardsResponse) ProtoMessage() {} func (*StreamExecuteShardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{22} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{22} } func (m *StreamExecuteShardsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteShardsResponse.Unmarshal(m, b) @@ -1955,7 +1955,7 @@ func (m *StreamExecuteKeyspaceIdsRequest) Reset() { *m = StreamExecuteKe func (m *StreamExecuteKeyspaceIdsRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteKeyspaceIdsRequest) ProtoMessage() {} func (*StreamExecuteKeyspaceIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{23} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{23} } func (m *StreamExecuteKeyspaceIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteKeyspaceIdsRequest.Unmarshal(m, b) @@ -2032,7 +2032,7 @@ func (m *StreamExecuteKeyspaceIdsResponse) Reset() { *m = StreamExecuteK func (m *StreamExecuteKeyspaceIdsResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteKeyspaceIdsResponse) ProtoMessage() {} func (*StreamExecuteKeyspaceIdsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{24} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{24} } func (m *StreamExecuteKeyspaceIdsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteKeyspaceIdsResponse.Unmarshal(m, b) @@ -2084,7 +2084,7 @@ func (m *StreamExecuteKeyRangesRequest) Reset() { *m = StreamExecuteKeyR func (m *StreamExecuteKeyRangesRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteKeyRangesRequest) ProtoMessage() {} func (*StreamExecuteKeyRangesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{25} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{25} } func (m *StreamExecuteKeyRangesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteKeyRangesRequest.Unmarshal(m, b) @@ -2161,7 +2161,7 @@ func (m *StreamExecuteKeyRangesResponse) Reset() { *m = StreamExecuteKey func (m *StreamExecuteKeyRangesResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteKeyRangesResponse) ProtoMessage() {} func (*StreamExecuteKeyRangesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{26} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{26} } func (m *StreamExecuteKeyRangesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteKeyRangesResponse.Unmarshal(m, b) @@ -2207,7 +2207,7 @@ func (m *BeginRequest) Reset() { *m = BeginRequest{} } func (m *BeginRequest) String() string { return proto.CompactTextString(m) } func (*BeginRequest) ProtoMessage() {} func (*BeginRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{27} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{27} } func (m *BeginRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginRequest.Unmarshal(m, b) @@ -2254,7 +2254,7 @@ func (m *BeginResponse) Reset() { *m = BeginResponse{} } func (m *BeginResponse) String() string { return proto.CompactTextString(m) } func (*BeginResponse) ProtoMessage() {} func (*BeginResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{28} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{28} } func (m *BeginResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginResponse.Unmarshal(m, b) @@ -2302,7 +2302,7 @@ func (m *CommitRequest) Reset() { *m = CommitRequest{} } func (m *CommitRequest) String() string { return proto.CompactTextString(m) } func (*CommitRequest) ProtoMessage() {} func (*CommitRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{29} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{29} } func (m *CommitRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CommitRequest.Unmarshal(m, b) @@ -2354,7 +2354,7 @@ func (m *CommitResponse) Reset() { *m = CommitResponse{} } func (m *CommitResponse) String() string { return proto.CompactTextString(m) } func (*CommitResponse) ProtoMessage() {} func (*CommitResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{30} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{30} } func (m *CommitResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CommitResponse.Unmarshal(m, b) @@ -2390,7 +2390,7 @@ func (m *RollbackRequest) Reset() { *m = RollbackRequest{} } func (m *RollbackRequest) String() string { return proto.CompactTextString(m) } func (*RollbackRequest) ProtoMessage() {} func (*RollbackRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{31} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{31} } func (m *RollbackRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RollbackRequest.Unmarshal(m, b) @@ -2435,7 +2435,7 @@ func (m *RollbackResponse) Reset() { *m = RollbackResponse{} } func (m *RollbackResponse) String() string { return proto.CompactTextString(m) } func (*RollbackResponse) ProtoMessage() {} func (*RollbackResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{32} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{32} } func (m *RollbackResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RollbackResponse.Unmarshal(m, b) @@ -2471,7 +2471,7 @@ func (m *ResolveTransactionRequest) Reset() { *m = ResolveTransactionReq func (m *ResolveTransactionRequest) String() string { return proto.CompactTextString(m) } func (*ResolveTransactionRequest) ProtoMessage() {} func (*ResolveTransactionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{33} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{33} } func (m *ResolveTransactionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResolveTransactionRequest.Unmarshal(m, b) @@ -2527,7 +2527,7 @@ func (m *MessageStreamRequest) Reset() { *m = MessageStreamRequest{} } func (m *MessageStreamRequest) String() string { return proto.CompactTextString(m) } func (*MessageStreamRequest) ProtoMessage() {} func (*MessageStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{34} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{34} } func (m *MessageStreamRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageStreamRequest.Unmarshal(m, b) @@ -2602,7 +2602,7 @@ func (m *MessageAckRequest) Reset() { *m = MessageAckRequest{} } func (m *MessageAckRequest) String() string { return proto.CompactTextString(m) } func (*MessageAckRequest) ProtoMessage() {} func (*MessageAckRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{35} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{35} } func (m *MessageAckRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageAckRequest.Unmarshal(m, b) @@ -2666,7 +2666,7 @@ func (m *IdKeyspaceId) Reset() { *m = IdKeyspaceId{} } func (m *IdKeyspaceId) String() string { return proto.CompactTextString(m) } func (*IdKeyspaceId) ProtoMessage() {} func (*IdKeyspaceId) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{36} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{36} } func (m *IdKeyspaceId) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IdKeyspaceId.Unmarshal(m, b) @@ -2719,7 +2719,7 @@ func (m *MessageAckKeyspaceIdsRequest) Reset() { *m = MessageAckKeyspace func (m *MessageAckKeyspaceIdsRequest) String() string { return proto.CompactTextString(m) } func (*MessageAckKeyspaceIdsRequest) ProtoMessage() {} func (*MessageAckKeyspaceIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{37} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{37} } func (m *MessageAckKeyspaceIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageAckKeyspaceIdsRequest.Unmarshal(m, b) @@ -2778,7 +2778,7 @@ func (m *ResolveTransactionResponse) Reset() { *m = ResolveTransactionRe func (m *ResolveTransactionResponse) String() string { return proto.CompactTextString(m) } func (*ResolveTransactionResponse) ProtoMessage() {} func (*ResolveTransactionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{38} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{38} } func (m *ResolveTransactionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResolveTransactionResponse.Unmarshal(m, b) @@ -2896,7 +2896,7 @@ func (m *SplitQueryRequest) Reset() { *m = SplitQueryRequest{} } func (m *SplitQueryRequest) String() string { return proto.CompactTextString(m) } func (*SplitQueryRequest) ProtoMessage() {} func (*SplitQueryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{39} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{39} } func (m *SplitQueryRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryRequest.Unmarshal(m, b) @@ -2985,7 +2985,7 @@ func (m *SplitQueryResponse) Reset() { *m = SplitQueryResponse{} } func (m *SplitQueryResponse) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse) ProtoMessage() {} func (*SplitQueryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{40} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{40} } func (m *SplitQueryResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse.Unmarshal(m, b) @@ -3026,7 +3026,7 @@ func (m *SplitQueryResponse_KeyRangePart) Reset() { *m = SplitQueryRespo func (m *SplitQueryResponse_KeyRangePart) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse_KeyRangePart) ProtoMessage() {} func (*SplitQueryResponse_KeyRangePart) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{40, 0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{40, 0} } func (m *SplitQueryResponse_KeyRangePart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse_KeyRangePart.Unmarshal(m, b) @@ -3074,7 +3074,7 @@ func (m *SplitQueryResponse_ShardPart) Reset() { *m = SplitQueryResponse func (m *SplitQueryResponse_ShardPart) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse_ShardPart) ProtoMessage() {} func (*SplitQueryResponse_ShardPart) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{40, 1} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{40, 1} } func (m *SplitQueryResponse_ShardPart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse_ShardPart.Unmarshal(m, b) @@ -3127,7 +3127,7 @@ func (m *SplitQueryResponse_Part) Reset() { *m = SplitQueryResponse_Part func (m *SplitQueryResponse_Part) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse_Part) ProtoMessage() {} func (*SplitQueryResponse_Part) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{40, 2} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{40, 2} } func (m *SplitQueryResponse_Part) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse_Part.Unmarshal(m, b) @@ -3188,7 +3188,7 @@ func (m *GetSrvKeyspaceRequest) Reset() { *m = GetSrvKeyspaceRequest{} } func (m *GetSrvKeyspaceRequest) String() string { return proto.CompactTextString(m) } func (*GetSrvKeyspaceRequest) ProtoMessage() {} func (*GetSrvKeyspaceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{41} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{41} } func (m *GetSrvKeyspaceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSrvKeyspaceRequest.Unmarshal(m, b) @@ -3228,7 +3228,7 @@ func (m *GetSrvKeyspaceResponse) Reset() { *m = GetSrvKeyspaceResponse{} func (m *GetSrvKeyspaceResponse) String() string { return proto.CompactTextString(m) } func (*GetSrvKeyspaceResponse) ProtoMessage() {} func (*GetSrvKeyspaceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{42} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{42} } func (m *GetSrvKeyspaceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSrvKeyspaceResponse.Unmarshal(m, b) @@ -3286,7 +3286,7 @@ func (m *UpdateStreamRequest) Reset() { *m = UpdateStreamRequest{} } func (m *UpdateStreamRequest) String() string { return proto.CompactTextString(m) } func (*UpdateStreamRequest) ProtoMessage() {} func (*UpdateStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{43} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{43} } func (m *UpdateStreamRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateStreamRequest.Unmarshal(m, b) @@ -3374,7 +3374,7 @@ func (m *UpdateStreamResponse) Reset() { *m = UpdateStreamResponse{} } func (m *UpdateStreamResponse) String() string { return proto.CompactTextString(m) } func (*UpdateStreamResponse) ProtoMessage() {} func (*UpdateStreamResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{44} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{44} } func (m *UpdateStreamResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateStreamResponse.Unmarshal(m, b) @@ -3462,9 +3462,9 @@ func init() { proto.RegisterEnum("vtgate.TransactionMode", TransactionMode_name, TransactionMode_value) } -func init() { proto.RegisterFile("vtgate.proto", fileDescriptor_vtgate_8f5c6038eac4796e) } +func init() { proto.RegisterFile("vtgate.proto", fileDescriptor_vtgate_1d4a858d9b127f46) } -var fileDescriptor_vtgate_8f5c6038eac4796e = []byte{ +var fileDescriptor_vtgate_1d4a858d9b127f46 = []byte{ // 1883 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0x4f, 0x8f, 0x23, 0x47, 0x15, 0xa7, 0xbb, 0xfd, 0xf7, 0xf9, 0xef, 0xd6, 0x78, 0x77, 0x1d, 0x67, 0xd8, 0x99, 0x74, 0x18, diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index 76d05808f3f..1b0a94e76b6 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -429,6 +429,16 @@ func (si *ShardInfo) removeCellsFromTabletControl(tc *topodatapb.Shard_TabletCon } } +// GetServedType returns the Shard_ServedType for a TabletType, or nil +func (si *ShardInfo) GetServedType(tabletType topodatapb.TabletType) *topodatapb.Shard_ServedType { + for _, st := range si.ServedTypes { + if st.TabletType == tabletType { + return st + } + } + return nil +} + // // Utility functions for shards // diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index 3f99606abcb..513849854ae 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -81,6 +81,20 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser // value: topo.SrvKeyspace object being built srvKeyspaceMap := make(map[string]*topodatapb.SrvKeyspace) for _, cell := range cells { + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + switch { + case err == nil: + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetShardTabletControls() != nil { + return fmt.Errorf("can't rebuild serving keyspace while a migration is on going. TabletControls is set for partition %v", partition) + } + + } + case topo.IsErrType(err, topo.NoNode): + // NOOP + default: + return err + } srvKeyspaceMap[cell] = &topodatapb.SrvKeyspace{ ShardingColumnName: ki.ShardingColumnName, ShardingColumnType: ki.ShardingColumnType, @@ -97,7 +111,10 @@ func RebuildKeyspaceLocked(ctx context.Context, log logutil.Logger, ts *topo.Ser // - check the ranges are compatible (no hole, covers everything) for cell, srvKeyspace := range srvKeyspaceMap { for _, si := range shards { - if !si.IsMasterServing { + // We rebuild keyspace iff: + // 1) shard master is in a serving state. + // 2) shard has served type for master (this is for backwards compatibility). + if !(si.IsMasterServing || si.GetServedType(topodatapb.TabletType_MASTER) != nil) { continue } // for each type this shard is supposed to serve, diff --git a/proto/topodata.proto b/proto/topodata.proto index 06c7b3d2683..870c794895a 100644 --- a/proto/topodata.proto +++ b/proto/topodata.proto @@ -173,6 +173,17 @@ message Shard { // Once set at creation time, it is never changed. KeyRange key_range = 2; + // ServedType is an entry in the served_types + message ServedType { + TabletType tablet_type = 1; + repeated string cells = 2; + } + + // served_types has at most one entry per TabletType + // This field is in the process of being deprecated in favor of + // is_master_serving. Keeping for backwards compatibility purposes. + repeated ServedType served_types = 3; + // SourceShard represents a data source for filtered replication // accross shards. When this is used in a destination shard, the master // of that shard will run filtered replication. @@ -222,8 +233,8 @@ message Shard { // The keyspace lock is always taken when changing this. bool is_master_serving = 7; - // OBSOLETE fields: served_types (3), cells (5) - reserved 3, 5; + // OBSOLETE cells (5) + reserved 5; } // A Keyspace contains data about a keyspace. diff --git a/py/vtproto/topodata_pb2.py b/py/vtproto/topodata_pb2.py index 8616429f0fe..7970c86e338 100644 --- a/py/vtproto/topodata_pb2.py +++ b/py/vtproto/topodata_pb2.py @@ -20,7 +20,7 @@ package='topodata', syntax='proto3', serialized_options=_b('\n\017io.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodata'), - serialized_pb=_b('\n\x0etopodata.proto\x12\x08topodata\"&\n\x08KeyRange\x12\r\n\x05start\x18\x01 \x01(\x0c\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x0c\"(\n\x0bTabletAlias\x12\x0c\n\x04\x63\x65ll\x18\x01 \x01(\t\x12\x0b\n\x03uid\x18\x02 \x01(\r\"\xb6\x03\n\x06Tablet\x12$\n\x05\x61lias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x10\n\x08hostname\x18\x02 \x01(\t\x12/\n\x08port_map\x18\x04 \x03(\x0b\x32\x1d.topodata.Tablet.PortMapEntry\x12\x10\n\x08keyspace\x18\x05 \x01(\t\x12\r\n\x05shard\x18\x06 \x01(\t\x12%\n\tkey_range\x18\x07 \x01(\x0b\x32\x12.topodata.KeyRange\x12\"\n\x04type\x18\x08 \x01(\x0e\x32\x14.topodata.TabletType\x12\x18\n\x10\x64\x62_name_override\x18\t \x01(\t\x12(\n\x04tags\x18\n \x03(\x0b\x32\x1a.topodata.Tablet.TagsEntry\x12\x16\n\x0emysql_hostname\x18\x0c \x01(\t\x12\x12\n\nmysql_port\x18\r \x01(\x05\x1a.\n\x0cPortMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01J\x04\x08\x03\x10\x04J\x04\x08\x0b\x10\x0c\"\xdf\x03\n\x05Shard\x12+\n\x0cmaster_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x32\n\rsource_shards\x18\x04 \x03(\x0b\x32\x1b.topodata.Shard.SourceShard\x12\x36\n\x0ftablet_controls\x18\x06 \x03(\x0b\x32\x1d.topodata.Shard.TabletControl\x12\x19\n\x11is_master_serving\x18\x07 \x01(\x08\x1ar\n\x0bSourceShard\x12\x0b\n\x03uid\x18\x01 \x01(\r\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\r\n\x05shard\x18\x03 \x01(\t\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\t\x1a{\n\rTabletControl\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x1a\n\x12\x62lacklisted_tables\x18\x04 \x03(\t\x12\x0e\n\x06\x66rozen\x18\x05 \x01(\x08J\x04\x08\x03\x10\x04J\x04\x08\x03\x10\x04J\x04\x08\x05\x10\x06\"\xf5\x01\n\x08Keyspace\x12\x1c\n\x14sharding_column_name\x18\x01 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x02 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x33\n\x0cserved_froms\x18\x04 \x03(\x0b\x32\x1d.topodata.Keyspace.ServedFrom\x1aX\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x10\n\x08keyspace\x18\x03 \x01(\tJ\x04\x08\x03\x10\x04\"w\n\x10ShardReplication\x12.\n\x05nodes\x18\x01 \x03(\x0b\x32\x1f.topodata.ShardReplication.Node\x1a\x33\n\x04Node\x12+\n\x0ctablet_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"E\n\x0eShardReference\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\"i\n\x12ShardTabletControl\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x1e\n\x16query_service_disabled\x18\x03 \x01(\x08\"\xda\x03\n\x0bSrvKeyspace\x12;\n\npartitions\x18\x01 \x03(\x0b\x32\'.topodata.SrvKeyspace.KeyspacePartition\x12\x1c\n\x14sharding_column_name\x18\x02 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x03 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x35\n\x0bserved_from\x18\x04 \x03(\x0b\x32 .topodata.SrvKeyspace.ServedFrom\x1a\xaf\x01\n\x11KeyspacePartition\x12)\n\x0bserved_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x32\n\x10shard_references\x18\x02 \x03(\x0b\x32\x18.topodata.ShardReference\x12;\n\x15shard_tablet_controls\x18\x03 \x03(\x0b\x32\x1c.topodata.ShardTabletControl\x1aI\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x10\n\x08keyspace\x18\x02 \x01(\tJ\x04\x08\x05\x10\x06\"@\n\x08\x43\x65llInfo\x12\x16\n\x0eserver_address\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\t\x12\x0e\n\x06region\x18\x03 \x01(\t*2\n\x0eKeyspaceIdType\x12\t\n\x05UNSET\x10\x00\x12\n\n\x06UINT64\x10\x01\x12\t\n\x05\x42YTES\x10\x02*\x90\x01\n\nTabletType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06MASTER\x10\x01\x12\x0b\n\x07REPLICA\x10\x02\x12\n\n\x06RDONLY\x10\x03\x12\t\n\x05\x42\x41TCH\x10\x03\x12\t\n\x05SPARE\x10\x04\x12\x10\n\x0c\x45XPERIMENTAL\x10\x05\x12\n\n\x06\x42\x41\x43KUP\x10\x06\x12\x0b\n\x07RESTORE\x10\x07\x12\x0b\n\x07\x44RAINED\x10\x08\x1a\x02\x10\x01\x42\x38\n\x0fio.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodatab\x06proto3') + serialized_pb=_b('\n\x0etopodata.proto\x12\x08topodata\"&\n\x08KeyRange\x12\r\n\x05start\x18\x01 \x01(\x0c\x12\x0b\n\x03\x65nd\x18\x02 \x01(\x0c\"(\n\x0bTabletAlias\x12\x0c\n\x04\x63\x65ll\x18\x01 \x01(\t\x12\x0b\n\x03uid\x18\x02 \x01(\r\"\xb6\x03\n\x06Tablet\x12$\n\x05\x61lias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x10\n\x08hostname\x18\x02 \x01(\t\x12/\n\x08port_map\x18\x04 \x03(\x0b\x32\x1d.topodata.Tablet.PortMapEntry\x12\x10\n\x08keyspace\x18\x05 \x01(\t\x12\r\n\x05shard\x18\x06 \x01(\t\x12%\n\tkey_range\x18\x07 \x01(\x0b\x32\x12.topodata.KeyRange\x12\"\n\x04type\x18\x08 \x01(\x0e\x32\x14.topodata.TabletType\x12\x18\n\x10\x64\x62_name_override\x18\t \x01(\t\x12(\n\x04tags\x18\n \x03(\x0b\x32\x1a.topodata.Tablet.TagsEntry\x12\x16\n\x0emysql_hostname\x18\x0c \x01(\t\x12\x12\n\nmysql_port\x18\r \x01(\x05\x1a.\n\x0cPortMapEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\x1a+\n\tTagsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01J\x04\x08\x03\x10\x04J\x04\x08\x0b\x10\x0c\"\xd3\x04\n\x05Shard\x12+\n\x0cmaster_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x30\n\x0cserved_types\x18\x03 \x03(\x0b\x32\x1a.topodata.Shard.ServedType\x12\x32\n\rsource_shards\x18\x04 \x03(\x0b\x32\x1b.topodata.Shard.SourceShard\x12\x36\n\x0ftablet_controls\x18\x06 \x03(\x0b\x32\x1d.topodata.Shard.TabletControl\x12\x19\n\x11is_master_serving\x18\x07 \x01(\x08\x1a\x46\n\nServedType\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x1ar\n\x0bSourceShard\x12\x0b\n\x03uid\x18\x01 \x01(\r\x12\x10\n\x08keyspace\x18\x02 \x01(\t\x12\r\n\x05shard\x18\x03 \x01(\t\x12%\n\tkey_range\x18\x04 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x0e\n\x06tables\x18\x05 \x03(\t\x1a{\n\rTabletControl\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x1a\n\x12\x62lacklisted_tables\x18\x04 \x03(\t\x12\x0e\n\x06\x66rozen\x18\x05 \x01(\x08J\x04\x08\x03\x10\x04J\x04\x08\x05\x10\x06\"\xf5\x01\n\x08Keyspace\x12\x1c\n\x14sharding_column_name\x18\x01 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x02 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x33\n\x0cserved_froms\x18\x04 \x03(\x0b\x32\x1d.topodata.Keyspace.ServedFrom\x1aX\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\r\n\x05\x63\x65lls\x18\x02 \x03(\t\x12\x10\n\x08keyspace\x18\x03 \x01(\tJ\x04\x08\x03\x10\x04\"w\n\x10ShardReplication\x12.\n\x05nodes\x18\x01 \x03(\x0b\x32\x1f.topodata.ShardReplication.Node\x1a\x33\n\x04Node\x12+\n\x0ctablet_alias\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"E\n\x0eShardReference\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\"i\n\x12ShardTabletControl\x12\x0c\n\x04name\x18\x01 \x01(\t\x12%\n\tkey_range\x18\x02 \x01(\x0b\x32\x12.topodata.KeyRange\x12\x1e\n\x16query_service_disabled\x18\x03 \x01(\x08\"\xda\x03\n\x0bSrvKeyspace\x12;\n\npartitions\x18\x01 \x03(\x0b\x32\'.topodata.SrvKeyspace.KeyspacePartition\x12\x1c\n\x14sharding_column_name\x18\x02 \x01(\t\x12\x36\n\x14sharding_column_type\x18\x03 \x01(\x0e\x32\x18.topodata.KeyspaceIdType\x12\x35\n\x0bserved_from\x18\x04 \x03(\x0b\x32 .topodata.SrvKeyspace.ServedFrom\x1a\xaf\x01\n\x11KeyspacePartition\x12)\n\x0bserved_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x32\n\x10shard_references\x18\x02 \x03(\x0b\x32\x18.topodata.ShardReference\x12;\n\x15shard_tablet_controls\x18\x03 \x03(\x0b\x32\x1c.topodata.ShardTabletControl\x1aI\n\nServedFrom\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\x12\x10\n\x08keyspace\x18\x02 \x01(\tJ\x04\x08\x05\x10\x06\"@\n\x08\x43\x65llInfo\x12\x16\n\x0eserver_address\x18\x01 \x01(\t\x12\x0c\n\x04root\x18\x02 \x01(\t\x12\x0e\n\x06region\x18\x03 \x01(\t*2\n\x0eKeyspaceIdType\x12\t\n\x05UNSET\x10\x00\x12\n\n\x06UINT64\x10\x01\x12\t\n\x05\x42YTES\x10\x02*\x90\x01\n\nTabletType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06MASTER\x10\x01\x12\x0b\n\x07REPLICA\x10\x02\x12\n\n\x06RDONLY\x10\x03\x12\t\n\x05\x42\x41TCH\x10\x03\x12\t\n\x05SPARE\x10\x04\x12\x10\n\x0c\x45XPERIMENTAL\x10\x05\x12\n\n\x06\x42\x41\x43KUP\x10\x06\x12\x0b\n\x07RESTORE\x10\x07\x12\x0b\n\x07\x44RAINED\x10\x08\x1a\x02\x10\x01\x42\x38\n\x0fio.vitess.protoZ%vitess.io/vitess/go/vt/proto/topodatab\x06proto3') ) _KEYSPACEIDTYPE = _descriptor.EnumDescriptor( @@ -44,8 +44,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=2123, - serialized_end=2173, + serialized_start=2239, + serialized_end=2289, ) _sym_db.RegisterEnumDescriptor(_KEYSPACEIDTYPE) @@ -99,8 +99,8 @@ ], containing_type=None, serialized_options=_b('\020\001'), - serialized_start=2176, - serialized_end=2320, + serialized_start=2292, + serialized_end=2436, ) _sym_db.RegisterEnumDescriptor(_TABLETTYPE) @@ -372,6 +372,43 @@ ) +_SHARD_SERVEDTYPE = _descriptor.Descriptor( + name='ServedType', + full_name='topodata.Shard.ServedType', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='tablet_type', full_name='topodata.Shard.ServedType.tablet_type', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='cells', full_name='topodata.Shard.ServedType.cells', index=1, + number=2, type=9, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=830, + serialized_end=900, +) + _SHARD_SOURCESHARD = _descriptor.Descriptor( name='SourceShard', full_name='topodata.Shard.SourceShard', @@ -426,8 +463,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=780, - serialized_end=894, + serialized_start=902, + serialized_end=1016, ) _SHARD_TABLETCONTROL = _descriptor.Descriptor( @@ -477,8 +514,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=896, - serialized_end=1019, + serialized_start=1018, + serialized_end=1141, ) _SHARD = _descriptor.Descriptor( @@ -503,21 +540,28 @@ is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='source_shards', full_name='topodata.Shard.source_shards', index=2, + name='served_types', full_name='topodata.Shard.served_types', index=2, + number=3, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='source_shards', full_name='topodata.Shard.source_shards', index=3, number=4, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='tablet_controls', full_name='topodata.Shard.tablet_controls', index=3, + name='tablet_controls', full_name='topodata.Shard.tablet_controls', index=4, number=6, type=11, cpp_type=10, label=3, has_default_value=False, default_value=[], message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), _descriptor.FieldDescriptor( - name='is_master_serving', full_name='topodata.Shard.is_master_serving', index=4, + name='is_master_serving', full_name='topodata.Shard.is_master_serving', index=5, number=7, type=8, cpp_type=7, label=1, has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, @@ -526,7 +570,7 @@ ], extensions=[ ], - nested_types=[_SHARD_SOURCESHARD, _SHARD_TABLETCONTROL, ], + nested_types=[_SHARD_SERVEDTYPE, _SHARD_SOURCESHARD, _SHARD_TABLETCONTROL, ], enum_types=[ ], serialized_options=None, @@ -536,7 +580,7 @@ oneofs=[ ], serialized_start=552, - serialized_end=1031, + serialized_end=1147, ) @@ -580,8 +624,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1185, - serialized_end=1273, + serialized_start=1301, + serialized_end=1389, ) _KEYSPACE = _descriptor.Descriptor( @@ -624,8 +668,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1034, - serialized_end=1279, + serialized_start=1150, + serialized_end=1395, ) @@ -655,8 +699,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1349, - serialized_end=1400, + serialized_start=1465, + serialized_end=1516, ) _SHARDREPLICATION = _descriptor.Descriptor( @@ -685,8 +729,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1281, - serialized_end=1400, + serialized_start=1397, + serialized_end=1516, ) @@ -723,8 +767,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1402, - serialized_end=1471, + serialized_start=1518, + serialized_end=1587, ) @@ -768,8 +812,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1473, - serialized_end=1578, + serialized_start=1589, + serialized_end=1694, ) @@ -813,8 +857,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1799, - serialized_end=1974, + serialized_start=1915, + serialized_end=2090, ) _SRVKEYSPACE_SERVEDFROM = _descriptor.Descriptor( @@ -850,8 +894,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1976, - serialized_end=2049, + serialized_start=2092, + serialized_end=2165, ) _SRVKEYSPACE = _descriptor.Descriptor( @@ -901,8 +945,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1581, - serialized_end=2055, + serialized_start=1697, + serialized_end=2171, ) @@ -946,8 +990,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2057, - serialized_end=2121, + serialized_start=2173, + serialized_end=2237, ) _TABLET_PORTMAPENTRY.containing_type = _TABLET @@ -957,12 +1001,15 @@ _TABLET.fields_by_name['key_range'].message_type = _KEYRANGE _TABLET.fields_by_name['type'].enum_type = _TABLETTYPE _TABLET.fields_by_name['tags'].message_type = _TABLET_TAGSENTRY +_SHARD_SERVEDTYPE.fields_by_name['tablet_type'].enum_type = _TABLETTYPE +_SHARD_SERVEDTYPE.containing_type = _SHARD _SHARD_SOURCESHARD.fields_by_name['key_range'].message_type = _KEYRANGE _SHARD_SOURCESHARD.containing_type = _SHARD _SHARD_TABLETCONTROL.fields_by_name['tablet_type'].enum_type = _TABLETTYPE _SHARD_TABLETCONTROL.containing_type = _SHARD _SHARD.fields_by_name['master_alias'].message_type = _TABLETALIAS _SHARD.fields_by_name['key_range'].message_type = _KEYRANGE +_SHARD.fields_by_name['served_types'].message_type = _SHARD_SERVEDTYPE _SHARD.fields_by_name['source_shards'].message_type = _SHARD_SOURCESHARD _SHARD.fields_by_name['tablet_controls'].message_type = _SHARD_TABLETCONTROL _KEYSPACE_SERVEDFROM.fields_by_name['tablet_type'].enum_type = _TABLETTYPE @@ -1036,6 +1083,13 @@ Shard = _reflection.GeneratedProtocolMessageType('Shard', (_message.Message,), dict( + ServedType = _reflection.GeneratedProtocolMessageType('ServedType', (_message.Message,), dict( + DESCRIPTOR = _SHARD_SERVEDTYPE, + __module__ = 'topodata_pb2' + # @@protoc_insertion_point(class_scope:topodata.Shard.ServedType) + )) + , + SourceShard = _reflection.GeneratedProtocolMessageType('SourceShard', (_message.Message,), dict( DESCRIPTOR = _SHARD_SOURCESHARD, __module__ = 'topodata_pb2' @@ -1054,6 +1108,7 @@ # @@protoc_insertion_point(class_scope:topodata.Shard) )) _sym_db.RegisterMessage(Shard) +_sym_db.RegisterMessage(Shard.ServedType) _sym_db.RegisterMessage(Shard.SourceShard) _sym_db.RegisterMessage(Shard.TabletControl) diff --git a/test/resharding.py b/test/resharding.py index 3963142588a..493a8bfd93a 100755 --- a/test/resharding.py +++ b/test/resharding.py @@ -984,6 +984,13 @@ def test_resharding(self): utils.check_tablet_query_service(self, shard_1_ny_rdonly, True, False) utils.check_tablet_query_service(self, shard_1_rdonly1, False, True) + # Shouldn't be able to rebuild keyspace graph while migration is on going + # (i.e there are records that have tablet controls set) + utils.run_vtctl(['RebuildKeyspaceGraph', 'test_keyspace'], + auto_log=True, + expect_fail=True, + ) + # rerun migrate to ensure it doesn't fail # skip refresh to make it go faster utils.run_vtctl(['MigrateServedTypes', '--cells=test_nj', From b00627e5823749c2590c65b79b35d7a48d5367a1 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Mon, 18 Feb 2019 19:15:21 -0800 Subject: [PATCH 095/196] Fixes test that broke due to adding back deprecated field Signed-off-by: Rafael Chacon --- go/vt/vtctld/api_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/go/vt/vtctld/api_test.go b/go/vt/vtctld/api_test.go index 31f2739b277..2d814c2131a 100644 --- a/go/vt/vtctld/api_test.go +++ b/go/vt/vtctld/api_test.go @@ -135,6 +135,7 @@ func TestAPI(t *testing.T) { "start": null, "end":"gA==" }, + "served_types": [], "source_shards": [], "tablet_controls": [], "is_master_serving": true From 1e4c7404497063ad26bf76b31167b2bc61ece48a Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 19 Feb 2019 12:16:46 -0800 Subject: [PATCH 096/196] introduce new timeout flag remote_operation_timeout. use it for short-running operations during reparent. Deprecate lock_timeout and use this one instead for topo locking Signed-off-by: deepthi --- go/vt/topo/locks.go | 23 +++++++++++++++++------ go/vt/wrangler/reparent.go | 16 +++++++++++++--- go/vt/wrangler/wrangler.go | 5 +++-- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/go/vt/topo/locks.go b/go/vt/topo/locks.go index 474e1561fea..7f5c11b7ed3 100644 --- a/go/vt/topo/locks.go +++ b/go/vt/topo/locks.go @@ -38,11 +38,18 @@ import ( var ( // DefaultLockTimeout is a good value to use as a default for // locking a shard / keyspace. - DefaultLockTimeout = 30 * time.Second + // Now used only for unlock operations + defaultLockTimeout = 30 * time.Second + // Deprecated // LockTimeout is the command line flag that introduces a shorter // timeout for locking topology structures. - LockTimeout = flag.Duration("lock_timeout", DefaultLockTimeout, "timeout for acquiring topology locks") + deprecatedLockTimeout = flag.Duration("lock_timeout", defaultLockTimeout, "deprecated: timeout for acquiring topology locks, use remote_operation_timeout") + + // RemoteOperationTimeout is used for operations where we have to + // call out to another process. + // Used for RPC calls (including topo server calls) + RemoteOperationTimeout = flag.Duration("remote_operation_timeout", 30*time.Second, "time to wait for a remote operation") ) // Lock describes a long-running lock on a keyspace or a shard. @@ -209,7 +216,7 @@ func CheckKeyspaceLocked(ctx context.Context, keyspace string) error { func (l *Lock) lockKeyspace(ctx context.Context, ts *Server, keyspace string) (LockDescriptor, error) { log.Infof("Locking keyspace %v for action %v", keyspace, l.Action) - ctx, cancel := context.WithTimeout(ctx, *LockTimeout) + ctx, cancel := context.WithTimeout(ctx, *RemoteOperationTimeout) defer cancel() span := trace.NewSpanFromContext(ctx) @@ -231,8 +238,10 @@ func (l *Lock) unlockKeyspace(ctx context.Context, ts *Server, keyspace string, // Detach from the parent timeout, but copy the trace span. // We need to still release the lock even if the parent // context timed out. + // Note that we are not using the user provided RemoteOperationTimeout + // here because it is possible that that timeout is too short. ctx = trace.CopySpan(context.TODO(), ctx) - ctx, cancel := context.WithTimeout(ctx, DefaultLockTimeout) + ctx, cancel := context.WithTimeout(ctx, defaultLockTimeout) defer cancel() span := trace.NewSpanFromContext(ctx) @@ -350,7 +359,7 @@ func CheckShardLocked(ctx context.Context, keyspace, shard string) error { func (l *Lock) lockShard(ctx context.Context, ts *Server, keyspace, shard string) (LockDescriptor, error) { log.Infof("Locking shard %v/%v for action %v", keyspace, shard, l.Action) - ctx, cancel := context.WithTimeout(ctx, *LockTimeout) + ctx, cancel := context.WithTimeout(ctx, *RemoteOperationTimeout) defer cancel() span := trace.NewSpanFromContext(ctx) @@ -372,8 +381,10 @@ func (l *Lock) lockShard(ctx context.Context, ts *Server, keyspace, shard string func (l *Lock) unlockShard(ctx context.Context, ts *Server, keyspace, shard string, lockDescriptor LockDescriptor, actionError error) error { // Detach from the parent timeout, but copy the trace span. // We need to still release the lock even if the parent context timed out. + // Note that we are not using the user provided RemoteOperationTimeout + // here because it is possible that that timeout is too short. ctx = trace.CopySpan(context.TODO(), ctx) - ctx, cancel := context.WithTimeout(ctx, DefaultLockTimeout) + ctx, cancel := context.WithTimeout(ctx, defaultLockTimeout) defer cancel() span := trace.NewSpanFromContext(ctx) diff --git a/go/vt/wrangler/reparent.go b/go/vt/wrangler/reparent.go index 7632b8bdf90..0b5bd589b4e 100644 --- a/go/vt/wrangler/reparent.go +++ b/go/vt/wrangler/reparent.go @@ -413,22 +413,32 @@ func (wr *Wrangler) plannedReparentShardLocked(ctx context.Context, ev *events.R } ev.OldMaster = *oldMasterTabletInfo.Tablet + // create a new context for the short running remote operations + remoteCtx, remoteCancel := context.WithTimeout(ctx, *topo.RemoteOperationTimeout) + defer remoteCancel() + // Demote the current master, get its replication position wr.logger.Infof("demote current master %v", shardInfo.MasterAlias) event.DispatchUpdate(ev, "demoting old master") - rp, err := wr.tmc.DemoteMaster(ctx, oldMasterTabletInfo.Tablet) + rp, err := wr.tmc.DemoteMaster(remoteCtx, oldMasterTabletInfo.Tablet) if err != nil { return fmt.Errorf("old master tablet %v DemoteMaster failed: %v", topoproto.TabletAliasString(shardInfo.MasterAlias), err) } + remoteCtx, remoteCancel = context.WithTimeout(ctx, *topo.RemoteOperationTimeout) + defer remoteCancel() + // Wait on the master-elect tablet until it reaches that position, // then promote it wr.logger.Infof("promote slave %v", masterElectTabletAliasStr) event.DispatchUpdate(ev, "promoting slave") - rp, err = wr.tmc.PromoteSlaveWhenCaughtUp(ctx, masterElectTabletInfo.Tablet, rp) + rp, err = wr.tmc.PromoteSlaveWhenCaughtUp(remoteCtx, masterElectTabletInfo.Tablet, rp) if err != nil || (ctx.Err() != nil && ctx.Err() == context.DeadlineExceeded) { + remoteCancel() // if this fails it is not enough to return an error. we should rollback all the changes made by DemoteMaster - if err1 := wr.tmc.UndoDemoteMaster(ctx, oldMasterTabletInfo.Tablet); err1 != nil { + remoteCtx, remoteCancel = context.WithTimeout(ctx, *topo.RemoteOperationTimeout) + defer remoteCancel() + if err1 := wr.tmc.UndoDemoteMaster(remoteCtx, oldMasterTabletInfo.Tablet); err1 != nil { log.Warningf("Encountered error %v while trying to undo DemoteMaster", err1) } return fmt.Errorf("master-elect tablet %v failed to catch up with replication or be upgraded to master: %v", masterElectTabletAliasStr, err) diff --git a/go/vt/wrangler/wrangler.go b/go/vt/wrangler/wrangler.go index e72df0d47b8..36b25707fae 100644 --- a/go/vt/wrangler/wrangler.go +++ b/go/vt/wrangler/wrangler.go @@ -27,9 +27,10 @@ import ( var ( // DefaultActionTimeout is a good default for interactive // remote actions. We usually take a lock then do an action, - // so basing this to be greater than DefaultLockTimeout is good. + // lock actions use RemoteOperationTimeout, + // so basing this to be greater than RemoteOperationTimeout is good. // Use this as the default value for Context that need a deadline. - DefaultActionTimeout = topo.DefaultLockTimeout * 4 + DefaultActionTimeout = *topo.RemoteOperationTimeout * 4 ) // Wrangler manages complex actions on the topology, like reparents, From 4309cd8229775d4abd0a9afa76c4edb517f27428 Mon Sep 17 00:00:00 2001 From: David Weitzman Date: Wed, 20 Feb 2019 12:26:16 -0800 Subject: [PATCH 097/196] Fix some vtctld commands failing to return information to vtctlclient Commands need to log to the wrangler logger so grpcvtctlserver can sent output back over the network instead of just logging locally. Signed-off-by: David Weitzman --- go/vt/vtctl/vtctl.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index 50b106ca977..c4c6e9e4544 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -114,7 +114,6 @@ import ( "vitess.io/vitess/go/sync2" hk "vitess.io/vitess/go/vt/hook" "vitess.io/vitess/go/vt/key" - "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/schemamanager" "vitess.io/vitess/go/vt/sqlparser" @@ -502,7 +501,7 @@ func dumpTablets(ctx context.Context, wr *wrangler.Wrangler, tabletAliases []*to for _, tabletAlias := range tabletAliases { ti, ok := tabletMap[topoproto.TabletAliasString(tabletAlias)] if !ok { - log.Warningf("failed to load tablet %v", tabletAlias) + wr.Logger().Warningf("failed to load tablet %v", tabletAlias) } else { wr.Logger().Printf("%v\n", fmtTabletAwkable(ti)) } @@ -1158,7 +1157,7 @@ func commandCreateShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl err = wr.TopoServer().CreateShard(ctx, keyspace, shard) if *force && topo.IsErrType(err, topo.NodeExists) { - log.Infof("shard %v/%v already exists (ignoring error with -force)", keyspace, shard) + wr.Logger().Infof("shard %v/%v already exists (ignoring error with -force)", keyspace, shard) err = nil } return err @@ -1485,7 +1484,7 @@ func commandDeleteShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl case err == nil: // keep going case topo.IsErrType(err, topo.NoNode): - log.Infof("Shard %v/%v doesn't exist, skipping it", ks.Keyspace, ks.Shard) + wr.Logger().Infof("Shard %v/%v doesn't exist, skipping it", ks.Keyspace, ks.Shard) default: return err } @@ -1790,7 +1789,7 @@ func commandValidate(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag. } if subFlags.NArg() != 0 { - log.Warningf("action Validate doesn't take any parameter any more") + wr.Logger().Warningf("action Validate doesn't take any parameter any more") } return wr.Validate(ctx, *pingTablets) } @@ -2065,7 +2064,7 @@ func commandGetPermissions(ctx context.Context, wr *wrangler.Wrangler, subFlags } p, err := wr.GetPermissions(ctx, tabletAlias) if err == nil { - log.Infof("%v", p.String()) // they can contain '%' + wr.Logger().Infof("%v", p.String()) // they can contain '%' } return err } From 1e4c61edcf37ff81e9675da48ef85d96c8e87ce5 Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Wed, 20 Feb 2019 19:38:25 -0500 Subject: [PATCH 098/196] Delete invalid picture links Signed-off-by: xichengliudui --- vitess.io/index.md | 1 - 1 file changed, 1 deletion(-) diff --git a/vitess.io/index.md b/vitess.io/index.md index 161d31bd208..8753f2b698f 100644 --- a/vitess.io/index.md +++ b/vitess.io/index.md @@ -100,6 +100,5 @@ Slack and Nozzle are swapped for aesthetics, because the icons don't align well
    -

    We are a Cloud Native Computing Foundation project.

    From c07b95b04b3795232148ea5918b8ba77ee5f7507 Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Wed, 20 Feb 2019 20:01:40 -0500 Subject: [PATCH 099/196] update java/README.md update pull request Signed-off-by: xichengliudui --- java/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/java/README.md b/java/README.md index 1fa7ffe2953..73a72d27e32 100644 --- a/java/README.md +++ b/java/README.md @@ -5,12 +5,12 @@ This subdirectory contains all Vitess Java code. It is split in the following subdirectories (Maven modules): * **client:** Our Java client library. - * See `VTGateConn.java` and `VTGateBlockingConn.java` for the API. + * See [VTGateConn.java](https://github.com/vitessio/vitess/blob/master/java/client/src/main/java/io/vitess/client/VTGateConn.java) and [VTGateBlockingConn.java](https://github.com/vitessio/vitess/blob/master/java/client/src/main/java/io/vitess/client/VTGateBlockingConn.java) for the API. * Note: The library is agnostic of the underlying RPC system and only defines an interface for that. * In open-source, the library must always be used together with the code in `grpc-client`. * **grpc-client:** Implements the client's RPC interface for gRPC. * **jdbc:** JDBC driver implementation for Vitess. -* **example:** Examples for using the "client" or the "jdbc" module. +* **example:** Examples for using the `client` or the `jdbc` module. * **hadoop:** Vitess support for Hadoop. See [documentation for details](hadoop/src/main/java/io/vitess/hadoop/README.md). **Note:** The `artifactId` for each module listed above has the prefix `vitess-` i.e. you will have to look for `vitess-jdbc` and not `jdbc`. @@ -25,6 +25,6 @@ When submitting contributions which require new dependencies, please follow thes * `make java_test` (which calls `mvn verify` in the `/java` directory) will run `mvn dependency:analyze` and fail if you got this wrong. * Limit the scope of test dependencies to `test`. * Do not include the version number in the module's pom.xml. Instead, add the dependency to the `dependencyManagement` section in `/java/pom.xml` and include the version number there. -* Sort dependencies in alphabetic order. Modules only: Put all dependencies with limited scope (e.g. `test`) in a separate "block" and sort it alphabetically as well (see `/java/client/pom.xml` for an example). +* Sort dependencies in alphabetic order. Modules only: Put all dependencies with limited scope (e.g. `test`) in a separate `block` and sort it alphabetically as well (see `/java/client/pom.xml` for an example). * Feel free to separate groups of dependencies by newlines (e.g. all io.vitess.* dependencies are a group). From af38ff9075fecf680578643ba186a0f3f83247b9 Mon Sep 17 00:00:00 2001 From: Kim Bao Long Date: Thu, 21 Feb 2019 11:14:36 +0700 Subject: [PATCH 100/196] Remove the duplicated words This commit aims to remove some duplicated words in this project Co-Authored-By: Nguyen Phuong An Signed-off-by: Kim Bao Long --- doc/Troubleshooting.md | 2 +- go/vt/vttablet/tabletmanager/vreplication/player_plan.go | 2 +- test/worker.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/Troubleshooting.md b/doc/Troubleshooting.md index 2937e405658..a7b4b0541c2 100644 --- a/doc/Troubleshooting.md +++ b/doc/Troubleshooting.md @@ -13,7 +13,7 @@ Below are a few possible scenarios. Diagnosis 1: Inspect the graphs to see if QPS has gone up. If yes, drill down on the more detailed QPS graphs to see which table, or user caused the increase. If a table is identified, look at /debug/queryz for queries on that table. -Action: Inform engineer about about toxic query. If it’s a specific user, you can stop their job or throttle them to keep the load manageable. As a last resort, blacklist query to allow the rest of the system to stay healthy. +Action: Inform engineer about toxic query. If it’s a specific user, you can stop their job or throttle them to keep the load manageable. As a last resort, blacklist query to allow the rest of the system to stay healthy. Diagnosis 2: QPS did not go up, only latency did. Inspect the per-table latency graphs. If it’s a specific table, then it’s most likely a long-running low QPS query that’s skewing the numbers. Identify the culprit query and take necessary steps to get it optimized. Such queries usually do not cause outage. So, there may not be a need to take extreme measures. diff --git a/go/vt/vttablet/tabletmanager/vreplication/player_plan.go b/go/vt/vttablet/tabletmanager/vreplication/player_plan.go index cc3ba11e5f7..b0130eba1cb 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/player_plan.go +++ b/go/vt/vttablet/tabletmanager/vreplication/player_plan.go @@ -251,7 +251,7 @@ func (tp *TablePlan) FindCol(name sqlparser.ColIdent) *ColExpr { // GenerateStatement must be called only after Fields and PKCols have been populated. func (tp *TablePlan) GenerateStatement(rowChange *binlogdatapb.RowChange) string { - // MakeRowTrusted is needed here because because Proto3ToResult is not convenient. + // MakeRowTrusted is needed here because Proto3ToResult is not convenient. var before, after []sqltypes.Value if rowChange.Before != nil { before = sqltypes.MakeRowTrusted(tp.Fields, rowChange.Before) diff --git a/test/worker.py b/test/worker.py index b84567efb8b..5c51f811289 100755 --- a/test/worker.py +++ b/test/worker.py @@ -229,7 +229,7 @@ def run_shard_tablets( # Wait for tablet state to change after starting all tablets. This allows # us to start all tablets at once, instead of sequentially waiting. # NOTE: Replication has to be enabled first or the health check will - # set a a replica or rdonly tablet back to NOT_SERVING. + # set a replica or rdonly tablet back to NOT_SERVING. for t in shard_tablets.all_tablets: t.wait_for_vttablet_state('SERVING') From 741182d2950034e0c927a38cc085d8b22d7d59e1 Mon Sep 17 00:00:00 2001 From: deepthi Date: Thu, 21 Feb 2019 14:21:52 -0800 Subject: [PATCH 101/196] refactor backup code to allow us to plugin other backup engines Signed-off-by: deepthi --- go/vt/mysqlctl/backup.go | 642 +----------------------- go/vt/mysqlctl/backupengine.go | 52 ++ go/vt/mysqlctl/builtinbackupengine.go | 691 ++++++++++++++++++++++++++ test/backup.py | 12 +- 4 files changed, 763 insertions(+), 634 deletions(-) create mode 100644 go/vt/mysqlctl/backupengine.go create mode 100644 go/vt/mysqlctl/builtinbackupengine.go diff --git a/go/vt/mysqlctl/backup.go b/go/vt/mysqlctl/backup.go index f97a7272451..474c78b9769 100644 --- a/go/vt/mysqlctl/backup.go +++ b/go/vt/mysqlctl/backup.go @@ -17,27 +17,17 @@ limitations under the License. package mysqlctl import ( - "bufio" - "encoding/json" "errors" "flag" "fmt" - "io" - "io/ioutil" "os" - "path" "path/filepath" "strings" - "sync" - "github.com/klauspost/pgzip" "golang.org/x/net/context" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqlescape" - "vitess.io/vitess/go/sync2" - "vitess.io/vitess/go/vt/concurrency" - "vitess.io/vitess/go/vt/hook" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" "vitess.io/vitess/go/vt/mysqlctl/backupstorage" @@ -88,186 +78,6 @@ var ( backupCompressBlocks = flag.Int("backup_storage_number_blocks", 2, "if backup_storage_compress is true, backup_storage_number_blocks sets the number of blocks that can be processed, at once, before the writer blocks, during compression (default is 2). It should be equal to the number of CPUs available for compression") ) -// FileEntry is one file to backup -type FileEntry struct { - // Base is one of: - // - backupInnodbDataHomeDir for files that go into Mycnf.InnodbDataHomeDir - // - backupInnodbLogGroupHomeDir for files that go into Mycnf.InnodbLogGroupHomeDir - // - backupData for files that go into Mycnf.DataDir - Base string - - // Name is the file name, relative to Base - Name string - - // Hash is the hash of the final data (transformed and - // compressed if specified) stored in the BackupStorage. - Hash string -} - -func (fe *FileEntry) open(cnf *Mycnf, readOnly bool) (*os.File, error) { - // find the root to use - var root string - switch fe.Base { - case backupInnodbDataHomeDir: - root = cnf.InnodbDataHomeDir - case backupInnodbLogGroupHomeDir: - root = cnf.InnodbLogGroupHomeDir - case backupData: - root = cnf.DataDir - default: - return nil, fmt.Errorf("unknown base: %v", fe.Base) - } - - // and open the file - name := path.Join(root, fe.Name) - var fd *os.File - var err error - if readOnly { - fd, err = os.Open(name) - } else { - dir := path.Dir(name) - if err := os.MkdirAll(dir, os.ModePerm); err != nil { - return nil, fmt.Errorf("cannot create destination directory %v: %v", dir, err) - } - fd, err = os.Create(name) - } - if err != nil { - return nil, fmt.Errorf("cannot open source file %v: %v", name, err) - } - return fd, nil -} - -// BackupManifest represents the backup. It lists all the files, the -// Position that the backup was taken at, and the transform hook used, -// if any. -type BackupManifest struct { - // FileEntries contains all the files in the backup - FileEntries []FileEntry - - // Position is the position at which the backup was taken - Position mysql.Position - - // TransformHook that was used on the files, if any. - TransformHook string - - // SkipCompress can be set if the backup files were not run - // through gzip. It is the negative of the flag, so old - // backups that don't have this flag are assumed to be - // compressed. - SkipCompress bool -} - -// isDbDir returns true if the given directory contains a DB -func isDbDir(p string) bool { - // db.opt is there - if _, err := os.Stat(path.Join(p, "db.opt")); err == nil { - return true - } - - // Look for at least one database file - fis, err := ioutil.ReadDir(p) - if err != nil { - return false - } - for _, fi := range fis { - if strings.HasSuffix(fi.Name(), ".frm") { - return true - } - - // the MyRocks engine stores data in RocksDB .sst files - // https://github.com/facebook/rocksdb/wiki/Rocksdb-BlockBasedTable-Format - if strings.HasSuffix(fi.Name(), ".sst") { - return true - } - - // .frm files were removed in MySQL 8, so we need to check for two other file types - // https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-file-removal.html - if strings.HasSuffix(fi.Name(), ".ibd") { - return true - } - // https://dev.mysql.com/doc/refman/8.0/en/serialized-dictionary-information.html - if strings.HasSuffix(fi.Name(), ".sdi") { - return true - } - } - - return false -} - -func addDirectory(fes []FileEntry, base string, baseDir string, subDir string) ([]FileEntry, error) { - p := path.Join(baseDir, subDir) - - fis, err := ioutil.ReadDir(p) - if err != nil { - return nil, err - } - for _, fi := range fis { - fes = append(fes, FileEntry{ - Base: base, - Name: path.Join(subDir, fi.Name()), - }) - } - return fes, nil -} - -// addMySQL8DataDictionary checks to see if the new data dictionary introduced in MySQL 8 exists -// and adds it to the backup manifest if it does -// https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-transactional-storage.html -func addMySQL8DataDictionary(fes []FileEntry, base string, baseDir string) ([]FileEntry, error) { - const dataDictionaryFile = "mysql.ibd" - filePath := path.Join(baseDir, dataDictionaryFile) - - // no-op if this file doesn't exist - if _, err := os.Stat(filePath); os.IsNotExist(err) { - return fes, nil - } - - fes = append(fes, FileEntry{ - Base: base, - Name: dataDictionaryFile, - }) - - return fes, nil -} - -func findFilesToBackup(cnf *Mycnf) ([]FileEntry, error) { - var err error - var result []FileEntry - - // first add inno db files - result, err = addDirectory(result, backupInnodbDataHomeDir, cnf.InnodbDataHomeDir, "") - if err != nil { - return nil, err - } - result, err = addDirectory(result, backupInnodbLogGroupHomeDir, cnf.InnodbLogGroupHomeDir, "") - if err != nil { - return nil, err - } - - // then add the transactional data dictionary if it exists - result, err = addMySQL8DataDictionary(result, backupData, cnf.DataDir) - if err != nil { - return nil, err - } - - // then add DB directories - fis, err := ioutil.ReadDir(cnf.DataDir) - if err != nil { - return nil, err - } - - for _, fi := range fis { - p := path.Join(cnf.DataDir, fi.Name()) - if isDbDir(p) { - result, err = addDirectory(result, backupData, cnf.DataDir, fi.Name()) - if err != nil { - return nil, err - } - } - } - return result, nil -} - // Backup is the main entry point for a backup: // - uses the BackupStorage service to store a new backup // - shuts down Mysqld during the backup @@ -284,8 +94,13 @@ func Backup(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil. return fmt.Errorf("StartBackup failed: %v", err) } + be, err := GetBackupEngine() + if err != nil { + return fmt.Errorf("Failed to find backup engine: %v", err) + } + // Take the backup, and either AbortBackup or EndBackup. - usable, err := backup(ctx, cnf, mysqld, logger, bh, backupConcurrency, hookExtraEnv) + usable, err := be.ExecuteBackup(ctx, cnf, mysqld, logger, bh, backupConcurrency, hookExtraEnv) var finishErr error if usable { finishErr = bh.EndBackup(ctx) @@ -307,272 +122,6 @@ func Backup(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil. return finishErr } -// backup returns a boolean that indicates if the backup is usable, -// and an overall error. -func backup(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil.Logger, bh backupstorage.BackupHandle, backupConcurrency int, hookExtraEnv map[string]string) (bool, error) { - // Save initial state so we can restore. - slaveStartRequired := false - sourceIsMaster := false - readOnly := true - var replicationPosition mysql.Position - semiSyncMaster, semiSyncSlave := mysqld.SemiSyncEnabled() - - // See if we need to restart replication after backup. - logger.Infof("getting current replication status") - slaveStatus, err := mysqld.SlaveStatus() - switch err { - case nil: - slaveStartRequired = slaveStatus.SlaveRunning() - case mysql.ErrNotSlave: - // keep going if we're the master, might be a degenerate case - sourceIsMaster = true - default: - return false, fmt.Errorf("can't get slave status: %v", err) - } - - // get the read-only flag - readOnly, err = mysqld.IsReadOnly() - if err != nil { - return false, fmt.Errorf("can't get read-only status: %v", err) - } - - // get the replication position - if sourceIsMaster { - if !readOnly { - logger.Infof("turning master read-only before backup") - if err = mysqld.SetReadOnly(true); err != nil { - return false, fmt.Errorf("can't set read-only status: %v", err) - } - } - replicationPosition, err = mysqld.MasterPosition() - if err != nil { - return false, fmt.Errorf("can't get master position: %v", err) - } - } else { - if err = mysqld.StopSlave(hookExtraEnv); err != nil { - return false, fmt.Errorf("can't stop slave: %v", err) - } - var slaveStatus mysql.SlaveStatus - slaveStatus, err = mysqld.SlaveStatus() - if err != nil { - return false, fmt.Errorf("can't get slave status: %v", err) - } - replicationPosition = slaveStatus.Position - } - logger.Infof("using replication position: %v", replicationPosition) - - // shutdown mysqld - err = mysqld.Shutdown(ctx, cnf, true) - if err != nil { - return false, fmt.Errorf("can't shutdown mysqld: %v", err) - } - - // Backup everything, capture the error. - backupErr := backupFiles(ctx, cnf, mysqld, logger, bh, replicationPosition, backupConcurrency, hookExtraEnv) - usable := backupErr == nil - - // Try to restart mysqld - err = mysqld.Start(ctx, cnf) - if err != nil { - return usable, fmt.Errorf("can't restart mysqld: %v", err) - } - - // Restore original mysqld state that we saved above. - if semiSyncMaster || semiSyncSlave { - // Only do this if one of them was on, since both being off could mean - // the plugin isn't even loaded, and the server variables don't exist. - logger.Infof("restoring semi-sync settings from before backup: master=%v, slave=%v", - semiSyncMaster, semiSyncSlave) - err := mysqld.SetSemiSyncEnabled(semiSyncMaster, semiSyncSlave) - if err != nil { - return usable, err - } - } - if slaveStartRequired { - logger.Infof("restarting mysql replication") - if err := mysqld.StartSlave(hookExtraEnv); err != nil { - return usable, fmt.Errorf("cannot restart slave: %v", err) - } - - // this should be quick, but we might as well just wait - if err := WaitForSlaveStart(mysqld, slaveStartDeadline); err != nil { - return usable, fmt.Errorf("slave is not restarting: %v", err) - } - } - - // And set read-only mode - logger.Infof("resetting mysqld read-only to %v", readOnly) - if err := mysqld.SetReadOnly(readOnly); err != nil { - return usable, err - } - - return usable, backupErr -} - -// backupFiles finds the list of files to backup, and creates the backup. -func backupFiles(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil.Logger, bh backupstorage.BackupHandle, replicationPosition mysql.Position, backupConcurrency int, hookExtraEnv map[string]string) (err error) { - // Get the files to backup. - fes, err := findFilesToBackup(cnf) - if err != nil { - return fmt.Errorf("can't find files to backup: %v", err) - } - logger.Infof("found %v files to backup", len(fes)) - - // Backup with the provided concurrency. - sema := sync2.NewSemaphore(backupConcurrency, 0) - rec := concurrency.AllErrorRecorder{} - wg := sync.WaitGroup{} - for i := range fes { - wg.Add(1) - go func(i int) { - defer wg.Done() - - // Wait until we are ready to go, skip if we already - // encountered an error. - sema.Acquire() - defer sema.Release() - if rec.HasErrors() { - return - } - - // Backup the individual file. - name := fmt.Sprintf("%v", i) - rec.RecordError(backupFile(ctx, cnf, mysqld, logger, bh, &fes[i], name, hookExtraEnv)) - }(i) - } - - wg.Wait() - if rec.HasErrors() { - return rec.Error() - } - - // open the MANIFEST - wc, err := bh.AddFile(ctx, backupManifest, 0) - if err != nil { - return fmt.Errorf("cannot add %v to backup: %v", backupManifest, err) - } - defer func() { - if closeErr := wc.Close(); err == nil { - err = closeErr - } - }() - - // JSON-encode and write the MANIFEST - bm := &BackupManifest{ - FileEntries: fes, - Position: replicationPosition, - TransformHook: *backupStorageHook, - SkipCompress: !*backupStorageCompress, - } - data, err := json.MarshalIndent(bm, "", " ") - if err != nil { - return fmt.Errorf("cannot JSON encode %v: %v", backupManifest, err) - } - if _, err := wc.Write([]byte(data)); err != nil { - return fmt.Errorf("cannot write %v: %v", backupManifest, err) - } - - return nil -} - -// backupFile backs up an individual file. -func backupFile(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil.Logger, bh backupstorage.BackupHandle, fe *FileEntry, name string, hookExtraEnv map[string]string) (err error) { - // Open the source file for reading. - var source *os.File - source, err = fe.open(cnf, true) - if err != nil { - return err - } - defer source.Close() - - fi, err := source.Stat() - if err != nil { - return err - } - - // Open the destination file for writing, and a buffer. - wc, err := bh.AddFile(ctx, name, fi.Size()) - if err != nil { - return fmt.Errorf("cannot add file: %v", err) - } - defer func() { - if rerr := wc.Close(); rerr != nil { - if err != nil { - // We already have an error, just log this one. - logger.Errorf2(rerr, "failed to close file %v", name) - } else { - err = rerr - } - } - }() - dst := bufio.NewWriterSize(wc, 2*1024*1024) - - // Create the hasher and the tee on top. - hasher := newHasher() - writer := io.MultiWriter(dst, hasher) - - // Create the external write pipe, if any. - var pipe io.WriteCloser - var wait hook.WaitFunc - if *backupStorageHook != "" { - h := hook.NewHook(*backupStorageHook, []string{"-operation", "write"}) - h.ExtraEnv = hookExtraEnv - pipe, wait, _, err = h.ExecuteAsWritePipe(writer) - if err != nil { - return fmt.Errorf("'%v' hook returned error: %v", *backupStorageHook, err) - } - writer = pipe - } - - // Create the gzip compression pipe, if necessary. - var gzip *pgzip.Writer - if *backupStorageCompress { - gzip, err = pgzip.NewWriterLevel(writer, pgzip.BestSpeed) - if err != nil { - return fmt.Errorf("cannot create gziper: %v", err) - } - gzip.SetConcurrency(*backupCompressBlockSize, *backupCompressBlocks) - writer = gzip - } - - // Copy from the source file to writer (optional gzip, - // optional pipe, tee, output file and hasher). - _, err = io.Copy(writer, source) - if err != nil { - return fmt.Errorf("cannot copy data: %v", err) - } - - // Close gzip to flush it, after that all data is sent to writer. - if gzip != nil { - if err = gzip.Close(); err != nil { - return fmt.Errorf("cannot close gzip: %v", err) - } - } - - // Close the hook pipe if necessary. - if pipe != nil { - if err := pipe.Close(); err != nil { - return fmt.Errorf("cannot close hook pipe: %v", err) - } - stderr, err := wait() - if stderr != "" { - logger.Infof("'%v' hook returned stderr: %v", *backupStorageHook, stderr) - } - if err != nil { - return fmt.Errorf("'%v' returned error: %v", *backupStorageHook, err) - } - } - - // Flush the buffer to finish writing on destination. - if err = dst.Flush(); err != nil { - return fmt.Errorf("cannot flush dst: %v", err) - } - - // Save the hash. - fe.Hash = hasher.HashString() - return nil -} - // checkNoDB makes sure there is no user data already there. // Used by Restore, as we do not want to destroy an existing DB. // The user's database name must be given since we ignore all others. @@ -606,126 +155,6 @@ func checkNoDB(ctx context.Context, mysqld MysqlDaemon, dbName string) (bool, er return true, nil } -// restoreFiles will copy all the files from the BackupStorage to the -// right place. -func restoreFiles(ctx context.Context, cnf *Mycnf, bh backupstorage.BackupHandle, fes []FileEntry, transformHook string, compress bool, restoreConcurrency int, hookExtraEnv map[string]string) error { - sema := sync2.NewSemaphore(restoreConcurrency, 0) - rec := concurrency.AllErrorRecorder{} - wg := sync.WaitGroup{} - for i := range fes { - wg.Add(1) - go func(i int) { - defer wg.Done() - - // Wait until we are ready to go, skip if we already - // encountered an error. - sema.Acquire() - defer sema.Release() - if rec.HasErrors() { - return - } - - // And restore the file. - name := fmt.Sprintf("%v", i) - rec.RecordError(restoreFile(ctx, cnf, bh, &fes[i], transformHook, compress, name, hookExtraEnv)) - }(i) - } - wg.Wait() - return rec.Error() -} - -// restoreFile restores an individual file. -func restoreFile(ctx context.Context, cnf *Mycnf, bh backupstorage.BackupHandle, fe *FileEntry, transformHook string, compress bool, name string, hookExtraEnv map[string]string) (err error) { - // Open the source file for reading. - var source io.ReadCloser - source, err = bh.ReadFile(ctx, name) - if err != nil { - return err - } - defer source.Close() - - // Open the destination file for writing. - dstFile, err := fe.open(cnf, false) - if err != nil { - return err - } - defer func() { - if cerr := dstFile.Close(); cerr != nil { - if err != nil { - // We already have an error, just log this one. - log.Errorf("failed to close file %v: %v", name, cerr) - } else { - err = cerr - } - } - }() - - // Create a buffering output. - dst := bufio.NewWriterSize(dstFile, 2*1024*1024) - - // Create hash to write the compressed data to. - hasher := newHasher() - - // Create a Tee: we split the input into the hasher - // and into the gunziper. - reader := io.TeeReader(source, hasher) - - // Create the external read pipe, if any. - var wait hook.WaitFunc - if transformHook != "" { - h := hook.NewHook(transformHook, []string{"-operation", "read"}) - h.ExtraEnv = hookExtraEnv - reader, wait, _, err = h.ExecuteAsReadPipe(reader) - if err != nil { - return fmt.Errorf("'%v' hook returned error: %v", transformHook, err) - } - } - - // Create the uncompresser if needed. - if compress { - gz, err := pgzip.NewReader(reader) - if err != nil { - return err - } - defer func() { - if cerr := gz.Close(); cerr != nil { - if err != nil { - // We already have an error, just log this one. - log.Errorf("failed to close gunziper %v: %v", name, cerr) - } else { - err = cerr - } - } - }() - reader = gz - } - - // Copy the data. Will also write to the hasher. - if _, err = io.Copy(dst, reader); err != nil { - return err - } - - // Close the Pipe. - if wait != nil { - stderr, err := wait() - if stderr != "" { - log.Infof("'%v' hook returned stderr: %v", transformHook, stderr) - } - if err != nil { - return fmt.Errorf("'%v' returned error: %v", transformHook, err) - } - } - - // Check the hash. - hash := hasher.HashString() - if hash != fe.Hash { - return fmt.Errorf("hash mismatch for %v, got %v expected %v", fe.Name, hash, fe.Hash) - } - - // Flush the buffer. - return dst.Flush() -} - // removeExistingFiles will delete existing files in the data dir to prevent // conflicts with the restored archive. In particular, binlogs can be created // even during initial bootstrap, and these can interfere with configuring @@ -790,6 +219,8 @@ func Restore( deleteBeforeRestore bool, dbName string) (mysql.Position, error) { + rval := mysql.Position{} + // Wait for mysqld to be ready, in case it was launched in parallel with us. if err := mysqld.Wait(ctx, cnf); err != nil { return mysql.Position{}, err @@ -826,7 +257,7 @@ func Restore( if len(bhs) == 0 { // There are no backups (not even broken/incomplete ones). logger.Errorf("No backup to restore on BackupStorage for directory %v. Starting up empty.", dir) - // Since this Was an empty database make sure we start replication at the beginning + // Since this is an empty database make sure we start replication at the beginning if err = mysqld.ResetReplication(ctx); err == nil { logger.Errorf("Error reseting slave replication: %v. Continuing", err) err = ErrNoBackup @@ -838,57 +269,12 @@ func Restore( return mysql.Position{}, err } - var bh backupstorage.BackupHandle - var bm BackupManifest - var toRestore int - for toRestore = len(bhs) - 1; toRestore >= 0; toRestore-- { - bh = bhs[toRestore] - rc, err := bh.ReadFile(ctx, backupManifest) - if err != nil { - log.Warningf("Possibly incomplete backup %v in directory %v on BackupStorage: can't read MANIFEST: %v)", bh.Name(), dir, err) - continue - } - - err = json.NewDecoder(rc).Decode(&bm) - rc.Close() - if err != nil { - log.Warningf("Possibly incomplete backup %v in directory %v on BackupStorage (cannot JSON decode MANIFEST: %v)", bh.Name(), dir, err) - continue - } - - logger.Infof("Restore: found backup %v %v to restore with %v files", bh.Directory(), bh.Name(), len(bm.FileEntries)) - break - } - if toRestore < 0 { - // There is at least one attempted backup, but none could be read. - // This implies there is data we ought to have, so it's not safe to start - // up empty. - return mysql.Position{}, errors.New("backup(s) found but none could be read, unsafe to start up empty, restart to retry restore") - } - - // Starting from here we won't be able to recover if we get stopped by a cancelled - // context. Thus we use the background context to get through to the finish. - - logger.Infof("Restore: shutdown mysqld") - err = mysqld.Shutdown(context.Background(), cnf, true) + be, err := GetBackupEngine() if err != nil { - return mysql.Position{}, err - } - - logger.Infof("Restore: deleting existing files") - if err := removeExistingFiles(cnf); err != nil { - return mysql.Position{}, err + return mysql.Position{}, fmt.Errorf("Failed to find backup engine: %v", err) } - - logger.Infof("Restore: reinit config file") - err = mysqld.ReinitConfig(context.Background(), cnf) - if err != nil { - return mysql.Position{}, err - } - - logger.Infof("Restore: copying all files") - if err := restoreFiles(context.Background(), cnf, bh, bm.FileEntries, bm.TransformHook, !bm.SkipCompress, restoreConcurrency, hookExtraEnv); err != nil { - return mysql.Position{}, err + if rval, err = be.ExecuteRestore(ctx, cnf, mysqld, logger, dir, bhs, restoreConcurrency, hookExtraEnv); err != nil { + return rval, err } // mysqld needs to be running in order for mysql_upgrade to work. @@ -930,5 +316,5 @@ func Restore( return mysql.Position{}, err } - return bm.Position, nil + return rval, nil } diff --git a/go/vt/mysqlctl/backupengine.go b/go/vt/mysqlctl/backupengine.go new file mode 100644 index 00000000000..c793a0493bb --- /dev/null +++ b/go/vt/mysqlctl/backupengine.go @@ -0,0 +1,52 @@ +/* +Copyright 2019 The Vitess 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 mysqlctl + +import ( + "context" + "flag" + "fmt" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/mysqlctl/backupstorage" +) + +var ( + // BackupEngineImplementation is the implementation to use + // for BackupEngine. Exported for test purposes. + BackupEngineImplementation = flag.String("backup_engine_implementation", "builtin", "which implementation to use for the backup storage engine") +) + +// BackupEngine is the interface to the backup engine +type BackupEngine interface { + ExecuteBackup(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil.Logger, bh backupstorage.BackupHandle, backupConcurrency int, hookExtraEnv map[string]string) (bool, error) + ExecuteRestore(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil.Logger, dir string, bhs []backupstorage.BackupHandle, restoreConcurrency int, hookExtraEnv map[string]string) (mysql.Position, error) +} + +// BackupEngineMap contains the registered implementations for BackupEngine +var BackupEngineMap = make(map[string]BackupEngine) + +// GetBackupEngine returns the current BackupEngine implementation. +// Should be called after flags have been initialized. +func GetBackupEngine() (BackupEngine, error) { + be, ok := BackupEngineMap[*BackupEngineImplementation] + if !ok { + return nil, fmt.Errorf("no registered implementation of BackupEngine") + } + return be, nil +} diff --git a/go/vt/mysqlctl/builtinbackupengine.go b/go/vt/mysqlctl/builtinbackupengine.go new file mode 100644 index 00000000000..38a23b85d4f --- /dev/null +++ b/go/vt/mysqlctl/builtinbackupengine.go @@ -0,0 +1,691 @@ +/* +Copyright 2019 The Vitess 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 mysqlctl + +import ( + "bufio" + "context" + "encoding/json" + "errors" + "fmt" + "io" + "io/ioutil" + "os" + "path" + "strings" + "sync" + + "github.com/klauspost/pgzip" + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sync2" + "vitess.io/vitess/go/vt/concurrency" + "vitess.io/vitess/go/vt/hook" + "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/mysqlctl/backupstorage" +) + +// BuiltinBackupEngine encapsulates the logic of the builtin engine +// it implements the BackupEngine interface and contains all the logic +// required to implement a backup/restore by copying files from and to +// the correct location / storage bucket +type BuiltinBackupEngine struct { +} + +// BackupManifest represents the backup. It lists all the files, the +// Position that the backup was taken at, and the transform hook used, +// if any. +type BackupManifest struct { + // FileEntries contains all the files in the backup + FileEntries []FileEntry + + // Position is the position at which the backup was taken + Position mysql.Position + + // TransformHook that was used on the files, if any. + TransformHook string + + // SkipCompress can be set if the backup files were not run + // through gzip. It is the negative of the flag, so old + // backups that don't have this flag are assumed to be + // compressed. + SkipCompress bool +} + +// FileEntry is one file to backup +type FileEntry struct { + // Base is one of: + // - backupInnodbDataHomeDir for files that go into Mycnf.InnodbDataHomeDir + // - backupInnodbLogGroupHomeDir for files that go into Mycnf.InnodbLogGroupHomeDir + // - backupData for files that go into Mycnf.DataDir + Base string + + // Name is the file name, relative to Base + Name string + + // Hash is the hash of the final data (transformed and + // compressed if specified) stored in the BackupStorage. + Hash string +} + +func (fe *FileEntry) open(cnf *Mycnf, readOnly bool) (*os.File, error) { + // find the root to use + var root string + switch fe.Base { + case backupInnodbDataHomeDir: + root = cnf.InnodbDataHomeDir + case backupInnodbLogGroupHomeDir: + root = cnf.InnodbLogGroupHomeDir + case backupData: + root = cnf.DataDir + default: + return nil, fmt.Errorf("unknown base: %v", fe.Base) + } + + // and open the file + name := path.Join(root, fe.Name) + var fd *os.File + var err error + if readOnly { + if fd, err = os.Open(name); err != nil { + return nil, fmt.Errorf("cannot open source file %v: %v", name, err) + } + } else { + dir := path.Dir(name) + if err := os.MkdirAll(dir, os.ModePerm); err != nil { + return nil, fmt.Errorf("cannot create destination directory %v: %v", dir, err) + } + if fd, err = os.Create(name); err != nil { + return nil, fmt.Errorf("cannot create destination file %v: %v", name, err) + } + } + return fd, nil +} + +// isDbDir returns true if the given directory contains a DB +func isDbDir(p string) bool { + // db.opt is there + if _, err := os.Stat(path.Join(p, "db.opt")); err == nil { + return true + } + + // Look for at least one database file + fis, err := ioutil.ReadDir(p) + if err != nil { + return false + } + for _, fi := range fis { + if strings.HasSuffix(fi.Name(), ".frm") { + return true + } + + // the MyRocks engine stores data in RocksDB .sst files + // https://github.com/facebook/rocksdb/wiki/Rocksdb-BlockBasedTable-Format + if strings.HasSuffix(fi.Name(), ".sst") { + return true + } + + // .frm files were removed in MySQL 8, so we need to check for two other file types + // https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-file-removal.html + if strings.HasSuffix(fi.Name(), ".ibd") { + return true + } + // https://dev.mysql.com/doc/refman/8.0/en/serialized-dictionary-information.html + if strings.HasSuffix(fi.Name(), ".sdi") { + return true + } + } + + return false +} + +func addDirectory(fes []FileEntry, base string, baseDir string, subDir string) ([]FileEntry, error) { + p := path.Join(baseDir, subDir) + + fis, err := ioutil.ReadDir(p) + if err != nil { + return nil, err + } + for _, fi := range fis { + fes = append(fes, FileEntry{ + Base: base, + Name: path.Join(subDir, fi.Name()), + }) + } + return fes, nil +} + +// addMySQL8DataDictionary checks to see if the new data dictionary introduced in MySQL 8 exists +// and adds it to the backup manifest if it does +// https://dev.mysql.com/doc/refman/8.0/en/data-dictionary-transactional-storage.html +func addMySQL8DataDictionary(fes []FileEntry, base string, baseDir string) ([]FileEntry, error) { + const dataDictionaryFile = "mysql.ibd" + filePath := path.Join(baseDir, dataDictionaryFile) + + // no-op if this file doesn't exist + if _, err := os.Stat(filePath); os.IsNotExist(err) { + return fes, nil + } + + fes = append(fes, FileEntry{ + Base: base, + Name: dataDictionaryFile, + }) + + return fes, nil +} + +func findFilesToBackup(cnf *Mycnf) ([]FileEntry, error) { + var err error + var result []FileEntry + + // first add inno db files + result, err = addDirectory(result, backupInnodbDataHomeDir, cnf.InnodbDataHomeDir, "") + if err != nil { + return nil, err + } + result, err = addDirectory(result, backupInnodbLogGroupHomeDir, cnf.InnodbLogGroupHomeDir, "") + if err != nil { + return nil, err + } + + // then add the transactional data dictionary if it exists + result, err = addMySQL8DataDictionary(result, backupData, cnf.DataDir) + if err != nil { + return nil, err + } + + // then add DB directories + fis, err := ioutil.ReadDir(cnf.DataDir) + if err != nil { + return nil, err + } + + for _, fi := range fis { + p := path.Join(cnf.DataDir, fi.Name()) + if isDbDir(p) { + result, err = addDirectory(result, backupData, cnf.DataDir, fi.Name()) + if err != nil { + return nil, err + } + } + } + return result, nil +} + +// ExecuteBackup returns a boolean that indicates if the backup is usable, +// and an overall error. +func (be *BuiltinBackupEngine) ExecuteBackup(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil.Logger, bh backupstorage.BackupHandle, backupConcurrency int, hookExtraEnv map[string]string) (bool, error) { + + logger.Infof("Hook: %v, Compress: %v", *backupStorageHook, *backupStorageCompress) + + // Save initial state so we can restore. + slaveStartRequired := false + sourceIsMaster := false + readOnly := true + var replicationPosition mysql.Position + semiSyncMaster, semiSyncSlave := mysqld.SemiSyncEnabled() + + // See if we need to restart replication after backup. + logger.Infof("getting current replication status") + slaveStatus, err := mysqld.SlaveStatus() + switch err { + case nil: + slaveStartRequired = slaveStatus.SlaveRunning() + case mysql.ErrNotSlave: + // keep going if we're the master, might be a degenerate case + sourceIsMaster = true + default: + return false, fmt.Errorf("can't get slave status: %v", err) + } + + // get the read-only flag + readOnly, err = mysqld.IsReadOnly() + if err != nil { + return false, fmt.Errorf("can't get read-only status: %v", err) + } + + // get the replication position + if sourceIsMaster { + if !readOnly { + logger.Infof("turning master read-only before backup") + if err = mysqld.SetReadOnly(true); err != nil { + return false, fmt.Errorf("can't set read-only status: %v", err) + } + } + replicationPosition, err = mysqld.MasterPosition() + if err != nil { + return false, fmt.Errorf("can't get master position: %v", err) + } + } else { + if err = mysqld.StopSlave(hookExtraEnv); err != nil { + return false, fmt.Errorf("can't stop slave: %v", err) + } + var slaveStatus mysql.SlaveStatus + slaveStatus, err = mysqld.SlaveStatus() + if err != nil { + return false, fmt.Errorf("can't get slave status: %v", err) + } + replicationPosition = slaveStatus.Position + } + logger.Infof("using replication position: %v", replicationPosition) + + // shutdown mysqld + err = mysqld.Shutdown(ctx, cnf, true) + if err != nil { + return false, fmt.Errorf("can't shutdown mysqld: %v", err) + } + + // Backup everything, capture the error. + backupErr := be.backupFiles(ctx, cnf, mysqld, logger, bh, replicationPosition, backupConcurrency, hookExtraEnv) + usable := backupErr == nil + + // Try to restart mysqld + err = mysqld.Start(ctx, cnf) + if err != nil { + return usable, fmt.Errorf("can't restart mysqld: %v", err) + } + + // Restore original mysqld state that we saved above. + if semiSyncMaster || semiSyncSlave { + // Only do this if one of them was on, since both being off could mean + // the plugin isn't even loaded, and the server variables don't exist. + logger.Infof("restoring semi-sync settings from before backup: master=%v, slave=%v", + semiSyncMaster, semiSyncSlave) + err := mysqld.SetSemiSyncEnabled(semiSyncMaster, semiSyncSlave) + if err != nil { + return usable, err + } + } + if slaveStartRequired { + logger.Infof("restarting mysql replication") + if err := mysqld.StartSlave(hookExtraEnv); err != nil { + return usable, fmt.Errorf("cannot restart slave: %v", err) + } + + // this should be quick, but we might as well just wait + if err := WaitForSlaveStart(mysqld, slaveStartDeadline); err != nil { + return usable, fmt.Errorf("slave is not restarting: %v", err) + } + } + + // And set read-only mode + logger.Infof("resetting mysqld read-only to %v", readOnly) + if err := mysqld.SetReadOnly(readOnly); err != nil { + return usable, err + } + + return usable, backupErr +} + +// backupFiles finds the list of files to backup, and creates the backup. +func (be *BuiltinBackupEngine) backupFiles(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil.Logger, bh backupstorage.BackupHandle, replicationPosition mysql.Position, backupConcurrency int, hookExtraEnv map[string]string) (err error) { + // Get the files to backup. + fes, err := findFilesToBackup(cnf) + if err != nil { + return fmt.Errorf("can't find files to backup: %v", err) + } + logger.Infof("found %v files to backup", len(fes)) + + // Backup with the provided concurrency. + sema := sync2.NewSemaphore(backupConcurrency, 0) + rec := concurrency.AllErrorRecorder{} + wg := sync.WaitGroup{} + for i := range fes { + wg.Add(1) + go func(i int) { + defer wg.Done() + + // Wait until we are ready to go, skip if we already + // encountered an error. + sema.Acquire() + defer sema.Release() + if rec.HasErrors() { + return + } + + // Backup the individual file. + name := fmt.Sprintf("%v", i) + rec.RecordError(be.backupFile(ctx, cnf, mysqld, logger, bh, &fes[i], name, hookExtraEnv)) + }(i) + } + + wg.Wait() + if rec.HasErrors() { + return rec.Error() + } + + // open the MANIFEST + wc, err := bh.AddFile(ctx, backupManifest, 0) + if err != nil { + return fmt.Errorf("cannot add %v to backup: %v", backupManifest, err) + } + defer func() { + if closeErr := wc.Close(); err == nil { + err = closeErr + } + }() + + // JSON-encode and write the MANIFEST + bm := &BackupManifest{ + FileEntries: fes, + Position: replicationPosition, + TransformHook: *backupStorageHook, + SkipCompress: !*backupStorageCompress, + } + data, err := json.MarshalIndent(bm, "", " ") + if err != nil { + return fmt.Errorf("cannot JSON encode %v: %v", backupManifest, err) + } + if _, err := wc.Write([]byte(data)); err != nil { + return fmt.Errorf("cannot write %v: %v", backupManifest, err) + } + + return nil +} + +// backupFile backs up an individual file. +func (be *BuiltinBackupEngine) backupFile(ctx context.Context, cnf *Mycnf, mysqld MysqlDaemon, logger logutil.Logger, bh backupstorage.BackupHandle, fe *FileEntry, name string, hookExtraEnv map[string]string) (err error) { + // Open the source file for reading. + var source *os.File + source, err = fe.open(cnf, true) + if err != nil { + return err + } + defer source.Close() + + fi, err := source.Stat() + if err != nil { + return err + } + + // Open the destination file for writing, and a buffer. + wc, err := bh.AddFile(ctx, name, fi.Size()) + if err != nil { + return fmt.Errorf("cannot add file: %v", err) + } + defer func() { + if rerr := wc.Close(); rerr != nil { + if err != nil { + // We already have an error, just log this one. + logger.Errorf2(rerr, "failed to close file %v", name) + } else { + err = rerr + } + } + }() + dst := bufio.NewWriterSize(wc, 2*1024*1024) + + // Create the hasher and the tee on top. + hasher := newHasher() + writer := io.MultiWriter(dst, hasher) + + // Create the external write pipe, if any. + var pipe io.WriteCloser + var wait hook.WaitFunc + if *backupStorageHook != "" { + h := hook.NewHook(*backupStorageHook, []string{"-operation", "write"}) + h.ExtraEnv = hookExtraEnv + pipe, wait, _, err = h.ExecuteAsWritePipe(writer) + if err != nil { + return fmt.Errorf("'%v' hook returned error: %v", *backupStorageHook, err) + } + writer = pipe + } + + // Create the gzip compression pipe, if necessary. + var gzip *pgzip.Writer + if *backupStorageCompress { + gzip, err = pgzip.NewWriterLevel(writer, pgzip.BestSpeed) + if err != nil { + return fmt.Errorf("cannot create gziper: %v", err) + } + gzip.SetConcurrency(*backupCompressBlockSize, *backupCompressBlocks) + writer = gzip + } + + // Copy from the source file to writer (optional gzip, + // optional pipe, tee, output file and hasher). + _, err = io.Copy(writer, source) + if err != nil { + return fmt.Errorf("cannot copy data: %v", err) + } + + // Close gzip to flush it, after that all data is sent to writer. + if gzip != nil { + if err = gzip.Close(); err != nil { + return fmt.Errorf("cannot close gzip: %v", err) + } + } + + // Close the hook pipe if necessary. + if pipe != nil { + if err := pipe.Close(); err != nil { + return fmt.Errorf("cannot close hook pipe: %v", err) + } + stderr, err := wait() + if stderr != "" { + logger.Infof("'%v' hook returned stderr: %v", *backupStorageHook, stderr) + } + if err != nil { + return fmt.Errorf("'%v' returned error: %v", *backupStorageHook, err) + } + } + + // Flush the buffer to finish writing on destination. + if err = dst.Flush(); err != nil { + return fmt.Errorf("cannot flush dst: %v", err) + } + + // Save the hash. + fe.Hash = hasher.HashString() + return nil +} + +// ExecuteRestore restores from a backup. If the restore is successful +// we return the position from which replication should start +// otherwise an error is returned +func (be *BuiltinBackupEngine) ExecuteRestore( + ctx context.Context, + cnf *Mycnf, + mysqld MysqlDaemon, + logger logutil.Logger, + dir string, + bhs []backupstorage.BackupHandle, + restoreConcurrency int, + hookExtraEnv map[string]string) (mysql.Position, error) { + + var bh backupstorage.BackupHandle + var bm BackupManifest + var toRestore int + + for toRestore = len(bhs) - 1; toRestore >= 0; toRestore-- { + bh = bhs[toRestore] + rc, err := bh.ReadFile(ctx, backupManifest) + if err != nil { + log.Warningf("Possibly incomplete backup %v in directory %v on BackupStorage: can't read MANIFEST: %v)", bh.Name(), dir, err) + continue + } + + err = json.NewDecoder(rc).Decode(&bm) + rc.Close() + if err != nil { + log.Warningf("Possibly incomplete backup %v in directory %v on BackupStorage (cannot JSON decode MANIFEST: %v)", bh.Name(), dir, err) + continue + } + + logger.Infof("Restore: found backup %v %v to restore with %v files", bh.Directory(), bh.Name(), len(bm.FileEntries)) + break + } + if toRestore < 0 { + // There is at least one attempted backup, but none could be read. + // This implies there is data we ought to have, so it's not safe to start + // up empty. + return mysql.Position{}, errors.New("backup(s) found but none could be read, unsafe to start up empty, restart to retry restore") + } + + // Starting from here we won't be able to recover if we get stopped by a cancelled + // context. Thus we use the background context to get through to the finish. + + logger.Infof("Restore: shutdown mysqld") + err := mysqld.Shutdown(context.Background(), cnf, true) + if err != nil { + return mysql.Position{}, err + } + + logger.Infof("Restore: deleting existing files") + if err := removeExistingFiles(cnf); err != nil { + return mysql.Position{}, err + } + + logger.Infof("Restore: reinit config file") + err = mysqld.ReinitConfig(context.Background(), cnf) + if err != nil { + return mysql.Position{}, err + } + + logger.Infof("Restore: copying all files") + if err := be.restoreFiles(context.Background(), cnf, bh, bm.FileEntries, bm.TransformHook, !bm.SkipCompress, restoreConcurrency, hookExtraEnv); err != nil { + return mysql.Position{}, err + } + + return bm.Position, nil +} + +// restoreFiles will copy all the files from the BackupStorage to the +// right place. +func (be *BuiltinBackupEngine) restoreFiles(ctx context.Context, cnf *Mycnf, bh backupstorage.BackupHandle, fes []FileEntry, transformHook string, compress bool, restoreConcurrency int, hookExtraEnv map[string]string) error { + sema := sync2.NewSemaphore(restoreConcurrency, 0) + rec := concurrency.AllErrorRecorder{} + wg := sync.WaitGroup{} + for i := range fes { + wg.Add(1) + go func(i int) { + defer wg.Done() + + // Wait until we are ready to go, skip if we already + // encountered an error. + sema.Acquire() + defer sema.Release() + if rec.HasErrors() { + return + } + + // And restore the file. + name := fmt.Sprintf("%v", i) + rec.RecordError(be.restoreFile(ctx, cnf, bh, &fes[i], transformHook, compress, name, hookExtraEnv)) + }(i) + } + wg.Wait() + return rec.Error() +} + +// restoreFile restores an individual file. +func (be *BuiltinBackupEngine) restoreFile(ctx context.Context, cnf *Mycnf, bh backupstorage.BackupHandle, fe *FileEntry, transformHook string, compress bool, name string, hookExtraEnv map[string]string) (err error) { + // Open the source file for reading. + var source io.ReadCloser + source, err = bh.ReadFile(ctx, name) + if err != nil { + return err + } + defer source.Close() + + // Open the destination file for writing. + dstFile, err := fe.open(cnf, false) + if err != nil { + return err + } + defer func() { + if cerr := dstFile.Close(); cerr != nil { + if err != nil { + // We already have an error, just log this one. + log.Errorf("failed to close file %v: %v", name, cerr) + } else { + err = cerr + } + } + }() + + // Create a buffering output. + dst := bufio.NewWriterSize(dstFile, 2*1024*1024) + + // Create hash to write the compressed data to. + hasher := newHasher() + + // Create a Tee: we split the input into the hasher + // and into the gunziper. + reader := io.TeeReader(source, hasher) + + // Create the external read pipe, if any. + var wait hook.WaitFunc + if transformHook != "" { + h := hook.NewHook(transformHook, []string{"-operation", "read"}) + h.ExtraEnv = hookExtraEnv + reader, wait, _, err = h.ExecuteAsReadPipe(reader) + if err != nil { + return fmt.Errorf("'%v' hook returned error: %v", transformHook, err) + } + } + + // Create the uncompresser if needed. + if compress { + gz, err := pgzip.NewReader(reader) + if err != nil { + return err + } + defer func() { + if cerr := gz.Close(); cerr != nil { + if err != nil { + // We already have an error, just log this one. + log.Errorf("failed to close gunziper %v: %v", name, cerr) + } else { + err = cerr + } + } + }() + reader = gz + } + + // Copy the data. Will also write to the hasher. + if _, err = io.Copy(dst, reader); err != nil { + return err + } + + // Close the Pipe. + if wait != nil { + stderr, err := wait() + if stderr != "" { + log.Infof("'%v' hook returned stderr: %v", transformHook, stderr) + } + if err != nil { + return fmt.Errorf("'%v' returned error: %v", transformHook, err) + } + } + + // Check the hash. + hash := hasher.HashString() + if hash != fe.Hash { + return fmt.Errorf("hash mismatch for %v, got %v expected %v", fe.Name, hash, fe.Hash) + } + + // Flush the buffer. + return dst.Flush() +} + +func init() { + BackupEngineMap["builtin"] = &BuiltinBackupEngine{} +} diff --git a/test/backup.py b/test/backup.py index 78e8735fb9b..4e75d8e1561 100755 --- a/test/backup.py +++ b/test/backup.py @@ -282,6 +282,12 @@ def _test_backup(self, tablet_type): # backup the slave utils.run_vtctl(['Backup', tablet_replica1.tablet_alias], auto_log=True) + # check that the backup shows up in the listing + backups = self._list_backups() + logging.debug('list of backups: %s', backups) + self.assertEqual(len(backups), 1) + self.assertTrue(backups[0].endswith(tablet_replica1.tablet_alias)) + # insert more data on the master self._insert_data(tablet_master, 2) @@ -304,12 +310,6 @@ def _test_backup(self, tablet_type): else: self.assertEqual(metadata['PromotionRule'], 'must_not') - # check that the backup shows up in the listing - backups = self._list_backups() - logging.debug('list of backups: %s', backups) - self.assertEqual(len(backups), 1) - self.assertTrue(backups[0].endswith(tablet_replica1.tablet_alias)) - # remove the backup and check that the list is empty self._remove_backup(backups[0]) backups = self._list_backups() From 0c26ad42319dfb228c758d8ec2ce65ef139a73d5 Mon Sep 17 00:00:00 2001 From: Kim Bao Long Date: Wed, 20 Feb 2019 14:08:16 +0700 Subject: [PATCH 102/196] Adding '#!/bin/bash' as a shebang line in env.sh This commit aims to add shebang line that indicates scripts use bash shell for interpreting Co-Authored-By: Nguyen Phuong An Signed-off-by: Kim Bao Long --- examples/kubernetes/env.sh | 1 + examples/local/env.sh | 1 + 2 files changed, 2 insertions(+) diff --git a/examples/kubernetes/env.sh b/examples/kubernetes/env.sh index 28e1211aa0b..922a3927f59 100644 --- a/examples/kubernetes/env.sh +++ b/examples/kubernetes/env.sh @@ -1,3 +1,4 @@ +#!/bin/bash # Copyright 2017 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/examples/local/env.sh b/examples/local/env.sh index 72398b2e1f2..4a5c503e7c0 100644 --- a/examples/local/env.sh +++ b/examples/local/env.sh @@ -1,3 +1,4 @@ +#!/bin/bash # Copyright 2017 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); From 29bf1d135e5089a8baef6a17df1007cfff96f0b3 Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Thu, 21 Feb 2019 23:20:34 -0800 Subject: [PATCH 103/196] Add detail of the OS, kernel version in bug report Insert the command to check the OS, kernel version and machine's architecture in order to get more detail in Bug Report template. Co-Authored-By: Dao Cong Tien tiendc@vn.fujitsu.com Signed-off-by: Nguyen Hai Truong --- .github/ISSUE_TEMPLATE/bug_report.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 818359e9335..083d7743f93 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -59,6 +59,10 @@ Version: a95cf5d (Git branch 'HEAD') built on Fri May 18 16:54:26 PDT 2018 by gi OS, Architecture, and any other information you can provide about the environment. +- Operating system (output of `cat /etc/os-release`): +- Kernel version (output of `uname -sr`): +- Architecture (output of `uname -m`): + #### Log Fragments Include appropriate log fragments. If the log is longer than a few dozen lines, please From cc04498f42e6a385a83d6f2c9a9b5075f2cc88c3 Mon Sep 17 00:00:00 2001 From: Kim Bao Long Date: Fri, 22 Feb 2019 16:45:14 +0700 Subject: [PATCH 104/196] Replacing 'HTTP' by 'HTTPS' for securing links Currently, when we access the **vitess.io** with **HTTP**, it is redirected to **HTTPS** automatically. So this commit aims to replace **HTTP** to **HTTPs** for security. Co-Authored-By: Nguyen Phuong An Signed-off-by: Kim Bao Long --- doc/internal/PublishWebsite.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/internal/PublishWebsite.md b/doc/internal/PublishWebsite.md index 9d36f1b7ba9..1232ee0ad4a 100644 --- a/doc/internal/PublishWebsite.md +++ b/doc/internal/PublishWebsite.md @@ -48,7 +48,7 @@ We have three main directories: * [`doc/`](https://github.com/vitessio/vitess/tree/master/doc) - original content * [`docs/`](https://github.com/vitessio/vitess/tree/master/docs) - generated - website actually served at http://vitess.io/ + website actually served at https://vitess.io/ * [`vitess.io/`](https://github.com/vitessio/vitess/tree/master/vitess.io) - all relevant files for the website e.g. * Jekyll configuration @@ -105,7 +105,7 @@ When you add a new section to the menu, please create a new directory below The main file in the section should have `index.md` as its boiler plate counter part. Example: `doc/Contributing.md` is included by `vitess.io/contributing/index.md` and therefore served as -http://vitess.io/contributing/. +https://vitess.io/contributing/. Make sure that you use `{% raw %}{% link ... %}{% endraw %}` to generate the URLs. See existing entries for examples. @@ -113,7 +113,7 @@ See existing entries for examples. ### Orphaned doc/ Markdown Files There are several files in `doc/` which are currently not visible on -http://vitess.io. +https://vitess.io. Examples: From b501f4af0de6967d4d57e4de8956d9dce0566075 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Fri, 22 Feb 2019 11:12:37 +0100 Subject: [PATCH 105/196] Fixes #4652 - Chaining grpc interceptors Signed-off-by: Andres Taylor --- go/vt/servenv/grpc_server.go | 54 +++++++++++++++++++++++++++--------- vendor/vendor.json | 6 ++++ 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/go/vt/servenv/grpc_server.go b/go/vt/servenv/grpc_server.go index e596d1702f8..ce9c28afedf 100644 --- a/go/vt/servenv/grpc_server.go +++ b/go/vt/servenv/grpc_server.go @@ -19,18 +19,18 @@ package servenv import ( "flag" "fmt" - "net" - - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" - "math" + "net" "time" + "github.com/grpc-ecosystem/go-grpc-middleware" "github.com/grpc-ecosystem/go-grpc-prometheus" - "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" "google.golang.org/grpc/keepalive" + + "golang.org/x/net/context" "vitess.io/vitess/go/vt/grpccommon" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/vttls" @@ -162,6 +162,16 @@ func createGRPCServer() { opts = append(opts, grpc.KeepaliveParams(ka)) } + opts = append(opts, interceptors()...) + + GRPCServer = grpc.NewServer(opts...) +} + +// We can only set a ServerInterceptor once, so we chain multiple interceptors into one +func interceptors() []grpc.ServerOption { + var streamInterceptor grpc.StreamServerInterceptor + var unaryInterceptor grpc.UnaryServerInterceptor + if *GRPCAuth != "" { log.Infof("enabling auth plugin %v", *GRPCAuth) pluginInitializer := GetAuthenticator(*GRPCAuth) @@ -170,16 +180,34 @@ func createGRPCServer() { log.Fatalf("Failed to load auth plugin: %v", err) } authPlugin = authPluginImpl - opts = append(opts, grpc.StreamInterceptor(streamInterceptor)) - opts = append(opts, grpc.UnaryInterceptor(unaryInterceptor)) + streamInterceptor = authenticatingStreamInterceptor + unaryInterceptor = authenticatingUnaryInterceptor } if *grpccommon.EnableGRPCPrometheus { - opts = append(opts, grpc.StreamInterceptor(grpc_prometheus.StreamServerInterceptor)) - opts = append(opts, grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor)) + streamInterceptor = mergeS(streamInterceptor, grpc_prometheus.StreamServerInterceptor) + unaryInterceptor = mergeU(unaryInterceptor, grpc_prometheus.UnaryServerInterceptor) } - GRPCServer = grpc.NewServer(opts...) + if streamInterceptor == nil { + return []grpc.ServerOption{} + } else { + return []grpc.ServerOption{grpc.StreamInterceptor(streamInterceptor), grpc.UnaryInterceptor(unaryInterceptor)} + } +} + +func mergeS(a,b grpc.StreamServerInterceptor) grpc.StreamServerInterceptor { + if a == nil { + return b + } + return grpc_middleware.ChainStreamServer(a, b) +} + +func mergeU(a,b grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor { + if a == nil { + return b + } + return grpc_middleware.ChainUnaryServer(a, b) } func serveGRPC() { @@ -227,7 +255,7 @@ func GRPCCheckServiceMap(name string) bool { return CheckServiceMap("grpc", name) } -func streamInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { +func authenticatingStreamInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error { newCtx, err := authPlugin.Authenticate(stream.Context(), info.FullMethod) if err != nil { @@ -239,7 +267,7 @@ func streamInterceptor(srv interface{}, stream grpc.ServerStream, info *grpc.Str return handler(srv, wrapped) } -func unaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { +func authenticatingUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { newCtx, err := authPlugin.Authenticate(ctx, info.FullMethod) if err != nil { return nil, err diff --git a/vendor/vendor.json b/vendor/vendor.json index 8fbf87b2dda..7c35cd37d1c 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -568,6 +568,12 @@ "revision": "2d1e4548da234d9cb742cc3628556fef86aafbac", "revisionTime": "2016-09-12T15:30:41Z" }, + { + "checksumSHA1": "Naa1qU7ykpIyDUZktjbqAU3V6bY=", + "path": "github.com/grpc-ecosystem/go-grpc-middleware", + "revision": "f849b5445de4819127e123ca96ba0eeb62b5e479", + "revisionTime": "2019-01-18T09:38:23Z" + }, { "checksumSHA1": "9dP53doJ/haDqTJyD0iuv8g0XFs=", "path": "github.com/grpc-ecosystem/go-grpc-prometheus", From 54498e35ae185916a1a187eca584456feb152928 Mon Sep 17 00:00:00 2001 From: zhoulin xie Date: Fri, 22 Feb 2019 22:19:20 +0800 Subject: [PATCH 106/196] Fix some misspells Signed-off-by: zhoulin xie --- doc/GitHubWorkflow.md | 2 +- go/vt/vtgate/safe_session.go | 2 +- go/vt/vttablet/tabletserver/tx_executor_test.go | 2 +- go/vt/vttablet/tabletserver/tx_prep_pool.go | 4 ++-- go/vt/vttablet/tabletserver/tx_prep_pool_test.go | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/GitHubWorkflow.md b/doc/GitHubWorkflow.md index 37db4f169da..6c7a7f22765 100644 --- a/doc/GitHubWorkflow.md +++ b/doc/GitHubWorkflow.md @@ -83,7 +83,7 @@ test` from the root of the Git tree. If you haven't installed all dependencies for `make test`, you can rely on the Travis CI test results as well. These results will be linked on your pull request. -## Commiting your work +## Committing your work When running `git commit` use the `-s` option to add a Signed-off-by line. This is needed for [the Developer Certificate of Origin](https://github.com/apps/dco). diff --git a/go/vt/vtgate/safe_session.go b/go/vt/vtgate/safe_session.go index 6461ac86cc9..0078370952e 100644 --- a/go/vt/vtgate/safe_session.go +++ b/go/vt/vtgate/safe_session.go @@ -96,7 +96,7 @@ func (session *SafeSession) SetAutocommitable(flag bool) { } // AutocommitApproval returns true if we can perform a single round-trip -// autocommit. If so, the caller is responsible for commiting their +// autocommit. If so, the caller is responsible for committing their // transaction. func (session *SafeSession) AutocommitApproval() bool { session.mu.Lock() diff --git a/go/vt/vttablet/tabletserver/tx_executor_test.go b/go/vt/vttablet/tabletserver/tx_executor_test.go index 7bc325b9c03..4635d0d9a39 100644 --- a/go/vt/vttablet/tabletserver/tx_executor_test.go +++ b/go/vt/vttablet/tabletserver/tx_executor_test.go @@ -160,7 +160,7 @@ func TestTxExecutorCommit(t *testing.T) { if err != nil { t.Error(err) } - // Commiting an absent transaction should succeed. + // Committing an absent transaction should succeed. err = txe.CommitPrepared("bb") if err != nil { t.Error(err) diff --git a/go/vt/vttablet/tabletserver/tx_prep_pool.go b/go/vt/vttablet/tabletserver/tx_prep_pool.go index b669ec756d8..184431cc450 100644 --- a/go/vt/vttablet/tabletserver/tx_prep_pool.go +++ b/go/vt/vttablet/tabletserver/tx_prep_pool.go @@ -23,7 +23,7 @@ import ( ) var ( - errPrepCommiting = errors.New("commiting") + errPrepCommitting = errors.New("committing") errPrepFailed = errors.New("failed") ) @@ -101,7 +101,7 @@ func (pp *TxPreparedPool) FetchForCommit(dtid string) (*TxConnection, error) { c, ok := pp.conns[dtid] if ok { delete(pp.conns, dtid) - pp.reserved[dtid] = errPrepCommiting + pp.reserved[dtid] = errPrepCommitting } return c, nil } diff --git a/go/vt/vttablet/tabletserver/tx_prep_pool_test.go b/go/vt/vttablet/tabletserver/tx_prep_pool_test.go index 66f9018c3ae..f7ffc0881b9 100644 --- a/go/vt/vttablet/tabletserver/tx_prep_pool_test.go +++ b/go/vt/vttablet/tabletserver/tx_prep_pool_test.go @@ -99,7 +99,7 @@ func TestPrepFetchForCommit(t *testing.T) { t.Errorf("pp.Get(aa): %p, want %p", got, conn) } got, err = pp.FetchForCommit("aa") - want := "commiting" + want := "committing" if err == nil || err.Error() != want { t.Errorf("FetchForCommit err: %v, want %s", err, want) } From acdcfcc77af0f277b399b7ed73d4be918ee8ef40 Mon Sep 17 00:00:00 2001 From: jvaidya Date: Sun, 24 Feb 2019 11:29:57 -0800 Subject: [PATCH 107/196] SET @@SESSION.sql_mode is now ignored rather than erroring out Signed-off-by: jvaidya --- go/vt/vtgate/executor.go | 2 +- go/vt/vtgate/executor_test.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index ef319ac7d0b..ade4811ea72 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -621,7 +621,7 @@ func (e *Executor) handleSet(ctx context.Context, safeSession *SafeSession, sql if !ok { return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unexpected value type for wait_timeout: %T", v) } - case "net_write_timeout", "net_read_timeout", "lc_messages", "collation_connection": + case "sql_mode", "net_write_timeout", "net_read_timeout", "lc_messages", "collation_connection": log.Warningf("Ignored inapplicable SET %v = %v", k, v) warnings.Add("IgnoredSet", 1) case "charset", "names": diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index 8af068afeed..b13ec8fea8b 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -389,6 +389,9 @@ func TestExecutorSet(t *testing.T) { }, { in: "set net_write_timeout = 600", out: &vtgatepb.Session{Autocommit: true}, + }, { + in: "set sql_mode = 'STRICT_ALL_TABLES'", + out: &vtgatepb.Session{Autocommit: true}, }, { in: "set net_read_timeout = 600", out: &vtgatepb.Session{Autocommit: true}, From d0063cb907f39c94f5bd0fecec90e1668fbf3044 Mon Sep 17 00:00:00 2001 From: Kim Bao Long Date: Mon, 25 Feb 2019 14:38:49 +0700 Subject: [PATCH 108/196] Trivial fix: Remove the redundant words Although it is spelling mistakes, it might make an affects while reading. Co-Authored-By: Nguyen Phuong An Signed-off-by: Kim Bao Long --- doc/VitessApi.md | 2 +- go/vt/proto/query/query.pb.go | 2 +- proto/query.proto | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/VitessApi.md b/doc/VitessApi.md index d4696429bdb..ab7ac7a01dd 100644 --- a/doc/VitessApi.md +++ b/doc/VitessApi.md @@ -666,7 +666,7 @@ StreamExecute executes a streaming query based on shards. It depends on the quer | BIT | 2073 | BIT specifies a BIT type. Properties: 25, IsQuoted. | | ENUM | 2074 | ENUM specifies an ENUM type. Properties: 26, IsQuoted. | | SET | 2075 | SET specifies a SET type. Properties: 27, IsQuoted. | -| TUPLE | 28 | TUPLE specifies a a tuple. This cannot be returned in a QueryResult, but it can be sent as a bind var. Properties: 28, None. | +| TUPLE | 28 | TUPLE specifies a tuple. This cannot be returned in a QueryResult, but it can be sent as a bind var. Properties: 28, None. | | GEOMETRY | 2077 | GEOMETRY specifies a GEOMETRY type. Properties: 29, IsQuoted. | | JSON | 2078 | JSON specified a JSON type. Properties: 30, IsQuoted. | diff --git a/go/vt/proto/query/query.pb.go b/go/vt/proto/query/query.pb.go index f821d65e994..15403d32d61 100644 --- a/go/vt/proto/query/query.pb.go +++ b/go/vt/proto/query/query.pb.go @@ -225,7 +225,7 @@ const ( // SET specifies a SET type. // Properties: 27, IsQuoted. Type_SET Type = 2075 - // TUPLE specifies a a tuple. This cannot + // TUPLE specifies a tuple. This cannot // be returned in a QueryResult, but it can // be sent as a bind var. // Properties: 28, None. diff --git a/proto/query.proto b/proto/query.proto index 5fdb91d4ed9..0e3e143c803 100644 --- a/proto/query.proto +++ b/proto/query.proto @@ -191,7 +191,7 @@ enum Type { // SET specifies a SET type. // Properties: 27, IsQuoted. SET = 2075; - // TUPLE specifies a a tuple. This cannot + // TUPLE specifies a tuple. This cannot // be returned in a QueryResult, but it can // be sent as a bind var. // Properties: 28, None. From 3c9641bf02b45b94f0d019498febf7f97b7fa9ea Mon Sep 17 00:00:00 2001 From: Kim Bao Long Date: Mon, 25 Feb 2019 14:57:58 +0700 Subject: [PATCH 109/196] Changing 'HTTP' to 'HTTPS' for securing vitess.io access Currently, when we access the ***vitess.io* with **HTTP**, it is redirected to **HTTPS** automatically. So this commit aims to replace **http://vitess.io** by **https://vitess.io** for security. Co-Authored-By: Nguyen Phuong An Signed-off-by: Kim Bao Long --- go/vt/vitessdriver/doc.go | 2 +- helm/vitess/Chart.yaml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go/vt/vitessdriver/doc.go b/go/vt/vitessdriver/doc.go index 6631f4b3be5..9641aa00ca6 100644 --- a/go/vt/vitessdriver/doc.go +++ b/go/vt/vitessdriver/doc.go @@ -41,7 +41,7 @@ Using this SQL driver is as simple as: For a full example, please see: https://github.com/vitessio/vitess/blob/master/examples/local/client.go -The full example is based on our tutorial for running Vitess locally: http://vitess.io/getting-started/local-instance/ +The full example is based on our tutorial for running Vitess locally: https://vitess.io/getting-started/local-instance/ Vtgate diff --git a/helm/vitess/Chart.yaml b/helm/vitess/Chart.yaml index c070e4b07c9..5b5f91e833e 100644 --- a/helm/vitess/Chart.yaml +++ b/helm/vitess/Chart.yaml @@ -11,10 +11,10 @@ keywords: - sql - database - shard -home: http://vitess.io +home: https://vitess.io sources: - https://github.com/vitessio/vitess maintainers: - name: Vitess Project email: vitess@googlegroups.com -icon: http://vitess.io/images/vitess_logo_with_border.svg +icon: https://vitess.io/images/vitess_logo_with_border.svg From 12d7eadefcfed7d71cfebcebf2c971007139cad6 Mon Sep 17 00:00:00 2001 From: Vu Cong Tuan Date: Mon, 25 Feb 2019 15:30:48 +0700 Subject: [PATCH 110/196] Fix many typos in test code Signed-off-by: Vu Cong Tuan --- test/cache_invalidation.py | 2 +- test/encrypted_transport.py | 2 +- test/tabletmanager.py | 2 +- test/tabletmanager2.py | 2 +- test/vtgate_buffer.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/test/cache_invalidation.py b/test/cache_invalidation.py index a3255cd5543..576a7860f37 100755 --- a/test/cache_invalidation.py +++ b/test/cache_invalidation.py @@ -284,7 +284,7 @@ def invalidate(self, table_name, row_id, token): # 1. If we can't compare the EventTokens, we want to store the # invalidation, so it's safer. # 2. If we have exactly the same EventToken, we do not want to - # store the ivalidation. We have either an invalidation or a + # store the invalidation. We have either an invalidation or a # value, in both cases we're fine keeping it. logging.debug(' invalidation event is older or equal than cache value,' ' ignoring') diff --git a/test/encrypted_transport.py b/test/encrypted_transport.py index 55aacec4843..e01f27213c4 100755 --- a/test/encrypted_transport.py +++ b/test/encrypted_transport.py @@ -38,7 +38,7 @@ vtgate vtgate client CA client -> vtgate client vtgate server CA client -> vtgate -Additionnally, we have the following constraints: +Additionally, we have the following constraints: - the client certificate common name is used as immediate caller ID by vtgate, and forwarded to vttablet. This allows us to use table ACLs on the vttablet side. diff --git a/test/tabletmanager.py b/test/tabletmanager.py index 1956cf9d245..89c02ef206a 100755 --- a/test/tabletmanager.py +++ b/test/tabletmanager.py @@ -48,7 +48,7 @@ def setUpModule(): topo_flavor = environment.topo_server().flavor() if topo_flavor == 'zk2': # This is a one-off test to make sure our 'zk2' implementation - # behave with a server that is not DNS-resolveable. + # behave with a server that is not DNS-resolvable. environment.topo_server().setup(add_bad_host=True) else: environment.topo_server().setup() diff --git a/test/tabletmanager2.py b/test/tabletmanager2.py index e65af1f1f92..e938156f3f6 100755 --- a/test/tabletmanager2.py +++ b/test/tabletmanager2.py @@ -58,7 +58,7 @@ def setUp(self): topo_flavor = environment.topo_server().flavor() if topo_flavor == 'zk2': # This is a one-off test to make sure our 'zk2' implementation - # behave with a server that is not DNS-resolveable. + # behave with a server that is not DNS-resolvable. environment.topo_server().setup(add_bad_host=True) else: environment.topo_server().setup() diff --git a/test/vtgate_buffer.py b/test/vtgate_buffer.py index 77104272140..ecc24d61551 100755 --- a/test/vtgate_buffer.py +++ b/test/vtgate_buffer.py @@ -348,7 +348,7 @@ def external_reparent(self): # Wait for replica to catch up to master. utils.wait_for_replication_pos(master, replica) - # Wait for at least one second to articially prolong the failover and give + # Wait for at least one second to artificially prolong the failover and give # the buffer a chance to observe it. d = time.time() - start min_unavailability_s = 1 From 46e847223c7ca4a2cf97528fbb9567800f336435 Mon Sep 17 00:00:00 2001 From: Vu Cong Tuan Date: Mon, 25 Feb 2019 16:12:13 +0700 Subject: [PATCH 111/196] Fix many typos in doc Signed-off-by: Vu Cong Tuan --- doc/LongRunningJobs.md | 2 +- doc/ReferenceTables.md | 6 +++--- doc/ReplicatoinLagBasedThrottlingOfTransactions.md | 2 +- doc/RowBasedReplication.md | 2 +- doc/SchemaManagement.md | 2 +- doc/Sharding.md | 4 ++-- doc/TopologyService.md | 2 +- doc/TwoPhaseCommitDesign.md | 2 +- doc/TwoPhaseCommitGuide.md | 2 +- doc/VSchema.md | 6 +++--- doc/VTGateSubqueries.md | 4 ++-- doc/VindexAsTable.md | 2 +- doc/VitessQueues.md | 2 +- doc/VitessSequences.md | 2 +- doc/life_of_a_query_client_to_vtgate.xml | 2 +- doc/meetups_notes/06-14-2018.md | 2 +- 16 files changed, 22 insertions(+), 22 deletions(-) diff --git a/doc/LongRunningJobs.md b/doc/LongRunningJobs.md index 8df2cff6b2c..832b9de3c93 100644 --- a/doc/LongRunningJobs.md +++ b/doc/LongRunningJobs.md @@ -130,7 +130,7 @@ do now). The link here is also very straightforward: -* When sucessfully starting a remote job, the address of the remote worker and +* When successfully starting a remote job, the address of the remote worker and the UID of the job can be checkpointed. * After that, the workflow can just connect and update its status and logs when diff --git a/doc/ReferenceTables.md b/doc/ReferenceTables.md index 9bf3a23fbb3..ea262f5d695 100644 --- a/doc/ReferenceTables.md +++ b/doc/ReferenceTables.md @@ -26,7 +26,7 @@ just a corner case of the vertical splits Vitess already supports. Action items: -* First, this setup probably needs to be explicitely mentioned somewhere in the +* First, this setup probably needs to be explicitly mentioned somewhere in the topology, not just as SourceShard objects in the destination keyspace, so Vitess can know about this setup at a higher level. Let's add a `repeated ReferenceKeyspace` field to the Keyspace object. Each `ReferenceKeyspace` @@ -59,7 +59,7 @@ the Reference Tables feature is enabled. Action items: * Each step of the process would know what to do because of the - `ReferenceKeyspace` entries in the destinatin keyspace. + `ReferenceKeyspace` entries in the destination keyspace. * `vtctl CopySchemaShard` needs to also copy the schema of the reference tables. @@ -82,7 +82,7 @@ Action items: ## Other Use Cases -Other scenarios might also need to be supported, or explicitely disabled: +Other scenarios might also need to be supported, or explicitly disabled: * Simple schema changes, or complicated Schema Swap in the reference keyspace: They would also need to be applied to the destination keyspace, the same way. diff --git a/doc/ReplicatoinLagBasedThrottlingOfTransactions.md b/doc/ReplicatoinLagBasedThrottlingOfTransactions.md index 42eed5db19e..ad93983313d 100644 --- a/doc/ReplicatoinLagBasedThrottlingOfTransactions.md +++ b/doc/ReplicatoinLagBasedThrottlingOfTransactions.md @@ -17,7 +17,7 @@ throttler: * *enable-tx-throttler* -A boolean flag controling whether the replication-lag-based throttling is enabled. +A boolean flag controlling whether the replication-lag-based throttling is enabled. * *tx-throttler-config* diff --git a/doc/RowBasedReplication.md b/doc/RowBasedReplication.md index c3fb795caf1..f4bba3611d2 100644 --- a/doc/RowBasedReplication.md +++ b/doc/RowBasedReplication.md @@ -97,7 +97,7 @@ same columns as all events in the binlog, plus some other optional columns that are then unused. That way, it is possible to add columns to tables without breaking anything. -Note if the main use case is Filtered Replicaiton for resharding, this +Note if the main use case is Filtered Replication for resharding, this limitation only exists while the resharding process is running. It is somewhat easy to not change the schema at the same time as resharding is on-going. diff --git a/doc/SchemaManagement.md b/doc/SchemaManagement.md index 1bdfcc6da66..701bc603658 100644 --- a/doc/SchemaManagement.md +++ b/doc/SchemaManagement.md @@ -1,4 +1,4 @@ -Uisng Vitess requires you to work with two different types of schemas: +Using Vitess requires you to work with two different types of schemas: 1. The MySQL database schema. This is the schema of the individual MySQL instances. 2. The [VSchema]({% link user-guide/vschema.md %}), which describes all the keyspaces and how they're sharded. diff --git a/doc/Sharding.md b/doc/Sharding.md index e50ff737d4f..1ab77855db7 100644 --- a/doc/Sharding.md +++ b/doc/Sharding.md @@ -39,7 +39,7 @@ for your application. Vitess allows you to choose the type of sharding scheme by the choice of your Primary Vindex for the tables of a shard. Once you have chosen the Primary Vindex, you can choose the partitions depending on how the -resulting keyspace IDs are distirbuted. +resulting keyspace IDs are distributed. Vitess calculates the sharding key or keys for each query and then routes that query to the appropriate shards. For example, a query @@ -168,7 +168,7 @@ is performed the following way: 1. The server process uses the primary vindex to compute the keyspace ID for every row coming throug the replication stream, and sends that row to the corresponding target shard. -1. The target shard converts the row into the corresponding DML (Data Manipulation Languate) +1. The target shard converts the row into the corresponding DML (Data Manipulation Language) and applies the statement. If using RBR, it's generally required that you have full image turned on. However, if your diff --git a/doc/TopologyService.md b/doc/TopologyService.md index 0cf4d7ecbfe..c5d690da58e 100644 --- a/doc/TopologyService.md +++ b/doc/TopologyService.md @@ -294,7 +294,7 @@ the same server address, and very importantly a *different* root directory. [Zookeeper Observers](https://zookeeper.apache.org/doc/trunk/zookeeperObservers.html) can also be used to limit the load on the global Zookeeper. They are configured by -specifying the adresses of the observers in the server address, after a `|`, +specifying the addresses of the observers in the server address, after a `|`, for instance: `global_server1:p1,global_server2:p2|observer1:po1,observer2:po2`. diff --git a/doc/TwoPhaseCommitDesign.md b/doc/TwoPhaseCommitDesign.md index 75bfc0a9b7a..1480c90ad65 100644 --- a/doc/TwoPhaseCommitDesign.md +++ b/doc/TwoPhaseCommitDesign.md @@ -90,7 +90,7 @@ We introduced many terms in the previous sections. It’s time for a quick recap Any form of failure until the point of saving the commit decision will result in a decision to rollback. * Transition the metadata state to ‘Rollback’. -* Issue RollbackPrepared comands to the prepared transactions using the DTID. +* Issue RollbackPrepared commands to the prepared transactions using the DTID. * If the original VTGate is still orchestrating, rollback the unprepared transactions using their VTIDs. The initial version will just execute RollbackPrepared on all participants with the assumption that any unprepared transactions will be rolled back by the transaction killer. * Delete the transaction in the MM (ConcludeTransaction). diff --git a/doc/TwoPhaseCommitGuide.md b/doc/TwoPhaseCommitGuide.md index 391cf42aabc..dccdb196eac 100644 --- a/doc/TwoPhaseCommitGuide.md +++ b/doc/TwoPhaseCommitGuide.md @@ -25,7 +25,7 @@ To enforce single-database transactions, the VTGates can be started by specifyin To enable 2PC, the VTGates need to be started with `transaction_mode=twopc`. The VTTablets will require a few more flags, which will be explained below. -The VTGate `transaction_mode` flag decides what to allow. The application can independently request a specific atomicity for each transaction. The request will be honored by VTGate only if it does not exceed what is allowed by the `transaction_mode`. For example, `transacion_mode=single` will only allow single-db transactions. On the other hand, `transaction_mode=twopc` will allow all three levels of atomicity. +The VTGate `transaction_mode` flag decides what to allow. The application can independently request a specific atomicity for each transaction. The request will be honored by VTGate only if it does not exceed what is allowed by the `transaction_mode`. For example, `transaction_mode=single` will only allow single-db transactions. On the other hand, `transaction_mode=twopc` will allow all three levels of atomicity. # Driver APIs diff --git a/doc/VSchema.md b/doc/VSchema.md index aafcd35f8ac..83c207badd7 100644 --- a/doc/VSchema.md +++ b/doc/VSchema.md @@ -11,7 +11,7 @@ In Vitess, a `keyspace` is sharded by `keyspace ID` ranges. Each row is assigned 1. The `keyspace ID` is a concept that is internal to Vitess. The application does not need to know anything about it. 2. There is no physical column that stores the actual `keyspace ID`. This value is computed as needed. -This difference is significant enough that we do not refer to the keyspace ID as the sharding key. we will later introduce the concept of a Primary Vindex which more closely ressembles the NoSQL sharding key. +This difference is significant enough that we do not refer to the keyspace ID as the sharding key. we will later introduce the concept of a Primary Vindex which more closely resembles the NoSQL sharding key. Mapping to a `keyspace ID`, and then to a shard, gives us the flexibility to reshard the data with minimal disruption because the `keyspace ID` of each row remains unchanged through the process. @@ -101,7 +101,7 @@ Lookup NonUnique | 20 #### Select -In the case of a simple select, Vitess scans the WHERE clause to match references to Vindex columns and chooses the best one to use. If there is no match and the query is simple without complex constructs like aggreates, etc, it is sent to all shards. +In the case of a simple select, Vitess scans the WHERE clause to match references to Vindex columns and chooses the best one to use. If there is no match and the query is simple without complex constructs like aggregates, etc, it is sent to all shards. Vitess can handle more complex queries. For now, you can refer to the [design doc](https://github.com/vitessio/vitess/blob/master/doc/V3HighLevelDesign.md) on how it handles them. @@ -148,7 +148,7 @@ As mentioned in the beginning of the document, a VSchema is needed to tie togeth If you have multiple unsharded keyspaces, you can still avoid defining a VSchema in one of two ways: 1. Connect to a keyspace and all queries are sent to it. -2. Connect to Vitess without specifying a keyspace, but use qualifed names for tables, like `keyspace.table` in your queries. +2. Connect to Vitess without specifying a keyspace, but use qualified names for tables, like `keyspace.table` in your queries. However, once the setup exceeds the above complexity, VSchemas become a necessity. Vitess has a [working demo](https://github.com/vitessio/vitess/tree/master/examples/demo) of VSchemas. This section documents the various features highlighted with snippets pulled from the demo. diff --git a/doc/VTGateSubqueries.md b/doc/VTGateSubqueries.md index 931857edd5e..40641bfbf5e 100644 --- a/doc/VTGateSubqueries.md +++ b/doc/VTGateSubqueries.md @@ -2,7 +2,7 @@ # Introduction -This document builds on top of [The V3 high level design](https://github.com/vitessio/vitess/blob/master/doc/V3HighLevelDesign.md). It discusses implemenation of subquery support in greater detail. +This document builds on top of [The V3 high level design](https://github.com/vitessio/vitess/blob/master/doc/V3HighLevelDesign.md). It discusses implementation of subquery support in greater detail. @@ -124,7 +124,7 @@ So, in the above case, c cannot be pulled out beyond b. If c was not correlated ### Generalizing pull-outs -The pull-out algorithm can be generallized as follows: +The pull-out algorithm can be generalized as follows: 1. Compute the primitive the subquery depends on: subqueryFrom 2. Compute the primitive the full expression depends on: subqueryTo diff --git a/doc/VindexAsTable.md b/doc/VindexAsTable.md index 55a9d529b23..642f74c482c 100644 --- a/doc/VindexAsTable.md +++ b/doc/VindexAsTable.md @@ -17,7 +17,7 @@ Looking at the vindex interface defined [here](https://github.com/vitessio/vites * Verify: `select 1 from my_vdx where id = :id and keyspace_id = :keyspace_id`. * ReverseMap: `select id from my_vdx where keyspace_id = :keyspace_id`. -The supported SQL syntax will be limited because of the limited functions that vindexes can perform. However, we can expand this meaningully. For example, we can allow `IN` clauses and multi-value constructs in the above cases. We can also add additional convenience functions like `vt_shard(keyspace_id)` that will map a keyspace_id to a shard. +The supported SQL syntax will be limited because of the limited functions that vindexes can perform. However, we can expand this meaningfully. For example, we can allow `IN` clauses and multi-value constructs in the above cases. We can also add additional convenience functions like `vt_shard(keyspace_id)` that will map a keyspace_id to a shard. The advantage of this approach is that we don't need to build new APIs to support these functionalities. diff --git a/doc/VitessQueues.md b/doc/VitessQueues.md index c570fa4ec55..8a0ccd2ec67 100644 --- a/doc/VitessQueues.md +++ b/doc/VitessQueues.md @@ -233,7 +233,7 @@ the event to one receiver only, until it is acked, or times out. *Hot Spots in the Queue table*: with very high QPS, we will end up having a hot spot on the window of events that are coming up. A proposed solution is to use an 'event_name' that has a unique value, and use it as a primary key. When the -Queue Manager gets new events howevers, it will still need to sort them by +Queue Manager gets new events however, it will still need to sort them by timestamp, and therefore will require an index. It is unclear which solution will work better, we'd need to experiment. For instance, if most events are only present in the table while they are being processed, the entire table will have diff --git a/doc/VitessSequences.md b/doc/VitessSequences.md index 7dc4e7ff6bf..d2a68ceb4ad 100644 --- a/doc/VitessSequences.md +++ b/doc/VitessSequences.md @@ -50,7 +50,7 @@ Alternative to auto-incrementing IDs are: ID. If taken (because the statement returns an integrity error), try another ID. -* use a UUID scheme, and generate trully unique IDs. +* use a UUID scheme, and generate truly unique IDs. Now that this is out of the way, let's get to MySQL auto-increment. diff --git a/doc/life_of_a_query_client_to_vtgate.xml b/doc/life_of_a_query_client_to_vtgate.xml index ea3e8967257..b546fb95e9c 100644 --- a/doc/life_of_a_query_client_to_vtgate.xml +++ b/doc/life_of_a_query_client_to_vtgate.xml @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/doc/meetups_notes/06-14-2018.md b/doc/meetups_notes/06-14-2018.md index 67348fe2656..904c9a7ee0c 100644 --- a/doc/meetups_notes/06-14-2018.md +++ b/doc/meetups_notes/06-14-2018.md @@ -82,7 +82,7 @@ Demmer brought up some other bugs and workarounds. But these workarounds don't w Sugu talked about how in the early days, we expected different behavior. So some artifacts of old design still linger and have to be fixed. -Sugu talked about how we need to work on resharding workflow. There are complaints about the general design being non-composable. We need to rework this to more easily use componenents to do other things like reversing filtered replication, or using filter replication for materialized views. We need to look at how to create alternative workflows. +Sugu talked about how we need to work on resharding workflow. There are complaints about the general design being non-composable. We need to rework this to more easily use components to do other things like reversing filtered replication, or using filter replication for materialized views. We need to look at how to create alternative workflows. Not discussed, but here is a [link](https://github.com/vitessio/vitess/issues/3997) to Sugu's thoughts on topo revamp. Here is link to the filtered replication [issue](https://github.com/vitessio/vitess/issues/4002), for context. From 5b7b1a4fc069227b0475510cde8e9ff620b6f054 Mon Sep 17 00:00:00 2001 From: Vu Cong Tuan Date: Mon, 25 Feb 2019 16:22:32 +0700 Subject: [PATCH 112/196] Update GitHub Workflow link Signed-off-by: Vu Cong Tuan --- doc/internal/PublishWebsite.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/internal/PublishWebsite.md b/doc/internal/PublishWebsite.md index 1232ee0ad4a..5787416f932 100644 --- a/doc/internal/PublishWebsite.md +++ b/doc/internal/PublishWebsite.md @@ -66,7 +66,7 @@ The boiler plate markdown files have multiple purposes: the file * re-arrange paths on the website e.g. [`doc/GitHubWorkFlow.md`](https://github.com/vitessio/vitess/blob/master/doc/GitHubWorkflow.md) - is actually served as http://vitess.io/contributing/github-workflow/ + is actually served as https://vitess.io/docs/contributing/github-workflow/ because there is the file [`vitess.io/contributing/github-workflow.md`](https://github.com/vitessio/vitess/blob/master/vitess.io/contributing/github-workflow.md). From bf2e687a35bd39c781d017acdf2b0f331bc5ac1d Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Mon, 25 Feb 2019 11:13:18 +0100 Subject: [PATCH 113/196] Refactor according to feedback Signed-off-by: Andres Taylor --- go/vt/servenv/grpc_server.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/go/vt/servenv/grpc_server.go b/go/vt/servenv/grpc_server.go index ce9c28afedf..8714e754663 100644 --- a/go/vt/servenv/grpc_server.go +++ b/go/vt/servenv/grpc_server.go @@ -185,8 +185,8 @@ func interceptors() []grpc.ServerOption { } if *grpccommon.EnableGRPCPrometheus { - streamInterceptor = mergeS(streamInterceptor, grpc_prometheus.StreamServerInterceptor) - unaryInterceptor = mergeU(unaryInterceptor, grpc_prometheus.UnaryServerInterceptor) + streamInterceptor = mergeStreamServerInterceptor(streamInterceptor, grpc_prometheus.StreamServerInterceptor) + unaryInterceptor = mergeUnaryServerInterceptor(unaryInterceptor, grpc_prometheus.UnaryServerInterceptor) } if streamInterceptor == nil { @@ -196,14 +196,14 @@ func interceptors() []grpc.ServerOption { } } -func mergeS(a,b grpc.StreamServerInterceptor) grpc.StreamServerInterceptor { +func mergeStreamServerInterceptor(a,b grpc.StreamServerInterceptor) grpc.StreamServerInterceptor { if a == nil { return b } return grpc_middleware.ChainStreamServer(a, b) } -func mergeU(a,b grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor { +func mergeUnaryServerInterceptor(a,b grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor { if a == nil { return b } From 44999b0ea842356fbab9bb64950b9dfa70693bbf Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Mon, 25 Feb 2019 22:54:39 -0500 Subject: [PATCH 114/196] fix 404 not fount Signed-off-by: xichengliudui --- vagrant-scripts/vitess/build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vagrant-scripts/vitess/build.sh b/vagrant-scripts/vitess/build.sh index b920f55c3a2..893b1061397 100755 --- a/vagrant-scripts/vitess/build.sh +++ b/vagrant-scripts/vitess/build.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash # -# See http://vitess.io/getting-started/local-instance.html#manual-build +# See https://vitess.io/docs/tutorials/vagrant/ # for more info # From 2d0dbe576db4b96ac631b67d3c5aacd4f4926b4b Mon Sep 17 00:00:00 2001 From: Kim Bao Long Date: Tue, 26 Feb 2019 11:24:57 +0700 Subject: [PATCH 115/196] Update the dead URL that links to 'guestbook-go' The URL that links to **guestbook-go** is unreachable now. This commit intends to solve this problem by replacing with the working URL Co-Authored-By: Nguyen Phuong An Signed-off-by: Kim Bao Long --- examples/kubernetes/guestbook/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/kubernetes/guestbook/README.md b/examples/kubernetes/guestbook/README.md index e0b2e11ae5d..2ff41a9217c 100644 --- a/examples/kubernetes/guestbook/README.md +++ b/examples/kubernetes/guestbook/README.md @@ -3,7 +3,7 @@ This is a Docker image for a sample guestbook app that uses Vitess. It is essentially a port of the -[kubernetes/guestbook-go](https://github.com/GoogleCloudPlatform/kubernetes/tree/master/examples/guestbook-go) +[kubernetes/guestbook-go](https://github.com/kubernetes/examples/tree/master/guestbook-go) example, but using Python instead of Go for the app server, and Vitess instead of Redis for the storage engine. From eb03e32d4e2c11f9c046703a44cc1538dc60967b Mon Sep 17 00:00:00 2001 From: xichengliudui Date: Mon, 25 Feb 2019 23:40:07 -0500 Subject: [PATCH 116/196] Remove any unnecessary highlighting Signed-off-by: xichengliudui --- doc/DockerBuild.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/DockerBuild.md b/doc/DockerBuild.md index 75ebf150580..bb88d3c7b5d 100644 --- a/doc/DockerBuild.md +++ b/doc/DockerBuild.md @@ -4,7 +4,7 @@ point to the `vitess/lite` image on [Docker Hub](https://hub.docker.com/u/vitess We created the `lite` image as a stripped down version of our main image `base` such that Kubernetes pods can start faster. The `lite` image does not change very often and is updated manually by the Vitess team with every release. In contrast, the `base` image is updated automatically after every push to the GitHub master branch. -For more information on the different images we provide, please read the [`docker/README.md` file](https://github.com/vitessio/vitess/tree/master/docker). +For more information on the different images we provide, please read the [`docker/README.md`](https://github.com/vitessio/vitess/tree/master/docker) file. If your goal is run the latest Vitess code, the simplest solution is to use the bigger `base` image instead of `lite`. From a2e43fedcebb212a8a72c136f6c567c4f7bd3ab8 Mon Sep 17 00:00:00 2001 From: Nguyen Hai Truong Date: Tue, 26 Feb 2019 02:12:44 -0800 Subject: [PATCH 117/196] Alphabetically sorted modules import Modules which are imported to python are sorted alphabetically are quicker to read and searchable. Co-Authored-By: Dao Cong Tien tiendc@vn.fujitsu.com Signed-off-by: Nguyen Hai Truong --- examples/kubernetes/guestbook/main.py | 2 +- test/base_sharding.py | 4 ++-- test/cluster/k8s_environment.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/kubernetes/guestbook/main.py b/examples/kubernetes/guestbook/main.py index a9a6aa7186d..3a2a74e824d 100644 --- a/examples/kubernetes/guestbook/main.py +++ b/examples/kubernetes/guestbook/main.py @@ -15,9 +15,9 @@ """Main python file.""" import argparse +import json import os import time -import json from flask import Flask diff --git a/test/base_sharding.py b/test/base_sharding.py index acc6d3a6f3d..64fefd28f89 100644 --- a/test/base_sharding.py +++ b/test/base_sharding.py @@ -17,10 +17,10 @@ """This module contains a base class and utility functions for sharding tests. """ -import struct - import logging +import struct + from vtdb import keyrange_constants import utils diff --git a/test/cluster/k8s_environment.py b/test/cluster/k8s_environment.py index ca9312e2ee7..deddabbd20f 100644 --- a/test/cluster/k8s_environment.py +++ b/test/cluster/k8s_environment.py @@ -14,8 +14,8 @@ """Kubernetes environment.""" -import json import getpass +import json import logging import os import subprocess From 9cbaed3ce10df35361b2bfa11215238c3bbec6e6 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Tue, 26 Feb 2019 15:00:08 +0100 Subject: [PATCH 118/196] Added unit tests Signed-off-by: Andres Taylor --- go/vt/servenv/grpc_server.go | 51 ++++++++------- go/vt/servenv/grpc_server_test.go | 100 ++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 23 deletions(-) create mode 100644 go/vt/servenv/grpc_server_test.go diff --git a/go/vt/servenv/grpc_server.go b/go/vt/servenv/grpc_server.go index 8714e754663..11b320ab1e9 100644 --- a/go/vt/servenv/grpc_server.go +++ b/go/vt/servenv/grpc_server.go @@ -169,8 +169,7 @@ func createGRPCServer() { // We can only set a ServerInterceptor once, so we chain multiple interceptors into one func interceptors() []grpc.ServerOption { - var streamInterceptor grpc.StreamServerInterceptor - var unaryInterceptor grpc.UnaryServerInterceptor + interceptors := &InterceptorBuilder{} if *GRPCAuth != "" { log.Infof("enabling auth plugin %v", *GRPCAuth) @@ -180,34 +179,20 @@ func interceptors() []grpc.ServerOption { log.Fatalf("Failed to load auth plugin: %v", err) } authPlugin = authPluginImpl - streamInterceptor = authenticatingStreamInterceptor - unaryInterceptor = authenticatingUnaryInterceptor + interceptors.Add(authenticatingStreamInterceptor, authenticatingUnaryInterceptor) } if *grpccommon.EnableGRPCPrometheus { - streamInterceptor = mergeStreamServerInterceptor(streamInterceptor, grpc_prometheus.StreamServerInterceptor) - unaryInterceptor = mergeUnaryServerInterceptor(unaryInterceptor, grpc_prometheus.UnaryServerInterceptor) + interceptors.Add(grpc_prometheus.StreamServerInterceptor, grpc_prometheus.UnaryServerInterceptor) } - if streamInterceptor == nil { - return []grpc.ServerOption{} + if interceptors.NonEmpty() { + return []grpc.ServerOption{ + grpc.StreamInterceptor(interceptors.StreamServerInterceptor), + grpc.UnaryInterceptor(interceptors.UnaryStreamInterceptor)} } else { - return []grpc.ServerOption{grpc.StreamInterceptor(streamInterceptor), grpc.UnaryInterceptor(unaryInterceptor)} - } -} - -func mergeStreamServerInterceptor(a,b grpc.StreamServerInterceptor) grpc.StreamServerInterceptor { - if a == nil { - return b - } - return grpc_middleware.ChainStreamServer(a, b) -} - -func mergeUnaryServerInterceptor(a,b grpc.UnaryServerInterceptor) grpc.UnaryServerInterceptor { - if a == nil { - return b + return []grpc.ServerOption{} } - return grpc_middleware.ChainUnaryServer(a, b) } func serveGRPC() { @@ -294,3 +279,23 @@ func WrapServerStream(stream grpc.ServerStream) *WrappedServerStream { } return &WrappedServerStream{ServerStream: stream, WrappedContext: stream.Context()} } + +// InterceptorBuilder chains together multiple ServerInterceptors +type InterceptorBuilder struct { + StreamServerInterceptor grpc.StreamServerInterceptor + UnaryStreamInterceptor grpc.UnaryServerInterceptor +} + +func (collector *InterceptorBuilder) Add(s grpc.StreamServerInterceptor, u grpc.UnaryServerInterceptor) { + if collector.StreamServerInterceptor == nil { + collector.StreamServerInterceptor = s + collector.UnaryStreamInterceptor = u + } else { + collector.StreamServerInterceptor = grpc_middleware.ChainStreamServer(collector.StreamServerInterceptor, s) + collector.UnaryStreamInterceptor = grpc_middleware.ChainUnaryServer(collector.UnaryStreamInterceptor, u) + } +} + +func (collector *InterceptorBuilder) NonEmpty() bool { + return collector.StreamServerInterceptor != nil +} \ No newline at end of file diff --git a/go/vt/servenv/grpc_server_test.go b/go/vt/servenv/grpc_server_test.go new file mode 100644 index 00000000000..5e4432eb4bf --- /dev/null +++ b/go/vt/servenv/grpc_server_test.go @@ -0,0 +1,100 @@ +/* +Copyright 2017 Google Inc. + +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 servenv + +import ( + "testing" + + "golang.org/x/net/context" + + "google.golang.org/grpc" +) + +func TestEmpty(t *testing.T) { + interceptors := &InterceptorBuilder{} + if interceptors.NonEmpty() { + t.Fatalf("expected empty builder to report as empty") + } +} + +func TestSingleInterceptor(t *testing.T) { + interceptors := &InterceptorBuilder{} + fake := &FakeInterceptor{} + + interceptors.Add(fake.StreamServerInterceptor, fake.UnaryServerInterceptor) + + if !interceptors.NonEmpty() { + t.Fatalf("non-empty collector claims to have stuff") + } + + _ = interceptors.StreamServerInterceptor(42, nil, nil, nullSHandler) + _, _ = interceptors.UnaryStreamInterceptor(context.Background(), 666, nil, nullUHandler) + + assertEquals(t, fake.streamSeen, 42) + assertEquals(t, fake.unarySeen, 666) +} + +func TestDoubleInterceptor(t *testing.T) { + interceptors := &InterceptorBuilder{} + fake1 := &FakeInterceptor{name: "ettan"} + fake2 := &FakeInterceptor{name: "tvaon"} + + interceptors.Add(fake1.StreamServerInterceptor, fake1.UnaryServerInterceptor) + interceptors.Add(fake2.StreamServerInterceptor, fake2.UnaryServerInterceptor) + + if !interceptors.NonEmpty() { + t.Fatalf("non-empty collector claims to have stuff") + } + + _ = interceptors.StreamServerInterceptor(42, nil, nil, nullSHandler) + _, _ = interceptors.UnaryStreamInterceptor(context.Background(), 666, nil, nullUHandler) + + assertEquals(t, fake1.streamSeen, 42) + assertEquals(t, fake1.unarySeen, 666) + assertEquals(t, fake2.streamSeen, 42) + assertEquals(t, fake2.unarySeen, 666) +} + +func nullSHandler(_ interface{}, _ grpc.ServerStream) error { + return nil +} + +func nullUHandler(_ context.Context, req interface{}) (interface{}, error) { + return req, nil +} + +func assertEquals(t *testing.T, a, b interface{}) { + if a != b { + t.Errorf("expected %v but got %v", a, b) + } +} + +type FakeInterceptor struct { + name string + streamSeen interface{} + unarySeen interface{} +} + +func (fake *FakeInterceptor) StreamServerInterceptor(value interface{}, stream grpc.ServerStream, _ *grpc.StreamServerInfo, handler grpc.StreamHandler) error { + fake.streamSeen = value + return handler(value, stream) +} + +func (fake *FakeInterceptor) UnaryServerInterceptor(ctx context.Context, value interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { + fake.unarySeen = value + return handler(ctx, value) +} From 261b341a02abb62a8dd164e179a6224d6f47683a Mon Sep 17 00:00:00 2001 From: David Weitzman Date: Tue, 26 Feb 2019 14:15:55 -0800 Subject: [PATCH 119/196] Use jsonpb marshaling for vtctl's GetVSchema Protobufs should generally go through jsonpb to convert to and from json. One specific thing that's different with jsonpb's encoding is that "columnListAuthoritative" is camelCase vs json's encoding using snake_case. jsonpb is lenient about parsing json, accepting either snake or camel case. Signed-off-by: David Weitzman --- go/vt/vtctl/vtctl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index c4c6e9e4544..7dd78e0153b 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -2108,7 +2108,7 @@ func commandGetVSchema(ctx context.Context, wr *wrangler.Wrangler, subFlags *fla if err != nil { return err } - b, err := json.MarshalIndent(schema, "", " ") + b, err := json2.MarshalIndentPB(schema, " ") if err != nil { wr.Logger().Printf("%v\n", err) return err From ec6a753f267a6997f774fb19e37797b7a5e6939e Mon Sep 17 00:00:00 2001 From: Michael Pawliszyn Date: Tue, 26 Feb 2019 15:51:44 -0500 Subject: [PATCH 120/196] We should always time out health connections to a vttablet. Otherwise when a connection goes dead and the vttablet procees restarts the vtgate will never try to reestablish the connection. Signed-off-by: Michael Pawliszyn --- go/vt/discovery/healthcheck.go | 11 ++--------- go/vt/discovery/healthcheck_test.go | 21 ++++++++++++--------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index 7fde2774bd4..8a840dd3471 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -527,24 +527,17 @@ func (hc *HealthCheckImpl) checkConn(hcc *healthCheckConn, name string) { // between the goroutine that sets it and the check for its value // later. timedout := sync2.NewAtomicBool(false) - serving := hcc.tabletStats.Serving go func() { for { select { - case serving = <-servingStatus: + case <-servingStatus: continue case <-time.After(hc.healthCheckTimeout): - // Ignore if not serving. - if !serving { - continue - } timedout.Set(true) streamCancel() return case <-streamCtx.Done(): - // If stream returns while serving is false, the function - // will get stuck in an infinite loop. This code path - // breaks the loop. + // If the stream is done, stop watching. return } } diff --git a/go/vt/discovery/healthcheck_test.go b/go/vt/discovery/healthcheck_test.go index 980eb90cadd..caa61e2d1fd 100644 --- a/go/vt/discovery/healthcheck_test.go +++ b/go/vt/discovery/healthcheck_test.go @@ -545,28 +545,31 @@ func TestHealthCheckTimeout(t *testing.T) { t.Errorf("StreamHealth should be canceled after timeout, but is not") } - // repeat the wait. There should be no error or cancelation. + // repeat the wait. It will timeout one more time trying to get the connection. fc.resetCanceledFlag() - time.Sleep(2 * timeout) + time.Sleep(timeout) t.Logf(`Sleep(2 * timeout)`) - select { - case res = <-l.output: - t.Errorf(`<-l.output: %+v; want not message`, res) - default: + res = <-l.output + if res.Serving { + t.Errorf(`<-l.output: %+v; want not serving`, res) } - if err := checkErrorCounter("k", "s", topodatapb.TabletType_MASTER, 1); err != nil { + if err := checkErrorCounter("k", "s", topodatapb.TabletType_MASTER, 2); err != nil { t.Errorf("%v", err) } - if fc.isCanceled() { - t.Errorf("StreamHealth should not be canceled after timeout") + if !fc.isCanceled() { + t.Errorf("StreamHealth should be canceled again after timeout") } // send a healthcheck response, it should be serving again + fc.resetCanceledFlag() input <- shr t.Logf(`input <- {{Keyspace: "k", Shard: "s", TabletType: MASTER}, Serving: true, TabletExternallyReparentedTimestamp: 10, {SecondsBehindMaster: 1, CpuUsage: 0.2}}`) + + // wait for the exponential backoff to wear off and health monitoring to resume. + time.Sleep(timeout) res = <-l.output if !reflect.DeepEqual(res, want) { t.Errorf(`<-l.output: %+v; want %+v`, res, want) From 69f128d60c4afe5cbee40c502d4014fd20357435 Mon Sep 17 00:00:00 2001 From: Michael Demmer Date: Tue, 26 Feb 2019 22:17:56 -0800 Subject: [PATCH 121/196] properly use sqlparser.String to quote reserved table names Signed-off-by: Michael Demmer --- go/vt/vtexplain/vtexplain_vttablet.go | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 64d9ed55470..e30727da8b5 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -388,7 +388,7 @@ func initTabletEnvironment(ddls []*sqlparser.DDL, opts *Options) error { } for i, ddl := range ddls { - table := ddl.Table.Name.String() + table := sqlparser.String(ddl.Table.Name) schemaQueries[mysql.BaseShowTablesForTable(table)] = &sqltypes.Result{ Fields: mysql.BaseShowTablesFields, RowsAffected: 1, @@ -511,9 +511,10 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* return callback(&sqltypes.Result{}) } - colTypeMap := tableColumns[table.String()] - if colTypeMap == nil && table.String() != "dual" { - return fmt.Errorf("unable to resolve table name %s", table.String()) + tableName := sqlparser.String(table) + colTypeMap := tableColumns[tableName] + if colTypeMap == nil && tableName != "dual" { + return fmt.Errorf("unable to resolve table name %s", tableName) } colNames := make([]string, 0, 4) From 7fb5dce2ff823ee25976d126f2625d5db4237855 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Wed, 27 Feb 2019 10:54:36 +0100 Subject: [PATCH 122/196] Errors clean up * Use vterrors in few places * Make stack trace display the default * More unit testing around error handling Signed-off-by: Andres Taylor --- go/vt/sqlparser/analyzer.go | 4 +- go/vt/topo/cell_info.go | 9 +- go/vt/topo/consultopo/lock.go | 7 +- go/vt/topo/consultopo/server.go | 5 +- go/vt/topo/etcd2topo/lock.go | 4 +- go/vt/topo/etcd2topo/watch.go | 7 +- go/vt/topo/helpers/compare.go | 49 +- go/vt/topo/keyspace.go | 21 +- go/vt/topo/locks.go | 21 +- go/vt/topo/memorytopo/directory.go | 6 +- go/vt/topo/memorytopo/file.go | 8 +- go/vt/topo/replication.go | 6 +- go/vt/topo/server.go | 4 +- go/vt/topo/shard.go | 27 +- go/vt/topo/srv_keyspace.go | 8 +- go/vt/topo/srv_vschema.go | 9 +- go/vt/topo/tablet.go | 6 +- go/vt/topo/topoproto/tablet.go | 5 +- go/vt/topo/vschema.go | 4 +- go/vt/topo/wildcards.go | 17 +- go/vt/topo/zk2topo/election.go | 4 +- go/vt/topo/zk2topo/lock.go | 4 +- go/vt/topo/zk2topo/utils.go | 7 +- go/vt/topo/zk2topo/watch.go | 3 +- go/vt/vtctld/api_test.go | 73 +-- go/vt/vterrors/errors_test.go | 75 ++- go/vt/vterrors/stack.go | 22 +- go/vt/vterrors/vterrors.go | 62 +-- go/vt/vterrors/vterrors_test.go | 73 --- go/vt/vtexplain/vtexplain_flaky_test.go | 12 +- go/vt/vtexplain/vtexplain_vtgate.go | 3 +- go/vt/vtgate/buffer/buffer_test.go | 2 +- go/vt/vtgate/executor_select_test.go | 9 +- go/vt/vtgate/gateway/discoverygateway.go | 2 +- go/vt/vtgate/gateway/discoverygateway_test.go | 105 +++-- go/vt/vtgate/gateway/shard_error.go | 8 +- go/vt/vtgate/planbuilder/insert.go | 3 +- go/vt/vtgate/planbuilder/plan_test.go | 40 +- go/vt/vtgate/resolver_test.go | 435 +++++++++--------- go/vt/vtgate/scatter_conn_test.go | 6 +- go/vt/vtgate/vindexes/hash.go | 5 +- go/vt/vtgate/vindexes/numeric.go | 5 +- go/vt/vtgate/vindexes/numeric_static_map.go | 6 +- go/vt/vtgate/vindexes/reverse_bits.go | 5 +- go/vt/vttablet/tabletserver/codex.go | 4 +- .../tabletserver/tabletserver_test.go | 33 +- go/vt/worker/block.go | 5 +- go/vt/worker/block_cmd.go | 4 +- go/vt/worker/chunk.go | 3 +- go/vt/worker/command.go | 6 +- go/vt/worker/diff_utils.go | 22 +- go/vt/worker/executor.go | 7 +- go/vt/worker/instance.go | 6 +- go/vt/worker/key_resolver.go | 28 +- go/vt/worker/multi_split_diff_cmd.go | 20 +- go/vt/worker/ping_cmd.go | 4 +- go/vt/worker/restartable_result_reader.go | 14 +- go/vt/worker/result_merger.go | 29 +- go/vt/worker/row_aggregator.go | 3 +- go/vt/worker/row_differ.go | 7 +- go/vt/worker/split_clone.go | 104 ++--- go/vt/worker/split_clone_cmd.go | 5 +- go/vt/worker/split_diff.go | 20 +- go/vt/worker/split_diff_cmd.go | 7 +- go/vt/worker/table_status.go | 4 +- go/vt/worker/vtworkerclient/interface.go | 5 +- 66 files changed, 809 insertions(+), 727 deletions(-) delete mode 100644 go/vt/vterrors/vterrors_test.go diff --git a/go/vt/sqlparser/analyzer.go b/go/vt/sqlparser/analyzer.go index 418a63ab01b..6d4db548ad0 100644 --- a/go/vt/sqlparser/analyzer.go +++ b/go/vt/sqlparser/analyzer.go @@ -220,7 +220,7 @@ func NewPlanValue(node Expr) (sqltypes.PlanValue, error) { case IntVal: n, err := sqltypes.NewIntegral(string(node.Val)) if err != nil { - return sqltypes.PlanValue{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v", err) + return sqltypes.PlanValue{}, err } return sqltypes.PlanValue{Value: n}, nil case StrVal: @@ -228,7 +228,7 @@ func NewPlanValue(node Expr) (sqltypes.PlanValue, error) { case HexVal: v, err := node.HexDecode() if err != nil { - return sqltypes.PlanValue{}, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v", err) + return sqltypes.PlanValue{}, err } return sqltypes.PlanValue{Value: sqltypes.MakeTrusted(sqltypes.VarBinary, v)}, nil } diff --git a/go/vt/topo/cell_info.go b/go/vt/topo/cell_info.go index 25523f4aa14..1f2658d217d 100644 --- a/go/vt/topo/cell_info.go +++ b/go/vt/topo/cell_info.go @@ -17,11 +17,12 @@ limitations under the License. package topo import ( - "fmt" "path" "github.com/golang/protobuf/proto" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -139,19 +140,19 @@ func (ts *Server) DeleteCellInfo(ctx context.Context, cell string) error { // Get all keyspaces. keyspaces, err := ts.GetKeyspaces(ctx) if err != nil { - return fmt.Errorf("GetKeyspaces() failed: %v", err) + return vterrors.Wrap(err, "GetKeyspaces() failed") } // For each keyspace, make sure no shard points at the cell. for _, keyspace := range keyspaces { shards, err := ts.FindAllShardsInKeyspace(ctx, keyspace) if err != nil { - return fmt.Errorf("FindAllShardsInKeyspace(%v) failed: %v", keyspace, err) + return vterrors.Wrapf(err, "FindAllShardsInKeyspace(%v) failed", keyspace) } for shard, si := range shards { if si.HasCell(cell) { - return fmt.Errorf("cell %v is used by shard %v/%v, cannot remove it. Use 'vtctl RemoveShardCell' to remove unused cells in a Shard", cell, keyspace, shard) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cell %v is used by shard %v/%v, cannot remove it. Use 'vtctl RemoveShardCell' to remove unused cells in a Shard", cell, keyspace, shard) } } } diff --git a/go/vt/topo/consultopo/lock.go b/go/vt/topo/consultopo/lock.go index f493a5fb7fb..49556fa3404 100644 --- a/go/vt/topo/consultopo/lock.go +++ b/go/vt/topo/consultopo/lock.go @@ -17,11 +17,12 @@ limitations under the License. package consultopo import ( - "fmt" "path" "github.com/hashicorp/consul/api" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo" @@ -106,7 +107,7 @@ func (s *Server) Lock(ctx context.Context, dirPath, contents string) (topo.LockD func (ld *consulLockDescriptor) Check(ctx context.Context) error { select { case <-ld.lost: - return fmt.Errorf("lost channel closed") + return vterrors.Errorf(vtrpc.Code_INTERNAL, "lost channel closed") default: } return nil @@ -123,7 +124,7 @@ func (s *Server) unlock(ctx context.Context, lockPath string) error { li, ok := s.locks[lockPath] s.mu.Unlock() if !ok { - return fmt.Errorf("unlock: lock %v not held", lockPath) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "unlock: lock %v not held", lockPath) } // Try to unlock our lock. We will clean up our entry anyway. diff --git a/go/vt/topo/consultopo/server.go b/go/vt/topo/consultopo/server.go index 55bd575f8fc..b68185bd00c 100644 --- a/go/vt/topo/consultopo/server.go +++ b/go/vt/topo/consultopo/server.go @@ -27,6 +27,7 @@ import ( "sync" "github.com/hashicorp/consul/api" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo" @@ -66,12 +67,12 @@ func getClientCreds() (creds map[string]*ClientAuthCred, err error) { data, err := ioutil.ReadFile(*consulAuthClientStaticFile) if err != nil { - err = fmt.Errorf("Failed to read consul_auth_static_file file: %v", err) + err = vterrors.Wrapf(err, "Failed to read consul_auth_static_file file") return creds, err } if err := json.Unmarshal(data, &creds); err != nil { - err = fmt.Errorf(fmt.Sprintf("Error parsing consul_auth_static_file: %v", err)) + err = vterrors.Wrapf(err, fmt.Sprintf("Error parsing consul_auth_static_file")) return creds, err } return creds, nil diff --git a/go/vt/topo/etcd2topo/lock.go b/go/vt/topo/etcd2topo/lock.go index 5479b992228..27928cf3e25 100644 --- a/go/vt/topo/etcd2topo/lock.go +++ b/go/vt/topo/etcd2topo/lock.go @@ -24,6 +24,8 @@ import ( "github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/mvcc/mvccpb" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo" @@ -88,7 +90,7 @@ func (s *Server) waitOnLastRev(ctx context.Context, cli *clientv3.Client, nodePa defer cancel() wc := cli.Watch(ctx, key, clientv3.WithRev(revision)) if wc == nil { - return false, fmt.Errorf("Watch failed") + return false, vterrors.Errorf(vtrpc.Code_INTERNAL, "Watch failed") } select { diff --git a/go/vt/topo/etcd2topo/watch.go b/go/vt/topo/etcd2topo/watch.go index b02f0e00d6c..9d8b78db1c5 100644 --- a/go/vt/topo/etcd2topo/watch.go +++ b/go/vt/topo/etcd2topo/watch.go @@ -17,13 +17,14 @@ limitations under the License. package etcd2topo import ( - "fmt" "path" "time" "github.com/coreos/etcd/clientv3" "github.com/coreos/etcd/mvcc/mvccpb" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo" @@ -56,7 +57,7 @@ func (s *Server) Watch(ctx context.Context, filePath string) (*topo.WatchData, < // not have that much history. watcher := s.cli.Watch(watchCtx, nodePath, clientv3.WithRev(initial.Header.Revision)) if watcher == nil { - return &topo.WatchData{Err: fmt.Errorf("Watch failed")}, nil, nil + return &topo.WatchData{Err: vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "Watch failed")}, nil, nil } // Create the notifications channel, send updates to it. @@ -117,7 +118,7 @@ func (s *Server) Watch(ctx context.Context, filePath string) (*topo.WatchData, < return default: notifications <- &topo.WatchData{ - Err: fmt.Errorf("unexpected event received: %v", ev), + Err: vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected event received: %v", ev), } return } diff --git a/go/vt/topo/helpers/compare.go b/go/vt/topo/helpers/compare.go index a14f3f83a03..53acbb34a4c 100644 --- a/go/vt/topo/helpers/compare.go +++ b/go/vt/topo/helpers/compare.go @@ -19,34 +19,35 @@ limitations under the License. package helpers import ( - "fmt" "reflect" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/topo" + "vitess.io/vitess/go/vt/vterrors" ) // CompareKeyspaces will compare the keyspaces in the destination topo. func CompareKeyspaces(ctx context.Context, fromTS, toTS *topo.Server) error { keyspaces, err := fromTS.GetKeyspaces(ctx) if err != nil { - return fmt.Errorf("GetKeyspace(%v): %v", keyspaces, err) + return vterrors.Wrapf(err, "GetKeyspace(%v)", keyspaces) } for _, keyspace := range keyspaces { fromKs, err := fromTS.GetKeyspace(ctx, keyspace) if err != nil { - return fmt.Errorf("GetKeyspace(%v): %v", keyspace, err) + return vterrors.Wrapf(err, "GetKeyspace(%v)", keyspace) } toKs, err := toTS.GetKeyspace(ctx, keyspace) if err != nil { - return fmt.Errorf("GetKeyspace(%v): %v", keyspace, err) + return vterrors.Wrapf(err, "GetKeyspace(%v)", keyspace) } if !reflect.DeepEqual(fromKs.Keyspace, toKs.Keyspace) { - return fmt.Errorf("Keyspace: %v does not match between from and to topology", keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Keyspace: %v does not match between from and to topology", keyspace) } fromVs, err := fromTS.GetVSchema(ctx, keyspace) @@ -56,7 +57,7 @@ func CompareKeyspaces(ctx context.Context, fromTS, toTS *topo.Server) error { case topo.IsErrType(err, topo.NoNode): // Nothing to do. default: - return fmt.Errorf("GetVSchema(%v): %v", keyspace, err) + return vterrors.Wrapf(err, "GetVSchema(%v)", keyspace) } toVs, err := toTS.GetVSchema(ctx, keyspace) @@ -66,11 +67,11 @@ func CompareKeyspaces(ctx context.Context, fromTS, toTS *topo.Server) error { case topo.IsErrType(err, topo.NoNode): // Nothing to do. default: - return fmt.Errorf("GetVSchema(%v): %v", keyspace, err) + return vterrors.Wrapf(err, "GetVSchema(%v)", keyspace) } if !reflect.DeepEqual(fromVs, toVs) { - return fmt.Errorf("Vschema for keyspace: %v does not match between from and to topology", keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Vschema for keyspace: %v does not match between from and to topology", keyspace) } } return nil @@ -80,27 +81,27 @@ func CompareKeyspaces(ctx context.Context, fromTS, toTS *topo.Server) error { func CompareShards(ctx context.Context, fromTS, toTS *topo.Server) error { keyspaces, err := fromTS.GetKeyspaces(ctx) if err != nil { - return fmt.Errorf("fromTS.GetKeyspaces: %v", err) + return vterrors.Wrapf(err, "fromTS.GetKeyspaces") } for _, keyspace := range keyspaces { shards, err := fromTS.GetShardNames(ctx, keyspace) if err != nil { - return fmt.Errorf("GetShardNames(%v): %v", keyspace, err) + return vterrors.Wrapf(err, "GetShardNames(%v)", keyspace) } for _, shard := range shards { fromSi, err := fromTS.GetShard(ctx, keyspace, shard) if err != nil { - return fmt.Errorf("GetShard(%v, %v): %v", keyspace, shard, err) + return vterrors.Wrapf(err, "GetShard(%v, %v)", keyspace, shard) } toSi, err := toTS.GetShard(ctx, keyspace, shard) if err != nil { - return fmt.Errorf("GetShard(%v, %v): %v", keyspace, shard, err) + return vterrors.Wrapf(err, "GetShard(%v, %v)", keyspace, shard) } if !reflect.DeepEqual(fromSi.Shard, toSi.Shard) { - return fmt.Errorf("Shard %v for keyspace: %v does not match between from and to topology", shard, keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Shard %v for keyspace: %v does not match between from and to topology", shard, keyspace) } } } @@ -111,27 +112,27 @@ func CompareShards(ctx context.Context, fromTS, toTS *topo.Server) error { func CompareTablets(ctx context.Context, fromTS, toTS *topo.Server) error { cells, err := fromTS.GetKnownCells(ctx) if err != nil { - return fmt.Errorf("fromTS.GetKnownCells: %v", err) + return vterrors.Wrapf(err, "fromTS.GetKnownCells") } for _, cell := range cells { tabletAliases, err := fromTS.GetTabletsByCell(ctx, cell) if err != nil { - return fmt.Errorf("GetTabletsByCell(%v): %v", cell, err) + return vterrors.Wrapf(err, "GetTabletsByCell(%v)", cell) } for _, tabletAlias := range tabletAliases { // read the source tablet fromTi, err := fromTS.GetTablet(ctx, tabletAlias) if err != nil { - return fmt.Errorf("GetTablet(%v): %v", tabletAlias, err) + return vterrors.Wrapf(err, "GetTablet(%v)", tabletAlias) } toTi, err := toTS.GetTablet(ctx, tabletAlias) if err != nil { - return fmt.Errorf("GetTablet(%v): %v", tabletAlias, err) + return vterrors.Wrapf(err, "GetTablet(%v)", tabletAlias) } if !reflect.DeepEqual(fromTi.Tablet, toTi.Tablet) { - return fmt.Errorf("Tablet %v: does not match between from and to topology", tabletAlias) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Tablet %v: does not match between from and to topology", tabletAlias) } } } @@ -143,13 +144,13 @@ func CompareTablets(ctx context.Context, fromTS, toTS *topo.Server) error { func CompareShardReplications(ctx context.Context, fromTS, toTS *topo.Server) error { keyspaces, err := fromTS.GetKeyspaces(ctx) if err != nil { - return fmt.Errorf("fromTS.GetKeyspaces: %v", err) + return vterrors.Wrapf(err, "fromTS.GetKeyspaces") } for _, keyspace := range keyspaces { shards, err := fromTS.GetShardNames(ctx, keyspace) if err != nil { - return fmt.Errorf("GetShardNames(%v): %v", keyspace, err) + return vterrors.Wrapf(err, "GetShardNames(%v)", keyspace) } for _, shard := range shards { @@ -157,20 +158,20 @@ func CompareShardReplications(ctx context.Context, fromTS, toTS *topo.Server) er // read the source shard to get the cells si, err := fromTS.GetShard(ctx, keyspace, shard) if err != nil { - return fmt.Errorf("GetShard(%v, %v): %v", keyspace, shard, err) + return vterrors.Wrapf(err, "GetShard(%v, %v)", keyspace, shard) } for _, cell := range si.Shard.Cells { fromSRi, err := fromTS.GetShardReplication(ctx, cell, keyspace, shard) if err != nil { - return fmt.Errorf("GetShardReplication(%v, %v, %v): %v", cell, keyspace, shard, err) + return vterrors.Wrapf(err, "GetShardReplication(%v, %v, %v)", cell, keyspace, shard) } toSRi, err := toTS.GetShardReplication(ctx, cell, keyspace, shard) if err != nil { - return fmt.Errorf("GetShardReplication(%v, %v, %v): %v", cell, keyspace, shard, err) + return vterrors.Wrapf(err, "GetShardReplication(%v, %v, %v)", cell, keyspace, shard) } if !reflect.DeepEqual(fromSRi.ShardReplication, toSRi.ShardReplication) { - return fmt.Errorf( + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Shard Replication in cell %v, keyspace %v, shard %v: does not match between from and to topology", cell, keyspace, diff --git a/go/vt/topo/keyspace.go b/go/vt/topo/keyspace.go index 44338ea2ae5..521753adafb 100644 --- a/go/vt/topo/keyspace.go +++ b/go/vt/topo/keyspace.go @@ -17,12 +17,13 @@ limitations under the License. package topo import ( - "fmt" "path" "sync" "github.com/golang/protobuf/proto" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/event" "vitess.io/vitess/go/vt/concurrency" @@ -63,25 +64,25 @@ func (ki *KeyspaceInfo) CheckServedFromMigration(tabletType topodatapb.TabletTyp // master is a special case with a few extra checks if tabletType == topodatapb.TabletType_MASTER { if !remove { - return fmt.Errorf("Cannot add master back to %v", ki.keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Cannot add master back to %v", ki.keyspace) } if len(cells) > 0 { - return fmt.Errorf("Cannot migrate only some cells for master removal in keyspace %v", ki.keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Cannot migrate only some cells for master removal in keyspace %v", ki.keyspace) } if len(ki.ServedFroms) > 1 { - return fmt.Errorf("Cannot migrate master into %v until everything else is migrated", ki.keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Cannot migrate master into %v until everything else is migrated", ki.keyspace) } } // we can't remove a type we don't have if ki.GetServedFrom(tabletType) == nil && remove { - return fmt.Errorf("Supplied type cannot be migrated") + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "Supplied type cannot be migrated") } // check the keyspace is consistent in any case for _, ksf := range ki.ServedFroms { if ksf.Keyspace != keyspace { - return fmt.Errorf("Inconsistent keypace specified in migration: %v != %v for type %v", keyspace, ksf.Keyspace, ksf.TabletType) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "Inconsistent keypace specified in migration: %v != %v for type %v", keyspace, ksf.Keyspace, ksf.TabletType) } } @@ -130,7 +131,7 @@ func (ki *KeyspaceInfo) UpdateServedFromMap(tabletType topodatapb.TabletType, ce } } else { if ksf.Keyspace != keyspace { - return fmt.Errorf("cannot UpdateServedFromMap on existing record for keyspace %v, different keyspace: %v != %v", ki.keyspace, ksf.Keyspace, keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot UpdateServedFromMap on existing record for keyspace %v, different keyspace: %v != %v", ki.keyspace, ksf.Keyspace, keyspace) } ksf.Cells = addCells(ksf.Cells, cells) } @@ -181,7 +182,7 @@ func (ts *Server) GetKeyspace(ctx context.Context, keyspace string) (*KeyspaceIn k := &topodatapb.Keyspace{} if err = proto.Unmarshal(data, k); err != nil { - return nil, fmt.Errorf("bad keyspace data %v", err) + return nil, vterrors.Wrap(err, "bad keyspace data") } return &KeyspaceInfo{ @@ -222,7 +223,7 @@ func (ts *Server) UpdateKeyspace(ctx context.Context, ki *KeyspaceInfo) error { func (ts *Server) FindAllShardsInKeyspace(ctx context.Context, keyspace string) (map[string]*ShardInfo, error) { shards, err := ts.GetShardNames(ctx, keyspace) if err != nil { - return nil, fmt.Errorf("failed to get list of shards for keyspace '%v': %v", keyspace, err) + return nil, vterrors.Wrapf(err, "failed to get list of shards for keyspace '%v'", keyspace) } result := make(map[string]*ShardInfo, len(shards)) @@ -238,7 +239,7 @@ func (ts *Server) FindAllShardsInKeyspace(ctx context.Context, keyspace string) if IsErrType(err, NoNode) { log.Warningf("GetShard(%v, %v) returned ErrNoNode, consider checking the topology.", keyspace, shard) } else { - rec.RecordError(fmt.Errorf("GetShard(%v, %v) failed: %v", keyspace, shard, err)) + rec.RecordError(vterrors.Wrapf(err, "GetShard(%v, %v) failed", keyspace, shard)) } return } diff --git a/go/vt/topo/locks.go b/go/vt/topo/locks.go index 7f5c11b7ed3..a52ed2ef254 100644 --- a/go/vt/topo/locks.go +++ b/go/vt/topo/locks.go @@ -19,7 +19,6 @@ package topo import ( "encoding/json" "flag" - "fmt" "os" "os/user" "path" @@ -27,6 +26,8 @@ import ( "time" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/log" @@ -87,7 +88,7 @@ func newLock(action string) *Lock { func (l *Lock) ToJSON() (string, error) { data, err := json.MarshalIndent(l, "", " ") if err != nil { - return "", fmt.Errorf("cannot JSON-marshal node: %v", err) + return "", vterrors.Wrapf(err, "cannot JSON-marshal node") } return string(data), nil } @@ -146,7 +147,7 @@ func (ts *Server) LockKeyspace(ctx context.Context, keyspace, action string) (co // check that we're not already locked if _, ok = i.info[keyspace]; ok { - return nil, nil, fmt.Errorf("lock for keyspace %v is already held", keyspace) + return nil, nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "lock for keyspace %v is already held", keyspace) } // lock @@ -169,7 +170,7 @@ func (ts *Server) LockKeyspace(ctx context.Context, keyspace, action string) (co if *finalErr != nil { log.Errorf("trying to unlock keyspace %v multiple times", keyspace) } else { - *finalErr = fmt.Errorf("trying to unlock keyspace %v multiple times", keyspace) + *finalErr = vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "trying to unlock keyspace %v multiple times", keyspace) } return } @@ -193,7 +194,7 @@ func CheckKeyspaceLocked(ctx context.Context, keyspace string) error { // extract the locksInfo pointer i, ok := ctx.Value(locksKey).(*locksInfo) if !ok { - return fmt.Errorf("keyspace %v is not locked (no locksInfo)", keyspace) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "keyspace %v is not locked (no locksInfo)", keyspace) } i.mu.Lock() defer i.mu.Unlock() @@ -201,7 +202,7 @@ func CheckKeyspaceLocked(ctx context.Context, keyspace string) error { // find the individual entry _, ok = i.info[keyspace] if !ok { - return fmt.Errorf("keyspace %v is not locked (no lockInfo in map)", keyspace) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "keyspace %v is not locked (no lockInfo in map)", keyspace) } // TODO(alainjobart): check the lock server implementation @@ -291,7 +292,7 @@ func (ts *Server) LockShard(ctx context.Context, keyspace, shard, action string) // check that we're not already locked mapKey := keyspace + "/" + shard if _, ok = i.info[mapKey]; ok { - return nil, nil, fmt.Errorf("lock for shard %v/%v is already held", keyspace, shard) + return nil, nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "lock for shard %v/%v is already held", keyspace, shard) } // lock @@ -314,7 +315,7 @@ func (ts *Server) LockShard(ctx context.Context, keyspace, shard, action string) if *finalErr != nil { log.Errorf("trying to unlock shard %v/%v multiple times", keyspace, shard) } else { - *finalErr = fmt.Errorf("trying to unlock shard %v/%v multiple times", keyspace, shard) + *finalErr = vterrors.Errorf(vtrpc.Code_INTERNAL, "trying to unlock shard %v/%v multiple times", keyspace, shard) } return } @@ -338,7 +339,7 @@ func CheckShardLocked(ctx context.Context, keyspace, shard string) error { // extract the locksInfo pointer i, ok := ctx.Value(locksKey).(*locksInfo) if !ok { - return fmt.Errorf("shard %v/%v is not locked (no locksInfo)", keyspace, shard) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "shard %v/%v is not locked (no locksInfo)", keyspace, shard) } i.mu.Lock() defer i.mu.Unlock() @@ -347,7 +348,7 @@ func CheckShardLocked(ctx context.Context, keyspace, shard string) error { mapKey := keyspace + "/" + shard li, ok := i.info[mapKey] if !ok { - return fmt.Errorf("shard %v/%v is not locked (no lockInfo in map)", keyspace, shard) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "shard %v/%v is not locked (no lockInfo in map)", keyspace, shard) } // Check the lock server implementation still holds the lock. diff --git a/go/vt/topo/memorytopo/directory.go b/go/vt/topo/memorytopo/directory.go index 89104f40a74..90640ef7302 100644 --- a/go/vt/topo/memorytopo/directory.go +++ b/go/vt/topo/memorytopo/directory.go @@ -17,9 +17,9 @@ limitations under the License. package memorytopo import ( - "fmt" - "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/topo" ) @@ -46,7 +46,7 @@ func (c *Conn) ListDir(ctx context.Context, dirPath string, full bool) ([]topo.D // Check it's a directory. if !n.isDirectory() { - return nil, fmt.Errorf("node %v in cell %v is not a directory", dirPath, c.cell) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "node %v in cell %v is not a directory", dirPath, c.cell) } result := make([]topo.DirEntry, 0, len(n.children)) diff --git a/go/vt/topo/memorytopo/file.go b/go/vt/topo/memorytopo/file.go index 1e3134689f3..d1322f8c4da 100644 --- a/go/vt/topo/memorytopo/file.go +++ b/go/vt/topo/memorytopo/file.go @@ -21,6 +21,8 @@ import ( "path" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/topo" ) @@ -42,7 +44,7 @@ func (c *Conn) Create(ctx context.Context, filePath string, contents []byte) (to dir, file := path.Split(filePath) p := c.factory.getOrCreatePath(c.cell, dir) if p == nil { - return nil, fmt.Errorf("trying to create file %v in cell %v in a path that contains files", filePath, c.cell) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "trying to create file %v in cell %v in a path that contains files", filePath, c.cell) } // Check the file doesn't already exist. @@ -79,7 +81,7 @@ func (c *Conn) Update(ctx context.Context, filePath string, contents []byte, ver } p = c.factory.getOrCreatePath(c.cell, dir) if p == nil { - return nil, fmt.Errorf("trying to create file %v in cell %v in a path that contains files", filePath, c.cell) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "trying to create file %v in cell %v in a path that contains files", filePath, c.cell) } } @@ -97,7 +99,7 @@ func (c *Conn) Update(ctx context.Context, filePath string, contents []byte, ver // Check if it's a directory. if n.isDirectory() { - return nil, fmt.Errorf("Update(%v, %v) failed: it's a directory", c.cell, filePath) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "Update(%v, %v) failed: it's a directory", c.cell, filePath) } // Check the version. diff --git a/go/vt/topo/replication.go b/go/vt/topo/replication.go index f061ccd5d1f..2ad06c9d1a9 100644 --- a/go/vt/topo/replication.go +++ b/go/vt/topo/replication.go @@ -17,11 +17,11 @@ limitations under the License. package topo import ( - "fmt" "path" "github.com/golang/protobuf/proto" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/trace" "vitess.io/vitess/go/vt/log" @@ -179,7 +179,7 @@ func (ts *Server) UpdateShardReplicationFields(ctx context.Context, cell, keyspa case err == nil: // Use any data we got. if err = proto.Unmarshal(data, sr); err != nil { - return fmt.Errorf("bad ShardReplication data %v", err) + return vterrors.Wrap(err, "bad ShardReplication data") } default: return err @@ -236,7 +236,7 @@ func (ts *Server) GetShardReplication(ctx context.Context, cell, keyspace, shard sr := &topodatapb.ShardReplication{} if err = proto.Unmarshal(data, sr); err != nil { - return nil, fmt.Errorf("bad ShardReplication data %v", err) + return nil, vterrors.Wrap(err, "bad ShardReplication data") } return NewShardReplicationInfo(sr, cell, keyspace, shard), nil diff --git a/go/vt/topo/server.go b/go/vt/topo/server.go index 6c4a07a2483..d0b3bf3c11f 100644 --- a/go/vt/topo/server.go +++ b/go/vt/topo/server.go @@ -44,10 +44,10 @@ package topo import ( "flag" - "fmt" "sync" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/log" ) @@ -258,7 +258,7 @@ func (ts *Server) ConnForCell(ctx context.Context, cell string) (Conn, error) { // Create the connection. conn, err = ts.factory.Create(cell, ci.ServerAddress, ci.Root) if err != nil { - return nil, fmt.Errorf("failed to create topo connection to %v, %v: %v", ci.ServerAddress, ci.Root, err) + return nil, vterrors.Wrapf(err, "failed to create topo connection to %v, %v", ci.ServerAddress, ci.Root) } conn = NewStatsConn(cell, conn) ts.cells[cell] = conn diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index eff52454207..94a035433ae 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -18,7 +18,6 @@ package topo import ( "encoding/hex" - "fmt" "path" "reflect" "sort" @@ -26,8 +25,10 @@ import ( "sync" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" - "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/proto" "vitess.io/vitess/go/event" "vitess.io/vitess/go/trace" @@ -104,7 +105,7 @@ func ValidateShardName(shard string) (string, *topodatapb.KeyRange, error) { parts := strings.Split(shard, "-") if len(parts) != 2 { - return "", nil, fmt.Errorf("invalid shardId, can only contain one '-': %v", shard) + return "", nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid shardId, can only contain one '-': %v", shard) } keyRange, err := key.ParseKeyRangeParts(parts[0], parts[1]) @@ -113,7 +114,7 @@ func ValidateShardName(shard string) (string, *topodatapb.KeyRange, error) { } if len(keyRange.End) > 0 && string(keyRange.Start) >= string(keyRange.End) { - return "", nil, fmt.Errorf("out of order keys: %v is not strictly smaller than %v", hex.EncodeToString(keyRange.Start), hex.EncodeToString(keyRange.End)) + return "", nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "out of order keys: %v is not strictly smaller than %v", hex.EncodeToString(keyRange.Start), hex.EncodeToString(keyRange.End)) } return strings.ToLower(shard), keyRange, nil @@ -182,7 +183,7 @@ func (ts *Server) GetShard(ctx context.Context, keyspace, shard string) (*ShardI value := &topodatapb.Shard{} if err = proto.Unmarshal(data, value); err != nil { - return nil, fmt.Errorf("GetShard(%v,%v): bad shard data: %v", keyspace, shard, err) + return nil, vterrors.Wrapf(err, "GetShard(%v,%v): bad shard data", keyspace, shard) } return &ShardInfo{ keyspace: keyspace, @@ -329,12 +330,12 @@ func (ts *Server) GetOrCreateShard(ctx context.Context, keyspace, shard string) // create the keyspace, maybe it already exists if err = ts.CreateKeyspace(ctx, keyspace, &topodatapb.Keyspace{}); err != nil && !IsErrType(err, NodeExists) { - return nil, fmt.Errorf("CreateKeyspace(%v) failed: %v", keyspace, err) + return nil, vterrors.Wrapf(err, "CreateKeyspace(%v) failed", keyspace) } // now try to create with the lock, may already exist if err = ts.CreateShard(ctx, keyspace, shard); err != nil && !IsErrType(err, NodeExists) { - return nil, fmt.Errorf("CreateShard(%v/%v) failed: %v", keyspace, shard, err) + return nil, vterrors.Wrapf(err, "CreateShard(%v/%v) failed", keyspace, shard) } // try to read the shard again, maybe someone created it @@ -405,14 +406,14 @@ func (si *ShardInfo) UpdateSourceBlacklistedTables(ctx context.Context, tabletTy // we have an existing record, check table lists matches and // DisableQueryService is not set if tc.DisableQueryService { - return fmt.Errorf("cannot safely alter BlacklistedTables as DisableQueryService is set for shard %v/%v", si.keyspace, si.shardName) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot safely alter BlacklistedTables as DisableQueryService is set for shard %v/%v", si.keyspace, si.shardName) } if remove { si.removeCellsFromTabletControl(tc, tabletType, cells) } else { if !reflect.DeepEqual(tc.BlacklistedTables, tables) { - return fmt.Errorf("trying to use two different sets of blacklisted tables for shard %v/%v: %v and %v", si.keyspace, si.shardName, tc.BlacklistedTables, tables) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "trying to use two different sets of blacklisted tables for shard %v/%v: %v and %v", si.keyspace, si.shardName, tc.BlacklistedTables, tables) } tc.Cells = addCells(tc.Cells, cells) @@ -447,18 +448,18 @@ func (si *ShardInfo) UpdateDisableQueryService(ctx context.Context, tabletType t // we have an existing record, check table list is empty and // DisableQueryService is set if len(tc.BlacklistedTables) > 0 { - return fmt.Errorf("cannot safely alter DisableQueryService as BlacklistedTables is set") + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot safely alter DisableQueryService as BlacklistedTables is set") } if !tc.DisableQueryService { // This code is unreachable because we always delete the control record when we enable QueryService. - return fmt.Errorf("cannot safely alter DisableQueryService as DisableQueryService is not set, this record should not be there for shard %v/%v", si.keyspace, si.shardName) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "cannot safely alter DisableQueryService as DisableQueryService is not set, this record should not be there for shard %v/%v", si.keyspace, si.shardName) } if disableQueryService { tc.Cells = addCells(tc.Cells, cells) } else { if tc.Frozen { - return fmt.Errorf("migrate has gone past the point of no return, cannot re-enable serving for %v/%v", si.keyspace, si.shardName) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "migrate has gone past the point of no return, cannot re-enable serving for %v/%v", si.keyspace, si.shardName) } si.removeCellsFromTabletControl(tc, tabletType, cells) } @@ -611,7 +612,7 @@ func (ts *Server) FindAllTabletAliasesInShardByCell(ctx context.Context, keyspac defer wg.Done() sri, err := ts.GetShardReplication(ctx, cell, keyspace, shard) if err != nil { - rec.RecordError(fmt.Errorf("GetShardReplication(%v, %v, %v) failed: %v", cell, keyspace, shard, err)) + rec.RecordError(vterrors.Wrapf(err, "GetShardReplication(%v, %v, %v) failed", cell, keyspace, shard)) return } diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index c5d0a6ceb31..b55c7dcb700 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -17,11 +17,11 @@ limitations under the License. package topo import ( - "fmt" "path" "github.com/golang/protobuf/proto" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -59,7 +59,7 @@ func (ts *Server) WatchSrvKeyspace(ctx context.Context, cell, keyspace string) ( cancel() for range wdChannel { } - return &WatchSrvKeyspaceData{Err: fmt.Errorf("error unpacking initial SrvKeyspace object: %v", err)}, nil, nil + return &WatchSrvKeyspaceData{Err: vterrors.Wrapf(err, "error unpacking initial SrvKeyspace object")}, nil, nil } changes := make(chan *WatchSrvKeyspaceData, 10) @@ -86,7 +86,7 @@ func (ts *Server) WatchSrvKeyspace(ctx context.Context, cell, keyspace string) ( cancel() for range wdChannel { } - changes <- &WatchSrvKeyspaceData{Err: fmt.Errorf("error unpacking SrvKeyspace object: %v", err)} + changes <- &WatchSrvKeyspaceData{Err: vterrors.Wrapf(err, "error unpacking SrvKeyspace object")} return } @@ -156,7 +156,7 @@ func (ts *Server) GetSrvKeyspace(ctx context.Context, cell, keyspace string) (*t } srvKeyspace := &topodatapb.SrvKeyspace{} if err := proto.Unmarshal(data, srvKeyspace); err != nil { - return nil, fmt.Errorf("SrvKeyspace unmarshal failed: %v %v", data, err) + return nil, vterrors.Wrapf(err, "SrvKeyspace unmarshal failed: %v", data) } return srvKeyspace, nil } diff --git a/go/vt/topo/srv_vschema.go b/go/vt/topo/srv_vschema.go index 1806cc99091..9bfb825abdd 100644 --- a/go/vt/topo/srv_vschema.go +++ b/go/vt/topo/srv_vschema.go @@ -17,10 +17,9 @@ limitations under the License. package topo import ( - "fmt" - "github.com/golang/protobuf/proto" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" vschemapb "vitess.io/vitess/go/vt/proto/vschema" ) @@ -53,7 +52,7 @@ func (ts *Server) WatchSrvVSchema(ctx context.Context, cell string) (*WatchSrvVS cancel() for range wdChannel { } - return &WatchSrvVSchemaData{Err: fmt.Errorf("error unpacking initial SrvVSchema object: %v", err)}, nil, nil + return &WatchSrvVSchemaData{Err: vterrors.Wrapf(err, "error unpacking initial SrvVSchema object")}, nil, nil } changes := make(chan *WatchSrvVSchemaData, 10) @@ -80,7 +79,7 @@ func (ts *Server) WatchSrvVSchema(ctx context.Context, cell string) (*WatchSrvVS cancel() for range wdChannel { } - changes <- &WatchSrvVSchemaData{Err: fmt.Errorf("error unpacking SrvVSchema object: %v", err)} + changes <- &WatchSrvVSchemaData{Err: vterrors.Wrapf(err, "error unpacking SrvVSchema object")} return } changes <- &WatchSrvVSchemaData{Value: value} @@ -120,7 +119,7 @@ func (ts *Server) GetSrvVSchema(ctx context.Context, cell string) (*vschemapb.Sr } srvVSchema := &vschemapb.SrvVSchema{} if err := proto.Unmarshal(data, srvVSchema); err != nil { - return nil, fmt.Errorf("SrvVSchema unmarshal failed: %v %v", data, err) + return nil, vterrors.Wrapf(err, "SrvVSchema unmarshal failed: %v", data) } return srvVSchema, nil } diff --git a/go/vt/topo/tablet.go b/go/vt/topo/tablet.go index fb542839c9f..4ca39b61d3d 100644 --- a/go/vt/topo/tablet.go +++ b/go/vt/topo/tablet.go @@ -22,6 +22,8 @@ import ( "sync" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "github.com/golang/protobuf/proto" "vitess.io/vitess/go/event" @@ -309,7 +311,7 @@ func Validate(ctx context.Context, ts *Server, tabletAlias *topodatapb.TabletAli return err } if !topoproto.TabletAliasEqual(tablet.Alias, tabletAlias) { - return fmt.Errorf("bad tablet alias data for tablet %v: %#v", topoproto.TabletAliasString(tabletAlias), tablet.Alias) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "bad tablet alias data for tablet %v: %#v", topoproto.TabletAliasString(tabletAlias), tablet.Alias) } // Validate the entry in the shard replication nodes @@ -319,7 +321,7 @@ func Validate(ctx context.Context, ts *Server, tabletAlias *topodatapb.TabletAli } if _, err = si.GetShardReplicationNode(tabletAlias); err != nil { - return fmt.Errorf("tablet %v not found in cell %v shard replication: %v", tabletAlias, tablet.Alias.Cell, err) + return vterrors.Wrapf(err, "tablet %v not found in cell %v shard replication", tabletAlias, tablet.Alias.Cell) } return nil diff --git a/go/vt/topo/topoproto/tablet.go b/go/vt/topo/topoproto/tablet.go index 4f47d0ce6e8..97dd1263c04 100644 --- a/go/vt/topo/topoproto/tablet.go +++ b/go/vt/topo/topoproto/tablet.go @@ -26,6 +26,7 @@ import ( "strings" "github.com/golang/protobuf/proto" + "vitess.io/vitess/go/vt/vterrors" topodatapb "vitess.io/vitess/go/vt/proto/topodata" ) @@ -79,7 +80,7 @@ func ParseTabletAlias(aliasStr string) (*topodatapb.TabletAlias, error) { } uid, err := ParseUID(nameParts[1]) if err != nil { - return nil, fmt.Errorf("invalid tablet uid in alias '%s': %v", aliasStr, err) + return nil, vterrors.Wrapf(err, "invalid tablet uid in alias '%s'", aliasStr) } return &topodatapb.TabletAlias{ Cell: nameParts[0], @@ -91,7 +92,7 @@ func ParseTabletAlias(aliasStr string) (*topodatapb.TabletAlias, error) { func ParseUID(value string) (uint32, error) { uid, err := strconv.ParseUint(value, 10, 32) if err != nil { - return 0, fmt.Errorf("bad tablet uid %v", err) + return 0, vterrors.Wrap(err, "bad tablet uid") } return uint32(uid), nil } diff --git a/go/vt/topo/vschema.go b/go/vt/topo/vschema.go index 1c58640befd..76799c35629 100644 --- a/go/vt/topo/vschema.go +++ b/go/vt/topo/vschema.go @@ -17,10 +17,10 @@ limitations under the License. package topo import ( - "fmt" "path" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "github.com/golang/protobuf/proto" vschemapb "vitess.io/vitess/go/vt/proto/vschema" @@ -60,7 +60,7 @@ func (ts *Server) GetVSchema(ctx context.Context, keyspace string) (*vschemapb.K var vs vschemapb.Keyspace err = proto.Unmarshal(data, &vs) if err != nil { - return nil, fmt.Errorf("bad vschema data (%v): %q", err, data) + return nil, vterrors.Wrapf(err, "bad vschema data: %q", data) } return &vs, nil } diff --git a/go/vt/topo/wildcards.go b/go/vt/topo/wildcards.go index b516f92fb71..0448e5cf1f1 100644 --- a/go/vt/topo/wildcards.go +++ b/go/vt/topo/wildcards.go @@ -17,12 +17,13 @@ limitations under the License. package topo import ( - "fmt" "path" "strings" "sync" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/fileutil" "vitess.io/vitess/go/vt/log" @@ -42,12 +43,12 @@ func (ts *Server) ResolveKeyspaceWildcard(ctx context.Context, param string) ([] keyspaces, err := ts.GetKeyspaces(ctx) if err != nil { - return nil, fmt.Errorf("failed to read keyspaces from topo: %v", err) + return nil, vterrors.Wrapf(err, "failed to read keyspaces from topo") } for _, k := range keyspaces { matched, err := path.Match(param, k) if err != nil { - return nil, fmt.Errorf("invalid pattern %v: %v", param, err) + return nil, vterrors.Wrapf(err, "invalid pattern %v", param) } if matched { result = append(result, k) @@ -73,7 +74,7 @@ type KeyspaceShard struct { func (ts *Server) ResolveShardWildcard(ctx context.Context, param string) ([]KeyspaceShard, error) { parts := strings.Split(param, "/") if len(parts) != 2 { - return nil, fmt.Errorf("invalid shard path: %v", param) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid shard path: %v", param) } result := make([]KeyspaceShard, 0, 1) @@ -99,14 +100,14 @@ func (ts *Server) ResolveShardWildcard(ctx context.Context, param string) ([]Key // that's the */* case when a keyspace has no shards continue } - return nil, fmt.Errorf("keyspace %v doesn't exist", matchedKeyspace) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "keyspace %v doesn't exist", matchedKeyspace) default: - return nil, fmt.Errorf("cannot read keyspace shards for %v: %v", matchedKeyspace, err) + return nil, vterrors.Wrapf(err, "cannot read keyspace shards for %v", matchedKeyspace) } for _, s := range shardNames { matched, err := path.Match(shard, s) if err != nil { - return nil, fmt.Errorf("Invalid pattern %v: %v", shard, err) + return nil, vterrors.Wrapf(err, "Invalid pattern %v", shard) } if matched { result = append(result, KeyspaceShard{matchedKeyspace, s}) @@ -129,7 +130,7 @@ func (ts *Server) ResolveShardWildcard(ctx context.Context, param string) ([]Key // no shard, ignore default: // other error - return nil, fmt.Errorf("Cannot read shard %v/%v: %v", matchedKeyspace, shard, err) + return nil, vterrors.Wrapf(err, "Cannot read shard %v/%v", matchedKeyspace, shard) } } else { // keyspace and shards are not wildcards, just add the value diff --git a/go/vt/topo/zk2topo/election.go b/go/vt/topo/zk2topo/election.go index b4cd2a95293..7268341300e 100644 --- a/go/vt/topo/zk2topo/election.go +++ b/go/vt/topo/zk2topo/election.go @@ -17,12 +17,12 @@ limitations under the License. package zk2topo import ( - "fmt" "path" "sort" "github.com/samuel/go-zookeeper/zk" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo" @@ -103,7 +103,7 @@ func (mp *zkMasterParticipation) WaitForMastership() (context.Context, error) { // Create the current proposal. proposal, err := mp.zs.conn.Create(ctx, zkPath+"/", mp.id, zk.FlagSequence|zk.FlagEphemeral, zk.WorldACL(PermFile)) if err != nil { - return nil, fmt.Errorf("cannot create proposal file in %v: %v", zkPath, err) + return nil, vterrors.Wrapf(err, "cannot create proposal file in %v", zkPath) } // Wait until we are it, or we are interrupted. Using a diff --git a/go/vt/topo/zk2topo/lock.go b/go/vt/topo/zk2topo/lock.go index 9f7d790ead2..2d9316ab379 100644 --- a/go/vt/topo/zk2topo/lock.go +++ b/go/vt/topo/zk2topo/lock.go @@ -17,11 +17,11 @@ limitations under the License. package zk2topo import ( - "fmt" "path" "github.com/samuel/go-zookeeper/zk" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/topo" @@ -56,7 +56,7 @@ func (zs *Server) Lock(ctx context.Context, dirPath, contents string) (topo.Lock case context.Canceled: errToReturn = topo.NewError(topo.Interrupted, nodePath) default: - errToReturn = fmt.Errorf("failed to obtain action lock: %v %v", nodePath, err) + errToReturn = vterrors.Wrapf(err, "failed to obtain action lock: %v", nodePath) } // Regardless of the reason, try to cleanup. diff --git a/go/vt/topo/zk2topo/utils.go b/go/vt/topo/zk2topo/utils.go index 21c3895473c..c6f676245ce 100644 --- a/go/vt/topo/zk2topo/utils.go +++ b/go/vt/topo/zk2topo/utils.go @@ -26,6 +26,7 @@ import ( "github.com/samuel/go-zookeeper/zk" "golang.org/x/net/context" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/fileutil" ) @@ -273,7 +274,7 @@ func DeleteRecursive(ctx context.Context, zconn *ZkConn, zkPath string, version for _, child := range children { err := DeleteRecursive(ctx, zconn, path.Join(zkPath, child), -1) if err != nil && err != zk.ErrNoNode { - return fmt.Errorf("DeleteRecursive: recursive delete failed: %v", err) + return vterrors.Wrapf(err, "DeleteRecursive: recursive delete failed") } } @@ -297,7 +298,7 @@ func obtainQueueLock(ctx context.Context, conn *ZkConn, zkPath string) error { // Get our siblings. children, _, err := conn.Children(ctx, queueNode) if err != nil { - return fmt.Errorf("obtainQueueLock: trylock failed %v", err) + return vterrors.Wrap(err, "obtainQueueLock: trylock failed %v") } sort.Strings(children) if len(children) == 0 { @@ -325,7 +326,7 @@ func obtainQueueLock(ctx context.Context, conn *ZkConn, zkPath string) error { zkPrevLock := path.Join(queueNode, prevLock) exists, _, watch, err := conn.ExistsW(ctx, zkPrevLock) if err != nil { - return fmt.Errorf("obtainQueueLock: unable to watch queued node %v %v", zkPrevLock, err) + return vterrors.Wrapf(err, "obtainQueueLock: unable to watch queued node %v", zkPrevLock) } if !exists { // The lock disappeared, try to read again. diff --git a/go/vt/topo/zk2topo/watch.go b/go/vt/topo/zk2topo/watch.go index f9f2f50747c..6d291451de1 100644 --- a/go/vt/topo/zk2topo/watch.go +++ b/go/vt/topo/zk2topo/watch.go @@ -22,6 +22,7 @@ import ( "sync" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/topo" ) @@ -72,7 +73,7 @@ func (zs *Server) Watch(ctx context.Context, filePath string) (*topo.WatchData, } if event.Err != nil { - c <- &topo.WatchData{Err: fmt.Errorf("received a non-OK event for %v: %v", zkPath, event.Err)} + c <- &topo.WatchData{Err: vterrors.Wrapf(event.Err, "received a non-OK event for %v", zkPath)} return } diff --git a/go/vt/vtctld/api_test.go b/go/vt/vtctld/api_test.go index b217500ebd7..f80159a4330 100644 --- a/go/vt/vtctld/api_test.go +++ b/go/vt/vtctld/api_test.go @@ -247,7 +247,7 @@ func TestAPI(t *testing.T) { "Name": "", "Target": { "keyspace": "ks1", "shard": "-80", "tablet_type": 2 }, "Up": true, "Serving": true, "TabletExternallyReparentedTimestamp": 0, "Stats": { "seconds_behind_master": 100 }, "LastError": null }`}, {"GET", "tablet_health/cell1", "", "can't get tablet_health: invalid tablet_health path: \"cell1\" expected path: /tablet_health//"}, - {"GET", "tablet_health/cell1/gh", "", "can't get tablet_health: incorrect uid: bad tablet uid strconv.ParseUint: parsing \"gh\": invalid syntax"}, + {"GET", "tablet_health/cell1/gh", "", "can't get tablet_health: incorrect uid"}, // Topology Info {"GET", "topology_info/?keyspace=all&cell=all", "", `{ @@ -273,43 +273,46 @@ func TestAPI(t *testing.T) { {"POST", "vtctl/", `["Panic"]`, `uncaught panic: this command panics on purpose`}, } for _, in := range table { - var resp *http.Response - var err error - - switch in.method { - case "GET": - resp, err = http.Get(server.URL + apiPrefix + in.path) - case "POST": - resp, err = http.Post(server.URL+apiPrefix+in.path, "application/json", strings.NewReader(in.body)) - default: - t.Errorf("[%v] unknown method: %v", in.path, in.method) - continue - } + t.Run(in.method+in.path, func(t *testing.T) { + var resp *http.Response + var err error - if err != nil { - t.Errorf("[%v] http error: %v", in.path, err) - continue - } + switch in.method { + case "GET": + resp, err = http.Get(server.URL + apiPrefix + in.path) + case "POST": + resp, err = http.Post(server.URL+apiPrefix+in.path, "application/json", strings.NewReader(in.body)) + default: + t.Fatalf("[%v] unknown method: %v", in.path, in.method) + return + } - body, err := ioutil.ReadAll(resp.Body) - resp.Body.Close() + if err != nil { + t.Fatalf("[%v] http error: %v", in.path, err) + return + } - if err != nil { - t.Errorf("[%v] ioutil.ReadAll(resp.Body) error: %v", in.path, err) - continue - } + body, err := ioutil.ReadAll(resp.Body) + resp.Body.Close() + + if err != nil { + t.Fatalf("[%v] ioutil.ReadAll(resp.Body) error: %v", in.path, err) + return + } + + got := compactJSON(body) + want := compactJSON([]byte(in.want)) + if want == "" { + // want is not valid JSON. Fallback to a string comparison. + want = in.want + // For unknown reasons errors have a trailing "\n\t\t". Remove it. + got = strings.TrimSpace(string(body)) + } + if !strings.HasPrefix(got, want) { + t.Fatalf("For path [%v] got\n'%v', want\n'%v'", in.path, got, want) + return + } + }) - got := compactJSON(body) - want := compactJSON([]byte(in.want)) - if want == "" { - // want is not valid JSON. Fallback to a string comparison. - want = in.want - // For unknown reasons errors have a trailing "\n\t\t". Remove it. - got = strings.TrimSpace(string(body)) - } - if got != want { - t.Errorf("[%v] got\n'%v', want\n'%v'", in.path, got, want) - continue - } } } diff --git a/go/vt/vterrors/errors_test.go b/go/vt/vterrors/errors_test.go index 138bc6ed387..772b7d90251 100644 --- a/go/vt/vterrors/errors_test.go +++ b/go/vt/vterrors/errors_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + "golang.org/x/net/context" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" ) @@ -169,7 +170,7 @@ func outer() error { func TestStackFormat(t *testing.T) { err := outer() - got := fmt.Sprintf("%+v", err) + got := fmt.Sprintf("%v", err) assertStringContains(t, got, "innerMost") assertStringContains(t, got, "middle") @@ -203,3 +204,75 @@ func TestErrorEquality(t *testing.T) { } } } + +func TestCreation(t *testing.T) { + testcases := []struct { + in, want vtrpcpb.Code + }{{ + in: vtrpcpb.Code_CANCELED, + want: vtrpcpb.Code_CANCELED, + }, { + in: vtrpcpb.Code_UNKNOWN, + want: vtrpcpb.Code_UNKNOWN, + }} + for _, tcase := range testcases { + if got := Code(New(tcase.in, "")); got != tcase.want { + t.Errorf("Code(New(%v)): %v, want %v", tcase.in, got, tcase.want) + } + if got := Code(Errorf(tcase.in, "")); got != tcase.want { + t.Errorf("Code(Errorf(%v)): %v, want %v", tcase.in, got, tcase.want) + } + } +} + +func TestCode(t *testing.T) { + testcases := []struct { + in error + want vtrpcpb.Code + }{{ + in: nil, + want: vtrpcpb.Code_OK, + }, { + in: errors.New("generic"), + want: vtrpcpb.Code_UNKNOWN, + }, { + in: New(vtrpcpb.Code_CANCELED, "generic"), + want: vtrpcpb.Code_CANCELED, + }, { + in: context.Canceled, + want: vtrpcpb.Code_CANCELED, + }, { + in: context.DeadlineExceeded, + want: vtrpcpb.Code_DEADLINE_EXCEEDED, + }} + for _, tcase := range testcases { + if got := Code(tcase.in); got != tcase.want { + t.Errorf("Code(%v): %v, want %v", tcase.in, got, tcase.want) + } + } +} + +func TestWrapping(t *testing.T) { + err1 := Errorf(vtrpcpb.Code_UNAVAILABLE, "foo") + err2 := Wrapf(err1, "bar") + err3 := Wrapf(err2, "baz") + errorWithStack := fmt.Sprintf("%v", err3) + + assertEquals(t, err3.Error(), "baz: bar: foo") + assertContains(t, errorWithStack, "foo") + assertContains(t, errorWithStack, "bar") + assertContains(t, errorWithStack, "baz") + assertContains(t, errorWithStack, "TestWrapping") +} + +func assertContains(t *testing.T, s, substring string) { + if !strings.Contains(s, substring) { + t.Fatalf("expected string that contains [%s] but got [%s]", substring, s) + } +} + +func assertEquals(t *testing.T, a, b interface{}) { + if a != b { + t.Fatalf("expected [%s] to be equal to [%s]", a, b) + } +} \ No newline at end of file diff --git a/go/vt/vterrors/stack.go b/go/vt/vterrors/stack.go index 2ba717ad3f0..2652c180e96 100644 --- a/go/vt/vterrors/stack.go +++ b/go/vt/vterrors/stack.go @@ -95,16 +95,15 @@ type StackTrace []Frame func (st StackTrace) Format(s fmt.State, verb rune) { switch verb { case 'v': - switch { - case s.Flag('+'): + + if s.Flag('#') { + fmt.Fprintf(s, "%#v", []Frame(st)) + } else { for _, f := range st { - fmt.Fprintf(s, "\n%+v", f) + fmt.Fprintf(s, "\n%v", f) } - case s.Flag('#'): - fmt.Fprintf(s, "%#v", []Frame(st)) - default: - fmt.Fprintf(s, "%v", []Frame(st)) } + case 's': fmt.Fprintf(s, "%s", []Frame(st)) } @@ -116,12 +115,9 @@ type stack []uintptr func (s *stack) Format(st fmt.State, verb rune) { switch verb { case 'v': - switch { - case st.Flag('+'): - for _, pc := range *s { - f := Frame(pc) - fmt.Fprintf(st, "\n%+v", f) - } + for _, pc := range *s { + f := Frame(pc) + fmt.Fprintf(st, "\n%+v", f) } } } diff --git a/go/vt/vterrors/vterrors.go b/go/vt/vterrors/vterrors.go index 6e85542cb10..6f8b7ad4b8d 100644 --- a/go/vt/vterrors/vterrors.go +++ b/go/vt/vterrors/vterrors.go @@ -1,9 +1,10 @@ // Package vterrors provides simple error handling primitives for Vitess // // In all Vitess code, errors should be propagated using vterrors.Wrapf() -// and not fmt.Errorf(). +// and not fmt.Errorf(). This makes sure that stacktraces are kept and +// propagated correctly. // -// New errors should be created using vterrors.New +// New errors should be created using vterrors.New or vterrors.Errorf // // Vitess uses canonical error codes for error reporting. This is based // on years of industry experience with error reporting. This idea is @@ -27,9 +28,10 @@ // Retrieving the cause of an error // // Using vterrors.Wrap constructs a stack of errors, adding context to the -// preceding error. Depending on the nature of the error it may be necessary -// to reverse the operation of errors.Wrap to retrieve the original error -// for inspection. Any error value which implements this interface +// preceding error, instead of simply building up a string. +// Depending on the nature of the error it may be necessary to reverse the +// operation of errors.Wrap to retrieve the original error for inspection. +// Any error value which implements this interface // // type causer interface { // Cause() error @@ -60,8 +62,7 @@ // // %s print the error. If the error has a Cause it will be // printed recursively -// %v see %s -// %+v extended format. Each Frame of the error's StackTrace will +// %v extended format. Each Frame of the error's StackTrace will // be printed in detail. // // Most but not all of the code in this file was originally copied from @@ -70,8 +71,9 @@ package vterrors import ( "fmt" - "golang.org/x/net/context" "io" + + "golang.org/x/net/context" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" ) @@ -118,17 +120,14 @@ func (f *fundamental) Error() string { return f.msg } func (f *fundamental) Format(s fmt.State, verb rune) { switch verb { case 'v': - if s.Flag('+') { - io.WriteString(s, "Code: "+f.code.String()+"\n") - io.WriteString(s, f.msg+"\n") - f.stack.Format(s, verb) - return - } - fallthrough + panicIfError(io.WriteString(s, "Code: "+f.code.String()+"\n")) + panicIfError(io.WriteString(s, f.msg+"\n")) + f.stack.Format(s, verb) + return case 's': - io.WriteString(s, f.msg) + panicIfError(io.WriteString(s, f.msg)) case 'q': - fmt.Fprintf(s, "%q", f.msg) + panicIfError(fmt.Fprintf(s, "%q", f.msg)) } } @@ -196,17 +195,24 @@ func (w *wrapping) Error() string { return w.msg + ": " + w.cause.Error() } func (w *wrapping) Cause() error { return w.cause } func (w *wrapping) Format(s fmt.State, verb rune) { - switch verb { - case 'v': - if s.Flag('+') { - fmt.Fprintf(s, "%+v\n", w.Cause()) - io.WriteString(s, w.msg) - w.stack.Format(s, verb) - return - } - fallthrough - case 's', 'q': - io.WriteString(s, w.Error()) + if rune('v') == verb { + panicIfError(fmt.Fprintf(s, "%v\n", w.Cause())) + panicIfError(io.WriteString(s, w.msg)) + w.stack.Format(s, verb) + return + } + + if rune('s') == verb || rune('q') == verb { + panicIfError(io.WriteString(s, w.Error())) + } + + return +} + +// since we can't return an error, let's panic if something goes wrong here +func panicIfError(_ int, err error) { + if err != nil { + panic(err) } } diff --git a/go/vt/vterrors/vterrors_test.go b/go/vt/vterrors/vterrors_test.go deleted file mode 100644 index 2a60a03837c..00000000000 --- a/go/vt/vterrors/vterrors_test.go +++ /dev/null @@ -1,73 +0,0 @@ -/* -Copyright 2017 Google Inc. - -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 agreedto 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 vterrors - -import ( - "errors" - "testing" - - "golang.org/x/net/context" - - vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" -) - -func TestCreation(t *testing.T) { - testcases := []struct { - in, want vtrpcpb.Code - }{{ - in: vtrpcpb.Code_CANCELED, - want: vtrpcpb.Code_CANCELED, - }, { - in: vtrpcpb.Code_UNKNOWN, - want: vtrpcpb.Code_UNKNOWN, - }} - for _, tcase := range testcases { - if got := Code(New(tcase.in, "")); got != tcase.want { - t.Errorf("Code(New(%v)): %v, want %v", tcase.in, got, tcase.want) - } - if got := Code(Errorf(tcase.in, "")); got != tcase.want { - t.Errorf("Code(Errorf(%v)): %v, want %v", tcase.in, got, tcase.want) - } - } -} - -func TestCode(t *testing.T) { - testcases := []struct { - in error - want vtrpcpb.Code - }{{ - in: nil, - want: vtrpcpb.Code_OK, - }, { - in: errors.New("generic"), - want: vtrpcpb.Code_UNKNOWN, - }, { - in: New(vtrpcpb.Code_CANCELED, "generic"), - want: vtrpcpb.Code_CANCELED, - }, { - in: context.Canceled, - want: vtrpcpb.Code_CANCELED, - }, { - in: context.DeadlineExceeded, - want: vtrpcpb.Code_DEADLINE_EXCEEDED, - }} - for _, tcase := range testcases { - if got := Code(tcase.in); got != tcase.want { - t.Errorf("Code(%v): %v, want %v", tcase.in, got, tcase.want) - } - } -} diff --git a/go/vt/vtexplain/vtexplain_flaky_test.go b/go/vt/vtexplain/vtexplain_flaky_test.go index 370f59fcccd..f0948dc717f 100644 --- a/go/vt/vtexplain/vtexplain_flaky_test.go +++ b/go/vt/vtexplain/vtexplain_flaky_test.go @@ -181,15 +181,17 @@ func TestErrors(t *testing.T) { { SQL: "SELECT * FROM table_not_in_schema", - Err: "vtexplain execute error in 'SELECT * FROM table_not_in_schema': target: ks_unsharded.-.master, used tablet: explainCell-0 (ks_unsharded/-), table table_not_in_schema not found in schema", + Err: "target: ks_unsharded.-.master, used tablet: explainCell-0 (ks_unsharded/-): table table_not_in_schema not found in schema", }, } for _, test := range tests { - _, err := Run(test.SQL) - if err == nil || err.Error() != test.Err { - t.Errorf("Run(%s): %v, want %s", test.SQL, err, test.Err) - } + t.Run(test.SQL, func(t *testing.T) { + _, err := Run(test.SQL) + if err == nil || !strings.Contains(err.Error(), test.Err) { + t.Errorf(">> Query: %s\n>> Got: %v\nWant: %s", test.SQL, err, test.Err) + } + }) } } diff --git a/go/vt/vtexplain/vtexplain_vtgate.go b/go/vt/vtexplain/vtexplain_vtgate.go index 4ea5b73abd8..56d1d41db82 100644 --- a/go/vt/vtexplain/vtexplain_vtgate.go +++ b/go/vt/vtexplain/vtexplain_vtgate.go @@ -23,6 +23,7 @@ import ( "fmt" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/json2" "vitess.io/vitess/go/vt/discovery" @@ -137,7 +138,7 @@ func vtgateExecute(sql string) ([]*engine.Plan, map[string]*TabletActions, error } planCache.Clear() - return nil, nil, fmt.Errorf("vtexplain execute error in '%s': %v", sql, err) + return nil, nil, vterrors.Wrapf(err, "vtexplain execute error in '%s'", sql) } var plans []*engine.Plan diff --git a/go/vt/vtgate/buffer/buffer_test.go b/go/vt/vtgate/buffer/buffer_test.go index 1edd007f7d1..5951ebb658f 100644 --- a/go/vt/vtgate/buffer/buffer_test.go +++ b/go/vt/vtgate/buffer/buffer_test.go @@ -687,7 +687,7 @@ func isCanceledError(err error) error { if got, want := vterrors.Code(err), vtrpcpb.Code_UNAVAILABLE; got != want { return fmt.Errorf("wrong error code for canceled buffered request. got = %v, want = %v", got, want) } - if got, want := err.Error(), "context was canceled before failover finished: context canceled"; got != want { + if got, want := err.Error(), "context was canceled before failover finished"; !strings.Contains(got, want) { return fmt.Errorf("canceled buffered request should return a different error message. got = %v, want = %v", got, want) } return nil diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index 997757330df..dec9546097c 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -19,9 +19,11 @@ package vtgate import ( "fmt" "reflect" + "strings" "testing" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/discovery" @@ -806,10 +808,13 @@ func TestSelectScatterPartial(t *testing.T) { // Fail 1 of N without the directive fails the whole operation conns[2].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000 results, err := executorExec(executor, "select id from user", nil) - wantErr := "target: TestExecutor.40-60.master, used tablet: aa-0 (40-60), RESOURCE_EXHAUSTED error" - if err == nil || err.Error() != wantErr { + wantErr := "TestExecutor.40-60.master, used tablet: aa-0 (40-60)" + if err == nil || !strings.Contains(err.Error(), wantErr) { t.Errorf("want error %v, got %v", wantErr, err) } + if vterrors.Code(err) != vtrpcpb.Code_RESOURCE_EXHAUSTED { + t.Errorf("want error code Code_RESOURCE_EXHAUSTED, but got %v", vterrors.Code(err)) + } if results != nil { t.Errorf("want nil results, got %v", results) } diff --git a/go/vt/vtgate/gateway/discoverygateway.go b/go/vt/vtgate/gateway/discoverygateway.go index 26731f72e69..cf1a10e18bb 100644 --- a/go/vt/vtgate/gateway/discoverygateway.go +++ b/go/vt/vtgate/gateway/discoverygateway.go @@ -327,7 +327,7 @@ func (dg *discoveryGateway) withRetry(ctx context.Context, target *querypb.Targe } break } - return NewShardError(err, target, tabletLastUsed, inTransaction) + return NewShardError(err, target, tabletLastUsed) } func shuffleTablets(cell string, tablets []discovery.TabletStats) { diff --git a/go/vt/vtgate/gateway/discoverygateway_test.go b/go/vt/vtgate/gateway/discoverygateway_test.go index f3e06462a63..35127cc4435 100644 --- a/go/vt/vtgate/gateway/discoverygateway_test.go +++ b/go/vt/vtgate/gateway/discoverygateway_test.go @@ -18,6 +18,7 @@ package gateway import ( "fmt" + "strings" "testing" "golang.org/x/net/context" @@ -34,23 +35,23 @@ import ( ) func TestDiscoveryGatewayExecute(t *testing.T) { - testDiscoveryGatewayGeneric(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayGeneric(t, func(dg Gateway, target *querypb.Target) error { _, err := dg.Execute(context.Background(), target, "query", nil, 0, nil) return err }) - testDiscoveryGatewayTransact(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayTransact(t, func(dg Gateway, target *querypb.Target) error { _, err := dg.Execute(context.Background(), target, "query", nil, 1, nil) return err }) } func TestDiscoveryGatewayExecuteBatch(t *testing.T) { - testDiscoveryGatewayGeneric(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayGeneric(t, func(dg Gateway, target *querypb.Target) error { queries := []*querypb.BoundQuery{{Sql: "query", BindVariables: nil}} _, err := dg.ExecuteBatch(context.Background(), target, queries, false, 0, nil) return err }) - testDiscoveryGatewayTransact(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayTransact(t, func(dg Gateway, target *querypb.Target) error { queries := []*querypb.BoundQuery{{Sql: "query", BindVariables: nil}} _, err := dg.ExecuteBatch(context.Background(), target, queries, false, 1, nil) return err @@ -58,7 +59,7 @@ func TestDiscoveryGatewayExecuteBatch(t *testing.T) { } func TestDiscoveryGatewayExecuteStream(t *testing.T) { - testDiscoveryGatewayGeneric(t, true, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayGeneric(t, func(dg Gateway, target *querypb.Target) error { err := dg.StreamExecute(context.Background(), target, "query", nil, 0, nil, func(qr *sqltypes.Result) error { return nil }) @@ -67,33 +68,33 @@ func TestDiscoveryGatewayExecuteStream(t *testing.T) { } func TestDiscoveryGatewayBegin(t *testing.T) { - testDiscoveryGatewayGeneric(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayGeneric(t, func(dg Gateway, target *querypb.Target) error { _, err := dg.Begin(context.Background(), target, nil) return err }) } func TestDiscoveryGatewayCommit(t *testing.T) { - testDiscoveryGatewayTransact(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayTransact(t, func(dg Gateway, target *querypb.Target) error { return dg.Commit(context.Background(), target, 1) }) } func TestDiscoveryGatewayRollback(t *testing.T) { - testDiscoveryGatewayTransact(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayTransact(t, func(dg Gateway, target *querypb.Target) error { return dg.Rollback(context.Background(), target, 1) }) } func TestDiscoveryGatewayBeginExecute(t *testing.T) { - testDiscoveryGatewayGeneric(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayGeneric(t, func(dg Gateway, target *querypb.Target) error { _, _, err := dg.BeginExecute(context.Background(), target, "query", nil, nil) return err }) } func TestDiscoveryGatewayBeginExecuteBatch(t *testing.T) { - testDiscoveryGatewayGeneric(t, false, func(dg Gateway, target *querypb.Target) error { + testDiscoveryGatewayGeneric(t, func(dg Gateway, target *querypb.Target) error { queries := []*querypb.BoundQuery{{Sql: "query", BindVariables: nil}} _, _, err := dg.BeginExecuteBatch(context.Background(), target, queries, false, nil) return err @@ -375,7 +376,7 @@ func benchmarkCellsGetAggregateStats(i int, b *testing.B) { } } -func testDiscoveryGatewayGeneric(t *testing.T, streaming bool, f func(dg Gateway, target *querypb.Target) error) { +func testDiscoveryGatewayGeneric(t *testing.T, f func(dg Gateway, target *querypb.Target) error) { keyspace := "ks" shard := "0" tabletType := topodatapb.TabletType_REPLICA @@ -390,25 +391,23 @@ func testDiscoveryGatewayGeneric(t *testing.T, streaming bool, f func(dg Gateway // no tablet hc.Reset() dg.tsc.ResetForTesting() - want := "target: ks.0.replica, no valid tablet" + want := []string{"target: ks.0.replica", "no valid tablet"} err := f(dg, target) - verifyShardError(t, err, want, vtrpcpb.Code_UNAVAILABLE) + verifyShardErrors(t, err, want, vtrpcpb.Code_UNAVAILABLE) // tablet with error hc.Reset() dg.tsc.ResetForTesting() hc.AddTestTablet("cell", "1.1.1.1", 1001, keyspace, shard, tabletType, false, 10, fmt.Errorf("no connection")) - want = "target: ks.0.replica, no valid tablet" err = f(dg, target) - verifyShardError(t, err, want, vtrpcpb.Code_UNAVAILABLE) + verifyShardErrors(t, err, want, vtrpcpb.Code_UNAVAILABLE) // tablet without connection hc.Reset() dg.tsc.ResetForTesting() ep1 := hc.AddTestTablet("cell", "1.1.1.1", 1001, keyspace, shard, tabletType, false, 10, nil).Tablet() - want = fmt.Sprintf(`target: ks.0.replica, no valid tablet`) err = f(dg, target) - verifyShardError(t, err, want, vtrpcpb.Code_UNAVAILABLE) + verifyShardErrors(t, err, want, vtrpcpb.Code_UNAVAILABLE) // retry error hc.Reset() @@ -419,14 +418,12 @@ func testDiscoveryGatewayGeneric(t *testing.T, streaming bool, f func(dg Gateway sc2.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 ep1 = sc1.Tablet() ep2 := sc2.Tablet() - wants := map[string]int{ - fmt.Sprintf(`target: ks.0.replica, used tablet: %s, FAILED_PRECONDITION error`, topotools.TabletIdent(ep1)): 0, - fmt.Sprintf(`target: ks.0.replica, used tablet: %s, FAILED_PRECONDITION error`, topotools.TabletIdent(ep2)): 0, - } + err = f(dg, target) - if _, ok := wants[fmt.Sprintf("%v", err)]; !ok { - t.Errorf("wanted error: %+v, got error: %v", wants, err) - } + verifyContainsError(t, err, "target: ks.0.replica", vtrpcpb.Code_FAILED_PRECONDITION) + verifyShardErrorEither(t, err, + fmt.Sprintf(`used tablet: %s`, topotools.TabletIdent(ep1)), + fmt.Sprintf(`used tablet: %s`, topotools.TabletIdent(ep2))) // fatal error hc.Reset() @@ -437,14 +434,11 @@ func testDiscoveryGatewayGeneric(t *testing.T, streaming bool, f func(dg Gateway sc2.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 ep1 = sc1.Tablet() ep2 = sc2.Tablet() - wants = map[string]int{ - fmt.Sprintf(`target: ks.0.replica, used tablet: %s, FAILED_PRECONDITION error`, topotools.TabletIdent(ep1)): 0, - fmt.Sprintf(`target: ks.0.replica, used tablet: %s, FAILED_PRECONDITION error`, topotools.TabletIdent(ep2)): 0, - } err = f(dg, target) - if _, ok := wants[fmt.Sprintf("%v", err)]; !ok { - t.Errorf("wanted error: %+v, got error: %v", wants, err) - } + verifyContainsError(t, err, "target: ks.0.replica", vtrpcpb.Code_FAILED_PRECONDITION) + verifyShardErrorEither(t, err, + fmt.Sprintf(`used tablet: %s`, topotools.TabletIdent(ep1)), + fmt.Sprintf(`used tablet: %s`, topotools.TabletIdent(ep2))) // server error - no retry hc.Reset() @@ -452,9 +446,8 @@ func testDiscoveryGatewayGeneric(t *testing.T, streaming bool, f func(dg Gateway sc1 = hc.AddTestTablet("cell", "1.1.1.1", 1001, keyspace, shard, tabletType, true, 10, nil) sc1.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 ep1 = sc1.Tablet() - want = fmt.Sprintf(`target: ks.0.replica, used tablet: %s, INVALID_ARGUMENT error`, topotools.TabletIdent(ep1)) err = f(dg, target) - verifyShardError(t, err, want, vtrpcpb.Code_INVALID_ARGUMENT) + verifyContainsError(t, err, fmt.Sprintf(`used tablet: %s`, topotools.TabletIdent(ep1)), vtrpcpb.Code_INVALID_ARGUMENT) // no failure hc.Reset() @@ -466,7 +459,7 @@ func testDiscoveryGatewayGeneric(t *testing.T, streaming bool, f func(dg Gateway } } -func testDiscoveryGatewayTransact(t *testing.T, streaming bool, f func(dg Gateway, target *querypb.Target) error) { +func testDiscoveryGatewayTransact(t *testing.T, f func(dg Gateway, target *querypb.Target) error) { keyspace := "ks" shard := "0" tabletType := topodatapb.TabletType_REPLICA @@ -487,14 +480,13 @@ func testDiscoveryGatewayTransact(t *testing.T, streaming bool, f func(dg Gatewa sc2.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 ep1 := sc1.Tablet() ep2 := sc2.Tablet() - wants := map[string]int{ - fmt.Sprintf(`target: ks.0.replica, used tablet: %s, FAILED_PRECONDITION error`, topotools.TabletIdent(ep1)): 0, - fmt.Sprintf(`target: ks.0.replica, used tablet: %s, FAILED_PRECONDITION error`, topotools.TabletIdent(ep2)): 0, - } + err := f(dg, target) - if _, ok := wants[fmt.Sprintf("%v", err)]; !ok { - t.Errorf("wanted error: %+v, got error: %v", wants, err) - } + verifyContainsError(t, err, "target: ks.0.replica", vtrpcpb.Code_FAILED_PRECONDITION) + format := `used tablet: %s` + verifyShardErrorEither(t, err, + fmt.Sprintf(format, topotools.TabletIdent(ep1)), + fmt.Sprintf(format, topotools.TabletIdent(ep2)), ) // server error - no retry hc.Reset() @@ -502,16 +494,35 @@ func testDiscoveryGatewayTransact(t *testing.T, streaming bool, f func(dg Gatewa sc1 = hc.AddTestTablet("cell", "1.1.1.1", 1001, keyspace, shard, tabletType, true, 10, nil) sc1.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 ep1 = sc1.Tablet() - want := fmt.Sprintf(`target: ks.0.replica, used tablet: %s, INVALID_ARGUMENT error`, topotools.TabletIdent(ep1)) err = f(dg, target) - verifyShardError(t, err, want, vtrpcpb.Code_INVALID_ARGUMENT) + verifyContainsError(t, err, "target: ks.0.replica", vtrpcpb.Code_INVALID_ARGUMENT) + verifyContainsError(t, err, fmt.Sprintf(format, topotools.TabletIdent(ep1)), vtrpcpb.Code_INVALID_ARGUMENT) +} + +func verifyContainsError(t *testing.T, err error, wantErr string, wantCode vtrpcpb.Code) { + if err == nil || !strings.Contains(err.Error(), wantErr) { + t.Fatalf("wanted error: \n%s\n, got error: \n%v\n", wantErr, err) + } + if code := vterrors.Code(err); code != wantCode { + t.Fatalf("wanted error code: %s, got: %v", wantCode, code) + } } -func verifyShardError(t *testing.T, err error, wantErr string, wantCode vtrpcpb.Code) { - if err == nil || err.Error() != wantErr { - t.Errorf("wanted error: %s, got error: %v", wantErr, err) +func verifyShardErrorEither(t *testing.T, err error, a, b string) { + if err == nil || !strings.Contains(err.Error(), a) || !strings.Contains(err.Error(), b) { + t.Fatalf("wanted error to contain: %v or %v\n, got error: %v", a, b, err) + } +} + +func verifyShardErrors(t *testing.T, err error, wantErrors []string, wantCode vtrpcpb.Code) { + if err != nil { + for _, wantErr := range wantErrors { + if err == nil || !strings.Contains(err.Error(), wantErr) { + t.Fatalf("wanted error: \n%s\n, got error: \n%v\n", wantErr, err) + } + } } if code := vterrors.Code(err); code != wantCode { - t.Errorf("wanted error code: %s, got: %v", wantCode, code) + t.Fatalf("wanted error code: %s, got: %v", wantCode, code) } } diff --git a/go/vt/vtgate/gateway/shard_error.go b/go/vt/vtgate/gateway/shard_error.go index 09d01e1cba0..27fb0bc752e 100644 --- a/go/vt/vtgate/gateway/shard_error.go +++ b/go/vt/vtgate/gateway/shard_error.go @@ -26,15 +26,15 @@ import ( ) // NewShardError returns a new error with the shard info amended. -func NewShardError(in error, target *querypb.Target, tablet *topodatapb.Tablet, inTransaction bool) error { +func NewShardError(in error, target *querypb.Target, tablet *topodatapb.Tablet) error { if in == nil { return nil } if tablet != nil { - return vterrors.Errorf(vterrors.Code(in), "target: %s.%s.%s, used tablet: %s, %v", target.Keyspace, target.Shard, topoproto.TabletTypeLString(target.TabletType), topotools.TabletIdent(tablet), in) + return vterrors.Wrapf(in, "target: %s.%s.%s, used tablet: %s", target.Keyspace, target.Shard, topoproto.TabletTypeLString(target.TabletType), topotools.TabletIdent(tablet)) } if target != nil { - return vterrors.Errorf(vterrors.Code(in), "target: %s.%s.%s, %v", target.Keyspace, target.Shard, topoproto.TabletTypeLString(target.TabletType), in) + return vterrors.Wrapf(in, "target: %s.%s.%s", target.Keyspace, target.Shard, topoproto.TabletTypeLString(target.TabletType)) } - return vterrors.Errorf(vterrors.Code(in), "%v", in) + return in } diff --git a/go/vt/vtgate/planbuilder/insert.go b/go/vt/vtgate/planbuilder/insert.go index 2e3624bd884..7bacfac0aee 100644 --- a/go/vt/vtgate/planbuilder/insert.go +++ b/go/vt/vtgate/planbuilder/insert.go @@ -23,6 +23,7 @@ import ( "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/sqlparser" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vtgate/engine" "vitess.io/vitess/go/vt/vtgate/vindexes" ) @@ -158,7 +159,7 @@ func buildInsertShardedPlan(ins *sqlparser.Insert, table *vindexes.Table) (*engi for rowNum, row := range rows { innerpv, err := sqlparser.NewPlanValue(row[colNum]) if err != nil { - return nil, fmt.Errorf("could not compute value for vindex or auto-inc column: %v", err) + return nil, vterrors.Wrapf(err, "could not compute value for vindex or auto-inc column") } routeValues[vIdx].Values[colIdx].Values[rowNum] = innerpv row[colNum] = sqlparser.NewValArg([]byte(baseName + strconv.Itoa(rowNum))) diff --git a/go/vt/vtgate/planbuilder/plan_test.go b/go/vt/vtgate/planbuilder/plan_test.go index 16327421d7f..31f1228f900 100644 --- a/go/vt/vtgate/planbuilder/plan_test.go +++ b/go/vt/vtgate/planbuilder/plan_test.go @@ -221,30 +221,32 @@ type testPlan struct { func testFile(t *testing.T, filename string, vschema *vindexes.VSchema) { for tcase := range iterateExecFile(filename) { - plan, err := Build(tcase.input, &vschemaWrapper{ - v: vschema, - }) - var out string - if err != nil { - out = err.Error() - } else { - bout, _ := json.Marshal(testPlan{ - Original: plan.Original, - Instructions: plan.Instructions, + t.Run(tcase.comments, func(t *testing.T) { + plan, err := Build(tcase.input, &vschemaWrapper{ + v: vschema, }) - out = string(bout) - } - if out != tcase.output { - t.Errorf("File: %s, Line:%v\n got:\n%s, \nwant:\n%s", filename, tcase.lineno, out, tcase.output) - // Uncomment these lines to re-generate input files + var out string if err != nil { - out = fmt.Sprintf("\"%s\"", out) + out = err.Error() } else { - bout, _ := json.MarshalIndent(plan, "", " ") + bout, _ := json.Marshal(testPlan{ + Original: plan.Original, + Instructions: plan.Instructions, + }) out = string(bout) } - fmt.Printf("%s\"%s\"\n%s\n\n", tcase.comments, tcase.input, out) - } + if out != tcase.output { + t.Errorf("File: %s, Line:%v\n got:\n%s, \nwant:\n%s", filename, tcase.lineno, out, tcase.output) + // Uncomment these lines to re-generate input files + if err != nil { + out = fmt.Sprintf("\"%s\"", out) + } else { + bout, _ := json.MarshalIndent(plan, "", " ") + out = string(bout) + } + fmt.Printf("%s\"%s\"\n%s\n\n", tcase.comments, tcase.input, out) + } + }) } } diff --git a/go/vt/vtgate/resolver_test.go b/go/vt/vtgate/resolver_test.go index 6638e2b9db6..687b07751cf 100644 --- a/go/vt/vtgate/resolver_test.go +++ b/go/vt/vtgate/resolver_test.go @@ -194,222 +194,243 @@ func TestResolverStreamExecuteKeyRanges(t *testing.T) { } func testResolverGeneric(t *testing.T, name string, action func(res *Resolver) (*sqltypes.Result, error)) { - // successful execute - s := createSandbox(name) - hc := discovery.NewFakeHealthCheck() - res := newTestResolver(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + t.Run("successful execute", func(t *testing.T) { + createSandbox(name) + hc := discovery.NewFakeHealthCheck() + res := newTestResolver(hc, new(sandboxTopo), "aa") + sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + + _, err := action(res) + if err != nil { + t.Errorf("want nil, got %v", err) + } + if execCount := sbc0.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + if execCount := sbc1.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + }) - _, err := action(res) - if err != nil { - t.Errorf("want nil, got %v", err) - } - if execCount := sbc0.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - if execCount := sbc1.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } + t.Run("non-retryable failure", func(t *testing.T) { + s := createSandbox(name) + hc := discovery.NewFakeHealthCheck() + res := newTestResolver(hc, new(sandboxTopo), "aa") + sbc0 := hc.AddTestTablet("aa", "-20", 1, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + sbc1 := hc.AddTestTablet("aa", "20-40", 1, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + sbc0.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 + sbc1.MustFailCodes[vtrpcpb.Code_INTERNAL] = 1 + _, err := action(res) + want := []string{ + fmt.Sprintf("target: %s.-20.master, used tablet: aa-0 (-20): INVALID_ARGUMENT error", name), + fmt.Sprintf("target: %s.20-40.master, used tablet: aa-0 (20-40): INTERNAL error", name), + } + if err == nil { + t.Errorf("want\n%v\ngot\n%v", want, err) + } else { + got := strings.Split(err.Error(), "\n") + sort.Strings(got) + if !reflect.DeepEqual(want, got) { + t.Errorf("want\n%v\ngot\n%v", want, got) + } + } + // Ensure that we tried only once + if execCount := sbc0.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + if execCount := sbc1.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + // Ensure that we tried topo only once when mapping KeyspaceId/KeyRange to shards + if s.SrvKeyspaceCounter != 1 { + t.Errorf("want 1, got %v", s.SrvKeyspaceCounter) + } - // non-retryable failure - s.Reset() - hc.Reset() - sbc0 = hc.AddTestTablet("aa", "-20", 1, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 = hc.AddTestTablet("aa", "20-40", 1, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) - sbc0.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 - sbc1.MustFailCodes[vtrpcpb.Code_INTERNAL] = 1 - _, err = action(res) - want := []string{ - fmt.Sprintf("target: %s.-20.master, used tablet: aa-0 (-20), INVALID_ARGUMENT error", name), - fmt.Sprintf("target: %s.20-40.master, used tablet: aa-0 (20-40), INTERNAL error", name), - } - if err == nil { - t.Errorf("want\n%v\ngot\n%v", want, err) - } else { - got := strings.Split(err.Error(), "\n") - sort.Strings(got) - if !reflect.DeepEqual(want, got) { - t.Errorf("want\n%v\ngot\n%v", want, got) + }) + + t.Run("retryable failure, no sharding event", func(t *testing.T) { + s := createSandbox(name) + hc := discovery.NewFakeHealthCheck() + res := newTestResolver(hc, new(sandboxTopo), "aa") + sbc0 := hc.AddTestTablet("aa", "-20", 1, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + sbc1 := hc.AddTestTablet("aa", "20-40", 1, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + sbc0.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 + sbc1.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 + _, err := action(res) + want := []string{ + fmt.Sprintf("target: %s.-20.master, used tablet: aa-0 (-20): FAILED_PRECONDITION error", name), + fmt.Sprintf("target: %s.20-40.master, used tablet: aa-0 (20-40): FAILED_PRECONDITION error", name), } - } - // Ensure that we tried only once - if execCount := sbc0.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - if execCount := sbc1.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - // Ensure that we tried topo only once when mapping KeyspaceId/KeyRange to shards - if s.SrvKeyspaceCounter != 1 { - t.Errorf("want 1, got %v", s.SrvKeyspaceCounter) - } + if err == nil { + t.Errorf("want\n%v\ngot\n%v", want, err) + } else { + got := strings.Split(err.Error(), "\n") + sort.Strings(got) + if !reflect.DeepEqual(want, got) { + t.Errorf("want\n%v\ngot\n%v", want, got) + } + } + // Ensure that we tried only once. + if execCount := sbc0.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + if execCount := sbc1.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + // Ensure that we tried topo only twice. + if s.SrvKeyspaceCounter != 2 { + t.Errorf("want 2, got %v", s.SrvKeyspaceCounter) + } + }) - // retryable failure, no sharding event - s.Reset() - hc.Reset() - sbc0 = hc.AddTestTablet("aa", "-20", 1, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 = hc.AddTestTablet("aa", "20-40", 1, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) - sbc0.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 - sbc1.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 - _, err = action(res) - want = []string{ - fmt.Sprintf("target: %s.-20.master, used tablet: aa-0 (-20), FAILED_PRECONDITION error", name), - fmt.Sprintf("target: %s.20-40.master, used tablet: aa-0 (20-40), FAILED_PRECONDITION error", name), - } - if err == nil { - t.Errorf("want\n%v\ngot\n%v", want, err) - } else { - got := strings.Split(err.Error(), "\n") - sort.Strings(got) - if !reflect.DeepEqual(want, got) { - t.Errorf("want\n%v\ngot\n%v", want, got) + t.Run("no failure, initial vertical resharding", func(t *testing.T) { + s := createSandbox(name) + hc := discovery.NewFakeHealthCheck() + res := newTestResolver(hc, new(sandboxTopo), "aa") + addSandboxServedFrom(name, name+"ServedFrom0") + sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + s0 := createSandbox(name + "ServedFrom0") // make sure we have a fresh copy + s0.ShardSpec = "-80-" + sbc2 := hc.AddTestTablet("aa", "1.1.1.1", 1003, name+"ServedFrom0", "-80", topodatapb.TabletType_MASTER, true, 1, nil) + _, err := action(res) + if err != nil { + t.Errorf("want nil, got %v", err) } - } - // Ensure that we tried only once. - if execCount := sbc0.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - if execCount := sbc1.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - // Ensure that we tried topo only twice. - if s.SrvKeyspaceCounter != 2 { - t.Errorf("want 2, got %v", s.SrvKeyspaceCounter) - } + // Ensure original keyspace is not used. + if execCount := sbc0.ExecCount.Get(); execCount != 0 { + t.Errorf("want 0, got %v", execCount) + } + if execCount := sbc1.ExecCount.Get(); execCount != 0 { + t.Errorf("want 0, got %v", execCount) + } + // Ensure redirected keyspace is accessed once. + if execCount := sbc2.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + // Ensure that we tried each keyspace only once. + if s.SrvKeyspaceCounter != 1 { + t.Errorf("want 1, got %v", s.SrvKeyspaceCounter) + } + if s0.SrvKeyspaceCounter != 1 { + t.Errorf("want 1, got %v", s0.SrvKeyspaceCounter) + } + s0.Reset() + }) - // no failure, initial vertical resharding - s.Reset() - addSandboxServedFrom(name, name+"ServedFrom0") - hc.Reset() - sbc0 = hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 = hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) - s0 := createSandbox(name + "ServedFrom0") // make sure we have a fresh copy - s0.ShardSpec = "-80-" - sbc2 := hc.AddTestTablet("aa", "1.1.1.1", 1003, name+"ServedFrom0", "-80", topodatapb.TabletType_MASTER, true, 1, nil) - _, err = action(res) - if err != nil { - t.Errorf("want nil, got %v", err) - } - // Ensure original keyspace is not used. - if execCount := sbc0.ExecCount.Get(); execCount != 0 { - t.Errorf("want 0, got %v", execCount) - } - if execCount := sbc1.ExecCount.Get(); execCount != 0 { - t.Errorf("want 0, got %v", execCount) - } - // Ensure redirected keyspace is accessed once. - if execCount := sbc2.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - // Ensure that we tried each keyspace only once. - if s.SrvKeyspaceCounter != 1 { - t.Errorf("want 1, got %v", s.SrvKeyspaceCounter) - } - if s0.SrvKeyspaceCounter != 1 { - t.Errorf("want 1, got %v", s0.SrvKeyspaceCounter) - } - s0.Reset() - - // retryable failure, vertical resharding - s.Reset() - hc.Reset() - sbc0 = hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 = hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 - i := 0 - s.SrvKeyspaceCallback = func() { - if i == 1 { - addSandboxServedFrom(name, name+"ServedFrom") - hc.Reset() - hc.AddTestTablet("aa", "1.1.1.1", 1001, name+"ServedFrom", "-20", topodatapb.TabletType_MASTER, true, 1, nil) - hc.AddTestTablet("aa", "1.1.1.1", 1002, name+"ServedFrom", "20-40", topodatapb.TabletType_MASTER, true, 1, nil) - } - i++ - } - _, err = action(res) - if err != nil { - t.Errorf("want nil, got %v", err) - } - // Ensure that we tried only once on the original conn. - if execCount := sbc0.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - if execCount := sbc1.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - // Ensure that we tried topo only 3 times. - if s.SrvKeyspaceCounter != 3 { - t.Errorf("want 3, got %v", s.SrvKeyspaceCounter) - } + // + t.Run("retryable failure, vertical resharding", func(t *testing.T) { + s := createSandbox(name) + hc := discovery.NewFakeHealthCheck() + res := newTestResolver(hc, new(sandboxTopo), "aa") + + sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + sbc1.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 + i := 0 + s.SrvKeyspaceCallback = func() { + if i == 1 { + addSandboxServedFrom(name, name+"ServedFrom") + hc.Reset() + hc.AddTestTablet("aa", "1.1.1.1", 1001, name+"ServedFrom", "-20", topodatapb.TabletType_MASTER, true, 1, nil) + hc.AddTestTablet("aa", "1.1.1.1", 1002, name+"ServedFrom", "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + } + i++ + } + _, err := action(res) + if err != nil { + t.Errorf("want nil, got %v", err) + } + // Ensure that we tried only once on the original conn. + if execCount := sbc0.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + if execCount := sbc1.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + // Ensure that we tried topo only 3 times. + if s.SrvKeyspaceCounter != 3 { + t.Errorf("want 3, got %v", s.SrvKeyspaceCounter) + } + }) - // retryable failure, horizontal resharding - s.Reset() - hc.Reset() - sbc0 = hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1 = hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) - sbc1.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 - i = 0 - s.SrvKeyspaceCallback = func() { - if i == 1 { - s.ShardSpec = "-20-30-40-60-80-a0-c0-e0-" - hc.Reset() - hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-30", topodatapb.TabletType_MASTER, true, 1, nil) - } - i++ - } - _, err = action(res) - if err != nil { - t.Errorf("want nil, got %v", err) - } - // Ensure that we tried only once on original guy. - if execCount := sbc0.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - if execCount := sbc1.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - // Ensure that we tried topo only twice. - if s.SrvKeyspaceCounter != 2 { - t.Errorf("want 2, got %v", s.SrvKeyspaceCounter) - } + t.Run("retryable failure, horizontal resharding", func(t *testing.T) { + s := createSandbox(name) + hc := discovery.NewFakeHealthCheck() + res := newTestResolver(hc, new(sandboxTopo), "aa") + + s.Reset() + hc.Reset() + sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + sbc1 := hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + sbc1.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 + i := 0 + s.SrvKeyspaceCallback = func() { + if i == 1 { + s.ShardSpec = "-20-30-40-60-80-a0-c0-e0-" + hc.Reset() + hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-30", topodatapb.TabletType_MASTER, true, 1, nil) + } + i++ + } + _, err := action(res) + if err != nil { + t.Errorf("want nil, got %v", err) + } + // Ensure that we tried only once on original guy. + if execCount := sbc0.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + if execCount := sbc1.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + // Ensure that we tried topo only twice. + if s.SrvKeyspaceCounter != 2 { + t.Errorf("want 2, got %v", s.SrvKeyspaceCounter) + } + }) } func testResolverStreamGeneric(t *testing.T, name string, action func(res *Resolver) (*sqltypes.Result, error)) { - // successful execute - s := createSandbox(name) - hc := discovery.NewFakeHealthCheck() - res := newTestResolver(hc, new(sandboxTopo), "aa") - sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) - _, err := action(res) - if err != nil { - t.Errorf("want nil, got %v", err) - } - if execCount := sbc0.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } + t.Run("successful execute", func(t *testing.T) { + createSandbox(name) + hc := discovery.NewFakeHealthCheck() + res := newTestResolver(hc, new(sandboxTopo), "aa") + sbc0 := hc.AddTestTablet("aa", "1.1.1.1", 1001, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + hc.AddTestTablet("aa", "1.1.1.1", 1002, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + _, err := action(res) + if err != nil { + t.Errorf("want nil, got %v", err) + } + if execCount := sbc0.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } - // failure - s.Reset() - hc.Reset() - sbc0 = hc.AddTestTablet("aa", "-20", 1, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) - hc.AddTestTablet("aa", "20-40", 1, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) - sbc0.MustFailCodes[vtrpcpb.Code_INTERNAL] = 1 - _, err = action(res) - want := fmt.Sprintf("target: %s.-20.master, used tablet: aa-0 (-20), INTERNAL error", name) - if err == nil || err.Error() != want { - t.Errorf("want\n%s\ngot\n%v", want, err) - } - // Ensure that we tried only once. - if execCount := sbc0.ExecCount.Get(); execCount != 1 { - t.Errorf("want 1, got %v", execCount) - } - // Ensure that we tried topo only once - if s.SrvKeyspaceCounter != 1 { - t.Errorf("want 1, got %v", s.SrvKeyspaceCounter) - } + }) + + t.Run("failure", func(t *testing.T) { + s := createSandbox(name) + hc := discovery.NewFakeHealthCheck() + res := newTestResolver(hc, new(sandboxTopo), "aa") + sbc0 := hc.AddTestTablet("aa", "-20", 1, name, "-20", topodatapb.TabletType_MASTER, true, 1, nil) + hc.AddTestTablet("aa", "20-40", 1, name, "20-40", topodatapb.TabletType_MASTER, true, 1, nil) + sbc0.MustFailCodes[vtrpcpb.Code_INTERNAL] = 1 + _, err := action(res) + want := fmt.Sprintf("target: %s.-20.master, used tablet: aa-0 (-20): INTERNAL error", name) + if err == nil || err.Error() != want { + t.Errorf("want\n%s\ngot\n%v", want, err) + } + // Ensure that we tried only once. + if execCount := sbc0.ExecCount.Get(); execCount != 1 { + t.Errorf("want 1, got %v", execCount) + } + // Ensure that we tried topo only once + if s.SrvKeyspaceCounter != 1 { + t.Errorf("want 1, got %v", s.SrvKeyspaceCounter) + } + }) } func TestResolverMessageAckSharded(t *testing.T) { @@ -593,7 +614,7 @@ func TestResolverExecBatchReresolve(t *testing.T) { } _, err := res.ExecuteBatch(context.Background(), topodatapb.TabletType_MASTER, false, nil, nil, buildBatchRequest) - want := "target: TestResolverExecBatchReresolve.0.master, used tablet: aa-0 (0), FAILED_PRECONDITION error" + want := "target: TestResolverExecBatchReresolve.0.master, used tablet: aa-0 (0): FAILED_PRECONDITION error" if err == nil || err.Error() != want { t.Errorf("want %s, got %v", want, err) } @@ -630,7 +651,7 @@ func TestResolverExecBatchAsTransaction(t *testing.T) { } _, err := res.ExecuteBatch(context.Background(), topodatapb.TabletType_MASTER, true, nil, nil, buildBatchRequest) - want := "target: TestResolverExecBatchAsTransaction.0.master, used tablet: aa-0 (0), INTERNAL error" + want := "target: TestResolverExecBatchAsTransaction.0.master, used tablet: aa-0 (0): INTERNAL error" if err == nil || err.Error() != want { t.Errorf("want %v, got %v", want, err) } diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 50d52060ce6..89af3ef4540 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -161,7 +161,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s sbc := hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 qr, err = f(sc, []string{"0"}) - want := fmt.Sprintf("target: %v.0.replica, used tablet: aa-0 (0), INVALID_ARGUMENT error", name) + want := fmt.Sprintf("target: %v.0.replica, used tablet: aa-0 (0): INVALID_ARGUMENT error", name) // Verify server error string. if err == nil || err.Error() != want { t.Errorf("want %s, got %v", want, err) @@ -181,7 +181,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s sbc1.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 _, err = f(sc, []string{"0", "1"}) // Verify server errors are consolidated. - want = fmt.Sprintf("target: %v.0.replica, used tablet: aa-0 (0), INVALID_ARGUMENT error\ntarget: %v.1.replica, used tablet: aa-0 (1), INVALID_ARGUMENT error", name, name) + want = fmt.Sprintf("target: %v.0.replica, used tablet: aa-0 (0): INVALID_ARGUMENT error\ntarget: %v.1.replica, used tablet: aa-0 (1): INVALID_ARGUMENT error", name, name) verifyScatterConnError(t, err, want, vtrpcpb.Code_INVALID_ARGUMENT) // Ensure that we tried only once. if execCount := sbc0.ExecCount.Get(); execCount != 1 { @@ -201,7 +201,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s sbc1.MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1 _, err = f(sc, []string{"0", "1"}) // Verify server errors are consolidated. - want = fmt.Sprintf("target: %v.0.replica, used tablet: aa-0 (0), INVALID_ARGUMENT error\ntarget: %v.1.replica, used tablet: aa-0 (1), RESOURCE_EXHAUSTED error", name, name) + want = fmt.Sprintf("target: %v.0.replica, used tablet: aa-0 (0): INVALID_ARGUMENT error\ntarget: %v.1.replica, used tablet: aa-0 (1): RESOURCE_EXHAUSTED error", name, name) // We should only surface the higher priority error code verifyScatterConnError(t, err, want, vtrpcpb.Code_INVALID_ARGUMENT) // Ensure that we tried only once. diff --git a/go/vt/vtgate/vindexes/hash.go b/go/vt/vtgate/vindexes/hash.go index 03882620daf..7c03640ea53 100644 --- a/go/vt/vtgate/vindexes/hash.go +++ b/go/vt/vtgate/vindexes/hash.go @@ -27,6 +27,7 @@ import ( "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" + "vitess.io/vitess/go/vt/vterrors" ) var ( @@ -98,9 +99,9 @@ func (vind *Hash) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) ([]boo for i := range ids { num, err := sqltypes.ToUint64(ids[i]) if err != nil { - return nil, fmt.Errorf("hash.Verify: %v", err) + return nil, vterrors.Wrap(err, "hash.Verify") } - out[i] = (bytes.Compare(vhash(num), ksids[i]) == 0) + out[i] = bytes.Compare(vhash(num), ksids[i]) == 0 } return out, nil } diff --git a/go/vt/vtgate/vindexes/numeric.go b/go/vt/vtgate/vindexes/numeric.go index 3a2b9eed65f..ec48cb05d0c 100644 --- a/go/vt/vtgate/vindexes/numeric.go +++ b/go/vt/vtgate/vindexes/numeric.go @@ -23,6 +23,7 @@ import ( "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" + "vitess.io/vitess/go/vt/vterrors" ) var ( @@ -68,10 +69,10 @@ func (*Numeric) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) ([]bool, var keybytes [8]byte num, err := sqltypes.ToUint64(ids[i]) if err != nil { - return nil, fmt.Errorf("Numeric.Verify: %v", err) + return nil, vterrors.Wrap(err, "Numeric.Verify") } binary.BigEndian.PutUint64(keybytes[:], num) - out[i] = (bytes.Compare(keybytes[:], ksids[i]) == 0) + out[i] = bytes.Compare(keybytes[:], ksids[i]) == 0 } return out, nil } diff --git a/go/vt/vtgate/vindexes/numeric_static_map.go b/go/vt/vtgate/vindexes/numeric_static_map.go index 275073fa09c..e0d6198a9e1 100644 --- a/go/vt/vtgate/vindexes/numeric_static_map.go +++ b/go/vt/vtgate/vindexes/numeric_static_map.go @@ -21,12 +21,12 @@ import ( "encoding/binary" "encoding/json" "errors" - "fmt" "io/ioutil" "strconv" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" + "vitess.io/vitess/go/vt/vterrors" ) var ( @@ -92,14 +92,14 @@ func (vind *NumericStaticMap) Verify(_ VCursor, ids []sqltypes.Value, ksids [][] var keybytes [8]byte num, err := sqltypes.ToUint64(ids[i]) if err != nil { - return nil, fmt.Errorf("NumericStaticMap.Verify: %v", err) + return nil, vterrors.Wrap(err, "NumericStaticMap.Verify") } lookupNum, ok := vind.lookup[num] if ok { num = lookupNum } binary.BigEndian.PutUint64(keybytes[:], num) - out[i] = (bytes.Compare(keybytes[:], ksids[i]) == 0) + out[i] = bytes.Compare(keybytes[:], ksids[i]) == 0 } return out, nil } diff --git a/go/vt/vtgate/vindexes/reverse_bits.go b/go/vt/vtgate/vindexes/reverse_bits.go index aa7e9852d5d..eb193935367 100644 --- a/go/vt/vtgate/vindexes/reverse_bits.go +++ b/go/vt/vtgate/vindexes/reverse_bits.go @@ -25,6 +25,7 @@ import ( "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/key" + "vitess.io/vitess/go/vt/vterrors" ) var ( @@ -83,9 +84,9 @@ func (vind *ReverseBits) Verify(_ VCursor, ids []sqltypes.Value, ksids [][]byte) for i := range ids { num, err := sqltypes.ToUint64(ids[i]) if err != nil { - return nil, fmt.Errorf("reverseBits.Verify: %v", err) + return nil, vterrors.Wrap(err, "reverseBits.Verify") } - out[i] = (bytes.Compare(reverse(num), ksids[i]) == 0) + out[i] = bytes.Compare(reverse(num), ksids[i]) == 0 } return out, nil } diff --git a/go/vt/vttablet/tabletserver/codex.go b/go/vt/vttablet/tabletserver/codex.go index ac55b2a6c46..559140fffaf 100644 --- a/go/vt/vttablet/tabletserver/codex.go +++ b/go/vt/vttablet/tabletserver/codex.go @@ -83,11 +83,11 @@ func buildSecondaryList(table *schema.Table, pkList [][]sqltypes.Value, secondar func resolveNumber(pv sqltypes.PlanValue, bindVars map[string]*querypb.BindVariable) (int64, error) { v, err := pv.ResolveValue(bindVars) if err != nil { - return 0, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v", err) + return 0, err } ret, err := sqltypes.ToInt64(v) if err != nil { - return 0, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v", err) + return 0, err } return ret, nil } diff --git a/go/vt/vttablet/tabletserver/tabletserver_test.go b/go/vt/vttablet/tabletserver/tabletserver_test.go index 4151045a98b..342567d5abe 100644 --- a/go/vt/vttablet/tabletserver/tabletserver_test.go +++ b/go/vt/vttablet/tabletserver/tabletserver_test.go @@ -2189,7 +2189,7 @@ func TestMessageAck(t *testing.T) { }} _, err := tsv.MessageAck(ctx, &target, "nonmsg", ids) want := "message table nonmsg not found in schema" - if err == nil || err.Error() != want { + if err == nil || strings.HasPrefix(err.Error(), want) { t.Errorf("tsv.MessageAck(invalid): %v, want %s", err, want) } @@ -2232,7 +2232,7 @@ func TestRescheduleMessages(t *testing.T) { _, err := tsv.PostponeMessages(ctx, &target, "nonmsg", []string{"1", "2"}) want := "message table nonmsg not found in schema" - if err == nil || err.Error() != want { + if err == nil || strings.HasPrefix(err.Error(), want) { t.Errorf("tsv.PostponeMessages(invalid): %v, want %s", err, want) } @@ -2275,7 +2275,7 @@ func TestPurgeMessages(t *testing.T) { _, err := tsv.PurgeMessages(ctx, &target, "nonmsg", 0) want := "message table nonmsg not found in schema" - if err == nil || err.Error() != want { + if err == nil || strings.HasPrefix(err.Error(), want) { t.Errorf("tsv.PurgeMessages(invalid): %v, want %s", err, want) } @@ -2545,13 +2545,14 @@ func TestHandleExecTabletError(t *testing.T) { vterrors.Errorf(vtrpcpb.Code_INTERNAL, "tablet error"), nil, ) + fmt.Println(">>>>>"+err.Error()) want := "tablet error" - if err == nil || err.Error() != want { - t.Errorf("%v, want '%s'", err, want) + if err == nil || !strings.Contains(err.Error(), want) { + t.Errorf("got `%v`, want '%s'", err, want) } - wantLog := "tablet error: Sql: \"select * from test_table\", BindVars: {}" - if wantLog != getTestLog(0) { - t.Errorf("error log %s, want '%s'", getTestLog(0), wantLog) + want = "Sql: \"select * from test_table\", BindVars: {}" + if !strings.Contains(getTestLog(0), want) { + t.Errorf("error log %s, want '%s'", getTestLog(0), want) } } @@ -2571,12 +2572,12 @@ func TestTerseErrorsNonSQLError(t *testing.T) { nil, ) want := "tablet error" - if err == nil || err.Error() != want { + if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("%v, want '%s'", err, want) } - wantLog := "tablet error: Sql: \"select * from test_table\", BindVars: {}" - if wantLog != getTestLog(0) { - t.Errorf("error log %s, want '%s'", getTestLog(0), wantLog) + want = "Sql: \"select * from test_table\", BindVars: {}" + if !strings.Contains(getTestLog(0), want) { + t.Errorf("error log %s, want '%s'", getTestLog(0), want) } } @@ -2620,12 +2621,12 @@ func TestTerseErrorsNoBindVars(t *testing.T) { defer clearTestLogger() err := tsv.convertAndLogError(ctx, "", nil, vterrors.Errorf(vtrpcpb.Code_DEADLINE_EXCEEDED, "sensitive message"), nil) want := "sensitive message" - if err == nil || err.Error() != want { + if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("%v, want '%s'", err, want) } - wantLog := "sensitive message: Sql: \"\", BindVars: {}" - if wantLog != getTestLog(0) { - t.Errorf("error log '%s', want '%s'", getTestLog(0), wantLog) + want = "Sql: \"\", BindVars: {}" + if !strings.Contains(getTestLog(0), want) { + t.Errorf("error log '%s', want '%s'", getTestLog(0), want) } } diff --git a/go/vt/worker/block.go b/go/vt/worker/block.go index 0d155767b96..01f48338a4d 100644 --- a/go/vt/worker/block.go +++ b/go/vt/worker/block.go @@ -17,10 +17,11 @@ limitations under the License. package worker import ( - "errors" "html/template" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/wrangler" ) @@ -96,5 +97,5 @@ func (bw *BlockWorker) run(ctx context.Context) error { bw.wr.Logger().Printf("Block command finished because the context is done: '%v'.\n", ctx.Err()) bw.SetState(WorkerStateDone) - return errors.New("command 'Block' was canceled") + return vterrors.New(vtrpc.Code_CANCELED, "command 'Block' was canceled") } diff --git a/go/vt/worker/block_cmd.go b/go/vt/worker/block_cmd.go index a2e27411d5d..9356fd9d728 100644 --- a/go/vt/worker/block_cmd.go +++ b/go/vt/worker/block_cmd.go @@ -18,10 +18,10 @@ package worker import ( "flag" - "fmt" "html/template" "net/http" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" @@ -54,7 +54,7 @@ func commandBlock(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.FlagSet, a } if subFlags.NArg() != 0 { subFlags.Usage() - return nil, fmt.Errorf("command Block does not accept any parameter") + return nil, vterrors.New(vtrpc.Code_INVALID_ARGUMENT, "command Block does not accept any parameter") } worker, err := NewBlockWorker(wr) diff --git a/go/vt/worker/chunk.go b/go/vt/worker/chunk.go index 2de9dc1c9f8..4b775b47018 100644 --- a/go/vt/worker/chunk.go +++ b/go/vt/worker/chunk.go @@ -19,6 +19,7 @@ package worker import ( "fmt" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" @@ -100,7 +101,7 @@ func generateChunks(ctx context.Context, wr *wrangler.Wrangler, tablet *topodata return nil, vterrors.Wrapf(err, "tablet: %v, table: %v: cannot determine MIN and MAX of the first primary key column. ExecuteFetchAsApp", topoproto.TabletAliasString(tablet.Alias), td.Name) } if len(qr.Rows) != 1 { - return nil, fmt.Errorf("tablet: %v, table: %v: cannot determine MIN and MAX of the first primary key column. Zero rows were returned", topoproto.TabletAliasString(tablet.Alias), td.Name) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "tablet: %v, table: %v: cannot determine MIN and MAX of the first primary key column. Zero rows were returned", topoproto.TabletAliasString(tablet.Alias), td.Name) } result := sqltypes.Proto3ToResult(qr) diff --git a/go/vt/worker/command.go b/go/vt/worker/command.go index fe8ce427754..e2f60db68a9 100644 --- a/go/vt/worker/command.go +++ b/go/vt/worker/command.go @@ -18,7 +18,6 @@ package worker import ( "flag" - "fmt" "html/template" "net/http" "os" @@ -26,6 +25,7 @@ import ( "time" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" @@ -77,7 +77,7 @@ func AddCommand(groupName string, c Command) { return } } - panic(fmt.Errorf("Trying to add to missing group %v", groupName)) + panic(vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "trying to add to missing group %v", groupName)) } func commandWorker(wi *Instance, wr *wrangler.Wrangler, args []string, cell string, runFromCli bool) (Worker, error) { @@ -110,7 +110,7 @@ func commandWorker(wi *Instance, wr *wrangler.Wrangler, args []string, cell stri } else { PrintAllCommands(wr.Logger()) } - return nil, fmt.Errorf("unknown command: %v", action) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "unknown command: %v", action) } // RunCommand executes the vtworker command specified by "args". Use WaitForCommand() to block on the returned done channel. diff --git a/go/vt/worker/diff_utils.go b/go/vt/worker/diff_utils.go index 304f8024993..4ba633a7f7a 100644 --- a/go/vt/worker/diff_utils.go +++ b/go/vt/worker/diff_utils.go @@ -20,14 +20,12 @@ import ( "bytes" "encoding/binary" "encoding/hex" - "errors" "fmt" "io" "strings" "time" "vitess.io/vitess/go/vt/proto/vtrpc" - "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttablet/tmclient" "vitess.io/vitess/go/vt/wrangler" @@ -120,7 +118,7 @@ func NewTransactionalQueryResultReaderForTablet(ctx context.Context, ts *topo.Se // read the columns, or grab the error cols, err := stream.Recv() if err != nil { - return nil, fmt.Errorf("Cannot read Fields for query '%v': %v", sql, err) + return nil, vterrors.Wrapf(err, "cannot read Fields for query '%v'", sql) } return &QueryResultReader{ @@ -345,7 +343,7 @@ func TableScanByKeyRange(ctx context.Context, log logutil.Logger, ts *topo.Serve } } default: - return nil, fmt.Errorf("Unsupported ShardingColumnType: %v", shardingColumnType) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Unsupported ShardingColumnType: %v", shardingColumnType) } sql := fmt.Sprintf("SELECT %v FROM %v %v", strings.Join(escapeAll(orderedColumns(td)), ", "), sqlescape.EscapeID(td.Name), where) @@ -358,7 +356,7 @@ func TableScanByKeyRange(ctx context.Context, log logutil.Logger, ts *topo.Serve // ErrStoppedRowReader is returned by RowReader.Next() when // StopAfterCurrentResult() and it finished the current result. -var ErrStoppedRowReader = errors.New("RowReader won't advance to the next Result because StopAfterCurrentResult() was called") +var ErrStoppedRowReader = vterrors.New(vtrpc.Code_ABORTED, "RowReader won't advance to the next Result because StopAfterCurrentResult() was called") // RowReader returns individual rows from a ResultReader. type RowReader struct { @@ -510,7 +508,7 @@ func CompareRows(fields []*querypb.Field, compareCount int, left, right []sqltyp r := rv.([]byte) return bytes.Compare(l, r), nil default: - return 0, fmt.Errorf("Unsupported type %T returned by mysql.proto.Convert", l) + return 0, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Unsupported type %T returned by mysql.proto.Convert", l) } } return 0, nil @@ -530,11 +528,11 @@ func NewRowDiffer(left, right ResultReader, tableDefinition *tabletmanagerdatapb leftFields := left.Fields() rightFields := right.Fields() if len(leftFields) != len(rightFields) { - return nil, fmt.Errorf("[table=%v] Cannot diff inputs with different types", tableDefinition.Name) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "[table=%v] Cannot diff inputs with different types", tableDefinition.Name) } for i, field := range leftFields { if field.Type != rightFields[i].Type { - return nil, fmt.Errorf("[table=%v] Cannot diff inputs with different types: field %v types are %v and %v", tableDefinition.Name, i, field.Type, rightFields[i].Type) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "[table=%v] Cannot diff inputs with different types: field %v types are %v and %v", tableDefinition.Name, i, field.Type, rightFields[i].Type) } } return &RowDiffer{ @@ -666,7 +664,7 @@ func createTransactions(ctx context.Context, numberOfScanners int, wr *wrangler. TransactionIsolation: query.ExecuteOptions_CONSISTENT_SNAPSHOT_READ_ONLY, }) if err != nil { - return nil, fmt.Errorf("could not open transaction on %v\n%v", topoproto.TabletAliasString(tabletInfo.Alias), err) + return nil, vterrors.Wrapf(err, "could not open transaction on %v", topoproto.TabletAliasString(tabletInfo.Alias)) } // Remember to rollback the transactions @@ -755,7 +753,7 @@ func CreateConsistentTransactions(ctx context.Context, tablet *topo.TabletInfo, // Lock all tables with a read lock to pause replication err := tm.LockTables(ctx, tablet.Tablet) if err != nil { - return nil, "", fmt.Errorf("could not lock tables on %v\n%v", topoproto.TabletAliasString(tablet.Tablet.Alias), err) + return nil, "", vterrors.Wrapf(err, "could not lock tables on %v", topoproto.TabletAliasString(tablet.Tablet.Alias)) } defer func() { tm := tmclient.NewTabletManagerClient() @@ -772,12 +770,12 @@ func CreateConsistentTransactions(ctx context.Context, tablet *topo.TabletInfo, defer queryService.Close(ctx) connections, err := createTransactions(ctx, numberOfScanners, wr, cleaner, queryService, target, tablet.Tablet) if err != nil { - return nil, "", fmt.Errorf("failed to create transactions on %v: %v", topoproto.TabletAliasString(tablet.Tablet.Alias), err) + return nil, "", vterrors.Wrapf(err, "failed to create transactions on %v", topoproto.TabletAliasString(tablet.Tablet.Alias)) } wr.Logger().Infof("transactions created on %v", topoproto.TabletAliasString(tablet.Tablet.Alias)) executedGtid, err := tm.MasterPosition(ctx, tablet.Tablet) if err != nil { - return nil, "", fmt.Errorf("could not read executed GTID set on %v\n%v", topoproto.TabletAliasString(tablet.Tablet.Alias), err) + return nil, "", vterrors.Wrapf(err, "could not read executed GTID set on %v", topoproto.TabletAliasString(tablet.Tablet.Alias)) } return connections, executedGtid, nil diff --git a/go/vt/worker/executor.go b/go/vt/worker/executor.go index 757cdaf00e9..07ec11d132b 100644 --- a/go/vt/worker/executor.go +++ b/go/vt/worker/executor.go @@ -179,10 +179,11 @@ func (e *executor) fetchWithRetries(ctx context.Context, action func(ctx context select { case <-retryCtx.Done(): - if retryCtx.Err() == context.DeadlineExceeded { - return fmt.Errorf("failed to connect to destination tablet %v after retrying for %v", tabletString, retryDuration) + err := retryCtx.Err() + if err == context.DeadlineExceeded { + return vterrors.Wrapf(err, "failed to connect to destination tablet %v after retrying for %v", tabletString, retryDuration) } - return fmt.Errorf("interrupted (context error: %v) while trying to run a command on tablet %v", retryCtx.Err(), tabletString) + return vterrors.Wrapf(err, "interrupted while trying to run a command on tablet %v", tabletString) case <-time.After(*executeFetchRetryTime): // Retry 30s after the failure using the current master seen by the HealthCheck. } diff --git a/go/vt/worker/instance.go b/go/vt/worker/instance.go index f730cde5629..bf083c55324 100644 --- a/go/vt/worker/instance.go +++ b/go/vt/worker/instance.go @@ -17,8 +17,6 @@ limitations under the License. package worker import ( - "errors" - "fmt" "os" "os/signal" "sync" @@ -138,7 +136,7 @@ func (wi *Instance) setAndStartWorker(ctx context.Context, wrk Worker, wr *wrang // The recovery code is a copy of servenv.HandlePanic(). if x := recover(); x != nil { log.Errorf("uncaught vtworker panic: %v\n%s", x, tb.Stack(4)) - err = fmt.Errorf("uncaught vtworker panic: %v", x) + err = vterrors.Errorf(vtrpcpb.Code_INTERNAL, "uncaught vtworker panic: %v", x) } wi.currentWorkerMutex.Lock() @@ -206,7 +204,7 @@ func (wi *Instance) Reset() error { return nil } - return errors.New("worker still executing") + return vterrors.New(vtrpcpb.Code_FAILED_PRECONDITION, "worker still executing") } // Cancel calls the cancel function of the current vtworker job. diff --git a/go/vt/worker/key_resolver.go b/go/vt/worker/key_resolver.go index a17cdd27e0c..2d63878c110 100644 --- a/go/vt/worker/key_resolver.go +++ b/go/vt/worker/key_resolver.go @@ -17,9 +17,7 @@ limitations under the License. package worker import ( - "errors" - "fmt" - + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/sqltypes" @@ -55,19 +53,19 @@ type v2Resolver struct { // V2 keyspaces have a preset sharding column name and type. func newV2Resolver(keyspaceInfo *topo.KeyspaceInfo, td *tabletmanagerdatapb.TableDefinition) (keyspaceIDResolver, error) { if keyspaceInfo.ShardingColumnName == "" { - return nil, errors.New("ShardingColumnName needs to be set for a v2 sharding key") + return nil, vterrors.New(vtrpc.Code_FAILED_PRECONDITION, "ShardingColumnName needs to be set for a v2 sharding key") } if keyspaceInfo.ShardingColumnType == topodatapb.KeyspaceIdType_UNSET { - return nil, errors.New("ShardingColumnType needs to be set for a v2 sharding key") + return nil, vterrors.New(vtrpc.Code_FAILED_PRECONDITION, "ShardingColumnType needs to be set for a v2 sharding key") } if td.Type != tmutils.TableBaseTable { - return nil, fmt.Errorf("a keyspaceID resolver can only be created for a base table, got %v", td.Type) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "a keyspaceID resolver can only be created for a base table, got %v", td.Type) } // Find the sharding key column index. columnIndex, ok := tmutils.TableDefinitionGetColumn(td, keyspaceInfo.ShardingColumnName) if !ok { - return nil, fmt.Errorf("table %v doesn't have a column named '%v'", td.Name, keyspaceInfo.ShardingColumnName) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "table %v doesn't have a column named '%v'", td.Name, keyspaceInfo.ShardingColumnName) } return &v2Resolver{keyspaceInfo, columnIndex}, nil @@ -86,7 +84,7 @@ func (r *v2Resolver) keyspaceID(row []sqltypes.Value) ([]byte, error) { } return key.Uint64Key(i).Bytes(), nil default: - return nil, fmt.Errorf("unsupported ShardingColumnType: %v", r.keyspaceInfo.ShardingColumnType) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "unsupported ShardingColumnType: %v", r.keyspaceInfo.ShardingColumnType) } } @@ -101,11 +99,11 @@ type v3Resolver struct { // newV3ResolverFromTableDefinition returns a keyspaceIDResolver for a v3 table. func newV3ResolverFromTableDefinition(keyspaceSchema *vindexes.KeyspaceSchema, td *tabletmanagerdatapb.TableDefinition) (keyspaceIDResolver, error) { if td.Type != tmutils.TableBaseTable { - return nil, fmt.Errorf("a keyspaceID resolver can only be created for a base table, got %v", td.Type) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "a keyspaceID resolver can only be created for a base table, got %v", td.Type) } tableSchema, ok := keyspaceSchema.Tables[td.Name] if !ok { - return nil, fmt.Errorf("no vschema definition for table %v", td.Name) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "no vschema definition for table %v", td.Name) } // use the lowest cost unique vindex as the sharding key colVindex, err := vindexes.FindVindexForSharding(td.Name, tableSchema.ColumnVindexes) @@ -116,7 +114,7 @@ func newV3ResolverFromTableDefinition(keyspaceSchema *vindexes.KeyspaceSchema, t // Find the sharding key column index. columnIndex, ok := tmutils.TableDefinitionGetColumn(td, colVindex.Columns[0].String()) if !ok { - return nil, fmt.Errorf("table %v has a Vindex on unknown column %v", td.Name, colVindex.Columns[0]) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "table %v has a Vindex on unknown column %v", td.Name, colVindex.Columns[0]) } return &v3Resolver{ @@ -129,7 +127,7 @@ func newV3ResolverFromTableDefinition(keyspaceSchema *vindexes.KeyspaceSchema, t func newV3ResolverFromColumnList(keyspaceSchema *vindexes.KeyspaceSchema, name string, columns []string) (keyspaceIDResolver, error) { tableSchema, ok := keyspaceSchema.Tables[name] if !ok { - return nil, fmt.Errorf("no vschema definition for table %v", name) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "no vschema definition for table %v", name) } // use the lowest cost unique vindex as the sharding key colVindex, err := vindexes.FindVindexForSharding(name, tableSchema.ColumnVindexes) @@ -146,7 +144,7 @@ func newV3ResolverFromColumnList(keyspaceSchema *vindexes.KeyspaceSchema, name s } } if columnIndex == -1 { - return nil, fmt.Errorf("table %v has a Vindex on unknown column %v", name, colVindex.Columns[0]) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "table %v has a Vindex on unknown column %v", name, colVindex.Columns[0]) } return &v3Resolver{ @@ -163,11 +161,11 @@ func (r *v3Resolver) keyspaceID(row []sqltypes.Value) ([]byte, error) { return nil, err } if len(destinations) != 1 { - return nil, fmt.Errorf("mapping row to keyspace id returned an invalid array of keyspace ids: %v", key.DestinationsString(destinations)) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "mapping row to keyspace id returned an invalid array of keyspace ids: %v", key.DestinationsString(destinations)) } ksid, ok := destinations[0].(key.DestinationKeyspaceID) if !ok || len(ksid) == 0 { - return nil, fmt.Errorf("could not map %v to a keyspace id, got destination %v", v, destinations[0]) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "could not map %v to a keyspace id, got destination %v", v, destinations[0]) } return ksid, nil } diff --git a/go/vt/worker/multi_split_diff_cmd.go b/go/vt/worker/multi_split_diff_cmd.go index 8d54df60c35..2c8f4b2bc12 100644 --- a/go/vt/worker/multi_split_diff_cmd.go +++ b/go/vt/worker/multi_split_diff_cmd.go @@ -26,6 +26,8 @@ import ( "sync" "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" "vitess.io/vitess/go/vt/concurrency" @@ -100,7 +102,7 @@ func commandMultiSplitDiff(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.F } if subFlags.NArg() != 1 { subFlags.Usage() - return nil, fmt.Errorf("command MultiSplitDiff requires ") + return nil, vterrors.New(vtrpc.Code_INVALID_ARGUMENT, "command MultiSplitDiff requires ") } keyspace, shard, err := topoproto.ParseKeyspaceShard(subFlags.Arg(0)) if err != nil { @@ -113,7 +115,7 @@ func commandMultiSplitDiff(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.F tabletType, ok := topodata.TabletType_value[*tabletTypeStr] if !ok { - return nil, fmt.Errorf("failed to find this tablet type %v", tabletTypeStr) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "failed to find this tablet type %v", tabletTypeStr) } return NewMultiSplitDiffWorker(wr, wi.cell, keyspace, shard, excludeTableArray, *minHealthyTablets, *parallelDiffsCount, *waitForFixedTimeRatherThanGtidSet, *useConsistentSnapshot, topodata.TabletType(tabletType)), nil @@ -125,7 +127,7 @@ func shardSources(ctx context.Context, wr *wrangler.Wrangler) ([]map[string]stri keyspaces, err := wr.TopoServer().GetKeyspaces(shortCtx) cancel() if err != nil { - return nil, fmt.Errorf("failed to get list of keyspaces: %v", err) + return nil, vterrors.Wrap(err, "failed to get list of keyspaces") } wg := sync.WaitGroup{} @@ -141,7 +143,7 @@ func shardSources(ctx context.Context, wr *wrangler.Wrangler) ([]map[string]stri shards, err := wr.TopoServer().GetShardNames(shortCtx, keyspace) cancel() if err != nil { - rec.RecordError(fmt.Errorf("failed to get list of shards for keyspace '%v': %v", keyspace, err)) + rec.RecordError(vterrors.Wrapf(err, "failed to get list of shards for keyspace '%v'", keyspace)) return } for _, shard := range shards { @@ -152,7 +154,7 @@ func shardSources(ctx context.Context, wr *wrangler.Wrangler) ([]map[string]stri si, err := wr.TopoServer().GetShard(shortCtx, keyspace, shard) cancel() if err != nil { - rec.RecordError(fmt.Errorf("failed to get details for shard '%v': %v", topoproto.KeyspaceShardString(keyspace, shard), err)) + rec.RecordError(vterrors.Wrapf(err, "failed to get details for shard '%v'", topoproto.KeyspaceShardString(keyspace, shard))) return } @@ -181,14 +183,14 @@ func shardSources(ctx context.Context, wr *wrangler.Wrangler) ([]map[string]stri result = append(result, shard) } if len(result) == 0 { - return nil, fmt.Errorf("there are no shards with SourceShards") + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "there are no shards with SourceShards") } return result, nil } func interactiveMultiSplitDiff(ctx context.Context, wi *Instance, wr *wrangler.Wrangler, _ http.ResponseWriter, r *http.Request) (Worker, *template.Template, map[string]interface{}, error) { if err := r.ParseForm(); err != nil { - return nil, nil, nil, fmt.Errorf("cannot parse form: %s", err) + return nil, nil, nil, vterrors.Wrap(err, "cannot parse form") } keyspace := r.FormValue("keyspace") shard := r.FormValue("shard") @@ -228,7 +230,7 @@ func interactiveMultiSplitDiff(ctx context.Context, wi *Instance, wr *wrangler.W minHealthyTablets, err := strconv.ParseInt(minHealthyTabletsStr, 0, 64) parallelDiffsCount, err := strconv.ParseInt(parallelDiffsCountStr, 0, 64) if err != nil { - return nil, nil, nil, fmt.Errorf("cannot parse minHealthyTablets: %s", err) + return nil, nil, nil, vterrors.Wrap(err, "cannot parse minHealthyTablets") } waitForFixedTimeRatherThanGtidSetStr := r.FormValue("waitForFixedTimeRatherThanGtidSet") waitForFixedTimeRatherThanGtidSet := waitForFixedTimeRatherThanGtidSetStr == "true" @@ -238,7 +240,7 @@ func interactiveMultiSplitDiff(ctx context.Context, wi *Instance, wr *wrangler.W tabletTypeStr := r.FormValue("tabletType") tabletType, ok := topodata.TabletType_value[tabletTypeStr] if !ok { - return nil, nil, nil, fmt.Errorf("cannot parse tabletType: %s", tabletTypeStr) + return nil, nil, nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "cannot parse tabletType: %s", tabletTypeStr) } // start the diff job diff --git a/go/vt/worker/ping_cmd.go b/go/vt/worker/ping_cmd.go index f0658ab1264..784587a3f23 100644 --- a/go/vt/worker/ping_cmd.go +++ b/go/vt/worker/ping_cmd.go @@ -18,10 +18,10 @@ package worker import ( "flag" - "fmt" "html/template" "net/http" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" @@ -56,7 +56,7 @@ func commandPing(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.FlagSet, ar } if subFlags.NArg() != 1 { subFlags.Usage() - return nil, fmt.Errorf("command Ping requires ") + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "command Ping requires ") } message := subFlags.Arg(0) diff --git a/go/vt/worker/restartable_result_reader.go b/go/vt/worker/restartable_result_reader.go index 90a5e8c20ea..71f7f9b1375 100644 --- a/go/vt/worker/restartable_result_reader.go +++ b/go/vt/worker/restartable_result_reader.go @@ -18,7 +18,6 @@ package worker import ( "bytes" - "fmt" "io" "strings" "time" @@ -101,18 +100,18 @@ func tryToConnect(r *RestartableResultReader) error { var err error var retryable bool if retryable, err = r.getTablet(); err != nil { - err = fmt.Errorf("tablet=unknown: %v", err) + err = vterrors.Wrap(err, "tablet=unknown") goto retry } if retryable, err = r.startStream(); err != nil { - err = fmt.Errorf("tablet=%v: %v", topoproto.TabletAliasString(r.tablet.Alias), err) + err = vterrors.Wrapf(err, "tablet=%v", topoproto.TabletAliasString(r.tablet.Alias)) goto retry } return nil retry: if !retryable || attempt > 1 { - return fmt.Errorf("failed to initialize tablet connection: retryable %v, %v", retryable, err) + return vterrors.Wrapf(err, "failed to initialize tablet connection: retryable %v", retryable) } statsRetryCount.Add(1) log.Infof("retrying after error: %v", err) @@ -300,10 +299,11 @@ func (r *RestartableResultReader) nextWithRetries() (*sqltypes.Result, error) { select { case <-retryCtx.Done(): - if retryCtx.Err() == context.DeadlineExceeded { - return nil, fmt.Errorf("%v: failed to restart the streaming connection after retrying for %v", r.tp.description(), *retryDuration) + err := retryCtx.Err() + if err == context.DeadlineExceeded { + return nil, vterrors.Wrapf(err, "%v: failed to restart the streaming connection after retrying for %v", r.tp.description(), *retryDuration) } - return nil, fmt.Errorf("%v: interrupted (context error: %v) while trying to restart the streaming connection (%.1f minutes elapsed so far)", r.tp.description(), retryCtx.Err(), time.Now().Sub(start).Minutes()) + return nil, vterrors.Wrapf(err, "%v: interrupted while trying to restart the streaming connection (%.1f minutes elapsed so far)", r.tp.description(), time.Now().Sub(start).Minutes()) case <-time.After(*executeFetchRetryTime): // Make a pause between the retries to avoid hammering the servers. } diff --git a/go/vt/worker/result_merger.go b/go/vt/worker/result_merger.go index c0ae2ec7190..2f298594726 100644 --- a/go/vt/worker/result_merger.go +++ b/go/vt/worker/result_merger.go @@ -23,6 +23,8 @@ import ( "github.com/golang/protobuf/proto" "golang.org/x/net/context" + + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/sqltypes" @@ -71,7 +73,7 @@ func NewResultMerger(inputs []ResultReader, pkFieldCount int) (*ResultMerger, er err := CheckValidTypesForResultMerger(fields, pkFieldCount) if err != nil { - return nil, fmt.Errorf("invalid PK types for ResultMerger. Use the vtworker LegacySplitClone command instead. %v", err.Error()) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "invalid PK types for ResultMerger. Use the vtworker LegacySplitClone command instead. %v", err.Error()) } // Initialize the priority queue with all input ResultReader which have at @@ -105,7 +107,7 @@ func CheckValidTypesForResultMerger(fields []*querypb.Field, pkFieldCount int) e for i := 0; i < pkFieldCount; i++ { typ := fields[i].Type if !sqltypes.IsIntegral(typ) && !sqltypes.IsFloat(typ) && !sqltypes.IsBinary(typ) { - return fmt.Errorf("unsupported type: %v cannot compare fields with this type", typ) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "unsupported type: %v cannot compare fields with this type", typ) } } return nil @@ -200,17 +202,24 @@ func (rm *ResultMerger) reset() { rm.output = make([][]sqltypes.Value, 0, ResultSizeRows) } +func equalFields(a, b []*querypb.Field) bool { + if len(a) != len(b) { + return false + } + for i, aField := range a { + bField := b[i] + if !proto.Equal(aField, bField) { + return false + } + } + return true +} + func checkFieldsEqual(fields []*querypb.Field, inputs []ResultReader) error { for i := 1; i < len(inputs); i++ { otherFields := inputs[i].Fields() - if len(fields) != len(otherFields) { - return fmt.Errorf("input ResultReaders have conflicting Fields data: ResultReader[0]: %v != ResultReader[%d]: %v", fields, i, otherFields) - } - for j, field := range fields { - otherField := otherFields[j] - if !proto.Equal(field, otherField) { - return fmt.Errorf("input ResultReaders have conflicting Fields data: ResultReader[0]: %v != ResultReader[%d]: %v", fields, i, otherFields) - } + if !equalFields(fields, otherFields) { + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "input ResultReaders have conflicting Fields data: ResultReader[0]: %v != ResultReader[%d]: %v", fields, i, otherFields) } } return nil diff --git a/go/vt/worker/row_aggregator.go b/go/vt/worker/row_aggregator.go index 9ccd803e4bb..8df872cd78a 100644 --- a/go/vt/worker/row_aggregator.go +++ b/go/vt/worker/row_aggregator.go @@ -22,6 +22,7 @@ import ( "strings" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/sqlescape" "vitess.io/vitess/go/sqltypes" @@ -124,7 +125,7 @@ func (ra *RowAggregator) Flush() error { select { case ra.insertChannel <- ra.buffer.String(): case <-ra.ctx.Done(): - return fmt.Errorf("failed to flush RowAggregator and send the query to a writer thread channel: %v", ra.ctx.Err()) + return vterrors.Wrap(ra.ctx.Err(), "failed to flush RowAggregator and send the query to a writer thread channel") } // Update our statistics. diff --git a/go/vt/worker/row_differ.go b/go/vt/worker/row_differ.go index 1253f95f72c..c231ed020a6 100644 --- a/go/vt/worker/row_differ.go +++ b/go/vt/worker/row_differ.go @@ -20,6 +20,7 @@ import ( "fmt" "time" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" @@ -127,11 +128,11 @@ func NewRowDiffer2(ctx context.Context, left, right ResultReader, td *tabletmana func compareFields(left, right []*querypb.Field) error { if len(left) != len(right) { - return fmt.Errorf("Cannot diff inputs with different number of fields: left: %v right: %v", left, right) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot diff inputs with different number of fields: left: %v right: %v", left, right) } for i, field := range left { if field.Type != right[i].Type { - return fmt.Errorf("Cannot diff inputs with different types: field %v types are %v and %v", i, field.Type, right[i].Type) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot diff inputs with different types: field %v types are %v and %v", i, field.Type, right[i].Type) } } return nil @@ -364,5 +365,5 @@ func (rr *RowRouter) Route(row []sqltypes.Value) (int, error) { return i, nil } } - return -1, fmt.Errorf("no shard's key range includes the keyspace id: %v for the row: %#v", k, row) + return -1, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "no shard's key range includes the keyspace id: %v for the row: %#v", k, row) } diff --git a/go/vt/worker/split_clone.go b/go/vt/worker/split_clone.go index d3e32e6e1d5..10ea583458e 100644 --- a/go/vt/worker/split_clone.go +++ b/go/vt/worker/split_clone.go @@ -17,30 +17,27 @@ limitations under the License. package worker import ( - "errors" "fmt" "html/template" "strings" "sync" "time" - "vitess.io/vitess/go/vt/vttablet/tabletconn" - - "vitess.io/vitess/go/vt/binlog/binlogplayer" - - "vitess.io/vitess/go/vt/vterrors" - "golang.org/x/net/context" "vitess.io/vitess/go/event" "vitess.io/vitess/go/stats" + "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/discovery" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/throttler" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/topoproto" "vitess.io/vitess/go/vt/topotools" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vtgate/vindexes" + "vitess.io/vitess/go/vt/vttablet/tabletconn" "vitess.io/vitess/go/vt/worker/events" "vitess.io/vitess/go/vt/wrangler" @@ -162,48 +159,48 @@ func newVerticalSplitCloneWorker(wr *wrangler.Wrangler, cell, keyspace, shard st // TODO(mberlin): Rename SplitCloneWorker to cloneWorker. func newCloneWorker(wr *wrangler.Wrangler, cloneType cloneType, cell, keyspace, shard string, online, offline bool, tables, excludeTables []string, chunkCount, minRowsPerChunk, sourceReaderCount, writeQueryMaxRows, writeQueryMaxSize, destinationWriterCount, minHealthyTablets int, tabletType topodatapb.TabletType, maxTPS, maxReplicationLag int64, useConsistentSnapshot bool) (Worker, error) { if cloneType != horizontalResharding && cloneType != verticalSplit { - return nil, fmt.Errorf("unknown cloneType: %v This is a bug. Please report", cloneType) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unknown cloneType: %v This is a bug. Please report", cloneType) } // Verify user defined flags. if !online && !offline { - return nil, errors.New("at least one clone phase (-online, -offline) must be enabled (and not set to false)") + return nil, vterrors.New(vtrpc.Code_INVALID_ARGUMENT, "at least one clone phase (-online, -offline) must be enabled (and not set to false)") } if tables != nil && len(tables) == 0 { - return nil, errors.New("list of tablets to be split out must not be empty") + return nil, vterrors.New(vtrpc.Code_INVALID_ARGUMENT, "list of tablets to be split out must not be empty") } if chunkCount <= 0 { - return nil, fmt.Errorf("chunk_count must be > 0: %v", chunkCount) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "chunk_count must be > 0: %v", chunkCount) } if minRowsPerChunk <= 0 { - return nil, fmt.Errorf("min_rows_per_chunk must be > 0: %v", minRowsPerChunk) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "min_rows_per_chunk must be > 0: %v", minRowsPerChunk) } if sourceReaderCount <= 0 { - return nil, fmt.Errorf("source_reader_count must be > 0: %v", sourceReaderCount) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "source_reader_count must be > 0: %v", sourceReaderCount) } if writeQueryMaxRows <= 0 { - return nil, fmt.Errorf("write_query_max_rows must be > 0: %v", writeQueryMaxRows) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "write_query_max_rows must be > 0: %v", writeQueryMaxRows) } if writeQueryMaxSize <= 0 { - return nil, fmt.Errorf("write_query_max_size must be > 0: %v", writeQueryMaxSize) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "write_query_max_size must be > 0: %v", writeQueryMaxSize) } if destinationWriterCount <= 0 { - return nil, fmt.Errorf("destination_writer_count must be > 0: %v", destinationWriterCount) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "destination_writer_count must be > 0: %v", destinationWriterCount) } if minHealthyTablets < 0 { - return nil, fmt.Errorf("min_healthy_tablets must be >= 0: %v", minHealthyTablets) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "min_healthy_tablets must be >= 0: %v", minHealthyTablets) } if maxTPS != throttler.MaxRateModuleDisabled { wr.Logger().Infof("throttling enabled and set to a max of %v transactions/second", maxTPS) } if maxTPS != throttler.MaxRateModuleDisabled && maxTPS < int64(destinationWriterCount) { - return nil, fmt.Errorf("-max_tps must be >= -destination_writer_count: %v >= %v", maxTPS, destinationWriterCount) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "-max_tps must be >= -destination_writer_count: %v >= %v", maxTPS, destinationWriterCount) } if maxReplicationLag <= 0 { - return nil, fmt.Errorf("max_replication_lag must be >= 1s: %v", maxReplicationLag) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "max_replication_lag must be >= 1s: %v", maxReplicationLag) } if tabletType != topodatapb.TabletType_REPLICA && tabletType != topodatapb.TabletType_RDONLY { - return nil, fmt.Errorf("tablet_type must be RDONLY or REPLICA: %v", topodatapb.TabletType_name[int32(tabletType)]) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "tablet_type must be RDONLY or REPLICA: %v", topodatapb.TabletType_name[int32(tabletType)]) } scw := &SplitCloneWorker{ @@ -507,7 +504,7 @@ func (scw *SplitCloneWorker) run(ctx context.Context) error { return vterrors.Wrap(err, "offline clone() failed") } if err := scw.setUpVReplication(ctx); err != nil { - return fmt.Errorf("failed to set up replication: %v", err) + return vterrors.Wrap(err, "failed to set up replication") } d := time.Since(start) @@ -590,7 +587,7 @@ func (scw *SplitCloneWorker) initShardsForHorizontalResharding(ctx context.Conte // find the shard we mentioned in there, if any os := topotools.OverlappingShardsForShard(osList, scw.shard) if os == nil { - return fmt.Errorf("the specified shard %v/%v is not in any overlapping shard", scw.destinationKeyspace, scw.shard) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "the specified shard %v/%v is not in any overlapping shard", scw.destinationKeyspace, scw.shard) } scw.wr.Logger().Infof("Found overlapping shards: %+v\n", os) @@ -605,7 +602,7 @@ func (scw *SplitCloneWorker) initShardsForHorizontalResharding(ctx context.Conte } if scw.useConsistentSnapshot && len(scw.sourceShards) > 1 { - return fmt.Errorf("cannot use consistent snapshot against multiple source shards") + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot use consistent snapshot against multiple source shards") } return nil @@ -613,7 +610,7 @@ func (scw *SplitCloneWorker) initShardsForHorizontalResharding(ctx context.Conte func (scw *SplitCloneWorker) initShardsForVerticalSplit(ctx context.Context) error { if len(scw.destinationKeyspaceInfo.ServedFroms) == 0 { - return fmt.Errorf("destination keyspace %v has no KeyspaceServedFrom", scw.destinationKeyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "destination keyspace %v has no KeyspaceServedFrom", scw.destinationKeyspace) } // Determine the source keyspace. @@ -621,13 +618,13 @@ func (scw *SplitCloneWorker) initShardsForVerticalSplit(ctx context.Context) err for _, st := range servingTypes { sf := scw.destinationKeyspaceInfo.GetServedFrom(st) if sf == nil { - return fmt.Errorf("destination keyspace %v is serving type %v", scw.destinationKeyspace, st) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "destination keyspace %v is serving type %v", scw.destinationKeyspace, st) } if servedFrom == "" { servedFrom = sf.Keyspace } else { if servedFrom != sf.Keyspace { - return fmt.Errorf("destination keyspace %v is serving from multiple source keyspaces %v and %v", scw.destinationKeyspace, servedFrom, sf.Keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "destination keyspace %v is serving from multiple source keyspaces %v and %v", scw.destinationKeyspace, servedFrom, sf.Keyspace) } } } @@ -640,7 +637,7 @@ func (scw *SplitCloneWorker) initShardsForVerticalSplit(ctx context.Context) err return vterrors.Wrapf(err, "cannot find source shard for source keyspace %s", sourceKeyspace) } if len(shardMap) != 1 { - return fmt.Errorf("found the wrong number of source shards, there should be only one, %v", shardMap) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "found the wrong number of source shards, there should be only one, %v", shardMap) } var sourceShard string for s := range shardMap { @@ -666,8 +663,9 @@ func (scw *SplitCloneWorker) sanityCheckShardInfos() error { // Verify that filtered replication is not already enabled. for _, si := range scw.destinationShards { if len(si.SourceShards) > 0 { - return fmt.Errorf("destination shard %v/%v has filtered replication already enabled from a previous resharding (ShardInfo is set)."+ - " This requires manual intervention e.g. use vtctl SourceShardDelete to remove it", + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, + "destination shard %v/%v has filtered replication already enabled from a previous resharding (ShardInfo is set)."+ + " This requires manual intervention e.g. use vtctl SourceShardDelete to remove it", si.Keyspace(), si.ShardName()) } } @@ -675,7 +673,7 @@ func (scw *SplitCloneWorker) sanityCheckShardInfos() error { for _, st := range servingTypes { for _, si := range scw.sourceShards { if si.GetServedType(st) == nil { - return fmt.Errorf("source shard %v/%v is not serving type %v", si.Keyspace(), si.ShardName(), st) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "source shard %v/%v is not serving type %v", si.Keyspace(), si.ShardName(), st) } } } @@ -685,7 +683,7 @@ func (scw *SplitCloneWorker) sanityCheckShardInfos() error { // Verify that the destination is not serving yet. for _, si := range scw.destinationShards { if len(si.ServedTypes) > 0 { - return fmt.Errorf("destination shard %v/%v is serving some types", si.Keyspace(), si.ShardName()) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "destination shard %v/%v is serving some types", si.Keyspace(), si.ShardName()) } } case verticalSplit: @@ -693,7 +691,7 @@ func (scw *SplitCloneWorker) sanityCheckShardInfos() error { for _, st := range servingTypes { for _, si := range scw.destinationShards { if si.GetServedType(st) == nil { - return fmt.Errorf("source shard %v/%v is not serving type %v", si.Keyspace(), si.ShardName(), st) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "source shard %v/%v is not serving type %v", si.Keyspace(), si.ShardName(), st) } } } @@ -710,7 +708,7 @@ func (scw *SplitCloneWorker) loadVSchema(ctx context.Context) error { return vterrors.Wrapf(err, "cannot load VSchema for keyspace %v", scw.destinationKeyspace) } if kschema == nil { - return fmt.Errorf("no VSchema for keyspace %v", scw.destinationKeyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "no VSchema for keyspace %v", scw.destinationKeyspace) } keyspaceSchema, err = vindexes.BuildKeyspaceSchema(kschema, scw.destinationKeyspace) @@ -756,7 +754,7 @@ func (scw *SplitCloneWorker) findOfflineSourceTablets(ctx context.Context) error err = scw.wr.TabletManagerClient().StopSlave(shortCtx, scw.sourceTablets[i]) cancel() if err != nil { - return fmt.Errorf("cannot stop replication on tablet %v", topoproto.TabletAliasString(alias)) + return vterrors.Wrapf(err, "cannot stop replication on tablet %v", topoproto.TabletAliasString(alias)) } wrangler.RecordStartSlaveAction(scw.cleaner, scw.sourceTablets[i]) @@ -771,7 +769,7 @@ func (scw *SplitCloneWorker) findTransactionalSources(ctx context.Context) error scw.setState(WorkerStateFindTargets) if len(scw.sourceShards) > 1 { - return fmt.Errorf("consistent snapshot can only be used with a single source shard") + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "consistent snapshot can only be used with a single source shard") } var err error @@ -780,7 +778,7 @@ func (scw *SplitCloneWorker) findTransactionalSources(ctx context.Context) error scw.sourceAliases = make([]*topodatapb.TabletAlias, 1) scw.sourceAliases[0], err = FindHealthyTablet(ctx, scw.wr, scw.tsc, scw.cell, si.Keyspace(), si.ShardName(), scw.minHealthyTablets, scw.tabletType) if err != nil { - return fmt.Errorf("FindHealthyTablet() failed for %v/%v/%v: %v", scw.cell, si.Keyspace(), si.ShardName(), err) + return vterrors.Wrapf(err, "FindHealthyTablet() failed for %v/%v/%v", scw.cell, si.Keyspace(), si.ShardName()) } scw.wr.Logger().Infof("Using tablet %v as source for %v/%v", topoproto.TabletAliasString(scw.sourceAliases[0]), si.Keyspace(), si.ShardName()) scw.setFormattedOfflineSources(scw.sourceAliases) @@ -791,7 +789,7 @@ func (scw *SplitCloneWorker) findTransactionalSources(ctx context.Context) error ti, err := scw.wr.TopoServer().GetTablet(shortCtx, scw.sourceAliases[0]) cancel() if err != nil { - return fmt.Errorf("cannot read tablet %v: %v", topoproto.TabletAliasString(scw.sourceAliases[0]), err) + return vterrors.Wrapf(err, "cannot read tablet %v", topoproto.TabletAliasString(scw.sourceAliases[0])) } scw.sourceTablets[0] = ti.Tablet @@ -821,7 +819,7 @@ func (scw *SplitCloneWorker) findDestinationMasters(ctx context.Context) error { } masters := scw.tsc.GetHealthyTabletStats(si.Keyspace(), si.ShardName(), topodatapb.TabletType_MASTER) if len(masters) == 0 { - return fmt.Errorf("cannot find MASTER tablet for destination shard for %v/%v (in cell: %v) in HealthCheck: empty TabletStats list", si.Keyspace(), si.ShardName(), scw.cell) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot find MASTER tablet for destination shard for %v/%v (in cell: %v) in HealthCheck: empty TabletStats list", si.Keyspace(), si.ShardName(), scw.cell) } master := masters[0] @@ -873,7 +871,7 @@ func (scw *SplitCloneWorker) findFirstSourceTablet(ctx context.Context, state St tablets := scw.tsc.GetHealthyTabletStats(si.Keyspace(), si.ShardName(), scw.tabletType) if len(tablets) == 0 { // We fail fast on this problem and don't retry because at the start all tablets should be healthy. - return nil, fmt.Errorf("no healthy %v tablet in source shard (%v) available (required to find out the schema)", topodatapb.TabletType_name[int32(scw.tabletType)], topoproto.KeyspaceShardString(si.Keyspace(), si.ShardName())) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "no healthy %v tablet in source shard (%v) available (required to find out the schema)", topodatapb.TabletType_name[int32(scw.tabletType)], topoproto.KeyspaceShardString(si.Keyspace(), si.ShardName())) } return tablets[0].Tablet, nil } @@ -931,13 +929,13 @@ func (scw *SplitCloneWorker) getSourceResultReader(ctx context.Context, td *tabl if state == WorkerStateCloneOffline && scw.useConsistentSnapshot { var err error if txID < 1 { - return nil, fmt.Errorf("tried using consistent snapshot without a valid transaction") + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "tried using consistent snapshot without a valid transaction") } tp := newShardTabletProvider(scw.tsc, scw.tabletTracker, si.Keyspace(), si.ShardName(), scw.tabletType) sourceResultReader, err = NewTransactionalRestartableResultReader(ctx, scw.wr.Logger(), tp, td, chunk, false, txID) if err != nil { closeReaders(ctx, sourceReaders) - return nil, fmt.Errorf("NewTransactionalRestartableResultReader for source: %v failed: %v", tp.description(), err) + return nil, vterrors.Wrapf(err, "NewTransactionalRestartableResultReader for source: %v failed", tp.description()) } } else { var err error @@ -957,7 +955,7 @@ func (scw *SplitCloneWorker) getSourceResultReader(ctx context.Context, td *tabl sourceResultReader, err = NewRestartableResultReader(ctx, scw.wr.Logger(), tp, td, chunk, allowMultipleRetries) if err != nil { closeReaders(ctx, sourceReaders) - return nil, fmt.Errorf("NewRestartableResultReader for source: %v failed: %v", tp.description(), err) + return nil, vterrors.Wrapf(err, "NewRestartableResultReader for source: %v failed", tp.description()) } } sourceReaders[shardIndex] = sourceResultReader @@ -978,7 +976,7 @@ func (scw *SplitCloneWorker) getDestinationResultReader(ctx context.Context, td destResultReader, err := NewRestartableResultReader(ctx, scw.wr.Logger(), tp, td, chunk, true /* allowMultipleRetries */) if err != nil { closeReaders(ctx, destReaders) - return nil, fmt.Errorf("NewRestartableResultReader for destination: %v failed: %v", tp.description(), err) + return nil, vterrors.Wrapf(err, "NewRestartableResultReader for destination: %v failed", tp.description()) } destReaders[shardIndex] = destResultReader } @@ -1061,7 +1059,7 @@ func (scw *SplitCloneWorker) startCloningData(ctx context.Context, state StatusW workPipeline := make(chan workUnit, 10) // We'll use a small buffer so producers do not run too far ahead of consumers queryService, err := tabletconn.GetDialer()(firstSourceTablet, true) if err != nil { - return fmt.Errorf("failed to create queryService: %v", err) + return vterrors.Wrap(err, "failed to create queryService") } defer queryService.Close(ctx) @@ -1089,14 +1087,14 @@ func (scw *SplitCloneWorker) startCloningData(ctx context.Context, state StatusW keyResolver, err := scw.createKeyResolver(td) if err != nil { - return fmt.Errorf("cannot resolve sharding keys for keyspace %v: %v", scw.destinationKeyspace, err) + return vterrors.Wrapf(err, "cannot resolve sharding keys for keyspace %v", scw.destinationKeyspace) } // TODO(mberlin): We're going to chunk *all* source shards based on the MIN // and MAX values of the *first* source shard. Is this going to be a problem? chunks, err := generateChunks(ctx, scw.wr, firstSourceTablet, td, scw.chunkCount, scw.minRowsPerChunk) if err != nil { - return fmt.Errorf("failed to split table into chunks: %v", err) + return vterrors.Wrap(err, "failed to split table into chunks") } tableStatusList.setThreadCount(tableIndex, len(chunks)) @@ -1156,7 +1154,7 @@ func (scw *SplitCloneWorker) clone(ctx context.Context, state StatusWorkerState) // and overwriting the variable will not cause any problems scw.wr.Logger().Errorf(format, args...) if firstError == nil { - firstError = fmt.Errorf(format, args...) + firstError = vterrors.Errorf(vtrpc.Code_INTERNAL, format, args...) cancelCopy() } } @@ -1193,7 +1191,7 @@ func (scw *SplitCloneWorker) clone(ctx context.Context, state StatusWorkerState) err = scw.startCloningData(ctx, state, sourceSchemaDefinition, processError, firstSourceTablet, tableStatusList, start, statsCounters, insertChannels, &readers) if err != nil { - return fmt.Errorf("failed to startCloningData : %v", err) + return vterrors.Wrap(err, "failed to startCloningData") } readers.Wait() @@ -1262,19 +1260,19 @@ func (scw *SplitCloneWorker) setUpVReplication(ctx context.Context) error { // TODO(mberlin): Fill in scw.maxReplicationLag once the adapative throttler is enabled by default. qr, err := exc.vreplicationExec(cancelableCtx, binlogplayer.CreateVReplication("SplitClone", bls, sourcePositions[shardIndex], scw.maxTPS, throttler.ReplicationLagModuleDisabled, time.Now().Unix())) if err != nil { - handleError(fmt.Errorf("vreplication queries failed: %v", err)) + handleError(vterrors.Wrap(err, "vreplication queries failed")) cancel() return } if err := scw.wr.SourceShardAdd(cancelableCtx, keyspace, shard, uint32(qr.InsertID), src.Keyspace(), src.ShardName(), src.Shard.KeyRange, scw.tables); err != nil { - handleError(fmt.Errorf("could not add source shard: %v", err)) + handleError(vterrors.Wrap(err, "could not add source shard")) break } } // refreshState will cause the destination to become non-serving because // it's now participating in the resharding workflow. if err := exc.refreshState(ctx); err != nil { - handleError(fmt.Errorf("RefreshState failed on tablet %v/%v: %v", keyspace, shard, err)) + handleError(vterrors.Wrapf(err, "RefreshState failed on tablet %v/%v", keyspace, shard)) } }(si.Keyspace(), si.ShardName(), si.KeyRange) } @@ -1296,11 +1294,11 @@ func (scw *SplitCloneWorker) getSourceSchema(ctx context.Context, tablet *topoda return nil, vterrors.Wrapf(err, "cannot get schema from source %v", topoproto.TabletAliasString(tablet.Alias)) } if len(sourceSchemaDefinition.TableDefinitions) == 0 { - return nil, fmt.Errorf("no tables matching the table filter in tablet %v", topoproto.TabletAliasString(tablet.Alias)) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "no tables matching the table filter in tablet %v", topoproto.TabletAliasString(tablet.Alias)) } for _, td := range sourceSchemaDefinition.TableDefinitions { if len(td.Columns) == 0 { - return nil, fmt.Errorf("schema for table %v has no columns", td.Name) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "schema for table %v has no columns", td.Name) } } return sourceSchemaDefinition, nil diff --git a/go/vt/worker/split_clone_cmd.go b/go/vt/worker/split_clone_cmd.go index e3d1085560d..b5f19acbd1a 100644 --- a/go/vt/worker/split_clone_cmd.go +++ b/go/vt/worker/split_clone_cmd.go @@ -26,6 +26,7 @@ import ( "sync" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/concurrency" "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/vt/proto/vtrpc" @@ -188,7 +189,7 @@ func keyspacesWithOverlappingShards(ctx context.Context, wr *wrangler.Wrangler) return nil, rec.Error() } if len(result) == 0 { - return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "there are no keyspaces with overlapping shards") + return nil, vterrors.New(vtrpc.Code_FAILED_PRECONDITION, "there are no keyspaces with overlapping shards") } return result, nil } @@ -310,4 +311,4 @@ func init() { commandSplitClone, interactiveSplitClone, "[--online=false] [--offline=false] [--exclude_tables=''] ", "Replicates the data and creates configuration for a horizontal split."}) -} \ No newline at end of file +} diff --git a/go/vt/worker/split_diff.go b/go/vt/worker/split_diff.go index 82c3211f017..43050b13038 100644 --- a/go/vt/worker/split_diff.go +++ b/go/vt/worker/split_diff.go @@ -17,11 +17,11 @@ limitations under the License. package worker import ( - "fmt" "html/template" "sort" "sync" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" @@ -201,13 +201,13 @@ func (sdw *SplitDiffWorker) init(ctx context.Context) error { } if len(sdw.shardInfo.SourceShards) == 0 { - return fmt.Errorf("shard %v/%v has no source shard", sdw.keyspace, sdw.shard) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "shard %v/%v has no source shard", sdw.keyspace, sdw.shard) } if sdw.sourceUID == 0 { if len(sdw.shardInfo.SourceShards) == 1 { sdw.sourceShard = sdw.shardInfo.SourceShards[0] } else { - return fmt.Errorf("shard %v/%v has more than one source, please specify a source UID", sdw.keyspace, sdw.shard) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "shard %v/%v has more than one source, please specify a source UID", sdw.keyspace, sdw.shard) } } else { for _, ss := range sdw.shardInfo.SourceShards { @@ -218,11 +218,11 @@ func (sdw *SplitDiffWorker) init(ctx context.Context) error { } } if sdw.sourceShard == nil { - return fmt.Errorf("shard %v/%v has no source shard with UID %v", sdw.keyspace, sdw.shard, sdw.sourceUID) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "shard %v/%v has no source shard with UID %v", sdw.keyspace, sdw.shard, sdw.sourceUID) } if !sdw.shardInfo.HasMaster() { - return fmt.Errorf("shard %v/%v has no master", sdw.keyspace, sdw.shard) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "shard %v/%v has no master", sdw.keyspace, sdw.shard) } return nil @@ -262,7 +262,7 @@ func (sdw *SplitDiffWorker) findTargets(ctx context.Context) error { for { select { case <-shortCtx.Done(): - return fmt.Errorf("Could not find healthy table for %v/%v%v: after: %v, aborting", sdw.cell, sdw.keyspace, sdw.sourceShard.Shard, *remoteActionsTimeout) + return vterrors.Errorf(vtrpc.Code_ABORTED, "could not find healthy table for %v/%v%v: after: %v, aborting", sdw.cell, sdw.keyspace, sdw.sourceShard.Shard, *remoteActionsTimeout) default: sdw.sourceAlias, err = FindWorkerTablet(ctx, sdw.wr, sdw.cleaner, nil /* tsc */, sdw.cell, sdw.keyspace, sdw.sourceShard.Shard, sdw.minHealthyRdonlyTablets, topodatapb.TabletType_RDONLY) if err != nil { @@ -319,7 +319,7 @@ func (sdw *SplitDiffWorker) synchronizeReplication(ctx context.Context) error { } qr := sqltypes.Proto3ToResult(p3qr) if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { - return fmt.Errorf("Unexpected result while reading position: %v", qr) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "Unexpected result while reading position: %v", qr) } vreplicationPos := qr.Rows[0][0].ToString() @@ -446,7 +446,7 @@ func (sdw *SplitDiffWorker) diff(ctx context.Context) error { return vterrors.Wrapf(err, "cannot load VSchema for keyspace %v", sdw.keyspace) } if kschema == nil { - return fmt.Errorf("no VSchema for keyspace %v", sdw.keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "no VSchema for keyspace %v", sdw.keyspace) } keyspaceSchema, err = vindexes.BuildKeyspaceSchema(kschema, sdw.keyspace) @@ -537,12 +537,12 @@ func (sdw *SplitDiffWorker) diff(ctx context.Context) error { // And run the diff. report, err := differ.Go(sdw.wr.Logger()) if err != nil { - newErr := fmt.Errorf("Differ.Go failed: %v", err.Error()) + newErr := vterrors.Wrapf(err, "Differ.Go failed") sdw.markAsWillFail(rec, newErr) sdw.wr.Logger().Error(newErr) } else { if report.HasDifferences() { - err := fmt.Errorf("Table %v has differences: %v", tableDefinition.Name, report.String()) + err := vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "table %v has differences: %v", tableDefinition.Name, report.String()) sdw.markAsWillFail(rec, err) sdw.wr.Logger().Warningf(err.Error()) } else { diff --git a/go/vt/worker/split_diff_cmd.go b/go/vt/worker/split_diff_cmd.go index 460c8587c92..7720b162c5e 100644 --- a/go/vt/worker/split_diff_cmd.go +++ b/go/vt/worker/split_diff_cmd.go @@ -25,6 +25,7 @@ import ( "strings" "sync" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" "golang.org/x/net/context" @@ -91,7 +92,7 @@ func commandSplitDiff(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.FlagSe } if subFlags.NArg() != 1 { subFlags.Usage() - return nil, fmt.Errorf("command SplitDiff requires ") + return nil, vterrors.New(vtrpc.Code_INVALID_ARGUMENT, "command SplitDiff requires ") } keyspace, shard, err := topoproto.ParseKeyspaceShard(subFlags.Arg(0)) if err != nil { @@ -104,7 +105,7 @@ func commandSplitDiff(wi *Instance, wr *wrangler.Wrangler, subFlags *flag.FlagSe destTabletType, ok := topodatapb.TabletType_value[*destTabletTypeStr] if !ok { - return nil, fmt.Errorf("command SplitDiff invalid dest_tablet_type: %v", destTabletType) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "command SplitDiff invalid dest_tablet_type: %v", destTabletType) } return NewSplitDiffWorker(wr, wi.cell, keyspace, shard, uint32(*sourceUID), excludeTableArray, *minHealthyRdonlyTablets, *parallelDiffsCount, topodatapb.TabletType(destTabletType)), nil @@ -165,7 +166,7 @@ func shardsWithSources(ctx context.Context, wr *wrangler.Wrangler) ([]map[string return nil, rec.Error() } if len(result) == 0 { - return nil, fmt.Errorf("there are no shards with SourceShards") + return nil, vterrors.New(vtrpc.Code_FAILED_PRECONDITION, "there are no shards with SourceShards") } return result, nil } diff --git a/go/vt/worker/table_status.go b/go/vt/worker/table_status.go index fadaf4071b4..026a1790109 100644 --- a/go/vt/worker/table_status.go +++ b/go/vt/worker/table_status.go @@ -22,6 +22,8 @@ import ( "time" "vitess.io/vitess/go/vt/mysqlctl/tmutils" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" ) @@ -46,7 +48,7 @@ func (t *tableStatusList) initialize(schema *tabletmanagerdatapb.SchemaDefinitio defer t.mu.Unlock() if t.initialized { - panic(fmt.Errorf("tableStatusList is already initialized: %v", t.tableStatuses)) + panic(vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "tableStatusList is already initialized: %v", t.tableStatuses)) } t.tableStatuses = make([]*tableStatus, len(schema.TableDefinitions)) diff --git a/go/vt/worker/vtworkerclient/interface.go b/go/vt/worker/vtworkerclient/interface.go index 3eca9edaa79..b7796de18e4 100644 --- a/go/vt/worker/vtworkerclient/interface.go +++ b/go/vt/worker/vtworkerclient/interface.go @@ -19,11 +19,12 @@ package vtworkerclient import ( "flag" - "fmt" "golang.org/x/net/context" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/logutil" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // protocol specifices which RPC client implementation should be used. @@ -67,7 +68,7 @@ func UnregisterFactoryForTest(name string) { func New(addr string) (Client, error) { factory, ok := factories[*protocol] if !ok { - return nil, fmt.Errorf("unknown vtworker client protocol: %v", *protocol) + return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "unknown vtworker client protocol: %v", *protocol) } return factory(addr) } From c6cae699f0a68802de89dd797b175cdc20c680d0 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Wed, 27 Feb 2019 11:06:46 +0100 Subject: [PATCH 123/196] Use vterrors in the mysql package Signed-off-by: Andres Taylor --- go/mysql/auth_server.go | 7 +++-- go/mysql/auth_server_static.go | 5 +-- go/mysql/binlog_event_common.go | 17 +++++----- go/mysql/binlog_event_json.go | 12 ++++--- go/mysql/binlog_event_json_test.go | 27 +++++++++------- go/mysql/binlog_event_mariadb.go | 6 ++-- go/mysql/binlog_event_mysql56.go | 6 ++-- go/mysql/binlog_event_rbr.go | 26 +++++++++------- go/mysql/charset.go | 6 ++-- go/mysql/client.go | 8 +++-- go/mysql/conn.go | 50 ++++++++++++++++-------------- go/mysql/flavor.go | 6 ++-- go/mysql/flavor_mariadb.go | 14 +++++---- go/mysql/flavor_mysql.go | 10 +++--- go/mysql/gtid.go | 5 ++- go/mysql/mariadb_gtid.go | 11 ++++--- go/mysql/mysql56_gtid.go | 13 +++++--- go/mysql/mysql56_gtid_set.go | 28 +++++++++-------- go/mysql/query.go | 12 +++---- go/mysql/replication_position.go | 5 ++- go/mysql/server.go | 45 ++++++++++++++------------- go/mysql/slave_status.go | 5 ++- go/mysql/sql_error.go | 1 + 23 files changed, 183 insertions(+), 142 deletions(-) diff --git a/go/mysql/auth_server.go b/go/mysql/auth_server.go index 83d0c5e04f8..03470b79a53 100644 --- a/go/mysql/auth_server.go +++ b/go/mysql/auth_server.go @@ -21,11 +21,12 @@ import ( "crypto/rand" "crypto/sha1" "encoding/hex" - "fmt" "net" "strings" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // AuthServer is the interface that servers must implement to validate @@ -226,7 +227,7 @@ func AuthServerReadPacketString(c *Conn) (string, error) { return "", err } if len(data) == 0 || data[len(data)-1] != 0 { - return "", fmt.Errorf("received invalid response packet, datalen=%v", len(data)) + return "", vterrors.Errorf(vtrpc.Code_INTERNAL, "received invalid response packet, datalen=%v", len(data)) } return string(data[:len(data)-1]), nil } @@ -244,6 +245,6 @@ func AuthServerNegotiateClearOrDialog(c *Conn, method string) (string, error) { return AuthServerReadPacketString(c) default: - return "", fmt.Errorf("unrecognized method: %v", method) + return "", vterrors.Errorf(vtrpc.Code_INTERNAL, "unrecognized method: %v", method) } } diff --git a/go/mysql/auth_server_static.go b/go/mysql/auth_server_static.go index 290de7a2b87..f4c068f9662 100644 --- a/go/mysql/auth_server_static.go +++ b/go/mysql/auth_server_static.go @@ -20,7 +20,6 @@ import ( "bytes" "encoding/json" "flag" - "fmt" "io/ioutil" "net" "os" @@ -30,6 +29,8 @@ import ( "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) var ( @@ -180,7 +181,7 @@ func validateConfig(config map[string][]*AuthServerStaticEntry) error { for _, entries := range config { for _, entry := range entries { if entry.SourceHost != "" && entry.SourceHost != localhostName { - return fmt.Errorf("Invalid SourceHost found (only localhost is supported): %v", entry.SourceHost) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "Invalid SourceHost found (only localhost is supported): %v", entry.SourceHost) } } } diff --git a/go/mysql/binlog_event_common.go b/go/mysql/binlog_event_common.go index afb462051f9..5765fbb0342 100644 --- a/go/mysql/binlog_event_common.go +++ b/go/mysql/binlog_event_common.go @@ -19,9 +19,10 @@ package mysql import ( "bytes" "encoding/binary" - "fmt" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // binlogEvent wraps a raw packet buffer and provides methods to examine it @@ -185,12 +186,12 @@ func (ev binlogEvent) Format() (f BinlogFormat, err error) { f.FormatVersion = binary.LittleEndian.Uint16(data[:2]) if f.FormatVersion != 4 { - return f, fmt.Errorf("format version = %d, we only support version 4", f.FormatVersion) + return f, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "format version = %d, we only support version 4", f.FormatVersion) } f.ServerVersion = string(bytes.TrimRight(data[2:2+50], "\x00")) f.HeaderLength = data[2+50+4] if f.HeaderLength < 19 { - return f, fmt.Errorf("header length = %d, should be >= 19", f.HeaderLength) + return f, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "header length = %d, should be >= 19", f.HeaderLength) } // MySQL/MariaDB 5.6.1+ always adds a 4-byte checksum to the end of a @@ -230,7 +231,7 @@ func (ev binlogEvent) Query(f BinlogFormat) (query Query, err error) { // position of SQL query sqlPos := dbPos + dbLen + 1 // +1 for NULL terminator if sqlPos > len(data) { - return query, fmt.Errorf("SQL query position overflows buffer (%v > %v)", sqlPos, len(data)) + return query, vterrors.Errorf(vtrpc.Code_INTERNAL, "SQL query position overflows buffer (%v > %v)", sqlPos, len(data)) } // We've checked that the buffer is big enough for sql, so everything before @@ -257,17 +258,17 @@ varsLoop: pos += 8 case QCatalog: // Used in MySQL 5.0.0 - 5.0.3 if pos+1 > len(vars) { - return query, fmt.Errorf("Q_CATALOG status var overflows buffer (%v + 1 > %v)", pos, len(vars)) + return query, vterrors.Errorf(vtrpc.Code_INTERNAL, "Q_CATALOG status var overflows buffer (%v + 1 > %v)", pos, len(vars)) } pos += 1 + int(vars[pos]) + 1 case QCatalogNZCode: // Used in MySQL > 5.0.3 to replace QCatalog if pos+1 > len(vars) { - return query, fmt.Errorf("Q_CATALOG_NZ_CODE status var overflows buffer (%v + 1 > %v)", pos, len(vars)) + return query, vterrors.Errorf(vtrpc.Code_INTERNAL, "Q_CATALOG_NZ_CODE status var overflows buffer (%v + 1 > %v)", pos, len(vars)) } pos += 1 + int(vars[pos]) case QCharsetCode: if pos+6 > len(vars) { - return query, fmt.Errorf("Q_CHARSET_CODE status var overflows buffer (%v + 6 > %v)", pos, len(vars)) + return query, vterrors.Errorf(vtrpc.Code_INTERNAL, "Q_CHARSET_CODE status var overflows buffer (%v + 6 > %v)", pos, len(vars)) } query.Charset = &binlogdatapb.Charset{ Client: int32(binary.LittleEndian.Uint16(vars[pos : pos+2])), @@ -295,7 +296,7 @@ func (ev binlogEvent) IntVar(f BinlogFormat) (byte, uint64, error) { typ := data[0] if typ != IntVarLastInsertID && typ != IntVarInsertID { - return 0, 0, fmt.Errorf("invalid IntVar ID: %v", data[0]) + return 0, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid IntVar ID: %v", data[0]) } value := binary.LittleEndian.Uint64(data[1 : 1+8]) diff --git a/go/mysql/binlog_event_json.go b/go/mysql/binlog_event_json.go index a59c3a759ac..800af6a1c8d 100644 --- a/go/mysql/binlog_event_json.go +++ b/go/mysql/binlog_event_json.go @@ -25,6 +25,8 @@ import ( "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) const ( @@ -97,7 +99,7 @@ func printJSONValue(typ byte, data []byte, toplevel bool, result *bytes.Buffer) case jsonTypeOpaque: return printJSONOpaque(data, toplevel, result) default: - return fmt.Errorf("unknown object type in JSON: %v", typ) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "unknown object type in JSON: %v", typ) } return nil @@ -108,7 +110,7 @@ func printJSONObject(data []byte, large bool, result *bytes.Buffer) error { elementCount, pos := readOffsetOrSize(data, pos, large) size, pos := readOffsetOrSize(data, pos, large) if size > len(data) { - return fmt.Errorf("not enough data for object, have %v bytes need %v", len(data), size) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "not enough data for object, have %v bytes need %v", len(data), size) } // Build an array for each key. @@ -152,7 +154,7 @@ func printJSONArray(data []byte, large bool, result *bytes.Buffer) error { elementCount, pos := readOffsetOrSize(data, pos, large) size, pos := readOffsetOrSize(data, pos, large) if size > len(data) { - return fmt.Errorf("not enough data for object, have %v bytes need %v", len(data), size) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "not enough data for object, have %v bytes need %v", len(data), size) } // Now read each value, and output them. The value entry is @@ -231,7 +233,7 @@ func printJSONLiteral(b byte, toplevel bool, result *bytes.Buffer) error { case jsonFalseLiteral: result.WriteString("false") default: - return fmt.Errorf("unknown literal value %v", b) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "unknown literal value %v", b) } if toplevel { result.WriteByte('\'') @@ -374,7 +376,7 @@ func printJSONOpaque(data []byte, toplevel bool, result *bytes.Buffer) error { // not straightforward (for instance, a bit field seems to // have one byte as metadata, not two as would be expected). // To be on the safer side, we just reject these cases for now. - return fmt.Errorf("opaque type %v is not supported yet, with data %v", typ, data[1:]) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "opaque type %v is not supported yet, with data %v", typ, data[1:]) } func printJSONDate(data []byte, toplevel bool, result *bytes.Buffer) error { diff --git a/go/mysql/binlog_event_json_test.go b/go/mysql/binlog_event_json_test.go index a1b25f9889f..22658a0096d 100644 --- a/go/mysql/binlog_event_json_test.go +++ b/go/mysql/binlog_event_json_test.go @@ -17,7 +17,7 @@ limitations under the License. package mysql import ( - "fmt" + "strings" "testing" ) @@ -123,19 +123,22 @@ func TestJSON(t *testing.T) { }, { // opaque, bit field. Not yet implemented. data: []byte{15, 16, 2, 202, 254}, - expected: `ERROR: opaque type 16 is not supported yet, with data [2 202 254]`, + expected: `opaque type 16 is not supported yet, with data [2 202 254]`, }} for _, tcase := range testcases { - r, err := printJSONData(tcase.data) - got := "" - if err != nil { - got = fmt.Sprintf("ERROR: %v", err) - } else { - got = string(r) - } - if got != tcase.expected { - t.Errorf("unexpected output for %v: got %v expected %v", tcase.data, got, tcase.expected) - } + t.Run(tcase.expected, func(t *testing.T) { + r, err := printJSONData(tcase.data) + if err != nil { + if got := err.Error(); !strings.HasPrefix(got, tcase.expected) { + t.Errorf("unexpected output for %v: got [%v] expected [%v]", tcase.data, got, tcase.expected) + } + } else { + if got := string(r); got != tcase.expected { + t.Errorf("unexpected output for %v: got [%v] expected [%v]", tcase.data, got, tcase.expected) + } + } + + }) } } diff --git a/go/mysql/binlog_event_mariadb.go b/go/mysql/binlog_event_mariadb.go index 22472cb2b9e..7b7548c520d 100644 --- a/go/mysql/binlog_event_mariadb.go +++ b/go/mysql/binlog_event_mariadb.go @@ -18,7 +18,9 @@ package mysql import ( "encoding/binary" - "fmt" + + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // mariadbBinlogEvent wraps a raw packet buffer and provides methods to examine @@ -60,7 +62,7 @@ func (ev mariadbBinlogEvent) GTID(f BinlogFormat) (GTID, bool, error) { // PreviousGTIDs implements BinlogEvent.PreviousGTIDs(). func (ev mariadbBinlogEvent) PreviousGTIDs(f BinlogFormat) (Position, error) { - return Position{}, fmt.Errorf("MariaDB should not provide PREVIOUS_GTIDS_EVENT events") + return Position{}, vterrors.Errorf(vtrpc.Code_INTERNAL, "MariaDB should not provide PREVIOUS_GTIDS_EVENT events") } // StripChecksum implements BinlogEvent.StripChecksum(). diff --git a/go/mysql/binlog_event_mysql56.go b/go/mysql/binlog_event_mysql56.go index 7437df86c7a..c83c196bb09 100644 --- a/go/mysql/binlog_event_mysql56.go +++ b/go/mysql/binlog_event_mysql56.go @@ -18,7 +18,9 @@ package mysql import ( "encoding/binary" - "fmt" + + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // mysql56BinlogEvent wraps a raw packet buffer and provides methods to examine @@ -81,6 +83,6 @@ func (ev mysql56BinlogEvent) StripChecksum(f BinlogFormat) (BinlogEvent, []byte, default: // MySQL 5.6 does not guarantee that future checksum algorithms will be // 4 bytes, so we can't support them a priori. - return ev, nil, fmt.Errorf("unsupported checksum algorithm: %v", f.ChecksumAlgorithm) + return ev, nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported checksum algorithm: %v", f.ChecksumAlgorithm) } } diff --git a/go/mysql/binlog_event_rbr.go b/go/mysql/binlog_event_rbr.go index a8ec52dd05b..2d12ffc52c9 100644 --- a/go/mysql/binlog_event_rbr.go +++ b/go/mysql/binlog_event_rbr.go @@ -25,6 +25,8 @@ import ( "time" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" querypb "vitess.io/vitess/go/vt/proto/query" ) @@ -89,7 +91,7 @@ func (ev binlogEvent) TableMap(f BinlogFormat) (*TableMap, error) { } } if pos != expectedEnd { - return nil, fmt.Errorf("unexpected metadata end: got %v was expecting %v (data=%v)", pos, expectedEnd, data) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected metadata end: got %v was expecting %v (data=%v)", pos, expectedEnd, data) } // A bit array that says if each colum can be NULL. @@ -119,7 +121,7 @@ func metadataLength(typ byte) int { default: // Unknown type. This is used in tests only, so panic. - panic(fmt.Errorf("metadataLength: unhandled data type: %v", typ)) + panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "metadataLength: unhandled data type: %v", typ)) } } @@ -155,7 +157,7 @@ func metadataRead(data []byte, pos int, typ byte) (uint16, int, error) { default: // Unknown types, we can't go on. - return 0, 0, fmt.Errorf("metadataRead: unhandled data type: %v", typ) + return 0, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "metadataRead: unhandled data type: %v", typ) } } @@ -186,7 +188,7 @@ func metadataWrite(data []byte, pos int, typ byte, value uint16) int { default: // Unknown type. This is used in tests only, so panic. - panic(fmt.Errorf("metadataRead: unhandled data type: %v", typ)) + panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "metadataRead: unhandled data type: %v", typ)) } } @@ -286,7 +288,7 @@ func cellLength(data []byte, pos int, typ byte, metadata uint16) (int, error) { uint32(data[pos+2])<<16| uint32(data[pos+3])<<24), nil default: - return 0, fmt.Errorf("unsupported blob/geometry metadata value %v (data: %v pos: %v)", metadata, data, pos) + return 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported blob/geometry metadata value %v (data: %v pos: %v)", metadata, data, pos) } case TypeString: // This may do String, Enum, and Set. The type is in @@ -307,7 +309,7 @@ func cellLength(data []byte, pos int, typ byte, metadata uint16) (int, error) { return l + 1, nil default: - return 0, fmt.Errorf("unsupported type %v (data: %v pos: %v)", typ, data, pos) + return 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported type %v (data: %v pos: %v)", typ, data, pos) } } @@ -772,7 +774,7 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ return sqltypes.MakeTrusted(querypb.Type_ENUM, strconv.AppendUint(nil, uint64(val), 10)), 2, nil default: - return sqltypes.NULL, 0, fmt.Errorf("unexpected enum size: %v", metadata&0xff) + return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected enum size: %v", metadata&0xff) } case TypeSet: @@ -800,7 +802,7 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ uint32(data[pos+2])<<16 | uint32(data[pos+3])<<24) default: - return sqltypes.NULL, 0, fmt.Errorf("unsupported blob metadata value %v (data: %v pos: %v)", metadata, data, pos) + return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported blob metadata value %v (data: %v pos: %v)", metadata, data, pos) } pos += int(metadata) @@ -808,7 +810,7 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ if typ == TypeJSON { d, err := printJSONData(data[pos : pos+l]) if err != nil { - return sqltypes.NULL, 0, fmt.Errorf("error parsing JSON data %v: %v", data[pos:pos+l], err) + return sqltypes.NULL, 0, vterrors.Wrapf(err, "error parsing JSON data %v", data[pos:pos+l]) } return sqltypes.MakeTrusted(sqltypes.Expression, d), l + int(metadata), nil @@ -835,7 +837,7 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ return sqltypes.MakeTrusted(querypb.Type_UINT16, strconv.AppendUint(nil, uint64(val), 10)), 2, nil default: - return sqltypes.NULL, 0, fmt.Errorf("unexpected enum size: %v", metadata&0xff) + return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected enum size: %v", metadata&0xff) } } if t == TypeSet { @@ -892,14 +894,14 @@ func CellValue(data []byte, pos int, typ byte, metadata uint16, styp querypb.Typ uint32(data[pos+2])<<16 | uint32(data[pos+3])<<24) default: - return sqltypes.NULL, 0, fmt.Errorf("unsupported geometry metadata value %v (data: %v pos: %v)", metadata, data, pos) + return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported geometry metadata value %v (data: %v pos: %v)", metadata, data, pos) } pos += int(metadata) return sqltypes.MakeTrusted(querypb.Type_GEOMETRY, data[pos:pos+l]), l + int(metadata), nil default: - return sqltypes.NULL, 0, fmt.Errorf("unsupported type %v", typ) + return sqltypes.NULL, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unsupported type %v", typ) } } diff --git a/go/mysql/charset.go b/go/mysql/charset.go index ddc9c035859..8c211385646 100644 --- a/go/mysql/charset.go +++ b/go/mysql/charset.go @@ -21,6 +21,8 @@ import ( "strconv" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // This file contains utility methods for Conn objects. Only useful on the client @@ -34,10 +36,10 @@ func ExecuteFetchMap(conn *Conn, query string) (map[string]string, error) { return nil, err } if len(qr.Rows) != 1 { - return nil, fmt.Errorf("query %#v returned %d rows, expected 1", query, len(qr.Rows)) + return nil, vterrors.Errorf(vtrpc.Code_OUT_OF_RANGE, "query %#v returned %d rows, expected 1", query, len(qr.Rows)) } if len(qr.Fields) != len(qr.Rows[0]) { - return nil, fmt.Errorf("query %#v returned %d column names, expected %d", query, len(qr.Fields), len(qr.Rows[0])) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "query %#v returned %d column names, expected %d", query, len(qr.Fields), len(qr.Rows[0])) } rowMap := make(map[string]string) diff --git a/go/mysql/client.go b/go/mysql/client.go index 1cc117a8f6e..ae851336beb 100644 --- a/go/mysql/client.go +++ b/go/mysql/client.go @@ -25,6 +25,8 @@ import ( "time" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vttls" ) @@ -185,7 +187,7 @@ func (c *Conn) Ping() error { case ErrPacket: return ParseErrorPacket(data) } - return fmt.Errorf("unexpected packet type: %d", data[0]) + return vterrors.Errorf(vtrpc.Code_INTERNAL,"unexpected packet type: %d", data[0]) } // parseCharacterSet parses the provided character set. @@ -634,7 +636,7 @@ func parseAuthSwitchRequest(data []byte) (string, []byte, error) { pos := 1 pluginName, pos, ok := readNullString(data, pos) if !ok { - return "", nil, fmt.Errorf("cannot get plugin name from AuthSwitchRequest: %v", data) + return "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "cannot get plugin name from AuthSwitchRequest: %v", data) } return pluginName, data[pos:], nil @@ -649,7 +651,7 @@ func (c *Conn) writeClearTextPassword(params *ConnParams) error { pos = writeNullString(data, pos, params.Pass) // Sanity check. if pos != len(data) { - return fmt.Errorf("error building ClearTextPassword packet: got %v bytes expected %v", pos, len(data)) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "error building ClearTextPassword packet: got %v bytes expected %v", pos, len(data)) } return c.writeEphemeralPacket() } diff --git a/go/mysql/conn.go b/go/mysql/conn.go index e14ffa941dd..a6c26df30ab 100644 --- a/go/mysql/conn.go +++ b/go/mysql/conn.go @@ -31,7 +31,9 @@ import ( "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/vt/log" querypb "vitess.io/vitess/go/vt/proto/query" + "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/sqlparser" + "vitess.io/vitess/go/vt/vterrors" ) const ( @@ -247,12 +249,12 @@ func (c *Conn) readHeaderFrom(r io.Reader) (int, error) { if strings.HasSuffix(err.Error(), "read: connection reset by peer") { return 0, io.EOF } - return 0, fmt.Errorf("io.ReadFull(header size) failed: %v", err) + return 0, vterrors.Wrapf(err, "io.ReadFull(header size) failed") } sequence := uint8(header[3]) if sequence != c.sequence { - return 0, fmt.Errorf("invalid sequence, expected %v got %v", c.sequence, sequence) + return 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid sequence, expected %v got %v", c.sequence, sequence) } c.sequence++ @@ -270,7 +272,7 @@ func (c *Conn) readHeaderFrom(r io.Reader) (int, error) { // it most likely will be io.EOF. func (c *Conn) readEphemeralPacket() ([]byte, error) { if c.currentEphemeralPolicy != ephemeralUnused { - panic(fmt.Errorf("readEphemeralPacket: unexpected currentEphemeralPolicy: %v", c.currentEphemeralPolicy)) + panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "readEphemeralPacket: unexpected currentEphemeralPolicy: %v", c.currentEphemeralPolicy)) } r := c.getReader() @@ -291,7 +293,7 @@ func (c *Conn) readEphemeralPacket() ([]byte, error) { if length < MaxPacketSize { c.currentEphemeralBuffer = bufPool.Get(length) if _, err := io.ReadFull(r, *c.currentEphemeralBuffer); err != nil { - return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err) + return nil, vterrors.Wrapf(err, "io.ReadFull(packet body of length %v) failed", length) } return *c.currentEphemeralBuffer, nil } @@ -301,7 +303,7 @@ func (c *Conn) readEphemeralPacket() ([]byte, error) { // optimize this code path easily. data := make([]byte, length) if _, err := io.ReadFull(r, data); err != nil { - return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err) + return nil, vterrors.Wrapf(err, "io.ReadFull(packet body of length %v) failed", length) } for { next, err := c.readOnePacket() @@ -330,7 +332,7 @@ func (c *Conn) readEphemeralPacket() ([]byte, error) { // This function usually shouldn't be used - use readEphemeralPacket. func (c *Conn) readEphemeralPacketDirect() ([]byte, error) { if c.currentEphemeralPolicy != ephemeralUnused { - panic(fmt.Errorf("readEphemeralPacketDirect: unexpected currentEphemeralPolicy: %v", c.currentEphemeralPolicy)) + panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "readEphemeralPacketDirect: unexpected currentEphemeralPolicy: %v", c.currentEphemeralPolicy)) } var r io.Reader = c.conn @@ -350,12 +352,12 @@ func (c *Conn) readEphemeralPacketDirect() ([]byte, error) { if length < MaxPacketSize { c.currentEphemeralBuffer = bufPool.Get(length) if _, err := io.ReadFull(r, *c.currentEphemeralBuffer); err != nil { - return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err) + return nil, vterrors.Wrapf(err, "io.ReadFull(packet body of length %v) failed", length) } return *c.currentEphemeralBuffer, nil } - return nil, fmt.Errorf("readEphemeralPacketDirect doesn't support more than one packet") + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "readEphemeralPacketDirect doesn't support more than one packet") } // recycleReadPacket recycles the read packet. It needs to be called @@ -363,7 +365,7 @@ func (c *Conn) readEphemeralPacketDirect() ([]byte, error) { func (c *Conn) recycleReadPacket() { if c.currentEphemeralPolicy != ephemeralRead { // Programming error. - panic(fmt.Errorf("trying to call recycleReadPacket while currentEphemeralPolicy is %d", c.currentEphemeralPolicy)) + panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "trying to call recycleReadPacket while currentEphemeralPolicy is %d", c.currentEphemeralPolicy)) } if c.currentEphemeralBuffer != nil { // We are using the pool, put the buffer back in. @@ -388,7 +390,7 @@ func (c *Conn) readOnePacket() ([]byte, error) { data := make([]byte, length) if _, err := io.ReadFull(r, data); err != nil { - return nil, fmt.Errorf("io.ReadFull(packet body of length %v) failed: %v", length, err) + return nil, vterrors.Wrapf(err, "io.ReadFull(packet body of length %v) failed", length) } return data, nil } @@ -467,16 +469,16 @@ func (c *Conn) writePacket(data []byte) error { header[2] = byte(packetLength >> 16) header[3] = c.sequence if n, err := w.Write(header[:]); err != nil { - return fmt.Errorf("Write(header) failed: %v", err) + return vterrors.Wrapf(err, "Write(header) failed") } else if n != 4 { - return fmt.Errorf("Write(header) returned a short write: %v < 4", n) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "Write(header) returned a short write: %v < 4", n) } // Write the body. if n, err := w.Write(data[index : index+packetLength]); err != nil { - return fmt.Errorf("Write(packet) failed: %v", err) + return vterrors.Wrapf(err, "Write(packet) failed") } else if n != packetLength { - return fmt.Errorf("Write(packet) returned a short write: %v < %v", n, packetLength) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "Write(packet) returned a short write: %v < %v", n, packetLength) } // Update our state. @@ -492,9 +494,9 @@ func (c *Conn) writePacket(data []byte) error { header[2] = 0 header[3] = c.sequence if n, err := w.Write(header[:]); err != nil { - return fmt.Errorf("Write(empty header) failed: %v", err) + return vterrors.Wrapf(err, "Write(empty header) failed") } else if n != 4 { - return fmt.Errorf("Write(empty header) returned a short write: %v < 4", n) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "Write(empty header) returned a short write: %v < 4", n) } c.sequence++ } @@ -523,11 +525,11 @@ func (c *Conn) writeEphemeralPacket() error { switch c.currentEphemeralPolicy { case ephemeralWrite: if err := c.writePacket(*c.currentEphemeralBuffer); err != nil { - return fmt.Errorf("Conn %v: %v", c.ID(), err) + return vterrors.Wrapf(err, "Conn %v", c.ID()) } case ephemeralUnused, ephemeralRead: // Programming error. - panic(fmt.Errorf("Conn %v: trying to call writeEphemeralPacket while currentEphemeralPolicy is %v", c.ID(), c.currentEphemeralPolicy)) + panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "Conn %v: trying to call writeEphemeralPacket while currentEphemeralPolicy is %v", c.ID(), c.currentEphemeralPolicy)) } return nil @@ -538,7 +540,7 @@ func (c *Conn) writeEphemeralPacket() error { func (c *Conn) recycleWritePacket() { if c.currentEphemeralPolicy != ephemeralWrite { // Programming error. - panic(fmt.Errorf("trying to call recycleWritePacket while currentEphemeralPolicy is %d", c.currentEphemeralPolicy)) + panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "trying to call recycleWritePacket while currentEphemeralPolicy is %d", c.currentEphemeralPolicy)) } // Release our reference so the buffer can be gced bufPool.Put(c.currentEphemeralBuffer) @@ -915,7 +917,7 @@ func parseEOFPacket(data []byte) (warnings uint16, more bool, err error) { // The status flag is in position 4 & 5 statusFlags, _, ok := readUint16(data, 3) if !ok { - return 0, false, fmt.Errorf("invalid EOF packet statusFlags: %v", data) + return 0, false, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid EOF packet statusFlags: %v", data) } return warnings, (statusFlags & ServerMoreResultsExists) != 0, nil } @@ -927,25 +929,25 @@ func parseOKPacket(data []byte) (uint64, uint64, uint16, uint16, error) { // Affected rows. affectedRows, pos, ok := readLenEncInt(data, pos) if !ok { - return 0, 0, 0, 0, fmt.Errorf("invalid OK packet affectedRows: %v", data) + return 0, 0, 0, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid OK packet affectedRows: %v", data) } // Last Insert ID. lastInsertID, pos, ok := readLenEncInt(data, pos) if !ok { - return 0, 0, 0, 0, fmt.Errorf("invalid OK packet lastInsertID: %v", data) + return 0, 0, 0, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid OK packet lastInsertID: %v", data) } // Status flags. statusFlags, pos, ok := readUint16(data, pos) if !ok { - return 0, 0, 0, 0, fmt.Errorf("invalid OK packet statusFlags: %v", data) + return 0, 0, 0, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid OK packet statusFlags: %v", data) } // Warnings. warnings, pos, ok := readUint16(data, pos) if !ok { - return 0, 0, 0, 0, fmt.Errorf("invalid OK packet warnings: %v", data) + return 0, 0, 0, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid OK packet warnings: %v", data) } return affectedRows, lastInsertID, statusFlags, warnings, nil diff --git a/go/mysql/flavor.go b/go/mysql/flavor.go index f0a9a53a20d..ffa806509ee 100644 --- a/go/mysql/flavor.go +++ b/go/mysql/flavor.go @@ -24,6 +24,8 @@ import ( "golang.org/x/net/context" "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) var ( @@ -224,10 +226,10 @@ func resultToMap(qr *sqltypes.Result) (map[string]string, error) { return nil, nil } if len(qr.Rows) > 1 { - return nil, fmt.Errorf("query returned %d rows, expected 1", len(qr.Rows)) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "query returned %d rows, expected 1", len(qr.Rows)) } if len(qr.Fields) != len(qr.Rows[0]) { - return nil, fmt.Errorf("query returned %d column names, expected %d", len(qr.Fields), len(qr.Rows[0])) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "query returned %d column names, expected %d", len(qr.Fields), len(qr.Rows[0])) } result := make(map[string]string, len(qr.Fields)) diff --git a/go/mysql/flavor_mariadb.go b/go/mysql/flavor_mariadb.go index 329b6a04b52..9cebc138bc2 100644 --- a/go/mysql/flavor_mariadb.go +++ b/go/mysql/flavor_mariadb.go @@ -23,6 +23,8 @@ import ( "time" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // mariadbFlavor implements the Flavor interface for MariaDB. @@ -35,7 +37,7 @@ func (mariadbFlavor) masterGTIDSet(c *Conn) (GTIDSet, error) { return nil, err } if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { - return nil, fmt.Errorf("unexpected result format for gtid_binlog_pos: %#v", qr) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected result format for gtid_binlog_pos: %#v", qr) } return parseMariadbGTIDSet(qr.Rows[0][0].ToString()) @@ -58,21 +60,21 @@ func (mariadbFlavor) sendBinlogDumpCommand(c *Conn, slaveID uint32, startPos Pos // Tell the server that we understand GTIDs by setting our slave // capability to MARIA_SLAVE_CAPABILITY_GTID = 4 (MariaDB >= 10.0.1). if _, err := c.ExecuteFetch("SET @mariadb_slave_capability=4", 0, false); err != nil { - return fmt.Errorf("failed to set @mariadb_slave_capability=4: %v", err) + return vterrors.Wrapf(err, "failed to set @mariadb_slave_capability=4") } // Set the slave_connect_state variable before issuing COM_BINLOG_DUMP // to provide the start position in GTID form. query := fmt.Sprintf("SET @slave_connect_state='%s'", startPos) if _, err := c.ExecuteFetch(query, 0, false); err != nil { - return fmt.Errorf("failed to set @slave_connect_state='%s': %v", startPos, err) + return vterrors.Wrapf(err, "failed to set @slave_connect_state='%s'", startPos) } // Real slaves set this upon connecting if their gtid_strict_mode option // was enabled. We always use gtid_strict_mode because we need it to // make our internal GTID comparisons safe. if _, err := c.ExecuteFetch("SET @slave_gtid_strict_mode=1", 0, false); err != nil { - return fmt.Errorf("failed to set @slave_gtid_strict_mode=1: %v", err) + return vterrors.Wrapf(err, "failed to set @slave_gtid_strict_mode=1") } // Since we use @slave_connect_state, the file and position here are @@ -138,7 +140,7 @@ func (mariadbFlavor) status(c *Conn) (SlaveStatus, error) { status := parseSlaveStatus(resultMap) status.Position.GTIDSet, err = parseMariadbGTIDSet(resultMap["Gtid_Slave_Pos"]) if err != nil { - return SlaveStatus{}, fmt.Errorf("SlaveStatus can't parse MariaDB GTID (Gtid_Slave_Pos: %#v): %v", resultMap["Gtid_Slave_Pos"], err) + return SlaveStatus{}, vterrors.Wrapf(err, "SlaveStatus can't parse MariaDB GTID (Gtid_Slave_Pos: %#v)", resultMap["Gtid_Slave_Pos"]) } return status, nil } @@ -151,7 +153,7 @@ func (mariadbFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) if deadline, ok := ctx.Deadline(); ok { timeout := deadline.Sub(time.Now()) if timeout <= 0 { - return "", fmt.Errorf("timed out waiting for position %v", pos) + return "", vterrors.Errorf(vtrpc.Code_DEADLINE_EXCEEDED, "timed out waiting for position %v", pos) } return fmt.Sprintf("SELECT MASTER_GTID_WAIT('%s', %.6f)", pos, timeout.Seconds()), nil } diff --git a/go/mysql/flavor_mysql.go b/go/mysql/flavor_mysql.go index 3a3fd99400b..a318c50c49e 100644 --- a/go/mysql/flavor_mysql.go +++ b/go/mysql/flavor_mysql.go @@ -22,6 +22,8 @@ import ( "time" "golang.org/x/net/context" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // mysqlFlavor implements the Flavor interface for Mysql. @@ -34,7 +36,7 @@ func (mysqlFlavor) masterGTIDSet(c *Conn) (GTIDSet, error) { return nil, err } if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { - return nil, fmt.Errorf("unexpected result format for gtid_executed: %#v", qr) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected result format for gtid_executed: %#v", qr) } return parseMysql56GTIDSet(qr.Rows[0][0].ToString()) } @@ -55,7 +57,7 @@ func (mysqlFlavor) stopSlaveCommand() string { func (mysqlFlavor) sendBinlogDumpCommand(c *Conn, slaveID uint32, startPos Position) error { gtidSet, ok := startPos.GTIDSet.(Mysql56GTIDSet) if !ok { - return fmt.Errorf("startPos.GTIDSet is wrong type - expected Mysql56GTIDSet, got: %#v", startPos.GTIDSet) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "startPos.GTIDSet is wrong type - expected Mysql56GTIDSet, got: %#v", startPos.GTIDSet) } // Build the command. @@ -105,7 +107,7 @@ func (mysqlFlavor) status(c *Conn) (SlaveStatus, error) { status := parseSlaveStatus(resultMap) status.Position.GTIDSet, err = parseMysql56GTIDSet(resultMap["Executed_Gtid_Set"]) if err != nil { - return SlaveStatus{}, fmt.Errorf("SlaveStatus can't parse MySQL 5.6 GTID (Executed_Gtid_Set: %#v): %v", resultMap["Executed_Gtid_Set"], err) + return SlaveStatus{}, vterrors.Wrapf(err, "SlaveStatus can't parse MySQL 5.6 GTID (Executed_Gtid_Set: %#v)", resultMap["Executed_Gtid_Set"]) } return status, nil } @@ -117,7 +119,7 @@ func (mysqlFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) ( if deadline, ok := ctx.Deadline(); ok { timeout := deadline.Sub(time.Now()) if timeout <= 0 { - return "", fmt.Errorf("timed out waiting for position %v", pos) + return "", vterrors.Errorf(vtrpc.Code_DEADLINE_EXCEEDED, "timed out waiting for position %v", pos) } // Only whole numbers of seconds are supported. diff --git a/go/mysql/gtid.go b/go/mysql/gtid.go index 751f2658355..c04f8bfa41f 100644 --- a/go/mysql/gtid.go +++ b/go/mysql/gtid.go @@ -19,6 +19,9 @@ package mysql import ( "fmt" "strings" + + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) // GTID represents a Global Transaction ID, also known as Transaction Group ID. @@ -60,7 +63,7 @@ var gtidParsers = make(map[string]func(string) (GTID, error)) func ParseGTID(flavor, value string) (GTID, error) { parser := gtidParsers[flavor] if parser == nil { - return nil, fmt.Errorf("parse error: unknown GTID flavor %#v", flavor) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parse error: unknown GTID flavor %#v", flavor) } return parser(value) } diff --git a/go/mysql/mariadb_gtid.go b/go/mysql/mariadb_gtid.go index e40584ab00d..4a24c78ab01 100644 --- a/go/mysql/mariadb_gtid.go +++ b/go/mysql/mariadb_gtid.go @@ -20,6 +20,9 @@ import ( "fmt" "strconv" "strings" + + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) const mariadbFlavorID = "MariaDB" @@ -29,25 +32,25 @@ func parseMariadbGTID(s string) (GTID, error) { // Split into parts. parts := strings.Split(s, "-") if len(parts) != 3 { - return nil, fmt.Errorf("invalid MariaDB GTID (%v): expecting Domain-Server-Sequence", s) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid MariaDB GTID (%v): expecting Domain-Server-Sequence", s) } // Parse Domain ID. Domain, err := strconv.ParseUint(parts[0], 10, 32) if err != nil { - return nil, fmt.Errorf("invalid MariaDB GTID Domain ID (%v): %v", parts[0], err) + return nil, vterrors.Wrapf(err, "invalid MariaDB GTID Domain ID (%v)", parts[0]) } // Parse Server ID. Server, err := strconv.ParseUint(parts[1], 10, 32) if err != nil { - return nil, fmt.Errorf("invalid MariaDB GTID Server ID (%v): %v", parts[1], err) + return nil, vterrors.Wrapf(err, "invalid MariaDB GTID Server ID (%v)", parts[1]) } // Parse Sequence number. Sequence, err := strconv.ParseUint(parts[2], 10, 64) if err != nil { - return nil, fmt.Errorf("invalid MariaDB GTID Sequence number (%v): %v", parts[2], err) + return nil, vterrors.Wrapf(err, "invalid MariaDB GTID Sequence number (%v)", parts[2]) } return MariadbGTID{ diff --git a/go/mysql/mysql56_gtid.go b/go/mysql/mysql56_gtid.go index 0bedf5cc6eb..0997b137ad5 100644 --- a/go/mysql/mysql56_gtid.go +++ b/go/mysql/mysql56_gtid.go @@ -21,6 +21,9 @@ import ( "fmt" "strconv" "strings" + + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) const mysql56FlavorID = "MySQL56" @@ -30,19 +33,19 @@ func parseMysql56GTID(s string) (GTID, error) { // Split into parts. parts := strings.Split(s, ":") if len(parts) != 2 { - return nil, fmt.Errorf("invalid MySQL 5.6 GTID (%v): expecting UUID:Sequence", s) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid MySQL 5.6 GTID (%v): expecting UUID:Sequence", s) } // Parse Server ID. sid, err := ParseSID(parts[0]) if err != nil { - return nil, fmt.Errorf("invalid MySQL 5.6 GTID Server ID (%v): %v", parts[0], err) + return nil, vterrors.Wrapf(err, "invalid MySQL 5.6 GTID Server ID (%v)", parts[0]) } // Parse Sequence number. seq, err := strconv.ParseInt(parts[1], 10, 64) if err != nil { - return nil, fmt.Errorf("invalid MySQL 5.6 GTID Sequence number (%v): %v", parts[1], err) + return nil, vterrors.Wrapf(err, "invalid MySQL 5.6 GTID Sequence number (%v)", parts[1]) } return Mysql56GTID{Server: sid, Sequence: seq}, nil @@ -65,7 +68,7 @@ func (sid SID) String() string { // ParseSID parses an SID in the form used by MySQL 5.6. func ParseSID(s string) (sid SID, err error) { if len(s) != 36 || s[8] != '-' || s[13] != '-' || s[18] != '-' || s[23] != '-' { - return sid, fmt.Errorf("invalid MySQL 5.6 SID %q", s) + return sid, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid MySQL 5.6 SID %q", s) } // Drop the dashes so we can just check the error of Decode once. @@ -77,7 +80,7 @@ func ParseSID(s string) (sid SID, err error) { b = append(b, s[24:]...) if _, err := hex.Decode(sid[:], b); err != nil { - return sid, fmt.Errorf("invalid MySQL 5.6 SID %q: %v", s, err) + return sid, vterrors.Wrapf(err, "invalid MySQL 5.6 SID %q", s) } return sid, nil } diff --git a/go/mysql/mysql56_gtid_set.go b/go/mysql/mysql56_gtid_set.go index 63813ef54a7..3d03cdab01a 100644 --- a/go/mysql/mysql56_gtid_set.go +++ b/go/mysql/mysql56_gtid_set.go @@ -19,10 +19,12 @@ package mysql import ( "bytes" "encoding/binary" - "fmt" "sort" "strconv" "strings" + + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) type interval struct { @@ -48,10 +50,10 @@ func parseInterval(s string) (interval, error) { parts := strings.Split(s, "-") start, err := strconv.ParseInt(parts[0], 10, 64) if err != nil { - return interval{}, fmt.Errorf("invalid interval (%q): %v", s, err) + return interval{}, vterrors.Wrapf(err, "invalid interval (%q)", s) } if start < 1 { - return interval{}, fmt.Errorf("invalid interval (%q): start must be > 0", s) + return interval{}, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid interval (%q): start must be > 0", s) } switch len(parts) { @@ -60,11 +62,11 @@ func parseInterval(s string) (interval, error) { case 2: end, err := strconv.ParseInt(parts[1], 10, 64) if err != nil { - return interval{}, fmt.Errorf("invalid interval (%q): %v", s, err) + return interval{}, vterrors.Wrapf(err, "invalid interval (%q)", s) } return interval{start: start, end: end}, nil default: - return interval{}, fmt.Errorf("invalid interval (%q): expected start-end or single number", s) + return interval{}, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid interval (%q): expected start-end or single number", s) } } @@ -84,13 +86,13 @@ func parseMysql56GTIDSet(s string) (GTIDSet, error) { // uuid_set: uuid:interval[:interval]... parts := strings.Split(uuidSet, ":") if len(parts) < 2 { - return nil, fmt.Errorf("invalid MySQL 5.6 GTID set (%q): expected uuid:interval", s) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid MySQL 5.6 GTID set (%q): expected uuid:interval", s) } // Parse Server ID. sid, err := ParseSID(parts[0]) if err != nil { - return nil, fmt.Errorf("invalid MySQL 5.6 GTID set (%q): %v", s, err) + return nil, vterrors.Wrapf(err, "invalid MySQL 5.6 GTID set (%q)", s) } // Parse Intervals. @@ -98,7 +100,7 @@ func parseMysql56GTIDSet(s string) (GTIDSet, error) { for _, part := range parts[1:] { iv, err := parseInterval(part) if err != nil { - return nil, fmt.Errorf("invalid MySQL 5.6 GTID set (%q): %v", s, err) + return nil, vterrors.Wrapf(err, "invalid MySQL 5.6 GTID set (%q)", s) } if iv.end < iv.start { // According to MySQL 5.6 code: @@ -377,24 +379,24 @@ func NewMysql56GTIDSetFromSIDBlock(data []byte) (Mysql56GTIDSet, error) { var set Mysql56GTIDSet = make(map[SID][]interval) var nSIDs uint64 if err := binary.Read(buf, binary.LittleEndian, &nSIDs); err != nil { - return nil, fmt.Errorf("cannot read nSIDs: %v", err) + return nil, vterrors.Wrapf(err, "cannot read nSIDs") } for i := uint64(0); i < nSIDs; i++ { var sid SID if c, err := buf.Read(sid[:]); err != nil || c != 16 { - return nil, fmt.Errorf("cannot read SID %v: %v %v", i, err, c) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "cannot read SID %v: %v %v", i, err, c) } var nIntervals uint64 if err := binary.Read(buf, binary.LittleEndian, &nIntervals); err != nil { - return nil, fmt.Errorf("cannot read nIntervals %v: %v", i, err) + return nil, vterrors.Wrapf(err, "cannot read nIntervals %v", i) } for j := uint64(0); j < nIntervals; j++ { var start, end uint64 if err := binary.Read(buf, binary.LittleEndian, &start); err != nil { - return nil, fmt.Errorf("cannot read start %v/%v: %v", i, j, err) + return nil, vterrors.Wrapf(err, "cannot read start %v/%v", i, j) } if err := binary.Read(buf, binary.LittleEndian, &end); err != nil { - return nil, fmt.Errorf("cannot read end %v/%v: %v", i, j, err) + return nil, vterrors.Wrapf(err, "cannot read end %v/%v", i, j) } set[sid] = append(set[sid], interval{ start: int64(start), diff --git a/go/mysql/query.go b/go/mysql/query.go index ebaabb27a6a..297ab60db62 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -17,9 +17,9 @@ limitations under the License. package mysql import ( - "fmt" - "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" querypb "vitess.io/vitess/go/vt/proto/query" ) @@ -391,7 +391,7 @@ func (c *Conn) ReadQueryResult(maxrows int, wantfields bool) (result *sqltypes.R return nil, false, 0, ParseErrorPacket(data) } else { defer c.recycleReadPacket() - return nil, false, 0, fmt.Errorf("unexpected packet after fields: %v", data) + return nil, false, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected packet after fields: %v", data) } } @@ -485,7 +485,7 @@ func (c *Conn) readComQueryResponse() (affectedRows uint64, lastInsertID uint64, return 0, 0, 0, false, 0, ParseErrorPacket(data) case 0xfb: // Local infile - return 0, 0, 0, false, 0, fmt.Errorf("not implemented") + return 0, 0, 0, false, 0, vterrors.Errorf(vtrpc.Code_UNIMPLEMENTED, "not implemented") } n, pos, ok := readLenEncInt(data, 0) if !ok { @@ -562,7 +562,7 @@ func (c *Conn) writeColumnDefinition(field *querypb.Field) error { pos = writeUint16(data, pos, uint16(0x0000)) if pos != len(data) { - return fmt.Errorf("internal error: packing of column definition used %v bytes instead of %v", pos, len(data)) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "packing of column definition used %v bytes instead of %v", pos, len(data)) } return c.writeEphemeralPacket() @@ -592,7 +592,7 @@ func (c *Conn) writeRow(row []sqltypes.Value) error { } if pos != length { - return fmt.Errorf("internal error packet row: got %v bytes but expected %v", pos, length) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "packet row: got %v bytes but expected %v", pos, length) } return c.writeEphemeralPacket() diff --git a/go/mysql/replication_position.go b/go/mysql/replication_position.go index f7b83fa2799..87895fc6d90 100644 --- a/go/mysql/replication_position.go +++ b/go/mysql/replication_position.go @@ -20,6 +20,9 @@ import ( "encoding/json" "fmt" "strings" + + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) const ( @@ -137,7 +140,7 @@ func DecodePosition(s string) (rp Position, err error) { func ParsePosition(flavor, value string) (rp Position, err error) { parser := gtidSetParsers[flavor] if parser == nil { - return rp, fmt.Errorf("parse error: unknown GTIDSet flavor %#v", flavor) + return rp, vterrors.Errorf(vtrpc.Code_INTERNAL, "parse error: unknown GTIDSet flavor %#v", flavor) } gtidSet, err := parser(value) if err != nil { diff --git a/go/mysql/server.go b/go/mysql/server.go index f7a6099ab2d..374aab6b8e8 100644 --- a/go/mysql/server.go +++ b/go/mysql/server.go @@ -17,8 +17,7 @@ limitations under the License. package mysql import ( - tls "crypto/tls" - "fmt" + "crypto/tls" "io" "net" "strings" @@ -30,6 +29,8 @@ import ( "vitess.io/vitess/go/sync2" "vitess.io/vitess/go/tb" "vitess.io/vitess/go/vt/log" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" ) const ( @@ -324,7 +325,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti } } else { if l.RequireSecureTransport { - c.writeErrorPacketFromError(fmt.Errorf("Server does not allow insecure connections, client must use SSL/TLS")) + c.writeErrorPacketFromError(vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "Server does not allow insecure connections, client must use SSL/TLS")) } connCountByTLSVer.Add(versionNoTLS, 1) defer connCountByTLSVer.Add(versionNoTLS, -1) @@ -546,7 +547,7 @@ func (c *Conn) writeHandshakeV10(serverVersion string, authServer AuthServer, en // Sanity check. if pos != len(data) { - return nil, fmt.Errorf("error building Handshake packet: got %v bytes expected %v", pos, len(data)) + return nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "error building Handshake packet: got %v bytes expected %v", pos, len(data)) } if err := c.writeEphemeralPacket(); err != nil { @@ -571,10 +572,10 @@ func (l *Listener) parseClientHandshakePacket(c *Conn, firstTime bool, data []by // Client flags, 4 bytes. clientFlags, pos, ok := readUint32(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read client flags") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read client flags") } if clientFlags&CapabilityClientProtocol41 == 0 { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: only support protocol 4.1") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: only support protocol 4.1") } // Remember a subset of the capabilities, so we can use them @@ -593,13 +594,13 @@ func (l *Listener) parseClientHandshakePacket(c *Conn, firstTime bool, data []by // See doc.go for more information. _, pos, ok = readUint32(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read maxPacketSize") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read maxPacketSize") } // Character set. Need to handle it. characterSet, pos, ok := readByte(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read characterSet") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read characterSet") } c.CharacterSet = characterSet @@ -619,7 +620,7 @@ func (l *Listener) parseClientHandshakePacket(c *Conn, firstTime bool, data []by // username username, pos, ok := readNullString(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read username") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read username") } // auth-response can have three forms. @@ -628,29 +629,29 @@ func (l *Listener) parseClientHandshakePacket(c *Conn, firstTime bool, data []by var l uint64 l, pos, ok = readLenEncInt(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read auth-response variable length") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read auth-response variable length") } authResponse, pos, ok = readBytesCopy(data, pos, int(l)) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read auth-response") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read auth-response") } } else if clientFlags&CapabilityClientSecureConnection != 0 { var l byte l, pos, ok = readByte(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read auth-response length") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read auth-response length") } authResponse, pos, ok = readBytesCopy(data, pos, int(l)) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read auth-response") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read auth-response") } } else { a := "" a, pos, ok = readNullString(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read auth-response") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read auth-response") } authResponse = []byte(a) } @@ -660,7 +661,7 @@ func (l *Listener) parseClientHandshakePacket(c *Conn, firstTime bool, data []by dbname := "" dbname, pos, ok = readNullString(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read dbname") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read dbname") } c.SchemaName = dbname } @@ -670,7 +671,7 @@ func (l *Listener) parseClientHandshakePacket(c *Conn, firstTime bool, data []by if clientFlags&CapabilityClientPluginAuth != 0 { authMethod, pos, ok = readNullString(data, pos) if !ok { - return "", "", nil, fmt.Errorf("parseClientHandshakePacket: can't read authMethod") + return "", "", nil, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read authMethod") } } @@ -696,7 +697,7 @@ func parseConnAttrs(data []byte, pos int) (map[string]string, int, error) { attrLen, pos, ok := readLenEncInt(data, pos) if !ok { - return nil, 0, fmt.Errorf("parseClientHandshakePacket: can't read connection attributes variable length") + return nil, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read connection attributes variable length") } var attrLenRead uint64 @@ -707,27 +708,27 @@ func parseConnAttrs(data []byte, pos int) (map[string]string, int, error) { var keyLen byte keyLen, pos, ok = readByte(data, pos) if !ok { - return nil, 0, fmt.Errorf("parseClientHandshakePacket: can't read connection attribute key length") + return nil, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read connection attribute key length") } attrLenRead += uint64(keyLen) + 1 var connAttrKey []byte connAttrKey, pos, ok = readBytesCopy(data, pos, int(keyLen)) if !ok { - return nil, 0, fmt.Errorf("parseClientHandshakePacket: can't read connection attribute key") + return nil, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read connection attribute key") } var valLen byte valLen, pos, ok = readByte(data, pos) if !ok { - return nil, 0, fmt.Errorf("parseClientHandshakePacket: can't read connection attribute value length") + return nil, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read connection attribute value length") } attrLenRead += uint64(valLen) + 1 var connAttrVal []byte connAttrVal, pos, ok = readBytesCopy(data, pos, int(valLen)) if !ok { - return nil, 0, fmt.Errorf("parseClientHandshakePacket: can't read connection attribute value") + return nil, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "parseClientHandshakePacket: can't read connection attribute value") } attrs[string(connAttrKey[:])] = string(connAttrVal[:]) @@ -757,7 +758,7 @@ func (c *Conn) writeAuthSwitchRequest(pluginName string, pluginData []byte) erro // Sanity check. if pos != len(data) { - return fmt.Errorf("error building AuthSwitchRequestPacket packet: got %v bytes expected %v", pos, len(data)) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "error building AuthSwitchRequestPacket packet: got %v bytes expected %v", pos, len(data)) } return c.writeEphemeralPacket() } diff --git a/go/mysql/slave_status.go b/go/mysql/slave_status.go index c313d561d11..623247d32ae 100644 --- a/go/mysql/slave_status.go +++ b/go/mysql/slave_status.go @@ -17,9 +17,8 @@ limitations under the License. package mysql import ( - "fmt" - replicationdatapb "vitess.io/vitess/go/vt/proto/replicationdata" + "vitess.io/vitess/go/vt/vterrors" ) // SlaveStatus holds replication information from SHOW SLAVE STATUS. @@ -56,7 +55,7 @@ func SlaveStatusToProto(s SlaveStatus) *replicationdatapb.Status { func ProtoToSlaveStatus(s *replicationdatapb.Status) SlaveStatus { pos, err := DecodePosition(s.Position) if err != nil { - panic(fmt.Errorf("cannot decode Position: %v", err)) + panic(vterrors.Wrapf(err, "cannot decode Position")) } return SlaveStatus{ Position: pos, diff --git a/go/mysql/sql_error.go b/go/mysql/sql_error.go index e88fc7a22dd..233fe49276e 100644 --- a/go/mysql/sql_error.go +++ b/go/mysql/sql_error.go @@ -38,6 +38,7 @@ type SQLError struct { // NewSQLError creates a new SQLError. // If sqlState is left empty, it will default to "HY000" (general error). +// TODO: Should be aligned with vterrors, stack traces and wrapping func NewSQLError(number int, sqlState string, format string, args ...interface{}) *SQLError { if sqlState == "" { sqlState = SSUnknownSQLState From ca92ecdd21b49ca854f4186addd79c83fd3021ae Mon Sep 17 00:00:00 2001 From: deepthi Date: Wed, 27 Feb 2019 13:12:31 -0800 Subject: [PATCH 124/196] fix mismatched parens Signed-off-by: deepthi --- MAINTAINERS.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MAINTAINERS.md b/MAINTAINERS.md index a69b7ab59f1..7b527586cb0 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -6,12 +6,12 @@ The following is the full list, alphabetically ordered. * David Weitzman ([dweitzman](https://github.com/dweitzman)) dweitzman@pinterest.com * Deepthi Sigireddi ([deepthi](https://github.com/deepthi)) deepthi@planetscale.com * Derek Perkins ([derekperkins](https://github.com/derekperkins)) derek@nozzle.io -* Harshit Gangal ([harshit-gangal](https://github.com/harshit-gangal) harshit.gangal@gmail.com -* Jon Tirsen ([tirsen]((https://github.com/tirsen)) jontirsen@squareup.com +* Harshit Gangal ([harshit-gangal](https://github.com/harshit-gangal)) harshit.gangal@gmail.com +* Jon Tirsen ([tirsen](https://github.com/tirsen)) jontirsen@squareup.com * Leo X. Lin ([leoxlin](https://github.com/leoxlin)) llin@hubspot.com * Michael Demmer ([demmer](https://github.com/demmer)) mdemmer@slack-corp.com * Michael Pawliszyn ([mpawliszyn](https://github.com/mpawliszyn)) mikepaw@squareup.com -* Rafael Chacon ([rafael]((https://github.com/rafael)) rchacon@slack-corp.com +* Rafael Chacon ([rafael](https://github.com/rafael)) rchacon@slack-corp.com * Sugu Sougoumarane ([sougou](https://github.com/sougou)) sougou@planetscale.com ## Areas of expertise From 0034a99d6d946c13b4373c373fa45d32b28e54e9 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Wed, 27 Feb 2019 14:03:27 -0800 Subject: [PATCH 125/196] InitShardMaster: make it more idempotent If ISM is retried, it's possible it gets stuck. The specific use case where this happens is when the first attempt went past the point where semi-sync gets enabled. If we retry ISM after that, the part where we create the reparent journal table will hang because the master will have semi-sync enabled, but no replica will be pointing to it. To overcome this, we always disable semi-sync when resetting replication. All the code that enables replication turns semi sync on as needed already. Signed-off-by: Sugu Sougoumarane --- go/mysql/flavor_mariadb.go | 1 + go/mysql/flavor_mysql.go | 1 + 2 files changed, 2 insertions(+) diff --git a/go/mysql/flavor_mariadb.go b/go/mysql/flavor_mariadb.go index 329b6a04b52..efef7cb24b4 100644 --- a/go/mysql/flavor_mariadb.go +++ b/go/mysql/flavor_mariadb.go @@ -87,6 +87,7 @@ func (mariadbFlavor) resetReplicationCommands() []string { "RESET SLAVE ALL", // "ALL" makes it forget master host:port. "RESET MASTER", "SET GLOBAL gtid_slave_pos = ''", + "SET GLOBAL rpl_semi_sync_master_enabled = false, GLOBAL rpl_semi_sync_slave_enabled = false", // semi-sync will be enabled if needed when slave is started. } } diff --git a/go/mysql/flavor_mysql.go b/go/mysql/flavor_mysql.go index 3a3fd99400b..8a054728413 100644 --- a/go/mysql/flavor_mysql.go +++ b/go/mysql/flavor_mysql.go @@ -69,6 +69,7 @@ func (mysqlFlavor) resetReplicationCommands() []string { "STOP SLAVE", "RESET SLAVE ALL", // "ALL" makes it forget master host:port. "RESET MASTER", // This will also clear gtid_executed and gtid_purged. + "SET GLOBAL rpl_semi_sync_master_enabled = false, GLOBAL rpl_semi_sync_slave_enabled = false", // semi-sync will be enabled if needed when slave is started. } } From 5d3c5b99de7731eda640cd808dd5d797ceccf4e8 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Wed, 27 Feb 2019 15:27:27 -0800 Subject: [PATCH 126/196] meetup details Signed-off-by: Sugu Sougoumarane --- doc/meetups_notes/details.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 doc/meetups_notes/details.md diff --git a/doc/meetups_notes/details.md b/doc/meetups_notes/details.md new file mode 100644 index 00000000000..9f0914ef1ed --- /dev/null +++ b/doc/meetups_notes/details.md @@ -0,0 +1,32 @@ +# Updated Meeting Info + +Until we find the right home for Vitess monthly meeting notes, they live here on [Google Docs](https://docs.google.com/document/d/1d8PcVD-ppnytRXZPOPvhRnnwei7-tYvgopD0UYzbAMs/edit). + +### Vitess Monthly Meeting + +Vitess monthly meetings happen on the 3rd Thursday of every month, unless otherwise stated on vitess.slack.com (click [here](https://vitess.slack.com/join/shared_invite/enQtMzIxMDMyMzA0NzA1LTBjYjY1M2I2Yjg5YmY3ODIwOTk0N2M1YzI4Y2ViODdiNmIxMDdiMDM5YWQ1ZTc0YmJhZDdiOTliMGVkNDY4MjM) to join us on Slack). + +There is a recurring calendar invite that will always have the latest meeting dates, ping Adrianna (@skinnylatte on vitess.slack.com or email adrianna [at] planetscale.com if you would like to be invited to it). + +### How To Dial-In + +Video Link: https://slack.zoom.us/j/314170129 +Joining by phone: + + +Or iPhone one-tap : + + US: +16699006833,,314170129# or +16465588656,,314170129# + +Or other phone: + +Dial(for higher quality, dial a number based on your current location): +US: +1 669 900 6833 or +1 646 558 8656 or +1 877 853 5247 (Toll Free) or +1 877 369 0926 (Toll Free) + +Canada: +1 855 703 8985 (Canada Toll-Free) +UK: +44 80 8189 4088 (United Kingdom Toll-Free) +Australia: +61 18 0079 2488 (Australia Toll-Free) + +Japan: +81 (0) 800 100 5040 (Japan Toll-Free) +China: 400 616 8835, 400 669 9381 +Most other countries: https://zoom.us/zoomconference (not available for some countries) From a70d6af13f9ff909aab870de30c51835ce147e43 Mon Sep 17 00:00:00 2001 From: David Weitzman Date: Wed, 27 Feb 2019 14:15:06 -0800 Subject: [PATCH 127/196] Optionally lint .sh files with "shellcheck" if it's installed Signed-off-by: David Weitzman --- misc/git/hooks/shellcheck | 45 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100755 misc/git/hooks/shellcheck diff --git a/misc/git/hooks/shellcheck b/misc/git/hooks/shellcheck new file mode 100755 index 00000000000..7833f2442fd --- /dev/null +++ b/misc/git/hooks/shellcheck @@ -0,0 +1,45 @@ +#!/bin/bash +# This file is based on the Go linter precommit hook +# "golint". Therefore, both files are very similar. + +# This script does not handle file names that contain spaces. +shfiles=$(git diff --cached --name-only --diff-filter=ACM | grep '.*\.sh$') +if [ -z "$shfiles" ] ; then + # No .sh files modified. + exit 0 +fi + +# The -e SC1090,SC1091 suppressing warnings about trying to find +# files imported with "source foo.sh". We only want to lint +# the files modified as part of this current diff. +if errors=$(shellcheck -e SC1090,SC1091 "$shfiles" 2>&1); then + # No lint errors. Return early. + exit 0 +fi + +if [ -z "$(command -v shellcheck)" ]; then + echo "shellcheck not found, please run: brew or apt-get install shellcheck" + exit 0 +fi + +# git doesn't give us access to user input, so let's steal it. +if exec < /dev/tty; then + # interactive shell. Prompt the user. + echo + echo "shellcheck suggestions were found. They're not enforced, but we're pausing" + echo "to let you know before they get clobbered in the scrollback buffer." + echo + read -r -p 'Press enter to cancel, "s" to show all warnings or type "ack" to continue: ' + if [ "$REPLY" = "ack" ]; then + exit 0 + fi + if [ "$REPLY" = "s" ]; then + echo + echo "$errors" + fi +else + # non-interactive shell (e.g. called from Eclipse). Just display the errors. + echo "$errors" +fi + +exit 1 From 66c316134b2b7839003028aa70121b4f412c4577 Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Thu, 28 Feb 2019 10:35:02 +0100 Subject: [PATCH 128/196] List available tests if test is not found Signed-off-by: Andres Taylor --- test.go | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/test.go b/test.go index 0cfedcb0029..f9b2afffc51 100755 --- a/test.go +++ b/test.go @@ -826,7 +826,17 @@ func selectedTests(args []string, config *Config) []*Test { for _, name := range args { t, ok := config.Tests[name] if !ok { - log.Fatalf("Unknown test: %v", name) + tests := make([]string, len(config.Tests)) + + i := 0 + for k := range config.Tests { + tests[i] = k + i++ + } + + sort.Strings(tests) + + log.Fatalf("Unknown test: %v\nAvailable tests are: %v", name, strings.Join(tests, ", ")) } t.name = name tests = append(tests, t) From 9c000b6a74e60ffabf925b2192f84fdc97d8b9ca Mon Sep 17 00:00:00 2001 From: Andres Taylor Date: Thu, 28 Feb 2019 10:49:05 +0100 Subject: [PATCH 129/196] Typos Signed-off-by: Andres Taylor --- test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test.go b/test.go index f9b2afffc51..d88cb105b04 100755 --- a/test.go +++ b/test.go @@ -781,7 +781,7 @@ firstPass: if ct.Tags == nil { ct.Tags = []string{} } - log.Printf("% 32v:\t%v\n", t.name, t.PassTime) + log.Printf("%v:\t%v\n", t.name, t.PassTime) } log.Printf("Shard %v total: %v\n", i, time.Duration(sums[i])) } @@ -808,13 +808,13 @@ func getTestsSorted(names []string, testMap map[string]*Test) []*Test { func selectedTests(args []string, config *Config) []*Test { var tests []*Test - excluded_tests := strings.Split(*exclude, ",") + excludedTests := strings.Split(*exclude, ",") if *shard >= 0 { // Run the tests in a given shard. // This can be combined with positional args. var names []string for name, t := range config.Tests { - if t.Shard == *shard && !t.Manual && (*exclude == "" || !t.hasAnyTag(excluded_tests)) { + if t.Shard == *shard && !t.Manual && (*exclude == "" || !t.hasAnyTag(excludedTests)) { t.name = name names = append(names, name) } @@ -846,7 +846,7 @@ func selectedTests(args []string, config *Config) []*Test { // Run all tests. var names []string for name, t := range config.Tests { - if !t.Manual && (*tag == "" || t.hasTag(*tag)) && (*exclude == "" || !t.hasAnyTag(excluded_tests)) { + if !t.Manual && (*tag == "" || t.hasTag(*tag)) && (*exclude == "" || !t.hasAnyTag(excludedTests)) { names = append(names, name) } } From 1a7ee9ca90f6d088768e2352d1a055d83d8c930a Mon Sep 17 00:00:00 2001 From: zhoulin xie Date: Thu, 28 Feb 2019 18:14:20 +0800 Subject: [PATCH 130/196] Fix some misspells in comment Signed-off-by: zhoulin xie --- doc/ReferenceTables.md | 6 +++--- go/mysql/endtoend/schema_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/ReferenceTables.md b/doc/ReferenceTables.md index 9bf3a23fbb3..ea262f5d695 100644 --- a/doc/ReferenceTables.md +++ b/doc/ReferenceTables.md @@ -26,7 +26,7 @@ just a corner case of the vertical splits Vitess already supports. Action items: -* First, this setup probably needs to be explicitely mentioned somewhere in the +* First, this setup probably needs to be explicitly mentioned somewhere in the topology, not just as SourceShard objects in the destination keyspace, so Vitess can know about this setup at a higher level. Let's add a `repeated ReferenceKeyspace` field to the Keyspace object. Each `ReferenceKeyspace` @@ -59,7 +59,7 @@ the Reference Tables feature is enabled. Action items: * Each step of the process would know what to do because of the - `ReferenceKeyspace` entries in the destinatin keyspace. + `ReferenceKeyspace` entries in the destination keyspace. * `vtctl CopySchemaShard` needs to also copy the schema of the reference tables. @@ -82,7 +82,7 @@ Action items: ## Other Use Cases -Other scenarios might also need to be supported, or explicitely disabled: +Other scenarios might also need to be supported, or explicitly disabled: * Simple schema changes, or complicated Schema Swap in the reference keyspace: They would also need to be applied to the destination keyspace, the same way. diff --git a/go/mysql/endtoend/schema_test.go b/go/mysql/endtoend/schema_test.go index 49ed2675472..540484a4927 100644 --- a/go/mysql/endtoend/schema_test.go +++ b/go/mysql/endtoend/schema_test.go @@ -42,7 +42,7 @@ func testDescribeTable(t *testing.T) { // This is because without this, we have exceptions: // - MariaDB and MySQL 5.6 return '0' as default. // - MySQL 5.7 returns NULL as default. - // So we explicitely set it, to avoid having to check both cases below. + // So we explicitly set it, to avoid having to check both cases below. if _, err := conn.ExecuteFetch("create table for_describe(id int default 0, name varchar(128), primary key(id))", 0, false); err != nil { t.Fatal(err) } From e113d2e457b6786c0d41ca4e5ae768e821b8f408 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Thu, 28 Feb 2019 06:46:48 -0800 Subject: [PATCH 131/196] meetup details: add time Signed-off-by: Sugu Sougoumarane --- doc/meetups_notes/details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/meetups_notes/details.md b/doc/meetups_notes/details.md index 9f0914ef1ed..1c67224dd25 100644 --- a/doc/meetups_notes/details.md +++ b/doc/meetups_notes/details.md @@ -4,7 +4,7 @@ Until we find the right home for Vitess monthly meeting notes, they live here on ### Vitess Monthly Meeting -Vitess monthly meetings happen on the 3rd Thursday of every month, unless otherwise stated on vitess.slack.com (click [here](https://vitess.slack.com/join/shared_invite/enQtMzIxMDMyMzA0NzA1LTBjYjY1M2I2Yjg5YmY3ODIwOTk0N2M1YzI4Y2ViODdiNmIxMDdiMDM5YWQ1ZTc0YmJhZDdiOTliMGVkNDY4MjM) to join us on Slack). +Vitess monthly meetings happen on the 3rd Thursday of every month at 8:00AM Pacific time, unless otherwise stated on vitess.slack.com (click [here](https://vitess.slack.com/join/shared_invite/enQtMzIxMDMyMzA0NzA1LTBjYjY1M2I2Yjg5YmY3ODIwOTk0N2M1YzI4Y2ViODdiNmIxMDdiMDM5YWQ1ZTc0YmJhZDdiOTliMGVkNDY4MjM) to join us on Slack). There is a recurring calendar invite that will always have the latest meeting dates, ping Adrianna (@skinnylatte on vitess.slack.com or email adrianna [at] planetscale.com if you would like to be invited to it). From 0d01465488629c694c100518842b458bc02e75b5 Mon Sep 17 00:00:00 2001 From: Jacob Schlather Date: Wed, 27 Feb 2019 23:31:18 -0800 Subject: [PATCH 132/196] Don't return cached heartbeat read when query service is down to avoid situation where replica tablet never recovers. Signed-off-by: Jacob Schlather Signed-off-by: Signed-off-by: --- go/vt/vttablet/heartbeat/reader.go | 4 ++++ go/vt/vttablet/tabletserver/tabletserver.go | 22 ++++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/go/vt/vttablet/heartbeat/reader.go b/go/vt/vttablet/heartbeat/reader.go index b0eb91728d9..166e123bf9e 100644 --- a/go/vt/vttablet/heartbeat/reader.go +++ b/go/vt/vttablet/heartbeat/reader.go @@ -227,3 +227,7 @@ func (r *Reader) recordError(err error) { r.errorLog.Errorf("%v", err) readErrors.Add(1) } + +func (r *Reader) IsOpen() bool { + return r.isOpen +} diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index 2b2a4ad6a98..91c036746ac 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -152,12 +152,12 @@ type TabletServer struct { // for health checks. This does not affect how queries are served. // target specifies the primary target type, and also allow specifies // secondary types that should be additionally allowed. - mu sync.Mutex - state int64 - lameduck sync2.AtomicInt32 - target querypb.Target - alsoAllow []topodatapb.TabletType - requests sync.WaitGroup + mu sync.Mutex + state int64 + lameduck sync2.AtomicInt32 + target querypb.Target + alsoAllow []topodatapb.TabletType + requests sync.WaitGroup // The following variables should be initialized only once // before starting the tabletserver. @@ -229,7 +229,7 @@ type TxPoolController interface { AcceptReadOnly() error // InitDBConfig must be called before Init. - InitDBConfig(dbcfgs *dbconfigs.DBConfigs) + InitDBConfig(dbcfgs *dbconfigs.DBConfigs) // Init must be called once when vttablet starts for setting // up the metadata tables. @@ -1867,6 +1867,14 @@ func (tsv *TabletServer) BroadcastHealth(terTimestamp int64, stats *querypb.Real // HeartbeatLag returns the current lag as calculated by the heartbeat // package, if heartbeat is enabled. Otherwise returns 0. func (tsv *TabletServer) HeartbeatLag() (time.Duration, error) { + // If the reader is closed and we are not serving, then the + // query service is shutdown and this value is not being updated. + // We return healthy from this as a signal to the healtcheck to attempt + // to start the query service again. If the query service fails to start + // with an error, then that error is be reported by the healthcheck. + if !tsv.hr.IsOpen() && !tsv.IsServing() { + return 0, nil + } return tsv.hr.GetLatest() } From 72689e88721326e97ae4cd20a4db51ddada54b45 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 16:21:08 -0800 Subject: [PATCH 133/196] allow backups on master tablet Signed-off-by: deepthi --- go/vt/proto/query/query.pb.go | 144 +++--- .../tabletmanagerdata/tabletmanagerdata.pb.go | 465 +++++++++--------- go/vt/proto/vtgate/vtgate.pb.go | 106 ++-- go/vt/schemamanager/schemaswap/schema_swap.go | 2 +- go/vt/vtcombo/tablet_map.go | 2 +- go/vt/vtctl/backup.go | 32 +- go/vt/vttablet/agentrpctest/test_agent_rpc.go | 8 +- go/vt/vttablet/faketmclient/fake_client.go | 2 +- go/vt/vttablet/grpctmclient/client.go | 3 +- go/vt/vttablet/grpctmserver/server.go | 2 +- go/vt/vttablet/tabletmanager/rpc_agent.go | 2 +- go/vt/vttablet/tabletmanager/rpc_backup.go | 10 +- go/vt/vttablet/tmclient/rpc_client_api.go | 2 +- proto/tabletmanagerdata.proto | 1 + py/vtproto/tabletmanagerdata_pb2.py | 23 +- test/backup.py | 55 +++ 16 files changed, 475 insertions(+), 384 deletions(-) diff --git a/go/vt/proto/query/query.pb.go b/go/vt/proto/query/query.pb.go index 15403d32d61..31390f74a26 100644 --- a/go/vt/proto/query/query.pb.go +++ b/go/vt/proto/query/query.pb.go @@ -95,7 +95,7 @@ func (x MySqlFlag) String() string { return proto.EnumName(MySqlFlag_name, int32(x)) } func (MySqlFlag) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{0} + return fileDescriptor_query_d975ca5e289d5e28, []int{0} } // Flag allows us to qualify types by their common properties. @@ -134,7 +134,7 @@ func (x Flag) String() string { return proto.EnumName(Flag_name, int32(x)) } func (Flag) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{1} + return fileDescriptor_query_d975ca5e289d5e28, []int{1} } // Type defines the various supported data types in bind vars @@ -315,7 +315,7 @@ func (x Type) String() string { return proto.EnumName(Type_name, int32(x)) } func (Type) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{2} + return fileDescriptor_query_d975ca5e289d5e28, []int{2} } // TransactionState represents the state of a distributed transaction. @@ -345,7 +345,7 @@ func (x TransactionState) String() string { return proto.EnumName(TransactionState_name, int32(x)) } func (TransactionState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{3} + return fileDescriptor_query_d975ca5e289d5e28, []int{3} } type ExecuteOptions_IncludedFields int32 @@ -371,7 +371,7 @@ func (x ExecuteOptions_IncludedFields) String() string { return proto.EnumName(ExecuteOptions_IncludedFields_name, int32(x)) } func (ExecuteOptions_IncludedFields) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{6, 0} + return fileDescriptor_query_d975ca5e289d5e28, []int{6, 0} } type ExecuteOptions_Workload int32 @@ -400,7 +400,7 @@ func (x ExecuteOptions_Workload) String() string { return proto.EnumName(ExecuteOptions_Workload_name, int32(x)) } func (ExecuteOptions_Workload) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{6, 1} + return fileDescriptor_query_d975ca5e289d5e28, []int{6, 1} } type ExecuteOptions_TransactionIsolation int32 @@ -437,7 +437,7 @@ func (x ExecuteOptions_TransactionIsolation) String() string { return proto.EnumName(ExecuteOptions_TransactionIsolation_name, int32(x)) } func (ExecuteOptions_TransactionIsolation) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{6, 2} + return fileDescriptor_query_d975ca5e289d5e28, []int{6, 2} } // The category of one statement. @@ -464,7 +464,7 @@ func (x StreamEvent_Statement_Category) String() string { return proto.EnumName(StreamEvent_Statement_Category_name, int32(x)) } func (StreamEvent_Statement_Category) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{12, 0, 0} + return fileDescriptor_query_d975ca5e289d5e28, []int{12, 0, 0} } type SplitQueryRequest_Algorithm int32 @@ -487,7 +487,7 @@ func (x SplitQueryRequest_Algorithm) String() string { return proto.EnumName(SplitQueryRequest_Algorithm_name, int32(x)) } func (SplitQueryRequest_Algorithm) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{50, 0} + return fileDescriptor_query_d975ca5e289d5e28, []int{50, 0} } // Target describes what the client expects the tablet is. @@ -508,7 +508,7 @@ func (m *Target) Reset() { *m = Target{} } func (m *Target) String() string { return proto.CompactTextString(m) } func (*Target) ProtoMessage() {} func (*Target) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{0} + return fileDescriptor_query_d975ca5e289d5e28, []int{0} } func (m *Target) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Target.Unmarshal(m, b) @@ -576,7 +576,7 @@ func (m *VTGateCallerID) Reset() { *m = VTGateCallerID{} } func (m *VTGateCallerID) String() string { return proto.CompactTextString(m) } func (*VTGateCallerID) ProtoMessage() {} func (*VTGateCallerID) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{1} + return fileDescriptor_query_d975ca5e289d5e28, []int{1} } func (m *VTGateCallerID) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VTGateCallerID.Unmarshal(m, b) @@ -632,7 +632,7 @@ func (m *EventToken) Reset() { *m = EventToken{} } func (m *EventToken) String() string { return proto.CompactTextString(m) } func (*EventToken) ProtoMessage() {} func (*EventToken) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{2} + return fileDescriptor_query_d975ca5e289d5e28, []int{2} } func (m *EventToken) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EventToken.Unmarshal(m, b) @@ -686,7 +686,7 @@ func (m *Value) Reset() { *m = Value{} } func (m *Value) String() string { return proto.CompactTextString(m) } func (*Value) ProtoMessage() {} func (*Value) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{3} + return fileDescriptor_query_d975ca5e289d5e28, []int{3} } func (m *Value) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Value.Unmarshal(m, b) @@ -735,7 +735,7 @@ func (m *BindVariable) Reset() { *m = BindVariable{} } func (m *BindVariable) String() string { return proto.CompactTextString(m) } func (*BindVariable) ProtoMessage() {} func (*BindVariable) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{4} + return fileDescriptor_query_d975ca5e289d5e28, []int{4} } func (m *BindVariable) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BindVariable.Unmarshal(m, b) @@ -792,7 +792,7 @@ func (m *BoundQuery) Reset() { *m = BoundQuery{} } func (m *BoundQuery) String() string { return proto.CompactTextString(m) } func (*BoundQuery) ProtoMessage() {} func (*BoundQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{5} + return fileDescriptor_query_d975ca5e289d5e28, []int{5} } func (m *BoundQuery) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BoundQuery.Unmarshal(m, b) @@ -866,7 +866,7 @@ func (m *ExecuteOptions) Reset() { *m = ExecuteOptions{} } func (m *ExecuteOptions) String() string { return proto.CompactTextString(m) } func (*ExecuteOptions) ProtoMessage() {} func (*ExecuteOptions) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{6} + return fileDescriptor_query_d975ca5e289d5e28, []int{6} } func (m *ExecuteOptions) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteOptions.Unmarshal(m, b) @@ -972,7 +972,7 @@ func (m *Field) Reset() { *m = Field{} } func (m *Field) String() string { return proto.CompactTextString(m) } func (*Field) ProtoMessage() {} func (*Field) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{7} + return fileDescriptor_query_d975ca5e289d5e28, []int{7} } func (m *Field) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Field.Unmarshal(m, b) @@ -1080,7 +1080,7 @@ func (m *Row) Reset() { *m = Row{} } func (m *Row) String() string { return proto.CompactTextString(m) } func (*Row) ProtoMessage() {} func (*Row) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{8} + return fileDescriptor_query_d975ca5e289d5e28, []int{8} } func (m *Row) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Row.Unmarshal(m, b) @@ -1132,7 +1132,7 @@ func (m *ResultExtras) Reset() { *m = ResultExtras{} } func (m *ResultExtras) String() string { return proto.CompactTextString(m) } func (*ResultExtras) ProtoMessage() {} func (*ResultExtras) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{9} + return fileDescriptor_query_d975ca5e289d5e28, []int{9} } func (m *ResultExtras) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResultExtras.Unmarshal(m, b) @@ -1190,7 +1190,7 @@ func (m *QueryResult) Reset() { *m = QueryResult{} } func (m *QueryResult) String() string { return proto.CompactTextString(m) } func (*QueryResult) ProtoMessage() {} func (*QueryResult) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{10} + return fileDescriptor_query_d975ca5e289d5e28, []int{10} } func (m *QueryResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QueryResult.Unmarshal(m, b) @@ -1259,7 +1259,7 @@ func (m *QueryWarning) Reset() { *m = QueryWarning{} } func (m *QueryWarning) String() string { return proto.CompactTextString(m) } func (*QueryWarning) ProtoMessage() {} func (*QueryWarning) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{11} + return fileDescriptor_query_d975ca5e289d5e28, []int{11} } func (m *QueryWarning) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QueryWarning.Unmarshal(m, b) @@ -1310,7 +1310,7 @@ func (m *StreamEvent) Reset() { *m = StreamEvent{} } func (m *StreamEvent) String() string { return proto.CompactTextString(m) } func (*StreamEvent) ProtoMessage() {} func (*StreamEvent) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{12} + return fileDescriptor_query_d975ca5e289d5e28, []int{12} } func (m *StreamEvent) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamEvent.Unmarshal(m, b) @@ -1363,7 +1363,7 @@ func (m *StreamEvent_Statement) Reset() { *m = StreamEvent_Statement{} } func (m *StreamEvent_Statement) String() string { return proto.CompactTextString(m) } func (*StreamEvent_Statement) ProtoMessage() {} func (*StreamEvent_Statement) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{12, 0} + return fileDescriptor_query_d975ca5e289d5e28, []int{12, 0} } func (m *StreamEvent_Statement) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamEvent_Statement.Unmarshal(m, b) @@ -1435,7 +1435,7 @@ func (m *ExecuteRequest) Reset() { *m = ExecuteRequest{} } func (m *ExecuteRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteRequest) ProtoMessage() {} func (*ExecuteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{13} + return fileDescriptor_query_d975ca5e289d5e28, []int{13} } func (m *ExecuteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteRequest.Unmarshal(m, b) @@ -1509,7 +1509,7 @@ func (m *ExecuteResponse) Reset() { *m = ExecuteResponse{} } func (m *ExecuteResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteResponse) ProtoMessage() {} func (*ExecuteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{14} + return fileDescriptor_query_d975ca5e289d5e28, []int{14} } func (m *ExecuteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteResponse.Unmarshal(m, b) @@ -1553,7 +1553,7 @@ func (m *ResultWithError) Reset() { *m = ResultWithError{} } func (m *ResultWithError) String() string { return proto.CompactTextString(m) } func (*ResultWithError) ProtoMessage() {} func (*ResultWithError) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{15} + return fileDescriptor_query_d975ca5e289d5e28, []int{15} } func (m *ResultWithError) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResultWithError.Unmarshal(m, b) @@ -1605,7 +1605,7 @@ func (m *ExecuteBatchRequest) Reset() { *m = ExecuteBatchRequest{} } func (m *ExecuteBatchRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchRequest) ProtoMessage() {} func (*ExecuteBatchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{16} + return fileDescriptor_query_d975ca5e289d5e28, []int{16} } func (m *ExecuteBatchRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchRequest.Unmarshal(m, b) @@ -1686,7 +1686,7 @@ func (m *ExecuteBatchResponse) Reset() { *m = ExecuteBatchResponse{} } func (m *ExecuteBatchResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchResponse) ProtoMessage() {} func (*ExecuteBatchResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{17} + return fileDescriptor_query_d975ca5e289d5e28, []int{17} } func (m *ExecuteBatchResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchResponse.Unmarshal(m, b) @@ -1730,7 +1730,7 @@ func (m *StreamExecuteRequest) Reset() { *m = StreamExecuteRequest{} } func (m *StreamExecuteRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteRequest) ProtoMessage() {} func (*StreamExecuteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{18} + return fileDescriptor_query_d975ca5e289d5e28, []int{18} } func (m *StreamExecuteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteRequest.Unmarshal(m, b) @@ -1804,7 +1804,7 @@ func (m *StreamExecuteResponse) Reset() { *m = StreamExecuteResponse{} } func (m *StreamExecuteResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteResponse) ProtoMessage() {} func (*StreamExecuteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{19} + return fileDescriptor_query_d975ca5e289d5e28, []int{19} } func (m *StreamExecuteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteResponse.Unmarshal(m, b) @@ -1846,7 +1846,7 @@ func (m *BeginRequest) Reset() { *m = BeginRequest{} } func (m *BeginRequest) String() string { return proto.CompactTextString(m) } func (*BeginRequest) ProtoMessage() {} func (*BeginRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{20} + return fileDescriptor_query_d975ca5e289d5e28, []int{20} } func (m *BeginRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginRequest.Unmarshal(m, b) @@ -1906,7 +1906,7 @@ func (m *BeginResponse) Reset() { *m = BeginResponse{} } func (m *BeginResponse) String() string { return proto.CompactTextString(m) } func (*BeginResponse) ProtoMessage() {} func (*BeginResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{21} + return fileDescriptor_query_d975ca5e289d5e28, []int{21} } func (m *BeginResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginResponse.Unmarshal(m, b) @@ -1948,7 +1948,7 @@ func (m *CommitRequest) Reset() { *m = CommitRequest{} } func (m *CommitRequest) String() string { return proto.CompactTextString(m) } func (*CommitRequest) ProtoMessage() {} func (*CommitRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{22} + return fileDescriptor_query_d975ca5e289d5e28, []int{22} } func (m *CommitRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CommitRequest.Unmarshal(m, b) @@ -2007,7 +2007,7 @@ func (m *CommitResponse) Reset() { *m = CommitResponse{} } func (m *CommitResponse) String() string { return proto.CompactTextString(m) } func (*CommitResponse) ProtoMessage() {} func (*CommitResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{23} + return fileDescriptor_query_d975ca5e289d5e28, []int{23} } func (m *CommitResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CommitResponse.Unmarshal(m, b) @@ -2042,7 +2042,7 @@ func (m *RollbackRequest) Reset() { *m = RollbackRequest{} } func (m *RollbackRequest) String() string { return proto.CompactTextString(m) } func (*RollbackRequest) ProtoMessage() {} func (*RollbackRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{24} + return fileDescriptor_query_d975ca5e289d5e28, []int{24} } func (m *RollbackRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RollbackRequest.Unmarshal(m, b) @@ -2101,7 +2101,7 @@ func (m *RollbackResponse) Reset() { *m = RollbackResponse{} } func (m *RollbackResponse) String() string { return proto.CompactTextString(m) } func (*RollbackResponse) ProtoMessage() {} func (*RollbackResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{25} + return fileDescriptor_query_d975ca5e289d5e28, []int{25} } func (m *RollbackResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RollbackResponse.Unmarshal(m, b) @@ -2137,7 +2137,7 @@ func (m *PrepareRequest) Reset() { *m = PrepareRequest{} } func (m *PrepareRequest) String() string { return proto.CompactTextString(m) } func (*PrepareRequest) ProtoMessage() {} func (*PrepareRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{26} + return fileDescriptor_query_d975ca5e289d5e28, []int{26} } func (m *PrepareRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PrepareRequest.Unmarshal(m, b) @@ -2203,7 +2203,7 @@ func (m *PrepareResponse) Reset() { *m = PrepareResponse{} } func (m *PrepareResponse) String() string { return proto.CompactTextString(m) } func (*PrepareResponse) ProtoMessage() {} func (*PrepareResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{27} + return fileDescriptor_query_d975ca5e289d5e28, []int{27} } func (m *PrepareResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PrepareResponse.Unmarshal(m, b) @@ -2238,7 +2238,7 @@ func (m *CommitPreparedRequest) Reset() { *m = CommitPreparedRequest{} } func (m *CommitPreparedRequest) String() string { return proto.CompactTextString(m) } func (*CommitPreparedRequest) ProtoMessage() {} func (*CommitPreparedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{28} + return fileDescriptor_query_d975ca5e289d5e28, []int{28} } func (m *CommitPreparedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CommitPreparedRequest.Unmarshal(m, b) @@ -2297,7 +2297,7 @@ func (m *CommitPreparedResponse) Reset() { *m = CommitPreparedResponse{} func (m *CommitPreparedResponse) String() string { return proto.CompactTextString(m) } func (*CommitPreparedResponse) ProtoMessage() {} func (*CommitPreparedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{29} + return fileDescriptor_query_d975ca5e289d5e28, []int{29} } func (m *CommitPreparedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CommitPreparedResponse.Unmarshal(m, b) @@ -2333,7 +2333,7 @@ func (m *RollbackPreparedRequest) Reset() { *m = RollbackPreparedRequest func (m *RollbackPreparedRequest) String() string { return proto.CompactTextString(m) } func (*RollbackPreparedRequest) ProtoMessage() {} func (*RollbackPreparedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{30} + return fileDescriptor_query_d975ca5e289d5e28, []int{30} } func (m *RollbackPreparedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RollbackPreparedRequest.Unmarshal(m, b) @@ -2399,7 +2399,7 @@ func (m *RollbackPreparedResponse) Reset() { *m = RollbackPreparedRespon func (m *RollbackPreparedResponse) String() string { return proto.CompactTextString(m) } func (*RollbackPreparedResponse) ProtoMessage() {} func (*RollbackPreparedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{31} + return fileDescriptor_query_d975ca5e289d5e28, []int{31} } func (m *RollbackPreparedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RollbackPreparedResponse.Unmarshal(m, b) @@ -2435,7 +2435,7 @@ func (m *CreateTransactionRequest) Reset() { *m = CreateTransactionReque func (m *CreateTransactionRequest) String() string { return proto.CompactTextString(m) } func (*CreateTransactionRequest) ProtoMessage() {} func (*CreateTransactionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{32} + return fileDescriptor_query_d975ca5e289d5e28, []int{32} } func (m *CreateTransactionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateTransactionRequest.Unmarshal(m, b) @@ -2501,7 +2501,7 @@ func (m *CreateTransactionResponse) Reset() { *m = CreateTransactionResp func (m *CreateTransactionResponse) String() string { return proto.CompactTextString(m) } func (*CreateTransactionResponse) ProtoMessage() {} func (*CreateTransactionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{33} + return fileDescriptor_query_d975ca5e289d5e28, []int{33} } func (m *CreateTransactionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CreateTransactionResponse.Unmarshal(m, b) @@ -2537,7 +2537,7 @@ func (m *StartCommitRequest) Reset() { *m = StartCommitRequest{} } func (m *StartCommitRequest) String() string { return proto.CompactTextString(m) } func (*StartCommitRequest) ProtoMessage() {} func (*StartCommitRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{34} + return fileDescriptor_query_d975ca5e289d5e28, []int{34} } func (m *StartCommitRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartCommitRequest.Unmarshal(m, b) @@ -2603,7 +2603,7 @@ func (m *StartCommitResponse) Reset() { *m = StartCommitResponse{} } func (m *StartCommitResponse) String() string { return proto.CompactTextString(m) } func (*StartCommitResponse) ProtoMessage() {} func (*StartCommitResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{35} + return fileDescriptor_query_d975ca5e289d5e28, []int{35} } func (m *StartCommitResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartCommitResponse.Unmarshal(m, b) @@ -2639,7 +2639,7 @@ func (m *SetRollbackRequest) Reset() { *m = SetRollbackRequest{} } func (m *SetRollbackRequest) String() string { return proto.CompactTextString(m) } func (*SetRollbackRequest) ProtoMessage() {} func (*SetRollbackRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{36} + return fileDescriptor_query_d975ca5e289d5e28, []int{36} } func (m *SetRollbackRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetRollbackRequest.Unmarshal(m, b) @@ -2705,7 +2705,7 @@ func (m *SetRollbackResponse) Reset() { *m = SetRollbackResponse{} } func (m *SetRollbackResponse) String() string { return proto.CompactTextString(m) } func (*SetRollbackResponse) ProtoMessage() {} func (*SetRollbackResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{37} + return fileDescriptor_query_d975ca5e289d5e28, []int{37} } func (m *SetRollbackResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetRollbackResponse.Unmarshal(m, b) @@ -2740,7 +2740,7 @@ func (m *ConcludeTransactionRequest) Reset() { *m = ConcludeTransactionR func (m *ConcludeTransactionRequest) String() string { return proto.CompactTextString(m) } func (*ConcludeTransactionRequest) ProtoMessage() {} func (*ConcludeTransactionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{38} + return fileDescriptor_query_d975ca5e289d5e28, []int{38} } func (m *ConcludeTransactionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConcludeTransactionRequest.Unmarshal(m, b) @@ -2799,7 +2799,7 @@ func (m *ConcludeTransactionResponse) Reset() { *m = ConcludeTransaction func (m *ConcludeTransactionResponse) String() string { return proto.CompactTextString(m) } func (*ConcludeTransactionResponse) ProtoMessage() {} func (*ConcludeTransactionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{39} + return fileDescriptor_query_d975ca5e289d5e28, []int{39} } func (m *ConcludeTransactionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ConcludeTransactionResponse.Unmarshal(m, b) @@ -2834,7 +2834,7 @@ func (m *ReadTransactionRequest) Reset() { *m = ReadTransactionRequest{} func (m *ReadTransactionRequest) String() string { return proto.CompactTextString(m) } func (*ReadTransactionRequest) ProtoMessage() {} func (*ReadTransactionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{40} + return fileDescriptor_query_d975ca5e289d5e28, []int{40} } func (m *ReadTransactionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReadTransactionRequest.Unmarshal(m, b) @@ -2894,7 +2894,7 @@ func (m *ReadTransactionResponse) Reset() { *m = ReadTransactionResponse func (m *ReadTransactionResponse) String() string { return proto.CompactTextString(m) } func (*ReadTransactionResponse) ProtoMessage() {} func (*ReadTransactionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{41} + return fileDescriptor_query_d975ca5e289d5e28, []int{41} } func (m *ReadTransactionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReadTransactionResponse.Unmarshal(m, b) @@ -2937,7 +2937,7 @@ func (m *BeginExecuteRequest) Reset() { *m = BeginExecuteRequest{} } func (m *BeginExecuteRequest) String() string { return proto.CompactTextString(m) } func (*BeginExecuteRequest) ProtoMessage() {} func (*BeginExecuteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{42} + return fileDescriptor_query_d975ca5e289d5e28, []int{42} } func (m *BeginExecuteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginExecuteRequest.Unmarshal(m, b) @@ -3010,7 +3010,7 @@ func (m *BeginExecuteResponse) Reset() { *m = BeginExecuteResponse{} } func (m *BeginExecuteResponse) String() string { return proto.CompactTextString(m) } func (*BeginExecuteResponse) ProtoMessage() {} func (*BeginExecuteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{43} + return fileDescriptor_query_d975ca5e289d5e28, []int{43} } func (m *BeginExecuteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginExecuteResponse.Unmarshal(m, b) @@ -3068,7 +3068,7 @@ func (m *BeginExecuteBatchRequest) Reset() { *m = BeginExecuteBatchReque func (m *BeginExecuteBatchRequest) String() string { return proto.CompactTextString(m) } func (*BeginExecuteBatchRequest) ProtoMessage() {} func (*BeginExecuteBatchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{44} + return fileDescriptor_query_d975ca5e289d5e28, []int{44} } func (m *BeginExecuteBatchRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginExecuteBatchRequest.Unmarshal(m, b) @@ -3148,7 +3148,7 @@ func (m *BeginExecuteBatchResponse) Reset() { *m = BeginExecuteBatchResp func (m *BeginExecuteBatchResponse) String() string { return proto.CompactTextString(m) } func (*BeginExecuteBatchResponse) ProtoMessage() {} func (*BeginExecuteBatchResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{45} + return fileDescriptor_query_d975ca5e289d5e28, []int{45} } func (m *BeginExecuteBatchResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginExecuteBatchResponse.Unmarshal(m, b) @@ -3205,7 +3205,7 @@ func (m *MessageStreamRequest) Reset() { *m = MessageStreamRequest{} } func (m *MessageStreamRequest) String() string { return proto.CompactTextString(m) } func (*MessageStreamRequest) ProtoMessage() {} func (*MessageStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{46} + return fileDescriptor_query_d975ca5e289d5e28, []int{46} } func (m *MessageStreamRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageStreamRequest.Unmarshal(m, b) @@ -3265,7 +3265,7 @@ func (m *MessageStreamResponse) Reset() { *m = MessageStreamResponse{} } func (m *MessageStreamResponse) String() string { return proto.CompactTextString(m) } func (*MessageStreamResponse) ProtoMessage() {} func (*MessageStreamResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{47} + return fileDescriptor_query_d975ca5e289d5e28, []int{47} } func (m *MessageStreamResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageStreamResponse.Unmarshal(m, b) @@ -3309,7 +3309,7 @@ func (m *MessageAckRequest) Reset() { *m = MessageAckRequest{} } func (m *MessageAckRequest) String() string { return proto.CompactTextString(m) } func (*MessageAckRequest) ProtoMessage() {} func (*MessageAckRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{48} + return fileDescriptor_query_d975ca5e289d5e28, []int{48} } func (m *MessageAckRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageAckRequest.Unmarshal(m, b) @@ -3379,7 +3379,7 @@ func (m *MessageAckResponse) Reset() { *m = MessageAckResponse{} } func (m *MessageAckResponse) String() string { return proto.CompactTextString(m) } func (*MessageAckResponse) ProtoMessage() {} func (*MessageAckResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{49} + return fileDescriptor_query_d975ca5e289d5e28, []int{49} } func (m *MessageAckResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageAckResponse.Unmarshal(m, b) @@ -3427,7 +3427,7 @@ func (m *SplitQueryRequest) Reset() { *m = SplitQueryRequest{} } func (m *SplitQueryRequest) String() string { return proto.CompactTextString(m) } func (*SplitQueryRequest) ProtoMessage() {} func (*SplitQueryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{50} + return fileDescriptor_query_d975ca5e289d5e28, []int{50} } func (m *SplitQueryRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryRequest.Unmarshal(m, b) @@ -3518,7 +3518,7 @@ func (m *QuerySplit) Reset() { *m = QuerySplit{} } func (m *QuerySplit) String() string { return proto.CompactTextString(m) } func (*QuerySplit) ProtoMessage() {} func (*QuerySplit) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{51} + return fileDescriptor_query_d975ca5e289d5e28, []int{51} } func (m *QuerySplit) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_QuerySplit.Unmarshal(m, b) @@ -3565,7 +3565,7 @@ func (m *SplitQueryResponse) Reset() { *m = SplitQueryResponse{} } func (m *SplitQueryResponse) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse) ProtoMessage() {} func (*SplitQueryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{52} + return fileDescriptor_query_d975ca5e289d5e28, []int{52} } func (m *SplitQueryResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse.Unmarshal(m, b) @@ -3603,7 +3603,7 @@ func (m *StreamHealthRequest) Reset() { *m = StreamHealthRequest{} } func (m *StreamHealthRequest) String() string { return proto.CompactTextString(m) } func (*StreamHealthRequest) ProtoMessage() {} func (*StreamHealthRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{53} + return fileDescriptor_query_d975ca5e289d5e28, []int{53} } func (m *StreamHealthRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamHealthRequest.Unmarshal(m, b) @@ -3662,7 +3662,7 @@ func (m *RealtimeStats) Reset() { *m = RealtimeStats{} } func (m *RealtimeStats) String() string { return proto.CompactTextString(m) } func (*RealtimeStats) ProtoMessage() {} func (*RealtimeStats) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{54} + return fileDescriptor_query_d975ca5e289d5e28, []int{54} } func (m *RealtimeStats) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RealtimeStats.Unmarshal(m, b) @@ -3750,7 +3750,7 @@ func (m *AggregateStats) Reset() { *m = AggregateStats{} } func (m *AggregateStats) String() string { return proto.CompactTextString(m) } func (*AggregateStats) ProtoMessage() {} func (*AggregateStats) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{55} + return fileDescriptor_query_d975ca5e289d5e28, []int{55} } func (m *AggregateStats) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_AggregateStats.Unmarshal(m, b) @@ -3862,7 +3862,7 @@ func (m *StreamHealthResponse) Reset() { *m = StreamHealthResponse{} } func (m *StreamHealthResponse) String() string { return proto.CompactTextString(m) } func (*StreamHealthResponse) ProtoMessage() {} func (*StreamHealthResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{56} + return fileDescriptor_query_d975ca5e289d5e28, []int{56} } func (m *StreamHealthResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamHealthResponse.Unmarshal(m, b) @@ -3946,7 +3946,7 @@ func (m *UpdateStreamRequest) Reset() { *m = UpdateStreamRequest{} } func (m *UpdateStreamRequest) String() string { return proto.CompactTextString(m) } func (*UpdateStreamRequest) ProtoMessage() {} func (*UpdateStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{57} + return fileDescriptor_query_d975ca5e289d5e28, []int{57} } func (m *UpdateStreamRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateStreamRequest.Unmarshal(m, b) @@ -4013,7 +4013,7 @@ func (m *UpdateStreamResponse) Reset() { *m = UpdateStreamResponse{} } func (m *UpdateStreamResponse) String() string { return proto.CompactTextString(m) } func (*UpdateStreamResponse) ProtoMessage() {} func (*UpdateStreamResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{58} + return fileDescriptor_query_d975ca5e289d5e28, []int{58} } func (m *UpdateStreamResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateStreamResponse.Unmarshal(m, b) @@ -4055,7 +4055,7 @@ func (m *TransactionMetadata) Reset() { *m = TransactionMetadata{} } func (m *TransactionMetadata) String() string { return proto.CompactTextString(m) } func (*TransactionMetadata) ProtoMessage() {} func (*TransactionMetadata) Descriptor() ([]byte, []int) { - return fileDescriptor_query_b0bca749772b6512, []int{59} + return fileDescriptor_query_d975ca5e289d5e28, []int{59} } func (m *TransactionMetadata) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TransactionMetadata.Unmarshal(m, b) @@ -4177,9 +4177,9 @@ func init() { proto.RegisterEnum("query.SplitQueryRequest_Algorithm", SplitQueryRequest_Algorithm_name, SplitQueryRequest_Algorithm_value) } -func init() { proto.RegisterFile("query.proto", fileDescriptor_query_b0bca749772b6512) } +func init() { proto.RegisterFile("query.proto", fileDescriptor_query_d975ca5e289d5e28) } -var fileDescriptor_query_b0bca749772b6512 = []byte{ +var fileDescriptor_query_d975ca5e289d5e28 = []byte{ // 3259 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0xcd, 0x73, 0x1b, 0xc9, 0x75, 0xd7, 0xe0, 0x8b, 0xc0, 0x03, 0x01, 0x36, 0x1b, 0xa4, 0x84, 0xe5, 0x7e, 0xd1, 0x63, 0xaf, diff --git a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go index 479fa1358af..c574ee39be7 100644 --- a/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go +++ b/go/vt/proto/tabletmanagerdata/tabletmanagerdata.pb.go @@ -46,7 +46,7 @@ func (m *TableDefinition) Reset() { *m = TableDefinition{} } func (m *TableDefinition) String() string { return proto.CompactTextString(m) } func (*TableDefinition) ProtoMessage() {} func (*TableDefinition) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{0} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{0} } func (m *TableDefinition) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TableDefinition.Unmarshal(m, b) @@ -128,7 +128,7 @@ func (m *SchemaDefinition) Reset() { *m = SchemaDefinition{} } func (m *SchemaDefinition) String() string { return proto.CompactTextString(m) } func (*SchemaDefinition) ProtoMessage() {} func (*SchemaDefinition) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{1} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{1} } func (m *SchemaDefinition) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SchemaDefinition.Unmarshal(m, b) @@ -183,7 +183,7 @@ func (m *SchemaChangeResult) Reset() { *m = SchemaChangeResult{} } func (m *SchemaChangeResult) String() string { return proto.CompactTextString(m) } func (*SchemaChangeResult) ProtoMessage() {} func (*SchemaChangeResult) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{2} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{2} } func (m *SchemaChangeResult) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SchemaChangeResult.Unmarshal(m, b) @@ -234,7 +234,7 @@ func (m *UserPermission) Reset() { *m = UserPermission{} } func (m *UserPermission) String() string { return proto.CompactTextString(m) } func (*UserPermission) ProtoMessage() {} func (*UserPermission) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{3} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{3} } func (m *UserPermission) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UserPermission.Unmarshal(m, b) @@ -298,7 +298,7 @@ func (m *DbPermission) Reset() { *m = DbPermission{} } func (m *DbPermission) String() string { return proto.CompactTextString(m) } func (*DbPermission) ProtoMessage() {} func (*DbPermission) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{4} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{4} } func (m *DbPermission) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DbPermission.Unmarshal(m, b) @@ -360,7 +360,7 @@ func (m *Permissions) Reset() { *m = Permissions{} } func (m *Permissions) String() string { return proto.CompactTextString(m) } func (*Permissions) ProtoMessage() {} func (*Permissions) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{5} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{5} } func (m *Permissions) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Permissions.Unmarshal(m, b) @@ -405,7 +405,7 @@ func (m *PingRequest) Reset() { *m = PingRequest{} } func (m *PingRequest) String() string { return proto.CompactTextString(m) } func (*PingRequest) ProtoMessage() {} func (*PingRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{6} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{6} } func (m *PingRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PingRequest.Unmarshal(m, b) @@ -443,7 +443,7 @@ func (m *PingResponse) Reset() { *m = PingResponse{} } func (m *PingResponse) String() string { return proto.CompactTextString(m) } func (*PingResponse) ProtoMessage() {} func (*PingResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{7} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{7} } func (m *PingResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PingResponse.Unmarshal(m, b) @@ -482,7 +482,7 @@ func (m *SleepRequest) Reset() { *m = SleepRequest{} } func (m *SleepRequest) String() string { return proto.CompactTextString(m) } func (*SleepRequest) ProtoMessage() {} func (*SleepRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{8} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{8} } func (m *SleepRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SleepRequest.Unmarshal(m, b) @@ -519,7 +519,7 @@ func (m *SleepResponse) Reset() { *m = SleepResponse{} } func (m *SleepResponse) String() string { return proto.CompactTextString(m) } func (*SleepResponse) ProtoMessage() {} func (*SleepResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{9} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{9} } func (m *SleepResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SleepResponse.Unmarshal(m, b) @@ -552,7 +552,7 @@ func (m *ExecuteHookRequest) Reset() { *m = ExecuteHookRequest{} } func (m *ExecuteHookRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteHookRequest) ProtoMessage() {} func (*ExecuteHookRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{10} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{10} } func (m *ExecuteHookRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteHookRequest.Unmarshal(m, b) @@ -606,7 +606,7 @@ func (m *ExecuteHookResponse) Reset() { *m = ExecuteHookResponse{} } func (m *ExecuteHookResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteHookResponse) ProtoMessage() {} func (*ExecuteHookResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{11} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{11} } func (m *ExecuteHookResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteHookResponse.Unmarshal(m, b) @@ -660,7 +660,7 @@ func (m *GetSchemaRequest) Reset() { *m = GetSchemaRequest{} } func (m *GetSchemaRequest) String() string { return proto.CompactTextString(m) } func (*GetSchemaRequest) ProtoMessage() {} func (*GetSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{12} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{12} } func (m *GetSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSchemaRequest.Unmarshal(m, b) @@ -712,7 +712,7 @@ func (m *GetSchemaResponse) Reset() { *m = GetSchemaResponse{} } func (m *GetSchemaResponse) String() string { return proto.CompactTextString(m) } func (*GetSchemaResponse) ProtoMessage() {} func (*GetSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{13} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{13} } func (m *GetSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSchemaResponse.Unmarshal(m, b) @@ -749,7 +749,7 @@ func (m *GetPermissionsRequest) Reset() { *m = GetPermissionsRequest{} } func (m *GetPermissionsRequest) String() string { return proto.CompactTextString(m) } func (*GetPermissionsRequest) ProtoMessage() {} func (*GetPermissionsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{14} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{14} } func (m *GetPermissionsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetPermissionsRequest.Unmarshal(m, b) @@ -780,7 +780,7 @@ func (m *GetPermissionsResponse) Reset() { *m = GetPermissionsResponse{} func (m *GetPermissionsResponse) String() string { return proto.CompactTextString(m) } func (*GetPermissionsResponse) ProtoMessage() {} func (*GetPermissionsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{15} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{15} } func (m *GetPermissionsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetPermissionsResponse.Unmarshal(m, b) @@ -817,7 +817,7 @@ func (m *SetReadOnlyRequest) Reset() { *m = SetReadOnlyRequest{} } func (m *SetReadOnlyRequest) String() string { return proto.CompactTextString(m) } func (*SetReadOnlyRequest) ProtoMessage() {} func (*SetReadOnlyRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{16} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{16} } func (m *SetReadOnlyRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadOnlyRequest.Unmarshal(m, b) @@ -847,7 +847,7 @@ func (m *SetReadOnlyResponse) Reset() { *m = SetReadOnlyResponse{} } func (m *SetReadOnlyResponse) String() string { return proto.CompactTextString(m) } func (*SetReadOnlyResponse) ProtoMessage() {} func (*SetReadOnlyResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{17} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{17} } func (m *SetReadOnlyResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadOnlyResponse.Unmarshal(m, b) @@ -877,7 +877,7 @@ func (m *SetReadWriteRequest) Reset() { *m = SetReadWriteRequest{} } func (m *SetReadWriteRequest) String() string { return proto.CompactTextString(m) } func (*SetReadWriteRequest) ProtoMessage() {} func (*SetReadWriteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{18} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{18} } func (m *SetReadWriteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadWriteRequest.Unmarshal(m, b) @@ -907,7 +907,7 @@ func (m *SetReadWriteResponse) Reset() { *m = SetReadWriteResponse{} } func (m *SetReadWriteResponse) String() string { return proto.CompactTextString(m) } func (*SetReadWriteResponse) ProtoMessage() {} func (*SetReadWriteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{19} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{19} } func (m *SetReadWriteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetReadWriteResponse.Unmarshal(m, b) @@ -938,7 +938,7 @@ func (m *ChangeTypeRequest) Reset() { *m = ChangeTypeRequest{} } func (m *ChangeTypeRequest) String() string { return proto.CompactTextString(m) } func (*ChangeTypeRequest) ProtoMessage() {} func (*ChangeTypeRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{20} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{20} } func (m *ChangeTypeRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChangeTypeRequest.Unmarshal(m, b) @@ -975,7 +975,7 @@ func (m *ChangeTypeResponse) Reset() { *m = ChangeTypeResponse{} } func (m *ChangeTypeResponse) String() string { return proto.CompactTextString(m) } func (*ChangeTypeResponse) ProtoMessage() {} func (*ChangeTypeResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{21} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{21} } func (m *ChangeTypeResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ChangeTypeResponse.Unmarshal(m, b) @@ -1005,7 +1005,7 @@ func (m *RefreshStateRequest) Reset() { *m = RefreshStateRequest{} } func (m *RefreshStateRequest) String() string { return proto.CompactTextString(m) } func (*RefreshStateRequest) ProtoMessage() {} func (*RefreshStateRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{22} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{22} } func (m *RefreshStateRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RefreshStateRequest.Unmarshal(m, b) @@ -1035,7 +1035,7 @@ func (m *RefreshStateResponse) Reset() { *m = RefreshStateResponse{} } func (m *RefreshStateResponse) String() string { return proto.CompactTextString(m) } func (*RefreshStateResponse) ProtoMessage() {} func (*RefreshStateResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{23} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{23} } func (m *RefreshStateResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RefreshStateResponse.Unmarshal(m, b) @@ -1065,7 +1065,7 @@ func (m *RunHealthCheckRequest) Reset() { *m = RunHealthCheckRequest{} } func (m *RunHealthCheckRequest) String() string { return proto.CompactTextString(m) } func (*RunHealthCheckRequest) ProtoMessage() {} func (*RunHealthCheckRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{24} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{24} } func (m *RunHealthCheckRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RunHealthCheckRequest.Unmarshal(m, b) @@ -1095,7 +1095,7 @@ func (m *RunHealthCheckResponse) Reset() { *m = RunHealthCheckResponse{} func (m *RunHealthCheckResponse) String() string { return proto.CompactTextString(m) } func (*RunHealthCheckResponse) ProtoMessage() {} func (*RunHealthCheckResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{25} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{25} } func (m *RunHealthCheckResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RunHealthCheckResponse.Unmarshal(m, b) @@ -1126,7 +1126,7 @@ func (m *IgnoreHealthErrorRequest) Reset() { *m = IgnoreHealthErrorReque func (m *IgnoreHealthErrorRequest) String() string { return proto.CompactTextString(m) } func (*IgnoreHealthErrorRequest) ProtoMessage() {} func (*IgnoreHealthErrorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{26} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{26} } func (m *IgnoreHealthErrorRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IgnoreHealthErrorRequest.Unmarshal(m, b) @@ -1163,7 +1163,7 @@ func (m *IgnoreHealthErrorResponse) Reset() { *m = IgnoreHealthErrorResp func (m *IgnoreHealthErrorResponse) String() string { return proto.CompactTextString(m) } func (*IgnoreHealthErrorResponse) ProtoMessage() {} func (*IgnoreHealthErrorResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{27} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{27} } func (m *IgnoreHealthErrorResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IgnoreHealthErrorResponse.Unmarshal(m, b) @@ -1197,7 +1197,7 @@ func (m *ReloadSchemaRequest) Reset() { *m = ReloadSchemaRequest{} } func (m *ReloadSchemaRequest) String() string { return proto.CompactTextString(m) } func (*ReloadSchemaRequest) ProtoMessage() {} func (*ReloadSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{28} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{28} } func (m *ReloadSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReloadSchemaRequest.Unmarshal(m, b) @@ -1234,7 +1234,7 @@ func (m *ReloadSchemaResponse) Reset() { *m = ReloadSchemaResponse{} } func (m *ReloadSchemaResponse) String() string { return proto.CompactTextString(m) } func (*ReloadSchemaResponse) ProtoMessage() {} func (*ReloadSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{29} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{29} } func (m *ReloadSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReloadSchemaResponse.Unmarshal(m, b) @@ -1265,7 +1265,7 @@ func (m *PreflightSchemaRequest) Reset() { *m = PreflightSchemaRequest{} func (m *PreflightSchemaRequest) String() string { return proto.CompactTextString(m) } func (*PreflightSchemaRequest) ProtoMessage() {} func (*PreflightSchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{30} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{30} } func (m *PreflightSchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PreflightSchemaRequest.Unmarshal(m, b) @@ -1305,7 +1305,7 @@ func (m *PreflightSchemaResponse) Reset() { *m = PreflightSchemaResponse func (m *PreflightSchemaResponse) String() string { return proto.CompactTextString(m) } func (*PreflightSchemaResponse) ProtoMessage() {} func (*PreflightSchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{31} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{31} } func (m *PreflightSchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PreflightSchemaResponse.Unmarshal(m, b) @@ -1347,7 +1347,7 @@ func (m *ApplySchemaRequest) Reset() { *m = ApplySchemaRequest{} } func (m *ApplySchemaRequest) String() string { return proto.CompactTextString(m) } func (*ApplySchemaRequest) ProtoMessage() {} func (*ApplySchemaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{32} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{32} } func (m *ApplySchemaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ApplySchemaRequest.Unmarshal(m, b) @@ -1414,7 +1414,7 @@ func (m *ApplySchemaResponse) Reset() { *m = ApplySchemaResponse{} } func (m *ApplySchemaResponse) String() string { return proto.CompactTextString(m) } func (*ApplySchemaResponse) ProtoMessage() {} func (*ApplySchemaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{33} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{33} } func (m *ApplySchemaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ApplySchemaResponse.Unmarshal(m, b) @@ -1458,7 +1458,7 @@ func (m *LockTablesRequest) Reset() { *m = LockTablesRequest{} } func (m *LockTablesRequest) String() string { return proto.CompactTextString(m) } func (*LockTablesRequest) ProtoMessage() {} func (*LockTablesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{34} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{34} } func (m *LockTablesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LockTablesRequest.Unmarshal(m, b) @@ -1488,7 +1488,7 @@ func (m *LockTablesResponse) Reset() { *m = LockTablesResponse{} } func (m *LockTablesResponse) String() string { return proto.CompactTextString(m) } func (*LockTablesResponse) ProtoMessage() {} func (*LockTablesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{35} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{35} } func (m *LockTablesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LockTablesResponse.Unmarshal(m, b) @@ -1518,7 +1518,7 @@ func (m *UnlockTablesRequest) Reset() { *m = UnlockTablesRequest{} } func (m *UnlockTablesRequest) String() string { return proto.CompactTextString(m) } func (*UnlockTablesRequest) ProtoMessage() {} func (*UnlockTablesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{36} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{36} } func (m *UnlockTablesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UnlockTablesRequest.Unmarshal(m, b) @@ -1548,7 +1548,7 @@ func (m *UnlockTablesResponse) Reset() { *m = UnlockTablesResponse{} } func (m *UnlockTablesResponse) String() string { return proto.CompactTextString(m) } func (*UnlockTablesResponse) ProtoMessage() {} func (*UnlockTablesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{37} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{37} } func (m *UnlockTablesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UnlockTablesResponse.Unmarshal(m, b) @@ -1583,7 +1583,7 @@ func (m *ExecuteFetchAsDbaRequest) Reset() { *m = ExecuteFetchAsDbaReque func (m *ExecuteFetchAsDbaRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsDbaRequest) ProtoMessage() {} func (*ExecuteFetchAsDbaRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{38} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{38} } func (m *ExecuteFetchAsDbaRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsDbaRequest.Unmarshal(m, b) @@ -1649,7 +1649,7 @@ func (m *ExecuteFetchAsDbaResponse) Reset() { *m = ExecuteFetchAsDbaResp func (m *ExecuteFetchAsDbaResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsDbaResponse) ProtoMessage() {} func (*ExecuteFetchAsDbaResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{39} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{39} } func (m *ExecuteFetchAsDbaResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsDbaResponse.Unmarshal(m, b) @@ -1690,7 +1690,7 @@ func (m *ExecuteFetchAsAllPrivsRequest) Reset() { *m = ExecuteFetchAsAll func (m *ExecuteFetchAsAllPrivsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAllPrivsRequest) ProtoMessage() {} func (*ExecuteFetchAsAllPrivsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{40} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{40} } func (m *ExecuteFetchAsAllPrivsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAllPrivsRequest.Unmarshal(m, b) @@ -1749,7 +1749,7 @@ func (m *ExecuteFetchAsAllPrivsResponse) Reset() { *m = ExecuteFetchAsAl func (m *ExecuteFetchAsAllPrivsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAllPrivsResponse) ProtoMessage() {} func (*ExecuteFetchAsAllPrivsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{41} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{41} } func (m *ExecuteFetchAsAllPrivsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAllPrivsResponse.Unmarshal(m, b) @@ -1788,7 +1788,7 @@ func (m *ExecuteFetchAsAppRequest) Reset() { *m = ExecuteFetchAsAppReque func (m *ExecuteFetchAsAppRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAppRequest) ProtoMessage() {} func (*ExecuteFetchAsAppRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{42} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{42} } func (m *ExecuteFetchAsAppRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAppRequest.Unmarshal(m, b) @@ -1833,7 +1833,7 @@ func (m *ExecuteFetchAsAppResponse) Reset() { *m = ExecuteFetchAsAppResp func (m *ExecuteFetchAsAppResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteFetchAsAppResponse) ProtoMessage() {} func (*ExecuteFetchAsAppResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{43} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{43} } func (m *ExecuteFetchAsAppResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteFetchAsAppResponse.Unmarshal(m, b) @@ -1870,7 +1870,7 @@ func (m *SlaveStatusRequest) Reset() { *m = SlaveStatusRequest{} } func (m *SlaveStatusRequest) String() string { return proto.CompactTextString(m) } func (*SlaveStatusRequest) ProtoMessage() {} func (*SlaveStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{44} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{44} } func (m *SlaveStatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveStatusRequest.Unmarshal(m, b) @@ -1901,7 +1901,7 @@ func (m *SlaveStatusResponse) Reset() { *m = SlaveStatusResponse{} } func (m *SlaveStatusResponse) String() string { return proto.CompactTextString(m) } func (*SlaveStatusResponse) ProtoMessage() {} func (*SlaveStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{45} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{45} } func (m *SlaveStatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveStatusResponse.Unmarshal(m, b) @@ -1938,7 +1938,7 @@ func (m *MasterPositionRequest) Reset() { *m = MasterPositionRequest{} } func (m *MasterPositionRequest) String() string { return proto.CompactTextString(m) } func (*MasterPositionRequest) ProtoMessage() {} func (*MasterPositionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{46} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{46} } func (m *MasterPositionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MasterPositionRequest.Unmarshal(m, b) @@ -1969,7 +1969,7 @@ func (m *MasterPositionResponse) Reset() { *m = MasterPositionResponse{} func (m *MasterPositionResponse) String() string { return proto.CompactTextString(m) } func (*MasterPositionResponse) ProtoMessage() {} func (*MasterPositionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{47} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{47} } func (m *MasterPositionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MasterPositionResponse.Unmarshal(m, b) @@ -2006,7 +2006,7 @@ func (m *StopSlaveRequest) Reset() { *m = StopSlaveRequest{} } func (m *StopSlaveRequest) String() string { return proto.CompactTextString(m) } func (*StopSlaveRequest) ProtoMessage() {} func (*StopSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{48} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{48} } func (m *StopSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveRequest.Unmarshal(m, b) @@ -2036,7 +2036,7 @@ func (m *StopSlaveResponse) Reset() { *m = StopSlaveResponse{} } func (m *StopSlaveResponse) String() string { return proto.CompactTextString(m) } func (*StopSlaveResponse) ProtoMessage() {} func (*StopSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{49} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{49} } func (m *StopSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveResponse.Unmarshal(m, b) @@ -2068,7 +2068,7 @@ func (m *StopSlaveMinimumRequest) Reset() { *m = StopSlaveMinimumRequest func (m *StopSlaveMinimumRequest) String() string { return proto.CompactTextString(m) } func (*StopSlaveMinimumRequest) ProtoMessage() {} func (*StopSlaveMinimumRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{50} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{50} } func (m *StopSlaveMinimumRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveMinimumRequest.Unmarshal(m, b) @@ -2113,7 +2113,7 @@ func (m *StopSlaveMinimumResponse) Reset() { *m = StopSlaveMinimumRespon func (m *StopSlaveMinimumResponse) String() string { return proto.CompactTextString(m) } func (*StopSlaveMinimumResponse) ProtoMessage() {} func (*StopSlaveMinimumResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{51} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{51} } func (m *StopSlaveMinimumResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopSlaveMinimumResponse.Unmarshal(m, b) @@ -2150,7 +2150,7 @@ func (m *StartSlaveRequest) Reset() { *m = StartSlaveRequest{} } func (m *StartSlaveRequest) String() string { return proto.CompactTextString(m) } func (*StartSlaveRequest) ProtoMessage() {} func (*StartSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{52} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{52} } func (m *StartSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveRequest.Unmarshal(m, b) @@ -2180,7 +2180,7 @@ func (m *StartSlaveResponse) Reset() { *m = StartSlaveResponse{} } func (m *StartSlaveResponse) String() string { return proto.CompactTextString(m) } func (*StartSlaveResponse) ProtoMessage() {} func (*StartSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{53} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{53} } func (m *StartSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveResponse.Unmarshal(m, b) @@ -2212,7 +2212,7 @@ func (m *StartSlaveUntilAfterRequest) Reset() { *m = StartSlaveUntilAfte func (m *StartSlaveUntilAfterRequest) String() string { return proto.CompactTextString(m) } func (*StartSlaveUntilAfterRequest) ProtoMessage() {} func (*StartSlaveUntilAfterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{54} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{54} } func (m *StartSlaveUntilAfterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveUntilAfterRequest.Unmarshal(m, b) @@ -2256,7 +2256,7 @@ func (m *StartSlaveUntilAfterResponse) Reset() { *m = StartSlaveUntilAft func (m *StartSlaveUntilAfterResponse) String() string { return proto.CompactTextString(m) } func (*StartSlaveUntilAfterResponse) ProtoMessage() {} func (*StartSlaveUntilAfterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{55} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{55} } func (m *StartSlaveUntilAfterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StartSlaveUntilAfterResponse.Unmarshal(m, b) @@ -2290,7 +2290,7 @@ func (m *TabletExternallyReparentedRequest) Reset() { *m = TabletExterna func (m *TabletExternallyReparentedRequest) String() string { return proto.CompactTextString(m) } func (*TabletExternallyReparentedRequest) ProtoMessage() {} func (*TabletExternallyReparentedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{56} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{56} } func (m *TabletExternallyReparentedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyReparentedRequest.Unmarshal(m, b) @@ -2327,7 +2327,7 @@ func (m *TabletExternallyReparentedResponse) Reset() { *m = TabletExtern func (m *TabletExternallyReparentedResponse) String() string { return proto.CompactTextString(m) } func (*TabletExternallyReparentedResponse) ProtoMessage() {} func (*TabletExternallyReparentedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{57} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{57} } func (m *TabletExternallyReparentedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyReparentedResponse.Unmarshal(m, b) @@ -2357,7 +2357,7 @@ func (m *TabletExternallyElectedRequest) Reset() { *m = TabletExternally func (m *TabletExternallyElectedRequest) String() string { return proto.CompactTextString(m) } func (*TabletExternallyElectedRequest) ProtoMessage() {} func (*TabletExternallyElectedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{58} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{58} } func (m *TabletExternallyElectedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyElectedRequest.Unmarshal(m, b) @@ -2387,7 +2387,7 @@ func (m *TabletExternallyElectedResponse) Reset() { *m = TabletExternall func (m *TabletExternallyElectedResponse) String() string { return proto.CompactTextString(m) } func (*TabletExternallyElectedResponse) ProtoMessage() {} func (*TabletExternallyElectedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{59} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{59} } func (m *TabletExternallyElectedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TabletExternallyElectedResponse.Unmarshal(m, b) @@ -2417,7 +2417,7 @@ func (m *GetSlavesRequest) Reset() { *m = GetSlavesRequest{} } func (m *GetSlavesRequest) String() string { return proto.CompactTextString(m) } func (*GetSlavesRequest) ProtoMessage() {} func (*GetSlavesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{60} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{60} } func (m *GetSlavesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSlavesRequest.Unmarshal(m, b) @@ -2448,7 +2448,7 @@ func (m *GetSlavesResponse) Reset() { *m = GetSlavesResponse{} } func (m *GetSlavesResponse) String() string { return proto.CompactTextString(m) } func (*GetSlavesResponse) ProtoMessage() {} func (*GetSlavesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{61} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{61} } func (m *GetSlavesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSlavesResponse.Unmarshal(m, b) @@ -2485,7 +2485,7 @@ func (m *ResetReplicationRequest) Reset() { *m = ResetReplicationRequest func (m *ResetReplicationRequest) String() string { return proto.CompactTextString(m) } func (*ResetReplicationRequest) ProtoMessage() {} func (*ResetReplicationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{62} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{62} } func (m *ResetReplicationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResetReplicationRequest.Unmarshal(m, b) @@ -2515,7 +2515,7 @@ func (m *ResetReplicationResponse) Reset() { *m = ResetReplicationRespon func (m *ResetReplicationResponse) String() string { return proto.CompactTextString(m) } func (*ResetReplicationResponse) ProtoMessage() {} func (*ResetReplicationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{63} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{63} } func (m *ResetReplicationResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResetReplicationResponse.Unmarshal(m, b) @@ -2546,7 +2546,7 @@ func (m *VReplicationExecRequest) Reset() { *m = VReplicationExecRequest func (m *VReplicationExecRequest) String() string { return proto.CompactTextString(m) } func (*VReplicationExecRequest) ProtoMessage() {} func (*VReplicationExecRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{64} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{64} } func (m *VReplicationExecRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VReplicationExecRequest.Unmarshal(m, b) @@ -2584,7 +2584,7 @@ func (m *VReplicationExecResponse) Reset() { *m = VReplicationExecRespon func (m *VReplicationExecResponse) String() string { return proto.CompactTextString(m) } func (*VReplicationExecResponse) ProtoMessage() {} func (*VReplicationExecResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{65} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{65} } func (m *VReplicationExecResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VReplicationExecResponse.Unmarshal(m, b) @@ -2623,7 +2623,7 @@ func (m *VReplicationWaitForPosRequest) Reset() { *m = VReplicationWaitF func (m *VReplicationWaitForPosRequest) String() string { return proto.CompactTextString(m) } func (*VReplicationWaitForPosRequest) ProtoMessage() {} func (*VReplicationWaitForPosRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{66} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{66} } func (m *VReplicationWaitForPosRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VReplicationWaitForPosRequest.Unmarshal(m, b) @@ -2667,7 +2667,7 @@ func (m *VReplicationWaitForPosResponse) Reset() { *m = VReplicationWait func (m *VReplicationWaitForPosResponse) String() string { return proto.CompactTextString(m) } func (*VReplicationWaitForPosResponse) ProtoMessage() {} func (*VReplicationWaitForPosResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{67} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{67} } func (m *VReplicationWaitForPosResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VReplicationWaitForPosResponse.Unmarshal(m, b) @@ -2697,7 +2697,7 @@ func (m *InitMasterRequest) Reset() { *m = InitMasterRequest{} } func (m *InitMasterRequest) String() string { return proto.CompactTextString(m) } func (*InitMasterRequest) ProtoMessage() {} func (*InitMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{68} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{68} } func (m *InitMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitMasterRequest.Unmarshal(m, b) @@ -2728,7 +2728,7 @@ func (m *InitMasterResponse) Reset() { *m = InitMasterResponse{} } func (m *InitMasterResponse) String() string { return proto.CompactTextString(m) } func (*InitMasterResponse) ProtoMessage() {} func (*InitMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{69} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{69} } func (m *InitMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitMasterResponse.Unmarshal(m, b) @@ -2769,7 +2769,7 @@ func (m *PopulateReparentJournalRequest) Reset() { *m = PopulateReparent func (m *PopulateReparentJournalRequest) String() string { return proto.CompactTextString(m) } func (*PopulateReparentJournalRequest) ProtoMessage() {} func (*PopulateReparentJournalRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{70} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{70} } func (m *PopulateReparentJournalRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PopulateReparentJournalRequest.Unmarshal(m, b) @@ -2827,7 +2827,7 @@ func (m *PopulateReparentJournalResponse) Reset() { *m = PopulateReparen func (m *PopulateReparentJournalResponse) String() string { return proto.CompactTextString(m) } func (*PopulateReparentJournalResponse) ProtoMessage() {} func (*PopulateReparentJournalResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{71} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{71} } func (m *PopulateReparentJournalResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PopulateReparentJournalResponse.Unmarshal(m, b) @@ -2860,7 +2860,7 @@ func (m *InitSlaveRequest) Reset() { *m = InitSlaveRequest{} } func (m *InitSlaveRequest) String() string { return proto.CompactTextString(m) } func (*InitSlaveRequest) ProtoMessage() {} func (*InitSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{72} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{72} } func (m *InitSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitSlaveRequest.Unmarshal(m, b) @@ -2911,7 +2911,7 @@ func (m *InitSlaveResponse) Reset() { *m = InitSlaveResponse{} } func (m *InitSlaveResponse) String() string { return proto.CompactTextString(m) } func (*InitSlaveResponse) ProtoMessage() {} func (*InitSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{73} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{73} } func (m *InitSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_InitSlaveResponse.Unmarshal(m, b) @@ -2941,7 +2941,7 @@ func (m *DemoteMasterRequest) Reset() { *m = DemoteMasterRequest{} } func (m *DemoteMasterRequest) String() string { return proto.CompactTextString(m) } func (*DemoteMasterRequest) ProtoMessage() {} func (*DemoteMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{74} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{74} } func (m *DemoteMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DemoteMasterRequest.Unmarshal(m, b) @@ -2972,7 +2972,7 @@ func (m *DemoteMasterResponse) Reset() { *m = DemoteMasterResponse{} } func (m *DemoteMasterResponse) String() string { return proto.CompactTextString(m) } func (*DemoteMasterResponse) ProtoMessage() {} func (*DemoteMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{75} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{75} } func (m *DemoteMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_DemoteMasterResponse.Unmarshal(m, b) @@ -3009,7 +3009,7 @@ func (m *UndoDemoteMasterRequest) Reset() { *m = UndoDemoteMasterRequest func (m *UndoDemoteMasterRequest) String() string { return proto.CompactTextString(m) } func (*UndoDemoteMasterRequest) ProtoMessage() {} func (*UndoDemoteMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{76} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{76} } func (m *UndoDemoteMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UndoDemoteMasterRequest.Unmarshal(m, b) @@ -3039,7 +3039,7 @@ func (m *UndoDemoteMasterResponse) Reset() { *m = UndoDemoteMasterRespon func (m *UndoDemoteMasterResponse) String() string { return proto.CompactTextString(m) } func (*UndoDemoteMasterResponse) ProtoMessage() {} func (*UndoDemoteMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{77} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{77} } func (m *UndoDemoteMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UndoDemoteMasterResponse.Unmarshal(m, b) @@ -3070,7 +3070,7 @@ func (m *PromoteSlaveWhenCaughtUpRequest) Reset() { *m = PromoteSlaveWhe func (m *PromoteSlaveWhenCaughtUpRequest) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveWhenCaughtUpRequest) ProtoMessage() {} func (*PromoteSlaveWhenCaughtUpRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{78} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{78} } func (m *PromoteSlaveWhenCaughtUpRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveWhenCaughtUpRequest.Unmarshal(m, b) @@ -3108,7 +3108,7 @@ func (m *PromoteSlaveWhenCaughtUpResponse) Reset() { *m = PromoteSlaveWh func (m *PromoteSlaveWhenCaughtUpResponse) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveWhenCaughtUpResponse) ProtoMessage() {} func (*PromoteSlaveWhenCaughtUpResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{79} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{79} } func (m *PromoteSlaveWhenCaughtUpResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveWhenCaughtUpResponse.Unmarshal(m, b) @@ -3145,7 +3145,7 @@ func (m *SlaveWasPromotedRequest) Reset() { *m = SlaveWasPromotedRequest func (m *SlaveWasPromotedRequest) String() string { return proto.CompactTextString(m) } func (*SlaveWasPromotedRequest) ProtoMessage() {} func (*SlaveWasPromotedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{80} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{80} } func (m *SlaveWasPromotedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasPromotedRequest.Unmarshal(m, b) @@ -3175,7 +3175,7 @@ func (m *SlaveWasPromotedResponse) Reset() { *m = SlaveWasPromotedRespon func (m *SlaveWasPromotedResponse) String() string { return proto.CompactTextString(m) } func (*SlaveWasPromotedResponse) ProtoMessage() {} func (*SlaveWasPromotedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{81} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{81} } func (m *SlaveWasPromotedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasPromotedResponse.Unmarshal(m, b) @@ -3208,7 +3208,7 @@ func (m *SetMasterRequest) Reset() { *m = SetMasterRequest{} } func (m *SetMasterRequest) String() string { return proto.CompactTextString(m) } func (*SetMasterRequest) ProtoMessage() {} func (*SetMasterRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{82} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{82} } func (m *SetMasterRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetMasterRequest.Unmarshal(m, b) @@ -3259,7 +3259,7 @@ func (m *SetMasterResponse) Reset() { *m = SetMasterResponse{} } func (m *SetMasterResponse) String() string { return proto.CompactTextString(m) } func (*SetMasterResponse) ProtoMessage() {} func (*SetMasterResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{83} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{83} } func (m *SetMasterResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SetMasterResponse.Unmarshal(m, b) @@ -3291,7 +3291,7 @@ func (m *SlaveWasRestartedRequest) Reset() { *m = SlaveWasRestartedReque func (m *SlaveWasRestartedRequest) String() string { return proto.CompactTextString(m) } func (*SlaveWasRestartedRequest) ProtoMessage() {} func (*SlaveWasRestartedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{84} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{84} } func (m *SlaveWasRestartedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasRestartedRequest.Unmarshal(m, b) @@ -3328,7 +3328,7 @@ func (m *SlaveWasRestartedResponse) Reset() { *m = SlaveWasRestartedResp func (m *SlaveWasRestartedResponse) String() string { return proto.CompactTextString(m) } func (*SlaveWasRestartedResponse) ProtoMessage() {} func (*SlaveWasRestartedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{85} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{85} } func (m *SlaveWasRestartedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SlaveWasRestartedResponse.Unmarshal(m, b) @@ -3358,7 +3358,7 @@ func (m *StopReplicationAndGetStatusRequest) Reset() { *m = StopReplicat func (m *StopReplicationAndGetStatusRequest) String() string { return proto.CompactTextString(m) } func (*StopReplicationAndGetStatusRequest) ProtoMessage() {} func (*StopReplicationAndGetStatusRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{86} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{86} } func (m *StopReplicationAndGetStatusRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopReplicationAndGetStatusRequest.Unmarshal(m, b) @@ -3389,7 +3389,7 @@ func (m *StopReplicationAndGetStatusResponse) Reset() { *m = StopReplica func (m *StopReplicationAndGetStatusResponse) String() string { return proto.CompactTextString(m) } func (*StopReplicationAndGetStatusResponse) ProtoMessage() {} func (*StopReplicationAndGetStatusResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{87} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{87} } func (m *StopReplicationAndGetStatusResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StopReplicationAndGetStatusResponse.Unmarshal(m, b) @@ -3426,7 +3426,7 @@ func (m *PromoteSlaveRequest) Reset() { *m = PromoteSlaveRequest{} } func (m *PromoteSlaveRequest) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveRequest) ProtoMessage() {} func (*PromoteSlaveRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{88} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{88} } func (m *PromoteSlaveRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveRequest.Unmarshal(m, b) @@ -3457,7 +3457,7 @@ func (m *PromoteSlaveResponse) Reset() { *m = PromoteSlaveResponse{} } func (m *PromoteSlaveResponse) String() string { return proto.CompactTextString(m) } func (*PromoteSlaveResponse) ProtoMessage() {} func (*PromoteSlaveResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{89} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{89} } func (m *PromoteSlaveResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PromoteSlaveResponse.Unmarshal(m, b) @@ -3486,6 +3486,7 @@ func (m *PromoteSlaveResponse) GetPosition() string { type BackupRequest struct { Concurrency int64 `protobuf:"varint,1,opt,name=concurrency,proto3" json:"concurrency,omitempty"` + AllowMaster bool `protobuf:"varint,2,opt,name=allowMaster,proto3" json:"allowMaster,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_unrecognized []byte `json:"-"` XXX_sizecache int32 `json:"-"` @@ -3495,7 +3496,7 @@ func (m *BackupRequest) Reset() { *m = BackupRequest{} } func (m *BackupRequest) String() string { return proto.CompactTextString(m) } func (*BackupRequest) ProtoMessage() {} func (*BackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{90} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{90} } func (m *BackupRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BackupRequest.Unmarshal(m, b) @@ -3522,6 +3523,13 @@ func (m *BackupRequest) GetConcurrency() int64 { return 0 } +func (m *BackupRequest) GetAllowMaster() bool { + if m != nil { + return m.AllowMaster + } + return false +} + type BackupResponse struct { Event *logutil.Event `protobuf:"bytes,1,opt,name=event,proto3" json:"event,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -3533,7 +3541,7 @@ func (m *BackupResponse) Reset() { *m = BackupResponse{} } func (m *BackupResponse) String() string { return proto.CompactTextString(m) } func (*BackupResponse) ProtoMessage() {} func (*BackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{91} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{91} } func (m *BackupResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BackupResponse.Unmarshal(m, b) @@ -3570,7 +3578,7 @@ func (m *RestoreFromBackupRequest) Reset() { *m = RestoreFromBackupReque func (m *RestoreFromBackupRequest) String() string { return proto.CompactTextString(m) } func (*RestoreFromBackupRequest) ProtoMessage() {} func (*RestoreFromBackupRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{92} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{92} } func (m *RestoreFromBackupRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RestoreFromBackupRequest.Unmarshal(m, b) @@ -3601,7 +3609,7 @@ func (m *RestoreFromBackupResponse) Reset() { *m = RestoreFromBackupResp func (m *RestoreFromBackupResponse) String() string { return proto.CompactTextString(m) } func (*RestoreFromBackupResponse) ProtoMessage() {} func (*RestoreFromBackupResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_tabletmanagerdata_56f589a6303df775, []int{93} + return fileDescriptor_tabletmanagerdata_3063cd7e973e1b02, []int{93} } func (m *RestoreFromBackupResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RestoreFromBackupResponse.Unmarshal(m, b) @@ -3729,138 +3737,139 @@ func init() { } func init() { - proto.RegisterFile("tabletmanagerdata.proto", fileDescriptor_tabletmanagerdata_56f589a6303df775) -} - -var fileDescriptor_tabletmanagerdata_56f589a6303df775 = []byte{ - // 2063 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x59, 0x5f, 0x6f, 0x1b, 0xc7, - 0x11, 0x07, 0x49, 0x49, 0x96, 0x86, 0x7f, 0x44, 0x1e, 0x29, 0x91, 0x92, 0x1b, 0x49, 0x3e, 0x3b, - 0x8d, 0xeb, 0xa2, 0x54, 0xac, 0xa4, 0x41, 0x90, 0x22, 0x45, 0x65, 0x59, 0xb2, 0x9d, 0x28, 0xb1, - 0x72, 0xb2, 0xec, 0x22, 0x28, 0x70, 0x58, 0xf2, 0x56, 0xe4, 0x41, 0xc7, 0xdb, 0xf3, 0xee, 0x1e, - 0x25, 0x7e, 0x89, 0xbe, 0xf5, 0xad, 0x6f, 0x05, 0xda, 0xf7, 0x7e, 0x98, 0x14, 0xfd, 0x24, 0x7d, - 0xe8, 0x4b, 0xb1, 0x7f, 0x8e, 0xdc, 0x23, 0x8f, 0xb6, 0x24, 0xb8, 0x40, 0x5e, 0x84, 0x9b, 0xdf, - 0xcc, 0xce, 0xbf, 0x9d, 0x99, 0x1d, 0x42, 0xd0, 0xe4, 0xa8, 0x13, 0x60, 0x3e, 0x40, 0x21, 0xea, - 0x61, 0xea, 0x21, 0x8e, 0xda, 0x11, 0x25, 0x9c, 0x58, 0xb5, 0x19, 0xc6, 0x66, 0xf1, 0x6d, 0x8c, - 0xe9, 0x48, 0xf1, 0x37, 0x2b, 0x9c, 0x44, 0x64, 0x22, 0xbf, 0xb9, 0x46, 0x71, 0x14, 0xf8, 0x5d, - 0xc4, 0x7d, 0x12, 0x1a, 0x70, 0x39, 0x20, 0xbd, 0x98, 0xfb, 0x81, 0x22, 0xed, 0x7f, 0xe7, 0x60, - 0xf5, 0x95, 0x50, 0xfc, 0x14, 0x9f, 0xfb, 0xa1, 0x2f, 0x84, 0x2d, 0x0b, 0x16, 0x42, 0x34, 0xc0, - 0xad, 0xdc, 0x4e, 0xee, 0xe1, 0x8a, 0x23, 0xbf, 0xad, 0x75, 0x58, 0x62, 0xdd, 0x3e, 0x1e, 0xa0, - 0x56, 0x5e, 0xa2, 0x9a, 0xb2, 0x5a, 0x70, 0xa7, 0x4b, 0x82, 0x78, 0x10, 0xb2, 0x56, 0x61, 0xa7, - 0xf0, 0x70, 0xc5, 0x49, 0x48, 0xab, 0x0d, 0xf5, 0x88, 0xfa, 0x03, 0x44, 0x47, 0xee, 0x05, 0x1e, - 0xb9, 0x89, 0xd4, 0x82, 0x94, 0xaa, 0x69, 0xd6, 0xb7, 0x78, 0x74, 0xa0, 0xe5, 0x2d, 0x58, 0xe0, - 0xa3, 0x08, 0xb7, 0x16, 0x95, 0x55, 0xf1, 0x6d, 0x6d, 0x43, 0x51, 0xb8, 0xee, 0x06, 0x38, 0xec, - 0xf1, 0x7e, 0x6b, 0x69, 0x27, 0xf7, 0x70, 0xc1, 0x01, 0x01, 0x1d, 0x4b, 0xc4, 0xba, 0x0b, 0x2b, - 0x94, 0x5c, 0xba, 0x5d, 0x12, 0x87, 0xbc, 0x75, 0x47, 0xb2, 0x97, 0x29, 0xb9, 0x3c, 0x10, 0xb4, - 0xfd, 0xf7, 0x1c, 0x54, 0x4f, 0xa5, 0x9b, 0x46, 0x70, 0x9f, 0xc0, 0xaa, 0x38, 0xdf, 0x41, 0x0c, - 0xbb, 0x3a, 0x22, 0x15, 0x67, 0x25, 0x81, 0xd5, 0x11, 0xeb, 0x25, 0xa8, 0x8c, 0xbb, 0xde, 0xf8, - 0x30, 0x6b, 0xe5, 0x77, 0x0a, 0x0f, 0x8b, 0x7b, 0x76, 0x7b, 0xf6, 0x92, 0xa6, 0x92, 0xe8, 0x54, - 0x79, 0x1a, 0x60, 0x22, 0x55, 0x43, 0x4c, 0x99, 0x4f, 0xc2, 0x56, 0x41, 0x5a, 0x4c, 0x48, 0xe1, - 0xa8, 0xa5, 0xac, 0x1e, 0xf4, 0x51, 0xd8, 0xc3, 0x0e, 0x66, 0x71, 0xc0, 0xad, 0xe7, 0x50, 0xee, - 0xe0, 0x73, 0x42, 0x53, 0x8e, 0x16, 0xf7, 0xee, 0x67, 0x58, 0x9f, 0x0e, 0xd3, 0x29, 0xa9, 0x93, - 0x3a, 0x96, 0x23, 0x28, 0xa1, 0x73, 0x8e, 0xa9, 0x6b, 0xdc, 0xe1, 0x35, 0x15, 0x15, 0xe5, 0x41, - 0x05, 0xdb, 0xff, 0xc9, 0x41, 0xe5, 0x8c, 0x61, 0x7a, 0x82, 0xe9, 0xc0, 0x67, 0x4c, 0x17, 0x4b, - 0x9f, 0x30, 0x9e, 0x14, 0x8b, 0xf8, 0x16, 0x58, 0xcc, 0x30, 0xd5, 0xa5, 0x22, 0xbf, 0xad, 0x5f, - 0x43, 0x2d, 0x42, 0x8c, 0x5d, 0x12, 0xea, 0xb9, 0xdd, 0x3e, 0xee, 0x5e, 0xb0, 0x78, 0x20, 0xf3, - 0xb0, 0xe0, 0x54, 0x13, 0xc6, 0x81, 0xc6, 0xad, 0x1f, 0x00, 0x22, 0xea, 0x0f, 0xfd, 0x00, 0xf7, - 0xb0, 0x2a, 0x99, 0xe2, 0xde, 0xe3, 0x0c, 0x6f, 0xd3, 0xbe, 0xb4, 0x4f, 0xc6, 0x67, 0x0e, 0x43, - 0x4e, 0x47, 0x8e, 0xa1, 0x64, 0xf3, 0x6b, 0x58, 0x9d, 0x62, 0x5b, 0x55, 0x28, 0x5c, 0xe0, 0x91, - 0xf6, 0x5c, 0x7c, 0x5a, 0x0d, 0x58, 0x1c, 0xa2, 0x20, 0xc6, 0xda, 0x73, 0x45, 0x7c, 0x95, 0xff, - 0x32, 0x67, 0xff, 0x94, 0x83, 0xd2, 0xd3, 0xce, 0x7b, 0xe2, 0xae, 0x40, 0xde, 0xeb, 0xe8, 0xb3, - 0x79, 0xaf, 0x33, 0xce, 0x43, 0xc1, 0xc8, 0xc3, 0xcb, 0x8c, 0xd0, 0x76, 0x33, 0x42, 0x33, 0x8d, - 0xfd, 0x3f, 0x03, 0xfb, 0x5b, 0x0e, 0x8a, 0x13, 0x4b, 0xcc, 0x3a, 0x86, 0xaa, 0xf0, 0xd3, 0x8d, - 0x26, 0x58, 0x2b, 0x27, 0xbd, 0xbc, 0xf7, 0xde, 0x0b, 0x70, 0x56, 0xe3, 0x14, 0xcd, 0xac, 0x23, - 0xa8, 0x78, 0x9d, 0x94, 0x2e, 0xd5, 0x41, 0xdb, 0xef, 0x89, 0xd8, 0x29, 0x7b, 0x06, 0xc5, 0xec, - 0x4f, 0xa0, 0x78, 0xe2, 0x87, 0x3d, 0x07, 0xbf, 0x8d, 0x31, 0xe3, 0xa2, 0x95, 0x22, 0x34, 0x0a, - 0x08, 0xf2, 0x74, 0x90, 0x09, 0x69, 0x3f, 0x84, 0x92, 0x12, 0x64, 0x11, 0x09, 0x19, 0x7e, 0x87, - 0xe4, 0x23, 0x28, 0x9d, 0x06, 0x18, 0x47, 0x89, 0xce, 0x4d, 0x58, 0xf6, 0x62, 0x2a, 0xc7, 0xa5, - 0x14, 0x2d, 0x38, 0x63, 0xda, 0x5e, 0x85, 0xb2, 0x96, 0x55, 0x6a, 0xed, 0x7f, 0xe5, 0xc0, 0x3a, - 0xbc, 0xc2, 0xdd, 0x98, 0xe3, 0xe7, 0x84, 0x5c, 0x24, 0x3a, 0xb2, 0x26, 0xe7, 0x16, 0x40, 0x84, - 0x28, 0x1a, 0x60, 0x8e, 0xa9, 0x0a, 0x7f, 0xc5, 0x31, 0x10, 0xeb, 0x04, 0x56, 0xf0, 0x15, 0xa7, - 0xc8, 0xc5, 0xe1, 0x50, 0xce, 0xd0, 0xe2, 0xde, 0x67, 0x19, 0xd9, 0x99, 0xb5, 0xd6, 0x3e, 0x14, - 0xc7, 0x0e, 0xc3, 0xa1, 0xaa, 0x89, 0x65, 0xac, 0xc9, 0xcd, 0xdf, 0x41, 0x39, 0xc5, 0xba, 0x51, - 0x3d, 0x9c, 0x43, 0x3d, 0x65, 0x4a, 0xe7, 0x71, 0x1b, 0x8a, 0xf8, 0xca, 0xe7, 0x2e, 0xe3, 0x88, - 0xc7, 0x4c, 0x27, 0x08, 0x04, 0x74, 0x2a, 0x11, 0xf9, 0x40, 0x70, 0x8f, 0xc4, 0x7c, 0xfc, 0x40, - 0x48, 0x4a, 0xe3, 0x98, 0x26, 0x5d, 0xa0, 0x29, 0x7b, 0x08, 0xd5, 0x67, 0x98, 0xab, 0xb9, 0x92, - 0xa4, 0x6f, 0x1d, 0x96, 0x64, 0xe0, 0xaa, 0xe2, 0x56, 0x1c, 0x4d, 0x59, 0xf7, 0xa1, 0xec, 0x87, - 0xdd, 0x20, 0xf6, 0xb0, 0x3b, 0xf4, 0xf1, 0x25, 0x93, 0x26, 0x96, 0x9d, 0x92, 0x06, 0x5f, 0x0b, - 0xcc, 0xfa, 0x18, 0x2a, 0xf8, 0x4a, 0x09, 0x69, 0x25, 0xea, 0x41, 0x2a, 0x6b, 0x54, 0x0e, 0x68, - 0x66, 0x63, 0xa8, 0x19, 0x76, 0x75, 0x74, 0x27, 0x50, 0x53, 0x93, 0xd1, 0x18, 0xf6, 0x37, 0x99, - 0xb6, 0x55, 0x36, 0x85, 0xd8, 0x4d, 0x58, 0x7b, 0x86, 0xb9, 0x51, 0xc2, 0x3a, 0x46, 0xfb, 0x47, - 0x58, 0x9f, 0x66, 0x68, 0x27, 0xfe, 0x00, 0xc5, 0x74, 0xd3, 0x09, 0xf3, 0x5b, 0x19, 0xe6, 0xcd, - 0xc3, 0xe6, 0x11, 0xbb, 0x01, 0xd6, 0x29, 0xe6, 0x0e, 0x46, 0xde, 0xcb, 0x30, 0x18, 0x25, 0x16, - 0xd7, 0xa0, 0x9e, 0x42, 0x75, 0x09, 0x4f, 0xe0, 0x37, 0xd4, 0xe7, 0x38, 0x91, 0x5e, 0x87, 0x46, - 0x1a, 0xd6, 0xe2, 0xdf, 0x40, 0x4d, 0x3d, 0x4e, 0xaf, 0x46, 0x51, 0x22, 0x6c, 0xfd, 0x16, 0x8a, - 0xca, 0x3d, 0x57, 0x3e, 0xdd, 0xc2, 0xe5, 0xca, 0x5e, 0xa3, 0x3d, 0xde, 0x44, 0x64, 0xce, 0xb9, - 0x3c, 0x01, 0x7c, 0xfc, 0x2d, 0xfc, 0x34, 0x75, 0x4d, 0x1c, 0x72, 0xf0, 0x39, 0xc5, 0xac, 0x2f, - 0x4a, 0xca, 0x74, 0x28, 0x0d, 0x6b, 0xf1, 0x26, 0xac, 0x39, 0x71, 0xf8, 0x1c, 0xa3, 0x80, 0xf7, - 0xe5, 0xc3, 0x91, 0x1c, 0x68, 0xc1, 0xfa, 0x34, 0x43, 0x1f, 0xf9, 0x1c, 0x5a, 0x2f, 0x7a, 0x21, - 0xa1, 0x58, 0x31, 0x0f, 0x29, 0x25, 0x34, 0x35, 0x52, 0x38, 0xc7, 0x34, 0x9c, 0x0c, 0x0a, 0x49, - 0xda, 0x77, 0x61, 0x23, 0xe3, 0x94, 0x56, 0xf9, 0x95, 0x70, 0x5a, 0xcc, 0x93, 0x74, 0x25, 0xdf, - 0x87, 0xf2, 0x25, 0xf2, 0xb9, 0x1b, 0x11, 0x36, 0x29, 0xa6, 0x15, 0xa7, 0x24, 0xc0, 0x13, 0x8d, - 0xa9, 0xc8, 0xcc, 0xb3, 0x5a, 0xe7, 0x1e, 0xac, 0x9f, 0x50, 0x7c, 0x1e, 0xf8, 0xbd, 0xfe, 0x54, - 0x83, 0x88, 0x6d, 0x4b, 0x26, 0x2e, 0xe9, 0x90, 0x84, 0xb4, 0x7b, 0xd0, 0x9c, 0x39, 0xa3, 0xeb, - 0xea, 0x18, 0x2a, 0x4a, 0xca, 0xa5, 0x72, 0xaf, 0x48, 0xe6, 0xf9, 0xc7, 0x73, 0x2b, 0xdb, 0xdc, - 0x42, 0x9c, 0x72, 0xd7, 0xa0, 0x98, 0xfd, 0xdf, 0x1c, 0x58, 0xfb, 0x51, 0x14, 0x8c, 0xd2, 0x9e, - 0x55, 0xa1, 0xc0, 0xde, 0x06, 0xc9, 0x88, 0x61, 0x6f, 0x03, 0x31, 0x62, 0xce, 0x09, 0xed, 0x62, - 0xdd, 0xac, 0x8a, 0x10, 0x6b, 0x00, 0x0a, 0x02, 0x72, 0xe9, 0x1a, 0xdb, 0xa9, 0x9c, 0x0c, 0xcb, - 0x4e, 0x55, 0x32, 0x9c, 0x09, 0x3e, 0xbb, 0x00, 0x2d, 0x7c, 0xa8, 0x05, 0x68, 0xf1, 0x96, 0x0b, - 0xd0, 0x3f, 0x72, 0x50, 0x4f, 0x45, 0xaf, 0x73, 0xfc, 0xf3, 0x5b, 0xd5, 0xea, 0x50, 0x3b, 0x26, - 0xdd, 0x0b, 0x35, 0xf5, 0x92, 0xd6, 0x68, 0x80, 0x65, 0x82, 0x93, 0xc6, 0x3b, 0x0b, 0x83, 0x19, - 0xe1, 0x75, 0x68, 0xa4, 0x61, 0x2d, 0xfe, 0xcf, 0x1c, 0xb4, 0xf4, 0x13, 0x71, 0x84, 0x79, 0xb7, - 0xbf, 0xcf, 0x9e, 0x76, 0xc6, 0x75, 0xd0, 0x80, 0x45, 0xf9, 0xa3, 0x44, 0x26, 0xa0, 0xe4, 0x28, - 0xc2, 0x6a, 0xc2, 0x1d, 0xaf, 0xe3, 0xca, 0xa7, 0x51, 0xbf, 0x0e, 0x5e, 0xe7, 0x7b, 0xf1, 0x38, - 0x6e, 0xc0, 0xf2, 0x00, 0x5d, 0xb9, 0x94, 0x5c, 0x32, 0xbd, 0x0c, 0xde, 0x19, 0xa0, 0x2b, 0x87, - 0x5c, 0x32, 0xb9, 0xa8, 0xfb, 0x4c, 0x6e, 0xe0, 0x1d, 0x3f, 0x0c, 0x48, 0x8f, 0xc9, 0xeb, 0x5f, - 0x76, 0x2a, 0x1a, 0x7e, 0xa2, 0x50, 0xd1, 0x6b, 0x54, 0xb6, 0x91, 0x79, 0xb9, 0xcb, 0x4e, 0x89, - 0x1a, 0xbd, 0x65, 0x3f, 0x83, 0x8d, 0x0c, 0x9f, 0xf5, 0xed, 0x3d, 0x82, 0x25, 0xd5, 0x1a, 0xfa, - 0xda, 0xac, 0xb6, 0xfa, 0x61, 0xf5, 0x83, 0xf8, 0xab, 0xdb, 0x40, 0x4b, 0xd8, 0x7f, 0xce, 0xc1, - 0x47, 0x69, 0x4d, 0xfb, 0x41, 0x20, 0x16, 0x30, 0xf6, 0xe1, 0x53, 0x30, 0x13, 0xd9, 0x42, 0x46, - 0x64, 0xc7, 0xb0, 0x35, 0xcf, 0x9f, 0x5b, 0x84, 0xf7, 0xed, 0xf4, 0xdd, 0xee, 0x47, 0xd1, 0xbb, - 0x03, 0x33, 0xfd, 0xcf, 0xa7, 0xfc, 0x9f, 0x4d, 0xba, 0x54, 0x76, 0x0b, 0xaf, 0xc4, 0xc3, 0x16, - 0xa0, 0x21, 0x56, 0xbb, 0x46, 0x52, 0xa0, 0x47, 0x50, 0x4f, 0xa1, 0x5a, 0xf1, 0xae, 0xd8, 0x38, - 0xc6, 0x5b, 0x4a, 0x71, 0xaf, 0xd9, 0x9e, 0xfe, 0x25, 0xac, 0x0f, 0x68, 0x31, 0xf1, 0x92, 0x7c, - 0x87, 0x18, 0xc7, 0x34, 0x99, 0xcc, 0x89, 0x81, 0xcf, 0x61, 0x7d, 0x9a, 0xa1, 0x6d, 0x6c, 0xc2, - 0xf2, 0xd4, 0x68, 0x1f, 0xd3, 0xb6, 0x05, 0xd5, 0x53, 0x4e, 0x22, 0xe9, 0x5a, 0xa2, 0xa9, 0x0e, - 0x35, 0x03, 0xd3, 0x8d, 0xf4, 0x47, 0x68, 0x8e, 0xc1, 0xef, 0xfc, 0xd0, 0x1f, 0xc4, 0x03, 0x63, - 0x19, 0x9d, 0xa7, 0xdf, 0xba, 0x07, 0xf2, 0x19, 0x71, 0xb9, 0x3f, 0xc0, 0xc9, 0xbe, 0x55, 0x70, - 0x8a, 0x02, 0x7b, 0xa5, 0x20, 0xfb, 0x0b, 0x68, 0xcd, 0x6a, 0xbe, 0x86, 0xeb, 0xd2, 0x4d, 0x44, - 0x79, 0xca, 0x77, 0x91, 0x7c, 0x03, 0xd4, 0xce, 0xff, 0x09, 0xee, 0x4e, 0xd0, 0xb3, 0x90, 0xfb, - 0xc1, 0xbe, 0x98, 0x3e, 0x1f, 0x28, 0x80, 0x2d, 0xf8, 0x45, 0xb6, 0x76, 0x6d, 0xfd, 0x29, 0xdc, - 0x53, 0xbb, 0xc5, 0xe1, 0x95, 0x78, 0xa3, 0x51, 0x20, 0x16, 0x9b, 0x08, 0x51, 0x1c, 0x72, 0xec, - 0x25, 0x3e, 0xc8, 0x9d, 0x55, 0xb1, 0x5d, 0x3f, 0xd9, 0xff, 0x21, 0x81, 0x5e, 0x78, 0xf6, 0x03, - 0xb0, 0xdf, 0xa5, 0x45, 0xdb, 0xda, 0x81, 0xad, 0x69, 0xa9, 0xc3, 0x00, 0x77, 0x27, 0x86, 0xec, - 0x7b, 0xb0, 0x3d, 0x57, 0x42, 0x2b, 0xb1, 0xd4, 0xba, 0x2b, 0xc2, 0x19, 0xd7, 0xef, 0xaf, 0xd4, - 0x2a, 0xaa, 0x31, 0x7d, 0x3d, 0x0d, 0x58, 0x44, 0x9e, 0x47, 0x93, 0x07, 0x5e, 0x11, 0xf6, 0x06, - 0x34, 0x1d, 0xcc, 0xc4, 0x5e, 0x36, 0xae, 0xe4, 0x44, 0xcb, 0x26, 0xb4, 0x66, 0x59, 0xda, 0xea, - 0x2e, 0x34, 0x5f, 0x1b, 0xb8, 0x68, 0xc6, 0xcc, 0x66, 0x5e, 0xd1, 0xcd, 0x6c, 0x1f, 0x41, 0x6b, - 0xf6, 0xc0, 0xad, 0xc6, 0xc8, 0x47, 0xa6, 0x9e, 0x37, 0xc8, 0xe7, 0x47, 0x44, 0xb4, 0x51, 0x62, - 0xbe, 0x02, 0x79, 0x7d, 0x25, 0x05, 0x27, 0xef, 0x7b, 0xa9, 0x7a, 0xc9, 0x4f, 0x55, 0xe5, 0x0e, - 0x6c, 0xcd, 0x53, 0xa6, 0xe3, 0xac, 0x43, 0xed, 0x45, 0xe8, 0x73, 0xd5, 0xac, 0x49, 0x62, 0x3e, - 0x05, 0xcb, 0x04, 0xaf, 0x51, 0xfe, 0x3f, 0xe5, 0x60, 0xeb, 0x84, 0x44, 0x71, 0x20, 0xf7, 0x4c, - 0x55, 0x08, 0xdf, 0x90, 0x58, 0xdc, 0x68, 0xe2, 0xf7, 0x2f, 0x61, 0x55, 0x94, 0xad, 0xdb, 0xa5, - 0x18, 0x71, 0xec, 0xb9, 0x61, 0xf2, 0x5b, 0xa8, 0x2c, 0xe0, 0x03, 0x85, 0x7e, 0xcf, 0x44, 0xed, - 0xa1, 0xae, 0x50, 0x6a, 0x8e, 0x7c, 0x50, 0x90, 0x1c, 0xfb, 0x5f, 0x42, 0x69, 0x20, 0x3d, 0x73, - 0x51, 0xe0, 0x23, 0x35, 0xfa, 0x8b, 0x7b, 0x6b, 0xd3, 0xbb, 0xf3, 0xbe, 0x60, 0x3a, 0x45, 0x25, - 0x2a, 0x09, 0xeb, 0x31, 0x34, 0x8c, 0x81, 0x36, 0x59, 0x31, 0x17, 0xa4, 0x8d, 0xba, 0xc1, 0x1b, - 0x6f, 0x9a, 0xf7, 0x60, 0x7b, 0x6e, 0x5c, 0x3a, 0x85, 0x7f, 0xcd, 0x41, 0x55, 0xa4, 0xcb, 0x6c, - 0x7d, 0xeb, 0x37, 0xb0, 0xa4, 0xa4, 0xf5, 0x95, 0xcf, 0x71, 0x4f, 0x0b, 0xcd, 0xf5, 0x2c, 0x3f, - 0xd7, 0xb3, 0xac, 0x7c, 0x16, 0x32, 0xf2, 0x99, 0xdc, 0x70, 0x7a, 0x06, 0xad, 0x41, 0xfd, 0x29, - 0x1e, 0x10, 0x8e, 0xd3, 0x17, 0xbf, 0x07, 0x8d, 0x34, 0x7c, 0x8d, 0xab, 0xdf, 0x80, 0xe6, 0x59, - 0xe8, 0x91, 0x2c, 0x75, 0x9b, 0xd0, 0x9a, 0x65, 0x69, 0x0f, 0xbe, 0x86, 0xed, 0x13, 0x4a, 0x04, - 0x43, 0x7a, 0xf6, 0xa6, 0x8f, 0xc3, 0x03, 0x14, 0xf7, 0xfa, 0xfc, 0x2c, 0xba, 0xc6, 0x24, 0xb4, - 0x7f, 0x0f, 0x3b, 0xf3, 0x8f, 0x5f, 0xcf, 0x6b, 0x75, 0x10, 0x31, 0xad, 0xc7, 0x33, 0xbc, 0x9e, - 0x65, 0x69, 0xaf, 0xff, 0x92, 0x83, 0xea, 0x29, 0x4e, 0xb7, 0xcb, 0x4d, 0xef, 0x3a, 0xe3, 0xe2, - 0xf2, 0x59, 0x8d, 0xf0, 0x08, 0x6a, 0x72, 0xf3, 0x77, 0x99, 0x98, 0xe7, 0x2e, 0x13, 0x3e, 0xe9, - 0x85, 0x7f, 0x55, 0x32, 0x26, 0x73, 0x5e, 0x3e, 0x3f, 0x78, 0xaa, 0x61, 0xed, 0x17, 0x93, 0x40, - 0x1c, 0x2c, 0x95, 0x4c, 0x26, 0xfc, 0xcd, 0x7c, 0x16, 0xbf, 0xe4, 0x32, 0x54, 0x69, 0x3b, 0x0f, - 0xc0, 0x16, 0x6f, 0xa6, 0x31, 0x68, 0xf6, 0x43, 0x4f, 0xcc, 0xe7, 0xd4, 0xce, 0xf1, 0x1a, 0xee, - 0xbf, 0x53, 0xea, 0xb6, 0x3b, 0xc8, 0x1a, 0xd4, 0xcd, 0x4a, 0x30, 0x4a, 0x39, 0x0d, 0x5f, 0xa3, - 0x28, 0x1e, 0x43, 0xf9, 0x09, 0xea, 0x5e, 0xc4, 0xe3, 0x0a, 0xdc, 0x81, 0x62, 0x97, 0x84, 0xdd, - 0x98, 0x52, 0x1c, 0x76, 0x47, 0x7a, 0x5e, 0x99, 0x90, 0xfd, 0x05, 0x54, 0x92, 0x23, 0xda, 0xc0, - 0x03, 0x58, 0xc4, 0xc3, 0x49, 0x62, 0x2b, 0xed, 0xe4, 0xdf, 0x06, 0x87, 0x02, 0x75, 0x14, 0x53, - 0xbf, 0x3d, 0x9c, 0x50, 0x7c, 0x44, 0xc9, 0x20, 0x65, 0xd5, 0xde, 0x87, 0x8d, 0x0c, 0xde, 0x4d, - 0xd4, 0x3f, 0xf9, 0xf4, 0xc7, 0xf6, 0xd0, 0xe7, 0x98, 0xb1, 0xb6, 0x4f, 0x76, 0xd5, 0xd7, 0x6e, - 0x8f, 0xec, 0x0e, 0xf9, 0xae, 0xfc, 0xe7, 0xc5, 0xee, 0xcc, 0x6f, 0xa2, 0xce, 0x92, 0x64, 0x7c, - 0xf6, 0xbf, 0x00, 0x00, 0x00, 0xff, 0xff, 0xaf, 0x00, 0xea, 0x85, 0x46, 0x19, 0x00, 0x00, + proto.RegisterFile("tabletmanagerdata.proto", fileDescriptor_tabletmanagerdata_3063cd7e973e1b02) +} + +var fileDescriptor_tabletmanagerdata_3063cd7e973e1b02 = []byte{ + // 2074 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x59, 0x5b, 0x6f, 0x1b, 0xc7, + 0xf5, 0x07, 0x49, 0x49, 0x96, 0x0e, 0x2f, 0x22, 0x97, 0x94, 0x48, 0xc9, 0xff, 0x48, 0xf2, 0xda, + 0xf9, 0xc7, 0x75, 0x51, 0x2a, 0x51, 0xd2, 0x20, 0x48, 0x91, 0xa2, 0xb2, 0x2e, 0xb6, 0x13, 0x25, + 0x56, 0x56, 0x96, 0x5d, 0x04, 0x05, 0x16, 0x43, 0xee, 0x88, 0x5c, 0x68, 0xb9, 0xb3, 0x9e, 0x99, + 0xa5, 0xc4, 0x2f, 0xd1, 0xb7, 0xbe, 0xf5, 0xad, 0x40, 0xfb, 0xde, 0x0f, 0x93, 0xa2, 0x9f, 0xa4, + 0x0f, 0x7d, 0x29, 0xe6, 0xb2, 0xe4, 0x2c, 0xb9, 0xb4, 0x25, 0xc1, 0x05, 0xfa, 0x22, 0xf0, 0xfc, + 0xce, 0x99, 0x73, 0x9b, 0x73, 0xce, 0x9c, 0x85, 0xa0, 0xc9, 0x51, 0x27, 0xc0, 0x7c, 0x80, 0x42, + 0xd4, 0xc3, 0xd4, 0x43, 0x1c, 0xb5, 0x23, 0x4a, 0x38, 0xb1, 0x6a, 0x33, 0x8c, 0xcd, 0xe2, 0xdb, + 0x18, 0xd3, 0x91, 0xe2, 0x6f, 0x56, 0x38, 0x89, 0xc8, 0x44, 0x7e, 0x73, 0x8d, 0xe2, 0x28, 0xf0, + 0xbb, 0x88, 0xfb, 0x24, 0x34, 0xe0, 0x72, 0x40, 0x7a, 0x31, 0xf7, 0x03, 0x45, 0xda, 0xff, 0xcc, + 0xc1, 0xea, 0x2b, 0xa1, 0xf8, 0x10, 0x5f, 0xf8, 0xa1, 0x2f, 0x84, 0x2d, 0x0b, 0x16, 0x42, 0x34, + 0xc0, 0xad, 0xdc, 0x4e, 0xee, 0xf1, 0x8a, 0x23, 0x7f, 0x5b, 0xeb, 0xb0, 0xc4, 0xba, 0x7d, 0x3c, + 0x40, 0xad, 0xbc, 0x44, 0x35, 0x65, 0xb5, 0xe0, 0x5e, 0x97, 0x04, 0xf1, 0x20, 0x64, 0xad, 0xc2, + 0x4e, 0xe1, 0xf1, 0x8a, 0x93, 0x90, 0x56, 0x1b, 0xea, 0x11, 0xf5, 0x07, 0x88, 0x8e, 0xdc, 0x4b, + 0x3c, 0x72, 0x13, 0xa9, 0x05, 0x29, 0x55, 0xd3, 0xac, 0xef, 0xf0, 0xe8, 0x40, 0xcb, 0x5b, 0xb0, + 0xc0, 0x47, 0x11, 0x6e, 0x2d, 0x2a, 0xab, 0xe2, 0xb7, 0xb5, 0x0d, 0x45, 0xe1, 0xba, 0x1b, 0xe0, + 0xb0, 0xc7, 0xfb, 0xad, 0xa5, 0x9d, 0xdc, 0xe3, 0x05, 0x07, 0x04, 0x74, 0x22, 0x11, 0xeb, 0x3e, + 0xac, 0x50, 0x72, 0xe5, 0x76, 0x49, 0x1c, 0xf2, 0xd6, 0x3d, 0xc9, 0x5e, 0xa6, 0xe4, 0xea, 0x40, + 0xd0, 0xf6, 0x5f, 0x73, 0x50, 0x3d, 0x93, 0x6e, 0x1a, 0xc1, 0x7d, 0x02, 0xab, 0xe2, 0x7c, 0x07, + 0x31, 0xec, 0xea, 0x88, 0x54, 0x9c, 0x95, 0x04, 0x56, 0x47, 0xac, 0x97, 0xa0, 0x32, 0xee, 0x7a, + 0xe3, 0xc3, 0xac, 0x95, 0xdf, 0x29, 0x3c, 0x2e, 0xee, 0xd9, 0xed, 0xd9, 0x4b, 0x9a, 0x4a, 0xa2, + 0x53, 0xe5, 0x69, 0x80, 0x89, 0x54, 0x0d, 0x31, 0x65, 0x3e, 0x09, 0x5b, 0x05, 0x69, 0x31, 0x21, + 0x85, 0xa3, 0x96, 0xb2, 0x7a, 0xd0, 0x47, 0x61, 0x0f, 0x3b, 0x98, 0xc5, 0x01, 0xb7, 0x9e, 0x43, + 0xb9, 0x83, 0x2f, 0x08, 0x4d, 0x39, 0x5a, 0xdc, 0x7b, 0x98, 0x61, 0x7d, 0x3a, 0x4c, 0xa7, 0xa4, + 0x4e, 0xea, 0x58, 0x8e, 0xa1, 0x84, 0x2e, 0x38, 0xa6, 0xae, 0x71, 0x87, 0x37, 0x54, 0x54, 0x94, + 0x07, 0x15, 0x6c, 0xff, 0x2b, 0x07, 0x95, 0x73, 0x86, 0xe9, 0x29, 0xa6, 0x03, 0x9f, 0x31, 0x5d, + 0x2c, 0x7d, 0xc2, 0x78, 0x52, 0x2c, 0xe2, 0xb7, 0xc0, 0x62, 0x86, 0xa9, 0x2e, 0x15, 0xf9, 0xdb, + 0xfa, 0x25, 0xd4, 0x22, 0xc4, 0xd8, 0x15, 0xa1, 0x9e, 0xdb, 0xed, 0xe3, 0xee, 0x25, 0x8b, 0x07, + 0x32, 0x0f, 0x0b, 0x4e, 0x35, 0x61, 0x1c, 0x68, 0xdc, 0xfa, 0x11, 0x20, 0xa2, 0xfe, 0xd0, 0x0f, + 0x70, 0x0f, 0xab, 0x92, 0x29, 0xee, 0x7d, 0x96, 0xe1, 0x6d, 0xda, 0x97, 0xf6, 0xe9, 0xf8, 0xcc, + 0x51, 0xc8, 0xe9, 0xc8, 0x31, 0x94, 0x6c, 0x7e, 0x03, 0xab, 0x53, 0x6c, 0xab, 0x0a, 0x85, 0x4b, + 0x3c, 0xd2, 0x9e, 0x8b, 0x9f, 0x56, 0x03, 0x16, 0x87, 0x28, 0x88, 0xb1, 0xf6, 0x5c, 0x11, 0x5f, + 0xe7, 0xbf, 0xca, 0xd9, 0x3f, 0xe7, 0xa0, 0x74, 0xd8, 0x79, 0x4f, 0xdc, 0x15, 0xc8, 0x7b, 0x1d, + 0x7d, 0x36, 0xef, 0x75, 0xc6, 0x79, 0x28, 0x18, 0x79, 0x78, 0x99, 0x11, 0xda, 0x6e, 0x46, 0x68, + 0xa6, 0xb1, 0xff, 0x66, 0x60, 0x7f, 0xc9, 0x41, 0x71, 0x62, 0x89, 0x59, 0x27, 0x50, 0x15, 0x7e, + 0xba, 0xd1, 0x04, 0x6b, 0xe5, 0xa4, 0x97, 0x0f, 0xde, 0x7b, 0x01, 0xce, 0x6a, 0x9c, 0xa2, 0x99, + 0x75, 0x0c, 0x15, 0xaf, 0x93, 0xd2, 0xa5, 0x3a, 0x68, 0xfb, 0x3d, 0x11, 0x3b, 0x65, 0xcf, 0xa0, + 0x98, 0xfd, 0x09, 0x14, 0x4f, 0xfd, 0xb0, 0xe7, 0xe0, 0xb7, 0x31, 0x66, 0x5c, 0xb4, 0x52, 0x84, + 0x46, 0x01, 0x41, 0x9e, 0x0e, 0x32, 0x21, 0xed, 0xc7, 0x50, 0x52, 0x82, 0x2c, 0x22, 0x21, 0xc3, + 0xef, 0x90, 0x7c, 0x02, 0xa5, 0xb3, 0x00, 0xe3, 0x28, 0xd1, 0xb9, 0x09, 0xcb, 0x5e, 0x4c, 0xe5, + 0xb8, 0x94, 0xa2, 0x05, 0x67, 0x4c, 0xdb, 0xab, 0x50, 0xd6, 0xb2, 0x4a, 0xad, 0xfd, 0x8f, 0x1c, + 0x58, 0x47, 0xd7, 0xb8, 0x1b, 0x73, 0xfc, 0x9c, 0x90, 0xcb, 0x44, 0x47, 0xd6, 0xe4, 0xdc, 0x02, + 0x88, 0x10, 0x45, 0x03, 0xcc, 0x31, 0x55, 0xe1, 0xaf, 0x38, 0x06, 0x62, 0x9d, 0xc2, 0x0a, 0xbe, + 0xe6, 0x14, 0xb9, 0x38, 0x1c, 0xca, 0x19, 0x5a, 0xdc, 0xfb, 0x3c, 0x23, 0x3b, 0xb3, 0xd6, 0xda, + 0x47, 0xe2, 0xd8, 0x51, 0x38, 0x54, 0x35, 0xb1, 0x8c, 0x35, 0xb9, 0xf9, 0x1b, 0x28, 0xa7, 0x58, + 0xb7, 0xaa, 0x87, 0x0b, 0xa8, 0xa7, 0x4c, 0xe9, 0x3c, 0x6e, 0x43, 0x11, 0x5f, 0xfb, 0xdc, 0x65, + 0x1c, 0xf1, 0x98, 0xe9, 0x04, 0x81, 0x80, 0xce, 0x24, 0x22, 0x1f, 0x08, 0xee, 0x91, 0x98, 0x8f, + 0x1f, 0x08, 0x49, 0x69, 0x1c, 0xd3, 0xa4, 0x0b, 0x34, 0x65, 0x0f, 0xa1, 0xfa, 0x0c, 0x73, 0x35, + 0x57, 0x92, 0xf4, 0xad, 0xc3, 0x92, 0x0c, 0x5c, 0x55, 0xdc, 0x8a, 0xa3, 0x29, 0xeb, 0x21, 0x94, + 0xfd, 0xb0, 0x1b, 0xc4, 0x1e, 0x76, 0x87, 0x3e, 0xbe, 0x62, 0xd2, 0xc4, 0xb2, 0x53, 0xd2, 0xe0, + 0x6b, 0x81, 0x59, 0x1f, 0x43, 0x05, 0x5f, 0x2b, 0x21, 0xad, 0x44, 0x3d, 0x48, 0x65, 0x8d, 0xca, + 0x01, 0xcd, 0x6c, 0x0c, 0x35, 0xc3, 0xae, 0x8e, 0xee, 0x14, 0x6a, 0x6a, 0x32, 0x1a, 0xc3, 0xfe, + 0x36, 0xd3, 0xb6, 0xca, 0xa6, 0x10, 0xbb, 0x09, 0x6b, 0xcf, 0x30, 0x37, 0x4a, 0x58, 0xc7, 0x68, + 0xff, 0x04, 0xeb, 0xd3, 0x0c, 0xed, 0xc4, 0xef, 0xa0, 0x98, 0x6e, 0x3a, 0x61, 0x7e, 0x2b, 0xc3, + 0xbc, 0x79, 0xd8, 0x3c, 0x62, 0x37, 0xc0, 0x3a, 0xc3, 0xdc, 0xc1, 0xc8, 0x7b, 0x19, 0x06, 0xa3, + 0xc4, 0xe2, 0x1a, 0xd4, 0x53, 0xa8, 0x2e, 0xe1, 0x09, 0xfc, 0x86, 0xfa, 0x1c, 0x27, 0xd2, 0xeb, + 0xd0, 0x48, 0xc3, 0x5a, 0xfc, 0x5b, 0xa8, 0xa9, 0xc7, 0xe9, 0xd5, 0x28, 0x4a, 0x84, 0xad, 0x5f, + 0x43, 0x51, 0xb9, 0xe7, 0xca, 0xa7, 0x5b, 0xb8, 0x5c, 0xd9, 0x6b, 0xb4, 0xc7, 0x9b, 0x88, 0xcc, + 0x39, 0x97, 0x27, 0x80, 0x8f, 0x7f, 0x0b, 0x3f, 0x4d, 0x5d, 0x13, 0x87, 0x1c, 0x7c, 0x41, 0x31, + 0xeb, 0x8b, 0x92, 0x32, 0x1d, 0x4a, 0xc3, 0x5a, 0xbc, 0x09, 0x6b, 0x4e, 0x1c, 0x3e, 0xc7, 0x28, + 0xe0, 0x7d, 0xf9, 0x70, 0x24, 0x07, 0x5a, 0xb0, 0x3e, 0xcd, 0xd0, 0x47, 0xbe, 0x80, 0xd6, 0x8b, + 0x5e, 0x48, 0x28, 0x56, 0xcc, 0x23, 0x4a, 0x09, 0x4d, 0x8d, 0x14, 0xce, 0x31, 0x0d, 0x27, 0x83, + 0x42, 0x92, 0xf6, 0x7d, 0xd8, 0xc8, 0x38, 0xa5, 0x55, 0x7e, 0x2d, 0x9c, 0x16, 0xf3, 0x24, 0x5d, + 0xc9, 0x0f, 0xa1, 0x7c, 0x85, 0x7c, 0xee, 0x46, 0x84, 0x4d, 0x8a, 0x69, 0xc5, 0x29, 0x09, 0xf0, + 0x54, 0x63, 0x2a, 0x32, 0xf3, 0xac, 0xd6, 0xb9, 0x07, 0xeb, 0xa7, 0x14, 0x5f, 0x04, 0x7e, 0xaf, + 0x3f, 0xd5, 0x20, 0x62, 0xdb, 0x92, 0x89, 0x4b, 0x3a, 0x24, 0x21, 0xed, 0x1e, 0x34, 0x67, 0xce, + 0xe8, 0xba, 0x3a, 0x81, 0x8a, 0x92, 0x72, 0xa9, 0xdc, 0x2b, 0x92, 0x79, 0xfe, 0xf1, 0xdc, 0xca, + 0x36, 0xb7, 0x10, 0xa7, 0xdc, 0x35, 0x28, 0x66, 0xff, 0x3b, 0x07, 0xd6, 0x7e, 0x14, 0x05, 0xa3, + 0xb4, 0x67, 0x55, 0x28, 0xb0, 0xb7, 0x41, 0x32, 0x62, 0xd8, 0xdb, 0x40, 0x8c, 0x98, 0x0b, 0x42, + 0xbb, 0x58, 0x37, 0xab, 0x22, 0xc4, 0x1a, 0x80, 0x82, 0x80, 0x5c, 0xb9, 0xc6, 0x76, 0x2a, 0x27, + 0xc3, 0xb2, 0x53, 0x95, 0x0c, 0x67, 0x82, 0xcf, 0x2e, 0x40, 0x0b, 0x1f, 0x6a, 0x01, 0x5a, 0xbc, + 0xe3, 0x02, 0xf4, 0xb7, 0x1c, 0xd4, 0x53, 0xd1, 0xeb, 0x1c, 0xff, 0xef, 0xad, 0x6a, 0x75, 0xa8, + 0x9d, 0x90, 0xee, 0xa5, 0x9a, 0x7a, 0x49, 0x6b, 0x34, 0xc0, 0x32, 0xc1, 0x49, 0xe3, 0x9d, 0x87, + 0xc1, 0x8c, 0xf0, 0x3a, 0x34, 0xd2, 0xb0, 0x16, 0xff, 0x7b, 0x0e, 0x5a, 0xfa, 0x89, 0x38, 0xc6, + 0xbc, 0xdb, 0xdf, 0x67, 0x87, 0x9d, 0x71, 0x1d, 0x34, 0x60, 0x51, 0x7e, 0x94, 0xc8, 0x04, 0x94, + 0x1c, 0x45, 0x58, 0x4d, 0xb8, 0xe7, 0x75, 0x5c, 0xf9, 0x34, 0xea, 0xd7, 0xc1, 0xeb, 0xfc, 0x20, + 0x1e, 0xc7, 0x0d, 0x58, 0x1e, 0xa0, 0x6b, 0x97, 0x92, 0x2b, 0xa6, 0x97, 0xc1, 0x7b, 0x03, 0x74, + 0xed, 0x90, 0x2b, 0x26, 0x17, 0x75, 0x9f, 0xc9, 0x0d, 0xbc, 0xe3, 0x87, 0x01, 0xe9, 0x31, 0x79, + 0xfd, 0xcb, 0x4e, 0x45, 0xc3, 0x4f, 0x15, 0x2a, 0x7a, 0x8d, 0xca, 0x36, 0x32, 0x2f, 0x77, 0xd9, + 0x29, 0x51, 0xa3, 0xb7, 0xec, 0x67, 0xb0, 0x91, 0xe1, 0xb3, 0xbe, 0xbd, 0x27, 0xb0, 0xa4, 0x5a, + 0x43, 0x5f, 0x9b, 0xd5, 0x56, 0x1f, 0x56, 0x3f, 0x8a, 0xbf, 0xba, 0x0d, 0xb4, 0x84, 0xfd, 0xc7, + 0x1c, 0x7c, 0x94, 0xd6, 0xb4, 0x1f, 0x04, 0x62, 0x01, 0x63, 0x1f, 0x3e, 0x05, 0x33, 0x91, 0x2d, + 0x64, 0x44, 0x76, 0x02, 0x5b, 0xf3, 0xfc, 0xb9, 0x43, 0x78, 0xdf, 0x4d, 0xdf, 0xed, 0x7e, 0x14, + 0xbd, 0x3b, 0x30, 0xd3, 0xff, 0x7c, 0xca, 0xff, 0xd9, 0xa4, 0x4b, 0x65, 0x77, 0xf0, 0x4a, 0x3c, + 0x6c, 0x01, 0x1a, 0x62, 0xb5, 0x6b, 0x24, 0x05, 0x7a, 0x0c, 0xf5, 0x14, 0xaa, 0x15, 0xef, 0x8a, + 0x8d, 0x63, 0xbc, 0xa5, 0x14, 0xf7, 0x9a, 0xed, 0xe9, 0x2f, 0x61, 0x7d, 0x40, 0x8b, 0x89, 0x97, + 0xe4, 0x7b, 0xc4, 0x38, 0xa6, 0xc9, 0x64, 0x4e, 0x0c, 0x7c, 0x01, 0xeb, 0xd3, 0x0c, 0x6d, 0x63, + 0x13, 0x96, 0xa7, 0x46, 0xfb, 0x98, 0xb6, 0x2d, 0xa8, 0x9e, 0x71, 0x12, 0x49, 0xd7, 0x12, 0x4d, + 0x75, 0xa8, 0x19, 0x98, 0x6e, 0xa4, 0xdf, 0x43, 0x73, 0x0c, 0x7e, 0xef, 0x87, 0xfe, 0x20, 0x1e, + 0x18, 0xcb, 0xe8, 0x3c, 0xfd, 0xd6, 0x03, 0x90, 0xcf, 0x88, 0xcb, 0xfd, 0x01, 0x4e, 0xf6, 0xad, + 0x82, 0x53, 0x14, 0xd8, 0x2b, 0x05, 0xd9, 0x5f, 0x42, 0x6b, 0x56, 0xf3, 0x0d, 0x5c, 0x97, 0x6e, + 0x22, 0xca, 0x53, 0xbe, 0x8b, 0xe4, 0x1b, 0xa0, 0x76, 0xfe, 0x0f, 0x70, 0x7f, 0x82, 0x9e, 0x87, + 0xdc, 0x0f, 0xf6, 0xc5, 0xf4, 0xf9, 0x40, 0x01, 0x6c, 0xc1, 0xff, 0x65, 0x6b, 0xd7, 0xd6, 0x0f, + 0xe1, 0x81, 0xda, 0x2d, 0x8e, 0xae, 0xc5, 0x1b, 0x8d, 0x02, 0xb1, 0xd8, 0x44, 0x88, 0xe2, 0x90, + 0x63, 0x2f, 0xf1, 0x41, 0xee, 0xac, 0x8a, 0xed, 0xfa, 0xc9, 0xfe, 0x0f, 0x09, 0xf4, 0xc2, 0xb3, + 0x1f, 0x81, 0xfd, 0x2e, 0x2d, 0xda, 0xd6, 0x0e, 0x6c, 0x4d, 0x4b, 0x1d, 0x05, 0xb8, 0x3b, 0x31, + 0x64, 0x3f, 0x80, 0xed, 0xb9, 0x12, 0x5a, 0x89, 0xa5, 0xd6, 0x5d, 0x11, 0xce, 0xb8, 0x7e, 0x7f, + 0xa1, 0x56, 0x51, 0x8d, 0xe9, 0xeb, 0x69, 0xc0, 0x22, 0xf2, 0x3c, 0x9a, 0x3c, 0xf0, 0x8a, 0xb0, + 0x37, 0xa0, 0xe9, 0x60, 0x26, 0xf6, 0xb2, 0x71, 0x25, 0x27, 0x5a, 0x36, 0xa1, 0x35, 0xcb, 0xd2, + 0x56, 0x77, 0xa1, 0xf9, 0xda, 0xc0, 0x45, 0x33, 0x66, 0x36, 0xf3, 0x8a, 0x6e, 0x66, 0xfb, 0x18, + 0x5a, 0xb3, 0x07, 0xee, 0x34, 0x46, 0x3e, 0x32, 0xf5, 0xbc, 0x41, 0x3e, 0x3f, 0x26, 0xa2, 0x8d, + 0x12, 0xf3, 0x15, 0xc8, 0xeb, 0x2b, 0x29, 0x38, 0x79, 0xdf, 0x4b, 0xd5, 0x4b, 0x7e, 0xaa, 0x2a, + 0x77, 0x60, 0x6b, 0x9e, 0x32, 0x1d, 0x67, 0x1d, 0x6a, 0x2f, 0x42, 0x9f, 0xab, 0x66, 0x4d, 0x12, + 0xf3, 0x29, 0x58, 0x26, 0x78, 0x83, 0xf2, 0xff, 0x39, 0x07, 0x5b, 0xa7, 0x24, 0x8a, 0x03, 0xb9, + 0x67, 0xaa, 0x42, 0xf8, 0x96, 0xc4, 0xe2, 0x46, 0x13, 0xbf, 0xff, 0x1f, 0x56, 0x45, 0xd9, 0xba, + 0x5d, 0x8a, 0x11, 0xc7, 0x9e, 0x1b, 0x26, 0xdf, 0x42, 0x65, 0x01, 0x1f, 0x28, 0xf4, 0x07, 0x26, + 0x6a, 0x0f, 0x75, 0x85, 0x52, 0x73, 0xe4, 0x83, 0x82, 0xe4, 0xd8, 0xff, 0x0a, 0x4a, 0x03, 0xe9, + 0x99, 0x8b, 0x02, 0x1f, 0xa9, 0xd1, 0x5f, 0xdc, 0x5b, 0x9b, 0xde, 0x9d, 0xf7, 0x05, 0xd3, 0x29, + 0x2a, 0x51, 0x49, 0x58, 0x9f, 0x41, 0xc3, 0x18, 0x68, 0x93, 0x15, 0x73, 0x41, 0xda, 0xa8, 0x1b, + 0xbc, 0xf1, 0xa6, 0xf9, 0x00, 0xb6, 0xe7, 0xc6, 0xa5, 0x53, 0xf8, 0xe7, 0x1c, 0x54, 0x45, 0xba, + 0xcc, 0xd6, 0xb7, 0x7e, 0x05, 0x4b, 0x4a, 0x5a, 0x5f, 0xf9, 0x1c, 0xf7, 0xb4, 0xd0, 0x5c, 0xcf, + 0xf2, 0x73, 0x3d, 0xcb, 0xca, 0x67, 0x21, 0x23, 0x9f, 0xc9, 0x0d, 0xa7, 0x67, 0xd0, 0x1a, 0xd4, + 0x0f, 0xf1, 0x80, 0x70, 0x9c, 0xbe, 0xf8, 0x3d, 0x68, 0xa4, 0xe1, 0x1b, 0x5c, 0xfd, 0x06, 0x34, + 0xcf, 0x43, 0x8f, 0x64, 0xa9, 0xdb, 0x84, 0xd6, 0x2c, 0x4b, 0x7b, 0xf0, 0x0d, 0x6c, 0x9f, 0x52, + 0x22, 0x18, 0xd2, 0xb3, 0x37, 0x7d, 0x1c, 0x1e, 0xa0, 0xb8, 0xd7, 0xe7, 0xe7, 0xd1, 0x0d, 0x26, + 0xa1, 0xfd, 0x5b, 0xd8, 0x99, 0x7f, 0xfc, 0x66, 0x5e, 0xab, 0x83, 0x88, 0x69, 0x3d, 0x9e, 0xe1, + 0xf5, 0x2c, 0x4b, 0x7b, 0xfd, 0xa7, 0x1c, 0x54, 0xcf, 0x70, 0xba, 0x5d, 0x6e, 0x7b, 0xd7, 0x19, + 0x17, 0x97, 0xcf, 0x6a, 0x84, 0x27, 0x50, 0x93, 0x9b, 0xbf, 0xcb, 0xc4, 0x3c, 0x77, 0x99, 0xf0, + 0x49, 0x2f, 0xfc, 0xab, 0x92, 0x31, 0x99, 0xf3, 0xf2, 0xf9, 0xc1, 0x53, 0x0d, 0x6b, 0xbf, 0x98, + 0x04, 0xe2, 0x60, 0xa9, 0x64, 0x32, 0xe1, 0x6f, 0xe7, 0xb3, 0xf8, 0x92, 0xcb, 0x50, 0xa5, 0xed, + 0x3c, 0x02, 0x5b, 0xbc, 0x99, 0xc6, 0xa0, 0xd9, 0x0f, 0x3d, 0x31, 0x9f, 0x53, 0x3b, 0xc7, 0x6b, + 0x78, 0xf8, 0x4e, 0xa9, 0xbb, 0xee, 0x20, 0x6b, 0x50, 0x37, 0x2b, 0xc1, 0x28, 0xe5, 0x34, 0x7c, + 0x83, 0xa2, 0x38, 0x83, 0xf2, 0x53, 0xd4, 0xbd, 0x8c, 0xc7, 0x15, 0xb8, 0x03, 0xc5, 0x2e, 0x09, + 0xbb, 0x31, 0xa5, 0x38, 0xec, 0x8e, 0xf4, 0xbc, 0x32, 0x21, 0x21, 0x21, 0x3f, 0xbe, 0x54, 0xea, + 0xf5, 0x17, 0x9b, 0x09, 0xd9, 0x5f, 0x42, 0x25, 0x51, 0xaa, 0x5d, 0x78, 0x04, 0x8b, 0x78, 0x38, + 0x49, 0x7d, 0xa5, 0x9d, 0xfc, 0x63, 0xe1, 0x48, 0xa0, 0x8e, 0x62, 0xea, 0xd7, 0x89, 0x13, 0x8a, + 0x8f, 0x29, 0x19, 0xa4, 0xfc, 0xb2, 0xf7, 0x61, 0x23, 0x83, 0x77, 0x1b, 0xf5, 0x4f, 0x3f, 0xfd, + 0xa9, 0x3d, 0xf4, 0x39, 0x66, 0xac, 0xed, 0x93, 0x5d, 0xf5, 0x6b, 0xb7, 0x47, 0x76, 0x87, 0x7c, + 0x57, 0xfe, 0x7b, 0x63, 0x77, 0xe6, 0xab, 0xa9, 0xb3, 0x24, 0x19, 0x9f, 0xff, 0x27, 0x00, 0x00, + 0xff, 0xff, 0x62, 0x6b, 0xcc, 0xed, 0x68, 0x19, 0x00, 0x00, } diff --git a/go/vt/proto/vtgate/vtgate.pb.go b/go/vt/proto/vtgate/vtgate.pb.go index ae204d1e8ac..e57b87e3dc0 100644 --- a/go/vt/proto/vtgate/vtgate.pb.go +++ b/go/vt/proto/vtgate/vtgate.pb.go @@ -53,7 +53,7 @@ func (x TransactionMode) String() string { return proto.EnumName(TransactionMode_name, int32(x)) } func (TransactionMode) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{0} } // Session objects are exchanged like cookies through various @@ -98,7 +98,7 @@ func (m *Session) Reset() { *m = Session{} } func (m *Session) String() string { return proto.CompactTextString(m) } func (*Session) ProtoMessage() {} func (*Session) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{0} } func (m *Session) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Session.Unmarshal(m, b) @@ -186,7 +186,7 @@ func (m *Session_ShardSession) Reset() { *m = Session_ShardSession{} } func (m *Session_ShardSession) String() string { return proto.CompactTextString(m) } func (*Session_ShardSession) ProtoMessage() {} func (*Session_ShardSession) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{0, 0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{0, 0} } func (m *Session_ShardSession) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Session_ShardSession.Unmarshal(m, b) @@ -244,7 +244,7 @@ func (m *ExecuteRequest) Reset() { *m = ExecuteRequest{} } func (m *ExecuteRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteRequest) ProtoMessage() {} func (*ExecuteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{1} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{1} } func (m *ExecuteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteRequest.Unmarshal(m, b) @@ -332,7 +332,7 @@ func (m *ExecuteResponse) Reset() { *m = ExecuteResponse{} } func (m *ExecuteResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteResponse) ProtoMessage() {} func (*ExecuteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{2} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{2} } func (m *ExecuteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteResponse.Unmarshal(m, b) @@ -402,7 +402,7 @@ func (m *ExecuteShardsRequest) Reset() { *m = ExecuteShardsRequest{} } func (m *ExecuteShardsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteShardsRequest) ProtoMessage() {} func (*ExecuteShardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{3} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{3} } func (m *ExecuteShardsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteShardsRequest.Unmarshal(m, b) @@ -497,7 +497,7 @@ func (m *ExecuteShardsResponse) Reset() { *m = ExecuteShardsResponse{} } func (m *ExecuteShardsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteShardsResponse) ProtoMessage() {} func (*ExecuteShardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{4} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{4} } func (m *ExecuteShardsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteShardsResponse.Unmarshal(m, b) @@ -568,7 +568,7 @@ func (m *ExecuteKeyspaceIdsRequest) Reset() { *m = ExecuteKeyspaceIdsReq func (m *ExecuteKeyspaceIdsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteKeyspaceIdsRequest) ProtoMessage() {} func (*ExecuteKeyspaceIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{5} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{5} } func (m *ExecuteKeyspaceIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteKeyspaceIdsRequest.Unmarshal(m, b) @@ -663,7 +663,7 @@ func (m *ExecuteKeyspaceIdsResponse) Reset() { *m = ExecuteKeyspaceIdsRe func (m *ExecuteKeyspaceIdsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteKeyspaceIdsResponse) ProtoMessage() {} func (*ExecuteKeyspaceIdsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{6} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{6} } func (m *ExecuteKeyspaceIdsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteKeyspaceIdsResponse.Unmarshal(m, b) @@ -734,7 +734,7 @@ func (m *ExecuteKeyRangesRequest) Reset() { *m = ExecuteKeyRangesRequest func (m *ExecuteKeyRangesRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteKeyRangesRequest) ProtoMessage() {} func (*ExecuteKeyRangesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{7} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{7} } func (m *ExecuteKeyRangesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteKeyRangesRequest.Unmarshal(m, b) @@ -829,7 +829,7 @@ func (m *ExecuteKeyRangesResponse) Reset() { *m = ExecuteKeyRangesRespon func (m *ExecuteKeyRangesResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteKeyRangesResponse) ProtoMessage() {} func (*ExecuteKeyRangesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{8} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{8} } func (m *ExecuteKeyRangesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteKeyRangesResponse.Unmarshal(m, b) @@ -902,7 +902,7 @@ func (m *ExecuteEntityIdsRequest) Reset() { *m = ExecuteEntityIdsRequest func (m *ExecuteEntityIdsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteEntityIdsRequest) ProtoMessage() {} func (*ExecuteEntityIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{9} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{9} } func (m *ExecuteEntityIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteEntityIdsRequest.Unmarshal(m, b) @@ -1001,7 +1001,7 @@ func (m *ExecuteEntityIdsRequest_EntityId) Reset() { *m = ExecuteEntityI func (m *ExecuteEntityIdsRequest_EntityId) String() string { return proto.CompactTextString(m) } func (*ExecuteEntityIdsRequest_EntityId) ProtoMessage() {} func (*ExecuteEntityIdsRequest_EntityId) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{9, 0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{9, 0} } func (m *ExecuteEntityIdsRequest_EntityId) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteEntityIdsRequest_EntityId.Unmarshal(m, b) @@ -1061,7 +1061,7 @@ func (m *ExecuteEntityIdsResponse) Reset() { *m = ExecuteEntityIdsRespon func (m *ExecuteEntityIdsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteEntityIdsResponse) ProtoMessage() {} func (*ExecuteEntityIdsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{10} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{10} } func (m *ExecuteEntityIdsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteEntityIdsResponse.Unmarshal(m, b) @@ -1126,7 +1126,7 @@ func (m *ExecuteBatchRequest) Reset() { *m = ExecuteBatchRequest{} } func (m *ExecuteBatchRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchRequest) ProtoMessage() {} func (*ExecuteBatchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{11} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{11} } func (m *ExecuteBatchRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchRequest.Unmarshal(m, b) @@ -1214,7 +1214,7 @@ func (m *ExecuteBatchResponse) Reset() { *m = ExecuteBatchResponse{} } func (m *ExecuteBatchResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchResponse) ProtoMessage() {} func (*ExecuteBatchResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{12} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{12} } func (m *ExecuteBatchResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchResponse.Unmarshal(m, b) @@ -1274,7 +1274,7 @@ func (m *BoundShardQuery) Reset() { *m = BoundShardQuery{} } func (m *BoundShardQuery) String() string { return proto.CompactTextString(m) } func (*BoundShardQuery) ProtoMessage() {} func (*BoundShardQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{13} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{13} } func (m *BoundShardQuery) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BoundShardQuery.Unmarshal(m, b) @@ -1342,7 +1342,7 @@ func (m *ExecuteBatchShardsRequest) Reset() { *m = ExecuteBatchShardsReq func (m *ExecuteBatchShardsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchShardsRequest) ProtoMessage() {} func (*ExecuteBatchShardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{14} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{14} } func (m *ExecuteBatchShardsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchShardsRequest.Unmarshal(m, b) @@ -1423,7 +1423,7 @@ func (m *ExecuteBatchShardsResponse) Reset() { *m = ExecuteBatchShardsRe func (m *ExecuteBatchShardsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchShardsResponse) ProtoMessage() {} func (*ExecuteBatchShardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{15} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{15} } func (m *ExecuteBatchShardsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchShardsResponse.Unmarshal(m, b) @@ -1484,7 +1484,7 @@ func (m *BoundKeyspaceIdQuery) Reset() { *m = BoundKeyspaceIdQuery{} } func (m *BoundKeyspaceIdQuery) String() string { return proto.CompactTextString(m) } func (*BoundKeyspaceIdQuery) ProtoMessage() {} func (*BoundKeyspaceIdQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{16} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{16} } func (m *BoundKeyspaceIdQuery) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BoundKeyspaceIdQuery.Unmarshal(m, b) @@ -1551,7 +1551,7 @@ func (m *ExecuteBatchKeyspaceIdsRequest) Reset() { *m = ExecuteBatchKeys func (m *ExecuteBatchKeyspaceIdsRequest) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchKeyspaceIdsRequest) ProtoMessage() {} func (*ExecuteBatchKeyspaceIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{17} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{17} } func (m *ExecuteBatchKeyspaceIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchKeyspaceIdsRequest.Unmarshal(m, b) @@ -1632,7 +1632,7 @@ func (m *ExecuteBatchKeyspaceIdsResponse) Reset() { *m = ExecuteBatchKey func (m *ExecuteBatchKeyspaceIdsResponse) String() string { return proto.CompactTextString(m) } func (*ExecuteBatchKeyspaceIdsResponse) ProtoMessage() {} func (*ExecuteBatchKeyspaceIdsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{18} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{18} } func (m *ExecuteBatchKeyspaceIdsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ExecuteBatchKeyspaceIdsResponse.Unmarshal(m, b) @@ -1696,7 +1696,7 @@ func (m *StreamExecuteRequest) Reset() { *m = StreamExecuteRequest{} } func (m *StreamExecuteRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteRequest) ProtoMessage() {} func (*StreamExecuteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{19} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{19} } func (m *StreamExecuteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteRequest.Unmarshal(m, b) @@ -1775,7 +1775,7 @@ func (m *StreamExecuteResponse) Reset() { *m = StreamExecuteResponse{} } func (m *StreamExecuteResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteResponse) ProtoMessage() {} func (*StreamExecuteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{20} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{20} } func (m *StreamExecuteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteResponse.Unmarshal(m, b) @@ -1826,7 +1826,7 @@ func (m *StreamExecuteShardsRequest) Reset() { *m = StreamExecuteShardsR func (m *StreamExecuteShardsRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteShardsRequest) ProtoMessage() {} func (*StreamExecuteShardsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{21} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{21} } func (m *StreamExecuteShardsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteShardsRequest.Unmarshal(m, b) @@ -1903,7 +1903,7 @@ func (m *StreamExecuteShardsResponse) Reset() { *m = StreamExecuteShards func (m *StreamExecuteShardsResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteShardsResponse) ProtoMessage() {} func (*StreamExecuteShardsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{22} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{22} } func (m *StreamExecuteShardsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteShardsResponse.Unmarshal(m, b) @@ -1955,7 +1955,7 @@ func (m *StreamExecuteKeyspaceIdsRequest) Reset() { *m = StreamExecuteKe func (m *StreamExecuteKeyspaceIdsRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteKeyspaceIdsRequest) ProtoMessage() {} func (*StreamExecuteKeyspaceIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{23} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{23} } func (m *StreamExecuteKeyspaceIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteKeyspaceIdsRequest.Unmarshal(m, b) @@ -2032,7 +2032,7 @@ func (m *StreamExecuteKeyspaceIdsResponse) Reset() { *m = StreamExecuteK func (m *StreamExecuteKeyspaceIdsResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteKeyspaceIdsResponse) ProtoMessage() {} func (*StreamExecuteKeyspaceIdsResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{24} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{24} } func (m *StreamExecuteKeyspaceIdsResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteKeyspaceIdsResponse.Unmarshal(m, b) @@ -2084,7 +2084,7 @@ func (m *StreamExecuteKeyRangesRequest) Reset() { *m = StreamExecuteKeyR func (m *StreamExecuteKeyRangesRequest) String() string { return proto.CompactTextString(m) } func (*StreamExecuteKeyRangesRequest) ProtoMessage() {} func (*StreamExecuteKeyRangesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{25} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{25} } func (m *StreamExecuteKeyRangesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteKeyRangesRequest.Unmarshal(m, b) @@ -2161,7 +2161,7 @@ func (m *StreamExecuteKeyRangesResponse) Reset() { *m = StreamExecuteKey func (m *StreamExecuteKeyRangesResponse) String() string { return proto.CompactTextString(m) } func (*StreamExecuteKeyRangesResponse) ProtoMessage() {} func (*StreamExecuteKeyRangesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{26} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{26} } func (m *StreamExecuteKeyRangesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_StreamExecuteKeyRangesResponse.Unmarshal(m, b) @@ -2207,7 +2207,7 @@ func (m *BeginRequest) Reset() { *m = BeginRequest{} } func (m *BeginRequest) String() string { return proto.CompactTextString(m) } func (*BeginRequest) ProtoMessage() {} func (*BeginRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{27} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{27} } func (m *BeginRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginRequest.Unmarshal(m, b) @@ -2254,7 +2254,7 @@ func (m *BeginResponse) Reset() { *m = BeginResponse{} } func (m *BeginResponse) String() string { return proto.CompactTextString(m) } func (*BeginResponse) ProtoMessage() {} func (*BeginResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{28} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{28} } func (m *BeginResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BeginResponse.Unmarshal(m, b) @@ -2302,7 +2302,7 @@ func (m *CommitRequest) Reset() { *m = CommitRequest{} } func (m *CommitRequest) String() string { return proto.CompactTextString(m) } func (*CommitRequest) ProtoMessage() {} func (*CommitRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{29} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{29} } func (m *CommitRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CommitRequest.Unmarshal(m, b) @@ -2354,7 +2354,7 @@ func (m *CommitResponse) Reset() { *m = CommitResponse{} } func (m *CommitResponse) String() string { return proto.CompactTextString(m) } func (*CommitResponse) ProtoMessage() {} func (*CommitResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{30} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{30} } func (m *CommitResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_CommitResponse.Unmarshal(m, b) @@ -2390,7 +2390,7 @@ func (m *RollbackRequest) Reset() { *m = RollbackRequest{} } func (m *RollbackRequest) String() string { return proto.CompactTextString(m) } func (*RollbackRequest) ProtoMessage() {} func (*RollbackRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{31} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{31} } func (m *RollbackRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RollbackRequest.Unmarshal(m, b) @@ -2435,7 +2435,7 @@ func (m *RollbackResponse) Reset() { *m = RollbackResponse{} } func (m *RollbackResponse) String() string { return proto.CompactTextString(m) } func (*RollbackResponse) ProtoMessage() {} func (*RollbackResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{32} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{32} } func (m *RollbackResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_RollbackResponse.Unmarshal(m, b) @@ -2471,7 +2471,7 @@ func (m *ResolveTransactionRequest) Reset() { *m = ResolveTransactionReq func (m *ResolveTransactionRequest) String() string { return proto.CompactTextString(m) } func (*ResolveTransactionRequest) ProtoMessage() {} func (*ResolveTransactionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{33} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{33} } func (m *ResolveTransactionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResolveTransactionRequest.Unmarshal(m, b) @@ -2527,7 +2527,7 @@ func (m *MessageStreamRequest) Reset() { *m = MessageStreamRequest{} } func (m *MessageStreamRequest) String() string { return proto.CompactTextString(m) } func (*MessageStreamRequest) ProtoMessage() {} func (*MessageStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{34} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{34} } func (m *MessageStreamRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageStreamRequest.Unmarshal(m, b) @@ -2602,7 +2602,7 @@ func (m *MessageAckRequest) Reset() { *m = MessageAckRequest{} } func (m *MessageAckRequest) String() string { return proto.CompactTextString(m) } func (*MessageAckRequest) ProtoMessage() {} func (*MessageAckRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{35} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{35} } func (m *MessageAckRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageAckRequest.Unmarshal(m, b) @@ -2666,7 +2666,7 @@ func (m *IdKeyspaceId) Reset() { *m = IdKeyspaceId{} } func (m *IdKeyspaceId) String() string { return proto.CompactTextString(m) } func (*IdKeyspaceId) ProtoMessage() {} func (*IdKeyspaceId) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{36} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{36} } func (m *IdKeyspaceId) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_IdKeyspaceId.Unmarshal(m, b) @@ -2719,7 +2719,7 @@ func (m *MessageAckKeyspaceIdsRequest) Reset() { *m = MessageAckKeyspace func (m *MessageAckKeyspaceIdsRequest) String() string { return proto.CompactTextString(m) } func (*MessageAckKeyspaceIdsRequest) ProtoMessage() {} func (*MessageAckKeyspaceIdsRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{37} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{37} } func (m *MessageAckKeyspaceIdsRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_MessageAckKeyspaceIdsRequest.Unmarshal(m, b) @@ -2778,7 +2778,7 @@ func (m *ResolveTransactionResponse) Reset() { *m = ResolveTransactionRe func (m *ResolveTransactionResponse) String() string { return proto.CompactTextString(m) } func (*ResolveTransactionResponse) ProtoMessage() {} func (*ResolveTransactionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{38} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{38} } func (m *ResolveTransactionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ResolveTransactionResponse.Unmarshal(m, b) @@ -2896,7 +2896,7 @@ func (m *SplitQueryRequest) Reset() { *m = SplitQueryRequest{} } func (m *SplitQueryRequest) String() string { return proto.CompactTextString(m) } func (*SplitQueryRequest) ProtoMessage() {} func (*SplitQueryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{39} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{39} } func (m *SplitQueryRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryRequest.Unmarshal(m, b) @@ -2985,7 +2985,7 @@ func (m *SplitQueryResponse) Reset() { *m = SplitQueryResponse{} } func (m *SplitQueryResponse) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse) ProtoMessage() {} func (*SplitQueryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{40} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{40} } func (m *SplitQueryResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse.Unmarshal(m, b) @@ -3026,7 +3026,7 @@ func (m *SplitQueryResponse_KeyRangePart) Reset() { *m = SplitQueryRespo func (m *SplitQueryResponse_KeyRangePart) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse_KeyRangePart) ProtoMessage() {} func (*SplitQueryResponse_KeyRangePart) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{40, 0} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{40, 0} } func (m *SplitQueryResponse_KeyRangePart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse_KeyRangePart.Unmarshal(m, b) @@ -3074,7 +3074,7 @@ func (m *SplitQueryResponse_ShardPart) Reset() { *m = SplitQueryResponse func (m *SplitQueryResponse_ShardPart) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse_ShardPart) ProtoMessage() {} func (*SplitQueryResponse_ShardPart) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{40, 1} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{40, 1} } func (m *SplitQueryResponse_ShardPart) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse_ShardPart.Unmarshal(m, b) @@ -3127,7 +3127,7 @@ func (m *SplitQueryResponse_Part) Reset() { *m = SplitQueryResponse_Part func (m *SplitQueryResponse_Part) String() string { return proto.CompactTextString(m) } func (*SplitQueryResponse_Part) ProtoMessage() {} func (*SplitQueryResponse_Part) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{40, 2} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{40, 2} } func (m *SplitQueryResponse_Part) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SplitQueryResponse_Part.Unmarshal(m, b) @@ -3188,7 +3188,7 @@ func (m *GetSrvKeyspaceRequest) Reset() { *m = GetSrvKeyspaceRequest{} } func (m *GetSrvKeyspaceRequest) String() string { return proto.CompactTextString(m) } func (*GetSrvKeyspaceRequest) ProtoMessage() {} func (*GetSrvKeyspaceRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{41} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{41} } func (m *GetSrvKeyspaceRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSrvKeyspaceRequest.Unmarshal(m, b) @@ -3228,7 +3228,7 @@ func (m *GetSrvKeyspaceResponse) Reset() { *m = GetSrvKeyspaceResponse{} func (m *GetSrvKeyspaceResponse) String() string { return proto.CompactTextString(m) } func (*GetSrvKeyspaceResponse) ProtoMessage() {} func (*GetSrvKeyspaceResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{42} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{42} } func (m *GetSrvKeyspaceResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_GetSrvKeyspaceResponse.Unmarshal(m, b) @@ -3286,7 +3286,7 @@ func (m *UpdateStreamRequest) Reset() { *m = UpdateStreamRequest{} } func (m *UpdateStreamRequest) String() string { return proto.CompactTextString(m) } func (*UpdateStreamRequest) ProtoMessage() {} func (*UpdateStreamRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{43} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{43} } func (m *UpdateStreamRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateStreamRequest.Unmarshal(m, b) @@ -3374,7 +3374,7 @@ func (m *UpdateStreamResponse) Reset() { *m = UpdateStreamResponse{} } func (m *UpdateStreamResponse) String() string { return proto.CompactTextString(m) } func (*UpdateStreamResponse) ProtoMessage() {} func (*UpdateStreamResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_vtgate_8f5c6038eac4796e, []int{44} + return fileDescriptor_vtgate_1d4a858d9b127f46, []int{44} } func (m *UpdateStreamResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UpdateStreamResponse.Unmarshal(m, b) @@ -3462,9 +3462,9 @@ func init() { proto.RegisterEnum("vtgate.TransactionMode", TransactionMode_name, TransactionMode_value) } -func init() { proto.RegisterFile("vtgate.proto", fileDescriptor_vtgate_8f5c6038eac4796e) } +func init() { proto.RegisterFile("vtgate.proto", fileDescriptor_vtgate_1d4a858d9b127f46) } -var fileDescriptor_vtgate_8f5c6038eac4796e = []byte{ +var fileDescriptor_vtgate_1d4a858d9b127f46 = []byte{ // 1883 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5a, 0x4f, 0x8f, 0x23, 0x47, 0x15, 0xa7, 0xbb, 0xfd, 0xf7, 0xf9, 0xef, 0xd6, 0x78, 0x77, 0x1d, 0x67, 0xd8, 0x99, 0x74, 0x18, diff --git a/go/vt/schemamanager/schemaswap/schema_swap.go b/go/vt/schemamanager/schemaswap/schema_swap.go index 2e8e232b54f..b32b0e0c146 100644 --- a/go/vt/schemamanager/schemaswap/schema_swap.go +++ b/go/vt/schemamanager/schemaswap/schema_swap.go @@ -1092,7 +1092,7 @@ func (shardSwap *shardSchemaSwap) takeSeedBackup() (err error) { } shardSwap.addShardLog(fmt.Sprintf("Taking backup on the seed tablet %v", seedTablet.Alias)) - eventStream, err := shardSwap.parent.tabletClient.Backup(shardSwap.parent.ctx, seedTablet, *backupConcurrency) + eventStream, err := shardSwap.parent.tabletClient.Backup(shardSwap.parent.ctx, seedTablet, *backupConcurrency, false) if err != nil { return err } diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index 3a7a450b374..0b2f8ab2d3a 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -699,7 +699,7 @@ func (itmc *internalTabletManagerClient) PromoteSlave(ctx context.Context, table return "", fmt.Errorf("not implemented in vtcombo") } -func (itmc *internalTabletManagerClient) Backup(ctx context.Context, tablet *topodatapb.Tablet, concurrency int) (logutil.EventStream, error) { +func (itmc *internalTabletManagerClient) Backup(ctx context.Context, tablet *topodatapb.Tablet, concurrency int, allowMaster bool) (logutil.EventStream, error) { return nil, fmt.Errorf("not implemented in vtcombo") } diff --git a/go/vt/vtctl/backup.go b/go/vt/vtctl/backup.go index 487bc909183..e22917bbfcb 100644 --- a/go/vt/vtctl/backup.go +++ b/go/vt/vtctl/backup.go @@ -39,7 +39,7 @@ func init() { addCommand("Shards", command{ "BackupShard", commandBackupShard, - "", + "[-allow_master=false] ", "Chooses a tablet and creates a backup for a shard."}) addCommand("Shards", command{ "RemoveBackup", @@ -50,7 +50,7 @@ func init() { addCommand("Tablets", command{ "Backup", commandBackup, - "[-concurrency=4] ", + "[-concurrency=4] [-allow_master=false] ", "Stops mysqld and uses the BackupStorage service to store a new backup. This function also remembers if the tablet was replicating so that it can restore the same state after the backup completes."}) addCommand("Tablets", command{ "RestoreFromBackup", @@ -61,6 +61,8 @@ func init() { func commandBackup(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { concurrency := subFlags.Int("concurrency", 4, "Specifies the number of compression/checksum jobs to run simultaneously") + allowMaster := subFlags.Bool("allow_master", false, "Allows backups to be taken on master. Warning!! If you are using the builtin backup engine, this will shutdown your master mysql for as long as it takes to create a backup ") + if err := subFlags.Parse(args); err != nil { return err } @@ -77,11 +79,13 @@ func commandBackup(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.Fl return err } - return execBackup(ctx, wr, tabletInfo.Tablet, *concurrency) + return execBackup(ctx, wr, tabletInfo.Tablet, *concurrency, *allowMaster) } func commandBackupShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { concurrency := subFlags.Int("concurrency", 4, "Specifies the number of compression/checksum jobs to run simultaneously") + allowMaster := subFlags.Bool("allow_master", false, "Whether to use master tablet for backup. Warning!! If you are using the builtin backup engine, this will shutdown your master mysql for as long as it takes to create a backup ") + if err := subFlags.Parse(args); err != nil { return err } @@ -103,13 +107,12 @@ func commandBackupShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl var secondsBehind uint32 for i := range tablets { - // only run a backup on a replica, rdonly or spare tablet type + // find a replica, rdonly or spare tablet type to run the backup on switch tablets[i].Type { case topodatapb.TabletType_REPLICA, topodatapb.TabletType_RDONLY, topodatapb.TabletType_SPARE: default: continue } - // choose the first tablet as the baseline if tabletForBackup == nil { tabletForBackup = tablets[i].Tablet @@ -124,16 +127,29 @@ func commandBackupShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl } } + if tabletForBackup == nil && *allowMaster { + for i := range tablets { + switch tablets[i].Type { + case topodatapb.TabletType_MASTER: + tabletForBackup = tablets[i].Tablet + secondsBehind = 0 + break + default: + continue + } + } + } + if tabletForBackup == nil { return errors.New("no tablet available for backup") } - return execBackup(ctx, wr, tabletForBackup, *concurrency) + return execBackup(ctx, wr, tabletForBackup, *concurrency, *allowMaster) } // execBackup is shared by Backup and BackupShard -func execBackup(ctx context.Context, wr *wrangler.Wrangler, tablet *topodatapb.Tablet, concurrency int) error { - stream, err := wr.TabletManagerClient().Backup(ctx, tablet, concurrency) +func execBackup(ctx context.Context, wr *wrangler.Wrangler, tablet *topodatapb.Tablet, concurrency int, allowMaster bool) error { + stream, err := wr.TabletManagerClient().Backup(ctx, tablet, concurrency, allowMaster) if err != nil { return err } diff --git a/go/vt/vttablet/agentrpctest/test_agent_rpc.go b/go/vt/vttablet/agentrpctest/test_agent_rpc.go index de979f35482..19316f2605f 100644 --- a/go/vt/vttablet/agentrpctest/test_agent_rpc.go +++ b/go/vt/vttablet/agentrpctest/test_agent_rpc.go @@ -1156,21 +1156,23 @@ func agentRPCTestPromoteSlavePanic(ctx context.Context, t *testing.T, client tmc // var testBackupConcurrency = 24 +var testBackupAllowMaster = false var testBackupCalled = false var testRestoreFromBackupCalled = false -func (fra *fakeRPCAgent) Backup(ctx context.Context, concurrency int, logger logutil.Logger) error { +func (fra *fakeRPCAgent) Backup(ctx context.Context, concurrency int, logger logutil.Logger, allowMaster bool) error { if fra.panics { panic(fmt.Errorf("test-triggered panic")) } compare(fra.t, "Backup args", concurrency, testBackupConcurrency) + compare(fra.t, "Backup args", allowMaster, testBackupAllowMaster) logStuff(logger, 10) testBackupCalled = true return nil } func agentRPCTestBackup(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - stream, err := client.Backup(ctx, tablet, testBackupConcurrency) + stream, err := client.Backup(ctx, tablet, testBackupConcurrency, testBackupAllowMaster) if err != nil { t.Fatalf("Backup failed: %v", err) } @@ -1179,7 +1181,7 @@ func agentRPCTestBackup(ctx context.Context, t *testing.T, client tmclient.Table } func agentRPCTestBackupPanic(ctx context.Context, t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.Tablet) { - stream, err := client.Backup(ctx, tablet, testBackupConcurrency) + stream, err := client.Backup(ctx, tablet, testBackupConcurrency, testBackupAllowMaster) if err != nil { t.Fatalf("Backup failed: %v", err) } diff --git a/go/vt/vttablet/faketmclient/fake_client.go b/go/vt/vttablet/faketmclient/fake_client.go index 436d7ee09bb..64c27104051 100644 --- a/go/vt/vttablet/faketmclient/fake_client.go +++ b/go/vt/vttablet/faketmclient/fake_client.go @@ -301,7 +301,7 @@ func (e *eofEventStream) Recv() (*logutilpb.Event, error) { } // Backup is part of the tmclient.TabletManagerClient interface. -func (client *FakeTabletManagerClient) Backup(ctx context.Context, tablet *topodatapb.Tablet, concurrency int) (logutil.EventStream, error) { +func (client *FakeTabletManagerClient) Backup(ctx context.Context, tablet *topodatapb.Tablet, concurrency int, allowMaster bool) (logutil.EventStream, error) { return &eofEventStream{}, nil } diff --git a/go/vt/vttablet/grpctmclient/client.go b/go/vt/vttablet/grpctmclient/client.go index 4dd9c0be243..e921ca3275e 100644 --- a/go/vt/vttablet/grpctmclient/client.go +++ b/go/vt/vttablet/grpctmclient/client.go @@ -775,7 +775,7 @@ func (e *backupStreamAdapter) Recv() (*logutilpb.Event, error) { } // Backup is part of the tmclient.TabletManagerClient interface. -func (client *Client) Backup(ctx context.Context, tablet *topodatapb.Tablet, concurrency int) (logutil.EventStream, error) { +func (client *Client) Backup(ctx context.Context, tablet *topodatapb.Tablet, concurrency int, allowMaster bool) (logutil.EventStream, error) { cc, c, err := client.dial(tablet) if err != nil { return nil, err @@ -783,6 +783,7 @@ func (client *Client) Backup(ctx context.Context, tablet *topodatapb.Tablet, con stream, err := c.Backup(ctx, &tabletmanagerdatapb.BackupRequest{ Concurrency: int64(concurrency), + AllowMaster: bool(allowMaster), }) if err != nil { cc.Close() diff --git a/go/vt/vttablet/grpctmserver/server.go b/go/vt/vttablet/grpctmserver/server.go index 6caa9bdfc54..90deda35ccd 100644 --- a/go/vt/vttablet/grpctmserver/server.go +++ b/go/vt/vttablet/grpctmserver/server.go @@ -449,7 +449,7 @@ func (s *server) Backup(request *tabletmanagerdatapb.BackupRequest, stream table }) }) - return s.agent.Backup(ctx, int(request.Concurrency), logger) + return s.agent.Backup(ctx, int(request.Concurrency), logger, bool(request.AllowMaster)) } func (s *server) RestoreFromBackup(request *tabletmanagerdatapb.RestoreFromBackupRequest, stream tabletmanagerservicepb.TabletManager_RestoreFromBackupServer) (err error) { diff --git a/go/vt/vttablet/tabletmanager/rpc_agent.go b/go/vt/vttablet/tabletmanager/rpc_agent.go index 29d8249c03f..c5ac21285e5 100644 --- a/go/vt/vttablet/tabletmanager/rpc_agent.go +++ b/go/vt/vttablet/tabletmanager/rpc_agent.go @@ -126,7 +126,7 @@ type RPCAgent interface { // Backup / restore related methods - Backup(ctx context.Context, concurrency int, logger logutil.Logger) error + Backup(ctx context.Context, concurrency int, logger logutil.Logger, allowMaster bool) error RestoreFromBackup(ctx context.Context, logger logutil.Logger) error diff --git a/go/vt/vttablet/tabletmanager/rpc_backup.go b/go/vt/vttablet/tabletmanager/rpc_backup.go index 8eeeb322ce1..bd52eeedaeb 100644 --- a/go/vt/vttablet/tabletmanager/rpc_backup.go +++ b/go/vt/vttablet/tabletmanager/rpc_backup.go @@ -30,7 +30,7 @@ import ( ) // Backup takes a db backup and sends it to the BackupStorage -func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger logutil.Logger) error { +func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger logutil.Logger, allowMaster bool) error { if err := agent.lock(ctx); err != nil { return err } @@ -45,16 +45,16 @@ func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger lo // but the process didn't find out about this. // It is not safe to take backups from tablet in this state currentTablet := agent.Tablet() - if currentTablet.Type == topodatapb.TabletType_MASTER { - return fmt.Errorf("type MASTER cannot take backup, if you really need to do this, restart vttablet in replica mode") + if !allowMaster && currentTablet.Type == topodatapb.TabletType_MASTER { + return fmt.Errorf("type MASTER cannot take backup, if you really need to do this, rerun the backup command with -allow_master") } tablet, err := agent.TopoServer.GetTablet(ctx, agent.TabletAlias) if err != nil { return err } - if tablet.Type == topodatapb.TabletType_MASTER { - return fmt.Errorf("type MASTER cannot take backup, if you really need to do this, restart vttablet in replica mode") + if !allowMaster && tablet.Type == topodatapb.TabletType_MASTER { + return fmt.Errorf("type MASTER cannot take backup, if you really need to do this, rerun the backup command with -allow_master") } originalType := tablet.Type diff --git a/go/vt/vttablet/tmclient/rpc_client_api.go b/go/vt/vttablet/tmclient/rpc_client_api.go index 063f5243708..8b3b0927c2c 100644 --- a/go/vt/vttablet/tmclient/rpc_client_api.go +++ b/go/vt/vttablet/tmclient/rpc_client_api.go @@ -201,7 +201,7 @@ type TabletManagerClient interface { // // Backup creates a database backup - Backup(ctx context.Context, tablet *topodatapb.Tablet, concurrency int) (logutil.EventStream, error) + Backup(ctx context.Context, tablet *topodatapb.Tablet, concurrency int, allowMaster bool) (logutil.EventStream, error) // RestoreFromBackup deletes local data and restores database from backup RestoreFromBackup(ctx context.Context, tablet *topodatapb.Tablet) (logutil.EventStream, error) diff --git a/proto/tabletmanagerdata.proto b/proto/tabletmanagerdata.proto index e52944035d8..0d518a74309 100644 --- a/proto/tabletmanagerdata.proto +++ b/proto/tabletmanagerdata.proto @@ -433,6 +433,7 @@ message PromoteSlaveResponse { message BackupRequest { int64 concurrency = 1; + bool allowMaster = 2; } message BackupResponse { diff --git a/py/vtproto/tabletmanagerdata_pb2.py b/py/vtproto/tabletmanagerdata_pb2.py index bdb2701df21..1a623c83833 100644 --- a/py/vtproto/tabletmanagerdata_pb2.py +++ b/py/vtproto/tabletmanagerdata_pb2.py @@ -23,7 +23,7 @@ package='tabletmanagerdata', syntax='proto3', serialized_options=_b('Z.vitess.io/vitess/go/vt/proto/tabletmanagerdata'), - serialized_pb=_b('\n\x17tabletmanagerdata.proto\x12\x11tabletmanagerdata\x1a\x0bquery.proto\x1a\x0etopodata.proto\x1a\x15replicationdata.proto\x1a\rlogutil.proto\"\x93\x01\n\x0fTableDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06schema\x18\x02 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x03 \x03(\t\x12\x1b\n\x13primary_key_columns\x18\x04 \x03(\t\x12\x0c\n\x04type\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x61ta_length\x18\x06 \x01(\x04\x12\x11\n\trow_count\x18\x07 \x01(\x04\"{\n\x10SchemaDefinition\x12\x17\n\x0f\x64\x61tabase_schema\x18\x01 \x01(\t\x12=\n\x11table_definitions\x18\x02 \x03(\x0b\x32\".tabletmanagerdata.TableDefinition\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x8b\x01\n\x12SchemaChangeResult\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\xc1\x01\n\x0eUserPermission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\x12\x19\n\x11password_checksum\x18\x03 \x01(\x04\x12\x45\n\nprivileges\x18\x04 \x03(\x0b\x32\x31.tabletmanagerdata.UserPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xae\x01\n\x0c\x44\x62Permission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\n\n\x02\x64\x62\x18\x02 \x01(\t\x12\x0c\n\x04user\x18\x03 \x01(\t\x12\x43\n\nprivileges\x18\x04 \x03(\x0b\x32/.tabletmanagerdata.DbPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x83\x01\n\x0bPermissions\x12;\n\x10user_permissions\x18\x01 \x03(\x0b\x32!.tabletmanagerdata.UserPermission\x12\x37\n\x0e\x64\x62_permissions\x18\x02 \x03(\x0b\x32\x1f.tabletmanagerdata.DbPermission\"\x1e\n\x0bPingRequest\x12\x0f\n\x07payload\x18\x01 \x01(\t\"\x1f\n\x0cPingResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t\" \n\x0cSleepRequest\x12\x10\n\x08\x64uration\x18\x01 \x01(\x03\"\x0f\n\rSleepResponse\"\xaf\x01\n\x12\x45xecuteHookRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nparameters\x18\x02 \x03(\t\x12\x46\n\textra_env\x18\x03 \x03(\x0b\x32\x33.tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry\x1a/\n\rExtraEnvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"J\n\x13\x45xecuteHookResponse\x12\x13\n\x0b\x65xit_status\x18\x01 \x01(\x03\x12\x0e\n\x06stdout\x18\x02 \x01(\t\x12\x0e\n\x06stderr\x18\x03 \x01(\t\"Q\n\x10GetSchemaRequest\x12\x0e\n\x06tables\x18\x01 \x03(\t\x12\x15\n\rinclude_views\x18\x02 \x01(\x08\x12\x16\n\x0e\x65xclude_tables\x18\x03 \x03(\t\"S\n\x11GetSchemaResponse\x12>\n\x11schema_definition\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x17\n\x15GetPermissionsRequest\"M\n\x16GetPermissionsResponse\x12\x33\n\x0bpermissions\x18\x01 \x01(\x0b\x32\x1e.tabletmanagerdata.Permissions\"\x14\n\x12SetReadOnlyRequest\"\x15\n\x13SetReadOnlyResponse\"\x15\n\x13SetReadWriteRequest\"\x16\n\x14SetReadWriteResponse\">\n\x11\x43hangeTypeRequest\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\"\x14\n\x12\x43hangeTypeResponse\"\x15\n\x13RefreshStateRequest\"\x16\n\x14RefreshStateResponse\"\x17\n\x15RunHealthCheckRequest\"\x18\n\x16RunHealthCheckResponse\"+\n\x18IgnoreHealthErrorRequest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"\x1b\n\x19IgnoreHealthErrorResponse\",\n\x13ReloadSchemaRequest\x12\x15\n\rwait_position\x18\x01 \x01(\t\"\x16\n\x14ReloadSchemaResponse\")\n\x16PreflightSchemaRequest\x12\x0f\n\x07\x63hanges\x18\x01 \x03(\t\"X\n\x17PreflightSchemaResponse\x12=\n\x0e\x63hange_results\x18\x01 \x03(\x0b\x32%.tabletmanagerdata.SchemaChangeResult\"\xc2\x01\n\x12\x41pplySchemaRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12\r\n\x05\x66orce\x18\x02 \x01(\x08\x12\x19\n\x11\x61llow_replication\x18\x03 \x01(\x08\x12:\n\rbefore_schema\x18\x04 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x05 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x8c\x01\n\x13\x41pplySchemaResponse\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x13\n\x11LockTablesRequest\"\x14\n\x12LockTablesResponse\"\x15\n\x13UnlockTablesRequest\"\x16\n\x14UnlockTablesResponse\"|\n\x18\x45xecuteFetchAsDbaRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x17\n\x0f\x64isable_binlogs\x18\x04 \x01(\x08\x12\x15\n\rreload_schema\x18\x05 \x01(\x08\"?\n\x19\x45xecuteFetchAsDbaResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"h\n\x1d\x45xecuteFetchAsAllPrivsRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x15\n\rreload_schema\x18\x04 \x01(\x08\"D\n\x1e\x45xecuteFetchAsAllPrivsResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\";\n\x18\x45xecuteFetchAsAppRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x10\n\x08max_rows\x18\x02 \x01(\x04\"?\n\x19\x45xecuteFetchAsAppResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\x14\n\x12SlaveStatusRequest\">\n\x13SlaveStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x17\n\x15MasterPositionRequest\"*\n\x16MasterPositionResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x12\n\x10StopSlaveRequest\"\x13\n\x11StopSlaveResponse\"A\n\x17StopSlaveMinimumRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\",\n\x18StopSlaveMinimumResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x13\n\x11StartSlaveRequest\"\x14\n\x12StartSlaveResponse\"E\n\x1bStartSlaveUntilAfterRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\"\x1e\n\x1cStartSlaveUntilAfterResponse\"8\n!TabletExternallyReparentedRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"$\n\"TabletExternallyReparentedResponse\" \n\x1eTabletExternallyElectedRequest\"!\n\x1fTabletExternallyElectedResponse\"\x12\n\x10GetSlavesRequest\"\"\n\x11GetSlavesResponse\x12\r\n\x05\x61\x64\x64rs\x18\x01 \x03(\t\"\x19\n\x17ResetReplicationRequest\"\x1a\n\x18ResetReplicationResponse\"(\n\x17VReplicationExecRequest\x12\r\n\x05query\x18\x01 \x01(\t\">\n\x18VReplicationExecResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"=\n\x1dVReplicationWaitForPosRequest\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08position\x18\x02 \x01(\t\" \n\x1eVReplicationWaitForPosResponse\"\x13\n\x11InitMasterRequest\"&\n\x12InitMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x99\x01\n\x1ePopulateReparentJournalRequest\x12\x17\n\x0ftime_created_ns\x18\x01 \x01(\x03\x12\x13\n\x0b\x61\x63tion_name\x18\x02 \x01(\t\x12+\n\x0cmaster_alias\x18\x03 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x04 \x01(\t\"!\n\x1fPopulateReparentJournalResponse\"p\n\x10InitSlaveRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x02 \x01(\t\x12\x17\n\x0ftime_created_ns\x18\x03 \x01(\x03\"\x13\n\x11InitSlaveResponse\"\x15\n\x13\x44\x65moteMasterRequest\"(\n\x14\x44\x65moteMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17UndoDemoteMasterRequest\"\x1a\n\x18UndoDemoteMasterResponse\"3\n\x1fPromoteSlaveWhenCaughtUpRequest\x12\x10\n\x08position\x18\x01 \x01(\t\"4\n PromoteSlaveWhenCaughtUpResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17SlaveWasPromotedRequest\"\x1a\n\x18SlaveWasPromotedResponse\"m\n\x10SetMasterRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x17\n\x0ftime_created_ns\x18\x02 \x01(\x03\x12\x19\n\x11\x66orce_start_slave\x18\x03 \x01(\x08\"\x13\n\x11SetMasterResponse\"A\n\x18SlaveWasRestartedRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"\x1b\n\x19SlaveWasRestartedResponse\"$\n\"StopReplicationAndGetStatusRequest\"N\n#StopReplicationAndGetStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x15\n\x13PromoteSlaveRequest\"(\n\x14PromoteSlaveResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"$\n\rBackupRequest\x12\x13\n\x0b\x63oncurrency\x18\x01 \x01(\x03\"/\n\x0e\x42\x61\x63kupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.Event\"\x1a\n\x18RestoreFromBackupRequest\":\n\x19RestoreFromBackupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.EventB0Z.vitess.io/vitess/go/vt/proto/tabletmanagerdatab\x06proto3') + serialized_pb=_b('\n\x17tabletmanagerdata.proto\x12\x11tabletmanagerdata\x1a\x0bquery.proto\x1a\x0etopodata.proto\x1a\x15replicationdata.proto\x1a\rlogutil.proto\"\x93\x01\n\x0fTableDefinition\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0e\n\x06schema\x18\x02 \x01(\t\x12\x0f\n\x07\x63olumns\x18\x03 \x03(\t\x12\x1b\n\x13primary_key_columns\x18\x04 \x03(\t\x12\x0c\n\x04type\x18\x05 \x01(\t\x12\x13\n\x0b\x64\x61ta_length\x18\x06 \x01(\x04\x12\x11\n\trow_count\x18\x07 \x01(\x04\"{\n\x10SchemaDefinition\x12\x17\n\x0f\x64\x61tabase_schema\x18\x01 \x01(\t\x12=\n\x11table_definitions\x18\x02 \x03(\x0b\x32\".tabletmanagerdata.TableDefinition\x12\x0f\n\x07version\x18\x03 \x01(\t\"\x8b\x01\n\x12SchemaChangeResult\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\xc1\x01\n\x0eUserPermission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\x0c\n\x04user\x18\x02 \x01(\t\x12\x19\n\x11password_checksum\x18\x03 \x01(\x04\x12\x45\n\nprivileges\x18\x04 \x03(\x0b\x32\x31.tabletmanagerdata.UserPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xae\x01\n\x0c\x44\x62Permission\x12\x0c\n\x04host\x18\x01 \x01(\t\x12\n\n\x02\x64\x62\x18\x02 \x01(\t\x12\x0c\n\x04user\x18\x03 \x01(\t\x12\x43\n\nprivileges\x18\x04 \x03(\x0b\x32/.tabletmanagerdata.DbPermission.PrivilegesEntry\x1a\x31\n\x0fPrivilegesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x83\x01\n\x0bPermissions\x12;\n\x10user_permissions\x18\x01 \x03(\x0b\x32!.tabletmanagerdata.UserPermission\x12\x37\n\x0e\x64\x62_permissions\x18\x02 \x03(\x0b\x32\x1f.tabletmanagerdata.DbPermission\"\x1e\n\x0bPingRequest\x12\x0f\n\x07payload\x18\x01 \x01(\t\"\x1f\n\x0cPingResponse\x12\x0f\n\x07payload\x18\x01 \x01(\t\" \n\x0cSleepRequest\x12\x10\n\x08\x64uration\x18\x01 \x01(\x03\"\x0f\n\rSleepResponse\"\xaf\x01\n\x12\x45xecuteHookRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x12\n\nparameters\x18\x02 \x03(\t\x12\x46\n\textra_env\x18\x03 \x03(\x0b\x32\x33.tabletmanagerdata.ExecuteHookRequest.ExtraEnvEntry\x1a/\n\rExtraEnvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"J\n\x13\x45xecuteHookResponse\x12\x13\n\x0b\x65xit_status\x18\x01 \x01(\x03\x12\x0e\n\x06stdout\x18\x02 \x01(\t\x12\x0e\n\x06stderr\x18\x03 \x01(\t\"Q\n\x10GetSchemaRequest\x12\x0e\n\x06tables\x18\x01 \x03(\t\x12\x15\n\rinclude_views\x18\x02 \x01(\x08\x12\x16\n\x0e\x65xclude_tables\x18\x03 \x03(\t\"S\n\x11GetSchemaResponse\x12>\n\x11schema_definition\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x17\n\x15GetPermissionsRequest\"M\n\x16GetPermissionsResponse\x12\x33\n\x0bpermissions\x18\x01 \x01(\x0b\x32\x1e.tabletmanagerdata.Permissions\"\x14\n\x12SetReadOnlyRequest\"\x15\n\x13SetReadOnlyResponse\"\x15\n\x13SetReadWriteRequest\"\x16\n\x14SetReadWriteResponse\">\n\x11\x43hangeTypeRequest\x12)\n\x0btablet_type\x18\x01 \x01(\x0e\x32\x14.topodata.TabletType\"\x14\n\x12\x43hangeTypeResponse\"\x15\n\x13RefreshStateRequest\"\x16\n\x14RefreshStateResponse\"\x17\n\x15RunHealthCheckRequest\"\x18\n\x16RunHealthCheckResponse\"+\n\x18IgnoreHealthErrorRequest\x12\x0f\n\x07pattern\x18\x01 \x01(\t\"\x1b\n\x19IgnoreHealthErrorResponse\",\n\x13ReloadSchemaRequest\x12\x15\n\rwait_position\x18\x01 \x01(\t\"\x16\n\x14ReloadSchemaResponse\")\n\x16PreflightSchemaRequest\x12\x0f\n\x07\x63hanges\x18\x01 \x03(\t\"X\n\x17PreflightSchemaResponse\x12=\n\x0e\x63hange_results\x18\x01 \x03(\x0b\x32%.tabletmanagerdata.SchemaChangeResult\"\xc2\x01\n\x12\x41pplySchemaRequest\x12\x0b\n\x03sql\x18\x01 \x01(\t\x12\r\n\x05\x66orce\x18\x02 \x01(\x08\x12\x19\n\x11\x61llow_replication\x18\x03 \x01(\x08\x12:\n\rbefore_schema\x18\x04 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x05 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x8c\x01\n\x13\x41pplySchemaResponse\x12:\n\rbefore_schema\x18\x01 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\x12\x39\n\x0c\x61\x66ter_schema\x18\x02 \x01(\x0b\x32#.tabletmanagerdata.SchemaDefinition\"\x13\n\x11LockTablesRequest\"\x14\n\x12LockTablesResponse\"\x15\n\x13UnlockTablesRequest\"\x16\n\x14UnlockTablesResponse\"|\n\x18\x45xecuteFetchAsDbaRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x17\n\x0f\x64isable_binlogs\x18\x04 \x01(\x08\x12\x15\n\rreload_schema\x18\x05 \x01(\x08\"?\n\x19\x45xecuteFetchAsDbaResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"h\n\x1d\x45xecuteFetchAsAllPrivsRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x0f\n\x07\x64\x62_name\x18\x02 \x01(\t\x12\x10\n\x08max_rows\x18\x03 \x01(\x04\x12\x15\n\rreload_schema\x18\x04 \x01(\x08\"D\n\x1e\x45xecuteFetchAsAllPrivsResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\";\n\x18\x45xecuteFetchAsAppRequest\x12\r\n\x05query\x18\x01 \x01(\x0c\x12\x10\n\x08max_rows\x18\x02 \x01(\x04\"?\n\x19\x45xecuteFetchAsAppResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"\x14\n\x12SlaveStatusRequest\">\n\x13SlaveStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x17\n\x15MasterPositionRequest\"*\n\x16MasterPositionResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x12\n\x10StopSlaveRequest\"\x13\n\x11StopSlaveResponse\"A\n\x17StopSlaveMinimumRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\",\n\x18StopSlaveMinimumResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x13\n\x11StartSlaveRequest\"\x14\n\x12StartSlaveResponse\"E\n\x1bStartSlaveUntilAfterRequest\x12\x10\n\x08position\x18\x01 \x01(\t\x12\x14\n\x0cwait_timeout\x18\x02 \x01(\x03\"\x1e\n\x1cStartSlaveUntilAfterResponse\"8\n!TabletExternallyReparentedRequest\x12\x13\n\x0b\x65xternal_id\x18\x01 \x01(\t\"$\n\"TabletExternallyReparentedResponse\" \n\x1eTabletExternallyElectedRequest\"!\n\x1fTabletExternallyElectedResponse\"\x12\n\x10GetSlavesRequest\"\"\n\x11GetSlavesResponse\x12\r\n\x05\x61\x64\x64rs\x18\x01 \x03(\t\"\x19\n\x17ResetReplicationRequest\"\x1a\n\x18ResetReplicationResponse\"(\n\x17VReplicationExecRequest\x12\r\n\x05query\x18\x01 \x01(\t\">\n\x18VReplicationExecResponse\x12\"\n\x06result\x18\x01 \x01(\x0b\x32\x12.query.QueryResult\"=\n\x1dVReplicationWaitForPosRequest\x12\n\n\x02id\x18\x01 \x01(\x03\x12\x10\n\x08position\x18\x02 \x01(\t\" \n\x1eVReplicationWaitForPosResponse\"\x13\n\x11InitMasterRequest\"&\n\x12InitMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x99\x01\n\x1ePopulateReparentJournalRequest\x12\x17\n\x0ftime_created_ns\x18\x01 \x01(\x03\x12\x13\n\x0b\x61\x63tion_name\x18\x02 \x01(\t\x12+\n\x0cmaster_alias\x18\x03 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x04 \x01(\t\"!\n\x1fPopulateReparentJournalResponse\"p\n\x10InitSlaveRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x1c\n\x14replication_position\x18\x02 \x01(\t\x12\x17\n\x0ftime_created_ns\x18\x03 \x01(\x03\"\x13\n\x11InitSlaveResponse\"\x15\n\x13\x44\x65moteMasterRequest\"(\n\x14\x44\x65moteMasterResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17UndoDemoteMasterRequest\"\x1a\n\x18UndoDemoteMasterResponse\"3\n\x1fPromoteSlaveWhenCaughtUpRequest\x12\x10\n\x08position\x18\x01 \x01(\t\"4\n PromoteSlaveWhenCaughtUpResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"\x19\n\x17SlaveWasPromotedRequest\"\x1a\n\x18SlaveWasPromotedResponse\"m\n\x10SetMasterRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\x12\x17\n\x0ftime_created_ns\x18\x02 \x01(\x03\x12\x19\n\x11\x66orce_start_slave\x18\x03 \x01(\x08\"\x13\n\x11SetMasterResponse\"A\n\x18SlaveWasRestartedRequest\x12%\n\x06parent\x18\x01 \x01(\x0b\x32\x15.topodata.TabletAlias\"\x1b\n\x19SlaveWasRestartedResponse\"$\n\"StopReplicationAndGetStatusRequest\"N\n#StopReplicationAndGetStatusResponse\x12\'\n\x06status\x18\x01 \x01(\x0b\x32\x17.replicationdata.Status\"\x15\n\x13PromoteSlaveRequest\"(\n\x14PromoteSlaveResponse\x12\x10\n\x08position\x18\x01 \x01(\t\"9\n\rBackupRequest\x12\x13\n\x0b\x63oncurrency\x18\x01 \x01(\x03\x12\x13\n\x0b\x61llowMaster\x18\x02 \x01(\x08\"/\n\x0e\x42\x61\x63kupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.Event\"\x1a\n\x18RestoreFromBackupRequest\":\n\x19RestoreFromBackupResponse\x12\x1d\n\x05\x65vent\x18\x01 \x01(\x0b\x32\x0e.logutil.EventB0Z.vitess.io/vitess/go/vt/proto/tabletmanagerdatab\x06proto3') , dependencies=[query__pb2.DESCRIPTOR,topodata__pb2.DESCRIPTOR,replicationdata__pb2.DESCRIPTOR,logutil__pb2.DESCRIPTOR,]) @@ -2959,6 +2959,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='allowMaster', full_name='tabletmanagerdata.BackupRequest.allowMaster', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), ], extensions=[ ], @@ -2972,7 +2979,7 @@ oneofs=[ ], serialized_start=5169, - serialized_end=5205, + serialized_end=5226, ) @@ -3002,8 +3009,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5207, - serialized_end=5254, + serialized_start=5228, + serialized_end=5275, ) @@ -3026,8 +3033,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5256, - serialized_end=5282, + serialized_start=5277, + serialized_end=5303, ) @@ -3057,8 +3064,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5284, - serialized_end=5342, + serialized_start=5305, + serialized_end=5363, ) _SCHEMADEFINITION.fields_by_name['table_definitions'].message_type = _TABLEDEFINITION diff --git a/test/backup.py b/test/backup.py index 4e75d8e1561..7ba5b03990a 100755 --- a/test/backup.py +++ b/test/backup.py @@ -257,6 +257,61 @@ def test_backup_rdonly(self): def test_backup_replica(self): self._test_backup('replica') + def test_backup_master(self): + """Test backup flow. + + test_backup will: + - create a shard with master and replica1 only + - run InitShardMaster + - insert some data + - take a backup on master + - insert more data on the master + - bring up tablet_replica2 after the fact, let it restore the backup + - check all data is right (before+after backup data) + - list the backup, remove it + + """ + # insert data on master, wait for slave to get it + tablet_master.mquery('vt_test_keyspace', self._create_vt_insert_test) + self._insert_data(tablet_master, 1) + self._check_data(tablet_replica1, 1, 'replica1 tablet getting data') + + # backup the master + utils.run_vtctl(['Backup', '-allow_master=true', tablet_master.tablet_alias], auto_log=True) + + # check that the backup shows up in the listing + backups = self._list_backups() + logging.debug('list of backups: %s', backups) + self.assertEqual(len(backups), 1) + self.assertTrue(backups[0].endswith(tablet_master.tablet_alias)) + + # insert more data on the master + self._insert_data(tablet_master, 2) + + # now bring up the other slave, letting it restore from backup. + self._restore(tablet_replica2, tablet_type='replica') + + # check the new slave has the data + self._check_data(tablet_replica2, 2, 'replica2 tablet getting data') + + # check that the restored slave has the right local_metadata + result = tablet_replica2.mquery('_vt', 'select * from local_metadata') + metadata = {} + for row in result: + metadata[row[0]] = row[1] + self.assertEqual(metadata['Alias'], 'test_nj-0000062346') + self.assertEqual(metadata['ClusterAlias'], 'test_keyspace.0') + self.assertEqual(metadata['DataCenter'], 'test_nj') + self.assertEqual(metadata['PromotionRule'], 'neutral') + + # remove the backup and check that the list is empty + self._remove_backup(backups[0]) + backups = self._list_backups() + logging.debug('list of backups after remove: %s', backups) + self.assertEqual(len(backups), 0) + + tablet_replica2.kill_vttablet() + def _test_backup(self, tablet_type): """Test backup flow. From 66eebaca8e5859394c4acecbb376b532f5201240 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 16:39:39 -0800 Subject: [PATCH 134/196] add failure case to test Signed-off-by: deepthi --- go/vt/vtctl/backup.go | 1 + go/vt/vttablet/tabletmanager/rpc_backup.go | 4 ++-- test/backup.py | 9 +++++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/go/vt/vtctl/backup.go b/go/vt/vtctl/backup.go index e22917bbfcb..6af8f8a896f 100644 --- a/go/vt/vtctl/backup.go +++ b/go/vt/vtctl/backup.go @@ -127,6 +127,7 @@ func commandBackupShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl } } + // if no other tablet is available and allowMaster is set to true if tabletForBackup == nil && *allowMaster { for i := range tablets { switch tablets[i].Type { diff --git a/go/vt/vttablet/tabletmanager/rpc_backup.go b/go/vt/vttablet/tabletmanager/rpc_backup.go index bd52eeedaeb..fd9b4480979 100644 --- a/go/vt/vttablet/tabletmanager/rpc_backup.go +++ b/go/vt/vttablet/tabletmanager/rpc_backup.go @@ -46,7 +46,7 @@ func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger lo // It is not safe to take backups from tablet in this state currentTablet := agent.Tablet() if !allowMaster && currentTablet.Type == topodatapb.TabletType_MASTER { - return fmt.Errorf("type MASTER cannot take backup, if you really need to do this, rerun the backup command with -allow_master") + return fmt.Errorf("type MASTER cannot take backup. if you really need to do this, rerun the backup command with -allow_master") } tablet, err := agent.TopoServer.GetTablet(ctx, agent.TabletAlias) @@ -54,7 +54,7 @@ func (agent *ActionAgent) Backup(ctx context.Context, concurrency int, logger lo return err } if !allowMaster && tablet.Type == topodatapb.TabletType_MASTER { - return fmt.Errorf("type MASTER cannot take backup, if you really need to do this, rerun the backup command with -allow_master") + return fmt.Errorf("type MASTER cannot take backup. if you really need to do this, rerun the backup command with -allow_master") } originalType := tablet.Type diff --git a/test/backup.py b/test/backup.py index 7ba5b03990a..99c3cc55cfa 100755 --- a/test/backup.py +++ b/test/backup.py @@ -276,6 +276,15 @@ def test_backup_master(self): self._insert_data(tablet_master, 1) self._check_data(tablet_replica1, 1, 'replica1 tablet getting data') + # This will fail, make sure we get the right error. + _, err = utils.run_vtctl(['Backup', tablet_master.tablet_alias], + auto_log=True, expect_fail=True) + self.assertIn('type MASTER cannot take backup. if you really need to do this, rerun the backup command with -allow_master', err) + + # And make sure there is no backup left. + backups = self._list_backups() + self.assertEqual(len(backups), 0, 'invalid backups: %s' % backups) + # backup the master utils.run_vtctl(['Backup', '-allow_master=true', tablet_master.tablet_alias], auto_log=True) From bec54fd6f243f9b73d3d701762bea2c6f17995e9 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Sun, 3 Mar 2019 11:36:03 -0800 Subject: [PATCH 135/196] vplayer: address review comments Signed-off-by: Sugu Sougoumarane --- go/vt/vttablet/tabletmanager/vreplication/relaylog.go | 1 - go/vt/vttablet/tabletmanager/vreplication/vplayer.go | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go/vt/vttablet/tabletmanager/vreplication/relaylog.go b/go/vt/vttablet/tabletmanager/vreplication/relaylog.go index f0714390d2e..489fd8e90c3 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/relaylog.go +++ b/go/vt/vttablet/tabletmanager/vreplication/relaylog.go @@ -38,7 +38,6 @@ type relayLog struct { curSize int items [][]*binlogdatapb.VEvent timedout bool - err error // canAccept is true if: curSize<=maxSize, len(items)0, ctx is not Done, and interuptFetch is false. diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index a181bcf8569..53efc39cdba 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -66,7 +66,7 @@ type vplayer struct { timeLastSaved time.Time // lastTimestampNs is the last timestamp seen so far. lastTimestampNs int64 - // timeOffsetNs keeps track of the time offset w.r.t. source tablet. + // timeOffsetNs keeps track of the clock difference with respect to source tablet. timeOffsetNs int64 stopPos mysql.Position @@ -204,7 +204,8 @@ func (vp *vplayer) applyEvents(ctx context.Context, relay *relayLog) error { if err != nil { return err } - // No events were received. Update SecondsBehindMaster. + // No events were received. This likely means that there's a network partition. + // So, we should assume we're falling behind. if len(items) == 0 { behind := time.Now().UnixNano() - vp.lastTimestampNs - vp.timeOffsetNs vp.stats.SecondsBehindMaster.Set(behind / 1e9) From 8510abf8ea185162fb5589ca6dc80fcfa15c41b5 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Sun, 17 Feb 2019 18:18:20 -0800 Subject: [PATCH 136/196] vreplication: fix row move bug If the target pk for a row changes (row move), then a simple update may not do the right thing, especially for aggregates. In such cases, we should delete and insert. Signed-off-by: Sugu Sougoumarane --- .../tabletmanager/vreplication/player_plan.go | 52 +++++++++++------ .../tabletmanager/vreplication/vplayer.go | 2 +- .../vreplication/vplayer_test.go | 57 ++++++++++++++++++- 3 files changed, 93 insertions(+), 18 deletions(-) diff --git a/go/vt/vttablet/tabletmanager/vreplication/player_plan.go b/go/vt/vttablet/tabletmanager/vreplication/player_plan.go index b0130eba1cb..ab960c90a2b 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/player_plan.go +++ b/go/vt/vttablet/tabletmanager/vreplication/player_plan.go @@ -249,8 +249,8 @@ func (tp *TablePlan) FindCol(name sqlparser.ColIdent) *ColExpr { return nil } -// GenerateStatement must be called only after Fields and PKCols have been populated. -func (tp *TablePlan) GenerateStatement(rowChange *binlogdatapb.RowChange) string { +// GenerateStatements must be called only after Fields and PKCols have been populated. +func (tp *TablePlan) GenerateStatements(rowChange *binlogdatapb.RowChange) []string { // MakeRowTrusted is needed here because Proto3ToResult is not convenient. var before, after []sqltypes.Value if rowChange.Before != nil { @@ -264,13 +264,33 @@ func (tp *TablePlan) GenerateStatement(rowChange *binlogdatapb.RowChange) string case before == nil && after != nil: query = tp.generateInsert(after) case before != nil && after != nil: + pkChanged := false + for _, cExpr := range tp.PKCols { + if !valsEqual(before[cExpr.ColNum], after[cExpr.ColNum]) { + pkChanged = true + break + } + } + if pkChanged { + queries := make([]string, 0, 2) + if query := tp.generateDelete(before); query != "" { + queries = append(queries, query) + } + if query := tp.generateInsert(after); query != "" { + queries = append(queries, query) + } + return queries + } query = tp.generateUpdate(before, after) case before != nil && after == nil: query = tp.generateDelete(before) case before == nil && after == nil: // unreachable } - return query + if query != "" { + return []string{query} + } + return nil } func (tp *TablePlan) generateInsert(after []sqltypes.Value) string { @@ -345,22 +365,10 @@ func (tp *TablePlan) generateUpdateValues(sql *sqlparser.TrackedBuffer, before, if cExpr.Operation == OpCount { continue } - bef := before[cExpr.ColNum] - aft := after[cExpr.ColNum] - // If both are null, there's no change - if bef.IsNull() && aft.IsNull() { - continue - } - // If any one of them is null, something has changed. - if bef.IsNull() || aft.IsNull() { - goto mustSet - } - // Compare content only if none are null. - if bef.ToString() == aft.ToString() { + if valsEqual(before[cExpr.ColNum], after[cExpr.ColNum]) { continue } } - mustSet: sql.Myprintf("%s%v=", separator, cExpr.ColName) separator = ", " hasSet = true @@ -407,3 +415,15 @@ func (tp *TablePlan) generateWhereValues(sql *sqlparser.TrackedBuffer, before [] encodeValue(sql, before[cExpr.ColNum]) } } + +func valsEqual(v1, v2 sqltypes.Value) bool { + if v1.IsNull() && v2.IsNull() { + return true + } + // If any one of them is null, something has changed. + if v1.IsNull() || v2.IsNull() { + return false + } + // Compare content only if none are null. + return v1.ToString() == v2.ToString() +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index 53efc39cdba..5bf9bcafd81 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -446,7 +446,7 @@ func (vp *vplayer) applyRowEvent(ctx context.Context, rowEvent *binlogdatapb.Row return fmt.Errorf("unexpected event on table %s", rowEvent.TableName) } for _, change := range rowEvent.RowChanges { - if query := tplan.GenerateStatement(change); query != "" { + for _, query := range tplan.GenerateStatements(change) { if err := vp.exec(ctx, query); err != nil { return err } diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer_test.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer_test.go index 1996015d82a..3af90ad45f4 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer_test.go @@ -249,7 +249,8 @@ func TestPlayerFilters(t *testing.T) { input: "update nopk set val='bbb' where id=1", output: []string{ "begin", - "update nopk set val='bbb' where id=1 and val='aaa'", + "delete from nopk where id=1 and val='aaa'", + "insert into nopk set id=1, val='bbb'", "/update _vt.vreplication set pos=", "commit", }, @@ -388,6 +389,60 @@ func TestPlayerUpdates(t *testing.T) { } } +func TestPlayerRowMove(t *testing.T) { + defer deleteTablet(addTablet(100, "0", topodatapb.TabletType_REPLICA, true, true)) + + execStatements(t, []string{ + "create table src(id int, val1 int, val2 int, primary key(id))", + fmt.Sprintf("create table %s.dst(val1 int, sval2 int, rcount int, primary key(val1))", vrepldb), + }) + defer execStatements(t, []string{ + "drop table src", + fmt.Sprintf("drop table %s.dst", vrepldb), + }) + env.SchemaEngine.Reload(context.Background()) + + filter := &binlogdatapb.Filter{ + Rules: []*binlogdatapb.Rule{{ + Match: "dst", + Filter: "select val1, sum(val2) as sval2, count(*) as rcount from src group by val1", + }}, + } + cancel, _ := startVReplication(t, filter, binlogdatapb.OnDDLAction_IGNORE, "") + defer cancel() + + execStatements(t, []string{ + "insert into src values(1, 1, 1), (2, 2, 2), (3, 2, 3)", + }) + expectDBClientQueries(t, []string{ + "begin", + "insert into dst set val1=1, sval2=1, rcount=1 on duplicate key update sval2=sval2+1, rcount=rcount+1", + "insert into dst set val1=2, sval2=2, rcount=1 on duplicate key update sval2=sval2+2, rcount=rcount+1", + "insert into dst set val1=2, sval2=3, rcount=1 on duplicate key update sval2=sval2+3, rcount=rcount+1", + "/update _vt.vreplication set pos=", + "commit", + }) + expectData(t, "dst", [][]string{ + {"1", "1", "1"}, + {"2", "5", "2"}, + }) + + execStatements(t, []string{ + "update src set val1=1, val2=4 where id=3", + }) + expectDBClientQueries(t, []string{ + "begin", + "update dst set sval2=sval2-3, rcount=rcount-1 where val1=2", + "insert into dst set val1=1, sval2=4, rcount=1 on duplicate key update sval2=sval2+4, rcount=rcount+1", + "/update _vt.vreplication set pos=", + "commit", + }) + expectData(t, "dst", [][]string{ + {"1", "5", "2"}, + {"2", "2", "1"}, + }) +} + func TestPlayerTypes(t *testing.T) { defer deleteTablet(addTablet(100, "0", topodatapb.TabletType_REPLICA, true, true)) From f6eeeba5797ec8c0309e617a97da695fa6cd8673 Mon Sep 17 00:00:00 2001 From: Dan Kozlowski Date: Mon, 4 Mar 2019 15:35:32 -0800 Subject: [PATCH 137/196] Updating chromedriver dependencies and pinning chromium version There is currently a defect in chromium that causes it to crash, this pins chromium to a previous version Signed-off-by: Dan Kozlowski --- bootstrap.sh | 2 +- docker/bootstrap/Dockerfile.common | 2 +- test/environment.py | 15 ++++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/bootstrap.sh b/bootstrap.sh index 971034fd7c7..d5a24af6550 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -269,7 +269,7 @@ function install_chromedriver() { rm chromedriver_linux64.zip } if [ "$BUILD_TESTS" == 1 ] ; then - install_dep "chromedriver" "2.44" "$VTROOT/dist/chromedriver" install_chromedriver + install_dep "chromedriver" "73.0.3683.20" "$VTROOT/dist/chromedriver" install_chromedriver fi diff --git a/docker/bootstrap/Dockerfile.common b/docker/bootstrap/Dockerfile.common index 86f5ad7e34c..6d96504e03c 100644 --- a/docker/bootstrap/Dockerfile.common +++ b/docker/bootstrap/Dockerfile.common @@ -6,7 +6,7 @@ RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-ins automake \ bison \ bzip2 \ - chromium \ + chromium=70.0.3538.110-1~deb9u1 \ curl \ g++ \ git \ diff --git a/test/environment.py b/test/environment.py index 2d615ddaace..2319597bc07 100644 --- a/test/environment.py +++ b/test/environment.py @@ -42,6 +42,7 @@ from selenium import webdriver from selenium.common.exceptions import WebDriverException +from selenium.webdriver.chrome.options import Options from vttest import mysql_flavor @@ -235,6 +236,13 @@ def reset_mysql_flavor(): def create_webdriver(): """Creates a webdriver object (local or remote for Travis).""" + + # Set common Options + chrome_options = Options() + chrome_options.add_argument("--disable-gpu") + chrome_options.add_argument("--no-sandbox") + chrome_options.headless = True + if os.environ.get('CI') == 'true' and os.environ.get('TRAVIS') == 'true': username = os.environ['SAUCE_USERNAME'] access_key = os.environ['SAUCE_ACCESS_KEY'] @@ -243,17 +251,22 @@ def create_webdriver(): capabilities['build'] = os.environ['TRAVIS_BUILD_NUMBER'] capabilities['platform'] = 'Linux' capabilities['browserName'] = 'chrome' + capabilities['chromeOptions'] = chrome_options hub_url = '%s:%s@localhost:4445' % (username, access_key) driver = webdriver.Remote( desired_capabilities=capabilities, command_executor='http://%s/wd/hub' % hub_url) + else: # Only testing against Chrome for now os.environ['webdriver.chrome.driver'] = os.path.join(vtroot, 'dist') service_log_path = os.path.join(tmproot, 'chromedriver.log') + try: driver = webdriver.Chrome(service_args=['--verbose'], - service_log_path=service_log_path) + service_log_path=service_log_path, + chrome_options=chrome_options + ) except WebDriverException as e: if 'Chrome failed to start' not in str(e): # Not a Chrome issue. Just re-raise the exception. From 2268d5622bcdc6a43355da1a36985ac1d9fed0b7 Mon Sep 17 00:00:00 2001 From: Dan Kozlowski Date: Tue, 5 Mar 2019 10:29:23 -0800 Subject: [PATCH 138/196] Overhaul the Dockerfiles This commit overhauls the dockerfiles, specifically it 1. Converts the lite builds to use a multi-stage build to allow easier automation 2. Adds in new versions of mysql and mariadb 3. Updates the dockerfiles to use the full gpg key hash to provent collisions 4. Updates the make file with new targets Signed-off-by: Dan Kozlowski --- Makefile | 26 +++++++++++- docker/base/Dockerfile.mariadb103 | 13 ++++++ docker/base/Dockerfile.mysql80 | 13 ++++++ docker/base/Dockerfile.percona80 | 12 ++++++ docker/bootstrap/Dockerfile.mariadb | 14 ++++--- docker/bootstrap/Dockerfile.mysql80 | 16 ++++++++ docker/bootstrap/Dockerfile.percona | 2 +- docker/bootstrap/Dockerfile.percona57 | 2 +- docker/bootstrap/Dockerfile.percona80 | 24 +++++++++++ docker/lite/Dockerfile.mariadb | 39 +++++++++++++----- docker/lite/Dockerfile.mariadb103 | 49 ++++++++++++++++++++++ docker/lite/Dockerfile.mysql56 | 36 +++++++++++----- docker/lite/Dockerfile.mysql57 | 52 +++++++++++++++++++++++ docker/lite/Dockerfile.mysql80 | 52 +++++++++++++++++++++++ docker/lite/Dockerfile.percona | 49 ++++++++++++++-------- docker/lite/Dockerfile.percona57 | 51 +++++++++++++++-------- docker/lite/Dockerfile.percona80 | 59 +++++++++++++++++++++++++++ docker/lite/build.sh | 41 +------------------ 18 files changed, 449 insertions(+), 101 deletions(-) create mode 100644 docker/base/Dockerfile.mariadb103 create mode 100644 docker/base/Dockerfile.mysql80 create mode 100644 docker/base/Dockerfile.percona80 create mode 100644 docker/bootstrap/Dockerfile.mysql80 create mode 100644 docker/bootstrap/Dockerfile.percona80 create mode 100644 docker/lite/Dockerfile.mariadb103 create mode 100644 docker/lite/Dockerfile.mysql57 create mode 100644 docker/lite/Dockerfile.mysql80 create mode 100644 docker/lite/Dockerfile.percona80 diff --git a/Makefile b/Makefile index 06446dd88f9..4c3a7b72bed 100644 --- a/Makefile +++ b/Makefile @@ -160,7 +160,7 @@ $(PROTO_GO_OUTS): install_protoc-gen-go proto/*.proto # Please read docker/README.md to understand the different available images. # This rule builds the bootstrap images for all flavors. -DOCKER_IMAGES_FOR_TEST = mariadb mysql56 mysql57 percona percona57 +DOCKER_IMAGES_FOR_TEST = mariadb mariadb103 mysql56 mysql57 mysql80 percona percona57 percona80 DOCKER_IMAGES = common $(DOCKER_IMAGES_FOR_TEST) docker_bootstrap: for i in $(DOCKER_IMAGES); do echo "building bootstrap image: $$i"; docker/bootstrap/build.sh $$i || exit 1; done @@ -184,10 +184,18 @@ docker_base_mysql56: chmod -R o=g * docker build -f docker/base/Dockerfile.mysql56 -t vitess/base:mysql56 . +docker_base_mysql80: + chmod -R o=g * + docker build -f docker/base/Dockerfile.mysql56 -t vitess/base:mysql80 . + docker_base_mariadb: chmod -R o=g * docker build -f docker/base/Dockerfile.mariadb -t vitess/base:mariadb . +docker_base_mariadb103: + chmod -R o=g * + docker build -f docker/base/Dockerfile.mariadb -t vitess/base:mariadb103 . + docker_base_percona: chmod -R o=g * docker build -f docker/base/Dockerfile.percona -t vitess/base:percona . @@ -196,6 +204,10 @@ docker_base_percona57: chmod -R o=g * docker build -f docker/base/Dockerfile.percona57 -t vitess/base:percona57 . +docker_base_percona80: + chmod -R o=g * + docker build -f docker/base/Dockerfile.percona57 -t vitess/base:percona80 . + # Run "make docker_lite PROMPT_NOTICE=false" to avoid that the script # prompts you to press ENTER and confirm that the vitess/base image is not # rebuild by this target as well. @@ -205,15 +217,27 @@ docker_lite: docker_lite_mysql56: cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) mysql56 +docker_lite_mysql57: + cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) mysql57 + +docker_lite_mysql80: + cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) mysql80 + docker_lite_mariadb: cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) mariadb +docker_lite_mariadb103: + cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) mariadb103 + docker_lite_percona: cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) percona docker_lite_percona57: cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) percona57 +docker_lite_percona80: + cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) percona80 + docker_lite_alpine: cd docker/lite && ./build.sh --prompt=$(PROMPT_NOTICE) alpine diff --git a/docker/base/Dockerfile.mariadb103 b/docker/base/Dockerfile.mariadb103 new file mode 100644 index 00000000000..75811dc68ba --- /dev/null +++ b/docker/base/Dockerfile.mariadb103 @@ -0,0 +1,13 @@ +FROM vitess/bootstrap:mariadb103 + +# Re-copy sources from working tree +USER root +COPY . /vt/src/vitess.io/vitess + +# Build Vitess +RUN make build + +# Fix permissions +RUN chown -R vitess:vitess /vt +USER vitess + diff --git a/docker/base/Dockerfile.mysql80 b/docker/base/Dockerfile.mysql80 new file mode 100644 index 00000000000..5b2fc5c91ae --- /dev/null +++ b/docker/base/Dockerfile.mysql80 @@ -0,0 +1,13 @@ +FROM vitess/bootstrap:mysql80 + +# Re-copy sources from working tree +USER root +COPY . /vt/src/vitess.io/vitess + +# Build Vitess +RUN make build + +# Fix permissions +RUN chown -R vitess:vitess /vt +USER vitess + diff --git a/docker/base/Dockerfile.percona80 b/docker/base/Dockerfile.percona80 new file mode 100644 index 00000000000..83672111166 --- /dev/null +++ b/docker/base/Dockerfile.percona80 @@ -0,0 +1,12 @@ +FROM vitess/bootstrap:percona80 + +# Re-copy sources from working tree +USER root +COPY . /vt/src/vitess.io/vitess + +# Fix permissions +RUN chown -R vitess:vitess /vt +USER vitess + +# Build Vitess +RUN make build diff --git a/docker/bootstrap/Dockerfile.mariadb b/docker/bootstrap/Dockerfile.mariadb index bc76702faa9..ca40724c12f 100644 --- a/docker/bootstrap/Dockerfile.mariadb +++ b/docker/bootstrap/Dockerfile.mariadb @@ -1,10 +1,14 @@ FROM vitess/bootstrap:common -# Install MariaDB 10. -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ - mariadb-server \ - libmariadbclient-dev \ - && rm -rf /var/lib/apt/lists/* +# Install MariaDB 10.3 +RUN apt-key adv --no-tty --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8 \ + && echo 'deb http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.3/debian stretch main' > /etc/apt/sources.list.d/mariadb.list \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + bzip2 \ + mariadb-server \ + libmariadbclient-dev \ + && rm -rf /var/lib/apt/lists/* # Bootstrap Vitess WORKDIR /vt/src/vitess.io/vitess diff --git a/docker/bootstrap/Dockerfile.mysql80 b/docker/bootstrap/Dockerfile.mysql80 new file mode 100644 index 00000000000..c82ee741dec --- /dev/null +++ b/docker/bootstrap/Dockerfile.mysql80 @@ -0,0 +1,16 @@ +FROM vitess/bootstrap:common + +# Install MySQL 5.7 +RUN for i in $(seq 1 10); do apt-key adv --no-tty --recv-keys --keyserver ha.pool.sks-keyservers.net 8C718D3B5072E1F5 && break; done && \ + add-apt-repository 'deb http://repo.mysql.com/apt/debian/ stretch mysql-8.0' && \ + apt-get update && \ + DEBIAN_FRONTEND=noninteractive apt-get install -y mysql-server libmysqlclient-dev && \ + rm -rf /var/lib/apt/lists/* + +# Bootstrap Vitess +WORKDIR /vt/src/vitess.io/vitess + + +ENV MYSQL_FLAVOR MySQL56 +USER vitess +RUN ./bootstrap.sh \ No newline at end of file diff --git a/docker/bootstrap/Dockerfile.percona b/docker/bootstrap/Dockerfile.percona index 422dacffb6b..427ab2670c0 100644 --- a/docker/bootstrap/Dockerfile.percona +++ b/docker/bootstrap/Dockerfile.percona @@ -1,7 +1,7 @@ FROM vitess/bootstrap:common # Install Percona 5.6 -RUN for i in $(seq 1 10); do apt-key adv --no-tty --keyserver keys.gnupg.net --recv-keys 8507EFA5 && break; done && \ +RUN for i in $(seq 1 10); do apt-key adv --no-tty --keyserver keys.gnupg.net --recv-keys 9334A25F8507EFA5 && break; done && \ add-apt-repository 'deb http://repo.percona.com/apt stretch main' && \ { \ echo debconf debconf/frontend select Noninteractive; \ diff --git a/docker/bootstrap/Dockerfile.percona57 b/docker/bootstrap/Dockerfile.percona57 index 054e0d3216a..371890d116f 100644 --- a/docker/bootstrap/Dockerfile.percona57 +++ b/docker/bootstrap/Dockerfile.percona57 @@ -1,7 +1,7 @@ FROM vitess/bootstrap:common # Install Percona 5.7 -RUN for i in $(seq 1 10); do apt-key adv --no-tty --keyserver keys.gnupg.net --recv-keys 8507EFA5 && break; done && \ +RUN for i in $(seq 1 10); do apt-key adv --no-tty --keyserver keys.gnupg.net --recv-keys 9334A25F8507EFA5 && break; done && \ add-apt-repository 'deb http://repo.percona.com/apt stretch main' && \ { \ echo debconf debconf/frontend select Noninteractive; \ diff --git a/docker/bootstrap/Dockerfile.percona80 b/docker/bootstrap/Dockerfile.percona80 new file mode 100644 index 00000000000..246c6519843 --- /dev/null +++ b/docker/bootstrap/Dockerfile.percona80 @@ -0,0 +1,24 @@ +FROM vitess/bootstrap:common + +# Install Percona 8.0 +RUN for i in $(seq 1 10); do apt-key adv --no-tty --keyserver keys.gnupg.net --recv-keys 9334A25F8507EFA5 && break; done && + && echo 'deb http://repo.percona.com/ps-80/apt stretch main' > /etc/apt/sources.list.d/percona.list && \ + { \ + echo debconf debconf/frontend select Noninteractive; \ + echo percona-server-server-8.0 percona-server-server/root_password password 'unused'; \ + echo percona-server-server-8.0 percona-server-server/root_password_again password 'unused'; \ + } | debconf-set-selections \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + percona-server-server \ + libperconaserverclient21 \ + percona-server-tokudb \ + percona-server-rocksdb \ + bzip2 + +# Bootstrap Vitess +WORKDIR /vt/src/vitess.io/vitess + +ENV MYSQL_FLAVOR MySQL56 +USER vitess +RUN ./bootstrap.sh diff --git a/docker/lite/Dockerfile.mariadb b/docker/lite/Dockerfile.mariadb index 7df86adb0e0..5c947ab804c 100644 --- a/docker/lite/Dockerfile.mariadb +++ b/docker/lite/Dockerfile.mariadb @@ -1,14 +1,35 @@ -# This image is only meant to be built from within the build.sh script. -FROM debian:jessie +FROM vitess/base AS builder +FROM debian:stretch-slim AS staging + +RUN mkdir -p /vt/vtdataroot/ \ + && mkdir -p /vt/bin \ + && mkdir -p /vt/src/vitess.io/vitess/web/vtctld2 \ + && groupadd -r vitess && useradd -r -g vitess vitess + +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld /vt/src/vitess.io/vitess/web/vtctld +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld2/app /vt/src/vitess.io/vitess/web/vtctld2/app +COPY --from=builder /vt/src/vitess.io/vitess/config /vt/config +COPY --from=builder /vt/bin/mysqlctld /vt/bin/ +COPY --from=builder /vt/bin/vtctld /vt/bin/ +COPY --from=builder /vt/bin/vtctlclient /vt/bin/ +COPY --from=builder /vt/bin/vtgate /vt/bin/ +COPY --from=builder /vt/bin/vttablet /vt/bin/ +COPY --from=builder /vt/bin/vtworker /vt/bin/ + +RUN chown -R vitess:vitess /vt + +FROM debian:stretch-slim # Install dependencies -RUN apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xcbcb082a1bb943db \ - && echo 'deb http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.0/debian jessie main' > /etc/apt/sources.list.d/mariadb.list \ +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gnupg dirmngr ca-certificates \ + && apt-key adv --no-tty --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8 \ + && echo 'deb http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.2/debian stretch main' > /etc/apt/sources.list.d/mariadb.list \ && apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ bzip2 \ mariadb-server \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r vitess && useradd -r -g vitess vitess # Set up Vitess environment (just enough to run pre-built Go binaries) ENV VTTOP /vt/src/vitess.io/vitess @@ -22,12 +43,8 @@ ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib # Copy binaries (placed by build.sh) -COPY lite/vt /vt - -# Create vitess user -RUN groupadd -r vitess && useradd -r -g vitess vitess && \ - mkdir -p /vt/vtdataroot && chown -R vitess:vitess /vt +COPY --from=staging /vt/ /vt/ # Create mount point for actual data (e.g. MySQL data dir) VOLUME /vt/vtdataroot -USER vitess \ No newline at end of file +USER vitess diff --git a/docker/lite/Dockerfile.mariadb103 b/docker/lite/Dockerfile.mariadb103 new file mode 100644 index 00000000000..2290a77fbc9 --- /dev/null +++ b/docker/lite/Dockerfile.mariadb103 @@ -0,0 +1,49 @@ +FROM vitess/base AS builder +FROM debian:stretch-slim AS staging + +RUN mkdir -p /vt/vtdataroot/ \ + && mkdir -p /vt/bin \ + && mkdir -p /vt/src/vitess.io/vitess/web/vtctld2 \ + && groupadd -r vitess && useradd -r -g vitess vitess + +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld /vt/src/vitess.io/vitess/web/vtctld +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld2/app /vt/src/vitess.io/vitess/web/vtctld2/app +COPY --from=builder /vt/src/vitess.io/vitess/config /vt/config +COPY --from=builder /vt/bin/mysqlctld /vt/bin/ +COPY --from=builder /vt/bin/vtctld /vt/bin/ +COPY --from=builder /vt/bin/vtctlclient /vt/bin/ +COPY --from=builder /vt/bin/vtgate /vt/bin/ +COPY --from=builder /vt/bin/vttablet /vt/bin/ +COPY --from=builder /vt/bin/vtworker /vt/bin/ +RUN chown -R vitess:vitess /vt + +FROM debian:stretch-slim + +# Install dependencies +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gnupg dirmngr ca-certificates \ + && apt-key adv --no-tty --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8 \ + && echo 'deb http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.3/debian stretch main' > /etc/apt/sources.list.d/mariadb.list \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + bzip2 \ + mariadb-server \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r vitess && useradd -r -g vitess vitess + +# Set up Vitess environment (just enough to run pre-built Go binaries) +ENV VTTOP /vt/src/vitess.io/vitess +ENV VTROOT /vt +ENV GOTOP $VTTOP/go +ENV VTDATAROOT $VTROOT/vtdataroot +ENV GOBIN $VTROOT/bin +ENV GOPATH $VTROOT +ENV PATH $VTROOT/bin:$PATH +ENV VT_MYSQL_ROOT /usr +ENV PKG_CONFIG_PATH $VTROOT/lib + +# Copy binaries (placed by build.sh) +COPY --from=staging /vt/ /vt/ + +# Create mount point for actual data (e.g. MySQL data dir) +VOLUME /vt/vtdataroot +USER vitess diff --git a/docker/lite/Dockerfile.mysql56 b/docker/lite/Dockerfile.mysql56 index 79e5381f909..89432bccc59 100644 --- a/docker/lite/Dockerfile.mysql56 +++ b/docker/lite/Dockerfile.mysql56 @@ -1,9 +1,28 @@ -# This image is only meant to be built from within the build.sh script. -FROM debian:jessie +FROM vitess/base AS builder +FROM debian:stretch-slim AS staging + +RUN mkdir -p /vt/vtdataroot/ \ + && mkdir -p /vt/bin \ + && mkdir -p /vt/src/vitess.io/vitess/web/vtctld2 \ + && groupadd -r vitess && useradd -r -g vitess vitess + +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld /vt/src/vitess.io/vitess/web/vtctld +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld2/app /vt/src/vitess.io/vitess/web/vtctld2/app +COPY --from=builder /vt/src/vitess.io/vitess/config /vt/config +COPY --from=builder /vt/bin/mysqlctld /vt/bin/ +COPY --from=builder /vt/bin/vtctld /vt/bin/ +COPY --from=builder /vt/bin/vtctlclient /vt/bin/ +COPY --from=builder /vt/bin/vtgate /vt/bin/ +COPY --from=builder /vt/bin/vttablet /vt/bin/ +COPY --from=builder /vt/bin/vtworker /vt/bin/ + +RUN chown -R vitess:vitess /vt + +FROM debian:stretch-slim # Install dependencies -RUN apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 5072E1F5 \ - && echo 'deb http://repo.mysql.com/apt/debian/ jessie mysql-5.6' > /etc/apt/sources.list.d/mysql.list \ +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gnupg dirmngr ca-certificates && apt-key adv --no-tty --recv-keys --keyserver keyserver.ubuntu.com 8C718D3B5072E1F5 \ + && echo 'deb http://repo.mysql.com/apt/debian/ stretch mysql-5.6' > /etc/apt/sources.list.d/mysql.list \ && apt-get update \ && DEBIAN_FRONTEND=noninteractive \ apt-get install -y --no-install-recommends \ @@ -11,7 +30,8 @@ RUN apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 5072E1F5 \ libmysqlclient18 \ mysql-client \ mysql-server \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r vitess && useradd -r -g vitess vitess # Set up Vitess environment (just enough to run pre-built Go binaries) ENV VTTOP /vt/src/vitess.io/vitess @@ -25,11 +45,7 @@ ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib # Copy binaries (placed by build.sh) -COPY lite/vt /vt - -# Create vitess user -RUN groupadd -r vitess && useradd -r -g vitess vitess && \ - mkdir -p /vt/vtdataroot && chown -R vitess:vitess /vt +COPY --from=staging /vt/ /vt/ # Create mount point for actual data (e.g. MySQL data dir) VOLUME /vt/vtdataroot diff --git a/docker/lite/Dockerfile.mysql57 b/docker/lite/Dockerfile.mysql57 new file mode 100644 index 00000000000..5d442d2e5ca --- /dev/null +++ b/docker/lite/Dockerfile.mysql57 @@ -0,0 +1,52 @@ +FROM vitess/base AS builder +FROM debian:stretch-slim AS staging + +RUN mkdir -p /vt/vtdataroot/ \ + && mkdir -p /vt/bin \ + && mkdir -p /vt/src/vitess.io/vitess/web/vtctld2 \ + && groupadd -r vitess && useradd -r -g vitess vitess + +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld /vt/src/vitess.io/vitess/web/vtctld +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld2/app /vt/src/vitess.io/vitess/web/vtctld2/app +COPY --from=builder /vt/src/vitess.io/vitess/config /vt/config +COPY --from=builder /vt/bin/mysqlctld /vt/bin/ +COPY --from=builder /vt/bin/vtctld /vt/bin/ +COPY --from=builder /vt/bin/vtctlclient /vt/bin/ +COPY --from=builder /vt/bin/vtgate /vt/bin/ +COPY --from=builder /vt/bin/vttablet /vt/bin/ +COPY --from=builder /vt/bin/vtworker /vt/bin/ + +RUN chown -R vitess:vitess /vt + +FROM debian:stretch-slim + +# Install dependencies +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gnupg dirmngr ca-certificates && apt-key adv --no-tty --recv-keys --keyserver keyserver.ubuntu.com 8C718D3B5072E1F5 \ + && echo 'deb http://repo.mysql.com/apt/debian/ stretch mysql-5.7' > /etc/apt/sources.list.d/mysql.list \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive \ + apt-get install -y --no-install-recommends \ + bzip2 \ + libmysqlclient20 \ + mysql-client \ + mysql-server \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r vitess && useradd -r -g vitess vitess + +# Set up Vitess environment (just enough to run pre-built Go binaries) +ENV VTTOP /vt/src/vitess.io/vitess +ENV VTROOT /vt +ENV GOTOP $VTTOP/go +ENV VTDATAROOT $VTROOT/vtdataroot +ENV GOBIN $VTROOT/bin +ENV GOPATH $VTROOT +ENV PATH $VTROOT/bin:$PATH +ENV VT_MYSQL_ROOT /usr +ENV PKG_CONFIG_PATH $VTROOT/lib + +# Copy binaries (placed by build.sh) +COPY --from=staging /vt/ /vt/ + +# Create mount point for actual data (e.g. MySQL data dir) +VOLUME /vt/vtdataroot +USER vitess \ No newline at end of file diff --git a/docker/lite/Dockerfile.mysql80 b/docker/lite/Dockerfile.mysql80 new file mode 100644 index 00000000000..4dc5f40f2d0 --- /dev/null +++ b/docker/lite/Dockerfile.mysql80 @@ -0,0 +1,52 @@ +FROM vitess/base AS builder +FROM debian:stretch-slim AS staging + +RUN mkdir -p /vt/vtdataroot/ \ + && mkdir -p /vt/bin \ + && mkdir -p /vt/src/vitess.io/vitess/web/vtctld2 \ + && groupadd -r vitess && useradd -r -g vitess vitess + +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld /vt/src/vitess.io/vitess/web/vtctld +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld2/app /vt/src/vitess.io/vitess/web/vtctld2/app +COPY --from=builder /vt/src/vitess.io/vitess/config /vt/config +COPY --from=builder /vt/bin/mysqlctld /vt/bin/ +COPY --from=builder /vt/bin/vtctld /vt/bin/ +COPY --from=builder /vt/bin/vtctlclient /vt/bin/ +COPY --from=builder /vt/bin/vtgate /vt/bin/ +COPY --from=builder /vt/bin/vttablet /vt/bin/ +COPY --from=builder /vt/bin/vtworker /vt/bin/ + +RUN chown -R vitess:vitess /vt + +FROM debian:stretch-slim + +# Install dependencies +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gnupg dirmngr ca-certificates && apt-key adv --no-tty --recv-keys --keyserver keyserver.ubuntu.com 8C718D3B5072E1F5 \ + && echo 'deb http://repo.mysql.com/apt/debian/ stretch mysql-8.0' > /etc/apt/sources.list.d/mysql.list \ + && apt-get update \ + && DEBIAN_FRONTEND=noninteractive \ + apt-get install -y --no-install-recommends \ + bzip2 \ + libmysqlclient21 \ + mysql-client \ + mysql-server \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r vitess && useradd -r -g vitess vitess + +# Set up Vitess environment (just enough to run pre-built Go binaries) +ENV VTTOP /vt/src/vitess.io/vitess +ENV VTROOT /vt +ENV GOTOP $VTTOP/go +ENV VTDATAROOT $VTROOT/vtdataroot +ENV GOBIN $VTROOT/bin +ENV GOPATH $VTROOT +ENV PATH $VTROOT/bin:$PATH +ENV VT_MYSQL_ROOT /usr +ENV PKG_CONFIG_PATH $VTROOT/lib + +# Copy binaries (placed by build.sh) +COPY --from=staging /vt/ /vt/ + +# Create mount point for actual data (e.g. MySQL data dir) +VOLUME /vt/vtdataroot +USER vitess \ No newline at end of file diff --git a/docker/lite/Dockerfile.percona b/docker/lite/Dockerfile.percona index 47a7430b825..c27944b637e 100644 --- a/docker/lite/Dockerfile.percona +++ b/docker/lite/Dockerfile.percona @@ -1,19 +1,40 @@ -# This image is only meant to be built from within the build.sh script. -FROM debian:jessie +FROM vitess/base AS builder +FROM debian:stretch-slim AS staging + +RUN mkdir -p /vt/vtdataroot/ \ + && mkdir -p /vt/bin \ + && mkdir -p /vt/src/vitess.io/vitess/web/vtctld2 \ + && groupadd -r vitess && useradd -r -g vitess vitess + +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld /vt/src/vitess.io/vitess/web/vtctld +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld2/app /vt/src/vitess.io/vitess/web/vtctld2/app +COPY --from=builder /vt/src/vitess.io/vitess/config /vt/config +COPY --from=builder /vt/bin/mysqlctld /vt/bin/ +COPY --from=builder /vt/bin/vtctld /vt/bin/ +COPY --from=builder /vt/bin/vtctlclient /vt/bin/ +COPY --from=builder /vt/bin/vtgate /vt/bin/ +COPY --from=builder /vt/bin/vttablet /vt/bin/ +COPY --from=builder /vt/bin/vtworker /vt/bin/ + +RUN chown -R vitess:vitess /vt + +FROM debian:stretch-slim # Install dependencies -RUN apt-key adv --keyserver keys.gnupg.net \ - --recv-keys 8507EFA5 && \ - echo 'deb http://repo.percona.com/apt jessie main' > /etc/apt/sources.list.d/mysql.list && \ +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gnupg dirmngr ca-certificates \ + && apt-key adv --no-tty --recv-keys --keyserver keys.gnupg.net 9334A25F8507EFA5 \ + && echo 'deb http://repo.percona.com/apt stretch main' > /etc/apt/sources.list.d/percona.list && \ { \ echo debconf debconf/frontend select Noninteractive; \ echo percona-server-server-5.6 percona-server-server/root_password password 'unused'; \ echo percona-server-server-5.6 percona-server-server/root_password_again password 'unused'; \ - } | debconf-set-selections && \ - apt-get update && \ - apt-get install -y --no-install-recommends \ - percona-server-server-5.6 bzip2 && \ - rm -rf /var/lib/apt/lists/* + } | debconf-set-selections \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + percona-server-server-5.6 \ + bzip2 \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r vitess && useradd -r -g vitess vitess # Set up Vitess environment (just enough to run pre-built Go binaries) ENV VTTOP /vt/src/vitess.io/vitess @@ -27,12 +48,8 @@ ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib # Copy binaries (placed by build.sh) -COPY lite/vt /vt - -# Create vitess user -RUN groupadd -r vitess && useradd -r -g vitess vitess && \ - mkdir -p /vt/vtdataroot && chown -R vitess:vitess /vt +COPY --from=staging /vt/ /vt/ # Create mount point for actual data (e.g. MySQL data dir) VOLUME /vt/vtdataroot -USER vitess \ No newline at end of file +USER vitess diff --git a/docker/lite/Dockerfile.percona57 b/docker/lite/Dockerfile.percona57 index 1b824cec101..def68853c31 100644 --- a/docker/lite/Dockerfile.percona57 +++ b/docker/lite/Dockerfile.percona57 @@ -1,19 +1,41 @@ -# This image is only meant to be built from within the build.sh script. -FROM debian:jessie +FROM vitess/base AS builder +FROM debian:stretch-slim AS staging + +RUN mkdir -p /vt/vtdataroot/ \ + && mkdir -p /vt/bin \ + && mkdir -p /vt/src/vitess.io/vitess/web/vtctld2 \ + && groupadd -r vitess && useradd -r -g vitess vitess + +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld /vt/src/vitess.io/vitess/web/vtctld +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld2/app /vt/src/vitess.io/vitess/web/vtctld2/app +COPY --from=builder /vt/src/vitess.io/vitess/config /vt/config +COPY --from=builder /vt/bin/mysqlctld /vt/bin/ +COPY --from=builder /vt/bin/vtctld /vt/bin/ +COPY --from=builder /vt/bin/vtctlclient /vt/bin/ +COPY --from=builder /vt/bin/vtgate /vt/bin/ +COPY --from=builder /vt/bin/vttablet /vt/bin/ +COPY --from=builder /vt/bin/vtworker /vt/bin/ + +RUN chown -R vitess:vitess /vt + +FROM debian:stretch-slim # Install dependencies -RUN apt-key adv --keyserver keys.gnupg.net \ - --recv-keys 8507EFA5 && \ - echo 'deb http://repo.percona.com/apt jessie main' > /etc/apt/sources.list.d/mysql.list && \ +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gnupg dirmngr ca-certificates \ + && apt-key adv --no-tty --recv-keys --keyserver keys.gnupg.net 9334A25F8507EFA5 \ + && echo 'deb http://repo.percona.com/apt stretch main' > /etc/apt/sources.list.d/percona.list && \ { \ echo debconf debconf/frontend select Noninteractive; \ echo percona-server-server-5.7 percona-server-server/root_password password 'unused'; \ echo percona-server-server-5.7 percona-server-server/root_password_again password 'unused'; \ - } | debconf-set-selections && \ - apt-get update && \ - apt-get install -y --no-install-recommends \ - percona-server-server-5.7 libperconaserverclient18.1 bzip2 && \ - rm -rf /var/lib/apt/lists/* + } | debconf-set-selections \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + percona-server-server-5.7 \ + libperconaserverclient20 \ + bzip2 \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r vitess && useradd -r -g vitess vitess # Set up Vitess environment (just enough to run pre-built Go binaries) ENV VTTOP /vt/src/vitess.io/vitess @@ -26,13 +48,10 @@ ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib -# Copy binaries (placed by build.sh) -COPY lite/vt /vt -# Create vitess user -RUN groupadd -r vitess && useradd -r -g vitess vitess && \ - mkdir -p /vt/vtdataroot && chown -R vitess:vitess /vt +# Copy binaries (placed by build.sh) +COPY --from=staging /vt/ /vt/ # Create mount point for actual data (e.g. MySQL data dir) VOLUME /vt/vtdataroot -USER vitess \ No newline at end of file +USER vitess diff --git a/docker/lite/Dockerfile.percona80 b/docker/lite/Dockerfile.percona80 new file mode 100644 index 00000000000..658b52c4902 --- /dev/null +++ b/docker/lite/Dockerfile.percona80 @@ -0,0 +1,59 @@ +FROM vitess/base AS builder +FROM debian:stretch-slim AS staging + +RUN mkdir -p /vt/vtdataroot/ \ + && mkdir -p /vt/bin \ + && mkdir -p /vt/src/vitess.io/vitess/web/vtctld2 \ + && groupadd -r vitess && useradd -r -g vitess vitess + +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld /vt/src/vitess.io/vitess/web/vtctld +COPY --from=builder /vt/src/vitess.io/vitess/web/vtctld2/app /vt/src/vitess.io/vitess/web/vtctld2/app +COPY --from=builder /vt/src/vitess.io/vitess/config /vt/config +COPY --from=builder /vt/bin/mysqlctld /vt/bin/ +COPY --from=builder /vt/bin/vtctld /vt/bin/ +COPY --from=builder /vt/bin/vtctlclient /vt/bin/ +COPY --from=builder /vt/bin/vtgate /vt/bin/ +COPY --from=builder /vt/bin/vttablet /vt/bin/ +COPY --from=builder /vt/bin/vtworker /vt/bin/ + +RUN chown -R vitess:vitess /vt + +FROM debian:stretch-slim + +# Install dependencies +RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends gnupg dirmngr ca-certificates \ + && apt-key adv --no-tty --recv-keys --keyserver keys.gnupg.net 9334A25F8507EFA5 \ + && echo 'deb http://repo.percona.com/ps-80/apt stretch main' > /etc/apt/sources.list.d/percona.list && \ + { \ + echo debconf debconf/frontend select Noninteractive; \ + echo percona-server-server-8.0 percona-server-server/root_password password 'unused'; \ + echo percona-server-server-8.0 percona-server-server/root_password_again password 'unused'; \ + } | debconf-set-selections \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + percona-server-server \ + libperconaserverclient21 \ + percona-server-tokudb \ + percona-server-rocksdb \ + bzip2 \ + && rm -rf /var/lib/apt/lists/* \ + && groupadd -r vitess && useradd -r -g vitess vitess + +# Set up Vitess environment (just enough to run pre-built Go binaries) +ENV VTTOP /vt/src/vitess.io/vitess +ENV VTROOT /vt +ENV GOTOP $VTTOP/go +ENV VTDATAROOT $VTROOT/vtdataroot +ENV GOBIN $VTROOT/bin +ENV GOPATH $VTROOT +ENV PATH $VTROOT/bin:$PATH +ENV VT_MYSQL_ROOT /usr +ENV PKG_CONFIG_PATH $VTROOT/lib + + +# Copy binaries (placed by build.sh) +COPY --from=staging /vt/ /vt/ + +# Create mount point for actual data (e.g. MySQL data dir) +VOLUME /vt/vtdataroot +USER vitess diff --git a/docker/lite/build.sh b/docker/lite/build.sh index 66f61ec3e6d..700412f6faf 100755 --- a/docker/lite/build.sh +++ b/docker/lite/build.sh @@ -29,15 +29,12 @@ if [[ "$1" == "--prompt"* ]]; then fi flavor=$1 - base_image=vitess/base -make_target=docker_base lite_image=vitess/lite dockerfile=Dockerfile tag=latest + if [[ -n "$flavor" ]]; then - base_image=vitess/base:$flavor - make_target=docker_base_$flavor lite_image=vitess/lite:$flavor dockerfile=Dockerfile.$flavor tag=$flavor @@ -71,40 +68,4 @@ END read fi -# cleanup both temporary folders when exiting, even in case of errors -function cleanup { - rm -rf $PWD/base $PWD/lite -} -trap cleanup EXIT - -# Extract files from vitess/base image -mkdir base -# Ignore permission errors. They occur for directories we do not care e.g. ".git". -# (Copying them fails because they are owned by root and not $UID and have stricter permissions.) -docker run --rm -v $PWD/base:/base -u $UID $base_image bash -c 'cp -R /vt /base/ 2>&1 | grep -v "Permission denied"' || true - -# Grab only what we need -lite=$PWD/lite -vttop=vt/src/vitess.io/vitess -mkdir -p $lite/vt/vtdataroot - -mkdir -p $lite/vt/bin -(cd base/vt/bin; cp mysqlctld vtctld vtctlclient vtgate vttablet vtworker $lite/vt/bin/) - -mkdir -p $lite/$vttop/web -cp -R base/$vttop/web/vtctld $lite/$vttop/web/ -mkdir $lite/$vttop/web/vtctld2 -cp -R base/$vttop/web/vtctld2/app $lite/$vttop/web/vtctld2/ - -mkdir -p $lite/$vttop/config -cp -R base/$vttop/config/* $lite/$vttop/config/ -ln -s /$vttop/config $lite/vt/config - -# remove the base folder now -- not needed for the final build -rm -rf $PWD/base - -# Fix permissions for AUFS workaround -chmod -R o=g lite - -# Build vitess/lite image docker build --no-cache -f $dockerfile -t $lite_image . From b3674f2233d1c25fee65c5b314774bea31f78be3 Mon Sep 17 00:00:00 2001 From: Dan Kozlowski Date: Tue, 5 Mar 2019 11:02:16 -0800 Subject: [PATCH 139/196] Additional changes to explicitly state flavor Signed-off-by: Dan Kozlowski --- docker/bootstrap/Dockerfile.mariadb | 6 ++---- docker/bootstrap/Dockerfile.mariadb103 | 16 ++++++++++++++++ docker/lite/Dockerfile.mariadb | 1 + docker/lite/Dockerfile.mariadb103 | 1 + docker/lite/Dockerfile.mysql56 | 1 + docker/lite/Dockerfile.mysql57 | 1 + docker/lite/Dockerfile.mysql80 | 1 + docker/lite/Dockerfile.percona | 1 + docker/lite/Dockerfile.percona57 | 2 +- docker/lite/Dockerfile.percona80 | 2 +- 10 files changed, 26 insertions(+), 6 deletions(-) create mode 100644 docker/bootstrap/Dockerfile.mariadb103 diff --git a/docker/bootstrap/Dockerfile.mariadb b/docker/bootstrap/Dockerfile.mariadb index ca40724c12f..83dfdff8b74 100644 --- a/docker/bootstrap/Dockerfile.mariadb +++ b/docker/bootstrap/Dockerfile.mariadb @@ -1,9 +1,7 @@ FROM vitess/bootstrap:common -# Install MariaDB 10.3 -RUN apt-key adv --no-tty --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8 \ - && echo 'deb http://sfo1.mirrors.digitalocean.com/mariadb/repo/10.3/debian stretch main' > /etc/apt/sources.list.d/mariadb.list \ - && apt-get update \ +# Install MariaDB 10 +RUN apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ bzip2 \ mariadb-server \ diff --git a/docker/bootstrap/Dockerfile.mariadb103 b/docker/bootstrap/Dockerfile.mariadb103 new file mode 100644 index 00000000000..e626cf4f2e6 --- /dev/null +++ b/docker/bootstrap/Dockerfile.mariadb103 @@ -0,0 +1,16 @@ +FROM vitess/bootstrap:common + +# Install MariaDB 10. +RUN apt-key adv --recv-keys --keyserver keyserver.ubuntu.com 0xF1656F24C74CD1D8 &&\ + add-apt-repository 'deb [arch=amd64] http://ftp.osuosl.org/pub/mariadb/repo/10.3/debian stretch main' + apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ + mariadb-server \ + libmariadbclient-dev \ + && rm -rf /var/lib/apt/lists/* + +# Bootstrap Vitess +WORKDIR /vt/src/vitess.io/vitess + +ENV MYSQL_FLAVOR MariaDB103 +USER vitess +RUN ./bootstrap.sh diff --git a/docker/lite/Dockerfile.mariadb b/docker/lite/Dockerfile.mariadb index 5c947ab804c..d25e274c46c 100644 --- a/docker/lite/Dockerfile.mariadb +++ b/docker/lite/Dockerfile.mariadb @@ -41,6 +41,7 @@ ENV GOPATH $VTROOT ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib +ENV MYSQL_FLAVOR MariaDB # Copy binaries (placed by build.sh) COPY --from=staging /vt/ /vt/ diff --git a/docker/lite/Dockerfile.mariadb103 b/docker/lite/Dockerfile.mariadb103 index 2290a77fbc9..e01e394813f 100644 --- a/docker/lite/Dockerfile.mariadb103 +++ b/docker/lite/Dockerfile.mariadb103 @@ -40,6 +40,7 @@ ENV GOPATH $VTROOT ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib +ENV MYSQL_FLAVOR MariaDB103 # Copy binaries (placed by build.sh) COPY --from=staging /vt/ /vt/ diff --git a/docker/lite/Dockerfile.mysql56 b/docker/lite/Dockerfile.mysql56 index 89432bccc59..a005a21cb46 100644 --- a/docker/lite/Dockerfile.mysql56 +++ b/docker/lite/Dockerfile.mysql56 @@ -43,6 +43,7 @@ ENV GOPATH $VTROOT ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib +ENV MYSQL_FLAVOR MySQL56 # Copy binaries (placed by build.sh) COPY --from=staging /vt/ /vt/ diff --git a/docker/lite/Dockerfile.mysql57 b/docker/lite/Dockerfile.mysql57 index 5d442d2e5ca..ebfdb21d5c4 100644 --- a/docker/lite/Dockerfile.mysql57 +++ b/docker/lite/Dockerfile.mysql57 @@ -43,6 +43,7 @@ ENV GOPATH $VTROOT ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib +ENV MYSQL_FLAVOR MySQL56 # Copy binaries (placed by build.sh) COPY --from=staging /vt/ /vt/ diff --git a/docker/lite/Dockerfile.mysql80 b/docker/lite/Dockerfile.mysql80 index 4dc5f40f2d0..1b98aae565f 100644 --- a/docker/lite/Dockerfile.mysql80 +++ b/docker/lite/Dockerfile.mysql80 @@ -43,6 +43,7 @@ ENV GOPATH $VTROOT ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib +ENV MYSQL_FLAVOR MySQL56 # Copy binaries (placed by build.sh) COPY --from=staging /vt/ /vt/ diff --git a/docker/lite/Dockerfile.percona b/docker/lite/Dockerfile.percona index c27944b637e..5dd69b7b2cc 100644 --- a/docker/lite/Dockerfile.percona +++ b/docker/lite/Dockerfile.percona @@ -46,6 +46,7 @@ ENV GOPATH $VTROOT ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib +ENV MYSQL_FLAVOR MySQL56 # Copy binaries (placed by build.sh) COPY --from=staging /vt/ /vt/ diff --git a/docker/lite/Dockerfile.percona57 b/docker/lite/Dockerfile.percona57 index def68853c31..3dc21bcf573 100644 --- a/docker/lite/Dockerfile.percona57 +++ b/docker/lite/Dockerfile.percona57 @@ -47,7 +47,7 @@ ENV GOPATH $VTROOT ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib - +ENV MYSQL_FLAVOR MySQL56 # Copy binaries (placed by build.sh) COPY --from=staging /vt/ /vt/ diff --git a/docker/lite/Dockerfile.percona80 b/docker/lite/Dockerfile.percona80 index 658b52c4902..b48b8db5c99 100644 --- a/docker/lite/Dockerfile.percona80 +++ b/docker/lite/Dockerfile.percona80 @@ -49,7 +49,7 @@ ENV GOPATH $VTROOT ENV PATH $VTROOT/bin:$PATH ENV VT_MYSQL_ROOT /usr ENV PKG_CONFIG_PATH $VTROOT/lib - +ENV MYSQL_FLAVOR MySQL56 # Copy binaries (placed by build.sh) COPY --from=staging /vt/ /vt/ From 7eac276e813abc5f22374f9c5616d72c770d48dc Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Tue, 5 Mar 2019 15:25:53 -0800 Subject: [PATCH 140/196] Add tests to srv_keyspace Signed-off-by: Rafael Chacon --- go/vt/topo/cell_info.go | 3 +- go/vt/topo/srv_keyspace.go | 103 ++++++- go/vt/topo/topotests/srv_keyspace_test.go | 346 ++++++++++++++++++++++ 3 files changed, 449 insertions(+), 3 deletions(-) diff --git a/go/vt/topo/cell_info.go b/go/vt/topo/cell_info.go index 0906dba8960..a207ad5c2ce 100644 --- a/go/vt/topo/cell_info.go +++ b/go/vt/topo/cell_info.go @@ -140,8 +140,7 @@ func (ts *Server) DeleteCellInfo(ctx context.Context, cell string) error { switch { case err == nil: if len(srvKeyspaces) != 0 { - // TODO @rafael - implement this function and expose it via a vtctld command - return fmt.Errorf("cell %v has serving keyspaces. Before deleting, delete serving keyspace with: DeleteSrvKeyspaces", cell) + return fmt.Errorf("cell %v has serving keyspaces. Before deleting, delete keyspace with: DeleteKeyspace", cell) } case IsErrType(err, NoNode): // Nothing to do. diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index 46a22783bc3..0250bf4b478 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -233,7 +233,7 @@ func (ts *Server) GetShardServingTypes(ctx context.Context, si *ShardInfo) (serv return servingTypes, nil } -// RemoveShardServingKeyspace ... +// RemoveShardServingKeyspace ... (Should I REMOVE ???) func (ts *Server) RemoveShardServingKeyspace(ctx context.Context, si *ShardInfo, cells []string) (err error) { if err = CheckKeyspaceLocked(ctx, si.keyspace); err != nil { return err @@ -295,6 +295,107 @@ func (ts *Server) RemoveShardServingKeyspace(ctx context.Context, si *ShardInfo, return nil } +// UpdateSrvKeyspacePartitions will make sure the disableQueryService is +// set appropriately in tablet controls in srvKeyspace. +func (ts *Server) UpdateSrvKeyspacePartitions(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string, remove bool) (err error) { + if err = CheckKeyspaceLocked(ctx, keyspace); err != nil { + return err + } + + // The caller intents to update all cells in this case + if len(cells) == 0 { + cells, err = ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + } + + wg := sync.WaitGroup{} + rec := concurrency.AllErrorRecorder{} + for _, cell := range cells { + wg.Add(1) + go func(cell string) { + defer wg.Done() + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + switch { + case err == nil: + partitionFound := false + + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } + partitionFound = true + + for _, si := range shards { + found := false + for _, shardReference := range partition.GetShardReferences() { + if key.KeyRangeEqual(shardReference.GetKeyRange(), si.GetKeyRange()) { + found = true + } + } + + if !found && !remove { + shardReference := &topodatapb.ShardReference{ + Name: si.ShardName(), + KeyRange: si.KeyRange, + } + partition.ShardReferences = append(partition.GetShardReferences(), shardReference) + } + + if found && remove { + shardReferences := make([]*topodatapb.ShardReference, 0) + for _, shardReference := range partition.GetShardReferences() { + if !key.KeyRangeEqual(shardReference.GetKeyRange(), si.GetKeyRange()) { + shardReferences = append(shardReferences, shardReference) + } + } + partition.ShardReferences = shardReferences + } + } + } + + // Partition does not exist at all, we need to create it + if !partitionFound && !remove { + + partition := &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: tabletType, + } + + shardReferences := make([]*topodatapb.ShardReference, 0) + for _, si := range shards { + shardReference := &topodatapb.ShardReference{ + Name: si.ShardName(), + KeyRange: si.KeyRange, + } + shardReferences = append(shardReferences, shardReference) + } + + partition.ShardReferences = shardReferences + + srvKeyspace.Partitions = append(srvKeyspace.GetPartitions(), partition) + } + + err = ts.UpdateSrvKeyspace(ctx, cell, keyspace, srvKeyspace) + if err != nil { + rec.RecordError(err) + return + } + case IsErrType(err, NoNode): + // NOOP + default: + rec.RecordError(err) + return + } + }(cell) + } + wg.Wait() + if rec.HasErrors() { + return NewError(PartialResult, rec.Error().Error()) + } + return nil +} + // UpdateDisableQueryService will make sure the disableQueryService is // set appropriately in tablet controls in srvKeyspace. func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string, disableQueryService bool) (err error) { diff --git a/go/vt/topo/topotests/srv_keyspace_test.go b/go/vt/topo/topotests/srv_keyspace_test.go index 8cf43d0c4b3..057f300eb57 100644 --- a/go/vt/topo/topotests/srv_keyspace_test.go +++ b/go/vt/topo/topotests/srv_keyspace_test.go @@ -24,6 +24,8 @@ import ( "golang.org/x/net/context" "github.com/golang/protobuf/proto" + "vitess.io/vitess/go/json2" + "vitess.io/vitess/go/vt/key" "vitess.io/vitess/go/vt/topo" "vitess.io/vitess/go/vt/topo/memorytopo" @@ -236,3 +238,347 @@ func TestWatchSrvKeyspaceCancel(t *testing.T) { // Cancel should still work here, although it does nothing. cancel() } + +func TestUpdateSrvKeyspacePartitions(t *testing.T) { + cell := "cell1" + cell2 := "cell2" + keyspace := "ks1" + ctx := context.Background() + ts := memorytopo.NewServer(cell, cell2) + + keyRange, err := key.ParseShardingSpec("-") + if err != nil || len(keyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(keyRange)) + } + // Create initial value + initial := &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: keyRange[0], + }, + }, + }, + }, + } + + if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + ks := &topodatapb.Keyspace{} + if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { + t.Fatalf("CreateKeyspace() failed: %v", err) + } + + leftKeyRange, err := key.ParseShardingSpec("-80") + if err != nil || len(leftKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) + } + + rightKeyRange, err := key.ParseShardingSpec("80-") + if err != nil || len(leftKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) + } + + wantSrvKeyspace := &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: keyRange[0], + }, + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + }, + } + + shards := []*topo.ShardInfo{ + topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil), + topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil), + } + + ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests") + if err != nil { + t.Fatalf("LockKeyspace() failed: %v", err) + } + defer unlock(&err) + + if err := ts.UpdateSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_MASTER, []string{cell}, false /* remove */); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err := json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err := json2.MarshalPB(wantSrvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + } + + // removing works + wantSrvKeyspace = &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: keyRange[0], + }, + }, + }, + }, + } + + if err = ts.UpdateSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_MASTER, []string{cell}, true /* remove */); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err = json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err = json2.MarshalPB(wantSrvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + } + + // You can add to partitions that do not exist + wantSrvKeyspace = &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: keyRange[0], + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_REPLICA, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + }, + } + + if err = ts.UpdateSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, []string{cell}, false /* remove */); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err = json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err = json2.MarshalPB(wantSrvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + } + + // it works in multiple cells + + if err = ts.UpdateSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, nil, false /* remove */); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err = json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err = json2.MarshalPB(wantSrvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + } + + // Now let's get the srvKeyspace in cell2. Partition should have been added there too. + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + } + +} + +func TestUpdateUpdateDisableQueryService(t *testing.T) { + cell := "cell1" + cell2 := "cell2" + keyspace := "ks1" + ctx := context.Background() + ts := memorytopo.NewServer(cell, cell2) + + leftKeyRange, err := key.ParseShardingSpec("-80") + if err != nil || len(leftKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) + } + + rightKeyRange, err := key.ParseShardingSpec("80-") + if err != nil || len(rightKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) + } + // Create initial value + initial := &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + }, + } + + if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + ks := &topodatapb.Keyspace{} + if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { + t.Fatalf("CreateKeyspace() failed: %v", err) + } + + wantSrvKeyspace := &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + ShardTabletControls: []*topodatapb.ShardTabletControl{ + &topodatapb.ShardTabletControl{ + Name: "-80", + KeyRange: leftKeyRange[0], + QueryServiceDisabled: true, + }, + &topodatapb.ShardTabletControl{ + Name: "80-", + KeyRange: rightKeyRange[0], + QueryServiceDisabled: true, + }, + }, + }, + }, + } + + shards := []*topo.ShardInfo{ + topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil), + topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil), + } + + ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests") + if err != nil { + t.Fatalf("LockKeyspace() failed: %v", err) + } + defer unlock(&err) + + if err := ts.UpdateDisableQueryService(ctx, keyspace, shards, topodatapb.TabletType_MASTER, []string{cell}, true /* disableQueryService */); err != nil { + t.Fatalf("UpdateDisableQueryService() failed: %v", err) + } + + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err := json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err := json2.MarshalPB(wantSrvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want)) + } +} From 075666ba02667571a8f601d76fbd1afb0253299b Mon Sep 17 00:00:00 2001 From: Michael Hebelka Date: Wed, 6 Mar 2019 14:13:45 -0500 Subject: [PATCH 141/196] Strictly check the structure of mysql static auth json config Signed-off-by: Michael Hebelka --- go/cmd/vtaclcheck/vtaclcheck.go | 15 ++++++------- go/mysql/auth_server_static.go | 21 ++++++++++-------- go/mysql/auth_server_static_test.go | 8 +++++++ go/vt/vtaclcheck/vtaclcheck.go | 33 ++++++++++++++++++----------- 4 files changed, 48 insertions(+), 29 deletions(-) diff --git a/go/cmd/vtaclcheck/vtaclcheck.go b/go/cmd/vtaclcheck/vtaclcheck.go index 0705fa7d9ff..6ef80fc8bdb 100644 --- a/go/cmd/vtaclcheck/vtaclcheck.go +++ b/go/cmd/vtaclcheck/vtaclcheck.go @@ -28,11 +28,13 @@ import ( ) var ( - aclFileFlag = flag.String("acl_file", "", "Identifies the JSON ACL file to check") + aclFileFlag = flag.String("acl_file", "", "The path of the JSON ACL file to check") + staticAuthFileFlag = flag.String("static_auth_file", "", "The path of the auth_server_static JSON file to check") // vtaclcheckFlags lists all the flags that should show in usage vtaclcheckFlags = []string{ "acl_file", + "static_auth_file", } ) @@ -41,7 +43,7 @@ func usage() { for _, name := range vtaclcheckFlags { f := flag.Lookup(name) if f == nil { - panic("unkown flag " + name) + panic("unknown flag " + name) } flagUsage(f) } @@ -93,15 +95,12 @@ func main() { } func parseAndRun() error { - if aclFileFlag == nil { - return fmt.Errorf("-acl_file option not provided") - } - opts := &vtaclcheck.Options{ - ACLFile: *aclFileFlag, + ACLFile: *aclFileFlag, + StaticAuthFile: *staticAuthFileFlag, } - log.V(100).Infof("acl_file %s\n", *aclFileFlag) + log.V(100).Infof("acl_file %s\nstatic_auth_file %s\n", *aclFileFlag, *staticAuthFileFlag) if err := vtaclcheck.Init(opts); err != nil { return err diff --git a/go/mysql/auth_server_static.go b/go/mysql/auth_server_static.go index f4c068f9662..164fb9b251c 100644 --- a/go/mysql/auth_server_static.go +++ b/go/mysql/auth_server_static.go @@ -156,7 +156,9 @@ func (a *AuthServerStatic) installSignalHandlers() { } func parseConfig(jsonConfig []byte, config *map[string][]*AuthServerStaticEntry) error { - if err := json.Unmarshal(jsonConfig, config); err != nil { + decoder := json.NewDecoder(bytes.NewReader(jsonConfig)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(config); err != nil { // Couldn't parse, will try to parse with legacy config return parseLegacyConfig(jsonConfig, config) } @@ -166,15 +168,16 @@ func parseConfig(jsonConfig []byte, config *map[string][]*AuthServerStaticEntry) func parseLegacyConfig(jsonConfig []byte, config *map[string][]*AuthServerStaticEntry) error { // legacy config doesn't have an array legacyConfig := make(map[string]*AuthServerStaticEntry) - err := json.Unmarshal(jsonConfig, &legacyConfig) - if err == nil { - log.Warningf("Config parsed using legacy configuration. Please update to the latest format: {\"user\":[{\"Password\": \"xxx\"}, ...]}") - for key, value := range legacyConfig { - (*config)[key] = append((*config)[key], value) - } - return nil + decoder := json.NewDecoder(bytes.NewReader(jsonConfig)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&legacyConfig); err != nil { + return err + } + log.Warningf("Config parsed using legacy configuration. Please update to the latest format: {\"user\":[{\"Password\": \"xxx\"}, ...]}") + for key, value := range legacyConfig { + (*config)[key] = append((*config)[key], value) } - return err + return nil } func validateConfig(config map[string][]*AuthServerStaticEntry) error { diff --git a/go/mysql/auth_server_static_test.go b/go/mysql/auth_server_static_test.go index ef4e9bd47b9..0a664640a08 100644 --- a/go/mysql/auth_server_static_test.go +++ b/go/mysql/auth_server_static_test.go @@ -62,6 +62,14 @@ func TestJsonConfigParser(t *testing.T) { if len(config["mysql_user"][2].Groups) != 1 || config["mysql_user"][2].Groups[0] != "user_group" { t.Fatalf("Groups should be equal to [\"user_group\"]") } + + jsonConfig = `{ + "mysql_user": [{"Password": "123", "UserData": "mysql_user_all", "InvalidKey": "oops"}] + }` + err = parseConfig([]byte(jsonConfig), &config) + if err == nil { + t.Fatalf("Invalid config should have errored, but didn't") + } } func TestValidateHashGetter(t *testing.T) { diff --git a/go/vt/vtaclcheck/vtaclcheck.go b/go/vt/vtaclcheck/vtaclcheck.go index d0d1026c8a1..5fd8510f3c4 100644 --- a/go/vt/vtaclcheck/vtaclcheck.go +++ b/go/vt/vtaclcheck/vtaclcheck.go @@ -22,6 +22,7 @@ package vtaclcheck import ( "fmt" + "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/vt/tableacl" "vitess.io/vitess/go/vt/tableacl/simpleacl" ) @@ -30,6 +31,8 @@ import ( type Options struct { // AclFile is the file with the JSON acl configuration ACLFile string + // StaticAuthFile is the file containing the mysql auth_server_static JSON + StaticAuthFile string } var options *Options @@ -41,8 +44,8 @@ func Init(opts *Options) error { return fmt.Errorf("vtaclcheck.Init: opts is NULL") } // Verify options - if len(opts.ACLFile) == 0 { - return fmt.Errorf("-acl_file provided but len(filename) is zero") + if opts.ACLFile == "" && opts.StaticAuthFile == "" { + return fmt.Errorf("No options specified") } options = opts @@ -52,18 +55,24 @@ func Init(opts *Options) error { // Run the check on the given file func Run() error { - filename := options.ACLFile - - tableacl.Register("simpleacl", &simpleacl.Factory{}) - err := tableacl.Init( - filename, - func() {}, - ) - if err != nil { - return fmt.Errorf("Fail to initialize Table ACL: %v", err) + if options.ACLFile != "" { + tableacl.Register("simpleacl", &simpleacl.Factory{}) + err := tableacl.Init( + options.ACLFile, + func() {}, + ) + if err != nil { + return fmt.Errorf("Fail to initialize Table ACL: %v", err) + } + + fmt.Printf("JSON ACL file %s looks good\n", options.ACLFile) } - fmt.Printf("JSON ACL file %s looks good\n", filename) + if options.StaticAuthFile != "" { + mysql.RegisterAuthServerStaticFromParams(options.StaticAuthFile, "") + + fmt.Printf("Static auth file %s looks good\n", options.StaticAuthFile) + } return nil } From d0903f47a91a191ebfaab6920b125c95517424d8 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Wed, 6 Mar 2019 16:21:17 -0800 Subject: [PATCH 142/196] Add more tests. Deprecated method in favor of a more generic one. Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 64 ------- go/vt/topo/topotests/srv_keyspace_test.go | 207 +++++++++++++++++++++- go/vt/wrangler/shard.go | 9 +- 3 files changed, 206 insertions(+), 74 deletions(-) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index 0250bf4b478..206abe61807 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -196,8 +196,6 @@ func (ts *Server) GetShardServingTypes(ctx context.Context, si *ShardInfo) (serv mu.Lock() defer mu.Unlock() for _, partition := range srvKeyspace.GetPartitions() { - // Check that served types hasn't been added already - // TODO MAKE SURE TO ADD TO TEST FOR THIS partitionAlreadyAdded := false for _, servingType := range servingTypes { if servingType == partition.ServedType { @@ -233,68 +231,6 @@ func (ts *Server) GetShardServingTypes(ctx context.Context, si *ShardInfo) (serv return servingTypes, nil } -// RemoveShardServingKeyspace ... (Should I REMOVE ???) -func (ts *Server) RemoveShardServingKeyspace(ctx context.Context, si *ShardInfo, cells []string) (err error) { - if err = CheckKeyspaceLocked(ctx, si.keyspace); err != nil { - return err - } - - // The caller intents to update all cells in this case - if len(cells) == 0 { - cells, err = ts.GetCellInfoNames(ctx) - if err != nil { - return err - } - } - - wg := sync.WaitGroup{} - rec := concurrency.AllErrorRecorder{} - for _, cell := range cells { - wg.Add(1) - go func(cell, keyspace string) { - defer wg.Done() - srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) - switch { - case err == nil: - shardReferences := make([]*topodatapb.ShardReference, 0) - for _, partition := range srvKeyspace.GetPartitions() { - - for _, shardReference := range partition.ShardReferences { - if shardReference.GetName() != si.ShardName() { - shardReferences = append(shardReferences, shardReference) - } - } - } - - if err := OrderAndCheckPartitions(cell, srvKeyspace); err != nil { - rec.RecordError(err) - return - } - - err = ts.UpdateSrvKeyspace(ctx, cell, si.keyspace, srvKeyspace) - if err != nil { - rec.RecordError(err) - return - } - case IsErrType(err, NoNode): - // NOOP - default: - rec.RecordError(err) - return - } - if err != nil { - rec.RecordError(err) - return - } - }(cell, si.Keyspace()) - } - wg.Wait() - if rec.HasErrors() { - return NewError(PartialResult, rec.Error().Error()) - } - return nil -} - // UpdateSrvKeyspacePartitions will make sure the disableQueryService is // set appropriately in tablet controls in srvKeyspace. func (ts *Server) UpdateSrvKeyspacePartitions(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string, remove bool) (err error) { diff --git a/go/vt/topo/topotests/srv_keyspace_test.go b/go/vt/topo/topotests/srv_keyspace_test.go index 057f300eb57..4d11989f532 100644 --- a/go/vt/topo/topotests/srv_keyspace_test.go +++ b/go/vt/topo/topotests/srv_keyspace_test.go @@ -17,6 +17,7 @@ limitations under the License. package topotests import ( + "reflect" "strings" "testing" "time" @@ -288,7 +289,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) } - wantSrvKeyspace := &topodatapb.SrvKeyspace{ + targetKs := &topodatapb.SrvKeyspace{ Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ &topodatapb.SrvKeyspace_KeyspacePartition{ ServedType: topodatapb.TabletType_MASTER, @@ -335,7 +336,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { t.Fatalf("MarshalPB() failed: %v", err) } - want, err := json2.MarshalPB(wantSrvKeyspace) + want, err := json2.MarshalPB(targetKs) if err != nil { t.Fatalf("MarshalPB() failed: %v", err) } @@ -345,7 +346,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { } // removing works - wantSrvKeyspace = &topodatapb.SrvKeyspace{ + targetKs = &topodatapb.SrvKeyspace{ Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ &topodatapb.SrvKeyspace_KeyspacePartition{ ServedType: topodatapb.TabletType_MASTER, @@ -373,7 +374,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { t.Fatalf("MarshalPB() failed: %v", err) } - want, err = json2.MarshalPB(wantSrvKeyspace) + want, err = json2.MarshalPB(targetKs) if err != nil { t.Fatalf("MarshalPB() failed: %v", err) } @@ -383,7 +384,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { } // You can add to partitions that do not exist - wantSrvKeyspace = &topodatapb.SrvKeyspace{ + targetKs = &topodatapb.SrvKeyspace{ Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ &topodatapb.SrvKeyspace_KeyspacePartition{ ServedType: topodatapb.TabletType_MASTER, @@ -424,7 +425,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { t.Fatalf("MarshalPB() failed: %v", err) } - want, err = json2.MarshalPB(wantSrvKeyspace) + want, err = json2.MarshalPB(targetKs) if err != nil { t.Fatalf("MarshalPB() failed: %v", err) } @@ -449,7 +450,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { t.Fatalf("MarshalPB() failed: %v", err) } - want, err = json2.MarshalPB(wantSrvKeyspace) + want, err = json2.MarshalPB(targetKs) if err != nil { t.Fatalf("MarshalPB() failed: %v", err) } @@ -518,7 +519,7 @@ func TestUpdateUpdateDisableQueryService(t *testing.T) { t.Fatalf("CreateKeyspace() failed: %v", err) } - wantSrvKeyspace := &topodatapb.SrvKeyspace{ + targetKs := &topodatapb.SrvKeyspace{ Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ &topodatapb.SrvKeyspace_KeyspacePartition{ ServedType: topodatapb.TabletType_MASTER, @@ -573,7 +574,7 @@ func TestUpdateUpdateDisableQueryService(t *testing.T) { t.Fatalf("MarshalPB() failed: %v", err) } - want, err := json2.MarshalPB(wantSrvKeyspace) + want, err := json2.MarshalPB(targetKs) if err != nil { t.Fatalf("MarshalPB() failed: %v", err) } @@ -581,4 +582,192 @@ func TestUpdateUpdateDisableQueryService(t *testing.T) { if string(got) != string(want) { t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want)) } + + // cell2 is untouched + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err = json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err = json2.MarshalPB(initial) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want)) + } + + // You can enable query service + targetKs = &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + ShardTabletControls: []*topodatapb.ShardTabletControl{ + &topodatapb.ShardTabletControl{ + Name: "-80", + KeyRange: leftKeyRange[0], + QueryServiceDisabled: false, + }, + &topodatapb.ShardTabletControl{ + Name: "80-", + KeyRange: rightKeyRange[0], + QueryServiceDisabled: false, + }, + }, + }, + }, + } + + shards = []*topo.ShardInfo{ + topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil), + topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil), + } + + if err := ts.UpdateDisableQueryService(ctx, keyspace, shards, topodatapb.TabletType_MASTER, []string{cell}, false /* disableQueryService */); err != nil { + t.Fatalf("UpdateDisableQueryService() failed: %v", err) + } + + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err = json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err = json2.MarshalPB(targetKs) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("UpdateDisableQueryService() failure. Got %v, want: %v", string(got), string(want)) + } +} + +func TestGetShardServingTypes(t *testing.T) { + cell := "cell1" + cell2 := "cell2" + keyspace := "ks1" + ctx := context.Background() + ts := memorytopo.NewServer(cell, cell2) + + leftKeyRange, err := key.ParseShardingSpec("-80") + if err != nil || len(leftKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) + } + + rightKeyRange, err := key.ParseShardingSpec("80-") + if err != nil || len(rightKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) + } + // Create initial value + initial := &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_REPLICA, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_RDONLY, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + }, + }, + }, + } + + if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + ks := &topodatapb.Keyspace{} + if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { + t.Fatalf("CreateKeyspace() failed: %v", err) + } + + shardInfo := topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil) + + got, err := ts.GetShardServingTypes(ctx, shardInfo) + if err != nil { + t.Fatalf("GetShardServingTypes() failed: %v", err) + } + + want := []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_RDONLY} + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) + } + + shardInfo = topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil) + + got, err = ts.GetShardServingTypes(ctx, shardInfo) + if err != nil { + t.Fatalf("GetShardServingTypes() failed: %v", err) + } + + want = []topodatapb.TabletType{topodatapb.TabletType_MASTER, topodatapb.TabletType_REPLICA} + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) + } + + keyRange, err := key.ParseShardingSpec("-") + + shardInfo = topo.NewShardInfo(keyspace, "-", &topodatapb.Shard{KeyRange: keyRange[0]}, nil) + + got, err = ts.GetShardServingTypes(ctx, shardInfo) + if err != nil { + t.Fatalf("GetShardServingTypes() failed: %v", err) + } + + want = []topodatapb.TabletType{} + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) + } + } diff --git a/go/vt/wrangler/shard.go b/go/vt/wrangler/shard.go index d17de7d5314..4a74eea3d95 100644 --- a/go/vt/wrangler/shard.go +++ b/go/vt/wrangler/shard.go @@ -307,7 +307,14 @@ func (wr *Wrangler) RemoveShardCell(ctx context.Context, keyspace, shard, cell s } defer unlock(&err) - return wr.ts.RemoveShardServingKeyspace(ctx, shardInfo, shardServingCells) + if err = wr.ts.UpdateSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_RDONLY, shardServingCells, true /* remove */); err != nil { + return err + } + + if err = wr.ts.UpdateSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_REPLICA, shardServingCells, true /* remove */); err != nil { + return err + } + return wr.ts.UpdateSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_MASTER, shardServingCells, true /* remove */) } // SourceShardDelete will delete a SourceShard inside a shard, by index. From 42a0d23aa4e6890e9108437e29beec6a20f0ada6 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Wed, 6 Mar 2019 22:08:02 -0800 Subject: [PATCH 143/196] Adds tests for MigrateServedType Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 2 +- go/vt/topo/topotests/srv_keyspace_test.go | 385 ++++++++++++++++++++++ 2 files changed, 386 insertions(+), 1 deletion(-) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index 206abe61807..c842e6dce35 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -421,7 +421,7 @@ func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string return nil } -// MigrateServedType will make sure the disableQueryService is +// MigrateServedType removes/adds shards from srvKeyspace when migrating a served type. func (ts *Server) MigrateServedType(ctx context.Context, keyspace string, shardsToAdd, shardsToRemove []*ShardInfo, tabletType topodatapb.TabletType, cells []string) (err error) { if err = CheckKeyspaceLocked(ctx, keyspace); err != nil { return err diff --git a/go/vt/topo/topotests/srv_keyspace_test.go b/go/vt/topo/topotests/srv_keyspace_test.go index 4d11989f532..14fe1a6f0da 100644 --- a/go/vt/topo/topotests/srv_keyspace_test.go +++ b/go/vt/topo/topotests/srv_keyspace_test.go @@ -769,5 +769,390 @@ func TestGetShardServingTypes(t *testing.T) { if !reflect.DeepEqual(got, want) { t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) } +} + +func TestGetShardServingCells(t *testing.T) { + cell := "cell1" + cell2 := "cell2" + keyspace := "ks1" + ctx := context.Background() + ts := memorytopo.NewServer(cell, cell2) + + leftKeyRange, err := key.ParseShardingSpec("-80") + if err != nil || len(leftKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) + } + + rightKeyRange, err := key.ParseShardingSpec("80-") + if err != nil || len(rightKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) + } + // Create initial value + initial := &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_REPLICA, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_RDONLY, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + }, + }, + }, + } + + shardInfo := topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil) + + got, err := ts.GetShardServingCells(ctx, shardInfo) + if err != nil { + t.Fatalf("GetShardServingTypes() failed: %v", err) + } + + want := []string{} + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetShardServingCells() failure. Got %v, want: %v", got, want) + } + + if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + ks := &topodatapb.Keyspace{} + if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { + t.Fatalf("CreateKeyspace() failed: %v", err) + } + + got, err = ts.GetShardServingCells(ctx, shardInfo) + if err != nil { + t.Fatalf("GetShardServingCells() failed: %v", err) + } + + want = []string{cell} + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetShardServingCells() failure. Got %v, want: %v", got, want) + } + + if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + got, err = ts.GetShardServingCells(ctx, shardInfo) + if err != nil { + t.Fatalf("GetShardServingCells() failed: %v", err) + } + + want = []string{cell2, cell} + + if !reflect.DeepEqual(got, want) { + t.Errorf("GetShardServingTypes() failure. Got %v, want: %v", got, want) + } +} + +func TestMasterMigrateServedType(t *testing.T) { + cell := "cell1" + cell2 := "cell2" + keyspace := "ks1" + ctx := context.Background() + ts := memorytopo.NewServer(cell, cell2) + + initialKeyRange, err := key.ParseShardingSpec("-") + if err != nil || len(initialKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(initialKeyRange)) + } + + leftKeyRange, err := key.ParseShardingSpec("-80") + if err != nil || len(leftKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(leftKeyRange)) + } + + rightKeyRange, err := key.ParseShardingSpec("80-") + if err != nil || len(rightKeyRange) != 1 { + t.Fatalf("ParseShardingSpec failed. Expected non error and only one element. Got err: %v, len(%v)", err, len(rightKeyRange)) + } + // Create initial value + initial := &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: initialKeyRange[0], + }, + }, + ShardTabletControls: []*topodatapb.ShardTabletControl{ + &topodatapb.ShardTabletControl{ + Name: "-", + KeyRange: initialKeyRange[0], + QueryServiceDisabled: true, + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_REPLICA, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: initialKeyRange[0], + }, + }, + ShardTabletControls: []*topodatapb.ShardTabletControl{ + &topodatapb.ShardTabletControl{ + Name: "-", + KeyRange: initialKeyRange[0], + QueryServiceDisabled: true, + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_RDONLY, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: initialKeyRange[0], + }, + }, + }, + }, + } + + if err := ts.UpdateSrvKeyspace(ctx, cell, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + if err := ts.UpdateSrvKeyspace(ctx, cell2, keyspace, initial); err != nil { + t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + } + + sourceShards := []*topo.ShardInfo{ + topo.NewShardInfo(keyspace, "-", &topodatapb.Shard{KeyRange: initialKeyRange[0]}, nil), + } + + destinationShards := []*topo.ShardInfo{ + topo.NewShardInfo(keyspace, "-80", &topodatapb.Shard{KeyRange: leftKeyRange[0]}, nil), + topo.NewShardInfo(keyspace, "80-", &topodatapb.Shard{KeyRange: rightKeyRange[0]}, nil), + } + + ks := &topodatapb.Keyspace{} + if err := ts.CreateKeyspace(ctx, keyspace, ks); err != nil { + t.Fatalf("CreateKeyspace() failed: %v", err) + } + + ctx, unlock, err := ts.LockKeyspace(ctx, keyspace, "Locking for tests") + if err != nil { + t.Fatalf("LockKeyspace() failed: %v", err) + } + defer unlock(&err) + + // You can migrate a single cell at a time + + err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_RDONLY, []string{cell}) + if err != nil { + t.Fatalf("MigrateServedType() failed: %v", err) + } + + targetKs := &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: initialKeyRange[0], + }, + }, + ShardTabletControls: []*topodatapb.ShardTabletControl{ + &topodatapb.ShardTabletControl{ + Name: "-", + KeyRange: initialKeyRange[0], + QueryServiceDisabled: true, + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_REPLICA, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: initialKeyRange[0], + }, + }, + ShardTabletControls: []*topodatapb.ShardTabletControl{ + &topodatapb.ShardTabletControl{ + Name: "-", + KeyRange: initialKeyRange[0], + QueryServiceDisabled: true, + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_RDONLY, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + }, + } + + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err := json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err := json2.MarshalPB(targetKs) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want)) + } + + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err = json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err = json2.MarshalPB(initial) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + if string(got) != string(want) { + t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want)) + } + + // migrating all cells + + err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_RDONLY, nil) + if err != nil { + t.Fatalf("MigrateServedType() failed: %v", err) + } + + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell2, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err = json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err = json2.MarshalPB(targetKs) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want)) + } + + // migrating master type cleans up shard tablet controls records + + targetKs = &topodatapb.SrvKeyspace{ + Partitions: []*topodatapb.SrvKeyspace_KeyspacePartition{ + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_MASTER, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_REPLICA, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-", + KeyRange: initialKeyRange[0], + }, + }, + }, + &topodatapb.SrvKeyspace_KeyspacePartition{ + ServedType: topodatapb.TabletType_RDONLY, + ShardReferences: []*topodatapb.ShardReference{ + &topodatapb.ShardReference{ + Name: "-80", + KeyRange: leftKeyRange[0], + }, + &topodatapb.ShardReference{ + Name: "80-", + KeyRange: rightKeyRange[0], + }, + }, + }, + }, + } + + err = ts.MigrateServedType(ctx, keyspace, destinationShards, sourceShards, topodatapb.TabletType_MASTER, nil) + if err != nil { + t.Fatalf("MigrateServedType() failed: %v", err) + } + + srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) + if err != nil { + t.Fatalf("GetSrvKeyspace() failed: %v", err) + } + + got, err = json2.MarshalPB(srvKeyspace) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + want, err = json2.MarshalPB(targetKs) + if err != nil { + t.Fatalf("MarshalPB() failed: %v", err) + } + + if string(got) != string(want) { + t.Errorf("MigrateServedType() failure. Got %v, want: %v", string(got), string(want)) + } } From 60e5bc66059a8dd7298b26d3dd1193adc51c1598 Mon Sep 17 00:00:00 2001 From: zhoulin xie Date: Fri, 8 Mar 2019 00:51:42 +0800 Subject: [PATCH 144/196] Fix some typos in docs Signed-off-by: zhoulin xie --- doc/ReplicatoinLagBasedThrottlingOfTransactions.md | 4 ++-- go/vt/workflow/parallel_runner.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/ReplicatoinLagBasedThrottlingOfTransactions.md b/doc/ReplicatoinLagBasedThrottlingOfTransactions.md index 97d8500876f..3a50f492306 100644 --- a/doc/ReplicatoinLagBasedThrottlingOfTransactions.md +++ b/doc/ReplicatoinLagBasedThrottlingOfTransactions.md @@ -17,7 +17,7 @@ throttler: * *enable-tx-throttler* -A boolean flag controling whether the replication-lag-based throttling is enabled. +A boolean flag controlling whether the replication-lag-based throttling is enabled. * *tx-throttler-config* @@ -37,6 +37,6 @@ the non-RDONLY replicas found in these cells for replication lag. the replication lag under the desired limit; as such the desired replication lag limit may occasionally be slightly violated. -* Transactions are considered homegenous. There is currently no support +* Transactions are considered homogenous. There is currently no support for specifying how "expensive" a transaction is. diff --git a/go/vt/workflow/parallel_runner.go b/go/vt/workflow/parallel_runner.go index da8d0e30479..88d3f687533 100644 --- a/go/vt/workflow/parallel_runner.go +++ b/go/vt/workflow/parallel_runner.go @@ -112,7 +112,7 @@ func NewParallelRunner(ctx context.Context, rootUINode *Node, cp *CheckpointWrit return p } -// Run is the entry point for controling task executions. +// Run is the entry point for controlling task executions. func (p *ParallelRunner) Run() error { // default value is 0. The task will not run in this case. var parallelNum int From 9ba5c078418d5f901776624218186ca3158ffb8e Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Thu, 7 Mar 2019 11:12:06 -0800 Subject: [PATCH 145/196] Adds test for multi shard migrate served types Signed-off-by: Rafael Chacon --- .../testlib/migrate_served_types_test.go | 352 ++++++++++++++++++ 1 file changed, 352 insertions(+) diff --git a/go/vt/wrangler/testlib/migrate_served_types_test.go b/go/vt/wrangler/testlib/migrate_served_types_test.go index 96669177f7a..4d118afd7f8 100644 --- a/go/vt/wrangler/testlib/migrate_served_types_test.go +++ b/go/vt/wrangler/testlib/migrate_served_types_test.go @@ -248,3 +248,355 @@ func TestMigrateServedTypes(t *testing.T) { checkShardSourceShards(t, ts, "-80", 0) checkShardSourceShards(t, ts, "80-", 0) } + +func TestMultiShardMigrateServedTypes(t *testing.T) { + // TODO(b/26388813): Remove the next two lines once vtctl WaitForDrain is integrated in the vtctl MigrateServed* commands. + flag.Set("wait_for_drain_sleep_rdonly", "0s") + flag.Set("wait_for_drain_sleep_replica", "0s") + + ts := memorytopo.NewServer("cell1", "cell2") + wr := wrangler.New(logutil.NewConsoleLogger(), ts, tmclient.NewTabletManagerClient()) + vp := NewVtctlPipe(t, ts) + defer vp.Close() + + // create keyspace + if err := ts.CreateKeyspace(context.Background(), "ks", &topodatapb.Keyspace{ + ShardingColumnName: "keyspace_id", + ShardingColumnType: topodatapb.KeyspaceIdType_UINT64, + }); err != nil { + t.Fatalf("CreateKeyspace failed: %v", err) + } + + // create the first source shard + source1Master := NewFakeTablet(t, wr, "cell1", 20, topodatapb.TabletType_MASTER, nil, + TabletKeyspaceShard(t, "ks", "-80")) + source1Replica := NewFakeTablet(t, wr, "cell1", 21, topodatapb.TabletType_REPLICA, nil, + TabletKeyspaceShard(t, "ks", "-80")) + source1Rdonly := NewFakeTablet(t, wr, "cell1", 22, topodatapb.TabletType_RDONLY, nil, + TabletKeyspaceShard(t, "ks", "-80")) + + // create the second source shard + source2Master := NewFakeTablet(t, wr, "cell1", 30, topodatapb.TabletType_MASTER, nil, + TabletKeyspaceShard(t, "ks", "80-")) + source2Replica := NewFakeTablet(t, wr, "cell1", 31, topodatapb.TabletType_REPLICA, nil, + TabletKeyspaceShard(t, "ks", "80-")) + source2Rdonly := NewFakeTablet(t, wr, "cell1", 32, topodatapb.TabletType_RDONLY, nil, + TabletKeyspaceShard(t, "ks", "80-")) + + dest1Master := NewFakeTablet(t, wr, "cell1", 40, topodatapb.TabletType_MASTER, nil, + TabletKeyspaceShard(t, "ks", "-40")) + dest1Replica := NewFakeTablet(t, wr, "cell1", 41, topodatapb.TabletType_REPLICA, nil, + TabletKeyspaceShard(t, "ks", "-40")) + dest1Rdonly := NewFakeTablet(t, wr, "cell1", 42, topodatapb.TabletType_RDONLY, nil, + TabletKeyspaceShard(t, "ks", "-40")) + + // create the second source shard + dest2Master := NewFakeTablet(t, wr, "cell1", 50, topodatapb.TabletType_MASTER, nil, + TabletKeyspaceShard(t, "ks", "40-80")) + dest2Replica := NewFakeTablet(t, wr, "cell1", 51, topodatapb.TabletType_REPLICA, nil, + TabletKeyspaceShard(t, "ks", "40-80")) + dest2Rdonly := NewFakeTablet(t, wr, "cell1", 52, topodatapb.TabletType_RDONLY, nil, + TabletKeyspaceShard(t, "ks", "40-80")) + + dest3Master := NewFakeTablet(t, wr, "cell1", 60, topodatapb.TabletType_MASTER, nil, + TabletKeyspaceShard(t, "ks", "80-c0")) + dest3Replica := NewFakeTablet(t, wr, "cell1", 61, topodatapb.TabletType_REPLICA, nil, + TabletKeyspaceShard(t, "ks", "80-c0")) + dest3Rdonly := NewFakeTablet(t, wr, "cell1", 62, topodatapb.TabletType_RDONLY, nil, + TabletKeyspaceShard(t, "ks", "80-c0")) + + // create the second source shard + dest4Master := NewFakeTablet(t, wr, "cell1", 70, topodatapb.TabletType_MASTER, nil, + TabletKeyspaceShard(t, "ks", "c0-")) + dest4Replica := NewFakeTablet(t, wr, "cell1", 71, topodatapb.TabletType_REPLICA, nil, + TabletKeyspaceShard(t, "ks", "c0-")) + dest4Rdonly := NewFakeTablet(t, wr, "cell1", 72, topodatapb.TabletType_RDONLY, nil, + TabletKeyspaceShard(t, "ks", "c0-")) + + if source1Master == nil || source1Replica == nil || source1Rdonly == nil || source2Master == nil || source2Replica == nil || source2Rdonly == nil { + + } + + if dest1Master == nil || dest1Replica == nil || dest1Rdonly == nil || dest2Master == nil || dest2Replica == nil || dest2Rdonly == nil { + + } + + if dest3Master == nil || dest3Replica == nil || dest3Rdonly == nil || dest4Master == nil || dest4Replica == nil || dest4Rdonly == nil { + + } + + // Build keyspace graph + err := topotools.RebuildKeyspace(context.Background(), logutil.NewConsoleLogger(), ts, "ks", []string{"cell1"}) + if err != nil { + t.Fatalf("RebuildKeyspaceLocked failed: %v", err) + } + // double check the shards have the right served types + checkShardServedTypes(t, ts, "-80", 3) + checkShardServedTypes(t, ts, "80-", 3) + checkShardServedTypes(t, ts, "-40", 0) + checkShardServedTypes(t, ts, "40-80", 0) + checkShardServedTypes(t, ts, "80-c0", 0) + checkShardServedTypes(t, ts, "c0-", 0) + + // source1Rdonly will see the refresh + source1Rdonly.StartActionLoop(t, wr) + defer source1Rdonly.StopActionLoop(t) + + // source1Replica will see the refresh + source1Replica.StartActionLoop(t, wr) + defer source1Replica.StopActionLoop(t) + + // source1Master will see the refresh, and has to respond to it + // also will be asked about its replication position. + source1Master.FakeMysqlDaemon.CurrentMasterPosition = mysql.Position{ + GTIDSet: mysql.MariadbGTIDSet{ + mysql.MariadbGTID{ + Domain: 5, + Server: 456, + Sequence: 892, + }, + }, + } + source1Master.StartActionLoop(t, wr) + defer source1Master.StopActionLoop(t) + + // // dest1Rdonly will see the refresh + dest1Rdonly.StartActionLoop(t, wr) + defer dest1Rdonly.StopActionLoop(t) + + // // dest1Replica will see the refresh + dest1Replica.StartActionLoop(t, wr) + defer dest1Replica.StopActionLoop(t) + + dest1Master.StartActionLoop(t, wr) + defer dest1Master.StopActionLoop(t) + + // // dest2Rdonly will see the refresh + dest2Rdonly.StartActionLoop(t, wr) + defer dest2Rdonly.StopActionLoop(t) + + // // dest2Replica will see the refresh + dest2Replica.StartActionLoop(t, wr) + defer dest2Replica.StopActionLoop(t) + + dest2Master.StartActionLoop(t, wr) + defer dest2Master.StopActionLoop(t) + + // Now let's kick off the process for the second shard. + + // source2Rdonly will see the refresh + source2Rdonly.StartActionLoop(t, wr) + defer source2Rdonly.StopActionLoop(t) + + // source2Replica will see the refresh + source2Replica.StartActionLoop(t, wr) + defer source2Replica.StopActionLoop(t) + + // sourceMaster will see the refresh, and has to respond to it + // also will be asked about its replication position. + source2Master.FakeMysqlDaemon.CurrentMasterPosition = mysql.Position{ + GTIDSet: mysql.MariadbGTIDSet{ + mysql.MariadbGTID{ + Domain: 5, + Server: 456, + Sequence: 892, + }, + }, + } + source2Master.StartActionLoop(t, wr) + defer source2Master.StopActionLoop(t) + + // dest3Rdonly will see the refresh + dest3Rdonly.StartActionLoop(t, wr) + defer dest3Rdonly.StopActionLoop(t) + + // dest3Replica will see the refresh + dest3Replica.StartActionLoop(t, wr) + defer dest3Replica.StopActionLoop(t) + + dest3Master.StartActionLoop(t, wr) + defer dest3Master.StopActionLoop(t) + + // dest4Rdonly will see the refresh + dest4Rdonly.StartActionLoop(t, wr) + defer dest4Rdonly.StopActionLoop(t) + + // dest4Replica will see the refresh + dest4Replica.StartActionLoop(t, wr) + defer dest4Replica.StopActionLoop(t) + + dest4Master.StartActionLoop(t, wr) + defer dest4Master.StopActionLoop(t) + + // Override with a fake VREngine after Agent is initialized in action loop. + dbClient1 := binlogplayer.NewMockDBClient(t) + dbClientFactory1 := func() binlogplayer.DBClient { return dbClient1 } + dest1Master.Agent.VREngine = vreplication.NewEngine(ts, "", dest1Master.FakeMysqlDaemon, dbClientFactory1) + // select * from _vt.vreplication during Open + dbClient1.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := dest1Master.Agent.VREngine.Open(context.Background()); err != nil { + t.Fatal(err) + } + // select pos, state, message from _vt.vreplication + dbClient1.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/5-456-892"), + sqltypes.NewVarBinary("Running"), + sqltypes.NewVarBinary(""), + }}}, nil) + dbClient1.ExpectRequest("use _vt", &sqltypes.Result{}, nil) + dbClient1.ExpectRequest("delete from _vt.vreplication where id = 1", &sqltypes.Result{RowsAffected: 1}, nil) + + // Override with a fake VREngine after Agent is initialized in action loop. + dbClient2 := binlogplayer.NewMockDBClient(t) + dbClientFactory2 := func() binlogplayer.DBClient { return dbClient2 } + dest2Master.Agent.VREngine = vreplication.NewEngine(ts, "", dest2Master.FakeMysqlDaemon, dbClientFactory2) + // select * from _vt.vreplication during Open + dbClient2.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := dest2Master.Agent.VREngine.Open(context.Background()); err != nil { + t.Fatal(err) + } + + // select pos, state, message from _vt.vreplication + dbClient2.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/5-456-892"), + sqltypes.NewVarBinary("Running"), + sqltypes.NewVarBinary(""), + }}}, nil) + dbClient2.ExpectRequest("use _vt", &sqltypes.Result{}, nil) + dbClient2.ExpectRequest("delete from _vt.vreplication where id = 1", &sqltypes.Result{RowsAffected: 1}, nil) + + // migrate will error if the overlapping shards have no "SourceShard" entry + // and we cannot decide which shard is the source or the destination. + if err := vp.Run([]string{"MigrateServedTypes", "ks/-80", "rdonly"}); err == nil || !strings.Contains(err.Error(), "' have a 'SourceShards' entry. Did you successfully run vtworker SplitClone before? Or did you already migrate the MASTER type?") { + t.Fatalf("MigrateServedType(rdonly) should fail if no 'SourceShards' entry is present: %v", err) + } + + // simulate the clone, by fixing the dest shard record + checkShardSourceShards(t, ts, "-40", 0) + checkShardSourceShards(t, ts, "40-80", 0) + if err := vp.Run([]string{"SourceShardAdd", "--key_range=-", "ks/-40", "1", "ks/-80"}); err != nil { + t.Fatalf("SourceShardAdd failed: %v", err) + } + if err := vp.Run([]string{"SourceShardAdd", "--key_range=-", "ks/40-80", "1", "ks/-80"}); err != nil { + t.Fatalf("SourceShardAdd failed: %v", err) + } + checkShardSourceShards(t, ts, "-40", 1) + checkShardSourceShards(t, ts, "40-80", 1) + + // migrate rdonly over + if err := vp.Run([]string{"MigrateServedTypes", "ks/-80", "rdonly"}); err != nil { + t.Fatalf("MigrateServedType(rdonly) failed: %v", err) + } + + checkShardServedTypes(t, ts, "-80", 2) + checkShardServedTypes(t, ts, "-40", 1) + checkShardServedTypes(t, ts, "40-80", 1) + checkShardSourceShards(t, ts, "-40", 1) + checkShardSourceShards(t, ts, "40-80", 1) + + // migrate replica over + if err := vp.Run([]string{"MigrateServedTypes", "ks/-80", "replica"}); err != nil { + t.Fatalf("MigrateServedType(replica) failed: %v", err) + } + + checkShardServedTypes(t, ts, "-80", 1) + checkShardServedTypes(t, ts, "-40", 2) + checkShardServedTypes(t, ts, "40-80", 2) + checkShardSourceShards(t, ts, "-40", 1) + checkShardSourceShards(t, ts, "40-80", 1) + + // migrate master over + if err := vp.Run([]string{"MigrateServedTypes", "ks/-80", "master"}); err != nil { + t.Fatalf("MigrateServedType(master) failed: %v", err) + } + + checkShardServedTypes(t, ts, "-80", 0) + checkShardServedTypes(t, ts, "-40", 3) + checkShardServedTypes(t, ts, "40-80", 3) + checkShardSourceShards(t, ts, "-40", 0) + checkShardSourceShards(t, ts, "40-80", 0) + + // Now migrate the second destination shard + + // Override with a fake VREngine after Agent is initialized in action loop. + dbClient1 = binlogplayer.NewMockDBClient(t) + dbClientFactory1 = func() binlogplayer.DBClient { return dbClient1 } + dest3Master.Agent.VREngine = vreplication.NewEngine(ts, "", dest3Master.FakeMysqlDaemon, dbClientFactory1) + // select * from _vt.vreplication during Open + dbClient1.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := dest3Master.Agent.VREngine.Open(context.Background()); err != nil { + t.Fatal(err) + } + // select pos, state, message from _vt.vreplication + dbClient1.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/5-456-892"), + sqltypes.NewVarBinary("Running"), + sqltypes.NewVarBinary(""), + }}}, nil) + dbClient1.ExpectRequest("use _vt", &sqltypes.Result{}, nil) + dbClient1.ExpectRequest("delete from _vt.vreplication where id = 1", &sqltypes.Result{RowsAffected: 1}, nil) + + // Override with a fake VREngine after Agent is initialized in action loop. + dbClient2 = binlogplayer.NewMockDBClient(t) + dbClientFactory2 = func() binlogplayer.DBClient { return dbClient2 } + dest4Master.Agent.VREngine = vreplication.NewEngine(ts, "", dest4Master.FakeMysqlDaemon, dbClientFactory2) + // select * from _vt.vreplication during Open + dbClient2.ExpectRequest("select * from _vt.vreplication", &sqltypes.Result{}, nil) + if err := dest4Master.Agent.VREngine.Open(context.Background()); err != nil { + t.Fatal(err) + } + + // select pos, state, message from _vt.vreplication + dbClient2.ExpectRequest("select pos, state, message from _vt.vreplication where id=1", &sqltypes.Result{Rows: [][]sqltypes.Value{{ + sqltypes.NewVarBinary("MariaDB/5-456-892"), + sqltypes.NewVarBinary("Running"), + sqltypes.NewVarBinary(""), + }}}, nil) + dbClient2.ExpectRequest("use _vt", &sqltypes.Result{}, nil) + dbClient2.ExpectRequest("delete from _vt.vreplication where id = 1", &sqltypes.Result{RowsAffected: 1}, nil) + + // // simulate the clone, by fixing the dest shard record + checkShardSourceShards(t, ts, "80-c0", 0) + checkShardSourceShards(t, ts, "c0-", 0) + if err := vp.Run([]string{"SourceShardAdd", "--key_range=-", "ks/80-c0", "1", "ks/80-"}); err != nil { + t.Fatalf("SourceShardAdd failed: %v", err) + } + if err := vp.Run([]string{"SourceShardAdd", "--key_range=-", "ks/c0-", "1", "ks/80-"}); err != nil { + t.Fatalf("SourceShardAdd failed: %v", err) + } + checkShardSourceShards(t, ts, "80-c0", 1) + checkShardSourceShards(t, ts, "c0-", 1) + + // // migrate rdonly over + if err := vp.Run([]string{"MigrateServedTypes", "ks/80-", "rdonly"}); err != nil { + t.Fatalf("MigrateServedType(rdonly) failed: %v", err) + } + + checkShardServedTypes(t, ts, "80-", 2) + checkShardServedTypes(t, ts, "80-c0", 1) + checkShardServedTypes(t, ts, "c0-", 1) + checkShardSourceShards(t, ts, "80-c0", 1) + checkShardSourceShards(t, ts, "c0-", 1) + + // // migrate replica over + if err := vp.Run([]string{"MigrateServedTypes", "ks/80-", "replica"}); err != nil { + t.Fatalf("MigrateServedType(replica) failed: %v", err) + } + + checkShardServedTypes(t, ts, "80-", 1) + checkShardServedTypes(t, ts, "80-c0", 2) + checkShardServedTypes(t, ts, "c0-", 2) + checkShardSourceShards(t, ts, "80-c0", 1) + checkShardSourceShards(t, ts, "c0-", 1) + + // // migrate master over + if err := vp.Run([]string{"MigrateServedTypes", "ks/80-", "master"}); err != nil { + t.Fatalf("MigrateServedType(master) failed: %v", err) + } + + checkShardServedTypes(t, ts, "80-", 0) + checkShardServedTypes(t, ts, "80-c0", 3) + checkShardServedTypes(t, ts, "c0-", 3) + checkShardSourceShards(t, ts, "80-c0", 0) + checkShardSourceShards(t, ts, "c0-", 0) +} From 7e3c96edb0bf0fc4e64358db148020732ac18b72 Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 19 Feb 2019 12:56:19 -0800 Subject: [PATCH 146/196] staticcheck: mysql package Signed-off-by: deepthi --- go/mysql/auth_server.go | 5 +- go/mysql/auth_server_static.go | 4 +- go/mysql/binlog_event_json.go | 4 +- go/mysql/binlog_event_make_test.go | 6 +- go/mysql/binlog_event_rbr_test.go | 2 +- go/mysql/client.go | 4 +- go/mysql/conn.go | 16 ++--- go/mysql/conn_test.go | 21 +++--- go/mysql/encoding_test.go | 26 ++++---- go/mysql/flavor_mariadb.go | 2 +- go/mysql/flavor_mysql.go | 2 +- go/mysql/handshake_test.go | 4 +- go/mysql/query.go | 4 +- go/mysql/query_test.go | 20 ++++-- go/mysql/replication.go | 2 +- go/mysql/replication_constants.go | 104 ++++++++++++++++++----------- go/mysql/replication_position.go | 2 +- go/mysql/server.go | 5 +- misc/git/hooks/staticcheck | 74 ++++++++++++++++++++ 19 files changed, 209 insertions(+), 98 deletions(-) create mode 100755 misc/git/hooks/staticcheck diff --git a/go/mysql/auth_server.go b/go/mysql/auth_server.go index 03470b79a53..91fefbc4893 100644 --- a/go/mysql/auth_server.go +++ b/go/mysql/auth_server.go @@ -186,10 +186,7 @@ func isPassScrambleMysqlNativePassword(reply, salt []byte, mysqlNativePassword s crypt.Write(hashStage1) candidateHash2 := crypt.Sum(nil) - if bytes.Compare(candidateHash2, hash) != 0 { - return false - } - return true + return bytes.Equal(candidateHash2, hash) } // Constants for the dialog plugin. diff --git a/go/mysql/auth_server_static.go b/go/mysql/auth_server_static.go index 164fb9b251c..5f7d5bdb8cc 100644 --- a/go/mysql/auth_server_static.go +++ b/go/mysql/auth_server_static.go @@ -184,7 +184,7 @@ func validateConfig(config map[string][]*AuthServerStaticEntry) error { for _, entries := range config { for _, entry := range entries { if entry.SourceHost != "" && entry.SourceHost != localhostName { - return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "Invalid SourceHost found (only localhost is supported): %v", entry.SourceHost) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid SourceHost found (only localhost is supported): %v", entry.SourceHost) } } } @@ -220,7 +220,7 @@ func (a *AuthServerStatic) ValidateHash(salt []byte, user string, authResponse [ } else { computedAuthResponse := ScramblePassword(salt, []byte(entry.Password)) // Validate the password. - if matchSourceHost(remoteAddr, entry.SourceHost) && bytes.Compare(authResponse, computedAuthResponse) == 0 { + if matchSourceHost(remoteAddr, entry.SourceHost) && bytes.Equal(authResponse, computedAuthResponse) { return &StaticUserData{entry.UserData, entry.Groups}, nil } } diff --git a/go/mysql/binlog_event_json.go b/go/mysql/binlog_event_json.go index 800af6a1c8d..5f662dad36f 100644 --- a/go/mysql/binlog_event_json.go +++ b/go/mysql/binlog_event_json.go @@ -484,10 +484,10 @@ func readOffsetOrSize(data []byte, pos int, large bool) (int, int) { } func readVariableInt(data []byte, pos int) (int, int) { - var b byte + var b int8 var result int for { - b = data[pos] + b = int8(data[pos]) pos++ result = (result << 7) + int(b&0x7f) if b >= 0 { diff --git a/go/mysql/binlog_event_make_test.go b/go/mysql/binlog_event_make_test.go index 64620bda567..c6c00cc27cf 100644 --- a/go/mysql/binlog_event_make_test.go +++ b/go/mysql/binlog_event_make_test.go @@ -356,11 +356,11 @@ func TestRowsEvent(t *testing.T) { // Test the Rows we just created, to be sure. // 1076895760 is 0x40302010. - identifies, err := rows.StringIdentifiesForTests(tm, 0) + identifies, _ := rows.StringIdentifiesForTests(tm, 0) if expected := []string{"1076895760", "abc"}; !reflect.DeepEqual(identifies, expected) { t.Fatalf("bad Rows idenfity, got %v expected %v", identifies, expected) } - values, err := rows.StringValuesForTests(tm, 0) + values, _ := rows.StringValuesForTests(tm, 0) if expected := []string{"1076895760", "abcd"}; !reflect.DeepEqual(values, expected) { t.Fatalf("bad Rows data, got %v expected %v", values, expected) } @@ -373,7 +373,7 @@ func TestRowsEvent(t *testing.T) { t.Fatalf("NewRowsEvent().IsUpdateRows() if false") } - event, _, err = event.StripChecksum(f) + event, _, err := event.StripChecksum(f) if err != nil { t.Fatalf("StripChecksum failed: %v", err) } diff --git a/go/mysql/binlog_event_rbr_test.go b/go/mysql/binlog_event_rbr_test.go index 327b78e036f..3b7d814b3fc 100644 --- a/go/mysql/binlog_event_rbr_test.go +++ b/go/mysql/binlog_event_rbr_test.go @@ -544,7 +544,7 @@ func TestCellLengthAndData(t *testing.T) { // Test CellValue. out, l, err := CellValue(padded, 1, tcase.typ, tcase.metadata, tcase.styp) - if err != nil || l != len(tcase.data) || out.Type() != tcase.out.Type() || bytes.Compare(out.Raw(), tcase.out.Raw()) != 0 { + if err != nil || l != len(tcase.data) || out.Type() != tcase.out.Type() || !bytes.Equal(out.Raw(), tcase.out.Raw()) { t.Errorf("testcase cellData(%v,%v) returned unexpected result: %v %v %v, was expecting %v %v ", tcase.typ, tcase.data, out, l, err, tcase.out, len(tcase.data)) } } diff --git a/go/mysql/client.go b/go/mysql/client.go index ae851336beb..d72956bbb0b 100644 --- a/go/mysql/client.go +++ b/go/mysql/client.go @@ -82,7 +82,7 @@ func Connect(ctx context.Context, params *ConnParams) (*Conn, error) { // return the right error to the client (ctx.Err(), vs // DialTimeout() error). if deadline, ok := ctx.Deadline(); ok { - timeout := deadline.Sub(time.Now()) + 5*time.Second + timeout := time.Until(deadline) + 5*time.Second conn, err = net.DialTimeout(netProto, addr, timeout) } else { conn, err = net.Dial(netProto, addr) @@ -531,7 +531,7 @@ func (c *Conn) writeSSLRequest(capabilities uint32, characterSet uint8, params * pos = writeZeroes(data, pos, 4) // Character set. - pos = writeByte(data, pos, characterSet) + _ = writeByte(data, pos, characterSet) // And send it as is. if err := c.writeEphemeralPacket(); err != nil { diff --git a/go/mysql/conn.go b/go/mysql/conn.go index a6c26df30ab..2f5394866b7 100644 --- a/go/mysql/conn.go +++ b/go/mysql/conn.go @@ -525,11 +525,11 @@ func (c *Conn) writeEphemeralPacket() error { switch c.currentEphemeralPolicy { case ephemeralWrite: if err := c.writePacket(*c.currentEphemeralBuffer); err != nil { - return vterrors.Wrapf(err, "Conn %v", c.ID()) + return vterrors.Wrapf(err, "conn %v", c.ID()) } case ephemeralUnused, ephemeralRead: // Programming error. - panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "Conn %v: trying to call writeEphemeralPacket while currentEphemeralPolicy is %v", c.ID(), c.currentEphemeralPolicy)) + panic(vterrors.Errorf(vtrpc.Code_INTERNAL, "conn %v: trying to call writeEphemeralPacket while currentEphemeralPolicy is %v", c.ID(), c.currentEphemeralPolicy)) } return nil @@ -613,7 +613,7 @@ func (c *Conn) writeOKPacket(affectedRows, lastInsertID uint64, flags uint16, wa pos = writeLenEncInt(data, pos, affectedRows) pos = writeLenEncInt(data, pos, lastInsertID) pos = writeUint16(data, pos, flags) - pos = writeUint16(data, pos, warnings) + _ = writeUint16(data, pos, warnings) return c.writeEphemeralPacket() } @@ -635,7 +635,7 @@ func (c *Conn) writeOKPacketWithEOFHeader(affectedRows, lastInsertID uint64, fla pos = writeLenEncInt(data, pos, affectedRows) pos = writeLenEncInt(data, pos, lastInsertID) pos = writeUint16(data, pos, flags) - pos = writeUint16(data, pos, warnings) + _ = writeUint16(data, pos, warnings) return c.writeEphemeralPacket() } @@ -658,7 +658,7 @@ func (c *Conn) writeErrorPacket(errorCode uint16, sqlState string, format string panic("sqlState has to be 5 characters long") } pos = writeEOFString(data, pos, sqlState) - pos = writeEOFString(data, pos, errorMessage) + _ = writeEOFString(data, pos, errorMessage) return c.writeEphemeralPacket() } @@ -681,7 +681,7 @@ func (c *Conn) writeEOFPacket(flags uint16, warnings uint16) error { pos := 0 pos = writeByte(data, pos, EOFPacket) pos = writeUint16(data, pos, warnings) - pos = writeUint16(data, pos, flags) + _ = writeUint16(data, pos, flags) return c.writeEphemeralPacket() } @@ -912,7 +912,7 @@ func isEOFPacket(data []byte) bool { // type code set, i.e. should not be used if ClientDeprecateEOF is set. func parseEOFPacket(data []byte) (warnings uint16, more bool, err error) { // The warning count is in position 2 & 3 - warnings, _, ok := readUint16(data, 1) + warnings, _, _ = readUint16(data, 1) // The status flag is in position 4 & 5 statusFlags, _, ok := readUint16(data, 3) @@ -945,7 +945,7 @@ func parseOKPacket(data []byte) (uint64, uint64, uint16, uint16, error) { } // Warnings. - warnings, pos, ok := readUint16(data, pos) + warnings, _, ok := readUint16(data, pos) if !ok { return 0, 0, 0, 0, vterrors.Errorf(vtrpc.Code_INTERNAL, "invalid OK packet warnings: %v", data) } diff --git a/go/mysql/conn_test.go b/go/mysql/conn_test.go index 796798e167f..5c352164831 100644 --- a/go/mysql/conn_test.go +++ b/go/mysql/conn_test.go @@ -38,29 +38,30 @@ func createSocketPair(t *testing.T) (net.Listener, *Conn, *Conn) { wg := sync.WaitGroup{} var clientConn net.Conn + var clientErr error wg.Add(1) go func() { defer wg.Done() - var err error - clientConn, err = net.Dial("tcp", addr) - if err != nil { - t.Fatalf("Dial failed: %v", err) - } + clientConn, clientErr = net.Dial("tcp", addr) }() var serverConn net.Conn + var serverErr error wg.Add(1) go func() { defer wg.Done() - var err error - serverConn, err = listener.Accept() - if err != nil { - t.Fatalf("Accept failed: %v", err) - } + serverConn, serverErr = listener.Accept() }() wg.Wait() + if clientErr != nil { + t.Fatalf("Dial failed: %v", clientErr) + } + if serverErr != nil { + t.Fatalf("Accept failed: %v", serverErr) + } + // Create a Conn on both sides. cConn := newConn(clientConn) sConn := newConn(serverConn) diff --git a/go/mysql/encoding_test.go b/go/mysql/encoding_test.go index b03a3fc54ad..75637146f91 100644 --- a/go/mysql/encoding_test.go +++ b/go/mysql/encoding_test.go @@ -76,7 +76,7 @@ func TestEncLenInt(t *testing.T) { } // Check failed decoding. - got, pos, ok = readLenEncInt(test.encoded[:len(test.encoded)-1], 0) + _, _, ok = readLenEncInt(test.encoded[:len(test.encoded)-1], 0) if ok { t.Errorf("readLenEncInt returned ok=true for shorter value %x", test.value) } @@ -101,7 +101,7 @@ func TestEncUint16(t *testing.T) { t.Errorf("readUint16 returned %v/%v/%v but expected %v/%v/%v", got16, pos, ok, val16, 4, true) } - got16, pos, ok = readUint16(data, 9) + _, _, ok = readUint16(data, 9) if ok { t.Errorf("readUint16 returned ok=true for shorter value") } @@ -119,7 +119,7 @@ func TestEncBytes(t *testing.T) { t.Errorf("readByte returned %v/%v/%v but expected %v/%v/%v", got, pos, ok, 0xab, 6, true) } - got, pos, ok = readByte(data, 10) + _, _, ok = readByte(data, 10) if ok { t.Errorf("readByte returned ok=true for shorter value") } @@ -130,7 +130,7 @@ func TestEncBytes(t *testing.T) { t.Errorf("readBytes returned %v/%v/%v but expected %v/%v/%v", b, pos, ok, expected, 7, true) } - b, pos, ok = readBytes(data, 9, 2) + _, _, ok = readBytes(data, 9, 2) if ok { t.Errorf("readBytes returned ok=true for shorter value") } @@ -154,7 +154,7 @@ func TestEncUint32(t *testing.T) { t.Errorf("readUint32 returned %v/%v/%v but expected %v/%v/%v", got32, pos, ok, val32, 6, true) } - got32, pos, ok = readUint32(data, 7) + _, _, ok = readUint32(data, 7) if ok { t.Errorf("readUint32 returned ok=true for shorter value") } @@ -179,7 +179,7 @@ func TestEncUint64(t *testing.T) { t.Errorf("readUint64 returned %v/%v/%v but expected %v/%v/%v", got64, pos, ok, val64, 6, true) } - got64, pos, ok = readUint64(data, 7) + _, _, ok = readUint64(data, 7) if ok { t.Errorf("readUint64 returned ok=true for shorter value") } @@ -247,13 +247,13 @@ func TestEncString(t *testing.T) { } // Check failed decoding with shorter data. - got, pos, ok = readLenEncString(test.lenEncoded[:len(test.lenEncoded)-1], 0) + _, _, ok = readLenEncString(test.lenEncoded[:len(test.lenEncoded)-1], 0) if ok { t.Errorf("readLenEncString returned ok=true for shorter value %v", test.value) } // Check failed decoding with no data. - got, pos, ok = readLenEncString([]byte{}, 0) + _, _, ok = readLenEncString([]byte{}, 0) if ok { t.Errorf("readLenEncString returned ok=true for empty value %v", test.value) } @@ -265,13 +265,13 @@ func TestEncString(t *testing.T) { } // Check failed skipping with shorter data. - pos, ok = skipLenEncString(test.lenEncoded[:len(test.lenEncoded)-1], 0) + _, ok = skipLenEncString(test.lenEncoded[:len(test.lenEncoded)-1], 0) if ok { t.Errorf("skipLenEncString returned ok=true for shorter value %v", test.value) } // Check failed skipping with no data. - pos, ok = skipLenEncString([]byte{}, 0) + _, ok = skipLenEncString([]byte{}, 0) if ok { t.Errorf("skipLenEncString returned ok=true for empty value %v", test.value) } @@ -283,13 +283,13 @@ func TestEncString(t *testing.T) { } // Check failed decoding as bytes with shorter data. - gotb, pos, ok = readLenEncStringAsBytes(test.lenEncoded[:len(test.lenEncoded)-1], 0) + _, _, ok = readLenEncStringAsBytes(test.lenEncoded[:len(test.lenEncoded)-1], 0) if ok { t.Errorf("readLenEncStringAsBytes returned ok=true for shorter value %v", test.value) } // Check failed decoding as bytes with no data. - gotb, pos, ok = readLenEncStringAsBytes([]byte{}, 0) + _, _, ok = readLenEncStringAsBytes([]byte{}, 0) if ok { t.Errorf("readLenEncStringAsBytes returned ok=true for empty value %v", test.value) } @@ -313,7 +313,7 @@ func TestEncString(t *testing.T) { } // Check failed decoding with shorter data. - got, pos, ok = readNullString(test.nullEncoded[:len(test.nullEncoded)-1], 0) + _, _, ok = readNullString(test.nullEncoded[:len(test.nullEncoded)-1], 0) if ok { t.Errorf("readNullString returned ok=true for shorter value %v", test.value) } diff --git a/go/mysql/flavor_mariadb.go b/go/mysql/flavor_mariadb.go index 3530f47d9c1..9167dabba5d 100644 --- a/go/mysql/flavor_mariadb.go +++ b/go/mysql/flavor_mariadb.go @@ -152,7 +152,7 @@ func (mariadbFlavor) status(c *Conn) (SlaveStatus, error) { // if the slave thread stops. If that is a problem, we'll have to change this. func (mariadbFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) (string, error) { if deadline, ok := ctx.Deadline(); ok { - timeout := deadline.Sub(time.Now()) + timeout := time.Until(deadline) if timeout <= 0 { return "", vterrors.Errorf(vtrpc.Code_DEADLINE_EXCEEDED, "timed out waiting for position %v", pos) } diff --git a/go/mysql/flavor_mysql.go b/go/mysql/flavor_mysql.go index 246b0037afa..446e6e95a57 100644 --- a/go/mysql/flavor_mysql.go +++ b/go/mysql/flavor_mysql.go @@ -118,7 +118,7 @@ func (mysqlFlavor) waitUntilPositionCommand(ctx context.Context, pos Position) ( // A timeout of 0 means wait indefinitely. timeoutSeconds := 0 if deadline, ok := ctx.Deadline(); ok { - timeout := deadline.Sub(time.Now()) + timeout := time.Until(deadline) if timeout <= 0 { return "", vterrors.Errorf(vtrpc.Code_DEADLINE_EXCEEDED, "timed out waiting for position %v", pos) } diff --git a/go/mysql/handshake_test.go b/go/mysql/handshake_test.go index a6f2e4287b6..cb4f3f61d62 100644 --- a/go/mysql/handshake_test.go +++ b/go/mysql/handshake_test.go @@ -64,14 +64,14 @@ func TestClearTextClientAuth(t *testing.T) { // Connection should fail, as server requires SSL for clear text auth. ctx := context.Background() - conn, err := Connect(ctx, params) + _, err = Connect(ctx, params) if err == nil || !strings.Contains(err.Error(), "Cannot use clear text authentication over non-SSL connections") { t.Fatalf("unexpected connection error: %v", err) } // Change server side to allow clear text without auth. l.AllowClearTextWithoutTLS = true - conn, err = Connect(ctx, params) + conn, err := Connect(ctx, params) if err != nil { t.Fatalf("unexpected connection error: %v", err) } diff --git a/go/mysql/query.go b/go/mysql/query.go index 297ab60db62..b92ece87b63 100644 --- a/go/mysql/query.go +++ b/go/mysql/query.go @@ -143,7 +143,7 @@ func (c *Conn) readColumnDefinition(field *querypb.Field, index int) error { } // Decimals is a byte. - decimals, pos, ok := readByte(colDef, pos) + decimals, _, ok := readByte(colDef, pos) if !ok { return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v decimals failed", index) } @@ -228,7 +228,7 @@ func (c *Conn) readColumnDefinitionType(field *querypb.Field, index int) error { } // flags is 2 bytes - flags, pos, ok := readUint16(colDef, pos) + flags, _, ok := readUint16(colDef, pos) if !ok { return NewSQLError(CRMalformedPacket, SSUnknownSQLState, "extracting col %v flags failed", index) } diff --git a/go/mysql/query_test.go b/go/mysql/query_test.go index c2ae6cf4176..5b7fe6bec85 100644 --- a/go/mysql/query_test.go +++ b/go/mysql/query_test.go @@ -343,6 +343,7 @@ func checkQueryInternal(t *testing.T, query string, sConn, cConn *Conn, result * query += " NOWARNINGS" } + var fatalError string // Use a go routine to run ExecuteFetch. wg := sync.WaitGroup{} wg.Add(1) @@ -367,7 +368,8 @@ func checkQueryInternal(t *testing.T, query string, sConn, cConn *Conn, result * return } if err != nil { - t.Fatalf("executeFetch failed: %v", err) + fatalError = fmt.Sprintf("executeFetch failed: %v", err) + return } expected := *result if !wantfields { @@ -380,7 +382,8 @@ func checkQueryInternal(t *testing.T, query string, sConn, cConn *Conn, result * t.Logf("Expected field(%v) = %v", i, expected.Fields[i]) } } - t.Fatalf("ExecuteFetch(wantfields=%v) returned:\n%v\nBut was expecting:\n%v", wantfields, got, expected) + fatalError = fmt.Sprintf("ExecuteFetch(wantfields=%v) returned:\n%v\nBut was expecting:\n%v", wantfields, got, expected) + return } if gotWarnings != warningCount { @@ -390,14 +393,15 @@ func checkQueryInternal(t *testing.T, query string, sConn, cConn *Conn, result * // Test ExecuteStreamFetch, build a Result. expected = *result if err := cConn.ExecuteStreamFetch(query); err != nil { - t.Fatalf("ExecuteStreamFetch(%v) failed: %v", query, err) + fatalError = fmt.Sprintf("ExecuteStreamFetch(%v) failed: %v", query, err) + return } got = &sqltypes.Result{} got.RowsAffected = result.RowsAffected got.InsertID = result.InsertID got.Fields, err = cConn.Fields() if err != nil { - t.Fatalf("Fields(%v) failed: %v", query, err) + fatalError = fmt.Sprintf("Fields(%v) failed: %v", query, err) } if len(got.Fields) == 0 { got.Fields = nil @@ -405,7 +409,8 @@ func checkQueryInternal(t *testing.T, query string, sConn, cConn *Conn, result * for { row, err := cConn.FetchNext() if err != nil { - t.Fatalf("FetchNext(%v) failed: %v", query, err) + fatalError = fmt.Sprintf("FetchNext(%v) failed: %v", query, err) + return } if row == nil { // Done. @@ -454,8 +459,13 @@ func checkQueryInternal(t *testing.T, query string, sConn, cConn *Conn, result * } wg.Wait() + + if fatalError != "" { + t.Fatalf(fatalError) + } } +//lint:ignore U1000 for now, because deleting this function causes more errors func writeResult(conn *Conn, result *sqltypes.Result) error { if len(result.Fields) == 0 { return conn.writeOKPacket(result.RowsAffected, result.InsertID, conn.StatusFlags, 0) diff --git a/go/mysql/replication.go b/go/mysql/replication.go index e59db547d6a..2649785a252 100644 --- a/go/mysql/replication.go +++ b/go/mysql/replication.go @@ -33,7 +33,7 @@ func (c *Conn) WriteComBinlogDump(serverID uint32, binlogFilename string, binlog pos = writeUint32(data, pos, binlogPos) pos = writeUint16(data, pos, flags) pos = writeUint32(data, pos, serverID) - pos = writeEOFString(data, pos, binlogFilename) + _ = writeEOFString(data, pos, binlogFilename) if err := c.writeEphemeralPacket(); err != nil { return NewSQLError(CRServerGone, SSUnknownSQLState, "%v", err) } diff --git a/go/mysql/replication_constants.go b/go/mysql/replication_constants.go index cf5f2f8ce32..947bbcbb843 100644 --- a/go/mysql/replication_constants.go +++ b/go/mysql/replication_constants.go @@ -152,54 +152,82 @@ const ( // These constants describe the event types. // See: http://dev.mysql.com/doc/internals/en/binlog-event-type.html const ( - eUnknownEvent = 0 - eStartEventV3 = 1 - eQueryEvent = 2 - eStopEvent = 3 - eRotateEvent = 4 - eIntVarEvent = 5 - eLoadEvent = 6 - eSlaveEvent = 7 - eCreateFileEvent = 8 - eAppendBlockEvent = 9 - eExecLoadEvent = 10 - eDeleteFileEvent = 11 - eNewLoadEvent = 12 - eRandEvent = 13 + //lint:ignore U1000 unused for now, reserved for future use + eUnknownEvent = 0 + //lint:ignore U1000 unused for now, reserved for future use + eStartEventV3 = 1 + eQueryEvent = 2 + //lint:ignore U1000 unused for now, reserved for future use + eStopEvent = 3 + eRotateEvent = 4 + eIntVarEvent = 5 + //lint:ignore U1000 unused for now, reserved for future use + eLoadEvent = 6 + //lint:ignore U1000 unused for now, reserved for future use + eSlaveEvent = 7 + //lint:ignore U1000 unused for now, reserved for future use + eCreateFileEvent = 8 + //lint:ignore U1000 unused for now, reserved for future use + eAppendBlockEvent = 9 + //lint:ignore U1000 unused for now, reserved for future use + eExecLoadEvent = 10 + //lint:ignore U1000 unused for now, reserved for future use + eDeleteFileEvent = 11 + //lint:ignore U1000 unused for now, reserved for future use + eNewLoadEvent = 12 + eRandEvent = 13 + //lint:ignore U1000 unused for now, reserved for future use eUserVarEvent = 14 eFormatDescriptionEvent = 15 eXIDEvent = 16 - eBeginLoadQueryEvent = 17 - eExecuteLoadQueryEvent = 18 - eTableMapEvent = 19 - eWriteRowsEventV0 = 20 - eUpdateRowsEventV0 = 21 - eDeleteRowsEventV0 = 22 - eWriteRowsEventV1 = 23 - eUpdateRowsEventV1 = 24 - eDeleteRowsEventV1 = 25 - eIncidentEvent = 26 - eHeartbeatEvent = 27 - eIgnorableEvent = 28 - eRowsQueryEvent = 29 - eWriteRowsEventV2 = 30 - eUpdateRowsEventV2 = 31 - eDeleteRowsEventV2 = 32 - eGTIDEvent = 33 - eAnonymousGTIDEvent = 34 - ePreviousGTIDsEvent = 35 + //lint:ignore U1000 unused for now, reserved for future use + eBeginLoadQueryEvent = 17 + //lint:ignore U1000 unused for now, reserved for future use + eExecuteLoadQueryEvent = 18 + eTableMapEvent = 19 + //lint:ignore U1000 unused for now, reserved for future use + eWriteRowsEventV0 = 20 + //lint:ignore U1000 unused for now, reserved for future use + eUpdateRowsEventV0 = 21 + //lint:ignore U1000 unused for now, reserved for future use + eDeleteRowsEventV0 = 22 + eWriteRowsEventV1 = 23 + eUpdateRowsEventV1 = 24 + eDeleteRowsEventV1 = 25 + //lint:ignore U1000 unused for now, reserved for future use + eIncidentEvent = 26 + //lint:ignore U1000 unused for now, reserved for future use + eHeartbeatEvent = 27 + //lint:ignore U1000 unused for now, reserved for future use + eIgnorableEvent = 28 + //lint:ignore U1000 unused for now, reserved for future use + eRowsQueryEvent = 29 + eWriteRowsEventV2 = 30 + eUpdateRowsEventV2 = 31 + eDeleteRowsEventV2 = 32 + eGTIDEvent = 33 + //lint:ignore U1000 unused for now, reserved for future use + eAnonymousGTIDEvent = 34 + ePreviousGTIDsEvent = 35 // MySQL 5.7 events + //lint:ignore U1000 unused for now, reserved for future use eTransactionContextEvent = 36 - eViewChangeEvent = 37 - eXAPrepareLogEvent = 38 + //lint:ignore U1000 unused for now, reserved for future use + eViewChangeEvent = 37 + //lint:ignore U1000 unused for now, reserved for future use + eXAPrepareLogEvent = 38 // MariaDB specific values. They start at 160. - eMariaAnnotateRowsEvent = 160 + //lint:ignore U1000 unused for now, reserved for future use + eMariaAnnotateRowsEvent = 160 + //lint:ignore U1000 unused for now, reserved for future use eMariaBinlogCheckpointEvent = 161 eMariaGTIDEvent = 162 - eMariaGTIDListEvent = 163 - eMariaStartEncryptionEvent = 164 + //lint:ignore U1000 unused for now, reserved for future use + eMariaGTIDListEvent = 163 + //lint:ignore U1000 unused for now, reserved for future use + eMariaStartEncryptionEvent = 164 ) // These constants describe the type of status variables in q Query packet. diff --git a/go/mysql/replication_position.go b/go/mysql/replication_position.go index 87895fc6d90..8d1ec3f9e08 100644 --- a/go/mysql/replication_position.go +++ b/go/mysql/replication_position.go @@ -51,7 +51,7 @@ type Position struct { // a problem until the runtime panic. Note that this must not be // the last field of the struct, or else the Go compiler will add // padding to prevent pointers to this field from becoming invalid. - _ [0]struct{ notComparable []byte } + _ [0]struct{ _ []byte } // GTIDSet is the underlying GTID set. It must not be anonymous, // or else Position would itself also implement the GTIDSet interface. diff --git a/go/mysql/server.go b/go/mysql/server.go index 374aab6b8e8..7538261c259 100644 --- a/go/mysql/server.go +++ b/go/mysql/server.go @@ -325,7 +325,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti } } else { if l.RequireSecureTransport { - c.writeErrorPacketFromError(vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "Server does not allow insecure connections, client must use SSL/TLS")) + c.writeErrorPacketFromError(vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "server does not allow insecure connections, client must use SSL/TLS")) } connCountByTLSVer.Add(versionNoTLS, 1) defer connCountByTLSVer.Add(versionNoTLS, -1) @@ -361,6 +361,7 @@ func (l *Listener) handle(conn net.Conn, connectionID uint32, acceptTime time.Ti if err != nil { return } + //lint:ignore SA4006 This line is required because the binary protocol requires padding with 0 data := make([]byte, 21) data = append(salt, byte(0x00)) if err := c.writeAuthSwitchRequest(MysqlNativePassword, data); err != nil { @@ -683,7 +684,7 @@ func (l *Listener) parseClientHandshakePacket(c *Conn, firstTime bool, data []by // Decode connection attributes send by the client if clientFlags&CapabilityClientConnAttr != 0 { var err error - _, pos, err = parseConnAttrs(data, pos) + _, _, err = parseConnAttrs(data, pos) if err != nil { return "", "", nil, err } diff --git a/misc/git/hooks/staticcheck b/misc/git/hooks/staticcheck new file mode 100755 index 00000000000..784b33bc4b5 --- /dev/null +++ b/misc/git/hooks/staticcheck @@ -0,0 +1,74 @@ +#!/bin/bash + +# git staticcheck pre-commit hook + +if [ -z "$GOPATH" ]; then + echo "ERROR: pre-commit hook for staticcheck: \$GOPATH is empty. Please run 'source dev.env' to set the correct \$GOPATH." + exit 1 +fi + +if [ -z "$(which staticcheck)" ]; then + echo "staticcheck not found, please run: go get honnef.co/go/tools/cmd/staticcheck" + exit 1 +fi + +# This script does not handle file names that contain spaces. +# Exclude auto-generated files (from proto or yacc compile). +gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '^go/.*\.go$' | grep -v '^go/vt/proto/' | grep -v 'go/vt/sqlparser/sql.go') +if [ "$gofiles" = "" ]; then + exit 0 +fi +# xargs -n1 because dirname on MacOS does not support multiple arguments. +gopackages=$(echo $gofiles | xargs -n1 dirname | sort -u) + +warnings= + +# Run on one package at a time +gopackages_with_warnings=() +for gopackage in $gopackages +do + warningcount="$(staticcheck "vitess.io/vitess/$gopackage" | wc -l)" + if [ "$warningcount" -gt "0" ]; then + warnings=YES + echo "$warningcount reports for:" + echo "staticcheck vitess.io/vitess/$gopackage" + gopackages_with_warnings+=($gopackage) + fi +done + +[ -z "$warnings" ] && exit 0 + +# git doesn't give us access to user input, so let's steal it. +exec < /dev/tty +if [[ $? -eq 0 ]]; then + # interactive shell. Prompt the user. + echo + echo "Suggestions from the go 'staticcheck' program were found." + echo "They're not enforced, but we're pausing to let you know" + echo "before they get clobbered in the scrollback buffer." + echo + read -r -p 'Press enter to cancel, "s" to step through the warnings or type "ack" to continue: ' + if [ "$REPLY" = "ack" ]; then + exit 0 + fi + if [ "$REPLY" = "s" ]; then + first_file="true" + for gopackage in "${gopackages_with_warnings[@]}" + do + echo + if [ "$first_file" != "true" ]; then + echo "Press enter to show the warnings for the next file." + read + fi + staticcheck "vitess.io/vitess/$gopackage" + first_file="false" + done + fi +else + # non-interactive shell (e.g. called from Eclipse). Just display the warnings. + for gopackage in "${gopackages_with_warnings[@]}" + do + staticcheck "vitess.io/vitess/$gopackage" + done +fi +exit 1 From c858a37c21b9383484aa56b6e35ad37b4c829b29 Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 26 Feb 2019 12:21:27 -0800 Subject: [PATCH 147/196] cmd package Signed-off-by: deepthi --- go/cmd/automation_client/automation_client.go | 2 +- go/cmd/vtclient/vtclient.go | 12 ++++++------ go/cmd/vtctlclient/main.go | 2 +- go/cmd/vtexplain/vtexplain.go | 2 +- go/cmd/vttablet/vttablet.go | 3 --- go/cmd/vttlstest/vttlstest.go | 2 +- go/cmd/zk/zkcmd.go | 8 ++++---- go/cmd/zkctl/zkctl.go | 2 +- go/cmd/zkctld/zkctld.go | 2 +- 9 files changed, 16 insertions(+), 19 deletions(-) diff --git a/go/cmd/automation_client/automation_client.go b/go/cmd/automation_client/automation_client.go index eaeeb16fe9e..73e16245b7d 100644 --- a/go/cmd/automation_client/automation_client.go +++ b/go/cmd/automation_client/automation_client.go @@ -115,7 +115,7 @@ func waitForClusterOp(client automationservicepb.AutomationClient, id string) (* resp, err := client.GetClusterOperationDetails(context.Background(), req, grpc.FailFast(false)) if err != nil { - return nil, fmt.Errorf("Failed to get ClusterOperation Details. Request: %v Error: %v", req, err) + return nil, fmt.Errorf("failed to get ClusterOperation Details. Request: %v Error: %v", req, err) } switch resp.ClusterOp.State { diff --git a/go/cmd/vtclient/vtclient.go b/go/cmd/vtclient/vtclient.go index e866fef7566..6c4d74d993c 100644 --- a/go/cmd/vtclient/vtclient.go +++ b/go/cmd/vtclient/vtclient.go @@ -72,7 +72,7 @@ func init() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) flag.PrintDefaults() - fmt.Fprintf(os.Stderr, usage) + fmt.Fprint(os.Stderr, usage) } } @@ -236,8 +236,8 @@ func execDml(ctx context.Context, db *sql.DB, sql string) (*results, error) { return nil, vterrors.Wrap(err, "COMMIT failed") } - rowsAffected, err := result.RowsAffected() - lastInsertID, err := result.LastInsertId() + rowsAffected, _ := result.RowsAffected() + lastInsertID, _ := result.LastInsertId() return &results{ rowsAffected: rowsAffected, lastInsertID: lastInsertID, @@ -257,7 +257,7 @@ func execNonDml(ctx context.Context, db *sql.DB, sql string) (*results, error) { var qr results cols, err := rows.Columns() if err != nil { - return nil, fmt.Errorf("client error: %v", err) + return nil, vterrors.Wrap(err, "client error") } qr.Fields = cols @@ -269,7 +269,7 @@ func execNonDml(ctx context.Context, db *sql.DB, sql string) (*results, error) { row[i] = &col } if err := rows.Scan(row...); err != nil { - return nil, fmt.Errorf("client error: %v", err) + return nil, vterrors.Wrap(err, "client error") } // unpack []*string into []string @@ -282,7 +282,7 @@ func execNonDml(ctx context.Context, db *sql.DB, sql string) (*results, error) { qr.rowsAffected = int64(len(qr.Rows)) if err := rows.Err(); err != nil { - return nil, fmt.Errorf("Vitess returned an error: %v", err) + return nil, vterrors.Wrap(err, "Vitess returned an error") } qr.duration = time.Since(start) diff --git a/go/cmd/vtctlclient/main.go b/go/cmd/vtctlclient/main.go index b7d215aae2c..c0f973971e8 100644 --- a/go/cmd/vtctlclient/main.go +++ b/go/cmd/vtctlclient/main.go @@ -47,7 +47,7 @@ func main() { // We can't do much without a -server flag if *server == "" { - log.Error(errors.New("Please specify -server to specify the vtctld server to connect to")) + log.Error(errors.New("please specify -server to specify the vtctld server to connect to")) os.Exit(1) } diff --git a/go/cmd/vtexplain/vtexplain.go b/go/cmd/vtexplain/vtexplain.go index b1831c54559..90e8280d067 100644 --- a/go/cmd/vtexplain/vtexplain.go +++ b/go/cmd/vtexplain/vtexplain.go @@ -116,7 +116,7 @@ func getFileParam(flag, flagFile, name string) (string, error) { } data, err := ioutil.ReadFile(flagFile) if err != nil { - return "", fmt.Errorf("Cannot read file %v: %v", flagFile, err) + return "", fmt.Errorf("cannot read file %v: %v", flagFile, err) } return string(data), nil } diff --git a/go/cmd/vttablet/vttablet.go b/go/cmd/vttablet/vttablet.go index dcc9768daa1..809eb4c1c84 100644 --- a/go/cmd/vttablet/vttablet.go +++ b/go/cmd/vttablet/vttablet.go @@ -67,9 +67,6 @@ func main() { if err != nil { log.Exitf("failed to parse -tablet-path: %v", err) } - if tabletAlias.Uid < 0 { - log.Exitf("invalid tablet id: %d", tabletAlias.Uid) - } var mycnf *mysqlctl.Mycnf var socketFile string diff --git a/go/cmd/vttlstest/vttlstest.go b/go/cmd/vttlstest/vttlstest.go index 889960bd101..856be6f49b8 100644 --- a/go/cmd/vttlstest/vttlstest.go +++ b/go/cmd/vttlstest/vttlstest.go @@ -87,7 +87,7 @@ func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %v:\n", os.Args[0]) flag.PrintDefaults() - fmt.Fprintf(os.Stderr, doc) + fmt.Fprint(os.Stderr, doc) } flag.Parse() args := flag.Args() diff --git a/go/cmd/zk/zkcmd.go b/go/cmd/zk/zkcmd.go index acf612d8750..0a93356a38e 100644 --- a/go/cmd/zk/zkcmd.go +++ b/go/cmd/zk/zkcmd.go @@ -136,7 +136,7 @@ func main() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %v:\n", os.Args[0]) flag.PrintDefaults() - fmt.Fprintf(os.Stderr, doc) + fmt.Fprint(os.Stderr, doc) } flag.Parse() args := flag.Args() @@ -206,7 +206,7 @@ func cmdWait(ctx context.Context, subFlags *flag.FlagSet, args []string) error { } if err != nil { if err == zk.ErrNoNode { - _, _, wait, err = zconn.ExistsW(ctx, zkPath) + _, _, wait, _ = zconn.ExistsW(ctx, zkPath) } else { return fmt.Errorf("wait: error %v: %v", zkPath, err) } @@ -600,7 +600,7 @@ func cmdEdit(ctx context.Context, subFlags *flag.FlagSet, args []string) error { return fmt.Errorf("edit: cannot read file %v", err) } - if bytes.Compare(fileData, data) != 0 { + if !bytes.Equal(fileData, data) { // data changed - update if we can _, err = zconn.Set(ctx, zkPath, fileData, stat.Version) if err != nil { @@ -900,7 +900,7 @@ func cmdZip(ctx context.Context, subFlags *flag.FlagSet, args []string) error { continue } fi := &zip.FileHeader{Name: path, Method: zip.Deflate} - fi.SetModTime(zk2topo.Time(stat.Mtime)) + fi.Modified = zk2topo.Time(stat.Mtime) f, err := zipWriter.CreateHeader(fi) if err != nil { return fmt.Errorf("zip: create failed: %v", err) diff --git a/go/cmd/zkctl/zkctl.go b/go/cmd/zkctl/zkctl.go index 23d48f804fe..57c0750cc29 100644 --- a/go/cmd/zkctl/zkctl.go +++ b/go/cmd/zkctl/zkctl.go @@ -48,7 +48,7 @@ func init() { flag.Usage = func() { fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0]) flag.PrintDefaults() - fmt.Fprintf(os.Stderr, usage) + fmt.Fprint(os.Stderr, usage) } stdin = bufio.NewReader(os.Stdin) } diff --git a/go/cmd/zkctld/zkctld.go b/go/cmd/zkctld/zkctld.go index d2847d168d4..e0d198e1ffe 100644 --- a/go/cmd/zkctld/zkctld.go +++ b/go/cmd/zkctld/zkctld.go @@ -62,7 +62,7 @@ func main() { } log.Infof("waiting for signal or server shutdown...") - sig := make(chan os.Signal) + sig := make(chan os.Signal, 1) signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM) select { case <-zkd.Done(): From 9e58dda87455c952c7cd19941278aeb42d7ecf2f Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 26 Feb 2019 12:23:53 -0800 Subject: [PATCH 148/196] remove unused hook Signed-off-by: deepthi --- misc/git/hooks/unused | 74 ------------------------------------------- 1 file changed, 74 deletions(-) delete mode 100755 misc/git/hooks/unused diff --git a/misc/git/hooks/unused b/misc/git/hooks/unused deleted file mode 100755 index 935740d2958..00000000000 --- a/misc/git/hooks/unused +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -# git unused pre-commit hook - -if [ -z "$GOPATH" ]; then - echo "ERROR: pre-commit hook for unused: \$GOPATH is empty. Please run 'source dev.env' to set the correct \$GOPATH." - exit 1 -fi - -if [ -z "$(which unused)" ]; then - echo "unused not found, please run: go get honnef.co/go/tools/cmd/unused" - exit 1 -fi - -# This script does not handle file names that contain spaces. -# Exclude auto-generated files (from proto or yacc compile). -gofiles=$(git diff --cached --name-only --diff-filter=ACM | grep '^go/.*\.go$' | grep -v '^go/vt/proto/' | grep -v 'go/vt/sqlparser/sql.go') -if [ "$gofiles" = "" ]; then - exit 0 -fi -# xargs -n1 because dirname on MacOS does not support multiple arguments. -gopackages=$(echo $gofiles | xargs -n1 dirname | sort -u) - -warnings= - -# Run on one package at a time -gopackages_with_warnings=() -for gopackage in $gopackages -do - warningcount="$(unused "vitess.io/vitess/$gopackage" | wc -l)" - if [ "$warningcount" -gt "0" ]; then - warnings=YES - echo "$warningcount reports for:" - echo "unused vitess.io/vitess/$gopackage" - gopackages_with_warnings+=($gopackage) - fi -done - -[ -z "$warnings" ] && exit 0 - -# git doesn't give us access to user input, so let's steal it. -exec < /dev/tty -if [[ $? -eq 0 ]]; then - # interactive shell. Prompt the user. - echo - echo "Suggestions from the go 'unused' program were found." - echo "They're not enforced, but we're pausing to let you know" - echo "before they get clobbered in the scrollback buffer." - echo - read -r -p 'Press enter to cancel, "s" to step through the warnings or type "ack" to continue: ' - if [ "$REPLY" = "ack" ]; then - exit 0 - fi - if [ "$REPLY" = "s" ]; then - first_file="true" - for gopackage in "${gopackages_with_warnings[@]}" - do - echo - if [ "$first_file" != "true" ]; then - echo "Press enter to show the warnings for the next file." - read - fi - unused "vitess.io/vitess/$gopackage" - first_file="false" - done - fi -else - # non-interactive shell (e.g. called from Eclipse). Just display the warnings. - for gopackage in "${gopackages_with_warnings[@]}" - do - unused "vitess.io/vitess/$gopackage" - done -fi -exit 1 From 2aa19cc5042b4d6fd5be5e5b5c23d65b7114001d Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 18:32:41 -0800 Subject: [PATCH 149/196] staticcheck: sqlparser package Signed-off-by: deepthi --- go/vt/sqlparser/ast.go | 2 -- go/vt/sqlparser/parse_next_test.go | 6 +++--- go/vt/sqlparser/parse_test.go | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index 93d8c745524..631e26ec499 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -403,7 +403,6 @@ func (node *Select) AddWhere(expr Expr) { Left: node.Where.Expr, Right: expr, } - return } // AddHaving adds the boolean expression to the @@ -426,7 +425,6 @@ func (node *Select) AddHaving(expr Expr) { Left: node.Having.Expr, Right: expr, } - return } // ParenSelect is a parenthesized SELECT statement. diff --git a/go/vt/sqlparser/parse_next_test.go b/go/vt/sqlparser/parse_next_test.go index c1dd85f5498..98f94f26b84 100644 --- a/go/vt/sqlparser/parse_next_test.go +++ b/go/vt/sqlparser/parse_next_test.go @@ -203,11 +203,11 @@ func TestParseNextStrictNonStrict(t *testing.T) { // Now try again with strict parsing and observe the expected error. tokens = NewStringTokenizer(input) - tree, err := ParseNextStrictDDL(tokens) + _, err := ParseNextStrictDDL(tokens) if err == nil || !strings.Contains(err.Error(), "ignore") { - t.Fatalf("ParseNext(%q) err = %q, want nil", input, err) + t.Fatalf("ParseNext(%q) err = %q, want ignore", input, err) } - tree, err = ParseNextStrictDDL(tokens) + tree, err := ParseNextStrictDDL(tokens) if err != nil { t.Fatalf("ParseNext(%q) err = %q, want nil", input, err) } diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index 1b71b1d85cd..fc1c98008b6 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -2066,12 +2066,12 @@ func TestCreateTable(t *testing.T) { } sql := "create table t garbage" - tree, err := Parse(sql) + _, err := Parse(sql) if err != nil { t.Errorf("input: %s, err: %v", sql, err) } - tree, err = ParseStrictDDL(sql) + tree, err := ParseStrictDDL(sql) if tree != nil || err == nil { t.Errorf("ParseStrictDDL unexpectedly accepted input %s", sql) } From 306c29d436d6adfccc072399340c81c661069fe4 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 18:45:02 -0800 Subject: [PATCH 150/196] staticcheck: automation package Signed-off-by: deepthi --- go/vt/automation/scheduler.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/go/vt/automation/scheduler.go b/go/vt/automation/scheduler.go index e43c959fc77..cfbb5fc0520 100644 --- a/go/vt/automation/scheduler.go +++ b/go/vt/automation/scheduler.go @@ -29,6 +29,7 @@ import ( "golang.org/x/net/context" "vitess.io/vitess/go/vt/log" automationpb "vitess.io/vitess/go/vt/proto/automation" + "vitess.io/vitess/go/vt/vterrors" ) type schedulerState int32 @@ -149,7 +150,7 @@ clusterOpLoop: // Make sure all new tasks do not miss any required parameters. err := s.validateTaskContainers(newTaskContainers) if err != nil { - err = fmt.Errorf("Task: %v (%v/%v) emitted a new task which is not valid. Error: %v", taskProto.Name, clusterOp.Id, taskProto.Id, err) + err = vterrors.Wrapf(err, "task: %v (%v/%v) emitted a new task which is not valid. Error: %v", taskProto.Name, clusterOp.Id, taskProto.Id, err) log.Error(err) MarkTaskFailed(taskProto, output, err) clusterOp.Error = err.Error() @@ -311,7 +312,7 @@ func (s *Scheduler) EnqueueClusterOperation(ctx context.Context, req *automation return nil, fmt.Errorf("scheduler is not running. State: %v", s.state) } - if s.registeredClusterOperations[req.Name] != true { + if !s.registeredClusterOperations[req.Name] { return nil, fmt.Errorf("no ClusterOperation with name: %v is registered", req.Name) } From 2e24040633491d52b354a83da71594e532020f12 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 18:48:11 -0800 Subject: [PATCH 151/196] staticcheck: binlog package Signed-off-by: deepthi --- go/vt/binlog/event_streamer.go | 2 +- go/vt/binlog/keyspace_id_resolver.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/binlog/event_streamer.go b/go/vt/binlog/event_streamer.go index 8aacd12d7d6..6fd098a78a3 100644 --- a/go/vt/binlog/event_streamer.go +++ b/go/vt/binlog/event_streamer.go @@ -168,7 +168,7 @@ func (evs *EventStreamer) buildDMLStatement(stmt FullBinlogStatement, insertid i } // then parse the PK values, one at a time - for typ, val = tokenizer.Scan(); typ != ';'; typ, val = tokenizer.Scan() { + for typ, _ = tokenizer.Scan(); typ != ';'; typ, _ = tokenizer.Scan() { switch typ { case '(': // pkTuple is a list of pk values diff --git a/go/vt/binlog/keyspace_id_resolver.go b/go/vt/binlog/keyspace_id_resolver.go index 5c97794da26..a590f083754 100644 --- a/go/vt/binlog/keyspace_id_resolver.go +++ b/go/vt/binlog/keyspace_id_resolver.go @@ -104,7 +104,7 @@ func (r *keyspaceIDResolverFactoryV2) keyspaceID(v sqltypes.Value) ([]byte, erro case topodatapb.KeyspaceIdType_UINT64: i, err := sqltypes.ToUint64(v) if err != nil { - return nil, fmt.Errorf("Non numerical value: %v", err) + return nil, fmt.Errorf("non numerical value: %v", err) } return key.Uint64Key(i).Bytes(), nil default: From 09e437caff5d5f9acb13cf0de42c94a800023a7e Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 18:50:29 -0800 Subject: [PATCH 152/196] staticcheck: dbconfigs package Signed-off-by: deepthi --- go/vt/dbconfigs/dbconfigs_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/go/vt/dbconfigs/dbconfigs_test.go b/go/vt/dbconfigs/dbconfigs_test.go index 86fbd757581..4bb3b936645 100644 --- a/go/vt/dbconfigs/dbconfigs_test.go +++ b/go/vt/dbconfigs/dbconfigs_test.go @@ -237,7 +237,7 @@ func TestCredentialsFileHUP(t *testing.T) { t.Fatalf("couldn't write temp file: %v", err) } cs := GetCredentialsServer() - _, pass, err := cs.GetUserAndPassword(oldStr) + _, pass, _ := cs.GetUserAndPassword(oldStr) if pass != oldStr { t.Fatalf("%s's Password should still be '%s'", oldStr, oldStr) } @@ -251,17 +251,17 @@ func hupTest(t *testing.T, tmpFile *os.File, oldStr, newStr string) { if err := ioutil.WriteFile(tmpFile.Name(), []byte(jsonConfig), 0600); err != nil { t.Fatalf("couldn't overwrite temp file: %v", err) } - _, pass, err := cs.GetUserAndPassword(oldStr) + _, pass, _ := cs.GetUserAndPassword(oldStr) if pass != oldStr { t.Fatalf("%s's Password should still be '%s'", oldStr, oldStr) } syscall.Kill(syscall.Getpid(), syscall.SIGHUP) time.Sleep(100 * time.Millisecond) // wait for signal handler - _, pass, err = cs.GetUserAndPassword(oldStr) + _, _, err := cs.GetUserAndPassword(oldStr) if err != ErrUnknownUser { t.Fatalf("Should not have old %s after config reload", oldStr) } - _, pass, err = cs.GetUserAndPassword(newStr) + _, pass, _ = cs.GetUserAndPassword(newStr) if pass != newStr { t.Fatalf("%s's Password should be '%s'", newStr, newStr) } From 872673a1d92a5e26bb66c3253f6e694074d5f366 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 18:53:32 -0800 Subject: [PATCH 153/196] staticcheck: env package Signed-off-by: deepthi --- go/vt/env/env.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/go/vt/env/env.go b/go/vt/env/env.go index d859d173ee9..7f639cf7fa5 100644 --- a/go/vt/env/env.go +++ b/go/vt/env/env.go @@ -25,6 +25,7 @@ import ( ) const ( + // DefaultVtDataRoot is the default value for VTROOT environment variable DefaultVtDataRoot = "/vt" ) @@ -44,7 +45,7 @@ func VtRoot() (root string, err error) { if strings.HasSuffix(dir, "/bin") { return path.Dir(dir), nil } - err = errors.New("VTROOT could not be guessed from the executable location. Please set $VTROOT.") + err = errors.New("VTROOT could not be guessed from the executable location. Please set $VTROOT") return } @@ -70,7 +71,7 @@ func VtMysqlRoot() (string, error) { // otherwise let's use VTROOT root, err := VtRoot() if err != nil { - return "", errors.New("VT_MYSQL_ROOT is not set and could not be guessed from the executable location. Please set $VT_MYSQL_ROOT.") + return "", errors.New("VT_MYSQL_ROOT is not set and could not be guessed from the executable location. Please set $VT_MYSQL_ROOT") } return root, nil } @@ -86,7 +87,7 @@ func VtMysqlBaseDir() (string, error) { // otherwise let's use VtMysqlRoot root, err := VtMysqlRoot() if err != nil { - return "", errors.New("VT_MYSQL_BASEDIR is not set. Please set $VT_MYSQL_BASEDIR.") + return "", errors.New("VT_MYSQL_BASEDIR is not set. Please set $VT_MYSQL_BASEDIR") } return root, nil } From 49f0161a779ca6b339c0c3d64be9006691bb01a2 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 18:55:11 -0800 Subject: [PATCH 154/196] staticcheck: hook package Signed-off-by: deepthi --- go/vt/hook/hook.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/hook/hook.go b/go/vt/hook/hook.go index db65ef497ae..1e44b710c5e 100644 --- a/go/vt/hook/hook.go +++ b/go/vt/hook/hook.go @@ -195,7 +195,7 @@ func (hook *Hook) ExecuteAsWritePipe(out io.Writer) (io.WriteCloser, WaitFunc, i // Configure the process's stdin, stdout, and stderr. in, err := cmd.StdinPipe() if err != nil { - return nil, nil, HOOK_GENERIC_ERROR, fmt.Errorf("Failed to configure stdin: %v", err) + return nil, nil, HOOK_GENERIC_ERROR, fmt.Errorf("failed to configure stdin: %v", err) } cmd.Stdout = out var stderr bytes.Buffer @@ -234,7 +234,7 @@ func (hook *Hook) ExecuteAsReadPipe(in io.Reader) (io.Reader, WaitFunc, int, err // Configure the process's stdin, stdout, and stderr. out, err := cmd.StdoutPipe() if err != nil { - return nil, nil, HOOK_GENERIC_ERROR, fmt.Errorf("Failed to configure stdout: %v", err) + return nil, nil, HOOK_GENERIC_ERROR, fmt.Errorf("failed to configure stdout: %v", err) } cmd.Stdin = in var stderr bytes.Buffer From 26a9d7eb42e563d9d99b2eca660c9840215a3c69 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 18:58:31 -0800 Subject: [PATCH 155/196] staticcheck: key package Signed-off-by: deepthi --- go/vt/key/key.go | 8 ++++---- go/vt/key/key_test.go | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go/vt/key/key.go b/go/vt/key/key.go index e64054fafa6..88c51e26f22 100644 --- a/go/vt/key/key.go +++ b/go/vt/key/key.go @@ -165,8 +165,8 @@ func KeyRangeEqual(left, right *topodatapb.KeyRange) bool { if right == nil { return len(left.Start) == 0 && len(left.End) == 0 } - return bytes.Compare(left.Start, right.Start) == 0 && - bytes.Compare(left.End, right.End) == 0 + return bytes.Equal(left.Start, right.Start) && + bytes.Equal(left.End, right.End) } // KeyRangeStartEqual returns true if both key ranges have the same start @@ -177,7 +177,7 @@ func KeyRangeStartEqual(left, right *topodatapb.KeyRange) bool { if right == nil { return len(left.Start) == 0 } - return bytes.Compare(left.Start, right.Start) == 0 + return bytes.Equal(left.Start, right.Start) } // KeyRangeEndEqual returns true if both key ranges have the same end @@ -188,7 +188,7 @@ func KeyRangeEndEqual(left, right *topodatapb.KeyRange) bool { if right == nil { return len(left.End) == 0 } - return bytes.Compare(left.End, right.End) == 0 + return bytes.Equal(left.End, right.End) } // For more info on the following functions, see: diff --git a/go/vt/key/key_test.go b/go/vt/key/key_test.go index 7a7fe46e187..b6e2229e760 100644 --- a/go/vt/key/key_test.go +++ b/go/vt/key/key_test.go @@ -131,7 +131,7 @@ func TestEvenShardsKeyRange(t *testing.T) { // Now verify that ParseKeyRangeParts() produces the same KeyRange object as // we do. parts := strings.Split(tc.wantSpec, "-") - kr, err := ParseKeyRangeParts(parts[0], parts[1]) + kr, _ := ParseKeyRangeParts(parts[0], parts[1]) if !proto.Equal(got, kr) { t.Errorf("EvenShardsKeyRange(%v, %v) != ParseKeyRangeParts(%v, %v): (%x, %x) != (%x, %x)", tc.i, tc.n, parts[0], parts[1], got.Start, got.End, kr.Start, kr.End) } From deadd837fdfa1b3a31049b32d5bc0b63143a8d67 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 19:15:58 -0800 Subject: [PATCH 156/196] staticcheck: logutil package Signed-off-by: deepthi --- go/vt/logutil/throttled_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/logutil/throttled_test.go b/go/vt/logutil/throttled_test.go index 7f37e9e8681..f7c7097d48b 100644 --- a/go/vt/logutil/throttled_test.go +++ b/go/vt/logutil/throttled_test.go @@ -51,7 +51,7 @@ func TestThrottledLogger(t *testing.T) { if got, want := skippedCount(tl), 0; got != want { t.Errorf("skippedCount is %v but was expecting %v after waiting", got, want) } - if got := time.Now().Sub(start); got < interval { + if got := time.Since(start); got < interval { t.Errorf("didn't wait long enough before logging, got %v, want >= %v", got, interval) } From 6dd12c52df1c3cdc070120aa9e868eb2535ae72f Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 19:30:22 -0800 Subject: [PATCH 157/196] staticcheck: mysqlctl package Signed-off-by: deepthi --- go/vt/mysqlctl/backup.go | 2 +- go/vt/mysqlctl/mycnf_test.go | 6 +++--- go/vt/mysqlctl/mysqld.go | 12 ++++++------ go/vt/mysqlctl/replication.go | 7 ++++--- go/vt/mysqlctl/schema.go | 2 +- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/go/vt/mysqlctl/backup.go b/go/vt/mysqlctl/backup.go index 474c78b9769..2248cfb4bf2 100644 --- a/go/vt/mysqlctl/backup.go +++ b/go/vt/mysqlctl/backup.go @@ -263,7 +263,7 @@ func Restore( err = ErrNoBackup } - if err = PopulateMetadataTables(mysqld, localMetadata); err == nil { + if err2 := PopulateMetadataTables(mysqld, localMetadata); err2 == nil { err = ErrNoBackup } return mysql.Position{}, err diff --git a/go/vt/mysqlctl/mycnf_test.go b/go/vt/mysqlctl/mycnf_test.go index 5bc438c3c84..0298b7f8713 100644 --- a/go/vt/mysqlctl/mycnf_test.go +++ b/go/vt/mysqlctl/mycnf_test.go @@ -86,7 +86,7 @@ func TestMycnf(t *testing.T) { // 3. go test // 4. \rm $VTROOT/vthook/make_mycnf // 5. Add No Prefix back - +//lint:ignore U1000 Test for Mycnf hook changes func NoTestMycnfHook(t *testing.T) { os.Setenv("MYSQL_FLAVOR", "MariaDB") uid := uint32(11111) @@ -105,11 +105,11 @@ func NoTestMycnfHook(t *testing.T) { // this is not being passed, so it should be nil os.Setenv("MY_VAR", "myvalue") - dbcfgs, err := dbconfigs.Init(cnf.SocketFile) + dbcfgs, _ := dbconfigs.Init(cnf.SocketFile) mysqld := NewMysqld(dbcfgs) servenv.OnClose(mysqld.Close) - err = mysqld.InitConfig(cnf) + err := mysqld.InitConfig(cnf) if err != nil { t.Errorf("err: %v", err) } diff --git a/go/vt/mysqlctl/mysqld.go b/go/vt/mysqlctl/mysqld.go index 713e1679a7b..c491e67fef2 100644 --- a/go/vt/mysqlctl/mysqld.go +++ b/go/vt/mysqlctl/mysqld.go @@ -686,22 +686,22 @@ func (mysqld *Mysqld) RefreshConfig(ctx context.Context, cnf *Mycnf) error { } f, err := ioutil.TempFile(path.Dir(cnf.path), "my.cnf") if err != nil { - return fmt.Errorf("Could not create temp file: %v", err) + return fmt.Errorf("could not create temp file: %v", err) } defer os.Remove(f.Name()) err = mysqld.initConfig(root, cnf, f.Name()) if err != nil { - return fmt.Errorf("Could not initConfig in %v: %v", f.Name(), err) + return fmt.Errorf("could not initConfig in %v: %v", f.Name(), err) } existing, err := ioutil.ReadFile(cnf.path) if err != nil { - return fmt.Errorf("Could not read existing file %v: %v", cnf.path, err) + return fmt.Errorf("could not read existing file %v: %v", cnf.path, err) } updated, err := ioutil.ReadFile(f.Name()) if err != nil { - return fmt.Errorf("Could not read updated file %v: %v", f.Name(), err) + return fmt.Errorf("could not read updated file %v: %v", f.Name(), err) } if bytes.Equal(existing, updated) { @@ -712,11 +712,11 @@ func (mysqld *Mysqld) RefreshConfig(ctx context.Context, cnf *Mycnf) error { backupPath := cnf.path + ".previous" err = os.Rename(cnf.path, backupPath) if err != nil { - return fmt.Errorf("Could not back up existing %v: %v", cnf.path, err) + return fmt.Errorf("could not back up existing %v: %v", cnf.path, err) } err = os.Rename(f.Name(), cnf.path) if err != nil { - return fmt.Errorf("Could not move %v to %v: %v", f.Name(), cnf.path, err) + return fmt.Errorf("could not move %v to %v: %v", f.Name(), cnf.path, err) } log.Infof("Updated my.cnf. Backup of previous version available in %v", backupPath) diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 9a0c9632004..028cb3488e1 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -273,9 +273,12 @@ func (mysqld *Mysqld) ResetReplication(ctx context.Context) error { // // Array indices for the results of SHOW PROCESSLIST. const ( + //lint:ignore U1000 needed for correct indexing of result columns colConnectionID = iota + //lint:ignore U1000 needed for correct indexing of result columns colUsername colClientAddr + //lint:ignore U1000 needed for correct indexing of result columns colDbName colCommand ) @@ -312,9 +315,7 @@ func FindSlaves(mysqld MysqlDaemon) ([]string, error) { if err != nil { return nil, fmt.Errorf("FindSlaves: LookupHost failed %v", err) } - for _, ip := range ips { - addrs = append(addrs, ip) - } + addrs = append(addrs, ips...) } } diff --git a/go/vt/mysqlctl/schema.go b/go/vt/mysqlctl/schema.go index e9d9518a420..2a06a04ba24 100644 --- a/go/vt/mysqlctl/schema.go +++ b/go/vt/mysqlctl/schema.go @@ -32,7 +32,7 @@ import ( tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" ) -var autoIncr = regexp.MustCompile(" AUTO_INCREMENT=\\d+") +var autoIncr = regexp.MustCompile(` AUTO_INCREMENT=\\d+`) // executeSchemaCommands executes some SQL commands, using the mysql // command line tool. It uses the dba connection parameters, with credentials. From c3ea63e7fb48e12f5c184ed1e8249671c9e7447a Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 19:33:45 -0800 Subject: [PATCH 158/196] staticcheck: schemamanager package Signed-off-by: deepthi --- go/vt/schemamanager/local_controller_test.go | 4 ++-- go/vt/schemamanager/schemamanager.go | 2 +- go/vt/schemamanager/schemamanager_test.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go/vt/schemamanager/local_controller_test.go b/go/vt/schemamanager/local_controller_test.go index 801fea44a51..cd48fd30d18 100644 --- a/go/vt/schemamanager/local_controller_test.go +++ b/go/vt/schemamanager/local_controller_test.go @@ -59,11 +59,11 @@ func TestLocalControllerOpen(t *testing.T) { t.Fatalf("Open should fail, no such dir, but got: %v", err) } - schemaChangeDir, err := ioutil.TempDir("", "localcontroller-test") + schemaChangeDir, _ := ioutil.TempDir("", "localcontroller-test") defer os.RemoveAll(schemaChangeDir) // create a file under schema change dir - _, err = os.Create(path.Join(schemaChangeDir, "create_test_table.sql")) + _, err := os.Create(path.Join(schemaChangeDir, "create_test_table.sql")) if err != nil { t.Fatalf("failed to create sql file, error: %v", err) } diff --git a/go/vt/schemamanager/schemamanager.go b/go/vt/schemamanager/schemamanager.go index 1f381f0dad1..47a270cbe2f 100644 --- a/go/vt/schemamanager/schemamanager.go +++ b/go/vt/schemamanager/schemamanager.go @@ -132,7 +132,7 @@ func Run(ctx context.Context, controller Controller, executor Executor) error { } if result.ExecutorErr != "" || len(result.FailedShards) > 0 { out, _ := json.MarshalIndent(result, "", " ") - return fmt.Errorf("Schema change failed, ExecuteResult: %v\n", string(out)) + return fmt.Errorf("schema change failed, ExecuteResult: %v", string(out)) } return nil } diff --git a/go/vt/schemamanager/schemamanager_test.go b/go/vt/schemamanager/schemamanager_test.go index 38047f82222..fa392012964 100644 --- a/go/vt/schemamanager/schemamanager_test.go +++ b/go/vt/schemamanager/schemamanager_test.go @@ -189,7 +189,7 @@ func TestSchemaManagerExecutorFail(t *testing.T) { ctx := context.Background() err := Run(ctx, controller, executor) - if err == nil || !strings.Contains(err.Error(), "Schema change failed") { + if err == nil || !strings.Contains(err.Error(), "schema change failed") { t.Fatalf("schema change should fail, but got err: %v", err) } } From 1a47e61730f965fbdfa3018c2a93bee301224060 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 19:36:16 -0800 Subject: [PATCH 159/196] staticcheck: servenv package Signed-off-by: deepthi --- go/vt/servenv/grpc_auth.go | 5 +++-- go/vt/servenv/grpc_server_auth_static.go | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/go/vt/servenv/grpc_auth.go b/go/vt/servenv/grpc_auth.go index 42bcfbc7073..4008cf6c542 100644 --- a/go/vt/servenv/grpc_auth.go +++ b/go/vt/servenv/grpc_auth.go @@ -22,6 +22,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" "vitess.io/vitess/go/vt/log" ) @@ -57,7 +58,7 @@ func FakeAuthStreamInterceptor(srv interface{}, stream grpc.ServerStream, info * if fakeDummyAuthenticate(stream.Context()) { return handler(srv, stream) } - return grpc.Errorf(codes.Unauthenticated, "username and password must be provided") + return status.Errorf(codes.Unauthenticated, "username and password must be provided") } // FakeAuthUnaryInterceptor fake interceptor to test plugin @@ -65,7 +66,7 @@ func FakeAuthUnaryInterceptor(ctx context.Context, req interface{}, info *grpc.U if fakeDummyAuthenticate(ctx) { return handler(ctx, req) } - return nil, grpc.Errorf(codes.Unauthenticated, "username and password must be provided") + return nil, status.Errorf(codes.Unauthenticated, "username and password must be provided") } func fakeDummyAuthenticate(ctx context.Context) bool { diff --git a/go/vt/servenv/grpc_server_auth_static.go b/go/vt/servenv/grpc_server_auth_static.go index 27fa9d231eb..e8b982fc4c5 100644 --- a/go/vt/servenv/grpc_server_auth_static.go +++ b/go/vt/servenv/grpc_server_auth_static.go @@ -23,9 +23,9 @@ import ( "io/ioutil" "golang.org/x/net/context" - "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" "vitess.io/vitess/go/vt/log" ) @@ -56,7 +56,7 @@ type StaticAuthPlugin struct { func (sa *StaticAuthPlugin) Authenticate(ctx context.Context, fullMethod string) (context.Context, error) { if md, ok := metadata.FromIncomingContext(ctx); ok { if len(md["username"]) == 0 || len(md["password"]) == 0 { - return nil, grpc.Errorf(codes.Unauthenticated, "username and password must be provided") + return nil, status.Errorf(codes.Unauthenticated, "username and password must be provided") } username := md["username"][0] password := md["password"][0] @@ -65,9 +65,9 @@ func (sa *StaticAuthPlugin) Authenticate(ctx context.Context, fullMethod string) return ctx, nil } } - return nil, grpc.Errorf(codes.PermissionDenied, "auth failure: caller %q provided invalid credentials", username) + return nil, status.Errorf(codes.PermissionDenied, "auth failure: caller %q provided invalid credentials", username) } - return nil, grpc.Errorf(codes.Unauthenticated, "username and password must be provided") + return nil, status.Errorf(codes.Unauthenticated, "username and password must be provided") } func staticAuthPluginInitializer() (Authenticator, error) { From 73edfaebeccc5e6185c9227140185badaa979282 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 19:38:13 -0800 Subject: [PATCH 160/196] staticcheck: sqlannotation package Signed-off-by: deepthi --- go/vt/sqlannotation/sqlannotation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/sqlannotation/sqlannotation.go b/go/vt/sqlannotation/sqlannotation.go index db18714f98c..c8e20328720 100644 --- a/go/vt/sqlannotation/sqlannotation.go +++ b/go/vt/sqlannotation/sqlannotation.go @@ -82,7 +82,7 @@ func AddKeyspaceIDs(sql string, keyspaceIDs [][]byte, marginComments string) str func ExtractKeyspaceIDS(sql string) (keyspaceIDs [][]byte, err error) { _, comments := sqlparser.SplitMarginComments(sql) keyspaceIDString, hasKeyspaceID := extractStringBetween(comments.Trailing, "/* vtgate:: keyspace_id:", " ") - hasUnfriendlyAnnotation := (strings.Index(sql, filteredReplicationUnfriendlyAnnotation) != -1) + hasUnfriendlyAnnotation := strings.Contains(sql, filteredReplicationUnfriendlyAnnotation) if !hasKeyspaceID { if hasUnfriendlyAnnotation { return nil, &ExtractKeySpaceIDError{ From ca4ed90b302186275edfcce6ba12af826ca4567a Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 19:42:21 -0800 Subject: [PATCH 161/196] staticcheck: srvtopo package Signed-off-by: deepthi --- go/vt/srvtopo/keyspace_filtering_server.go | 4 ++-- go/vt/srvtopo/resilient_server_flaky_test.go | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go/vt/srvtopo/keyspace_filtering_server.go b/go/vt/srvtopo/keyspace_filtering_server.go index 32b264001cc..6e272cf1939 100644 --- a/go/vt/srvtopo/keyspace_filtering_server.go +++ b/go/vt/srvtopo/keyspace_filtering_server.go @@ -29,11 +29,11 @@ import ( var ( // ErrNilUnderlyingServer is returned when attempting to create a new keyspace // filtering server if a nil underlying server implementation is provided. - ErrNilUnderlyingServer = fmt.Errorf("Unable to construct filtering server without an underlying server") + ErrNilUnderlyingServer = fmt.Errorf("unable to construct filtering server without an underlying server") // ErrTopoServerNotAvailable is returned if a caller tries to access the // topo.Server supporting this srvtopo.Server. - ErrTopoServerNotAvailable = fmt.Errorf("Cannot access underlying topology server when keyspace filtering is enabled") + ErrTopoServerNotAvailable = fmt.Errorf("cannot access underlying topology server when keyspace filtering is enabled") ) // NewKeyspaceFilteringServer constructs a new server based on the provided diff --git a/go/vt/srvtopo/resilient_server_flaky_test.go b/go/vt/srvtopo/resilient_server_flaky_test.go index 184174cccf1..e40d9500c32 100644 --- a/go/vt/srvtopo/resilient_server_flaky_test.go +++ b/go/vt/srvtopo/resilient_server_flaky_test.go @@ -105,7 +105,7 @@ func TestGetSrvKeyspace(t *testing.T) { } expiry = time.Now().Add(5 * time.Second) for { - got, err = rs.GetSrvKeyspace(context.Background(), "test_cell", "test_ks") + _, err = rs.GetSrvKeyspace(context.Background(), "test_cell", "test_ks") if topo.IsErrType(err, topo.NoNode) { break } @@ -138,7 +138,7 @@ func TestGetSrvKeyspace(t *testing.T) { // Now simulate a topo service error and see that the last value is // cached for at least half of the expected ttl. errorTestStart := time.Now() - errorReqsBefore, _ := rs.counts.Counts()[errorCategory] + errorReqsBefore := rs.counts.Counts()[errorCategory] forceErr := fmt.Errorf("test topo error") factory.SetError(forceErr) @@ -234,7 +234,7 @@ func TestGetSrvKeyspace(t *testing.T) { // Check that the expected number of errors were counted during the // interval - errorReqs, _ := rs.counts.Counts()[errorCategory] + errorReqs := rs.counts.Counts()[errorCategory] expectedErrors := int64(time.Since(errorTestStart) / *srvTopoCacheRefresh) if errorReqs-errorReqsBefore > expectedErrors { t.Errorf("expected <= %v error requests got %d", expectedErrors, errorReqs-errorReqsBefore) From 3d833306db0d067e1faec68f3c3fb950e5bba81c Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 19:48:17 -0800 Subject: [PATCH 162/196] staticcheck: tableacl package Signed-off-by: deepthi --- go/vt/tableacl/tableacl.go | 8 ++++---- go/vt/tableacl/tableacl_test.go | 8 ++++---- go/vt/vttablet/tabletserver/query_engine.go | 2 +- go/vt/vttablet/tabletserver/query_executor_test.go | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go/vt/tableacl/tableacl.go b/go/vt/tableacl/tableacl.go index 8e4624a43ab..dd15c7eb708 100644 --- a/go/vt/tableacl/tableacl.go +++ b/go/vt/tableacl/tableacl.go @@ -121,7 +121,7 @@ func (tacl *tableACL) init(configFile string, aclCB func()) error { // try to parse tableacl as json file if jsonErr := json2.Unmarshal(data, config); jsonErr != nil { log.Infof("unable to parse tableACL config file as a json file: %v", jsonErr) - return fmt.Errorf("Unable to unmarshal Table ACL data: %v", data) + return fmt.Errorf("unable to unmarshal Table ACL data: %v", data) } } return tacl.Set(config) @@ -176,7 +176,7 @@ func load(config *tableaclpb.Config, newACL func([]string) (acl.ACL, error)) (en func (tacl *tableACL) aclFactory() (acl.Factory, error) { if tacl.factory == nil { - return GetCurrentAclFactory() + return GetCurrentACLFactory() } return tacl.factory, nil } @@ -301,8 +301,8 @@ func SetDefaultACL(name string) { defaultACL = name } -// GetCurrentAclFactory returns current table acl implementation. -func GetCurrentAclFactory() (acl.Factory, error) { +// GetCurrentACLFactory returns current table acl implementation. +func GetCurrentACLFactory() (acl.Factory, error) { mu.Lock() defer mu.Unlock() if len(acls) == 0 { diff --git a/go/vt/tableacl/tableacl_test.go b/go/vt/tableacl/tableacl_test.go index 23fc31a7a19..68e319508f1 100644 --- a/go/vt/tableacl/tableacl_test.go +++ b/go/vt/tableacl/tableacl_test.go @@ -221,7 +221,7 @@ func TestGetCurrentAclFactory(t *testing.T) { name := "tableacl-name-TestGetCurrentAclFactory" aclFactory := &simpleacl.Factory{} Register(name+"-1", aclFactory) - f, err := GetCurrentAclFactory() + f, err := GetCurrentACLFactory() if err != nil { t.Errorf("Fail to get current ACL Factory: %v", err) } @@ -229,13 +229,13 @@ func TestGetCurrentAclFactory(t *testing.T) { t.Fatalf("should return registered acl factory even if default acl is not set.") } Register(name+"-2", aclFactory) - _, err = GetCurrentAclFactory() + _, err = GetCurrentACLFactory() if err == nil { t.Fatalf("there are more than one acl factories, but the default is not set") } } -func TestGetCurrentAclFactoryWithWrongDefault(t *testing.T) { +func TestGetCurrentACLFactoryWithWrongDefault(t *testing.T) { acls = make(map[string]acl.Factory) defaultACL = "" name := "tableacl-name-TestGetCurrentAclFactoryWithWrongDefault" @@ -243,7 +243,7 @@ func TestGetCurrentAclFactoryWithWrongDefault(t *testing.T) { Register(name+"-1", aclFactory) Register(name+"-2", aclFactory) SetDefaultACL("wrong_name") - _, err := GetCurrentAclFactory() + _, err := GetCurrentACLFactory() if err == nil { t.Fatalf("there are more than one acl factories, but the default given does not match any of these.") } diff --git a/go/vt/vttablet/tabletserver/query_engine.go b/go/vt/vttablet/tabletserver/query_engine.go index c8388d6abeb..355a6dea6e4 100644 --- a/go/vt/vttablet/tabletserver/query_engine.go +++ b/go/vt/vttablet/tabletserver/query_engine.go @@ -217,7 +217,7 @@ func NewQueryEngine(checker connpool.MySQLChecker, se *schema.Engine, config tab qe.strictTransTables = config.EnforceStrictTransTables if config.TableACLExemptACL != "" { - if f, err := tableacl.GetCurrentAclFactory(); err == nil { + if f, err := tableacl.GetCurrentACLFactory(); err == nil { if exemptACL, err := f.New([]string{config.TableACLExemptACL}); err == nil { log.Infof("Setting Table ACL exempt rule for %v", config.TableACLExemptACL) qe.exemptACL = exemptACL diff --git a/go/vt/vttablet/tabletserver/query_executor_test.go b/go/vt/vttablet/tabletserver/query_executor_test.go index 334c026a28b..d131ac81583 100644 --- a/go/vt/vttablet/tabletserver/query_executor_test.go +++ b/go/vt/vttablet/tabletserver/query_executor_test.go @@ -1830,7 +1830,7 @@ func TestQueryExecutorTableAclExemptACL(t *testing.T) { // table acl should be ignored since this is an exempt user. username = "exempt-acl" - f, _ := tableacl.GetCurrentAclFactory() + f, _ := tableacl.GetCurrentACLFactory() if tsv.qe.exemptACL, err = f.New([]string{username}); err != nil { t.Fatalf("Cannot load exempt ACL for Table ACL: %v", err) } From 41babfb4d600854056b0cf2d9a04dc6f87fa3e78 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 20:06:18 -0800 Subject: [PATCH 163/196] staticcheck: throttler package Signed-off-by: deepthi --- go/vt/throttler/max_replication_lag_module.go | 4 ++-- go/vt/throttler/result.go | 4 ++-- go/vt/throttler/throttler.go | 4 ++-- go/vt/throttler/throttler_test.go | 9 +++------ 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/go/vt/throttler/max_replication_lag_module.go b/go/vt/throttler/max_replication_lag_module.go index 549d2619f8a..7cab0bf5681 100644 --- a/go/vt/throttler/max_replication_lag_module.go +++ b/go/vt/throttler/max_replication_lag_module.go @@ -37,8 +37,8 @@ type state string const ( stateIncreaseRate state = "I" - stateDecreaseAndGuessRate = "D" - stateEmergency = "E" + stateDecreaseAndGuessRate state = "D" + stateEmergency state = "E" ) type replicationLagChange int diff --git a/go/vt/throttler/result.go b/go/vt/throttler/result.go index 99bc6972030..1266a40cf37 100644 --- a/go/vt/throttler/result.go +++ b/go/vt/throttler/result.go @@ -30,8 +30,8 @@ type rateChange string const ( increasedRate rateChange = "increased" - decreasedRate = "decreased" - unchangedRate = "not changed" + decreasedRate rateChange = "decreased" + unchangedRate rateChange = "not changed" ) type goodOrBadRate string diff --git a/go/vt/throttler/throttler.go b/go/vt/throttler/throttler.go index 179b6f1059f..4db59307ede 100644 --- a/go/vt/throttler/throttler.go +++ b/go/vt/throttler/throttler.go @@ -157,7 +157,7 @@ func newThrottler(manager *managerImpl, name, unit string, threadCount int, maxR } runningThreads := make(map[int]bool, threadCount) - threadThrottlers := make([]*threadThrottler, threadCount, threadCount) + threadThrottlers := make([]*threadThrottler, threadCount) for i := 0; i < threadCount; i++ { threadThrottlers[i] = newThreadThrottler(i, actualRateHistory) runningThreads[i] = true @@ -171,7 +171,7 @@ func newThrottler(manager *managerImpl, name, unit string, threadCount int, maxR maxReplicationLagModule: maxReplicationLagModule, rateUpdateChan: rateUpdateChan, threadThrottlers: threadThrottlers, - threadFinished: make([]bool, threadCount, threadCount), + threadFinished: make([]bool, threadCount), runningThreads: runningThreads, nowFunc: nowFunc, actualRateHistory: actualRateHistory, diff --git a/go/vt/throttler/throttler_test.go b/go/vt/throttler/throttler_test.go index b8d6faf6363..6aacf7b67b4 100644 --- a/go/vt/throttler/throttler_test.go +++ b/go/vt/throttler/throttler_test.go @@ -134,12 +134,9 @@ func BenchmarkThrottlerDisabled(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - for { - backoff := throttler.Throttle(0) - if backoff != NotThrottled { - b.Fatalf("unthrottled throttler should never have throttled us: %v", backoff) - } - break + backoff := throttler.Throttle(0) + if backoff != NotThrottled { + b.Fatalf("unthrottled throttler should never have throttled us: %v", backoff) } } } From 5169d5bf1da468358dce86ac556c7a3144ae3c76 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 20:21:19 -0800 Subject: [PATCH 164/196] staticcheck: topo package Signed-off-by: deepthi --- go/vt/tlstest/tlstest_test.go | 36 +++++++++++++++++++---------------- go/vt/topo/keyspace.go | 10 +++++----- go/vt/topo/keyspace_test.go | 10 +++++----- go/vt/topo/wildcards.go | 4 ++-- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/go/vt/tlstest/tlstest_test.go b/go/vt/tlstest/tlstest_test.go index a88ab1c5857..d033795582e 100644 --- a/go/vt/tlstest/tlstest_test.go +++ b/go/vt/tlstest/tlstest_test.go @@ -80,20 +80,21 @@ func TestClientServer(t *testing.T) { // // Positive case: accept on server side, connect a client, send data. // - + var clientErr error wg.Add(1) go func() { defer wg.Done() - clientConn, err := tls.Dial("tcp", addr, clientConfig) - if err != nil { - t.Fatalf("Dial failed: %v", err) + clientConn, clientErr := tls.Dial("tcp", addr, clientConfig) + if clientErr == nil { + clientConn.Write([]byte{42}) + clientConn.Close() } - - clientConn.Write([]byte{42}) - clientConn.Close() }() serverConn, err := listener.Accept() + if clientErr != nil { + t.Fatalf("Dial failed: %v", clientErr) + } if err != nil { t.Fatalf("Accept failed: %v", err) } @@ -123,23 +124,26 @@ func TestClientServer(t *testing.T) { t.Fatalf("TLSClientConfig failed: %v", err) } + var serverErr error wg.Add(1) go func() { // We expect the Accept to work, but the first read to fail. defer wg.Done() - serverConn, err := listener.Accept() - if err != nil { - t.Fatalf("Connection failed: %v", err) - } - + serverConn, serverErr := listener.Accept() // This will fail. - result := make([]byte, 1) - if n, err := serverConn.Read(result); err == nil { - fmt.Printf("Was able to read from server: %v\n", n) + if serverErr == nil { + result := make([]byte, 1) + if n, err := serverConn.Read(result); err == nil { + fmt.Printf("Was able to read from server: %v\n", n) + } + serverConn.Close() } - serverConn.Close() }() + if serverErr != nil { + t.Fatalf("Connection failed: %v", serverErr) + } + // When using TLS 1.2, the Dial will fail. // With TLS 1.3, the Dial will succeed and the first Read will fail. clientConn, err := tls.Dial("tcp", addr, badClientConfig) diff --git a/go/vt/topo/keyspace.go b/go/vt/topo/keyspace.go index 521753adafb..96a58fd970b 100644 --- a/go/vt/topo/keyspace.go +++ b/go/vt/topo/keyspace.go @@ -64,25 +64,25 @@ func (ki *KeyspaceInfo) CheckServedFromMigration(tabletType topodatapb.TabletTyp // master is a special case with a few extra checks if tabletType == topodatapb.TabletType_MASTER { if !remove { - return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Cannot add master back to %v", ki.keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot add master back to %v", ki.keyspace) } if len(cells) > 0 { - return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Cannot migrate only some cells for master removal in keyspace %v", ki.keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot migrate only some cells for master removal in keyspace %v", ki.keyspace) } if len(ki.ServedFroms) > 1 { - return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Cannot migrate master into %v until everything else is migrated", ki.keyspace) + return vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "cannot migrate master into %v until everything else is migrated", ki.keyspace) } } // we can't remove a type we don't have if ki.GetServedFrom(tabletType) == nil && remove { - return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "Supplied type cannot be migrated") + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "supplied type cannot be migrated") } // check the keyspace is consistent in any case for _, ksf := range ki.ServedFroms { if ksf.Keyspace != keyspace { - return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "Inconsistent keypace specified in migration: %v != %v for type %v", keyspace, ksf.Keyspace, ksf.TabletType) + return vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "inconsistent keypace specified in migration: %v != %v for type %v", keyspace, ksf.Keyspace, ksf.TabletType) } } diff --git a/go/vt/topo/keyspace_test.go b/go/vt/topo/keyspace_test.go index 8a6bd06d997..ac9ed109c05 100644 --- a/go/vt/topo/keyspace_test.go +++ b/go/vt/topo/keyspace_test.go @@ -95,10 +95,10 @@ func TestUpdateServedFromMap(t *testing.T) { } // couple error cases - if err := ki.UpdateServedFromMap(topodatapb.TabletType_RDONLY, []string{"second"}, "othersource", true, allCells); err == nil || (err.Error() != "Inconsistent keypace specified in migration: othersource != source for type MASTER" && err.Error() != "Inconsistent keypace specified in migration: othersource != source for type RDONLY") { + if err := ki.UpdateServedFromMap(topodatapb.TabletType_RDONLY, []string{"second"}, "othersource", true, allCells); err == nil || (err.Error() != "inconsistent keypace specified in migration: othersource != source for type MASTER" && err.Error() != "inconsistent keypace specified in migration: othersource != source for type RDONLY") { t.Fatalf("different keyspace should fail: %v", err) } - if err := ki.UpdateServedFromMap(topodatapb.TabletType_MASTER, nil, "source", true, allCells); err == nil || err.Error() != "Cannot migrate master into ks until everything else is migrated" { + if err := ki.UpdateServedFromMap(topodatapb.TabletType_MASTER, nil, "source", true, allCells); err == nil || err.Error() != "cannot migrate master into ks until everything else is migrated" { t.Fatalf("migrate the master early should have failed: %v", err) } @@ -112,12 +112,12 @@ func TestUpdateServedFromMap(t *testing.T) { }) { t.Fatalf("remove all cells failed: %v", ki) } - if err := ki.UpdateServedFromMap(topodatapb.TabletType_RDONLY, nil, "source", true, allCells); err == nil || err.Error() != "Supplied type cannot be migrated" { + if err := ki.UpdateServedFromMap(topodatapb.TabletType_RDONLY, nil, "source", true, allCells); err == nil || err.Error() != "supplied type cannot be migrated" { t.Fatalf("migrate rdonly again should have failed: %v", err) } // finally migrate the master - if err := ki.UpdateServedFromMap(topodatapb.TabletType_MASTER, []string{"second"}, "source", true, allCells); err == nil || err.Error() != "Cannot migrate only some cells for master removal in keyspace ks" { + if err := ki.UpdateServedFromMap(topodatapb.TabletType_MASTER, []string{"second"}, "source", true, allCells); err == nil || err.Error() != "cannot migrate only some cells for master removal in keyspace ks" { t.Fatalf("migrate master with cells should have failed: %v", err) } if err := ki.UpdateServedFromMap(topodatapb.TabletType_MASTER, nil, "source", true, allCells); err != nil || ki.ServedFroms != nil { @@ -125,7 +125,7 @@ func TestUpdateServedFromMap(t *testing.T) { } // error case again - if err := ki.UpdateServedFromMap(topodatapb.TabletType_MASTER, nil, "source", true, allCells); err == nil || err.Error() != "Supplied type cannot be migrated" { + if err := ki.UpdateServedFromMap(topodatapb.TabletType_MASTER, nil, "source", true, allCells); err == nil || err.Error() != "supplied type cannot be migrated" { t.Fatalf("migrate the master again should have failed: %v", err) } } diff --git a/go/vt/topo/wildcards.go b/go/vt/topo/wildcards.go index 0448e5cf1f1..92d76a0187c 100644 --- a/go/vt/topo/wildcards.go +++ b/go/vt/topo/wildcards.go @@ -107,7 +107,7 @@ func (ts *Server) ResolveShardWildcard(ctx context.Context, param string) ([]Key for _, s := range shardNames { matched, err := path.Match(shard, s) if err != nil { - return nil, vterrors.Wrapf(err, "Invalid pattern %v", shard) + return nil, vterrors.Wrapf(err, "invalid pattern %v", shard) } if matched { result = append(result, KeyspaceShard{matchedKeyspace, s}) @@ -130,7 +130,7 @@ func (ts *Server) ResolveShardWildcard(ctx context.Context, param string) ([]Key // no shard, ignore default: // other error - return nil, vterrors.Wrapf(err, "Cannot read shard %v/%v", matchedKeyspace, shard) + return nil, vterrors.Wrapf(err, "cannot read shard %v/%v", matchedKeyspace, shard) } } else { // keyspace and shards are not wildcards, just add the value From 9239a4aea7658ee41ce1dc2ac028d0ecb7474ad9 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 20:26:57 -0800 Subject: [PATCH 165/196] staticcheck: vtaclcheck package Signed-off-by: deepthi --- go/vt/topotools/rebuild_keyspace.go | 2 +- go/vt/topotools/split.go | 4 ++-- go/vt/topotools/vschema_ddl.go | 4 ++-- go/vt/vtaclcheck/vtaclcheck.go | 2 +- go/vt/vtctl/backup.go | 3 ++- go/vt/vtctl/query.go | 15 ++++++++++++--- go/vt/vtctl/throttler.go | 2 +- go/vt/vtctl/vtctl.go | 14 ++++++-------- 8 files changed, 27 insertions(+), 19 deletions(-) diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index 8a29f1e6231..a9280a0344e 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -180,7 +180,7 @@ func orderAndCheckPartitions(cell string, srvKeyspace *topodatapb.SrvKeyspace) e // this is the custom sharding case, all KeyRanges must be nil continue } - if bytes.Compare(currShard.KeyRange.End, nextShard.KeyRange.Start) != 0 { + if bytes.Equal(currShard.KeyRange.End, nextShard.KeyRange.Start) { return fmt.Errorf("non-contiguous KeyRange values for %v in cell %v at shard %v to %v: %v != %v", tabletType, cell, i, i+1, hex.EncodeToString(currShard.KeyRange.End), hex.EncodeToString(nextShard.KeyRange.Start)) } } diff --git a/go/vt/topotools/split.go b/go/vt/topotools/split.go index 2e2d8b947b3..4055eccbdfa 100644 --- a/go/vt/topotools/split.go +++ b/go/vt/topotools/split.go @@ -101,7 +101,7 @@ func findOverlappingShards(shardMap map[string]*topo.ShardInfo) ([]*OverlappingS si := findIntersectingShard(shardMap, left) if si != nil { if intersect(si, right) { - return nil, fmt.Errorf("Shard %v intersects with more than one shard, this is not supported", si.ShardName()) + return nil, fmt.Errorf("shard %v intersects with more than one shard, this is not supported", si.ShardName()) } foundOne = true right = append(right, si) @@ -111,7 +111,7 @@ func findOverlappingShards(shardMap map[string]*topo.ShardInfo) ([]*OverlappingS si = findIntersectingShard(shardMap, right) if si != nil { if intersect(si, left) { - return nil, fmt.Errorf("Shard %v intersects with more than one shard, this is not supported", si.ShardName()) + return nil, fmt.Errorf("shard %v intersects with more than one shard, this is not supported", si.ShardName()) } foundOne = true left = append(left, si) diff --git a/go/vt/topotools/vschema_ddl.go b/go/vt/topotools/vschema_ddl.go index ed5d6b1c907..f6ccdbc99bc 100644 --- a/go/vt/topotools/vschema_ddl.go +++ b/go/vt/topotools/vschema_ddl.go @@ -45,7 +45,7 @@ func ApplyVSchemaDDL(ksName string, ks *vschemapb.Keyspace, ddl *sqlparser.DDL) var table *vschemapb.Table if !ddl.Table.IsEmpty() { tableName = ddl.Table.Name.String() - table, _ = ks.Tables[tableName] + table = ks.Tables[tableName] } switch ddl.Action { @@ -151,7 +151,7 @@ func ApplyVSchemaDDL(ksName string, ks *vschemapb.Keyspace, ddl *sqlparser.DDL) } } - columns := make([]string, len(ddl.VindexCols), len(ddl.VindexCols)) + columns := make([]string, len(ddl.VindexCols)) for i, col := range ddl.VindexCols { columns[i] = col.String() } diff --git a/go/vt/vtaclcheck/vtaclcheck.go b/go/vt/vtaclcheck/vtaclcheck.go index 5fd8510f3c4..8574ac43f72 100644 --- a/go/vt/vtaclcheck/vtaclcheck.go +++ b/go/vt/vtaclcheck/vtaclcheck.go @@ -62,7 +62,7 @@ func Run() error { func() {}, ) if err != nil { - return fmt.Errorf("Fail to initialize Table ACL: %v", err) + return fmt.Errorf("fail to initialize Table ACL: %v", err) } fmt.Printf("JSON ACL file %s looks good\n", options.ACLFile) diff --git a/go/vt/vtctl/backup.go b/go/vt/vtctl/backup.go index 6af8f8a896f..61fd0231e9b 100644 --- a/go/vt/vtctl/backup.go +++ b/go/vt/vtctl/backup.go @@ -129,12 +129,13 @@ func commandBackupShard(ctx context.Context, wr *wrangler.Wrangler, subFlags *fl // if no other tablet is available and allowMaster is set to true if tabletForBackup == nil && *allowMaster { + ChooseMaster: for i := range tablets { switch tablets[i].Type { case topodatapb.TabletType_MASTER: tabletForBackup = tablets[i].Tablet secondsBehind = 0 - break + break ChooseMaster default: continue } diff --git a/go/vt/vtctl/query.go b/go/vt/vtctl/query.go index 00944a2e97e..1638e474abe 100644 --- a/go/vt/vtctl/query.go +++ b/go/vt/vtctl/query.go @@ -190,11 +190,13 @@ func commandVtGateExecute(ctx context.Context, wr *wrangler.Wrangler, subFlags * bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } qr, err := session.Execute(ctx, subFlags.Arg(0), bindVars) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } if *json { @@ -244,11 +246,13 @@ func commandVtGateExecuteShards(ctx context.Context, wr *wrangler.Wrangler, subF bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } qr, err := vtgateConn.ExecuteShards(ctx, subFlags.Arg(0), *keyspace, shards, bindVars, t, executeOptions) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } if *json { @@ -305,11 +309,13 @@ func commandVtGateExecuteKeyspaceIds(ctx context.Context, wr *wrangler.Wrangler, bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } qr, err := vtgateConn.ExecuteKeyspaceIds(ctx, subFlags.Arg(0), *keyspace, keyspaceIDs, bindVars, t, executeOptions) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } if *json { @@ -343,7 +349,7 @@ func commandVtGateSplitQuery(ctx context.Context, wr *wrangler.Wrangler, subFlag } if (*splitCount == 0 && *numRowsPerQueryPart == 0) || (*splitCount != 0 && *numRowsPerQueryPart != 0) { - return fmt.Errorf("Exactly one of split_count or num_rows_per_query_part"+ + return fmt.Errorf("exactly one of split_count or num_rows_per_query_part"+ "must be nonzero. Got: split_count:%v, num_rows_per_query_part:%v", *splitCount, *numRowsPerQueryPart) } @@ -358,7 +364,7 @@ func commandVtGateSplitQuery(ctx context.Context, wr *wrangler.Wrangler, subFlag case "EQUAL_SPLITS": algorithm = querypb.SplitQueryRequest_EQUAL_SPLITS default: - return fmt.Errorf("Unknown split-query algorithm: %v", algorithmStr) + return fmt.Errorf("unknown split-query algorithm: %v", algorithmStr) } if subFlags.NArg() != 1 { return fmt.Errorf("the argument is required for the VtGateSplitQuery command") @@ -371,6 +377,7 @@ func commandVtGateSplitQuery(ctx context.Context, wr *wrangler.Wrangler, subFlag bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } @@ -434,6 +441,7 @@ func commandVtTabletExecute(ctx context.Context, wr *wrangler.Wrangler, subFlags bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } @@ -443,6 +451,7 @@ func commandVtTabletExecute(ctx context.Context, wr *wrangler.Wrangler, subFlags TabletType: tabletInfo.Tablet.Type, }, subFlags.Arg(1), bindVars, int64(*transactionID), executeOptions) if err != nil { + //lint:ignore ST1005 function name return fmt.Errorf("Execute failed: %v", err) } if *json { @@ -491,7 +500,7 @@ func commandVtTabletBegin(ctx context.Context, wr *wrangler.Wrangler, subFlags * TabletType: tabletInfo.Tablet.Type, }, nil) if err != nil { - return fmt.Errorf("Begin failed: %v", err) + return fmt.Errorf("begin failed: %v", err) } result := map[string]int64{ "transaction_id": transactionID, diff --git a/go/vt/vtctl/throttler.go b/go/vt/vtctl/throttler.go index eba38f905ba..9418b7d1518 100644 --- a/go/vt/vtctl/throttler.go +++ b/go/vt/vtctl/throttler.go @@ -224,7 +224,7 @@ func commandUpdateThrottlerConfiguration(ctx context.Context, wr *wrangler.Wrang protoText := subFlags.Arg(0) configuration := &throttlerdatapb.Configuration{} if err := proto.UnmarshalText(protoText, configuration); err != nil { - return fmt.Errorf("Failed to unmarshal the configuration protobuf text (%v) into a protobuf instance: %v", protoText, err) + return fmt.Errorf("failed to unmarshal the configuration protobuf text (%v) into a protobuf instance: %v", protoText, err) } // Connect to the server. diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index 7dd78e0153b..52908e9a186 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -440,7 +440,7 @@ func addCommand(groupName string, c command) { return } } - panic(fmt.Errorf("Trying to add to missing group %v", groupName)) + panic(fmt.Errorf("trying to add to missing group %v", groupName)) } func addCommandGroup(groupName string) { @@ -524,7 +524,7 @@ func getFileParam(flag, flagFile, name string) (string, error) { } data, err := ioutil.ReadFile(flagFile) if err != nil { - return "", fmt.Errorf("Cannot read file %v: %v", flagFile, err) + return "", fmt.Errorf("cannot read file %v: %v", flagFile, err) } return string(data), nil } @@ -539,15 +539,13 @@ func keyspaceParamsToKeyspaces(ctx context.Context, wr *wrangler.Wrangler, param for _, param := range params { if param[0] == '/' { // this is a topology-specific path - for _, path := range params { - result = append(result, path) - } + result = append(result, params...) } else { // this is not a path, so assume a keyspace name, // possibly with wildcards keyspaces, err := wr.TopoServer().ResolveKeyspaceWildcard(ctx, param) if err != nil { - return nil, fmt.Errorf("Failed to resolve keyspace wildcard %v: %v", param, err) + return nil, fmt.Errorf("failed to resolve keyspace wildcard %v: %v", param, err) } result = append(result, keyspaces...) } @@ -577,7 +575,7 @@ func shardParamsToKeyspaceShards(ctx context.Context, wr *wrangler.Wrangler, par // name / shard name, each possibly with wildcards keyspaceShards, err := wr.TopoServer().ResolveShardWildcard(ctx, param) if err != nil { - return nil, fmt.Errorf("Failed to resolve keyspace/shard wildcard %v: %v", param, err) + return nil, fmt.Errorf("failed to resolve keyspace/shard wildcard %v: %v", param, err) } result = append(result, keyspaceShards...) } @@ -607,7 +605,7 @@ func parseTabletType(param string, types []topodatapb.TabletType) (topodatapb.Ta return topodatapb.TabletType_UNKNOWN, fmt.Errorf("invalid tablet type %v: %v", param, err) } if !topoproto.IsTypeInList(topodatapb.TabletType(tabletType), types) { - return topodatapb.TabletType_UNKNOWN, fmt.Errorf("Type %v is not one of: %v", tabletType, strings.Join(topoproto.MakeStringTypeList(types), " ")) + return topodatapb.TabletType_UNKNOWN, fmt.Errorf("type %v is not one of: %v", tabletType, strings.Join(topoproto.MakeStringTypeList(types), " ")) } return tabletType, nil } From 9b90784977c36f3c6ab9bb298d9fd34b8783f28c Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 20:39:38 -0800 Subject: [PATCH 166/196] staticcheck: vterrors package Signed-off-by: deepthi --- go/vt/vtctld/api.go | 6 ++--- go/vt/vtctld/tablet_stats_cache.go | 22 ++++++++-------- go/vt/vterrors/stack.go | 40 ------------------------------ go/vt/vterrors/vterrors.go | 4 +-- 4 files changed, 15 insertions(+), 57 deletions(-) diff --git a/go/vt/vtctld/api.go b/go/vt/vtctld/api.go index 54da31b7653..e2657720f77 100644 --- a/go/vt/vtctld/api.go +++ b/go/vt/vtctld/api.go @@ -153,7 +153,7 @@ func initAPI(ctx context.Context, ts *topo.Server, actions *ActionRepository, re // Perform an action on a keyspace. case "POST": if keyspace == "" { - return nil, errors.New("A POST request needs a keyspace in the URL") + return nil, errors.New("a POST request needs a keyspace in the URL") } if err := r.ParseForm(); err != nil { return nil, err @@ -161,7 +161,7 @@ func initAPI(ctx context.Context, ts *topo.Server, actions *ActionRepository, re action := r.FormValue("action") if action == "" { - return nil, errors.New("A POST request must specify action") + return nil, errors.New("a POST request must specify action") } return actions.ApplyKeyspaceAction(ctx, action, keyspace, r), nil default: @@ -275,7 +275,7 @@ func initAPI(ctx context.Context, ts *topo.Server, actions *ActionRepository, re if keyspace != "" { srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) if err != nil { - return nil, fmt.Errorf("Can't get server keyspace: %v", err) + return nil, fmt.Errorf("can't get server keyspace: %v", err) } return srvKeyspace, nil } diff --git a/go/vt/vtctld/tablet_stats_cache.go b/go/vt/vtctld/tablet_stats_cache.go index 467476de208..3ee0df82abc 100644 --- a/go/vt/vtctld/tablet_stats_cache.go +++ b/go/vt/vtctld/tablet_stats_cache.go @@ -131,27 +131,27 @@ func (c *tabletStatsCache) StatsUpdate(stats *discovery.TabletStats) { if !ok { // Tablet isn't tracked yet so just add it. - shards, ok := c.statuses[keyspace] + _, ok := c.statuses[keyspace] if !ok { - shards = make(map[string]map[string]map[topodatapb.TabletType][]*discovery.TabletStats) + shards := make(map[string]map[string]map[topodatapb.TabletType][]*discovery.TabletStats) c.statuses[keyspace] = shards } - cells, ok := c.statuses[keyspace][shard] + _, ok = c.statuses[keyspace][shard] if !ok { - cells = make(map[string]map[topodatapb.TabletType][]*discovery.TabletStats) + cells := make(map[string]map[topodatapb.TabletType][]*discovery.TabletStats) c.statuses[keyspace][shard] = cells } - types, ok := c.statuses[keyspace][shard][cell] + _, ok = c.statuses[keyspace][shard][cell] if !ok { - types = make(map[topodatapb.TabletType][]*discovery.TabletStats) + types := make(map[topodatapb.TabletType][]*discovery.TabletStats) c.statuses[keyspace][shard][cell] = types } - tablets, ok := c.statuses[keyspace][shard][cell][tabletType] + _, ok = c.statuses[keyspace][shard][cell][tabletType] if !ok { - tablets = make([]*discovery.TabletStats, 0) + tablets := make([]*discovery.TabletStats, 0) c.statuses[keyspace][shard][cell][tabletType] = tablets } @@ -290,7 +290,7 @@ func (c *tabletStatsCache) typesInTopology(keyspace, cell string) []topodatapb.T func sortTypes(types map[topodatapb.TabletType]bool) []topodatapb.TabletType { var listOfTypes []topodatapb.TabletType for _, tabType := range availableTabletTypes { - if t, _ := types[tabType]; t { + if t := types[tabType]; t { listOfTypes = append(listOfTypes, tabType) } } @@ -490,11 +490,11 @@ func (c *tabletStatsCache) aggregatedData(keyspace, cell, selectedType, selected sum += metricVal count++ } - if unhealthyFound == true { + if unhealthyFound { break } } - if hasTablets == true { + if hasTablets { dataRow[shardIndex] = (sum / count) } else { dataRow[shardIndex] = tabletMissing diff --git a/go/vt/vterrors/stack.go b/go/vt/vterrors/stack.go index 2652c180e96..3b81c0fda83 100644 --- a/go/vt/vterrors/stack.go +++ b/go/vt/vterrors/stack.go @@ -145,43 +145,3 @@ func funcname(name string) string { i = strings.Index(name, ".") return name[i+1:] } - -func trimGOPATH(name, file string) string { - // Here we want to get the source file path relative to the compile time - // GOPATH. As of Go 1.6.x there is no direct way to know the compiled - // GOPATH at runtime, but we can infer the number of path segments in the - // GOPATH. We note that fn.Name() returns the function name qualified by - // the import path, which does not include the GOPATH. Thus we can trim - // segments from the beginning of the file path until the number of path - // separators remaining is one more than the number of path separators in - // the function name. For example, given: - // - // GOPATH /home/user - // file /home/user/src/pkg/sub/file.go - // fn.Name() pkg/sub.Type.Method - // - // We want to produce: - // - // pkg/sub/file.go - // - // From this we can easily see that fn.Name() has one less path separator - // than our desired output. We count separators from the end of the file - // path until it finds two more than in the function name and then move - // one character forward to preserve the initial path segment without a - // leading separator. - const sep = "/" - goal := strings.Count(name, sep) + 2 - i := len(file) - for n := 0; n < goal; n++ { - i = strings.LastIndex(file[:i], sep) - if i == -1 { - // not enough separators found, set i so that the slice expression - // below leaves file unmodified - i = -len(sep) - break - } - } - // get back to 0 or trim the leading separator - file = file[i+len(sep):] - return file -} diff --git a/go/vt/vterrors/vterrors.go b/go/vt/vterrors/vterrors.go index 6f8b7ad4b8d..c798fa8ffb7 100644 --- a/go/vt/vterrors/vterrors.go +++ b/go/vt/vterrors/vterrors.go @@ -202,11 +202,9 @@ func (w *wrapping) Format(s fmt.State, verb rune) { return } - if rune('s') == verb || rune('q') == verb { + if rune('s') == verb || rune('q') == verb { panicIfError(io.WriteString(s, w.Error())) } - - return } // since we can't return an error, let's panic if something goes wrong here From 52592802f614666c010e52fdc126645c8abe8eba Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 20:46:46 -0800 Subject: [PATCH 167/196] staticcheck: vtgate package Signed-off-by: deepthi --- go/vt/vtexplain/vtexplain.go | 2 +- go/vt/vtexplain/vtexplain_vttablet.go | 8 -- go/vt/vtgate/executor.go | 12 +-- go/vt/vtgate/executor_select_test.go | 8 +- go/vt/vtgate/executor_stream_test.go | 4 +- go/vt/vtgate/executor_test.go | 123 +++++++++++++++----------- go/vt/vtgate/queryz_test.go | 4 + go/vt/vtgate/scatter_conn.go | 3 +- go/vt/vtgate/scatter_conn_test.go | 4 +- go/vt/vtgate/tx_conn_test.go | 3 +- go/vt/vtgate/vschema_manager.go | 2 +- go/vt/vtgate/vtgate_test.go | 37 ++++---- 12 files changed, 112 insertions(+), 98 deletions(-) diff --git a/go/vt/vtexplain/vtexplain.go b/go/vt/vtexplain/vtexplain.go index f97edad17f6..8c7d6e6438b 100644 --- a/go/vt/vtexplain/vtexplain.go +++ b/go/vt/vtexplain/vtexplain.go @@ -328,7 +328,7 @@ func ExplainsAsText(explains []*Explain) string { fmt.Fprintf(&b, "\n") } fmt.Fprintf(&b, "----------------------------------------------------------------------\n") - return string(b.Bytes()) + return b.String() } // ExplainsAsJSON returns a json representation of the explains diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index e30727da8b5..4b80522d6f8 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -501,7 +501,6 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* switch node := selStmt.From[0].(type) { case *sqlparser.AliasedTableExpr: table = sqlparser.GetTableName(node.Expr) - break } // For complex select queries just return an empty result @@ -531,12 +530,10 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* } colNames = append(colNames, col) colTypes = append(colTypes, colType) - break case *sqlparser.FuncExpr: // As a shortcut, functions are integral types colNames = append(colNames, sqlparser.String(node)) colTypes = append(colTypes, querypb.Type_INT32) - break case *sqlparser.SQLVal: colNames = append(colNames, sqlparser.String(node)) switch node.Type { @@ -555,11 +552,9 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* default: return fmt.Errorf("unsupported sql value %s", sqlparser.String(node)) } - break default: return fmt.Errorf("unsupported select expression %s", sqlparser.String(node)) } - break case *sqlparser.StarExpr: for col, colType := range colTypeMap { colNames = append(colNames, col) @@ -598,15 +593,12 @@ func (t *explainTablet) HandleQuery(c *mysql.Conn, query string, callback func(* resultJSON, _ := json.MarshalIndent(result, "", " ") log.V(100).Infof("query %s result %s\n", query, string(resultJSON)) - break case sqlparser.StmtBegin, sqlparser.StmtCommit, sqlparser.StmtSet, sqlparser.StmtShow: result = &sqltypes.Result{} - break case sqlparser.StmtInsert, sqlparser.StmtReplace, sqlparser.StmtUpdate, sqlparser.StmtDelete: result = &sqltypes.Result{ RowsAffected: 1, } - break default: return fmt.Errorf("unsupported query %s", query) } diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index ade4811ea72..9eafc481079 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -274,7 +274,7 @@ func (e *Executor) handleExec(ctx context.Context, safeSession *SafeSession, sql logStats.SQL = sql logStats.BindVariables = bindVars result, err := e.destinationExec(ctx, safeSession, sql, bindVars, dest, destKeyspace, destTabletType, logStats) - logStats.ExecuteTime = time.Now().Sub(execStart) + logStats.ExecuteTime = time.Since(execStart) queriesRouted.Add("ShardDirect", int64(logStats.ShardQueries)) return result, err } @@ -394,7 +394,7 @@ func (e *Executor) handleVSchemaDDL(ctx context.Context, safeSession *SafeSessio return errNoKeyspace } - ks, _ := vschema.Keyspaces[ksName] + ks := vschema.Keyspaces[ksName] ks, err := topotools.ApplyVSchemaDDL(ksName, ks, ddl) if err != nil { @@ -917,7 +917,7 @@ func (e *Executor) handleShow(ctx context.Context, safeSession *SafeSession, sql } sort.Strings(ksNames) for _, ksName := range ksNames { - ks, _ := vschema.Keyspaces[ksName] + ks := vschema.Keyspaces[ksName] vindexNames := make([]string, 0, len(ks.Vindexes)) for name := range ks.Vindexes { @@ -925,7 +925,7 @@ func (e *Executor) handleShow(ctx context.Context, safeSession *SafeSession, sql } sort.Strings(vindexNames) for _, vindexName := range vindexNames { - vindex, _ := ks.Vindexes[vindexName] + vindex := ks.Vindexes[vindexName] params := make([]string, 0, 4) for k, v := range vindex.GetParams() { @@ -946,7 +946,7 @@ func (e *Executor) handleShow(ctx context.Context, safeSession *SafeSession, sql {Name: "Type", Type: sqltypes.Uint16}, {Name: "Message", Type: sqltypes.VarChar}, } - rows := make([][]sqltypes.Value, 0, 0) + rows := make([][]sqltypes.Value, 0) if safeSession.Warnings != nil { for _, warning := range safeSession.Warnings { @@ -1026,7 +1026,7 @@ func (e *Executor) handleOther(ctx context.Context, safeSession *SafeSession, sq } func (e *Executor) handleComment(sql string) (*sqltypes.Result, error) { - _, sql = sqlparser.ExtractMysqlComment(sql) + _, _ = sqlparser.ExtractMysqlComment(sql) // Not sure if this is a good idea. return &sqltypes.Result{}, nil } diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index dec9546097c..88e4d61232b 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -859,10 +859,8 @@ func TestStreamSelectScatter(t *testing.T) { serv := new(sandboxTopo) resolver := newTestResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} - var conns []*sandboxconn.SandboxConn for _, shard := range shards { - sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_MASTER, true, 1, nil) - conns = append(conns, sbc) + _ = hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_MASTER, true, 1, nil) } executor := NewExecutor(context.Background(), serv, cell, "", resolver, false, testBufferSize, testCacheSize, false) @@ -1624,10 +1622,6 @@ func TestVarJoinStream(t *testing.T) { if !reflect.DeepEqual(sbc1.Queries, wantQueries) { t.Errorf("sbc1.Queries: %+v, want %+v\n", sbc1.Queries, wantQueries) } - wantQueries = []*querypb.BoundQuery{{ - Sql: "select u2.id from user as u2 where u2.id = :u1_col", - BindVariables: map[string]*querypb.BindVariable{}, - }} // We have to use string representation because bindvars type is too complex. got := fmt.Sprintf("%+v", sbc2.Queries) want := `[sql:"select u2.id from user as u2 where u2.id = :u1_col" bind_variables: > ]` diff --git a/go/vt/vtgate/executor_stream_test.go b/go/vt/vtgate/executor_stream_test.go index 69bfe6e299e..b56d174ab1b 100644 --- a/go/vt/vtgate/executor_stream_test.go +++ b/go/vt/vtgate/executor_stream_test.go @@ -55,10 +55,8 @@ func TestStreamSQLSharded(t *testing.T) { serv := new(sandboxTopo) resolver := newTestResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} - var conns []*sandboxconn.SandboxConn for _, shard := range shards { - sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_MASTER, true, 1, nil) - conns = append(conns, sbc) + _ = hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_MASTER, true, 1, nil) } executor := NewExecutor(context.Background(), serv, cell, "", resolver, false, testBufferSize, testCacheSize, false) diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index b13ec8fea8b..1eb6d50aec0 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -26,7 +26,7 @@ import ( "testing" "time" - "golang.org/x/net/context" + "context" "github.com/golang/protobuf/proto" "vitess.io/vitess/go/mysql" @@ -63,6 +63,9 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { t.Errorf("want 0, got %d", commitCount) } logStats := testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + if logStats.CommitTime != 0 { + t.Errorf("logstats: expected zero CommitTime") + } // commit. _, err = executor.Execute(context.Background(), "TestExecute", session, "select id from main1", nil) @@ -110,8 +113,8 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { if rollbackCount := sbclookup.RollbackCount.Get(); rollbackCount != 1 { t.Errorf("want 1, got %d", rollbackCount) } - logStats = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) - logStats = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) + _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + _ = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) logStats = testQueryLog(t, logChan, "TestExecute", "ROLLBACK", "rollback", 1) if logStats.CommitTime == 0 { t.Errorf("logstats: expected non-zero CommitTime") @@ -170,7 +173,7 @@ func TestExecutorTransactionsAutoCommit(t *testing.T) { if commitCount := sbclookup.CommitCount.Get(); commitCount != 0 { t.Errorf("want 0, got %d", commitCount) } - logStats := testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) // commit. _, err = executor.Execute(context.Background(), "TestExecute", session, "select id from main1", nil) @@ -189,7 +192,7 @@ func TestExecutorTransactionsAutoCommit(t *testing.T) { t.Errorf("want 1, got %d", commitCount) } - logStats = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) + logStats := testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) if logStats.CommitTime != 0 { t.Errorf("logstats: expected zero CommitTime") } @@ -465,7 +468,7 @@ func TestExecutorAutocommit(t *testing.T) { if err != nil { t.Fatal(err) } - logStats = testQueryLog(t, logChan, "TestExecute", "SET", "set autocommit=1", 0) + _ = testQueryLog(t, logChan, "TestExecute", "SET", "set autocommit=1", 0) // Setting autocommit=1 commits existing transaction. if got, want := sbclookup.CommitCount.Get(), startCount+1; got != want { @@ -502,7 +505,7 @@ func TestExecutorAutocommit(t *testing.T) { if err != nil { t.Fatal(err) } - logStats = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) + _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) _, err = executor.Execute(context.Background(), "TestExecute", session, "update main1 set id=1", nil) if err != nil { @@ -537,7 +540,7 @@ func TestExecutorAutocommit(t *testing.T) { if got, want := sbclookup.CommitCount.Get(), startCount+1; got != want { t.Errorf("Commit count: %d, want %d", got, want) } - logStats = testQueryLog(t, logChan, "TestExecute", "COMMIT", "commit", 1) + _ = testQueryLog(t, logChan, "TestExecute", "COMMIT", "commit", 1) // transition autocommit from 0 to 1 in the middle of a transaction. startCount = sbclookup.CommitCount.Get() @@ -785,6 +788,9 @@ func TestExecutorShow(t *testing.T) { } qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes", nil) + if err != nil { + t.Error(err) + } wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Keyspace", "Name", "Type", "Params", "Owner"), Rows: [][]sqltypes.Value{ @@ -806,6 +812,9 @@ func TestExecutorShow(t *testing.T) { } qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.user", nil) + if err != nil { + t.Error(err) + } wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), Rows: [][]sqltypes.Value{ @@ -818,13 +827,13 @@ func TestExecutorShow(t *testing.T) { t.Errorf("show vschema vindexes on TestExecutor.user:\n%+v, want\n%+v", qr, wantqr) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on user", nil) + _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on user", nil) wantErr := errNoKeyspace.Error() if err == nil || err.Error() != wantErr { t.Errorf("show vschema vindexes on user: %v, want %v", err, wantErr) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.garbage", nil) + _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.garbage", nil) wantErr = "table `garbage` does not exist in keyspace `TestExecutor`" if err == nil || err.Error() != wantErr { t.Errorf("show vschema vindexes on user: %v, want %v", err, wantErr) @@ -832,6 +841,9 @@ func TestExecutorShow(t *testing.T) { session.TargetString = "TestExecutor" qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on user", nil) + if err != nil { + t.Error(err) + } wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), Rows: [][]sqltypes.Value{ @@ -846,6 +858,9 @@ func TestExecutorShow(t *testing.T) { session.TargetString = "TestExecutor" qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on user2", nil) + if err != nil { + t.Error(err) + } wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), Rows: [][]sqltypes.Value{ @@ -858,13 +873,16 @@ func TestExecutorShow(t *testing.T) { t.Errorf("show vschema vindexes on user2:\n%+v, want\n%+v", qr, wantqr) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on garbage", nil) + _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on garbage", nil) wantErr = "table `garbage` does not exist in keyspace `TestExecutor`" if err == nil || err.Error() != wantErr { t.Errorf("show vschema vindexes on user: %v, want %v", err, wantErr) } qr, err = executor.Execute(context.Background(), "TestExecute", session, "show warnings", nil) + if err != nil { + t.Error(err) + } wantqr = &sqltypes.Result{ Fields: []*querypb.Field{ {Name: "Level", Type: sqltypes.VarChar}, @@ -881,6 +899,9 @@ func TestExecutorShow(t *testing.T) { session.Warnings = []*querypb.QueryWarning{} qr, err = executor.Execute(context.Background(), "TestExecute", session, "show warnings", nil) + if err != nil { + t.Error(err) + } wantqr = &sqltypes.Result{ Fields: []*querypb.Field{ {Name: "Level", Type: sqltypes.VarChar}, @@ -899,6 +920,9 @@ func TestExecutorShow(t *testing.T) { {Code: mysql.EROutOfResources, Message: "ks/-40: query timed out"}, } qr, err = executor.Execute(context.Background(), "TestExecute", session, "show warnings", nil) + if err != nil { + t.Error(err) + } wantqr = &sqltypes.Result{ Fields: []*querypb.Field{ {Name: "Level", Type: sqltypes.VarChar}, @@ -961,20 +985,20 @@ func TestExecutorShow(t *testing.T) { } session = NewSafeSession(&vtgatepb.Session{}) - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema tables", nil) + _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema tables", nil) want := errNoKeyspace.Error() if err == nil || err.Error() != want { t.Errorf("show vschema tables: %v, want %v", err, want) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show 10", nil) + _, err = executor.Execute(context.Background(), "TestExecute", session, "show 10", nil) want = "syntax error at position 8 near '10'" if err == nil || err.Error() != want { t.Errorf("show vschema tables: %v, want %v", err, want) } session = NewSafeSession(&vtgatepb.Session{TargetString: "no_such_keyspace"}) - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema tables", nil) + _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema tables", nil) want = "keyspace no_such_keyspace not found in vschema" if err == nil || err.Error() != want { t.Errorf("show vschema tables: %v, want %v", err, want) @@ -1175,7 +1199,6 @@ func waitForVindex(t *testing.T, ks, name string, watch chan *vschemapb.SrvVSche if !ok { t.Errorf("updated vschema did not contain %s", name) } - break default: time.Sleep(time.Millisecond) } @@ -1268,7 +1291,7 @@ func TestExecutorCreateVindexDDL(t *testing.T) { }) vschema := <-vschemaUpdates - vindex, ok := vschema.Keyspaces[ks].Vindexes["test_vindex"] + _, ok := vschema.Keyspaces[ks].Vindexes["test_vindex"] if ok { t.Fatalf("test_vindex should not exist in original vschema") } @@ -1280,7 +1303,7 @@ func TestExecutorCreateVindexDDL(t *testing.T) { t.Error(err) } - vschema, vindex = waitForVindex(t, ks, "test_vindex", vschemaUpdates, executor) + _, vindex := waitForVindex(t, ks, "test_vindex", vschemaUpdates, executor) if vindex == nil || vindex.Type != "hash" { t.Errorf("updated vschema did not contain test_vindex") } @@ -1291,8 +1314,8 @@ func TestExecutorCreateVindexDDL(t *testing.T) { t.Errorf("create duplicate vindex: %v, want %s", err, wantErr) } select { - case vschema = <-vschemaUpdates: - t.Errorf("vschema should not be updated on error") + case <-vschemaUpdates: + t.Error("vschema should not be updated on error") default: } @@ -1357,14 +1380,14 @@ func TestExecutorAddDropVschemaTableDDL(t *testing.T) { if err != nil { t.Error(err) } - vschema = waitForVschemaTables(t, ks, append(vschemaTables, "test_table"), executor) + _ = waitForVschemaTables(t, ks, append(vschemaTables, "test_table"), executor) stmt = "alter vschema add table test_table2" _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) if err != nil { t.Error(err) } - vschema = waitForVschemaTables(t, ks, append(vschemaTables, []string{"test_table", "test_table2"}...), executor) + _ = waitForVschemaTables(t, ks, append(vschemaTables, []string{"test_table", "test_table2"}...), executor) // Should fail on a sharded keyspace session = NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}) @@ -1401,7 +1424,7 @@ func TestExecutorAddDropVindexDDL(t *testing.T) { }) vschema := <-vschemaUpdates - vindex, ok := vschema.Keyspaces[ks].Vindexes["test_hash"] + _, ok := vschema.Keyspaces[ks].Vindexes["test_hash"] if ok { t.Fatalf("test_hash should not exist in original vschema") } @@ -1413,12 +1436,12 @@ func TestExecutorAddDropVindexDDL(t *testing.T) { t.Fatalf("error in %s: %v", stmt, err) } - vschema, vindex = waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) + _, vindex := waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) if vindex.Type != "hash" { t.Errorf("vindex type %s not hash", vindex.Type) } - vschema = waitForColVindexes(t, ks, "test", []string{"test_hash"}, executor) + _ = waitForColVindexes(t, ks, "test", []string{"test_hash"}, executor) qr, err := executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) if err != nil { t.Fatalf("error in show vschema vindexes on TestExecutor.test: %v", err) @@ -1441,9 +1464,9 @@ func TestExecutorAddDropVindexDDL(t *testing.T) { t.Fatalf("error in %s: %v", stmt, err) } - vschema, vindex = waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) - vschema = waitForColVindexes(t, ks, "test", []string{}, executor) - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) + _, _ = waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) + _ = waitForColVindexes(t, ks, "test", []string{}, executor) + _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) wantErr := "table `test` does not exist in keyspace `TestExecutor`" if err == nil || err.Error() != wantErr { t.Fatalf("expected error in show vschema vindexes on TestExecutor.test %v: got %v", wantErr, err) @@ -1456,12 +1479,12 @@ func TestExecutorAddDropVindexDDL(t *testing.T) { t.Fatalf("error in %s: %v", stmt, err) } - vschema, vindex = waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) + _, vindex = waitForVindex(t, ks, "test_hash", vschemaUpdates, executor) if vindex.Type != "hash" { t.Errorf("vindex type %s not hash", vindex.Type) } - vschema = waitForColVindexes(t, ks, "test", []string{"test_hash"}, executor) + _ = waitForColVindexes(t, ks, "test", []string{"test_hash"}, executor) qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.test", nil) if err != nil { @@ -1754,17 +1777,17 @@ func TestExecutorVindexDDLNewKeyspace(t *testing.T) { t.Fatalf("keyspace was not created as expected") } - vindex, _ := ks.Vindexes["test_hash"] + vindex := ks.Vindexes["test_hash"] if vindex == nil { t.Fatalf("vindex was not created as expected") } - vindex2, _ := ks.Vindexes["test_hash2"] + vindex2 := ks.Vindexes["test_hash2"] if vindex2 == nil { t.Fatalf("vindex was not created as expected") } - table, _ := ks.Tables["test"] + table := ks.Tables["test"] if table == nil { t.Fatalf("column vindex was not created as expected") } @@ -1925,7 +1948,7 @@ func TestGetPlanUnnormalized(t *testing.T) { emptyvc := newVCursorImpl(context.Background(), nil, "", 0, makeComments(""), r, nil) unshardedvc := newVCursorImpl(context.Background(), nil, KsTestUnsharded, 0, makeComments(""), r, nil) - logStats1 := NewLogStats(nil, "Test", "", nil) + logStats1 := NewLogStats(context.Background(), "Test", "", nil) query1 := "select * from music_user_map where id = 1" plan1, err := r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats1) if err != nil { @@ -1936,7 +1959,7 @@ func TestGetPlanUnnormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats1.SQL) } - logStats2 := NewLogStats(nil, "Test", "", nil) + logStats2 := NewLogStats(context.Background(), "Test", "", nil) plan2, err := r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats2) if err != nil { t.Error(err) @@ -1953,7 +1976,7 @@ func TestGetPlanUnnormalized(t *testing.T) { if logStats2.SQL != wantSQL { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats2.SQL) } - logStats3 := NewLogStats(nil, "Test", "", nil) + logStats3 := NewLogStats(context.Background(), "Test", "", nil) plan3, err := r.getPlan(unshardedvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats3) if err != nil { t.Error(err) @@ -1964,7 +1987,7 @@ func TestGetPlanUnnormalized(t *testing.T) { if logStats3.SQL != wantSQL { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats3.SQL) } - logStats4 := NewLogStats(nil, "Test", "", nil) + logStats4 := NewLogStats(context.Background(), "Test", "", nil) plan4, err := r.getPlan(unshardedvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats4) if err != nil { t.Error(err) @@ -1988,7 +2011,7 @@ func TestGetPlanCacheUnnormalized(t *testing.T) { r, _, _, _ := createExecutorEnv() emptyvc := newVCursorImpl(context.Background(), nil, "", 0, makeComments(""), r, nil) query1 := "select * from music_user_map where id = 1" - logStats1 := NewLogStats(nil, "Test", "", nil) + logStats1 := NewLogStats(context.Background(), "Test", "", nil) _, err := r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, true /* skipQueryPlanCache */, logStats1) if err != nil { t.Error(err) @@ -2000,7 +2023,7 @@ func TestGetPlanCacheUnnormalized(t *testing.T) { if logStats1.SQL != wantSQL { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats1.SQL) } - logStats2 := NewLogStats(nil, "Test", "", nil) + logStats2 := NewLogStats(context.Background(), "Test", "", nil) _, err = r.getPlan(emptyvc, query1, makeComments(" /* comment 2 */"), map[string]*querypb.BindVariable{}, false /* skipQueryPlanCache */, logStats2) if err != nil { t.Error(err) @@ -2018,7 +2041,7 @@ func TestGetPlanCacheUnnormalized(t *testing.T) { unshardedvc := newVCursorImpl(context.Background(), nil, KsTestUnsharded, 0, makeComments(""), r, nil) query1 = "insert /*vt+ SKIP_QUERY_PLAN_CACHE=1 */ into user(id) values (1), (2)" - logStats1 = NewLogStats(nil, "Test", "", nil) + logStats1 = NewLogStats(context.Background(), "Test", "", nil) _, err = r.getPlan(unshardedvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats1) if err != nil { t.Error(err) @@ -2042,7 +2065,7 @@ func TestGetPlanCacheNormalized(t *testing.T) { r.normalize = true emptyvc := newVCursorImpl(context.Background(), nil, "", 0, makeComments(""), r, nil) query1 := "select * from music_user_map where id = 1" - logStats1 := NewLogStats(nil, "Test", "", nil) + logStats1 := NewLogStats(context.Background(), "Test", "", nil) _, err := r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, true /* skipQueryPlanCache */, logStats1) if err != nil { t.Error(err) @@ -2054,7 +2077,7 @@ func TestGetPlanCacheNormalized(t *testing.T) { if logStats1.SQL != wantSQL { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats1.SQL) } - logStats2 := NewLogStats(nil, "Test", "", nil) + logStats2 := NewLogStats(context.Background(), "Test", "", nil) _, err = r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false /* skipQueryPlanCache */, logStats2) if err != nil { t.Error(err) @@ -2072,7 +2095,7 @@ func TestGetPlanCacheNormalized(t *testing.T) { unshardedvc := newVCursorImpl(context.Background(), nil, KsTestUnsharded, 0, makeComments(""), r, nil) query1 = "insert /*vt+ SKIP_QUERY_PLAN_CACHE=1 */ into user(id) values (1), (2)" - logStats1 = NewLogStats(nil, "Test", "", nil) + logStats1 = NewLogStats(context.Background(), "Test", "", nil) _, err = r.getPlan(unshardedvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats1) if err != nil { t.Error(err) @@ -2100,12 +2123,12 @@ func TestGetPlanNormalized(t *testing.T) { query1 := "select * from music_user_map where id = 1" query2 := "select * from music_user_map where id = 2" normalized := "select * from music_user_map where id = :vtg1" - logStats1 := NewLogStats(nil, "Test", "", nil) + logStats1 := NewLogStats(context.Background(), "Test", "", nil) plan1, err := r.getPlan(emptyvc, query1, makeComments(" /* comment 1 */"), map[string]*querypb.BindVariable{}, false, logStats1) if err != nil { t.Error(err) } - logStats2 := NewLogStats(nil, "Test", "", nil) + logStats2 := NewLogStats(context.Background(), "Test", "", nil) plan2, err := r.getPlan(emptyvc, query1, makeComments(" /* comment 2 */"), map[string]*querypb.BindVariable{}, false, logStats2) if err != nil { t.Error(err) @@ -2129,7 +2152,7 @@ func TestGetPlanNormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats2.SQL) } - logStats3 := NewLogStats(nil, "Test", "", nil) + logStats3 := NewLogStats(context.Background(), "Test", "", nil) plan3, err := r.getPlan(emptyvc, query2, makeComments(" /* comment 3 */"), map[string]*querypb.BindVariable{}, false, logStats3) if err != nil { t.Error(err) @@ -2142,7 +2165,7 @@ func TestGetPlanNormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats3.SQL) } - logStats4 := NewLogStats(nil, "Test", "", nil) + logStats4 := NewLogStats(context.Background(), "Test", "", nil) plan4, err := r.getPlan(emptyvc, normalized, makeComments(" /* comment 4 */"), map[string]*querypb.BindVariable{}, false, logStats4) if err != nil { t.Error(err) @@ -2155,7 +2178,7 @@ func TestGetPlanNormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats4.SQL) } - logStats5 := NewLogStats(nil, "Test", "", nil) + logStats5 := NewLogStats(context.Background(), "Test", "", nil) plan3, err = r.getPlan(unshardedvc, query1, makeComments(" /* comment 5 */"), map[string]*querypb.BindVariable{}, false, logStats5) if err != nil { t.Error(err) @@ -2168,7 +2191,7 @@ func TestGetPlanNormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats5.SQL) } - logStats6 := NewLogStats(nil, "Test", "", nil) + logStats6 := NewLogStats(context.Background(), "Test", "", nil) plan4, err = r.getPlan(unshardedvc, query1, makeComments(" /* comment 6 */"), map[string]*querypb.BindVariable{}, false, logStats6) if err != nil { t.Error(err) @@ -2185,13 +2208,13 @@ func TestGetPlanNormalized(t *testing.T) { } // Errors - logStats7 := NewLogStats(nil, "Test", "", nil) + logStats7 := NewLogStats(context.Background(), "Test", "", nil) _, err = r.getPlan(emptyvc, "syntax", makeComments(""), map[string]*querypb.BindVariable{}, false, logStats7) wantErr := "syntax error at position 7 near 'syntax'" if err == nil || err.Error() != wantErr { t.Errorf("getPlan(syntax): %v, want %s", err, wantErr) } - logStats8 := NewLogStats(nil, "Test", "", nil) + logStats8 := NewLogStats(context.Background(), "Test", "", nil) _, err = r.getPlan(emptyvc, "create table a(id int)", makeComments(""), map[string]*querypb.BindVariable{}, false, logStats8) wantErr = "unsupported construct: ddl" if err == nil || err.Error() != wantErr { diff --git a/go/vt/vtgate/queryz_test.go b/go/vt/vtgate/queryz_test.go index 890918561b3..d7dd6537c6b 100644 --- a/go/vt/vtgate/queryz_test.go +++ b/go/vt/vtgate/queryz_test.go @@ -91,6 +91,10 @@ func TestQueryzHandler(t *testing.T) { "name": sqltypes.BytesBindVariable([]byte("myname")), }) + if err != nil { + t.Error(err) + } + plan3.ExecTime = time.Duration(100 * time.Millisecond) plan4.ExecTime = time.Duration(200 * time.Millisecond) diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index da72bc52787..8694a7b0901 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -562,7 +562,7 @@ func (stc *ScatterConn) MessageStream(ctx context.Context, rss []*srvtopo.Resolv default: } firstErrorTimeStamp := lastErrors.Record(rs.Target) - if time.Now().Sub(firstErrorTimeStamp) >= *messageStreamGracePeriod { + if time.Since(firstErrorTimeStamp) >= *messageStreamGracePeriod { // Cancel all streams and return an error. cancel() return vterrors.Errorf(vtrpcpb.Code_DEADLINE_EXCEEDED, "message stream from %v has repeatedly failed for longer than %v", rs.Target, *messageStreamGracePeriod) @@ -693,6 +693,7 @@ func init() { // as the random generator used by shuffleQueryParts. This function // should only be used in tests and should not be called concurrently. // It returns the previous shuffleQueryPartsRandomGenerator used. +// lint:ignore U1000 available for tests to use func injectShuffleQueryPartsRandomGenerator( randGen shuffleQueryPartsRandomGeneratorInterface) shuffleQueryPartsRandomGeneratorInterface { oldRandGen := shuffleQueryPartsRandomGenerator diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 89af3ef4540..3957fb54706 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -160,7 +160,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s sc = newTestScatterConn(hc, new(sandboxTopo), "aa") sbc := hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 - qr, err = f(sc, []string{"0"}) + _, err = f(sc, []string{"0"}) want := fmt.Sprintf("target: %v.0.replica, used tablet: aa-0 (0): INVALID_ARGUMENT error", name) // Verify server error string. if err == nil || err.Error() != want { @@ -217,7 +217,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s hc.Reset() sc = newTestScatterConn(hc, new(sandboxTopo), "aa") sbc = hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) - qr, err = f(sc, []string{"0", "0"}) + _, _ = f(sc, []string{"0", "0"}) // Ensure that we executed only once. if execCount := sbc.ExecCount.Get(); execCount != 1 { t.Errorf("want 1, got %v", execCount) diff --git a/go/vt/vtgate/tx_conn_test.go b/go/vt/vtgate/tx_conn_test.go index e548091e74f..bdaed10b3b0 100644 --- a/go/vt/vtgate/tx_conn_test.go +++ b/go/vt/vtgate/tx_conn_test.go @@ -65,10 +65,9 @@ func TestTxConnBegin(t *testing.T) { func TestTxConnBeginDisallowed(t *testing.T) { sc, _, _, _, _, _ := newTestTxConnEnv(t, "TestTxConn") - session := &vtgatepb.Session{} sc.txConn.mode = vtgatepb.TransactionMode_SINGLE - session = &vtgatepb.Session{TransactionMode: vtgatepb.TransactionMode_MULTI} + session := &vtgatepb.Session{TransactionMode: vtgatepb.TransactionMode_MULTI} err := sc.txConn.Begin(context.Background(), NewSafeSession(session)) wantErr := "requested transaction mode MULTI disallowed: vtgate must be started with --transaction_mode=MULTI (or TWOPC). Current transaction mode: SINGLE" if err == nil || err.Error() != wantErr { diff --git a/go/vt/vtgate/vschema_manager.go b/go/vt/vtgate/vschema_manager.go index d3189f58b2d..d99d440813b 100644 --- a/go/vt/vtgate/vschema_manager.go +++ b/go/vt/vtgate/vschema_manager.go @@ -85,7 +85,7 @@ func (vm *VSchemaManager) watchSrvVSchema(ctx context.Context, cell string) { vschema, err = vindexes.BuildVSchema(v) if err != nil { log.Warningf("Error creating VSchema for cell %v (will try again next update): %v", cell, err) - err = fmt.Errorf("Error creating VSchema for cell %v: %v", cell, err) + err = fmt.Errorf("error creating VSchema for cell %v: %v", cell, err) if vschemaCounters != nil { vschemaCounters.Add("Parsing", 1) } diff --git a/go/vt/vtgate/vtgate_test.go b/go/vt/vtgate/vtgate_test.go index f0300c4d45d..5f11adadb4e 100644 --- a/go/vt/vtgate/vtgate_test.go +++ b/go/vt/vtgate/vtgate_test.go @@ -253,6 +253,9 @@ func TestVTGateExecute(t *testing.T) { } session, err := rpcVTGate.Begin(context.Background(), false) + if err != nil { + t.Error(err) + } if !session.InTransaction { t.Errorf("want true, got false") } @@ -282,7 +285,7 @@ func TestVTGateExecute(t *testing.T) { t.Errorf("want 1, got %d", commitCount) } - session, err = rpcVTGate.Begin(context.Background(), false) + session, _ = rpcVTGate.Begin(context.Background(), false) rpcVTGate.Execute( context.Background(), session, @@ -385,7 +388,7 @@ func TestVTGateExecuteShards(t *testing.T) { t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc.Options[0], executeOptions) } - session, err := rpcVTGate.Begin(context.Background(), false) + session, _ := rpcVTGate.Begin(context.Background(), false) if !session.InTransaction { t.Errorf("want true, got false") } @@ -418,7 +421,7 @@ func TestVTGateExecuteShards(t *testing.T) { t.Errorf("want 1, got %d", commitCount) } - session, err = rpcVTGate.Begin(context.Background(), false) + session, _ = rpcVTGate.Begin(context.Background(), false) rpcVTGate.ExecuteShards(context.Background(), "query", nil, @@ -465,7 +468,7 @@ func TestVTGateExecuteKeyspaceIds(t *testing.T) { t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc1.Options[0], executeOptions) } // Test for successful execution in transaction - session, err := rpcVTGate.Begin(context.Background(), false) + session, _ := rpcVTGate.Begin(context.Background(), false) if !session.InTransaction { t.Errorf("want true, got false") } @@ -513,7 +516,7 @@ func TestVTGateExecuteKeyspaceIds(t *testing.T) { t.Errorf("want 2, got %v", qr.RowsAffected) } // Test for multiple shards for DML - qr, err = rpcVTGate.ExecuteKeyspaceIds(context.Background(), + _, err = rpcVTGate.ExecuteKeyspaceIds(context.Background(), "update table set a = b", nil, ks, @@ -559,11 +562,11 @@ func TestVTGateExecuteKeyRanges(t *testing.T) { t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc1.Options[0], executeOptions) } // Test for successful execution in transaction - session, err := rpcVTGate.Begin(context.Background(), false) + session, _ := rpcVTGate.Begin(context.Background(), false) if !session.InTransaction { t.Errorf("want true, got false") } - qr, err = rpcVTGate.ExecuteKeyRanges(context.Background(), + _, err = rpcVTGate.ExecuteKeyRanges(context.Background(), "query", nil, ks, @@ -648,7 +651,7 @@ func TestVTGateExecuteEntityIds(t *testing.T) { t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc1.Options[0], executeOptions) } // Test for successful execution in transaction - session, err := rpcVTGate.Begin(context.Background(), false) + session, _ := rpcVTGate.Begin(context.Background(), false) if !session.InTransaction { t.Errorf("want true, got false") } @@ -808,7 +811,7 @@ func TestVTGateExecuteBatchShards(t *testing.T) { t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc1.Options[0], executeOptions) } - session, err := rpcVTGate.Begin(context.Background(), false) + session, _ := rpcVTGate.Begin(context.Background(), false) rpcVTGate.ExecuteBatchShards(context.Background(), []*vtgatepb.BoundShardQuery{{ Query: &querypb.BoundQuery{ @@ -882,7 +885,7 @@ func TestVTGateExecuteBatchKeyspaceIds(t *testing.T) { t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc1.Options[0], executeOptions) } - session, err := rpcVTGate.Begin(context.Background(), false) + session, _ := rpcVTGate.Begin(context.Background(), false) rpcVTGate.ExecuteBatchKeyspaceIds(context.Background(), []*vtgatepb.BoundKeyspaceIdQuery{{ Query: &querypb.BoundQuery{ @@ -1322,7 +1325,7 @@ func TestVTGateMessageStreamRetry(t *testing.T) { // which should make vtgate wait for 1s (5s/5) and retry. start := time.Now() <-ch - duration := time.Now().Sub(start) + duration := time.Since(start) if duration < 1*time.Second || duration > 2*time.Second { t.Errorf("Retry duration should be around 1 second: %v", duration) } @@ -1363,7 +1366,7 @@ func TestVTGateMessageStreamUnavailable(t *testing.T) { // Verify the 1s delay. start := time.Now() <-ch - duration := time.Now().Sub(start) + duration := time.Since(start) if duration < 1*time.Second || duration > 2*time.Second { t.Errorf("Retry duration should be around 1 second: %v", duration) } @@ -1400,7 +1403,7 @@ func TestVTGateMessageStreamGracePeriod(t *testing.T) { if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("MessageStream err: %v, must contain %s", err, want) } - duration := time.Now().Sub(start) + duration := time.Since(start) if duration < 1*time.Second || duration > 2*time.Second { t.Errorf("Retry duration should be around 1 second: %v", duration) } @@ -1516,7 +1519,7 @@ func TestVTGateSplitQueryUnsharded(t *testing.T) { } // Total number of splits should be number of shards (1) as our sandbox returns a single split // for its fake implementation of SplitQuery. - if 1 != len(splits) { + if len(splits) != 1 { t.Errorf("wrong number of splits, got %+v, want %+v. testCase:\n%+v", len(splits), 1, testCase) continue @@ -2515,7 +2518,7 @@ func TestErrorIssuesRollback(t *testing.T) { t.Errorf("want 0, got %d", sbc.RollbackCount.Get()) } sbc.MustFailCodes[vtrpcpb.Code_ABORTED] = 20 - session, _, err = rpcVTGate.Execute( + _, _, err = rpcVTGate.Execute( context.Background(), session, "select id from t1", @@ -2550,7 +2553,7 @@ func TestErrorIssuesRollback(t *testing.T) { t.Errorf("want 0, got %d", sbc.RollbackCount.Get()) } sbc.MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 20 - session, _, err = rpcVTGate.Execute( + _, _, err = rpcVTGate.Execute( context.Background(), session, "select id from t1", @@ -2585,7 +2588,7 @@ func TestErrorIssuesRollback(t *testing.T) { t.Errorf("want 0, got %d", sbc.RollbackCount.Get()) } sbc.MustFailCodes[vtrpcpb.Code_ALREADY_EXISTS] = 20 - session, _, err = rpcVTGate.Execute( + _, _, err = rpcVTGate.Execute( context.Background(), session, "select id from t1", From d36a1bca4412e90df4113ab170e93fa5ea359d32 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 21:29:36 -0800 Subject: [PATCH 168/196] staticcheck: vttls package Signed-off-by: deepthi --- go/vt/vttls/vttls.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/vttls/vttls.go b/go/vt/vttls/vttls.go index 03926e0647b..ebec9382da9 100644 --- a/go/vt/vttls/vttls.go +++ b/go/vt/vttls/vttls.go @@ -103,11 +103,11 @@ func ServerConfig(cert, key, ca string) (*tls.Config, error) { if ca != "" { b, err := ioutil.ReadFile(ca) if err != nil { - return nil, fmt.Errorf("Failed to read ca file: %v", err) + return nil, fmt.Errorf("failed to read ca file: %v", err) } cp := x509.NewCertPool() if !cp.AppendCertsFromPEM(b) { - return nil, fmt.Errorf("Failed to append certificates") + return nil, fmt.Errorf("failed to append certificates") } config.ClientCAs = cp config.ClientAuth = tls.RequireAndVerifyClientCert From 48b7d473018b00e9c61a3336a1dafacc1a02b2c5 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 21:33:00 -0800 Subject: [PATCH 169/196] staticcheck: topotools package Signed-off-by: deepthi --- go/vt/topotools/rebuild_keyspace.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/topotools/rebuild_keyspace.go b/go/vt/topotools/rebuild_keyspace.go index a9280a0344e..a59ce27d9ce 100644 --- a/go/vt/topotools/rebuild_keyspace.go +++ b/go/vt/topotools/rebuild_keyspace.go @@ -180,7 +180,7 @@ func orderAndCheckPartitions(cell string, srvKeyspace *topodatapb.SrvKeyspace) e // this is the custom sharding case, all KeyRanges must be nil continue } - if bytes.Equal(currShard.KeyRange.End, nextShard.KeyRange.Start) { + if !bytes.Equal(currShard.KeyRange.End, nextShard.KeyRange.Start) { return fmt.Errorf("non-contiguous KeyRange values for %v in cell %v at shard %v to %v: %v != %v", tabletType, cell, i, i+1, hex.EncodeToString(currShard.KeyRange.End), hex.EncodeToString(nextShard.KeyRange.Start)) } } From 46084785f89e02974a18f09e7fc561e070de1906 Mon Sep 17 00:00:00 2001 From: deepthi Date: Sat, 2 Mar 2019 21:37:44 -0800 Subject: [PATCH 170/196] staticcheck: worker package Signed-off-by: deepthi --- go/vt/worker/block.go | 4 +--- go/vt/worker/command.go | 5 +++-- go/vt/worker/diff_utils.go | 10 +++++----- go/vt/worker/instance.go | 2 +- go/vt/worker/legacy_split_clone.go | 2 +- go/vt/worker/legacy_split_clone_test.go | 8 ++++++-- go/vt/worker/multi_split_diff.go | 6 +++--- go/vt/worker/multi_split_diff_cmd.go | 7 +++++-- go/vt/worker/restartable_result_reader.go | 8 ++++---- go/vt/worker/split_clone.go | 6 +----- go/vt/worker/split_diff.go | 4 ++-- go/vt/worker/split_diff_cmd.go | 5 ++++- go/vt/worker/split_diff_test.go | 2 +- go/vt/worker/topo_utils.go | 6 +++--- go/vt/worker/vertical_split_diff.go | 4 ++-- go/vt/workflow/manager.go | 14 +++++--------- go/vt/workflow/parallel_runner.go | 9 +++------ 17 files changed, 50 insertions(+), 52 deletions(-) diff --git a/go/vt/worker/block.go b/go/vt/worker/block.go index 01f48338a4d..9753e7c9f20 100644 --- a/go/vt/worker/block.go +++ b/go/vt/worker/block.go @@ -91,9 +91,7 @@ func (bw *BlockWorker) run(ctx context.Context) error { // We reuse the Copy state to reflect that the blocking is in progress. bw.SetState(WorkerStateDebugRunning) bw.wr.Logger().Printf("Block command was called and will block infinitely until the RPC context is canceled.\n") - select { - case <-ctx.Done(): - } + <-ctx.Done() bw.wr.Logger().Printf("Block command finished because the context is done: '%v'.\n", ctx.Err()) bw.SetState(WorkerStateDone) diff --git a/go/vt/worker/command.go b/go/vt/worker/command.go index e2f60db68a9..9b2c052cf79 100644 --- a/go/vt/worker/command.go +++ b/go/vt/worker/command.go @@ -145,7 +145,8 @@ func (wi *Instance) RunCommand(ctx context.Context, args []string, wr *wrangler. // WaitForCommand blocks until "done" is closed. In the meantime, it logs the status of "wrk". func (wi *Instance) WaitForCommand(wrk Worker, done chan struct{}) error { // display the status every second - timer := time.Tick(wi.commandDisplayInterval) + timer := time.NewTicker(wi.commandDisplayInterval) + defer timer.Stop() for { select { case <-done: @@ -157,7 +158,7 @@ func (wi *Instance) WaitForCommand(wrk Worker, done chan struct{}) error { return err } return nil - case <-timer: + case <-timer.C: log.Info(wrk.StatusAsText()) } } diff --git a/go/vt/worker/diff_utils.go b/go/vt/worker/diff_utils.go index 4ba633a7f7a..19d2dcbca3a 100644 --- a/go/vt/worker/diff_utils.go +++ b/go/vt/worker/diff_utils.go @@ -343,7 +343,7 @@ func TableScanByKeyRange(ctx context.Context, log logutil.Logger, ts *topo.Serve } } default: - return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Unsupported ShardingColumnType: %v", shardingColumnType) + return nil, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "unsupported ShardingColumnType: %v", shardingColumnType) } sql := fmt.Sprintf("SELECT %v FROM %v %v", strings.Join(escapeAll(orderedColumns(td)), ", "), sqlescape.EscapeID(td.Name), where) @@ -452,7 +452,7 @@ func (dr *DiffReport) HasDifferences() bool { // ComputeQPS fills in processingQPS func (dr *DiffReport) ComputeQPS() { if dr.processedRows > 0 { - dr.processingQPS = int(time.Duration(dr.processedRows) * time.Second / time.Now().Sub(dr.startingTime)) + dr.processingQPS = int(time.Duration(dr.processedRows) * time.Second / time.Since(dr.startingTime)) } } @@ -508,7 +508,7 @@ func CompareRows(fields []*querypb.Field, compareCount int, left, right []sqltyp r := rv.([]byte) return bytes.Compare(l, r), nil default: - return 0, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "Unsupported type %T returned by mysql.proto.Convert", l) + return 0, vterrors.Errorf(vtrpc.Code_FAILED_PRECONDITION, "unsupported type %T returned by mysql.proto.Convert", l) } } return 0, nil @@ -723,7 +723,7 @@ func CreateConsistentTableScanners(ctx context.Context, tablet *topo.TabletInfo, return nil, "", err } - queryService, err := tabletconn.GetDialer()(tablet.Tablet, true) + queryService, _ := tabletconn.GetDialer()(tablet.Tablet, true) defer queryService.Close(ctx) scanners := make([]TableScanner, numberOfScanners) @@ -766,7 +766,7 @@ func CreateConsistentTransactions(ctx context.Context, tablet *topo.TabletInfo, target := CreateTargetFrom(tablet.Tablet) // Create transactions - queryService, err := tabletconn.GetDialer()(tablet.Tablet, true) + queryService, _ := tabletconn.GetDialer()(tablet.Tablet, true) defer queryService.Close(ctx) connections, err := createTransactions(ctx, numberOfScanners, wr, cleaner, queryService, target, tablet.Tablet) if err != nil { diff --git a/go/vt/worker/instance.go b/go/vt/worker/instance.go index bf083c55324..018596c4564 100644 --- a/go/vt/worker/instance.go +++ b/go/vt/worker/instance.go @@ -108,7 +108,7 @@ func (wi *Instance) setAndStartWorker(ctx context.Context, wrk Worker, wr *wrang // We return FAILED_PRECONDITION to signal that a manual resolution is required. return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "The worker job was stopped %.1f minutes ago, but not reset. Run the 'Reset' command to clear it manually. Job: %v", - time.Now().Sub(wi.lastRunStopTime).Minutes(), + time.Since(wi.lastRunStopTime).Minutes(), wi.currentWorker) } diff --git a/go/vt/worker/legacy_split_clone.go b/go/vt/worker/legacy_split_clone.go index 3a870245688..0f5e18cccf4 100644 --- a/go/vt/worker/legacy_split_clone.go +++ b/go/vt/worker/legacy_split_clone.go @@ -424,7 +424,7 @@ func (scw *LegacySplitCloneWorker) copy(ctx context.Context) error { scw.setState(WorkerStateCloneOffline) start := time.Now() defer func() { - statsStateDurationsNs.Set(string(WorkerStateCloneOffline), time.Now().Sub(start).Nanoseconds()) + statsStateDurationsNs.Set(string(WorkerStateCloneOffline), time.Since(start).Nanoseconds()) }() // get source schema from the first shard diff --git a/go/vt/worker/legacy_split_clone_test.go b/go/vt/worker/legacy_split_clone_test.go index 1bdd773fb8b..3996118c2f6 100644 --- a/go/vt/worker/legacy_split_clone_test.go +++ b/go/vt/worker/legacy_split_clone_test.go @@ -251,7 +251,7 @@ func (sq *legacyTestQueryService) StreamExecute(ctx context.Context, target *que return err } } else if strings.HasPrefix(part, "`id`<") { - max, err = strconv.Atoi(part[5:]) + max, _ = strconv.Atoi(part[5:]) } } sq.t.Logf("legacyTestQueryService: got query: %v with min %v max %v", sql, min, max) @@ -466,6 +466,7 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { // is too late because this Go routine potentially reads it before the worker // resets the old value. statsRetryCounters.ResetAll() + var err error go func() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() @@ -477,7 +478,7 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { select { case <-ctx.Done(): - t.Fatalf("timed out waiting for vtworker to retry due to NoMasterAvailable: %v", ctx.Err()) + err = ctx.Err() case <-time.After(10 * time.Millisecond): // Poll constantly. } @@ -489,6 +490,9 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { tc.leftReplicaQs.AddDefaultHealthResponse() }() + if err != nil { + t.Fatalf("timed out waiting for vtworker to retry due to NoMasterAvailable: %v", err) + } // Only wait 1 ms between retries, so that the test passes faster. *executeFetchRetryTime = 1 * time.Millisecond diff --git a/go/vt/worker/multi_split_diff.go b/go/vt/worker/multi_split_diff.go index 56ec444d4f9..b4ab8cf9cea 100644 --- a/go/vt/worker/multi_split_diff.go +++ b/go/vt/worker/multi_split_diff.go @@ -41,7 +41,7 @@ import ( "vitess.io/vitess/go/vt/vtgate/vindexes" ) -// One of these per paralell runner +// Scanners encapsulates a source and a destination. We create one of these per paralell runner. type Scanners struct { // this is how we get data from the source shard sourceScanner TableScanner @@ -561,7 +561,7 @@ func (msdw *MultiSplitDiffWorker) synchronizeSrcAndDestTxState(ctx context.Conte } shortCtx, cancel := context.WithTimeout(ctx, *remoteActionsTimeout) - source, err := msdw.wr.TopoServer().GetTablet(shortCtx, msdw.sourceAlias) + source, _ := msdw.wr.TopoServer().GetTablet(shortCtx, msdw.sourceAlias) cancel() var sourcePosition string @@ -611,7 +611,7 @@ func (msdw *MultiSplitDiffWorker) synchronizeSrcAndDestTxState(ctx context.Conte return vterrors.Wrapf(err, "waitForDestinationTabletToReach: cannot get Tablet record for master %v", msdw.shardInfo.MasterAlias) } - queryService, err := tabletconn.GetDialer()(source.Tablet, true) + queryService, _ := tabletconn.GetDialer()(source.Tablet, true) var destScanners []TableScanner if msdw.useConsistentSnapshot { diff --git a/go/vt/worker/multi_split_diff_cmd.go b/go/vt/worker/multi_split_diff_cmd.go index 2c8f4b2bc12..5a6b880c545 100644 --- a/go/vt/worker/multi_split_diff_cmd.go +++ b/go/vt/worker/multi_split_diff_cmd.go @@ -228,10 +228,13 @@ func interactiveMultiSplitDiff(ctx context.Context, wi *Instance, wr *wrangler.W minHealthyTabletsStr := r.FormValue("minHealthyTablets") parallelDiffsCountStr := r.FormValue("parallelDiffsCount") minHealthyTablets, err := strconv.ParseInt(minHealthyTabletsStr, 0, 64) - parallelDiffsCount, err := strconv.ParseInt(parallelDiffsCountStr, 0, 64) if err != nil { return nil, nil, nil, vterrors.Wrap(err, "cannot parse minHealthyTablets") } + parallelDiffsCount, err := strconv.ParseInt(parallelDiffsCountStr, 0, 64) + if err != nil { + return nil, nil, nil, fmt.Errorf("cannot parse parallelDiffsCount: %s", err) + } waitForFixedTimeRatherThanGtidSetStr := r.FormValue("waitForFixedTimeRatherThanGtidSet") waitForFixedTimeRatherThanGtidSet := waitForFixedTimeRatherThanGtidSetStr == "true" useConsistentSnapshotStr := r.FormValue("useConsistentSnapshot") @@ -253,4 +256,4 @@ func init() { commandMultiSplitDiff, interactiveMultiSplitDiff, "[--exclude_tables=''] ", "Diffs a rdonly destination shard against its SourceShards"}) -} \ No newline at end of file +} diff --git a/go/vt/worker/restartable_result_reader.go b/go/vt/worker/restartable_result_reader.go index 71f7f9b1375..be0e7568879 100644 --- a/go/vt/worker/restartable_result_reader.go +++ b/go/vt/worker/restartable_result_reader.go @@ -269,7 +269,7 @@ func (r *RestartableResultReader) nextWithRetries() (*sqltypes.Result, error) { result, err = r.output.Recv() if err == nil || err == io.EOF { alias := topoproto.TabletAliasString(r.tablet.Alias) - log.V(2).Infof("tablet=%v table=%v chunk=%v: Successfully restarted streaming query with query '%v' after %.1f seconds.", alias, r.td.Name, r.chunk, r.query, time.Now().Sub(start).Seconds()) + log.V(2).Infof("tablet=%v table=%v chunk=%v: Successfully restarted streaming query with query '%v' after %.1f seconds.", alias, r.td.Name, r.chunk, r.query, time.Since(start).Seconds()) if attempt == 2 { statsStreamingQueryRestartsSameTabletCounters.Add(alias, 1) } else { @@ -295,7 +295,7 @@ func (r *RestartableResultReader) nextWithRetries() (*sqltypes.Result, error) { } deadline, _ := retryCtx.Deadline() - log.V(2).Infof("tablet=%v table=%v chunk=%v: Failed to restart streaming query (attempt %d) with query '%v'. Retrying to restart stream on a different tablet (for up to %.1f minutes). Next retry is in %.1f seconds. Error: %v", alias, r.td.Name, r.chunk, attempt, r.query, deadline.Sub(time.Now()).Minutes(), executeFetchRetryTime.Seconds(), err) + log.V(2).Infof("tablet=%v table=%v chunk=%v: Failed to restart streaming query (attempt %d) with query '%v'. Retrying to restart stream on a different tablet (for up to %.1f minutes). Next retry is in %.1f seconds. Error: %v", alias, r.td.Name, r.chunk, attempt, r.query, time.Until(deadline).Minutes(), executeFetchRetryTime.Seconds(), err) select { case <-retryCtx.Done(): @@ -303,7 +303,7 @@ func (r *RestartableResultReader) nextWithRetries() (*sqltypes.Result, error) { if err == context.DeadlineExceeded { return nil, vterrors.Wrapf(err, "%v: failed to restart the streaming connection after retrying for %v", r.tp.description(), *retryDuration) } - return nil, vterrors.Wrapf(err, "%v: interrupted while trying to restart the streaming connection (%.1f minutes elapsed so far)", r.tp.description(), time.Now().Sub(start).Minutes()) + return nil, vterrors.Wrapf(err, "%v: interrupted while trying to restart the streaming connection (%.1f minutes elapsed so far)", r.tp.description(), time.Since(start).Minutes()) case <-time.After(*executeFetchRetryTime): // Make a pause between the retries to avoid hammering the servers. } @@ -428,4 +428,4 @@ func greaterThanTupleWhereClause(columns []string, row []sqltypes.Value) []strin clauses = append(clauses, b.String()) return clauses -} \ No newline at end of file +} diff --git a/go/vt/worker/split_clone.go b/go/vt/worker/split_clone.go index 10ea583458e..189f0eff795 100644 --- a/go/vt/worker/split_clone.go +++ b/go/vt/worker/split_clone.go @@ -1119,7 +1119,7 @@ func (scw *SplitCloneWorker) clone(ctx context.Context, state StatusWorkerState) scw.setState(state) start := time.Now() defer func() { - statsStateDurationsNs.Set(string(state), time.Now().Sub(start).Nanoseconds()) + statsStateDurationsNs.Set(string(state), time.Since(start).Nanoseconds()) }() var firstSourceTablet, err = scw.findFirstSourceTablet(ctx, state) @@ -1205,10 +1205,6 @@ func (scw *SplitCloneWorker) clone(ctx context.Context, state StatusWorkerState) func (scw *SplitCloneWorker) setUpVReplication(ctx context.Context) error { wg := sync.WaitGroup{} - // Create and populate the vreplication table to give filtered replication - // a starting point. - queries := make([]string, 0, 4) - queries = append(queries, binlogplayer.CreateVReplicationTable()...) // get the current position from the sources sourcePositions := make([]string, len(scw.sourceShards)) diff --git a/go/vt/worker/split_diff.go b/go/vt/worker/split_diff.go index 43050b13038..7fd7a40cf73 100644 --- a/go/vt/worker/split_diff.go +++ b/go/vt/worker/split_diff.go @@ -319,7 +319,7 @@ func (sdw *SplitDiffWorker) synchronizeReplication(ctx context.Context) error { } qr := sqltypes.Proto3ToResult(p3qr) if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { - return vterrors.Errorf(vtrpc.Code_INTERNAL, "Unexpected result while reading position: %v", qr) + return vterrors.Errorf(vtrpc.Code_INTERNAL, "unexpected result while reading position: %v", qr) } vreplicationPos := qr.Rows[0][0].ToString() @@ -379,7 +379,7 @@ func (sdw *SplitDiffWorker) synchronizeReplication(ctx context.Context) error { sdw.wr.Logger().Infof("Restarting filtered replication on master %v", sdw.shardInfo.MasterAlias) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) defer cancel() - if _, err = sdw.wr.TabletManagerClient().VReplicationExec(ctx, masterInfo.Tablet, binlogplayer.StartVReplication(sdw.sourceShard.Uid)); err != nil { + if _, err = sdw.wr.TabletManagerClient().VReplicationExec(shortCtx, masterInfo.Tablet, binlogplayer.StartVReplication(sdw.sourceShard.Uid)); err != nil { return vterrors.Wrapf(err, "VReplicationExec(start) failed for %v", sdw.shardInfo.MasterAlias) } diff --git a/go/vt/worker/split_diff_cmd.go b/go/vt/worker/split_diff_cmd.go index 7720b162c5e..5ece6f5dce4 100644 --- a/go/vt/worker/split_diff_cmd.go +++ b/go/vt/worker/split_diff_cmd.go @@ -216,10 +216,13 @@ func interactiveSplitDiff(ctx context.Context, wi *Instance, wr *wrangler.Wrangl minHealthyRdonlyTabletsStr := r.FormValue("minHealthyRdonlyTablets") parallelDiffsCountStr := r.FormValue("parallelDiffsCount") minHealthyRdonlyTablets, err := strconv.ParseInt(minHealthyRdonlyTabletsStr, 0, 64) - parallelDiffsCount, err := strconv.ParseInt(parallelDiffsCountStr, 0, 64) if err != nil { return nil, nil, nil, vterrors.Wrap(err, "cannot parse minHealthyRdonlyTablets") } + parallelDiffsCount, err := strconv.ParseInt(parallelDiffsCountStr, 0, 64) + if err != nil { + return nil, nil, nil, vterrors.Wrap(err, "cannot parse parallelDiffsCount") + } // start the diff job // TODO: @rafael - Add option to set destination tablet type in UI form. diff --git a/go/vt/worker/split_diff_test.go b/go/vt/worker/split_diff_test.go index c281852f804..5fb1ed37ca4 100644 --- a/go/vt/worker/split_diff_test.go +++ b/go/vt/worker/split_diff_test.go @@ -288,7 +288,7 @@ func testSplitDiff(t *testing.T, v3 bool, destinationTabletType topodatapb.Table defer ft.StopActionLoop(t) } - tabletTypeName, _ := topodatapb.TabletType_name[int32(destinationTabletType)] + tabletTypeName := topodatapb.TabletType_name[int32(destinationTabletType)] // Run the vtworker command. args := []string{ "SplitDiff", diff --git a/go/vt/worker/topo_utils.go b/go/vt/worker/topo_utils.go index 4a57f007e9e..95b0714419d 100644 --- a/go/vt/worker/topo_utils.go +++ b/go/vt/worker/topo_utils.go @@ -74,7 +74,7 @@ func waitForHealthyTablets(ctx context.Context, wr *wrangler.Wrangler, tsc *disc start := time.Now() deadlineForLog, _ := busywaitCtx.Deadline() log.V(2).Infof("Waiting for enough healthy %v tablets to become available in (%v,%v/%v). required: %v Waiting up to %.1f seconds.", tabletType, - cell, keyspace, shard, minHealthyRdonlyTablets, deadlineForLog.Sub(time.Now()).Seconds()) + cell, keyspace, shard, minHealthyRdonlyTablets, time.Until(deadlineForLog).Seconds()) // Wait for at least one RDONLY tablet initially before checking the list. if err := tsc.WaitForTablets(busywaitCtx, cell, keyspace, shard, tabletType); err != nil { @@ -97,7 +97,7 @@ func waitForHealthyTablets(ctx context.Context, wr *wrangler.Wrangler, tsc *disc deadlineForLog, _ := busywaitCtx.Deadline() wr.Logger().Infof("Waiting for enough healthy %v tablets to become available (%v,%v/%v). available: %v required: %v Waiting up to %.1f more seconds.", - tabletType, cell, keyspace, shard, len(healthyTablets), minHealthyRdonlyTablets, deadlineForLog.Sub(time.Now()).Seconds()) + tabletType, cell, keyspace, shard, len(healthyTablets), minHealthyRdonlyTablets, time.Until(deadlineForLog).Seconds()) // Block for 1 second because 2 seconds is the -health_check_interval flag value in integration tests. timer := time.NewTimer(1 * time.Second) select { @@ -107,7 +107,7 @@ func waitForHealthyTablets(ctx context.Context, wr *wrangler.Wrangler, tsc *disc } } log.V(2).Infof("At least %v healthy %v tablets are available in (%v,%v/%v) (required: %v). Took %.1f seconds to find this out.", - tabletType, len(healthyTablets), cell, keyspace, shard, minHealthyRdonlyTablets, time.Now().Sub(start).Seconds()) + tabletType, len(healthyTablets), cell, keyspace, shard, minHealthyRdonlyTablets, time.Since(start).Seconds()) return healthyTablets, nil } diff --git a/go/vt/worker/vertical_split_diff.go b/go/vt/worker/vertical_split_diff.go index eed0d695883..fb5a8e3a06f 100644 --- a/go/vt/worker/vertical_split_diff.go +++ b/go/vt/worker/vertical_split_diff.go @@ -285,7 +285,7 @@ func (vsdw *VerticalSplitDiffWorker) synchronizeReplication(ctx context.Context) } qr := sqltypes.Proto3ToResult(p3qr) if len(qr.Rows) != 1 || len(qr.Rows[0]) != 1 { - return fmt.Errorf("Unexpected result while reading position: %v", qr) + return fmt.Errorf("unexpected result while reading position: %v", qr) } vreplicationPos := qr.Rows[0][0].ToString() @@ -344,7 +344,7 @@ func (vsdw *VerticalSplitDiffWorker) synchronizeReplication(ctx context.Context) vsdw.wr.Logger().Infof("Restarting filtered replication on master %v", topoproto.TabletAliasString(vsdw.shardInfo.MasterAlias)) shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout) defer cancel() - if _, err = vsdw.wr.TabletManagerClient().VReplicationExec(ctx, masterInfo.Tablet, binlogplayer.StartVReplication(ss.Uid)); err != nil { + if _, err = vsdw.wr.TabletManagerClient().VReplicationExec(shortCtx, masterInfo.Tablet, binlogplayer.StartVReplication(ss.Uid)); err != nil { return vterrors.Wrapf(err, "VReplicationExec(start) failed for %v", vsdw.shardInfo.MasterAlias) } diff --git a/go/vt/workflow/manager.go b/go/vt/workflow/manager.go index ea93a79207d..f3f94d39f81 100644 --- a/go/vt/workflow/manager.go +++ b/go/vt/workflow/manager.go @@ -170,9 +170,7 @@ func (m *Manager) Run(ctx context.Context) { m.mu.Unlock() // Wait for the context to be canceled. - select { - case <-ctx.Done(): - } + <-ctx.Done() // Clear context and get a copy of the running jobs. m.mu.Lock() @@ -187,9 +185,7 @@ func (m *Manager) Run(ctx context.Context) { rw.cancel() } for _, rw := range runningWorkflows { - select { - case <-rw.done: - } + <-rw.done } } @@ -331,7 +327,7 @@ func (m *Manager) Start(ctx context.Context, uuid string) error { rw, ok := m.workflows[uuid] if !ok { - return fmt.Errorf("Cannot find workflow %v in the workflow list", uuid) + return fmt.Errorf("cannot find workflow %v in the workflow list", uuid) } if rw.wi.State != workflowpb.WorkflowState_NotStarted { @@ -446,10 +442,10 @@ func (m *Manager) Delete(ctx context.Context, uuid string) error { rw, ok := m.workflows[uuid] if !ok { - return fmt.Errorf("No workflow with uuid %v", uuid) + return fmt.Errorf("no workflow with uuid %v", uuid) } if rw.wi.State == workflowpb.WorkflowState_Running { - return fmt.Errorf("Cannot delete running workflow") + return fmt.Errorf("cannot delete running workflow") } if err := m.ts.DeleteWorkflow(m.ctx, rw.wi); err != nil { log.Errorf("Could not delete workflow %v: %v", rw.wi, err) diff --git a/go/vt/workflow/parallel_runner.go b/go/vt/workflow/parallel_runner.go index da8d0e30479..6de0fc5f88a 100644 --- a/go/vt/workflow/parallel_runner.go +++ b/go/vt/workflow/parallel_runner.go @@ -233,7 +233,7 @@ func (p *ParallelRunner) Action(ctx context.Context, path, name string) error { } return fmt.Errorf("ignored the approval action %v because no pending approval found: it might be already approved before", actionNameApproveRemainingTasks) default: - return fmt.Errorf("Unknown action: %v", name) + return fmt.Errorf("unknown action: %v", name) } } @@ -244,7 +244,7 @@ func (p *ParallelRunner) triggerRetry(taskID string) error { // Unregister the retry channel. retryChannel, ok := p.retryActionRegistry[taskID] if !ok { - return fmt.Errorf("Unregistered action for node: %v", taskID) + return fmt.Errorf("unregistered action for node: %v", taskID) } delete(p.retryActionRegistry, taskID) @@ -343,10 +343,7 @@ func isTaskSucceeded(task *workflowpb.Task) bool { } func isTaskRunning(task *workflowpb.Task) bool { - if task.State == workflowpb.TaskState_TaskRunning { - return true - } - return false + return task.State == workflowpb.TaskState_TaskRunning } func (p *ParallelRunner) waitForApproval(taskIndex int) { From e5d8602b4d4d8529fc2784d2fa2a90e19c961e8c Mon Sep 17 00:00:00 2001 From: deepthi Date: Sun, 3 Mar 2019 15:22:47 -0800 Subject: [PATCH 171/196] staticcheck: vtgate package Signed-off-by: deepthi --- go/vt/vtgate/gateway/discoverygateway.go | 6 ++--- go/vt/vtgate/gateway/discoverygateway_test.go | 6 ++--- go/vt/wrangler/keyspace.go | 24 +++++++++---------- go/vt/wrangler/permissions.go | 10 ++++---- go/vt/wrangler/reparent.go | 8 +++---- go/vt/wrangler/schema.go | 12 +++++----- go/vt/wrangler/split.go | 2 +- go/vt/wrangler/validator.go | 7 +++--- go/vt/wrangler/version.go | 12 +++++----- 9 files changed, 43 insertions(+), 44 deletions(-) diff --git a/go/vt/vtgate/gateway/discoverygateway.go b/go/vt/vtgate/gateway/discoverygateway.go index cf1a10e18bb..f270c4e568a 100644 --- a/go/vt/vtgate/gateway/discoverygateway.go +++ b/go/vt/vtgate/gateway/discoverygateway.go @@ -238,7 +238,7 @@ func (dg *discoveryGateway) CacheStatus() TabletCacheStatusList { // the middle of a transaction. While returning the error check if it maybe a result of // a resharding event, and set the re-resolve bit and let the upper layers // re-resolve and retry. -func (dg *discoveryGateway) withRetry(ctx context.Context, target *querypb.Target, unused queryservice.QueryService, name string, inTransaction bool, inner func(ctx context.Context, target *querypb.Target, conn queryservice.QueryService) (error, bool)) error { +func (dg *discoveryGateway) withRetry(ctx context.Context, target *querypb.Target, unused queryservice.QueryService, name string, inTransaction bool, inner func(ctx context.Context, target *querypb.Target, conn queryservice.QueryService) (bool, error)) error { var tabletLastUsed *topodatapb.Tablet var err error invalidTablets := make(map[string]bool) @@ -319,7 +319,7 @@ func (dg *discoveryGateway) withRetry(ctx context.Context, target *querypb.Targe startTime := time.Now() var canRetry bool - err, canRetry = inner(ctx, ts.Target, conn) + canRetry, err = inner(ctx, ts.Target, conn) dg.updateStats(target, startTime, err) if canRetry { invalidTablets[ts.Key] = true @@ -378,7 +378,7 @@ func nextTablet(cell string, tablets []discovery.TabletStats, offset, length int } func (dg *discoveryGateway) updateStats(target *querypb.Target, startTime time.Time, err error) { - elapsed := time.Now().Sub(startTime) + elapsed := time.Since(startTime) aggr := dg.getStatsAggregator(target) aggr.UpdateQueryInfo("", target.TabletType, elapsed, err != nil) } diff --git a/go/vt/vtgate/gateway/discoverygateway_test.go b/go/vt/vtgate/gateway/discoverygateway_test.go index 35127cc4435..e8dd72cdeb7 100644 --- a/go/vt/vtgate/gateway/discoverygateway_test.go +++ b/go/vt/vtgate/gateway/discoverygateway_test.go @@ -405,7 +405,7 @@ func testDiscoveryGatewayGeneric(t *testing.T, f func(dg Gateway, target *queryp // tablet without connection hc.Reset() dg.tsc.ResetForTesting() - ep1 := hc.AddTestTablet("cell", "1.1.1.1", 1001, keyspace, shard, tabletType, false, 10, nil).Tablet() + _ = hc.AddTestTablet("cell", "1.1.1.1", 1001, keyspace, shard, tabletType, false, 10, nil).Tablet() err = f(dg, target) verifyShardErrors(t, err, want, vtrpcpb.Code_UNAVAILABLE) @@ -416,7 +416,7 @@ func testDiscoveryGatewayGeneric(t *testing.T, f func(dg Gateway, target *queryp sc2 := hc.AddTestTablet("cell", "1.1.1.1", 1002, keyspace, shard, tabletType, true, 10, nil) sc1.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 sc2.MustFailCodes[vtrpcpb.Code_FAILED_PRECONDITION] = 1 - ep1 = sc1.Tablet() + ep1 := sc1.Tablet() ep2 := sc2.Tablet() err = f(dg, target) @@ -486,7 +486,7 @@ func testDiscoveryGatewayTransact(t *testing.T, f func(dg Gateway, target *query format := `used tablet: %s` verifyShardErrorEither(t, err, fmt.Sprintf(format, topotools.TabletIdent(ep1)), - fmt.Sprintf(format, topotools.TabletIdent(ep2)), ) + fmt.Sprintf(format, topotools.TabletIdent(ep2))) // server error - no retry hc.Reset() diff --git a/go/vt/wrangler/keyspace.go b/go/vt/wrangler/keyspace.go index a98a467feef..98902a3c33e 100644 --- a/go/vt/wrangler/keyspace.go +++ b/go/vt/wrangler/keyspace.go @@ -71,7 +71,7 @@ func (wr *Wrangler) SetKeyspaceShardingInfo(ctx context.Context, keyspace, shard if force { wr.Logger().Warningf("Forcing keyspace ShardingColumnName change from %v to %v", ki.ShardingColumnName, shardingColumnName) } else { - return fmt.Errorf("Cannot change ShardingColumnName from %v to %v (use -force to override)", ki.ShardingColumnName, shardingColumnName) + return fmt.Errorf("cannot change ShardingColumnName from %v to %v (use -force to override)", ki.ShardingColumnName, shardingColumnName) } } @@ -79,7 +79,7 @@ func (wr *Wrangler) SetKeyspaceShardingInfo(ctx context.Context, keyspace, shard if force { wr.Logger().Warningf("Forcing keyspace ShardingColumnType change from %v to %v", ki.ShardingColumnType, shardingColumnType) } else { - return fmt.Errorf("Cannot change ShardingColumnType from %v to %v (use -force to override)", ki.ShardingColumnType, shardingColumnType) + return fmt.Errorf("cannot change ShardingColumnType from %v to %v (use -force to override)", ki.ShardingColumnType, shardingColumnType) } } @@ -184,7 +184,7 @@ func (wr *Wrangler) cancelHorizontalResharding(ctx context.Context, keyspace, sh // find our shard in there os := topotools.OverlappingShardsForShard(osList, shard) if os == nil { - return fmt.Errorf("Shard %v is not involved in any overlapping shards", shard) + return fmt.Errorf("shard %v is not involved in any overlapping shards", shard) } _, destinationShards, err := wr.findSourceDest(ctx, os) @@ -229,14 +229,14 @@ func (wr *Wrangler) MigrateServedTypes(ctx context.Context, keyspace, shard stri // we cannot migrate a master back, since when master migration // is done, the source shards are dead if reverse { - return fmt.Errorf("Cannot migrate master back to %v/%v", keyspace, shard) + return fmt.Errorf("cannot migrate master back to %v/%v", keyspace, shard) } // we cannot skip refresh state for a master if skipReFreshState { - return fmt.Errorf("Cannot skip refresh state for master migration on %v/%v", keyspace, shard) + return fmt.Errorf("cannot skip refresh state for master migration on %v/%v", keyspace, shard) } if cells != nil { - return fmt.Errorf("Cannot specify cells for master migration on %v/%v", keyspace, shard) + return fmt.Errorf("cannot specify cells for master migration on %v/%v", keyspace, shard) } } @@ -257,7 +257,7 @@ func (wr *Wrangler) MigrateServedTypes(ctx context.Context, keyspace, shard stri // find our shard in there os := topotools.OverlappingShardsForShard(osList, shard) if os == nil { - return fmt.Errorf("Shard %v is not involved in any overlapping shards", shard) + return fmt.Errorf("shard %v is not involved in any overlapping shards", shard) } sourceShards, destinationShards, err := wr.findSourceDest(ctx, os) @@ -817,14 +817,14 @@ func (wr *Wrangler) waitForDrainInCell(ctx context.Context, cell, keyspace, shar if len(drainedHealthyTablets) == len(healthyTablets) { wr.Logger().Infof("%v: All %d healthy tablets were drained after %.1f seconds (not counting %.1f seconds for the initial wait).", - cell, len(healthyTablets), time.Now().Sub(startTime).Seconds(), healthCheckTimeout.Seconds()) + cell, len(healthyTablets), time.Since(startTime).Seconds(), healthCheckTimeout.Seconds()) break } // Continue waiting, sleep in between. deadlineString := "" if d, ok := ctx.Deadline(); ok { - deadlineString = fmt.Sprintf(" up to %.1f more seconds", d.Sub(time.Now()).Seconds()) + deadlineString = fmt.Sprintf(" up to %.1f more seconds", time.Until(d).Seconds()) } wr.Logger().Infof("%v: Waiting%v for all healthy tablets to be drained (%d/%d done).", cell, deadlineString, len(drainedHealthyTablets), len(healthyTablets)) @@ -924,7 +924,7 @@ func (wr *Wrangler) MigrateServedFrom(ctx context.Context, keyspace, shard strin return err } if len(ki.ServedFroms) == 0 { - return fmt.Errorf("Destination keyspace %v is not a vertical split target", keyspace) + return fmt.Errorf("destination keyspace %v is not a vertical split target", keyspace) } // read the destination shard, check it @@ -933,7 +933,7 @@ func (wr *Wrangler) MigrateServedFrom(ctx context.Context, keyspace, shard strin return err } if len(si.SourceShards) != 1 || len(si.SourceShards[0].Tables) == 0 { - return fmt.Errorf("Destination shard %v/%v is not a vertical split target", keyspace, shard) + return fmt.Errorf("destination shard %v/%v is not a vertical split target", keyspace, shard) } // check the migration is valid before locking (will also be checked @@ -985,7 +985,7 @@ func (wr *Wrangler) migrateServedFromLocked(ctx context.Context, ki *topo.Keyspa return err } if len(destinationShard.SourceShards) != 1 { - return fmt.Errorf("Destination shard %v/%v is not a vertical split target", destinationShard.Keyspace(), destinationShard.ShardName()) + return fmt.Errorf("destination shard %v/%v is not a vertical split target", destinationShard.Keyspace(), destinationShard.ShardName()) } tables := destinationShard.SourceShards[0].Tables diff --git a/go/vt/wrangler/permissions.go b/go/vt/wrangler/permissions.go index 8cf49fceaad..a00e99398e9 100644 --- a/go/vt/wrangler/permissions.go +++ b/go/vt/wrangler/permissions.go @@ -65,7 +65,7 @@ func (wr *Wrangler) ValidatePermissionsShard(ctx context.Context, keyspace, shar // get permissions from the master, or error if !si.HasMaster() { - return fmt.Errorf("No master in shard %v/%v", keyspace, shard) + return fmt.Errorf("no master in shard %v/%v", keyspace, shard) } log.Infof("Gathering permissions for master %v", topoproto.TabletAliasString(si.MasterAlias)) masterPermissions, err := wr.GetPermissions(ctx, si.MasterAlias) @@ -92,7 +92,7 @@ func (wr *Wrangler) ValidatePermissionsShard(ctx context.Context, keyspace, shar } wg.Wait() if er.HasErrors() { - return fmt.Errorf("Permissions diffs: %v", er.Error().Error()) + return fmt.Errorf("permissions diffs: %v", er.Error().Error()) } return nil } @@ -108,7 +108,7 @@ func (wr *Wrangler) ValidatePermissionsKeyspace(ctx context.Context, keyspace st // corner cases if len(shards) == 0 { - return fmt.Errorf("No shards in keyspace %v", keyspace) + return fmt.Errorf("no shards in keyspace %v", keyspace) } sort.Strings(shards) if len(shards) == 1 { @@ -121,7 +121,7 @@ func (wr *Wrangler) ValidatePermissionsKeyspace(ctx context.Context, keyspace st return err } if !si.HasMaster() { - return fmt.Errorf("No master in shard %v/%v", keyspace, shards[0]) + return fmt.Errorf("no master in shard %v/%v", keyspace, shards[0]) } referenceAlias := si.MasterAlias log.Infof("Gathering permissions for reference master %v", topoproto.TabletAliasString(referenceAlias)) @@ -151,7 +151,7 @@ func (wr *Wrangler) ValidatePermissionsKeyspace(ctx context.Context, keyspace st } wg.Wait() if er.HasErrors() { - return fmt.Errorf("Permissions diffs: %v", er.Error().Error()) + return fmt.Errorf("permissions diffs: %v", er.Error().Error()) } return nil } diff --git a/go/vt/wrangler/reparent.go b/go/vt/wrangler/reparent.go index 0b5bd589b4e..565023cee4c 100644 --- a/go/vt/wrangler/reparent.go +++ b/go/vt/wrangler/reparent.go @@ -218,7 +218,7 @@ func (wr *Wrangler) initShardMasterLocked(ctx context.Context, ev *events.Repare defer wg.Done() wr.logger.Infof("resetting replication on tablet %v", alias) if err := wr.tmc.ResetReplication(resetCtx, tabletInfo.Tablet); err != nil { - rec.RecordError(fmt.Errorf("Tablet %v ResetReplication failed (either fix it, or Scrap it): %v", alias, err)) + rec.RecordError(fmt.Errorf("tablet %v ResetReplication failed (either fix it, or Scrap it): %v", alias, err)) } }(alias, tabletInfo) } @@ -277,7 +277,7 @@ func (wr *Wrangler) initShardMasterLocked(ctx context.Context, ev *events.Repare defer wgSlaves.Done() wr.logger.Infof("initializing slave %v", alias) if err := wr.tmc.InitSlave(replCtx, tabletInfo.Tablet, masterElectTabletAlias, rp, now); err != nil { - rec.RecordError(fmt.Errorf("Tablet %v InitSlave failed: %v", alias, err)) + rec.RecordError(fmt.Errorf("tablet %v InitSlave failed: %v", alias, err)) } }(alias, tabletInfo) } @@ -480,7 +480,7 @@ func (wr *Wrangler) plannedReparentShardLocked(ctx context.Context, ev *events.R // also restart replication on old master forceStartSlave := alias == oldMasterTabletInfoAliasStr if err := wr.tmc.SetMaster(replCtx, tabletInfo.Tablet, masterElectTabletAlias, now, forceStartSlave); err != nil { - rec.RecordError(fmt.Errorf("Tablet %v SetMaster failed: %v", alias, err)) + rec.RecordError(fmt.Errorf("tablet %v SetMaster failed: %v", alias, err)) return } }(alias, tabletInfo) @@ -776,7 +776,7 @@ func (wr *Wrangler) emergencyReparentShardLocked(ctx context.Context, ev *events forceStartSlave = status.SlaveIoRunning || status.SlaveSqlRunning } if err := wr.tmc.SetMaster(replCtx, tabletInfo.Tablet, masterElectTabletAlias, now, forceStartSlave); err != nil { - rec.RecordError(fmt.Errorf("Tablet %v SetMaster failed: %v", alias, err)) + rec.RecordError(fmt.Errorf("tablet %v SetMaster failed: %v", alias, err)) } }(alias, tabletInfo) } diff --git a/go/vt/wrangler/schema.go b/go/vt/wrangler/schema.go index c743a303dd1..4b6bbb533d4 100644 --- a/go/vt/wrangler/schema.go +++ b/go/vt/wrangler/schema.go @@ -151,7 +151,7 @@ func (wr *Wrangler) ValidateSchemaShard(ctx context.Context, keyspace, shard str // get schema from the master, or error if !si.HasMaster() { - return fmt.Errorf("No master in shard %v/%v", keyspace, shard) + return fmt.Errorf("no master in shard %v/%v", keyspace, shard) } log.Infof("Gathering schema for master %v", topoproto.TabletAliasString(si.MasterAlias)) masterSchema, err := wr.GetSchema(ctx, si.MasterAlias, nil, excludeTables, includeViews) @@ -179,7 +179,7 @@ func (wr *Wrangler) ValidateSchemaShard(ctx context.Context, keyspace, shard str } wg.Wait() if er.HasErrors() { - return fmt.Errorf("Schema diffs: %v", er.Error().Error()) + return fmt.Errorf("schema diffs: %v", er.Error().Error()) } return nil } @@ -195,7 +195,7 @@ func (wr *Wrangler) ValidateSchemaKeyspace(ctx context.Context, keyspace string, // corner cases if len(shards) == 0 { - return fmt.Errorf("No shards in keyspace %v", keyspace) + return fmt.Errorf("no shards in keyspace %v", keyspace) } sort.Strings(shards) if len(shards) == 1 { @@ -208,7 +208,7 @@ func (wr *Wrangler) ValidateSchemaKeyspace(ctx context.Context, keyspace string, return fmt.Errorf("GetShard(%v, %v) failed: %v", keyspace, shards[0], err) } if !si.HasMaster() { - return fmt.Errorf("No master in shard %v/%v", keyspace, shards[0]) + return fmt.Errorf("no master in shard %v/%v", keyspace, shards[0]) } referenceAlias := si.MasterAlias log.Infof("Gathering schema for reference master %v", topoproto.TabletAliasString(referenceAlias)) @@ -245,7 +245,7 @@ func (wr *Wrangler) ValidateSchemaKeyspace(ctx context.Context, keyspace string, } if !si.HasMaster() { - er.RecordError(fmt.Errorf("No master in shard %v/%v", keyspace, shard)) + er.RecordError(fmt.Errorf("no master in shard %v/%v", keyspace, shard)) continue } @@ -262,7 +262,7 @@ func (wr *Wrangler) ValidateSchemaKeyspace(ctx context.Context, keyspace string, } wg.Wait() if er.HasErrors() { - return fmt.Errorf("Schema diffs: %v", er.Error().Error()) + return fmt.Errorf("schema diffs: %v", er.Error().Error()) } return nil } diff --git a/go/vt/wrangler/split.go b/go/vt/wrangler/split.go index e374336ba3a..718bfd19ab4 100644 --- a/go/vt/wrangler/split.go +++ b/go/vt/wrangler/split.go @@ -68,7 +68,7 @@ func (wr *Wrangler) SetSourceShards(ctx context.Context, keyspace, shard string, // If the shard already has sources, maybe it's already been restored, // so let's be safe and abort right here. if len(si.SourceShards) > 0 { - return fmt.Errorf("Shard %v/%v already has SourceShards, not overwriting them (full record: %v)", keyspace, shard, *si.Shard) + return fmt.Errorf("shard %v/%v already has SourceShards, not overwriting them (full record: %v)", keyspace, shard, *si.Shard) } si.SourceShards = sourceShards diff --git a/go/vt/wrangler/validator.go b/go/vt/wrangler/validator.go index 231b6f65221..9d0a21bee1b 100644 --- a/go/vt/wrangler/validator.go +++ b/go/vt/wrangler/validator.go @@ -95,7 +95,7 @@ func (wr *Wrangler) validateAllTablets(ctx context.Context, wg *sync.WaitGroup, go func(alias *topodatapb.TabletAlias) { defer wg.Done() if err := topo.Validate(ctx, wr.ts, alias); err != nil { - results <- fmt.Errorf("Validate(%v) failed: %v", topoproto.TabletAliasString(alias), err) + results <- fmt.Errorf("topo.Validate(%v) failed: %v", topoproto.TabletAliasString(alias), err) } else { wr.Logger().Infof("tablet %v is valid", topoproto.TabletAliasString(alias)) } @@ -162,7 +162,7 @@ func (wr *Wrangler) validateShard(ctx context.Context, keyspace, shard string, p go func(alias *topodatapb.TabletAlias) { defer wg.Done() if err := topo.Validate(ctx, wr.ts, alias); err != nil { - results <- fmt.Errorf("Validate(%v) failed: %v", topoproto.TabletAliasString(alias), err) + results <- fmt.Errorf("topo.Validate(%v) failed: %v", topoproto.TabletAliasString(alias), err) } else { wr.Logger().Infof("tablet %v is valid", topoproto.TabletAliasString(alias)) } @@ -173,8 +173,6 @@ func (wr *Wrangler) validateShard(ctx context.Context, keyspace, shard string, p wr.validateReplication(ctx, shardInfo, tabletMap, results) wr.pingTablets(ctx, tabletMap, wg, results) } - - return } func normalizeIP(ip string) string { @@ -253,6 +251,7 @@ func (wr *Wrangler) pingTablets(ctx context.Context, tabletMap map[string]*topo. defer wg.Done() if err := wr.tmc.Ping(ctx, tabletInfo.Tablet); err != nil { + //lint:ignore ST1005 function name results <- fmt.Errorf("Ping(%v) failed: %v tablet hostname: %v", tabletAlias, err, tabletInfo.Hostname) } }(tabletAlias, tabletInfo) diff --git a/go/vt/wrangler/version.go b/go/vt/wrangler/version.go index 62298579ca3..92256d7af0b 100644 --- a/go/vt/wrangler/version.go +++ b/go/vt/wrangler/version.go @@ -94,7 +94,7 @@ func (wr *Wrangler) diffVersion(ctx context.Context, masterVersion string, maste } if masterVersion != slaveVersion { - er.RecordError(fmt.Errorf("Master %v version %v is different than slave %v version %v", topoproto.TabletAliasString(masterAlias), masterVersion, topoproto.TabletAliasString(alias), slaveVersion)) + er.RecordError(fmt.Errorf("master %v version %v is different than slave %v version %v", topoproto.TabletAliasString(masterAlias), masterVersion, topoproto.TabletAliasString(alias), slaveVersion)) } } @@ -108,7 +108,7 @@ func (wr *Wrangler) ValidateVersionShard(ctx context.Context, keyspace, shard st // get version from the master, or error if !si.HasMaster() { - return fmt.Errorf("No master in shard %v/%v", keyspace, shard) + return fmt.Errorf("no master in shard %v/%v", keyspace, shard) } log.Infof("Gathering version for master %v", topoproto.TabletAliasString(si.MasterAlias)) masterVersion, err := wr.GetVersion(ctx, si.MasterAlias) @@ -136,7 +136,7 @@ func (wr *Wrangler) ValidateVersionShard(ctx context.Context, keyspace, shard st } wg.Wait() if er.HasErrors() { - return fmt.Errorf("Version diffs: %v", er.Error().Error()) + return fmt.Errorf("version diffs: %v", er.Error().Error()) } return nil } @@ -152,7 +152,7 @@ func (wr *Wrangler) ValidateVersionKeyspace(ctx context.Context, keyspace string // corner cases if len(shards) == 0 { - return fmt.Errorf("No shards in keyspace %v", keyspace) + return fmt.Errorf("no shards in keyspace %v", keyspace) } sort.Strings(shards) if len(shards) == 1 { @@ -165,7 +165,7 @@ func (wr *Wrangler) ValidateVersionKeyspace(ctx context.Context, keyspace string return err } if !si.HasMaster() { - return fmt.Errorf("No master in shard %v/%v", keyspace, shards[0]) + return fmt.Errorf("no master in shard %v/%v", keyspace, shards[0]) } referenceAlias := si.MasterAlias log.Infof("Gathering version for reference master %v", topoproto.TabletAliasString(referenceAlias)) @@ -195,7 +195,7 @@ func (wr *Wrangler) ValidateVersionKeyspace(ctx context.Context, keyspace string } wg.Wait() if er.HasErrors() { - return fmt.Errorf("Version diffs: %v", er.Error().Error()) + return fmt.Errorf("version diffs: %v", er.Error().Error()) } return nil } From 90c99d1d65d493a917a1a3f092da4c8a6bb368ff Mon Sep 17 00:00:00 2001 From: deepthi Date: Sun, 3 Mar 2019 20:53:19 -0800 Subject: [PATCH 172/196] staticcheck: vttablet packages Signed-off-by: deepthi --- go/vt/vtexplain/vtexplain_vttablet.go | 2 +- go/vt/vttablet/agentrpctest/test_agent_rpc.go | 1 + go/vt/vttablet/endtoend/config_test.go | 4 + go/vt/vttablet/endtoend/message_test.go | 42 +++++---- go/vt/vttablet/endtoend/misc_test.go | 6 +- go/vt/vttablet/endtoend/transaction_test.go | 14 ++- go/vt/vttablet/grpcqueryservice/server.go | 3 +- go/vt/vttablet/heartbeat/reader.go | 2 +- .../queryservice/fakes/error_query_service.go | 2 +- go/vt/vttablet/queryservice/wrapped.go | 94 +++++++++---------- .../tabletconntest/fakequeryservice.go | 2 +- go/vt/vttablet/tabletmanager/action_agent.go | 3 +- .../tabletmanager/healthcheck_test.go | 4 +- .../tabletmanager/init_tablet_test.go | 2 +- go/vt/vttablet/tabletmanager/orchestrator.go | 2 +- .../tabletmanager/replication_reporter.go | 2 +- .../replication_reporter_test.go | 2 +- go/vt/vttablet/tabletserver/query_executor.go | 11 +-- .../tabletserver/query_executor_test.go | 5 +- go/vt/vttablet/tabletserver/query_list.go | 2 +- go/vt/vttablet/tabletserver/tabletserver.go | 10 +- .../tabletserver/tabletserver_test.go | 8 +- go/vt/vttablet/tabletserver/twopc.go | 2 +- go/vt/vttablet/tabletserver/twopcz.go | 1 - go/vt/vttablet/tabletserver/tx_engine.go | 6 +- go/vt/vttablet/tabletserver/tx_engine_test.go | 18 ++-- go/vt/vttablet/tabletserver/tx_pool.go | 2 +- .../tabletserver/tx_prep_pool_test.go | 9 +- go/vt/vttablet/tabletserver/txlogz.go | 2 +- test.go | 6 +- 30 files changed, 146 insertions(+), 123 deletions(-) diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 4b80522d6f8..421c6e4be65 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -88,7 +88,7 @@ func newTablet(opts *Options, t *topodatapb.Tablet) *explainTablet { tablet.QueryService = queryservice.Wrap( nil, - func(ctx context.Context, target *querypb.Target, conn queryservice.QueryService, name string, inTransaction bool, inner func(context.Context, *querypb.Target, queryservice.QueryService) (error, bool)) error { + func(ctx context.Context, target *querypb.Target, conn queryservice.QueryService, name string, inTransaction bool, inner func(context.Context, *querypb.Target, queryservice.QueryService) (bool, error)) error { return fmt.Errorf("explainTablet does not implement %s", name) }, ) diff --git a/go/vt/vttablet/agentrpctest/test_agent_rpc.go b/go/vt/vttablet/agentrpctest/test_agent_rpc.go index 19316f2605f..5632b66ae01 100644 --- a/go/vt/vttablet/agentrpctest/test_agent_rpc.go +++ b/go/vt/vttablet/agentrpctest/test_agent_rpc.go @@ -1271,6 +1271,7 @@ func Run(t *testing.T, client tmclient.TabletManagerClient, tablet *topodatapb.T agentRPCTestStopSlave(ctx, t, client, tablet) agentRPCTestStopSlaveMinimum(ctx, t, client, tablet) agentRPCTestStartSlave(ctx, t, client, tablet) + agentRPCTestStartSlaveUntilAfter(ctx, t, client, tablet) agentRPCTestTabletExternallyReparented(ctx, t, client, tablet) agentRPCTestGetSlaves(ctx, t, client, tablet) diff --git a/go/vt/vttablet/endtoend/config_test.go b/go/vt/vttablet/endtoend/config_test.go index 487b71574ec..7fa175faa2e 100644 --- a/go/vt/vttablet/endtoend/config_test.go +++ b/go/vt/vttablet/endtoend/config_test.go @@ -293,6 +293,10 @@ func TestMaxDMLRows(t *testing.T) { "(3, 1, '', ''), (3, 2, '', ''), (3, 3, '', '')", nil, ) + if err != nil { + t.Error(err) + return + } catcher := framework.NewQueryCatcher() defer catcher.Close() diff --git a/go/vt/vttablet/endtoend/message_test.go b/go/vt/vttablet/endtoend/message_test.go index f496ed91887..913b4ae93e3 100644 --- a/go/vt/vttablet/endtoend/message_test.go +++ b/go/vt/vttablet/endtoend/message_test.go @@ -43,10 +43,11 @@ var createMessage = `create table vitess_message( comment 'vitess_message,vt_ack_wait=1,vt_purge_after=3,vt_batch_size=2,vt_cache_size=10,vt_poller_interval=1'` func TestMessage(t *testing.T) { + var err error ch := make(chan *sqltypes.Result) done := make(chan struct{}) client := framework.NewClient() - if _, err := client.Execute(createMessage, nil); err != nil { + if _, err = client.Execute(createMessage, nil); err != nil { t.Fatal(err) } defer client.Execute("drop table vitess_message", nil) @@ -60,7 +61,7 @@ func TestMessage(t *testing.T) { // Start goroutine to consume message stream. go func() { - if err := client.MessageStream("vitess_message", func(qr *sqltypes.Result) error { + err = client.MessageStream("vitess_message", func(qr *sqltypes.Result) error { select { case <-done: return io.EOF @@ -68,11 +69,12 @@ func TestMessage(t *testing.T) { } ch <- qr return nil - }); err != nil { - t.Fatal(err) - } + }) close(ch) }() + if err != nil { + t.Fatal(err) + } got := <-ch want := &sqltypes.Result{ Fields: []*querypb.Field{{ @@ -93,7 +95,7 @@ func TestMessage(t *testing.T) { defer func() { close(done) }() // Create message. - err := client.Begin(false) + err = client.Begin(false) if err != nil { t.Error(err) return @@ -240,16 +242,17 @@ var createThreeColMessage = `create table vitess_message3( comment 'vitess_message,vt_ack_wait=1,vt_purge_after=3,vt_batch_size=2,vt_cache_size=10,vt_poller_interval=1'` func TestThreeColMessage(t *testing.T) { + var err error ch := make(chan *sqltypes.Result) done := make(chan struct{}) client := framework.NewClient() - if _, err := client.Execute(createThreeColMessage, nil); err != nil { + if _, err = client.Execute(createThreeColMessage, nil); err != nil { t.Fatal(err) } defer client.Execute("drop table vitess_message3", nil) go func() { - if err := client.MessageStream("vitess_message3", func(qr *sqltypes.Result) error { + err = client.MessageStream("vitess_message3", func(qr *sqltypes.Result) error { select { case <-done: return io.EOF @@ -257,11 +260,12 @@ func TestThreeColMessage(t *testing.T) { } ch <- qr return nil - }); err != nil { - t.Fatal(err) - } + }) close(ch) }() + if err != nil { + t.Fatal(err) + } // Verify fields. got := <-ch @@ -285,7 +289,7 @@ func TestThreeColMessage(t *testing.T) { } runtime.Gosched() defer func() { close(done) }() - err := client.Begin(false) + err = client.Begin(false) if err != nil { t.Error(err) return @@ -349,17 +353,18 @@ comment 'vitess_message,vt_ack_wait=1,vt_purge_after=3,vt_batch_size=1,vt_cache_ // TestMessageAuto tests for the case where id is an auto-inc column. func TestMessageAuto(t *testing.T) { + var err error ch := make(chan *sqltypes.Result) done := make(chan struct{}) client := framework.NewClient() - if _, err := client.Execute(createMessageAuto, nil); err != nil { + if _, err = client.Execute(createMessageAuto, nil); err != nil { t.Fatal(err) } defer client.Execute("drop table vitess_message_auto", nil) // Start goroutine to consume message stream. go func() { - if err := client.MessageStream("vitess_message_auto", func(qr *sqltypes.Result) error { + err = client.MessageStream("vitess_message_auto", func(qr *sqltypes.Result) error { select { case <-done: return io.EOF @@ -367,16 +372,17 @@ func TestMessageAuto(t *testing.T) { } ch <- qr return nil - }); err != nil { - t.Fatal(err) - } + }) close(ch) }() + if err != nil { + t.Fatal(err) + } <-ch defer func() { close(done) }() // Create message. - err := client.Begin(false) + err = client.Begin(false) if err != nil { t.Error(err) return diff --git a/go/vt/vttablet/endtoend/misc_test.go b/go/vt/vttablet/endtoend/misc_test.go index 81fb606ba0a..4544ac0bc31 100644 --- a/go/vt/vttablet/endtoend/misc_test.go +++ b/go/vt/vttablet/endtoend/misc_test.go @@ -476,7 +476,7 @@ func TestQueryStats(t *testing.T) { t.Fatal(err) } stat := framework.QueryStats()[query] - duration := int(time.Now().Sub(start)) + duration := int(time.Since(start)) if stat.Time <= 0 || stat.Time > duration { t.Errorf("stat.Time: %d, must be between 0 and %d", stat.Time, duration) } @@ -706,7 +706,7 @@ func TestClientFoundRows(t *testing.T) { func TestLastInsertId(t *testing.T) { client := framework.NewClient() - res, err := client.Execute("insert ignore into vitess_autoinc_seq SET name = 'foo', sequence = 0", nil) + _, err := client.Execute("insert ignore into vitess_autoinc_seq SET name = 'foo', sequence = 0", nil) if err != nil { t.Fatal(err) } @@ -717,7 +717,7 @@ func TestLastInsertId(t *testing.T) { } defer client.Rollback() - res, err = client.Execute("insert ignore into vitess_autoinc_seq SET name = 'foo', sequence = 0", nil) + res, err := client.Execute("insert ignore into vitess_autoinc_seq SET name = 'foo', sequence = 0", nil) if err != nil { t.Fatal(err) } diff --git a/go/vt/vttablet/endtoend/transaction_test.go b/go/vt/vttablet/endtoend/transaction_test.go index 40557ee724c..ae15d5da92d 100644 --- a/go/vt/vttablet/endtoend/transaction_test.go +++ b/go/vt/vttablet/endtoend/transaction_test.go @@ -713,7 +713,7 @@ func TestWatchdog(t *testing.T) { if dtid != "aa" { t.Errorf("dtid: %s, want aa", dtid) } - diff := time.Now().Sub(start) + diff := time.Since(start) if diff < 1*time.Second { t.Errorf("diff: %v, want greater than 1s", diff) } @@ -797,6 +797,10 @@ func TestManualTwopcz(t *testing.T) { return } _, err = client.Execute("insert into vitess_test (intval, floatval, charval, binval) values(4, null, null, null)", nil) + if err != nil { + t.Error(err) + return + } _, err = client.Execute("insert into vitess_test (intval, floatval, charval, binval) values(5, null, null, null)", nil) if err != nil { t.Error(err) @@ -816,6 +820,10 @@ func TestManualTwopcz(t *testing.T) { return } _, err = client.Execute("insert into vitess_test (intval, floatval, charval, binval) values(6, null, null, null)", nil) + if err != nil { + t.Error(err) + return + } _, err = client.Execute("insert into vitess_test (intval, floatval, charval, binval) values(7, null, null, null)", nil) if err != nil { t.Error(err) @@ -840,6 +848,10 @@ func TestManualTwopcz(t *testing.T) { }}) defer client.ConcludeTransaction("distributed") + if err != nil { + t.Error(err) + return + } fmt.Printf("%s/twopcz\n", framework.ServerAddress) fmt.Print("Sleeping for 30 seconds\n") time.Sleep(30 * time.Second) diff --git a/go/vt/vttablet/grpcqueryservice/server.go b/go/vt/vttablet/grpcqueryservice/server.go index 3ea8fb016fb..36a776ae540 100644 --- a/go/vt/vttablet/grpcqueryservice/server.go +++ b/go/vt/vttablet/grpcqueryservice/server.go @@ -335,8 +335,7 @@ func (q *query) SplitQuery(ctx context.Context, request *querypb.SplitQueryReque request.EffectiveCallerId, request.ImmediateCallerId, ) - splits := []*querypb.QuerySplit{} - splits, err = q.server.SplitQuery( + splits, err := q.server.SplitQuery( ctx, request.Target, request.Query, diff --git a/go/vt/vttablet/heartbeat/reader.go b/go/vt/vttablet/heartbeat/reader.go index 883023bf607..78b61ff1cff 100644 --- a/go/vt/vttablet/heartbeat/reader.go +++ b/go/vt/vttablet/heartbeat/reader.go @@ -207,7 +207,7 @@ func (r *Reader) bindHeartbeatFetch() (string, error) { // parseHeartbeatResult turns a raw result into the timestamp for processing. func parseHeartbeatResult(res *sqltypes.Result) (int64, error) { if len(res.Rows) != 1 { - return 0, fmt.Errorf("Failed to read heartbeat: writer query did not result in 1 row. Got %v", len(res.Rows)) + return 0, fmt.Errorf("failed to read heartbeat: writer query did not result in 1 row. Got %v", len(res.Rows)) } ts, err := sqltypes.ToInt64(res.Rows[0][0]) if err != nil { diff --git a/go/vt/vttablet/queryservice/fakes/error_query_service.go b/go/vt/vttablet/queryservice/fakes/error_query_service.go index e113a69941a..f32febf6fd4 100644 --- a/go/vt/vttablet/queryservice/fakes/error_query_service.go +++ b/go/vt/vttablet/queryservice/fakes/error_query_service.go @@ -28,7 +28,7 @@ import ( // ErrorQueryService is an object that returns an error for all methods. var ErrorQueryService = queryservice.Wrap( nil, - func(ctx context.Context, target *querypb.Target, conn queryservice.QueryService, name string, inTransaction bool, inner func(context.Context, *querypb.Target, queryservice.QueryService) (error, bool)) error { + func(ctx context.Context, target *querypb.Target, conn queryservice.QueryService, name string, inTransaction bool, inner func(context.Context, *querypb.Target, queryservice.QueryService) (bool, error)) error { return fmt.Errorf("ErrorQueryService does not implement any method") }, ) diff --git a/go/vt/vttablet/queryservice/wrapped.go b/go/vt/vttablet/queryservice/wrapped.go index d0873b22af0..9d25d42dbd0 100644 --- a/go/vt/vttablet/queryservice/wrapped.go +++ b/go/vt/vttablet/queryservice/wrapped.go @@ -34,7 +34,7 @@ var _ QueryService = &wrappedService{} // The inner function returns err and canRetry. // If canRetry is true, the error is specific to the current vttablet and can be retried elsewhere. // The flag will be false if there was no error. -type WrapperFunc func(ctx context.Context, target *querypb.Target, conn QueryService, name string, inTransaction bool, inner func(context.Context, *querypb.Target, QueryService) (err error, canRetry bool)) error +type WrapperFunc func(ctx context.Context, target *querypb.Target, conn QueryService, name string, inTransaction bool, inner func(context.Context, *querypb.Target, QueryService) (canRetry bool, err error)) error // Wrap returns a wrapped version of the original QueryService implementation. // This lets you avoid repeating boiler-plate code by consolidating it in the @@ -84,100 +84,100 @@ type wrappedService struct { } func (ws *wrappedService) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (transactionID int64, err error) { - err = ws.wrapper(ctx, target, ws.impl, "Begin", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + err = ws.wrapper(ctx, target, ws.impl, "Begin", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error transactionID, innerErr = conn.Begin(ctx, target, options) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) return transactionID, err } func (ws *wrappedService) Commit(ctx context.Context, target *querypb.Target, transactionID int64) error { - return ws.wrapper(ctx, target, ws.impl, "Commit", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "Commit", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.Commit(ctx, target, transactionID) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) Rollback(ctx context.Context, target *querypb.Target, transactionID int64) error { - return ws.wrapper(ctx, target, ws.impl, "Rollback", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "Rollback", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.Rollback(ctx, target, transactionID) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) Prepare(ctx context.Context, target *querypb.Target, transactionID int64, dtid string) error { - return ws.wrapper(ctx, target, ws.impl, "Prepare", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "Prepare", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.Prepare(ctx, target, transactionID, dtid) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) CommitPrepared(ctx context.Context, target *querypb.Target, dtid string) (err error) { - return ws.wrapper(ctx, target, ws.impl, "CommitPrepared", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "CommitPrepared", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.CommitPrepared(ctx, target, dtid) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) RollbackPrepared(ctx context.Context, target *querypb.Target, dtid string, originalID int64) (err error) { - return ws.wrapper(ctx, target, ws.impl, "RollbackPrepared", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "RollbackPrepared", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.RollbackPrepared(ctx, target, dtid, originalID) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) CreateTransaction(ctx context.Context, target *querypb.Target, dtid string, participants []*querypb.Target) (err error) { - return ws.wrapper(ctx, target, ws.impl, "CreateTransaction", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "CreateTransaction", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.CreateTransaction(ctx, target, dtid, participants) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) StartCommit(ctx context.Context, target *querypb.Target, transactionID int64, dtid string) (err error) { - return ws.wrapper(ctx, target, ws.impl, "StartCommit", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "StartCommit", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.StartCommit(ctx, target, transactionID, dtid) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) SetRollback(ctx context.Context, target *querypb.Target, dtid string, transactionID int64) (err error) { - return ws.wrapper(ctx, target, ws.impl, "SetRollback", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "SetRollback", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.SetRollback(ctx, target, dtid, transactionID) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) ConcludeTransaction(ctx context.Context, target *querypb.Target, dtid string) (err error) { - return ws.wrapper(ctx, target, ws.impl, "ConcludeTransaction", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "ConcludeTransaction", true, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.ConcludeTransaction(ctx, target, dtid) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) ReadTransaction(ctx context.Context, target *querypb.Target, dtid string) (metadata *querypb.TransactionMetadata, err error) { - err = ws.wrapper(ctx, target, ws.impl, "ReadTransaction", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + err = ws.wrapper(ctx, target, ws.impl, "ReadTransaction", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error metadata, innerErr = conn.ReadTransaction(ctx, target, dtid) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) return metadata, err } func (ws *wrappedService) Execute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, transactionID int64, options *querypb.ExecuteOptions) (qr *sqltypes.Result, err error) { inTransaction := (transactionID != 0) - err = ws.wrapper(ctx, target, ws.impl, "Execute", inTransaction, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + err = ws.wrapper(ctx, target, ws.impl, "Execute", inTransaction, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error qr, innerErr = conn.Execute(ctx, target, query, bindVars, transactionID, options) // You cannot retry if you're in a transaction. retryable := canRetry(ctx, innerErr) && (!inTransaction) - return innerErr, retryable + return retryable, innerErr }) return qr, err } func (ws *wrappedService) StreamExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, transactionID int64, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) error { - return ws.wrapper(ctx, target, ws.impl, "StreamExecute", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "StreamExecute", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { streamingStarted := false innerErr := conn.StreamExecute(ctx, target, query, bindVars, transactionID, options, func(qr *sqltypes.Result) error { streamingStarted = true @@ -185,83 +185,83 @@ func (ws *wrappedService) StreamExecute(ctx context.Context, target *querypb.Tar }) // You cannot restart a stream once it's sent results. retryable := canRetry(ctx, innerErr) && (!streamingStarted) - return innerErr, retryable + return retryable, innerErr }) } func (ws *wrappedService) ExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, transactionID int64, options *querypb.ExecuteOptions) (qrs []sqltypes.Result, err error) { inTransaction := (transactionID != 0) - err = ws.wrapper(ctx, target, ws.impl, "ExecuteBatch", inTransaction, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + err = ws.wrapper(ctx, target, ws.impl, "ExecuteBatch", inTransaction, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error qrs, innerErr = conn.ExecuteBatch(ctx, target, queries, asTransaction, transactionID, options) // You cannot retry if you're in a transaction. retryable := canRetry(ctx, innerErr) && (!inTransaction) - return innerErr, retryable + return retryable, innerErr }) return qrs, err } func (ws *wrappedService) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (qr *sqltypes.Result, transactionID int64, err error) { - err = ws.wrapper(ctx, target, ws.impl, "BeginExecute", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + err = ws.wrapper(ctx, target, ws.impl, "BeginExecute", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error qr, transactionID, innerErr = conn.BeginExecute(ctx, target, query, bindVars, options) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) return qr, transactionID, err } func (ws *wrappedService) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) (qrs []sqltypes.Result, transactionID int64, err error) { - err = ws.wrapper(ctx, target, ws.impl, "BeginExecuteBatch", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + err = ws.wrapper(ctx, target, ws.impl, "BeginExecuteBatch", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error qrs, transactionID, innerErr = conn.BeginExecuteBatch(ctx, target, queries, asTransaction, options) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) return qrs, transactionID, err } func (ws *wrappedService) MessageStream(ctx context.Context, target *querypb.Target, name string, callback func(*sqltypes.Result) error) error { - return ws.wrapper(ctx, target, ws.impl, "MessageStream", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "MessageStream", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.MessageStream(ctx, target, name, callback) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) MessageAck(ctx context.Context, target *querypb.Target, name string, ids []*querypb.Value) (count int64, err error) { - err = ws.wrapper(ctx, target, ws.impl, "MessageAck", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + err = ws.wrapper(ctx, target, ws.impl, "MessageAck", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error count, innerErr = conn.MessageAck(ctx, target, name, ids) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) return count, err } func (ws *wrappedService) SplitQuery(ctx context.Context, target *querypb.Target, query *querypb.BoundQuery, splitColumns []string, splitCount int64, numRowsPerQueryPart int64, algorithm querypb.SplitQueryRequest_Algorithm) (queries []*querypb.QuerySplit, err error) { - err = ws.wrapper(ctx, target, ws.impl, "SplitQuery", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + err = ws.wrapper(ctx, target, ws.impl, "SplitQuery", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error queries, innerErr = conn.SplitQuery(ctx, target, query, splitColumns, splitCount, numRowsPerQueryPart, algorithm) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) return queries, err } func (ws *wrappedService) UpdateStream(ctx context.Context, target *querypb.Target, position string, timestamp int64, callback func(*querypb.StreamEvent) error) error { - return ws.wrapper(ctx, target, ws.impl, "UpdateStream", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "UpdateStream", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.UpdateStream(ctx, target, position, timestamp, callback) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) VStream(ctx context.Context, target *querypb.Target, startPos string, filter *binlogdatapb.Filter, send func([]*binlogdatapb.VEvent) error) error { - return ws.wrapper(ctx, target, ws.impl, "UpdateStream", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, target, ws.impl, "UpdateStream", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.VStream(ctx, target, startPos, filter, send) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } func (ws *wrappedService) StreamHealth(ctx context.Context, callback func(*querypb.StreamHealthResponse) error) error { - return ws.wrapper(ctx, nil, ws.impl, "StreamHealth", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, nil, ws.impl, "StreamHealth", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { innerErr := conn.StreamHealth(ctx, callback) - return innerErr, canRetry(ctx, innerErr) + return canRetry(ctx, innerErr), innerErr }) } @@ -270,8 +270,8 @@ func (ws *wrappedService) HandlePanic(err *error) { } func (ws *wrappedService) Close(ctx context.Context) error { - return ws.wrapper(ctx, nil, ws.impl, "Close", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (error, bool) { + return ws.wrapper(ctx, nil, ws.impl, "Close", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { // No point retrying Close. - return conn.Close(ctx), false + return false, conn.Close(ctx) }) } diff --git a/go/vt/vttablet/tabletconntest/fakequeryservice.go b/go/vt/vttablet/tabletconntest/fakequeryservice.go index 5a935e5867f..51ae53f8b33 100644 --- a/go/vt/vttablet/tabletconntest/fakequeryservice.go +++ b/go/vt/vttablet/tabletconntest/fakequeryservice.go @@ -578,7 +578,7 @@ func (f *FakeQueryService) ExecuteBatch(ctx context.Context, target *querypb.Tar f.t.Errorf("invalid ExecuteBatch.ExecuteOptions: got %v expected %v", options, TestExecuteOptions) } f.checkTargetCallerID(ctx, "ExecuteBatch", target) - if asTransaction != TestAsTransaction { + if !asTransaction { f.t.Errorf("invalid ExecuteBatch.AsTransaction: got %v expected %v", asTransaction, TestAsTransaction) } if transactionID != f.ExpectedTransactionID { diff --git a/go/vt/vttablet/tabletmanager/action_agent.go b/go/vt/vttablet/tabletmanager/action_agent.go index 2663fe4ac10..e55377e7993 100644 --- a/go/vt/vttablet/tabletmanager/action_agent.go +++ b/go/vt/vttablet/tabletmanager/action_agent.go @@ -209,7 +209,8 @@ type ActionAgent struct { // _lockTablesConnection is used to get and release the table read locks to pause replication _lockTablesConnection *dbconnpool.DBConnection _lockTablesTimer *time.Timer - _lockTablesTimeout *time.Duration + // unused + //_lockTablesTimeout *time.Duration } // NewActionAgent creates a new ActionAgent and registers all the diff --git a/go/vt/vttablet/tabletmanager/healthcheck_test.go b/go/vt/vttablet/tabletmanager/healthcheck_test.go index 2084bd283a7..06af56d5b69 100644 --- a/go/vt/vttablet/tabletmanager/healthcheck_test.go +++ b/go/vt/vttablet/tabletmanager/healthcheck_test.go @@ -710,9 +710,7 @@ func TestStateChangeImmediateHealthBroadcast(t *testing.T) { if err := agent.TabletExternallyReparented(ctx, "unused_id"); err != nil { t.Fatal(err) } - select { - case <-agent.finalizeReparentCtx.Done(): - } + <-agent.finalizeReparentCtx.Done() ti, err := agent.TopoServer.GetTablet(ctx, tabletAlias) if err != nil { t.Fatalf("GetTablet failed: %v", err) diff --git a/go/vt/vttablet/tabletmanager/init_tablet_test.go b/go/vt/vttablet/tabletmanager/init_tablet_test.go index 1171474637e..5ecabe33519 100644 --- a/go/vt/vttablet/tabletmanager/init_tablet_test.go +++ b/go/vt/vttablet/tabletmanager/init_tablet_test.go @@ -255,7 +255,7 @@ func TestInitTablet(t *testing.T) { // (This simulates the case where the MasterAlias in the shard record says // that we are the master but the tablet record says otherwise. In that case, // we assume we are not the MASTER.) - si, err = agent.TopoServer.UpdateShardFields(ctx, "test_keyspace", "-c0", func(si *topo.ShardInfo) error { + _, err = agent.TopoServer.UpdateShardFields(ctx, "test_keyspace", "-c0", func(si *topo.ShardInfo) error { si.MasterAlias = tabletAlias return nil }) diff --git a/go/vt/vttablet/tabletmanager/orchestrator.go b/go/vt/vttablet/tabletmanager/orchestrator.go index 87a1eacdaea..95e37d2ccde 100644 --- a/go/vt/vttablet/tabletmanager/orchestrator.go +++ b/go/vt/vttablet/tabletmanager/orchestrator.go @@ -156,7 +156,7 @@ func (orc *orcClient) InActiveShardRecovery(tablet *topodatapb.Tablet) (bool, er active, ok := r[0]["IsActive"].(bool) if !ok { - return false, fmt.Errorf("Error parsing JSON response from Orchestrator") + return false, fmt.Errorf("error parsing JSON response from Orchestrator") } return active, nil } diff --git a/go/vt/vttablet/tabletmanager/replication_reporter.go b/go/vt/vttablet/tabletmanager/replication_reporter.go index 97c4590269b..027a11f6bfd 100644 --- a/go/vt/vttablet/tabletmanager/replication_reporter.go +++ b/go/vt/vttablet/tabletmanager/replication_reporter.go @@ -133,7 +133,7 @@ func repairReplication(ctx context.Context, agent *ActionAgent) error { return err } if re { - return fmt.Errorf("Orchestrator actively reparenting shard %v, skipping repairReplication", si) + return fmt.Errorf("orchestrator actively reparenting shard %v, skipping repairReplication", si) } // Before repairing replication, tell Orchestrator to enter maintenance mode for this tablet and to diff --git a/go/vt/vttablet/tabletmanager/replication_reporter_test.go b/go/vt/vttablet/tabletmanager/replication_reporter_test.go index 5365ac06313..d1a030f4369 100644 --- a/go/vt/vttablet/tabletmanager/replication_reporter_test.go +++ b/go/vt/vttablet/tabletmanager/replication_reporter_test.go @@ -105,7 +105,7 @@ func TestNoExtrapolatedMySQLReplicationLag(t *testing.T) { // now 20 seconds later, mysqld is down now = now.Add(20 * time.Second) mysqld.SlaveStatusError = errors.New("mysql is down") - dur, err = rep.Report(true, true) + _, err = rep.Report(true, true) if err != mysqld.SlaveStatusError { t.Fatalf("wrong Report error: %v", err) } diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index 079486b8db2..7576f920a85 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -74,7 +74,7 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { planName := qre.plan.PlanID.String() qre.logStats.PlanType = planName defer func(start time.Time) { - duration := time.Now().Sub(start) + duration := time.Since(start) tabletenv.QueryStats.Add(planName, duration) tabletenv.RecordUserQuery(qre.ctx, qre.plan.TableName(), "Execute", int64(duration)) @@ -115,7 +115,6 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { Extras: nil, }, nil } - break } if qre.transactionID != 0 { @@ -212,7 +211,7 @@ func (qre *QueryExecutor) Stream(callback func(*sqltypes.Result) error) error { defer func(start time.Time) { tabletenv.QueryStats.Record(qre.plan.PlanID.String(), start) - tabletenv.RecordUserQuery(qre.ctx, qre.plan.TableName(), "Stream", int64(time.Now().Sub(start))) + tabletenv.RecordUserQuery(qre.ctx, qre.plan.TableName(), "Stream", int64(time.Since(start))) }(time.Now()) if err := qre.checkPermissions(); err != nil { @@ -251,7 +250,7 @@ func (qre *QueryExecutor) MessageStream(callback func(*sqltypes.Result) error) e defer func(start time.Time) { tabletenv.QueryStats.Record(qre.plan.PlanID.String(), start) - tabletenv.RecordUserQuery(qre.ctx, qre.plan.TableName(), "MessageStream", int64(time.Now().Sub(start))) + tabletenv.RecordUserQuery(qre.ctx, qre.plan.TableName(), "MessageStream", int64(time.Since(start))) }(time.Now()) if err := qre.checkPermissions(); err != nil { @@ -798,7 +797,7 @@ func (qre *QueryExecutor) getConn() (*connpool.DBConn, error) { conn, err := qre.tsv.qe.getQueryConn(qre.ctx) switch err { case nil: - qre.logStats.WaitingForConnection += time.Now().Sub(start) + qre.logStats.WaitingForConnection += time.Since(start) return conn, nil case connpool.ErrConnPoolClosed: return nil, err @@ -815,7 +814,7 @@ func (qre *QueryExecutor) getStreamConn() (*connpool.DBConn, error) { conn, err := qre.tsv.qe.streamConns.Get(qre.ctx) switch err { case nil: - qre.logStats.WaitingForConnection += time.Now().Sub(start) + qre.logStats.WaitingForConnection += time.Since(start) return conn, nil case connpool.ErrConnPoolClosed: return nil, err diff --git a/go/vt/vttablet/tabletserver/query_executor_test.go b/go/vt/vttablet/tabletserver/query_executor_test.go index d131ac81583..ecfb187fc71 100644 --- a/go/vt/vttablet/tabletserver/query_executor_test.go +++ b/go/vt/vttablet/tabletserver/query_executor_test.go @@ -146,6 +146,10 @@ func TestQueryExecutorPassthroughDml(t *testing.T) { tsv.SetAllowUnsafeDMLs(true) got, err = qre.Execute() + + if err != nil { + t.Fatalf("qre.Execute() = %v, want nil", err) + } if !reflect.DeepEqual(got, want) { t.Fatalf("got: %v, want: %v", got, want) } @@ -612,7 +616,6 @@ func TestQueryExecutorPlanUpsertPk(t *testing.T) { if err == nil || !strings.Contains(err.Error(), wantErr) { t.Errorf("qre.Execute() = %v, want %v", err, wantErr) } - wantqueries = []string{} if gotqueries = fetchRecordedQueries(qre); gotqueries != nil { t.Errorf("queries: %v, want nil", gotqueries) } diff --git a/go/vt/vttablet/tabletserver/query_list.go b/go/vt/vttablet/tabletserver/query_list.go index 020e1cdb649..1f801fae5ff 100644 --- a/go/vt/vttablet/tabletserver/query_list.go +++ b/go/vt/vttablet/tabletserver/query_list.go @@ -118,7 +118,7 @@ func (ql *QueryList) GetQueryzRows() []QueryDetailzRow { Query: qd.conn.Current(), ContextHTML: callinfo.HTMLFromContext(qd.ctx), Start: qd.start, - Duration: time.Now().Sub(qd.start), + Duration: time.Since(qd.start), ConnID: qd.connID, } rows = append(rows, row) diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index 01e7082258a..9c5881c5c8f 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -1383,7 +1383,7 @@ func (tsv *TabletServer) SplitQuery( } defer func(start time.Time) { splitTableName := splitParams.GetSplitTableName() - tabletenv.RecordUserQuery(ctx, splitTableName, "SplitQuery", int64(time.Now().Sub(start))) + tabletenv.RecordUserQuery(ctx, splitTableName, "SplitQuery", int64(time.Since(start))) }(time.Now()) sqlExecuter, err := newSplitQuerySQLExecuter(ctx, logStats, tsv) if err != nil { @@ -1557,7 +1557,7 @@ func truncateSQLAndBindVars(sql string, bindVariables map[string]*querypb.BindVa fmt.Fprintf(buf, "%s: %q", key, valString) } fmt.Fprintf(buf, "}") - bv := string(buf.Bytes()) + bv := buf.String() maxLen := *sqlparser.TruncateErrLen if maxLen != 0 && len(bv) > maxLen { bv = bv[:maxLen-12] + " [TRUNCATED]" @@ -1706,7 +1706,7 @@ func createSplitParams( return splitquery.NewSplitParamsGivenSplitCount( query, splitColumns, splitCount, schema) default: - panic(fmt.Errorf("Exactly one of {numRowsPerQueryPart, splitCount} must be"+ + panic(fmt.Errorf("exactly one of {numRowsPerQueryPart, splitCount} must be"+ " non zero. This should have already been caught by 'validateSplitQueryParameters' and "+ " returned as an error. Got: numRowsPerQueryPart=%v, splitCount=%v. SQL: %v", numRowsPerQueryPart, @@ -1781,7 +1781,7 @@ func createSplitQueryAlgorithmObject( case querypb.SplitQueryRequest_EQUAL_SPLITS: return splitquery.NewEqualSplitsAlgorithm(splitParams, sqlExecuter) default: - panic(fmt.Errorf("Unknown algorithm enum: %+v", algorithm)) + panic(fmt.Errorf("unknown algorithm enum: %+v", algorithm)) } } @@ -2191,7 +2191,7 @@ func queryAsString(sql string, bindVariables map[string]*querypb.BindVariable) s fmt.Fprintf(buf, "%s: %q", key, valString) } fmt.Fprintf(buf, "}") - return string(buf.Bytes()) + return buf.String() } // withTimeout returns a context based on the specified timeout. diff --git a/go/vt/vttablet/tabletserver/tabletserver_test.go b/go/vt/vttablet/tabletserver/tabletserver_test.go index 342567d5abe..96d09666e74 100644 --- a/go/vt/vttablet/tabletserver/tabletserver_test.go +++ b/go/vt/vttablet/tabletserver/tabletserver_test.go @@ -233,14 +233,14 @@ func TestDecideAction(t *testing.T) { } tsv.setState(StateTransitioning) - action, err = tsv.decideAction(topodatapb.TabletType_MASTER, false, nil) + _, err = tsv.decideAction(topodatapb.TabletType_MASTER, false, nil) want := "cannot SetServingType" if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("decideAction: %v, must contain %s", err, want) } tsv.setState(StateShuttingDown) - action, err = tsv.decideAction(topodatapb.TabletType_MASTER, false, nil) + _, err = tsv.decideAction(topodatapb.TabletType_MASTER, false, nil) want = "cannot SetServingType" if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("decideAction: %v, must contain %s", err, want) @@ -1919,7 +1919,7 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests(t *testing.T) { wg.Wait() - got, _ := tabletenv.WaitStats.Counts()["TxSerializer"] + got := tabletenv.WaitStats.Counts()["TxSerializer"] want := countStart + 0 if got != want { t.Fatalf("tx2 should have failed early and not tracked as serialized: got: %v want: %v", got, want) @@ -2013,7 +2013,7 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests_ExecuteBatchAsTrans wg.Wait() - got, _ := tabletenv.WaitStats.Counts()["TxSerializer"] + got := tabletenv.WaitStats.Counts()["TxSerializer"] want := countStart + 0 if got != want { t.Fatalf("tx2 should have failed early and not tracked as serialized: got: %v want: %v", got, want) diff --git a/go/vt/vttablet/tabletserver/twopc.go b/go/vt/vttablet/tabletserver/twopc.go index c86adb75e05..79be25c59f5 100644 --- a/go/vt/vttablet/tabletserver/twopc.go +++ b/go/vt/vttablet/tabletserver/twopc.go @@ -425,7 +425,7 @@ func (tpc *TwoPC) ReadTransaction(ctx context.Context, dtid string) (*querypb.Tr } result.State = querypb.TransactionState(st) if result.State < querypb.TransactionState_PREPARE || result.State > querypb.TransactionState_ROLLBACK { - return nil, fmt.Errorf("Unexpected state for dtid %s: %v", dtid, result.State) + return nil, fmt.Errorf("unexpected state for dtid %s: %v", dtid, result.State) } // A failure in time parsing will show up as a very old time, // which is harmless. diff --git a/go/vt/vttablet/tabletserver/twopcz.go b/go/vt/vttablet/tabletserver/twopcz.go index d5cc8ff7776..1d16ece1245 100644 --- a/go/vt/vttablet/tabletserver/twopcz.go +++ b/go/vt/vttablet/tabletserver/twopcz.go @@ -146,7 +146,6 @@ func twopczHandler(txe *TxExecutor, w http.ResponseWriter, r *http.Request) { var msg string if action != "" { if err != nil { - msg = err.Error() msg = fmt.Sprintf("%s(%s): %v", r.FormValue("Action"), dtid, err) } else { msg = fmt.Sprintf("%s(%s): completed.", r.FormValue("Action"), dtid) diff --git a/go/vt/vttablet/tabletserver/tx_engine.go b/go/vt/vttablet/tabletserver/tx_engine.go index 8ecd19b653c..cb928f9a934 100644 --- a/go/vt/vttablet/tabletserver/tx_engine.go +++ b/go/vt/vttablet/tabletserver/tx_engine.go @@ -306,10 +306,8 @@ func (te *TxEngine) unknownStateError() error { } func (te *TxEngine) blockUntilEndOfTransition() error { - select { - case <-te.transitionSignal: - return nil - } + <-te.transitionSignal + return nil } func (te *TxEngine) transitionTo(nextState txEngineState) error { diff --git a/go/vt/vttablet/tabletserver/tx_engine_test.go b/go/vt/vttablet/tabletserver/tx_engine_test.go index 8cbfef5556c..cb7c235e41c 100644 --- a/go/vt/vttablet/tabletserver/tx_engine_test.go +++ b/go/vt/vttablet/tabletserver/tx_engine_test.go @@ -49,7 +49,7 @@ func TestTxEngineClose(t *testing.T) { te.open() start := time.Now() te.close(false) - if diff := time.Now().Sub(start); diff > 500*time.Millisecond { + if diff := time.Since(start); diff > 500*time.Millisecond { t.Errorf("Close time: %v, must be under 0.5s", diff) } @@ -62,7 +62,7 @@ func TestTxEngineClose(t *testing.T) { c.Recycle() start = time.Now() te.close(false) - if diff := time.Now().Sub(start); diff < 500*time.Millisecond { + if diff := time.Since(start); diff < 500*time.Millisecond { t.Errorf("Close time: %v, must be over 0.5s", diff) } @@ -75,7 +75,7 @@ func TestTxEngineClose(t *testing.T) { c.Recycle() start = time.Now() te.close(true) - if diff := time.Now().Sub(start); diff > 500*time.Millisecond { + if diff := time.Since(start); diff > 500*time.Millisecond { t.Errorf("Close time: %v, must be under 0.5s", diff) } @@ -89,10 +89,10 @@ func TestTxEngineClose(t *testing.T) { c.Recycle() start = time.Now() te.close(false) - if diff := time.Now().Sub(start); diff > 500*time.Millisecond { + if diff := time.Since(start); diff > 500*time.Millisecond { t.Errorf("Close time: %v, must be under 0.5s", diff) } - if diff := time.Now().Sub(start); diff < 250*time.Millisecond { + if diff := time.Since(start); diff < 250*time.Millisecond { t.Errorf("Close time: %v, must be over 0.25s", diff) } @@ -114,10 +114,10 @@ func TestTxEngineClose(t *testing.T) { }() start = time.Now() te.close(false) - if diff := time.Now().Sub(start); diff > 250*time.Millisecond { + if diff := time.Since(start); diff > 250*time.Millisecond { t.Errorf("Close time: %v, must be under 0.25s", diff) } - if diff := time.Now().Sub(start); diff < 100*time.Millisecond { + if diff := time.Since(start); diff < 100*time.Millisecond { t.Errorf("Close time: %v, must be over 0.1", diff) } @@ -133,10 +133,10 @@ func TestTxEngineClose(t *testing.T) { }() start = time.Now() te.close(true) - if diff := time.Now().Sub(start); diff > 250*time.Millisecond { + if diff := time.Since(start); diff > 250*time.Millisecond { t.Errorf("Close time: %v, must be under 0.25s", diff) } - if diff := time.Now().Sub(start); diff < 100*time.Millisecond { + if diff := time.Since(start); diff < 100*time.Millisecond { t.Errorf("Close time: %v, must be over 0.1", diff) } } diff --git a/go/vt/vttablet/tabletserver/tx_pool.go b/go/vt/vttablet/tabletserver/tx_pool.go index 0c47f93f33c..531ecd24c9a 100644 --- a/go/vt/vttablet/tabletserver/tx_pool.go +++ b/go/vt/vttablet/tabletserver/tx_pool.go @@ -342,7 +342,7 @@ func (axp *TxPool) localRollback(ctx context.Context, conn *TxConnection) error func (axp *TxPool) LogActive() { axp.logMu.Lock() defer axp.logMu.Unlock() - if time.Now().Sub(axp.lastLog) < txLogInterval { + if time.Since(axp.lastLog) < txLogInterval { return } axp.lastLog = time.Now() diff --git a/go/vt/vttablet/tabletserver/tx_prep_pool_test.go b/go/vt/vttablet/tabletserver/tx_prep_pool_test.go index f7ffc0881b9..d3313d809b8 100644 --- a/go/vt/vttablet/tabletserver/tx_prep_pool_test.go +++ b/go/vt/vttablet/tabletserver/tx_prep_pool_test.go @@ -50,6 +50,9 @@ func TestPrepPut(t *testing.T) { t.Errorf("Put err: %v, want %s", err, want) } _, err = pp.FetchForCommit("aa") + if err != nil { + t.Error(err) + } err = pp.Put(nil, "aa") want = "duplicate DTID in Prepare: aa" if err == nil || err.Error() != want { @@ -98,19 +101,19 @@ func TestPrepFetchForCommit(t *testing.T) { if got != conn { t.Errorf("pp.Get(aa): %p, want %p", got, conn) } - got, err = pp.FetchForCommit("aa") + _, err = pp.FetchForCommit("aa") want := "committing" if err == nil || err.Error() != want { t.Errorf("FetchForCommit err: %v, want %s", err, want) } pp.SetFailed("aa") - got, err = pp.FetchForCommit("aa") + _, err = pp.FetchForCommit("aa") want = "failed" if err == nil || err.Error() != want { t.Errorf("FetchForCommit err: %v, want %s", err, want) } pp.SetFailed("bb") - got, err = pp.FetchForCommit("bb") + _, err = pp.FetchForCommit("bb") want = "failed" if err == nil || err.Error() != want { t.Errorf("FetchForCommit err: %v, want %s", err, want) diff --git a/go/vt/vttablet/tabletserver/txlogz.go b/go/vt/vttablet/tabletserver/txlogz.go index 25e2097865c..553c2631906 100644 --- a/go/vt/vttablet/tabletserver/txlogz.go +++ b/go/vt/vttablet/tabletserver/txlogz.go @@ -113,7 +113,7 @@ func txlogzHandler(w http.ResponseWriter, req *http.Request) { case out := <-ch: txc, ok := out.(*TxConnection) if !ok { - err := fmt.Errorf("Unexpected value in %s: %#v (expecting value of type %T)", tabletenv.TxLogger.Name(), out, &TxConnection{}) + err := fmt.Errorf("unexpected value in %s: %#v (expecting value of type %T)", tabletenv.TxLogger.Name(), out, &TxConnection{}) io.WriteString(w, ``) io.WriteString(w, err.Error()) io.WriteString(w, "") diff --git a/test.go b/test.go index d88cb105b04..208c073dd42 100755 --- a/test.go +++ b/test.go @@ -414,7 +414,7 @@ func main() { flaky := 0 // Listen for signals. - sigchan := make(chan os.Signal) + sigchan := make(chan os.Signal, 1) signal.Notify(sigchan, syscall.SIGINT) // Run tests. @@ -563,7 +563,7 @@ func main() { } // Print summary. - log.Printf(strings.Repeat("=", 60)) + log.Print(strings.Repeat("=", 60)) for _, t := range tests { tname := t.flavor + "." + t.name switch { @@ -577,7 +577,7 @@ func main() { log.Printf("%-40s\tSKIPPED", tname) } } - log.Printf(strings.Repeat("=", 60)) + log.Print(strings.Repeat("=", 60)) skipped := len(tests) - passed - flaky - failed log.Printf("%v PASSED, %v FLAKY, %v FAILED, %v SKIPPED", passed, flaky, failed, skipped) log.Printf("Total time: %v", round(time.Since(startTime))) From 0bf3d5bd21a60308a3e3d75be663c57323fd13fc Mon Sep 17 00:00:00 2001 From: deepthi Date: Sun, 3 Mar 2019 21:30:55 -0800 Subject: [PATCH 173/196] staticcheck: handle errors from goroutines in tests correctly Signed-off-by: deepthi --- go/vt/tlstest/tlstest_test.go | 9 +++++---- go/vt/worker/legacy_split_clone_test.go | 15 ++++++++++----- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/go/vt/tlstest/tlstest_test.go b/go/vt/tlstest/tlstest_test.go index d033795582e..785b2978d2b 100644 --- a/go/vt/tlstest/tlstest_test.go +++ b/go/vt/tlstest/tlstest_test.go @@ -140,10 +140,6 @@ func TestClientServer(t *testing.T) { } }() - if serverErr != nil { - t.Fatalf("Connection failed: %v", serverErr) - } - // When using TLS 1.2, the Dial will fail. // With TLS 1.3, the Dial will succeed and the first Read will fail. clientConn, err := tls.Dial("tcp", addr, badClientConfig) @@ -153,6 +149,11 @@ func TestClientServer(t *testing.T) { } return } + wg.Wait() + if serverErr != nil { + t.Fatalf("Connection failed: %v", serverErr) + } + data := make([]byte, 1) _, err = clientConn.Read(data) if err == nil { diff --git a/go/vt/worker/legacy_split_clone_test.go b/go/vt/worker/legacy_split_clone_test.go index 3996118c2f6..65494ade261 100644 --- a/go/vt/worker/legacy_split_clone_test.go +++ b/go/vt/worker/legacy_split_clone_test.go @@ -466,7 +466,7 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { // is too late because this Go routine potentially reads it before the worker // resets the old value. statsRetryCounters.ResetAll() - var err error + errs := make(chan error, 1) go func() { ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() @@ -478,7 +478,9 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { select { case <-ctx.Done(): - err = ctx.Err() + errs <- ctx.Err() + close(errs) + return case <-time.After(10 * time.Millisecond): // Poll constantly. } @@ -488,11 +490,10 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { tc.leftReplica.Agent.TabletExternallyReparented(ctx, "1") tc.leftReplicaQs.UpdateType(topodatapb.TabletType_MASTER) tc.leftReplicaQs.AddDefaultHealthResponse() + errs <- nil + close(errs) }() - if err != nil { - t.Fatalf("timed out waiting for vtworker to retry due to NoMasterAvailable: %v", err) - } // Only wait 1 ms between retries, so that the test passes faster. *executeFetchRetryTime = 1 * time.Millisecond @@ -500,6 +501,10 @@ func TestLegacySplitCloneV2_NoMasterAvailable(t *testing.T) { if err := runCommand(t, tc.wi, tc.wi.wr, tc.defaultWorkerArgs); err != nil { t.Fatal(err) } + err := <-errs + if err != nil { + t.Fatalf("timed out waiting for vtworker to retry due to NoMasterAvailable: %v", err) + } } func TestLegacySplitCloneV3(t *testing.T) { From a0087477182eafb3b91a8bf6769e12abf37951d4 Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 5 Mar 2019 16:10:20 -0800 Subject: [PATCH 174/196] staticcheck: unit test for readVariableInt bugfix Signed-off-by: deepthi --- go/mysql/binlog_event_json_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/go/mysql/binlog_event_json_test.go b/go/mysql/binlog_event_json_test.go index 22658a0096d..f49350324ef 100644 --- a/go/mysql/binlog_event_json_test.go +++ b/go/mysql/binlog_event_json_test.go @@ -46,6 +46,21 @@ func TestJSON(t *testing.T) { }, { data: []byte{12, 13, 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103}, expected: `'"scalar string"'`, + }, { + // repeat the same string 10 times, to test readVariableInt when length of string + // requires 2 bytes to store + data: []byte{12, 129, 2, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103, + 115, 99, 97, 108, 97, 114, 32, 115, 116, 114, 105, 110, 103}, + expected: `'"scalar stringscalar stringscalar stringscalar stringscalar stringscalar stringscalar stringscalar stringscalar stringscalar string"'`, }, { data: []byte{4, 1}, expected: `'true'`, From 86474bbd5913983d82c1735ab4ea78d961bb8be7 Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 5 Mar 2019 16:10:57 -0800 Subject: [PATCH 175/196] staticcheck: packages/files missed during first pass Signed-off-by: deepthi --- go/acl/fallback_policy.go | 6 +- go/memcache/memcache_test.go | 10 +- go/mysql/endtoend/client_test.go | 2 +- go/mysql/endtoend/query_benchmark_test.go | 4 +- go/mysql/endtoend/query_test.go | 4 +- go/mysql/endtoend/replication_test.go | 8 +- go/mysql/fakesqldb/server.go | 4 +- go/mysql/ldapauthserver/auth_server_ldap.go | 14 ++- go/mysql/query_test.go | 1 + go/mysql/replication_constants.go | 104 +++++++----------- go/netutil/conn_test.go | 4 +- go/netutil/netutil.go | 3 + go/pools/numbered_test.go | 10 +- go/pools/resource_pool.go | 6 +- go/proc/counting_listener_test.go | 2 +- go/ratelimiter/ratelimiter.go | 2 +- go/ratelimiter/ratelimiter_test.go | 3 +- go/sqltypes/value_test.go | 2 +- go/stats/kebab_case_converter.go | 2 +- go/stats/snake_case_converter.go | 2 +- go/stats/timings.go | 2 +- go/streamlog/streamlog.go | 4 +- go/sync2/consolidator.go | 2 +- go/timer/randticker_flaky_test.go | 4 +- go/vt/mysqlctl/replication.go | 4 +- go/vt/mysqlctl/schema.go | 2 +- go/vt/vtctl/query.go | 21 ++-- .../tabletserver/tabletserver_test.go | 62 +++++------ 28 files changed, 132 insertions(+), 162 deletions(-) diff --git a/go/acl/fallback_policy.go b/go/acl/fallback_policy.go index 4c1152e9208..e1016d4f52a 100644 --- a/go/acl/fallback_policy.go +++ b/go/acl/fallback_policy.go @@ -21,7 +21,7 @@ import ( "net/http" ) -var fallbackError = errors.New("not allowed: fallback policy") +var errFallback = errors.New("not allowed: fallback policy") // FallbackPolicy is the policy that's used if the // requested policy cannot be found. It rejects all @@ -30,10 +30,10 @@ type FallbackPolicy struct{} // CheckAccessActor disallows all actor access. func (fp FallbackPolicy) CheckAccessActor(actor, role string) error { - return fallbackError + return errFallback } // CheckAccessHTTP disallows all HTTP access. func (fp FallbackPolicy) CheckAccessHTTP(req *http.Request, role string) error { - return fallbackError + return errFallback } diff --git a/go/memcache/memcache_test.go b/go/memcache/memcache_test.go index e170c554897..1449b62051b 100644 --- a/go/memcache/memcache_test.go +++ b/go/memcache/memcache_test.go @@ -166,7 +166,7 @@ func TestMemcache(t *testing.T) { t.Errorf("want false, got %v", stored) } expect(t, c, "Data", "Set") - stored, err = c.Cas("Data", 0, 0, []byte("Changed"), cas) + _, err = c.Cas("Data", 0, 0, []byte("Changed"), cas) if err != nil { t.Fatalf("Set: %v", err) } @@ -217,7 +217,7 @@ func TestMemcache(t *testing.T) { // FlushAll // Set - stored, err = c.Set("Flush", 0, 0, []byte("Test")) + _, err = c.Set("Flush", 0, 0, []byte("Test")) if err != nil { t.Errorf("Set: %v", err) } @@ -237,8 +237,8 @@ func TestMemcache(t *testing.T) { } // Multi - stored, _ = c.Set("key1", 0, 0, []byte("val1")) - stored, _ = c.Set("key2", 0, 0, []byte("val2")) + _, _ = c.Set("key1", 0, 0, []byte("val1")) + _, _ = c.Set("key2", 0, 0, []byte("val2")) results, _ = c.Get("key1", "key2") if len(results) != 2 { @@ -276,7 +276,7 @@ func TestMemcache(t *testing.T) { // timeout test c.timeout = 1 * time.Nanosecond - results, err = c.Gets("key1", "key3", "key2") + _, err = c.Gets("key1", "key3", "key2") want := "i/o timeout" if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("\"%v\" does not contain \"%s\"", err, want) diff --git a/go/mysql/endtoend/client_test.go b/go/mysql/endtoend/client_test.go index 569f4c9ae50..ad6a86b1f34 100644 --- a/go/mysql/endtoend/client_test.go +++ b/go/mysql/endtoend/client_test.go @@ -220,7 +220,7 @@ func doTestMultiResult(t *testing.T, disableClientDeprecateEOF bool) { expectFlag(t, "ReadQueryResult(2)", more, false) expectRows(t, "ReadQueryResult(2)", qr, 1) - result, err = conn.ExecuteFetch("drop table a", 10, true) + _, err = conn.ExecuteFetch("drop table a", 10, true) if err != nil { t.Fatalf("drop table failed: %v", err) } diff --git a/go/mysql/endtoend/query_benchmark_test.go b/go/mysql/endtoend/query_benchmark_test.go index f2089767699..7d466ef9d88 100644 --- a/go/mysql/endtoend/query_benchmark_test.go +++ b/go/mysql/endtoend/query_benchmark_test.go @@ -111,12 +111,12 @@ func benchmarkParallelReads(b *testing.B, params *mysql.ConnParams, parallelCoun conn, err := mysql.Connect(ctx, params) if err != nil { - b.Fatal(err) + b.Error(err) } for j := 0; j < b.N; j++ { if _, err := conn.ExecuteFetch("select * from a", 10000, true); err != nil { - b.Fatalf("ExecuteFetch(%v, %v) failed: %v", i, j, err) + b.Errorf("ExecuteFetch(%v, %v) failed: %v", i, j, err) } } conn.Close() diff --git a/go/mysql/endtoend/query_test.go b/go/mysql/endtoend/query_test.go index 8621c1bb877..ff8abebff3c 100644 --- a/go/mysql/endtoend/query_test.go +++ b/go/mysql/endtoend/query_test.go @@ -256,7 +256,7 @@ func doTestWarnings(t *testing.T, disableClientDeprecateEOF bool) { } // Disable strict mode - result, err = conn.ExecuteFetch("set session sql_mode=''", 0, false) + _, err = conn.ExecuteFetch("set session sql_mode=''", 0, false) if err != nil { t.Fatalf("disable strict mode failed: %v", err) } @@ -273,7 +273,7 @@ func doTestWarnings(t *testing.T, disableClientDeprecateEOF bool) { t.Errorf("unexpected result for warnings: %v", warnings) } - result, err = conn.ExecuteFetch("drop table a", 0, false) + _, err = conn.ExecuteFetch("drop table a", 0, false) if err != nil { t.Fatalf("create table failed: %v", err) } diff --git a/go/mysql/endtoend/replication_test.go b/go/mysql/endtoend/replication_test.go index b78920af3bb..8ddfc0b3998 100644 --- a/go/mysql/endtoend/replication_test.go +++ b/go/mysql/endtoend/replication_test.go @@ -135,10 +135,10 @@ func TestReplicationConnectionClosing(t *testing.T) { if err != nil { serr, ok := err.(*mysql.SQLError) if !ok { - t.Fatalf("Got a non mysql.SQLError error: %v", err) + t.Errorf("Got a non mysql.SQLError error: %v", err) } if serr.Num != mysql.CRServerLost { - t.Fatalf("Got an unexpected mysql.SQLError error: %v", serr) + t.Errorf("Got an unexpected mysql.SQLError error: %v", serr) } // we got the right error, all good. return @@ -150,10 +150,10 @@ func TestReplicationConnectionClosing(t *testing.T) { // What we expect, keep going. case mysql.ErrPacket: err := mysql.ParseErrorPacket(data) - t.Fatalf("ReadPacket returned an error packet: %v", err) + t.Errorf("ReadPacket returned an error packet: %v", err) default: // Very unexpected. - t.Fatalf("ReadPacket returned a weird packet: %v", data) + t.Errorf("ReadPacket returned a weird packet: %v", data) } } }() diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index 2272b17d7cb..60dbb0547ee 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -439,7 +439,7 @@ func (db *DB) comQueryOrdered(query string) (*sqltypes.Result, error) { // AddQuery adds a query and its expected result. func (db *DB) AddQuery(query string, expectedResult *sqltypes.Result) *ExpectedResult { if len(expectedResult.Rows) > 0 && len(expectedResult.Fields) == 0 { - panic(fmt.Errorf("Please add Fields to this Result so it's valid: %v", query)) + panic(fmt.Errorf("please add Fields to this Result so it's valid: %v", query)) } resultCopy := &sqltypes.Result{} *resultCopy = *expectedResult @@ -471,7 +471,7 @@ func (db *DB) SetBeforeFunc(query string, f func()) { // case-insensitive matching mode. func (db *DB) AddQueryPattern(queryPattern string, expectedResult *sqltypes.Result) { if len(expectedResult.Rows) > 0 && len(expectedResult.Fields) == 0 { - panic(fmt.Errorf("Please add Fields to this Result so it's valid: %v", queryPattern)) + panic(fmt.Errorf("please add Fields to this Result so it's valid: %v", queryPattern)) } expr := regexp.MustCompile("(?is)^" + queryPattern + "$") result := *expectedResult diff --git a/go/mysql/ldapauthserver/auth_server_ldap.go b/go/mysql/ldapauthserver/auth_server_ldap.go index a51e8ca3b11..f7f197b96e0 100644 --- a/go/mysql/ldapauthserver/auth_server_ldap.go +++ b/go/mysql/ldapauthserver/auth_server_ldap.go @@ -43,11 +43,12 @@ var ( type AuthServerLdap struct { Client ServerConfig - Method string - User string - Password string - GroupQuery string - UserDnPattern string + Method string + User string + Password string + GroupQuery string + UserDnPattern string + // staticcheck: var RefreshSeconds is of type time.Duration; don't use unit-specific suffix "Seconds" (ST1011) RefreshSeconds time.Duration } @@ -221,6 +222,9 @@ type ClientImpl struct { // This must be called before any other methods func (lci *ClientImpl) Connect(network string, config *ServerConfig) error { conn, err := ldap.Dial(network, config.LdapServer) + if err != nil { + return err + } lci.Conn = conn // Reconnect with TLS ... why don't we simply DialTLS directly? serverName, _, err := netutil.SplitHostPort(config.LdapServer) diff --git a/go/mysql/query_test.go b/go/mysql/query_test.go index 5b7fe6bec85..14625d1e30b 100644 --- a/go/mysql/query_test.go +++ b/go/mysql/query_test.go @@ -402,6 +402,7 @@ func checkQueryInternal(t *testing.T, query string, sConn, cConn *Conn, result * got.Fields, err = cConn.Fields() if err != nil { fatalError = fmt.Sprintf("Fields(%v) failed: %v", query, err) + return } if len(got.Fields) == 0 { got.Fields = nil diff --git a/go/mysql/replication_constants.go b/go/mysql/replication_constants.go index 947bbcbb843..cf5f2f8ce32 100644 --- a/go/mysql/replication_constants.go +++ b/go/mysql/replication_constants.go @@ -152,82 +152,54 @@ const ( // These constants describe the event types. // See: http://dev.mysql.com/doc/internals/en/binlog-event-type.html const ( - //lint:ignore U1000 unused for now, reserved for future use - eUnknownEvent = 0 - //lint:ignore U1000 unused for now, reserved for future use - eStartEventV3 = 1 - eQueryEvent = 2 - //lint:ignore U1000 unused for now, reserved for future use - eStopEvent = 3 - eRotateEvent = 4 - eIntVarEvent = 5 - //lint:ignore U1000 unused for now, reserved for future use - eLoadEvent = 6 - //lint:ignore U1000 unused for now, reserved for future use - eSlaveEvent = 7 - //lint:ignore U1000 unused for now, reserved for future use - eCreateFileEvent = 8 - //lint:ignore U1000 unused for now, reserved for future use - eAppendBlockEvent = 9 - //lint:ignore U1000 unused for now, reserved for future use - eExecLoadEvent = 10 - //lint:ignore U1000 unused for now, reserved for future use - eDeleteFileEvent = 11 - //lint:ignore U1000 unused for now, reserved for future use - eNewLoadEvent = 12 - eRandEvent = 13 - //lint:ignore U1000 unused for now, reserved for future use + eUnknownEvent = 0 + eStartEventV3 = 1 + eQueryEvent = 2 + eStopEvent = 3 + eRotateEvent = 4 + eIntVarEvent = 5 + eLoadEvent = 6 + eSlaveEvent = 7 + eCreateFileEvent = 8 + eAppendBlockEvent = 9 + eExecLoadEvent = 10 + eDeleteFileEvent = 11 + eNewLoadEvent = 12 + eRandEvent = 13 eUserVarEvent = 14 eFormatDescriptionEvent = 15 eXIDEvent = 16 - //lint:ignore U1000 unused for now, reserved for future use - eBeginLoadQueryEvent = 17 - //lint:ignore U1000 unused for now, reserved for future use - eExecuteLoadQueryEvent = 18 - eTableMapEvent = 19 - //lint:ignore U1000 unused for now, reserved for future use - eWriteRowsEventV0 = 20 - //lint:ignore U1000 unused for now, reserved for future use - eUpdateRowsEventV0 = 21 - //lint:ignore U1000 unused for now, reserved for future use - eDeleteRowsEventV0 = 22 - eWriteRowsEventV1 = 23 - eUpdateRowsEventV1 = 24 - eDeleteRowsEventV1 = 25 - //lint:ignore U1000 unused for now, reserved for future use - eIncidentEvent = 26 - //lint:ignore U1000 unused for now, reserved for future use - eHeartbeatEvent = 27 - //lint:ignore U1000 unused for now, reserved for future use - eIgnorableEvent = 28 - //lint:ignore U1000 unused for now, reserved for future use - eRowsQueryEvent = 29 - eWriteRowsEventV2 = 30 - eUpdateRowsEventV2 = 31 - eDeleteRowsEventV2 = 32 - eGTIDEvent = 33 - //lint:ignore U1000 unused for now, reserved for future use - eAnonymousGTIDEvent = 34 - ePreviousGTIDsEvent = 35 + eBeginLoadQueryEvent = 17 + eExecuteLoadQueryEvent = 18 + eTableMapEvent = 19 + eWriteRowsEventV0 = 20 + eUpdateRowsEventV0 = 21 + eDeleteRowsEventV0 = 22 + eWriteRowsEventV1 = 23 + eUpdateRowsEventV1 = 24 + eDeleteRowsEventV1 = 25 + eIncidentEvent = 26 + eHeartbeatEvent = 27 + eIgnorableEvent = 28 + eRowsQueryEvent = 29 + eWriteRowsEventV2 = 30 + eUpdateRowsEventV2 = 31 + eDeleteRowsEventV2 = 32 + eGTIDEvent = 33 + eAnonymousGTIDEvent = 34 + ePreviousGTIDsEvent = 35 // MySQL 5.7 events - //lint:ignore U1000 unused for now, reserved for future use eTransactionContextEvent = 36 - //lint:ignore U1000 unused for now, reserved for future use - eViewChangeEvent = 37 - //lint:ignore U1000 unused for now, reserved for future use - eXAPrepareLogEvent = 38 + eViewChangeEvent = 37 + eXAPrepareLogEvent = 38 // MariaDB specific values. They start at 160. - //lint:ignore U1000 unused for now, reserved for future use - eMariaAnnotateRowsEvent = 160 - //lint:ignore U1000 unused for now, reserved for future use + eMariaAnnotateRowsEvent = 160 eMariaBinlogCheckpointEvent = 161 eMariaGTIDEvent = 162 - //lint:ignore U1000 unused for now, reserved for future use - eMariaGTIDListEvent = 163 - //lint:ignore U1000 unused for now, reserved for future use - eMariaStartEncryptionEvent = 164 + eMariaGTIDListEvent = 163 + eMariaStartEncryptionEvent = 164 ) // These constants describe the type of status variables in q Query packet. diff --git a/go/netutil/conn_test.go b/go/netutil/conn_test.go index eeae20c05d9..95068f2a1f8 100644 --- a/go/netutil/conn_test.go +++ b/go/netutil/conn_test.go @@ -39,7 +39,7 @@ func createSocketPair(t *testing.T) (net.Listener, net.Conn, net.Conn) { var err error clientConn, err = net.Dial("tcp", addr) if err != nil { - t.Fatalf("Dial failed: %v", err) + t.Errorf("Dial failed: %v", err) } }() @@ -50,7 +50,7 @@ func createSocketPair(t *testing.T) (net.Listener, net.Conn, net.Conn) { var err error serverConn, err = listener.Accept() if err != nil { - t.Fatalf("Accept failed: %v", err) + t.Errorf("Accept failed: %v", err) } }() diff --git a/go/netutil/netutil.go b/go/netutil/netutil.go index c47f1fa3a4e..158a8f2f637 100644 --- a/go/netutil/netutil.go +++ b/go/netutil/netutil.go @@ -174,6 +174,9 @@ func ResolveIPv4Addrs(addr string) ([]string, error) { return nil, err } ipAddrs, err := net.LookupIP(host) + if err != nil { + return nil, err + } result := make([]string, 0, len(ipAddrs)) for _, ipAddr := range ipAddrs { ipv4 := ipAddr.To4() diff --git a/go/pools/numbered_test.go b/go/pools/numbered_test.go index 25c737579e5..dfe19cb203c 100644 --- a/go/pools/numbered_test.go +++ b/go/pools/numbered_test.go @@ -41,18 +41,18 @@ func TestNumbered(t *testing.T) { if v.(int64) != id { t.Errorf("want %v, got %v", id, v.(int64)) } - if v, err = p.Get(id, "test1"); err.Error() != "in use: test" { + if _, err = p.Get(id, "test1"); err.Error() != "in use: test" { t.Errorf("want 'in use: test', got '%v'", err) } p.Put(id) - if v, err = p.Get(1, "test2"); err.Error() != "not found" { + if _, err = p.Get(1, "test2"); err.Error() != "not found" { t.Errorf("want 'not found', got '%v'", err) } p.Unregister(1, "test") // Should not fail p.Unregister(0, "test") // p is now empty - if v, err = p.Get(0, "test3"); !(strings.HasPrefix(err.Error(), "ended at") && strings.HasSuffix(err.Error(), "(test)")) { + if _, err = p.Get(0, "test3"); !(strings.HasPrefix(err.Error(), "ended at") && strings.HasSuffix(err.Error(), "(test)")) { t.Errorf("want prefix 'ended at' and suffix '(test'), got '%v'", err) } @@ -71,7 +71,7 @@ func TestNumbered(t *testing.T) { if num := len(vals); num != 2 { t.Errorf("want 2, got %v", num) } - if v, err = p.Get(vals[0].(int64), "test1"); err.Error() != "in use: by outdated" { + if _, err = p.Get(vals[0].(int64), "test1"); err.Error() != "in use: by outdated" { t.Errorf("want 'in use: by outdated', got '%v'", err) } for _, v := range vals { @@ -85,7 +85,7 @@ func TestNumbered(t *testing.T) { if len(vals) != 1 { t.Errorf("want 1, got %v", len(vals)) } - if v, err = p.Get(vals[0].(int64), "test1"); err.Error() != "in use: by idle" { + if _, err = p.Get(vals[0].(int64), "test1"); err.Error() != "in use: by idle" { t.Errorf("want 'in use: by idle', got '%v'", err) } if vals[0].(int64) != 3 { diff --git a/go/pools/resource_pool.go b/go/pools/resource_pool.go index a63bcfdb9b3..60717b3ec61 100644 --- a/go/pools/resource_pool.go +++ b/go/pools/resource_pool.go @@ -122,13 +122,13 @@ func (rp *ResourcePool) closeIdleResources() { for i := 0; i < available; i++ { var wrapper resourceWrapper select { - case wrapper, _ = <-rp.resources: + case wrapper = <-rp.resources: default: // stop early if we don't get anything new from the pool return } - if wrapper.resource != nil && idleTimeout > 0 && wrapper.timeUsed.Add(idleTimeout).Sub(time.Now()) < 0 { + if wrapper.resource != nil && idleTimeout > 0 && time.Until(wrapper.timeUsed.Add(idleTimeout)) < 0 { wrapper.resource.Close() wrapper.resource = nil rp.idleClosed.Add(1) @@ -260,7 +260,7 @@ func (rp *ResourcePool) SetCapacity(capacity int) error { func (rp *ResourcePool) recordWait(start time.Time) { rp.waitCount.Add(1) - rp.waitTime.Add(time.Now().Sub(start)) + rp.waitTime.Add(time.Since(start)) } // SetIdleTimeout sets the idle timeout. It can only be used if there was an diff --git a/go/proc/counting_listener_test.go b/go/proc/counting_listener_test.go index 597a39e1bee..c8151aa62e4 100644 --- a/go/proc/counting_listener_test.go +++ b/go/proc/counting_listener_test.go @@ -35,7 +35,7 @@ func TestPublished(t *testing.T) { conn, err := l.Accept() opened <- struct{}{} if err != nil { - t.Fatal(err) + t.Error(err) } go func() { b := make([]byte, 100) diff --git a/go/ratelimiter/ratelimiter.go b/go/ratelimiter/ratelimiter.go index 34a8bb1607f..33f79a8cbf9 100644 --- a/go/ratelimiter/ratelimiter.go +++ b/go/ratelimiter/ratelimiter.go @@ -53,7 +53,7 @@ func NewRateLimiter(maxCount int, interval time.Duration) *RateLimiter { func (rl *RateLimiter) Allow() bool { rl.mu.Lock() defer rl.mu.Unlock() - if time.Now().Sub(rl.lastTime) < rl.interval { + if time.Since(rl.lastTime) < rl.interval { if rl.curCount > 0 { rl.curCount-- return true diff --git a/go/ratelimiter/ratelimiter_test.go b/go/ratelimiter/ratelimiter_test.go index 5fef295d4e7..fe679f105a4 100644 --- a/go/ratelimiter/ratelimiter_test.go +++ b/go/ratelimiter/ratelimiter_test.go @@ -23,8 +23,7 @@ import ( func TestLimiter1(t *testing.T) { rl := NewRateLimiter(1, 10*time.Millisecond) - var result bool - result = rl.Allow() + result := rl.Allow() if !result { t.Error("Allow: false, want true") } diff --git a/go/sqltypes/value_test.go b/go/sqltypes/value_test.go index 2a76058bb33..0be764f0fd4 100644 --- a/go/sqltypes/value_test.go +++ b/go/sqltypes/value_test.go @@ -344,7 +344,7 @@ func TestToBytesAndString(t *testing.T) { TestValue(Int64, "1"), TestValue(Int64, "12"), } { - if b := v.ToBytes(); bytes.Compare(b, v.Raw()) != 0 { + if b := v.ToBytes(); !bytes.Equal(b, v.Raw()) { t.Errorf("%v.ToBytes: %s, want %s", v, b, v.Raw()) } if s := v.ToString(); s != string(v.Raw()) { diff --git a/go/stats/kebab_case_converter.go b/go/stats/kebab_case_converter.go index f288a8b6bbb..59f3ff7cb67 100644 --- a/go/stats/kebab_case_converter.go +++ b/go/stats/kebab_case_converter.go @@ -50,7 +50,7 @@ var kebabConverters = []struct { // example: CCa -> C-Ca (e.g. CCamel -> C-Camel). {regexp.MustCompile("([A-Z])([A-Z][a-z])"), "$1-$2"}, {regexp.MustCompile("_"), "-"}, - {regexp.MustCompile("\\."), "_"}, + {regexp.MustCompile(`\.`), "_"}, } var memoizer = memoizerType{ diff --git a/go/stats/snake_case_converter.go b/go/stats/snake_case_converter.go index c29f8c83fbe..34dc610216c 100644 --- a/go/stats/snake_case_converter.go +++ b/go/stats/snake_case_converter.go @@ -55,7 +55,7 @@ var snakeConverters = []struct { {regexp.MustCompile("([a-z])([A-Z])"), "${1}_${2}"}, // example: CCa -> C_Ca (e.g. CCamel -> C_Camel). {regexp.MustCompile("([A-Z])([A-Z][a-z])"), "${1}_${2}"}, - {regexp.MustCompile("\\."), "_"}, + {regexp.MustCompile(`\.`), "_"}, {regexp.MustCompile("-"), "_"}, } diff --git a/go/stats/timings.go b/go/stats/timings.go index 94cd2573375..468f35e8999 100644 --- a/go/stats/timings.go +++ b/go/stats/timings.go @@ -92,7 +92,7 @@ func (t *Timings) Add(name string, elapsed time.Duration) { // Record is a convenience function that records completion // timing data based on the provided start time of an event. func (t *Timings) Record(name string, startTime time.Time) { - t.Add(name, time.Now().Sub(startTime)) + t.Add(name, time.Since(startTime)) } // String is for expvar. diff --git a/go/streamlog/streamlog.go b/go/streamlog/streamlog.go index b6211d3b131..6b9559694be 100644 --- a/go/streamlog/streamlog.go +++ b/go/streamlog/streamlog.go @@ -171,9 +171,9 @@ func (logger *StreamLogger) LogToFile(path string, logf LogFormatter) (chan inte go func() { for { select { - case record, _ := <-logChan: + case record := <-logChan: logf(f, formatParams, record) - case _, _ = <-rotateChan: + case <-rotateChan: f.Close() f, _ = os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644) } diff --git a/go/sync2/consolidator.go b/go/sync2/consolidator.go index a5b36a69313..1c69d802505 100644 --- a/go/sync2/consolidator.go +++ b/go/sync2/consolidator.go @@ -117,7 +117,7 @@ type ConsolidatorCacheItem struct { // Items returns the items in the cache as an array of String, int64 structs func (cc *ConsolidatorCache) Items() []ConsolidatorCacheItem { items := cc.LRUCache.Items() - ret := make([]ConsolidatorCacheItem, len(items), len(items)) + ret := make([]ConsolidatorCacheItem, len(items)) for i, v := range items { ret[i] = ConsolidatorCacheItem{Query: v.Key, Count: v.Value.(*ccount).get()} } diff --git a/go/timer/randticker_flaky_test.go b/go/timer/randticker_flaky_test.go index 0ad8bd26030..155a9fe2cba 100644 --- a/go/timer/randticker_flaky_test.go +++ b/go/timer/randticker_flaky_test.go @@ -48,14 +48,14 @@ func TestTickSkip(t *testing.T) { tkr := NewRandTicker(10*time.Millisecond, 1*time.Millisecond) time.Sleep(35 * time.Millisecond) end := <-tkr.C - diff := time.Now().Sub(end) + diff := time.Since(end) if diff < 20*time.Millisecond { t.Errorf("diff: %v, want >20ms", diff) } // This tick should be up-to-date end = <-tkr.C - diff = time.Now().Sub(end) + diff = time.Since(end) if diff > 1*time.Millisecond { t.Errorf("diff: %v, want <1ms", diff) } diff --git a/go/vt/mysqlctl/replication.go b/go/vt/mysqlctl/replication.go index 028cb3488e1..8d926fb9e66 100644 --- a/go/vt/mysqlctl/replication.go +++ b/go/vt/mysqlctl/replication.go @@ -273,12 +273,10 @@ func (mysqld *Mysqld) ResetReplication(ctx context.Context) error { // // Array indices for the results of SHOW PROCESSLIST. const ( - //lint:ignore U1000 needed for correct indexing of result columns + //lint:ignore U1000 unused fields are needed for correct indexing of result columns colConnectionID = iota - //lint:ignore U1000 needed for correct indexing of result columns colUsername colClientAddr - //lint:ignore U1000 needed for correct indexing of result columns colDbName colCommand ) diff --git a/go/vt/mysqlctl/schema.go b/go/vt/mysqlctl/schema.go index 2a06a04ba24..16e114eb625 100644 --- a/go/vt/mysqlctl/schema.go +++ b/go/vt/mysqlctl/schema.go @@ -32,7 +32,7 @@ import ( tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata" ) -var autoIncr = regexp.MustCompile(` AUTO_INCREMENT=\\d+`) +var autoIncr = regexp.MustCompile(` AUTO_INCREMENT=\d+`) // executeSchemaCommands executes some SQL commands, using the mysql // command line tool. It uses the dba connection parameters, with credentials. diff --git a/go/vt/vtctl/query.go b/go/vt/vtctl/query.go index 1638e474abe..a4cc9655246 100644 --- a/go/vt/vtctl/query.go +++ b/go/vt/vtctl/query.go @@ -190,8 +190,7 @@ func commandVtGateExecute(ctx context.Context, wr *wrangler.Wrangler, subFlags * bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { - //lint:ignore ST1005 function name - return fmt.Errorf("Execute failed: %v", err) + return fmt.Errorf("BuildBindVariables failed: %v", err) } qr, err := session.Execute(ctx, subFlags.Arg(0), bindVars) @@ -246,14 +245,12 @@ func commandVtGateExecuteShards(ctx context.Context, wr *wrangler.Wrangler, subF bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { - //lint:ignore ST1005 function name - return fmt.Errorf("Execute failed: %v", err) + return fmt.Errorf("BuildBindVariables failed: %v", err) } qr, err := vtgateConn.ExecuteShards(ctx, subFlags.Arg(0), *keyspace, shards, bindVars, t, executeOptions) if err != nil { - //lint:ignore ST1005 function name - return fmt.Errorf("Execute failed: %v", err) + return fmt.Errorf("ExecuteShards failed: %v", err) } if *json { return printJSON(wr.Logger(), qr) @@ -309,14 +306,12 @@ func commandVtGateExecuteKeyspaceIds(ctx context.Context, wr *wrangler.Wrangler, bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { - //lint:ignore ST1005 function name - return fmt.Errorf("Execute failed: %v", err) + return fmt.Errorf("BuildBindVariables failed: %v", err) } qr, err := vtgateConn.ExecuteKeyspaceIds(ctx, subFlags.Arg(0), *keyspace, keyspaceIDs, bindVars, t, executeOptions) if err != nil { - //lint:ignore ST1005 function name - return fmt.Errorf("Execute failed: %v", err) + return fmt.Errorf("ExecuteKeyspaceIds failed: %v", err) } if *json { return printJSON(wr.Logger(), qr) @@ -377,8 +372,7 @@ func commandVtGateSplitQuery(ctx context.Context, wr *wrangler.Wrangler, subFlag bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { - //lint:ignore ST1005 function name - return fmt.Errorf("Execute failed: %v", err) + return fmt.Errorf("BuildBindVariables failed: %v", err) } r, err := vtgateConn.SplitQuery( @@ -441,8 +435,7 @@ func commandVtTabletExecute(ctx context.Context, wr *wrangler.Wrangler, subFlags bindVars, err := sqltypes.BuildBindVariables(*bindVariables) if err != nil { - //lint:ignore ST1005 function name - return fmt.Errorf("Execute failed: %v", err) + return fmt.Errorf("BuildBindVariables failed: %v", err) } qr, err := conn.Execute(ctx, &querypb.Target{ diff --git a/go/vt/vttablet/tabletserver/tabletserver_test.go b/go/vt/vttablet/tabletserver/tabletserver_test.go index 96d09666e74..ca5d2c38dc7 100644 --- a/go/vt/vttablet/tabletserver/tabletserver_test.go +++ b/go/vt/vttablet/tabletserver/tabletserver_test.go @@ -1517,10 +1517,10 @@ func TestSerializeTransactionsSameRow(t *testing.T) { _, tx1, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q1, err) + t.Errorf("failed to execute query: %s: %s", q1, err) } if err := tsv.Commit(ctx, &target, tx1); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } }() @@ -1532,7 +1532,7 @@ func TestSerializeTransactionsSameRow(t *testing.T) { <-tx1Started _, tx2, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q2, err) + t.Errorf("failed to execute query: %s: %s", q2, err) } // TODO(mberlin): This should actually be in the BeforeFunc() of tx1 but // then the test is hanging. It looks like the MySQL C client library cannot @@ -1540,7 +1540,7 @@ func TestSerializeTransactionsSameRow(t *testing.T) { // still pending. <-tx3Finished if err := tsv.Commit(ctx, &target, tx2); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } }() @@ -1552,10 +1552,10 @@ func TestSerializeTransactionsSameRow(t *testing.T) { <-tx1Started _, tx3, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q3, err) + t.Errorf("failed to execute query: %s: %s", q3, err) } if err := tsv.Commit(ctx, &target, tx3); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } close(tx3Finished) }() @@ -1645,10 +1645,10 @@ func TestSerializeTransactionsSameRow_ExecuteBatchAsTransaction(t *testing.T) { BindVariables: bvTx1, }}, true /*asTransaction*/, 0 /*transactionID*/, nil /*options*/) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q1, err) + t.Errorf("failed to execute query: %s: %s", q1, err) } if len(results) != 1 || results[0].RowsAffected != 1 { - t.Fatalf("TabletServer.ExecuteBatch returned wrong results: %+v", results) + t.Errorf("TabletServer.ExecuteBatch returned wrong results: %+v", results) } }() @@ -1663,10 +1663,10 @@ func TestSerializeTransactionsSameRow_ExecuteBatchAsTransaction(t *testing.T) { BindVariables: bvTx2, }}, true /*asTransaction*/, 0 /*transactionID*/, nil /*options*/) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q2, err) + t.Errorf("failed to execute query: %s: %s", q2, err) } if len(results) != 1 || results[0].RowsAffected != 1 { - t.Fatalf("TabletServer.ExecuteBatch returned wrong results: %+v", results) + t.Errorf("TabletServer.ExecuteBatch returned wrong results: %+v", results) } }() @@ -1681,10 +1681,10 @@ func TestSerializeTransactionsSameRow_ExecuteBatchAsTransaction(t *testing.T) { BindVariables: bvTx3, }}, true /*asTransaction*/, 0 /*transactionID*/, nil /*options*/) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q3, err) + t.Errorf("failed to execute query: %s: %s", q3, err) } if len(results) != 1 || results[0].RowsAffected != 1 { - t.Fatalf("TabletServer.ExecuteBatch returned wrong results: %+v", results) + t.Errorf("TabletServer.ExecuteBatch returned wrong results: %+v", results) } }() @@ -1757,11 +1757,11 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { _, tx1, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q1, err) + t.Errorf("failed to execute query: %s: %s", q1, err) } if err := tsv.Commit(ctx, &target, tx1); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } }() @@ -1776,11 +1776,11 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { _, tx2, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q2, err) + t.Errorf("failed to execute query: %s: %s", q2, err) } if err := tsv.Commit(ctx, &target, tx2); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } }() @@ -1795,11 +1795,11 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { _, tx3, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q3, err) + t.Errorf("failed to execute query: %s: %s", q3, err) } if err := tsv.Commit(ctx, &target, tx3); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } }() @@ -1896,10 +1896,10 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests(t *testing.T) { _, tx1, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q1, err) + t.Errorf("failed to execute query: %s: %s", q1, err) } if err := tsv.Commit(ctx, &target, tx1); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } }() @@ -1912,7 +1912,7 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests(t *testing.T) { <-tx1Started _, _, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) if err == nil || vterrors.Code(err) != vtrpcpb.Code_RESOURCE_EXHAUSTED || err.Error() != "hot row protection: too many queued transactions (1 >= 1) for the same row (table + WHERE clause: 'test_table where pk = 1 and name = 1')" { - t.Fatalf("tx2 should have failed because there are too many pending requests: %v", err) + t.Errorf("tx2 should have failed because there are too many pending requests: %v", err) } // No commit necessary because the Begin failed. }() @@ -1988,10 +1988,10 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests_ExecuteBatchAsTrans BindVariables: bvTx1, }}, true /*asTransaction*/, 0 /*transactionID*/, nil /*options*/) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q1, err) + t.Errorf("failed to execute query: %s: %s", q1, err) } if len(results) != 1 || results[0].RowsAffected != 1 { - t.Fatalf("TabletServer.ExecuteBatch returned wrong results: %+v", results) + t.Errorf("TabletServer.ExecuteBatch returned wrong results: %+v", results) } }() @@ -2007,7 +2007,7 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests_ExecuteBatchAsTrans BindVariables: bvTx2, }}, true /*asTransaction*/, 0 /*transactionID*/, nil /*options*/) if err == nil || vterrors.Code(err) != vtrpcpb.Code_RESOURCE_EXHAUSTED || err.Error() != "hot row protection: too many queued transactions (1 >= 1) for the same row (table + WHERE clause: 'test_table where pk = 1 and name = 1')" { - t.Fatalf("tx2 should have failed because there are too many pending requests: %v results: %+v", err, results) + t.Errorf("tx2 should have failed because there are too many pending requests: %v results: %+v", err, results) } }() @@ -2083,11 +2083,11 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { _, tx1, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q1, err) + t.Errorf("failed to execute query: %s: %s", q1, err) } if err := tsv.Commit(ctx, &target, tx1); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } }() @@ -2103,7 +2103,7 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { _, _, err := tsv.BeginExecute(ctxTx2, &target, q2, bvTx2, nil) if err == nil || vterrors.Code(err) != vtrpcpb.Code_CANCELED || err.Error() != "context canceled" { - t.Fatalf("tx2 should have failed because the context was canceled: %v", err) + t.Errorf("tx2 should have failed because the context was canceled: %v", err) } // No commit necessary because the Begin failed. }() @@ -2115,16 +2115,16 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { // Wait until tx1 and tx2 are pending to make the test deterministic. if err := waitForTxSerializationPendingQueries(tsv, "test_table where pk = 1 and name = 1", 2); err != nil { - t.Fatal(err) + t.Error(err) } _, tx3, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) if err != nil { - t.Fatalf("failed to execute query: %s: %s", q3, err) + t.Errorf("failed to execute query: %s: %s", q3, err) } if err := tsv.Commit(ctx, &target, tx3); err != nil { - t.Fatalf("call TabletServer.Commit failed: %v", err) + t.Errorf("call TabletServer.Commit failed: %v", err) } }() @@ -2545,7 +2545,7 @@ func TestHandleExecTabletError(t *testing.T) { vterrors.Errorf(vtrpcpb.Code_INTERNAL, "tablet error"), nil, ) - fmt.Println(">>>>>"+err.Error()) + fmt.Println(">>>>>" + err.Error()) want := "tablet error" if err == nil || !strings.Contains(err.Error(), want) { t.Errorf("got `%v`, want '%s'", err, want) From cc4030c8d2a128fce4f5e90700bc378003901e3d Mon Sep 17 00:00:00 2001 From: deepthi Date: Wed, 6 Mar 2019 12:39:23 -0800 Subject: [PATCH 176/196] staticcheck: replace t.Fatal in goroutines with t.Error Signed-off-by: deepthi --- go/vt/vttablet/endtoend/message_test.go | 42 +++++++++++-------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/go/vt/vttablet/endtoend/message_test.go b/go/vt/vttablet/endtoend/message_test.go index 913b4ae93e3..79a86227671 100644 --- a/go/vt/vttablet/endtoend/message_test.go +++ b/go/vt/vttablet/endtoend/message_test.go @@ -43,11 +43,10 @@ var createMessage = `create table vitess_message( comment 'vitess_message,vt_ack_wait=1,vt_purge_after=3,vt_batch_size=2,vt_cache_size=10,vt_poller_interval=1'` func TestMessage(t *testing.T) { - var err error ch := make(chan *sqltypes.Result) done := make(chan struct{}) client := framework.NewClient() - if _, err = client.Execute(createMessage, nil); err != nil { + if _, err := client.Execute(createMessage, nil); err != nil { t.Fatal(err) } defer client.Execute("drop table vitess_message", nil) @@ -61,7 +60,7 @@ func TestMessage(t *testing.T) { // Start goroutine to consume message stream. go func() { - err = client.MessageStream("vitess_message", func(qr *sqltypes.Result) error { + if err := client.MessageStream("vitess_message", func(qr *sqltypes.Result) error { select { case <-done: return io.EOF @@ -69,12 +68,11 @@ func TestMessage(t *testing.T) { } ch <- qr return nil - }) + }); err != nil { + t.Error(err) + } close(ch) }() - if err != nil { - t.Fatal(err) - } got := <-ch want := &sqltypes.Result{ Fields: []*querypb.Field{{ @@ -95,7 +93,7 @@ func TestMessage(t *testing.T) { defer func() { close(done) }() // Create message. - err = client.Begin(false) + err := client.Begin(false) if err != nil { t.Error(err) return @@ -242,17 +240,16 @@ var createThreeColMessage = `create table vitess_message3( comment 'vitess_message,vt_ack_wait=1,vt_purge_after=3,vt_batch_size=2,vt_cache_size=10,vt_poller_interval=1'` func TestThreeColMessage(t *testing.T) { - var err error ch := make(chan *sqltypes.Result) done := make(chan struct{}) client := framework.NewClient() - if _, err = client.Execute(createThreeColMessage, nil); err != nil { + if _, err := client.Execute(createThreeColMessage, nil); err != nil { t.Fatal(err) } defer client.Execute("drop table vitess_message3", nil) go func() { - err = client.MessageStream("vitess_message3", func(qr *sqltypes.Result) error { + if err := client.MessageStream("vitess_message3", func(qr *sqltypes.Result) error { select { case <-done: return io.EOF @@ -260,12 +257,11 @@ func TestThreeColMessage(t *testing.T) { } ch <- qr return nil - }) + }); err != nil { + t.Error(err) + } close(ch) }() - if err != nil { - t.Fatal(err) - } // Verify fields. got := <-ch @@ -289,7 +285,7 @@ func TestThreeColMessage(t *testing.T) { } runtime.Gosched() defer func() { close(done) }() - err = client.Begin(false) + err := client.Begin(false) if err != nil { t.Error(err) return @@ -353,18 +349,17 @@ comment 'vitess_message,vt_ack_wait=1,vt_purge_after=3,vt_batch_size=1,vt_cache_ // TestMessageAuto tests for the case where id is an auto-inc column. func TestMessageAuto(t *testing.T) { - var err error ch := make(chan *sqltypes.Result) done := make(chan struct{}) client := framework.NewClient() - if _, err = client.Execute(createMessageAuto, nil); err != nil { + if _, err := client.Execute(createMessageAuto, nil); err != nil { t.Fatal(err) } defer client.Execute("drop table vitess_message_auto", nil) // Start goroutine to consume message stream. go func() { - err = client.MessageStream("vitess_message_auto", func(qr *sqltypes.Result) error { + if err := client.MessageStream("vitess_message_auto", func(qr *sqltypes.Result) error { select { case <-done: return io.EOF @@ -372,17 +367,16 @@ func TestMessageAuto(t *testing.T) { } ch <- qr return nil - }) + }); err != nil { + t.Error(err) + } close(ch) }() - if err != nil { - t.Fatal(err) - } <-ch defer func() { close(done) }() // Create message. - err = client.Begin(false) + err := client.Begin(false) if err != nil { t.Error(err) return From 40e6e274ae6204989cd647ce2c52343bd0e183d8 Mon Sep 17 00:00:00 2001 From: deepthi Date: Wed, 6 Mar 2019 19:17:38 -0800 Subject: [PATCH 177/196] staticcheck: fix test failures from changing error messages Signed-off-by: deepthi --- test/initial_sharding.py | 2 +- test/reparent.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/initial_sharding.py b/test/initial_sharding.py index 5c639def51b..1213544b171 100755 --- a/test/initial_sharding.py +++ b/test/initial_sharding.py @@ -241,7 +241,7 @@ def test_resharding(self): _, stderr = utils.run_vtctl(['InitShardMaster', '-force', 'test_keyspace/0', shard_master.tablet_alias], auto_log=True, expect_fail=True) - self.assertIn('Tablet test_nj-0000062345 ResetReplication failed', stderr) + self.assertIn('tablet test_nj-0000062345 ResetReplication failed', stderr) # start replica shard_replica.start_vttablet(wait_for_state=None, binlog_use_v3_resharding_mode=False) diff --git a/test/reparent.py b/test/reparent.py index 5f1f07a30b5..521c57ca25b 100755 --- a/test/reparent.py +++ b/test/reparent.py @@ -380,7 +380,7 @@ def test_reparent_slave_offline(self, shard_id='0'): _, stderr = utils.run_vtctl(['PlannedReparentShard', '-keyspace_shard', 'test_keyspace/' + shard_id, '-new_master', tablet_62044.tablet_alias], expect_fail=True) - self.assertIn('Tablet test_ny-0000031981 SetMaster failed', stderr) + self.assertIn('tablet test_ny-0000031981 SetMaster failed', stderr) self._check_master_tablet(tablet_62044) From 227cd8475a6e2df3a2fd1fc372a40708fba14231 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Mar 2019 11:04:22 -0800 Subject: [PATCH 178/196] Error formatting fixes Signed-off-by: Rafael Chacon --- go/vt/topo/cell_info.go | 6 +++--- go/vt/topo/helpers/compare.go | 2 +- go/vt/topo/server.go | 5 +++-- go/vt/topo/shard.go | 3 ++- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/go/vt/topo/cell_info.go b/go/vt/topo/cell_info.go index 7bdcd2d6537..7549705a1d3 100644 --- a/go/vt/topo/cell_info.go +++ b/go/vt/topo/cell_info.go @@ -17,11 +17,11 @@ limitations under the License. package topo import ( + "fmt" "path" "github.com/golang/protobuf/proto" "golang.org/x/net/context" - "vitess.io/vitess/go/vt/proto/vtrpc" "vitess.io/vitess/go/vt/vterrors" topodatapb "vitess.io/vitess/go/vt/proto/topodata" @@ -141,12 +141,12 @@ func (ts *Server) DeleteCellInfo(ctx context.Context, cell string) error { switch { case err == nil: if len(srvKeyspaces) != 0 { - return fmt.Errorf("cell %v has serving keyspaces. Before deleting, delete keyspace with: DeleteKeyspace", cell) + return vterrors.Wrap(err, fmt.Sprintf("cell %v has serving keyspaces. Before deleting, delete keyspace with: DeleteKeyspace", cell)) } case IsErrType(err, NoNode): // Nothing to do. default: - return fmt.Errorf("GetSrvKeyspaceNames() failed: %v", err) + return vterrors.Wrap(err, "GetSrvKeyspaceNames() failed") } filePath := pathForCellInfo(cell) diff --git a/go/vt/topo/helpers/compare.go b/go/vt/topo/helpers/compare.go index 714d054da0e..a30777c8d6e 100644 --- a/go/vt/topo/helpers/compare.go +++ b/go/vt/topo/helpers/compare.go @@ -148,7 +148,7 @@ func CompareShardReplications(ctx context.Context, fromTS, toTS *topo.Server) er } cells, err := fromTS.GetCellInfoNames(ctx) if err != nil { - return fmt.Errorf("GetCellInfoNames(): %v", err) + return vterrors.Wrap(err, "GetCellInfoNames()") } for _, keyspace := range keyspaces { diff --git a/go/vt/topo/server.go b/go/vt/topo/server.go index 8cae1a46025..cf6b86acc36 100644 --- a/go/vt/topo/server.go +++ b/go/vt/topo/server.go @@ -44,6 +44,7 @@ package topo import ( "flag" + "fmt" "sync" "golang.org/x/net/context" @@ -263,10 +264,10 @@ func (ts *Server) ConnForCell(ctx context.Context, cell string) (Conn, error) { ts.cells[cell] = conn return conn, nil case IsErrType(err, NoNode): - err = fmt.Errorf("failed to create topo connection to %v, %v: %v", ci.ServerAddress, ci.Root, err) + err = vterrors.Wrap(err, fmt.Sprintf("failed to create topo connection to %v, %v", ci.ServerAddress, ci.Root)) return nil, NewError(NoNode, err.Error()) default: - return nil, fmt.Errorf("failed to create topo connection to %v, %v: %v", ci.ServerAddress, ci.Root, err) + return nil, vterrors.Wrap(err, fmt.Sprintf("failed to create topo connection to %v, %v", ci.ServerAddress, ci.Root)) } } diff --git a/go/vt/topo/shard.go b/go/vt/topo/shard.go index b721c346e6e..182738b42d9 100644 --- a/go/vt/topo/shard.go +++ b/go/vt/topo/shard.go @@ -18,6 +18,7 @@ package topo import ( "encoding/hex" + "fmt" "path" "reflect" "sort" @@ -527,7 +528,7 @@ func (ts *Server) FindAllTabletAliasesInShardByCell(ctx context.Context, keyspac case IsErrType(err, NoNode): // There is no shard replication for this shard in this cell. NOOP default: - rec.RecordError(fmt.Errorf("GetShardReplication(%v, %v, %v) failed: %v", cell, keyspace, shard, err)) + rec.RecordError(vterrors.Wrap(err, fmt.Sprintf("GetShardReplication(%v, %v, %v) failed.", cell, keyspace, shard))) return } }(cell) From b5af454b8a0a00b111dec8723aad06f1270c0592 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Fri, 8 Mar 2019 12:44:23 -0800 Subject: [PATCH 179/196] Adds utility function to manipulate serving keyspace graph Signed-off-by: Rafael Chacon --- go/vt/vtctl/vtctl.go | 34 ++++++++++++++++++++++++++++++++++ go/vt/wrangler/shard.go | 19 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/go/vt/vtctl/vtctl.go b/go/vt/vtctl/vtctl.go index b129d4fbd32..7d660189ad6 100644 --- a/go/vt/vtctl/vtctl.go +++ b/go/vt/vtctl/vtctl.go @@ -249,6 +249,9 @@ var commands = []commandGroup{ "To set the DisableQueryServiceFlag, keep 'blacklisted_tables' empty, and set 'disable_query_service' to true or false. Useful to fix horizontal splits gone wrong.\n" + "To change the blacklisted tables list, specify the 'blacklisted_tables' parameter with the new list. Useful to fix tables that are being blocked after a vertical split.\n" + "To just remove the ShardTabletControl entirely, use the 'remove' flag, useful after a vertical split is finished to remove serving restrictions."}, + {"UpdateSrvKeyspacePartition", commandUpdateSrvKeyspacePartition, + "[--cells=c1,c2,...] [--remove] ", + "Updates KeyspaceGraph partition for a shard and type. Only use this for an emergency fix during an horizontal shard split. The *MigrateServedType* commands set this field appropriately already. Specify the remove flag, if you want the shard to be removed from the desired partition."}, {"SourceShardDelete", commandSourceShardDelete, " ", "Deletes the SourceShard record with the provided index. This is meant as an emergency cleanup function. It does not call RefreshState for the shard master."}, @@ -1290,6 +1293,37 @@ func commandSetShardServedTypes(ctx context.Context, wr *wrangler.Wrangler, subF return wr.SetShardServedTypes(ctx, keyspace, shard, cells, servedType, *remove) } +func commandUpdateSrvKeyspacePartition(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { + cellsStr := subFlags.String("cells", "", "Specifies a comma-separated list of cells to update") + remove := subFlags.Bool("remove", false, "Removes shard from serving keyspace partition") + + if err := subFlags.Parse(args); err != nil { + return err + } + if subFlags.NArg() != 2 { + return fmt.Errorf("the and arguments are both required for the UpdateSrvKeyspacePartition command") + } + keyspace, shard, err := topoproto.ParseKeyspaceShard(subFlags.Arg(0)) + if err != nil { + return err + } + tabletType, err := parseServingTabletType3(subFlags.Arg(1)) + if err != nil { + return err + } + + var cells []string + if *cellsStr != "" { + cells = strings.Split(*cellsStr, ",") + } + + err = wr.UpdateSrvKeyspacePartitions(ctx, keyspace, shard, tabletType, cells, *remove) + if err != nil { + return err + } + return nil +} + func commandSetShardTabletControl(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error { cellsStr := subFlags.String("cells", "", "Specifies a comma-separated list of cells to update") blacklistedTablesStr := subFlags.String("blacklisted_tables", "", "Specifies a comma-separated list of tables to blacklist (used for vertical split). Each is either an exact match, or a regular expression of the form '/regexp/'.") diff --git a/go/vt/wrangler/shard.go b/go/vt/wrangler/shard.go index 4a74eea3d95..56bff8f5e3d 100644 --- a/go/vt/wrangler/shard.go +++ b/go/vt/wrangler/shard.go @@ -123,6 +123,25 @@ func (wr *Wrangler) UpdateDisableQueryService(ctx context.Context, keyspace, sha return wr.ts.UpdateDisableQueryService(ctx, keyspace, []*topo.ShardInfo{si}, tabletType, cells, disableQueryService) } +// UpdateSrvKeyspacePartitions changes the SrvKeyspaceGraph +// for a shard. It updates serving graph +// +// This takes the keyspace lock as to not interfere with resharding operations. +func (wr *Wrangler) UpdateSrvKeyspacePartitions(ctx context.Context, keyspace, shard string, tabletType topodatapb.TabletType, cells []string, remove bool) (err error) { + // lock the keyspace + ctx, unlock, lockErr := wr.ts.LockKeyspace(ctx, keyspace, "UpdateSrvKeyspacePartitions") + if lockErr != nil { + return lockErr + } + defer unlock(&err) + + si, err := wr.ts.GetShard(ctx, keyspace, shard) + if err != nil { + return err + } + return wr.ts.UpdateSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{si}, tabletType, cells, remove) +} + // DeleteShard will do all the necessary changes in the topology server // to entirely remove a shard. func (wr *Wrangler) DeleteShard(ctx context.Context, keyspace, shard string, recursive, evenIfServing bool) error { From 90a03e97c0b51c33a637661f6f7df7f4e0830091 Mon Sep 17 00:00:00 2001 From: Gary Edgar Date: Fri, 8 Mar 2019 12:05:03 -0800 Subject: [PATCH 180/196] Adding pentest PDF Signed-off-by: Gary Edgar --- doc/VIT-01-report.pdf | Bin 0 -> 158736 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/VIT-01-report.pdf diff --git a/doc/VIT-01-report.pdf b/doc/VIT-01-report.pdf new file mode 100644 index 0000000000000000000000000000000000000000..353b62cd3e54213fbf077de40c164df1c7b95653 GIT binary patch literal 158736 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 F{{eU;U)=xz literal 0 HcmV?d00001 From cd77571affc5eb7cb0b42029878b9f197af9ab5e Mon Sep 17 00:00:00 2001 From: Gary Edgar Date: Fri, 8 Mar 2019 12:08:25 -0800 Subject: [PATCH 181/196] Add security section to README Signed-off-by: Gary Edgar --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 37bf331c2d4..6689e88fdcc 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,12 @@ Subscribe to or the [Vitess Blog](https://blog.vitess.io/) for low-frequency updates like new features and releases. +## Security + +### Security Audit + +A third party security audit was performed by Cure53, you can see the full report [here](docs/SECURITY_AUDIT.pdf). + ## License Unless otherwise noted, the Vitess source files are distributed From a49977e368546fe5e20e758ca60ae4573dbd2855 Mon Sep 17 00:00:00 2001 From: Gary Edgar Date: Fri, 8 Mar 2019 12:20:00 -0800 Subject: [PATCH 182/196] Correcting link to pentest PDF Signed-off-by: Gary Edgar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6689e88fdcc..b9f26544c7d 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ for low-frequency updates like new features and releases. ### Security Audit -A third party security audit was performed by Cure53, you can see the full report [here](docs/SECURITY_AUDIT.pdf). +A third party security audit was performed by Cure53, you can see the full report [here](doc/VIT-01-report.pdf). ## License From a592e8740a45b5f5036534e52b3b59c4b3ddd05b Mon Sep 17 00:00:00 2001 From: Gary Edgar Date: Fri, 8 Mar 2019 12:24:46 -0800 Subject: [PATCH 183/196] Grammar tweak Signed-off-by: Gary Edgar --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b9f26544c7d..f8b14b0c126 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ for low-frequency updates like new features and releases. ### Security Audit -A third party security audit was performed by Cure53, you can see the full report [here](doc/VIT-01-report.pdf). +A third party security audit was performed by Cure53. You can see the full report [here](doc/VIT-01-report.pdf). ## License From b9acd8699def06ecce1a9b7727a92305acc7cacd Mon Sep 17 00:00:00 2001 From: deepthi Date: Tue, 12 Mar 2019 13:30:10 -0700 Subject: [PATCH 184/196] fixes from review Signed-off-by: deepthi --- go/mysql/conn_test.go | 4 +++- go/mysql/ldapauthserver/auth_server_ldap.go | 15 +++++++-------- go/mysql/ldapauthserver/auth_server_ldap_test.go | 9 +++++---- go/vt/tlstest/tlstest_test.go | 9 +++++++-- 4 files changed, 22 insertions(+), 15 deletions(-) diff --git a/go/mysql/conn_test.go b/go/mysql/conn_test.go index 5c352164831..3c3a848cac3 100644 --- a/go/mysql/conn_test.go +++ b/go/mysql/conn_test.go @@ -24,6 +24,7 @@ import ( "reflect" "sync" "testing" + "time" ) func createSocketPair(t *testing.T) (net.Listener, *Conn, *Conn) { @@ -33,6 +34,7 @@ func createSocketPair(t *testing.T) (net.Listener, *Conn, *Conn) { t.Fatalf("Listen failed: %v", err) } addr := listener.Addr().String() + listener.(*net.TCPListener).SetDeadline(time.Now().Add(10 * time.Second)) // Dial a client, Accept a server. wg := sync.WaitGroup{} @@ -42,7 +44,7 @@ func createSocketPair(t *testing.T) (net.Listener, *Conn, *Conn) { wg.Add(1) go func() { defer wg.Done() - clientConn, clientErr = net.Dial("tcp", addr) + clientConn, clientErr = net.DialTimeout("tcp", addr, 10*time.Second) }() var serverConn net.Conn diff --git a/go/mysql/ldapauthserver/auth_server_ldap.go b/go/mysql/ldapauthserver/auth_server_ldap.go index f7f197b96e0..513e1c66502 100644 --- a/go/mysql/ldapauthserver/auth_server_ldap.go +++ b/go/mysql/ldapauthserver/auth_server_ldap.go @@ -43,13 +43,12 @@ var ( type AuthServerLdap struct { Client ServerConfig - Method string - User string - Password string - GroupQuery string - UserDnPattern string - // staticcheck: var RefreshSeconds is of type time.Duration; don't use unit-specific suffix "Seconds" (ST1011) - RefreshSeconds time.Duration + Method string + User string + Password string + GroupQuery string + UserDnPattern string + RefreshSeconds int64 } // Init is public so it can be called from plugin_auth_ldap.go (go/cmd/vtgate) @@ -190,7 +189,7 @@ func (lud *LdapUserData) update() { // Get returns wrapped username and LDAP groups and possibly updates the cache func (lud *LdapUserData) Get() *querypb.VTGateCallerID { - if time.Since(lud.lastUpdated) > lud.asl.RefreshSeconds*time.Second { + if int64(time.Since(lud.lastUpdated).Seconds()) > lud.asl.RefreshSeconds { go lud.update() } return &querypb.VTGateCallerID{Username: lud.username, Groups: lud.groups} diff --git a/go/mysql/ldapauthserver/auth_server_ldap_test.go b/go/mysql/ldapauthserver/auth_server_ldap_test.go index fd9daef65ac..983cf1ff13e 100644 --- a/go/mysql/ldapauthserver/auth_server_ldap_test.go +++ b/go/mysql/ldapauthserver/auth_server_ldap_test.go @@ -39,10 +39,11 @@ func (mlc *MockLdapClient) Search(searchRequest *ldap.SearchRequest) (*ldap.Sear func TestValidateClearText(t *testing.T) { asl := &AuthServerLdap{ - Client: &MockLdapClient{}, - User: "testuser", - Password: "testpass", - UserDnPattern: "%s", + Client: &MockLdapClient{}, + User: "testuser", + Password: "testpass", + UserDnPattern: "%s", + RefreshSeconds: 1, } _, err := asl.validate("testuser", "testpass") if err != nil { diff --git a/go/vt/tlstest/tlstest_test.go b/go/vt/tlstest/tlstest_test.go index 785b2978d2b..b8bd0039d6f 100644 --- a/go/vt/tlstest/tlstest_test.go +++ b/go/vt/tlstest/tlstest_test.go @@ -21,11 +21,13 @@ import ( "fmt" "io" "io/ioutil" + "net" "os" "path" "strings" "sync" "testing" + "time" "vitess.io/vitess/go/vt/vttls" ) @@ -74,6 +76,9 @@ func TestClientServer(t *testing.T) { } addr := listener.Addr().String() defer listener.Close() + // create a dialer with timeout + dialer := new(net.Dialer) + dialer.Timeout = 10 * time.Second wg := sync.WaitGroup{} @@ -84,7 +89,7 @@ func TestClientServer(t *testing.T) { wg.Add(1) go func() { defer wg.Done() - clientConn, clientErr := tls.Dial("tcp", addr, clientConfig) + clientConn, clientErr := tls.DialWithDialer(dialer, "tcp", addr, clientConfig) if clientErr == nil { clientConn.Write([]byte{42}) clientConn.Close() @@ -142,7 +147,7 @@ func TestClientServer(t *testing.T) { // When using TLS 1.2, the Dial will fail. // With TLS 1.3, the Dial will succeed and the first Read will fail. - clientConn, err := tls.Dial("tcp", addr, badClientConfig) + clientConn, err := tls.DialWithDialer(dialer, "tcp", addr, badClientConfig) if err != nil { if !strings.Contains(err.Error(), "bad certificate") { t.Errorf("Wrong error returned: %v", err) From 410e20dcb1bbf977187675a8a71608eac8296b19 Mon Sep 17 00:00:00 2001 From: Rafael Chacon Date: Thu, 14 Mar 2019 14:36:21 -0700 Subject: [PATCH 185/196] Updates per code review Signed-off-by: Rafael Chacon --- go/vt/topo/srv_keyspace.go | 134 ++++++++++++---------- go/vt/topo/topotests/srv_keyspace_test.go | 26 ++--- go/vt/wrangler/shard.go | 12 +- 3 files changed, 93 insertions(+), 79 deletions(-) diff --git a/go/vt/topo/srv_keyspace.go b/go/vt/topo/srv_keyspace.go index e0abe139358..7f895741d0d 100644 --- a/go/vt/topo/srv_keyspace.go +++ b/go/vt/topo/srv_keyspace.go @@ -232,9 +232,8 @@ func (ts *Server) GetShardServingTypes(ctx context.Context, si *ShardInfo) (serv return servingTypes, nil } -// UpdateSrvKeyspacePartitions will make sure the disableQueryService is -// set appropriately in tablet controls in srvKeyspace. -func (ts *Server) UpdateSrvKeyspacePartitions(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string, remove bool) (err error) { +// AddSrvKeyspacePartitions adds partitions to srvKeyspace +func (ts *Server) AddSrvKeyspacePartitions(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string) (err error) { if err = CheckKeyspaceLocked(ctx, keyspace); err != nil { return err } @@ -272,28 +271,18 @@ func (ts *Server) UpdateSrvKeyspacePartitions(ctx context.Context, keyspace stri } } - if !found && !remove { + if !found { shardReference := &topodatapb.ShardReference{ Name: si.ShardName(), KeyRange: si.KeyRange, } partition.ShardReferences = append(partition.GetShardReferences(), shardReference) } - - if found && remove { - shardReferences := make([]*topodatapb.ShardReference, 0) - for _, shardReference := range partition.GetShardReferences() { - if !key.KeyRangeEqual(shardReference.GetKeyRange(), si.GetKeyRange()) { - shardReferences = append(shardReferences, shardReference) - } - } - partition.ShardReferences = shardReferences - } } } // Partition does not exist at all, we need to create it - if !partitionFound && !remove { + if !partitionFound { partition := &topodatapb.SrvKeyspace_KeyspacePartition{ ServedType: tabletType, @@ -333,6 +322,74 @@ func (ts *Server) UpdateSrvKeyspacePartitions(ctx context.Context, keyspace stri return nil } +// DeleteSrvKeyspacePartitions deletes shards from srvKeyspace partitions +func (ts *Server) DeleteSrvKeyspacePartitions(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string) (err error) { + if err = CheckKeyspaceLocked(ctx, keyspace); err != nil { + return err + } + + // The caller intents to update all cells in this case + if len(cells) == 0 { + cells, err = ts.GetCellInfoNames(ctx) + if err != nil { + return err + } + } + + wg := sync.WaitGroup{} + rec := concurrency.AllErrorRecorder{} + for _, cell := range cells { + wg.Add(1) + go func(cell string) { + defer wg.Done() + srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) + switch { + case err == nil: + for _, partition := range srvKeyspace.GetPartitions() { + if partition.GetServedType() != tabletType { + continue + } + + for _, si := range shards { + found := false + for _, shardReference := range partition.GetShardReferences() { + if key.KeyRangeEqual(shardReference.GetKeyRange(), si.GetKeyRange()) { + found = true + } + } + + if found { + shardReferences := make([]*topodatapb.ShardReference, 0) + for _, shardReference := range partition.GetShardReferences() { + if !key.KeyRangeEqual(shardReference.GetKeyRange(), si.GetKeyRange()) { + shardReferences = append(shardReferences, shardReference) + } + } + partition.ShardReferences = shardReferences + } + } + } + + err = ts.UpdateSrvKeyspace(ctx, cell, keyspace, srvKeyspace) + if err != nil { + rec.RecordError(err) + return + } + case IsErrType(err, NoNode): + // NOOP + default: + rec.RecordError(err) + return + } + }(cell) + } + wg.Wait() + if rec.HasErrors() { + return NewError(PartialResult, rec.Error().Error()) + } + return nil +} + // UpdateDisableQueryService will make sure the disableQueryService is // set appropriately in tablet controls in srvKeyspace. func (ts *Server) UpdateDisableQueryService(ctx context.Context, keyspace string, shards []*ShardInfo, tabletType topodatapb.TabletType, cells []string, disableQueryService bool) (err error) { @@ -570,53 +627,6 @@ func (ts *Server) GetSrvKeyspaceAllCells(ctx context.Context, keyspace string) ( return srvKeyspaces, nil } -// IsShardQueryServiceDisabled returns served types for given shard across all cells -func (ts *Server) IsShardQueryServiceDisabled(ctx context.Context, si *ShardInfo) (queryServiceDisabled bool, err error) { - cells, err := ts.GetCellInfoNames(ctx) - if err != nil { - return queryServiceDisabled, err - } - - wg := sync.WaitGroup{} - rec := concurrency.AllErrorRecorder{} - var mu sync.Mutex - for _, cell := range cells { - wg.Add(1) - go func(cell, keyspace string) { - defer wg.Done() - srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, si.keyspace) - switch { - case err == nil: - func() { - mu.Lock() - defer mu.Unlock() - if queryServiceDisabled { - return - } - for _, partition := range srvKeyspace.GetPartitions() { - for _, shardReference := range partition.ShardReferences { - if shardReference.GetName() == si.ShardName() { - } - } - - } - }() - case IsErrType(err, NoNode): - // NOOP - return - default: - rec.RecordError(err) - return - } - }(cell, si.Keyspace()) - } - wg.Wait() - if rec.HasErrors() { - return queryServiceDisabled, NewError(PartialResult, rec.Error().Error()) - } - return queryServiceDisabled, nil -} - // GetSrvKeyspace returns the SrvKeyspace for a cell/keyspace. func (ts *Server) GetSrvKeyspace(ctx context.Context, cell, keyspace string) (*topodatapb.SrvKeyspace, error) { conn, err := ts.ConnForCell(ctx, cell) diff --git a/go/vt/topo/topotests/srv_keyspace_test.go b/go/vt/topo/topotests/srv_keyspace_test.go index 14fe1a6f0da..45829c5dfe7 100644 --- a/go/vt/topo/topotests/srv_keyspace_test.go +++ b/go/vt/topo/topotests/srv_keyspace_test.go @@ -322,8 +322,8 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { } defer unlock(&err) - if err := ts.UpdateSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_MASTER, []string{cell}, false /* remove */); err != nil { - t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + if err := ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_MASTER, []string{cell}); err != nil { + t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err) } srvKeyspace, err := ts.GetSrvKeyspace(ctx, cell, keyspace) @@ -342,7 +342,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { } if string(got) != string(want) { - t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + t.Errorf("AddSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) } // removing works @@ -360,8 +360,8 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { }, } - if err = ts.UpdateSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_MASTER, []string{cell}, true /* remove */); err != nil { - t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + if err = ts.DeleteSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_MASTER, []string{cell}); err != nil { + t.Fatalf("DeleteSrvKeyspacePartitions() failed: %v", err) } srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) @@ -380,7 +380,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { } if string(got) != string(want) { - t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + t.Errorf("DeleteSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) } // You can add to partitions that do not exist @@ -411,8 +411,8 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { }, } - if err = ts.UpdateSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, []string{cell}, false /* remove */); err != nil { - t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + if err = ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, []string{cell}); err != nil { + t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err) } srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) @@ -431,13 +431,13 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { } if string(got) != string(want) { - t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + t.Errorf("SrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) } // it works in multiple cells - if err = ts.UpdateSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, nil, false /* remove */); err != nil { - t.Fatalf("UpdateSrvKeyspace() failed: %v", err) + if err = ts.AddSrvKeyspacePartitions(ctx, keyspace, shards, topodatapb.TabletType_REPLICA, nil); err != nil { + t.Fatalf("AddSrvKeyspacePartitions() failed: %v", err) } srvKeyspace, err = ts.GetSrvKeyspace(ctx, cell, keyspace) @@ -456,7 +456,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { } if string(got) != string(want) { - t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + t.Errorf("AddSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) } // Now let's get the srvKeyspace in cell2. Partition should have been added there too. @@ -466,7 +466,7 @@ func TestUpdateSrvKeyspacePartitions(t *testing.T) { } if string(got) != string(want) { - t.Errorf("UpdateSrvKeyspacePartitions() failure. Got %v, want: %v", string(got), string(want)) + t.Errorf("GetSrvKeyspace() failure. Got %v, want: %v", string(got), string(want)) } } diff --git a/go/vt/wrangler/shard.go b/go/vt/wrangler/shard.go index 56bff8f5e3d..ec19ad4fe54 100644 --- a/go/vt/wrangler/shard.go +++ b/go/vt/wrangler/shard.go @@ -139,7 +139,11 @@ func (wr *Wrangler) UpdateSrvKeyspacePartitions(ctx context.Context, keyspace, s if err != nil { return err } - return wr.ts.UpdateSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{si}, tabletType, cells, remove) + + if remove { + return wr.ts.DeleteSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{si}, tabletType, cells) + } + return wr.ts.AddSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{si}, tabletType, cells) } // DeleteShard will do all the necessary changes in the topology server @@ -326,14 +330,14 @@ func (wr *Wrangler) RemoveShardCell(ctx context.Context, keyspace, shard, cell s } defer unlock(&err) - if err = wr.ts.UpdateSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_RDONLY, shardServingCells, true /* remove */); err != nil { + if err = wr.ts.DeleteSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_RDONLY, shardServingCells); err != nil { return err } - if err = wr.ts.UpdateSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_REPLICA, shardServingCells, true /* remove */); err != nil { + if err = wr.ts.DeleteSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_REPLICA, shardServingCells); err != nil { return err } - return wr.ts.UpdateSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_MASTER, shardServingCells, true /* remove */) + return wr.ts.DeleteSrvKeyspacePartitions(ctx, keyspace, []*topo.ShardInfo{shardInfo}, topodatapb.TabletType_MASTER, shardServingCells) } // SourceShardDelete will delete a SourceShard inside a shard, by index. From 04ca16e806f2d851354cebcc8f51ad5a7a4918cc Mon Sep 17 00:00:00 2001 From: Gary Edgar Date: Fri, 15 Mar 2019 17:46:50 -0700 Subject: [PATCH 186/196] Chart.yaml: Update icon URL Signed-off-by: Gary Edgar --- helm/vitess/Chart.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helm/vitess/Chart.yaml b/helm/vitess/Chart.yaml index 5b5f91e833e..16da802ec96 100644 --- a/helm/vitess/Chart.yaml +++ b/helm/vitess/Chart.yaml @@ -17,4 +17,4 @@ sources: maintainers: - name: Vitess Project email: vitess@googlegroups.com -icon: https://vitess.io/images/vitess_logo_with_border.svg +icon: https://vitess.io/img/logos/vitess.png From ad1827f4c75ed90d73c353dc18fbb4e21e80341a Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Sat, 23 Feb 2019 16:29:12 -0800 Subject: [PATCH 187/196] vstreamer: remove hour, etc. Removing these functions. These will be done on the vplayer side using mysql native functions. Signed-off-by: Sugu Sougoumarane --- .../tabletserver/vstreamer/planbuilder.go | 114 +++++------------- .../vstreamer/planbuilder_test.go | 80 +++--------- .../tabletserver/vstreamer/vstreamer_test.go | 50 -------- 3 files changed, 44 insertions(+), 200 deletions(-) diff --git a/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go b/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go index f9920e791fb..296f7bb40b2 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go +++ b/go/vt/vttablet/tabletserver/vstreamer/planbuilder.go @@ -20,7 +20,6 @@ import ( "fmt" "regexp" "strings" - "time" "vitess.io/vitess/go/mysql" "vitess.io/vitess/go/sqltypes" @@ -45,23 +44,11 @@ type Plan struct { // ColExpr represents a column expression. type ColExpr struct { - ColNum int - Alias sqlparser.ColIdent - Type querypb.Type - Operation Operation + ColNum int + Alias sqlparser.ColIdent + Type querypb.Type } -// Operation represents the operation to be performed on a column. -type Operation int - -// The following are the supported operations on a column. -const ( - OpNone = Operation(iota) - OpMonth - OpDay - OpHour -) - // Table contains the metadata for a table. The // name is dervied from mysql's Table_map_log_event. type Table struct { @@ -78,25 +65,7 @@ type Table struct { func (plan *Plan) filter(values []sqltypes.Value) (bool, []sqltypes.Value, error) { result := make([]sqltypes.Value, len(plan.ColExprs)) for i, colExpr := range plan.ColExprs { - switch colExpr.Operation { - case OpMonth: - v, _ := sqltypes.ToInt64(values[colExpr.ColNum]) - t := time.Unix(v, 0).UTC() - s := fmt.Sprintf("%d%02d", t.Year(), t.Month()) - result[i] = sqltypes.NewVarBinary(s) - case OpDay: - v, _ := sqltypes.ToInt64(values[colExpr.ColNum]) - t := time.Unix(v, 0).UTC() - s := fmt.Sprintf("%d%02d%02d", t.Year(), t.Month(), t.Day()) - result[i] = sqltypes.NewVarBinary(s) - case OpHour: - v, _ := sqltypes.ToInt64(values[colExpr.ColNum]) - t := time.Unix(v, 0).UTC() - s := fmt.Sprintf("%d%02d%02d%02d", t.Year(), t.Month(), t.Day(), t.Hour()) - result[i] = sqltypes.NewVarBinary(s) - default: - result[i] = values[colExpr.ColNum] - } + result[i] = values[colExpr.ColNum] } if plan.Vindex == nil { return true, result, nil @@ -251,21 +220,21 @@ func buildTablePlan(ti *Table, kschema *vindexes.KeyspaceSchema, query string) ( } sel, ok := statement.(*sqlparser.Select) if !ok { - return nil, fmt.Errorf("unexpected: %v", sqlparser.String(statement)) + return nil, fmt.Errorf("unsupported: %v", sqlparser.String(statement)) } if len(sel.From) > 1 { - return nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + return nil, fmt.Errorf("unsupported: %v", sqlparser.String(sel)) } node, ok := sel.From[0].(*sqlparser.AliasedTableExpr) if !ok { - return nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + return nil, fmt.Errorf("unsupported: %v", sqlparser.String(sel)) } fromTable := sqlparser.GetTableName(node.Expr) if fromTable.IsEmpty() { - return nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + return nil, fmt.Errorf("unsupported: %v", sqlparser.String(sel)) } if fromTable.String() != ti.Name { - return nil, fmt.Errorf("unexpected: select expression table %v does not match the table entry name %s", sqlparser.String(fromTable), ti.Name) + return nil, fmt.Errorf("unsupported: select expression table %v does not match the table entry name %s", sqlparser.String(fromTable), ti.Name) } if _, ok := sel.SelectExprs[0].(*sqlparser.StarExpr); !ok { @@ -278,7 +247,7 @@ func buildTablePlan(ti *Table, kschema *vindexes.KeyspaceSchema, query string) ( } } else { if len(sel.SelectExprs) != 1 { - return nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + return nil, fmt.Errorf("unsupported: %v", sqlparser.String(sel)) } plan.ColExprs = make([]ColExpr, len(ti.Columns)) for i, col := range ti.Columns { @@ -295,10 +264,10 @@ func buildTablePlan(ti *Table, kschema *vindexes.KeyspaceSchema, query string) ( // Filter by Vindex. funcExpr, ok := sel.Where.Expr.(*sqlparser.FuncExpr) if !ok { - return nil, fmt.Errorf("unexpected where clause: %v", sqlparser.String(sel.Where)) + return nil, fmt.Errorf("unsupported where clause: %v", sqlparser.String(sel.Where)) } if !funcExpr.Name.EqualString("in_keyrange") { - return nil, fmt.Errorf("unexpected where clause: %v", sqlparser.String(sel.Where)) + return nil, fmt.Errorf("unsupported where clause: %v", sqlparser.String(sel.Where)) } if len(funcExpr.Exprs) != 3 { return nil, fmt.Errorf("unexpected where clause: %v", sqlparser.String(sel.Where)) @@ -309,7 +278,7 @@ func buildTablePlan(ti *Table, kschema *vindexes.KeyspaceSchema, query string) ( } colname, ok := aexpr.Expr.(*sqlparser.ColName) if !ok { - return nil, fmt.Errorf("unsupported: %v", sqlparser.String(funcExpr)) + return nil, fmt.Errorf("unexpected: %v", sqlparser.String(funcExpr)) } found := false for i, cExpr := range plan.ColExprs { @@ -351,63 +320,34 @@ func buildTablePlan(ti *Table, kschema *vindexes.KeyspaceSchema, query string) ( func analyzeExpr(ti *Table, selExpr sqlparser.SelectExpr) (cExpr ColExpr, err error) { aliased, ok := selExpr.(*sqlparser.AliasedExpr) if !ok { - return ColExpr{}, fmt.Errorf("unexpected: %v", sqlparser.String(selExpr)) + return ColExpr{}, fmt.Errorf("unsupported: %v", sqlparser.String(selExpr)) } as := aliased.As if as.IsEmpty() { as = sqlparser.NewColIdent(sqlparser.String(aliased.Expr)) } - switch expr := aliased.Expr.(type) { - case *sqlparser.ColName: - colnum, err := findColumn(ti, expr.Name) - if err != nil { - return ColExpr{}, err - } - return ColExpr{ColNum: colnum, Alias: as, Type: ti.Columns[colnum].Type}, nil - case *sqlparser.FuncExpr: - if expr.Distinct || len(expr.Exprs) != 1 { - return ColExpr{}, fmt.Errorf("unsupported: %v", sqlparser.String(expr)) - } - switch fname := expr.Name.Lowered(); fname { - case "month", "day", "hour": - aInner, ok := expr.Exprs[0].(*sqlparser.AliasedExpr) - if !ok { - return ColExpr{}, fmt.Errorf("unsupported: %v", sqlparser.String(expr)) - } - innerCol, ok := aInner.Expr.(*sqlparser.ColName) - if !ok { - return ColExpr{}, fmt.Errorf("unsupported: %v", sqlparser.String(expr)) - } - colnum, err := findColumn(ti, innerCol.Name) - if err != nil { - return ColExpr{}, err - } - switch fname { - case "month": - return ColExpr{ColNum: colnum, Alias: as, Type: sqltypes.VarBinary, Operation: OpMonth}, nil - case "day": - return ColExpr{ColNum: colnum, Alias: as, Type: sqltypes.VarBinary, Operation: OpDay}, nil - case "hour": - return ColExpr{ColNum: colnum, Alias: as, Type: sqltypes.VarBinary, Operation: OpHour}, nil - default: - panic("unreachable") - } - default: - return ColExpr{}, fmt.Errorf("unsupported: %v", sqlparser.String(expr)) - } - default: - return ColExpr{}, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) + colname, ok := aliased.Expr.(*sqlparser.ColName) + if !ok { + return ColExpr{}, fmt.Errorf("unsupported: %v", sqlparser.String(aliased.Expr)) + } + if !colname.Qualifier.IsEmpty() { + return ColExpr{}, fmt.Errorf("unsupported qualifier for column: %v", sqlparser.String(colname)) + } + colnum, err := findColumn(ti, colname.Name) + if err != nil { + return ColExpr{}, err } + return ColExpr{ColNum: colnum, Alias: as, Type: ti.Columns[colnum].Type}, nil } func selString(expr sqlparser.SelectExpr) (string, error) { aexpr, ok := expr.(*sqlparser.AliasedExpr) if !ok { - return "", fmt.Errorf("unexpected: %v", sqlparser.String(expr)) + return "", fmt.Errorf("unsupported: %v", sqlparser.String(expr)) } val, ok := aexpr.Expr.(*sqlparser.SQLVal) if !ok { - return "", fmt.Errorf("unexpected: %v", sqlparser.String(expr)) + return "", fmt.Errorf("unsupported: %v", sqlparser.String(expr)) } return string(val.Val), nil } diff --git a/go/vt/vttablet/tabletserver/vstreamer/planbuilder_test.go b/go/vt/vttablet/tabletserver/vstreamer/planbuilder_test.go index f9f357e24e2..23a896eff78 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/planbuilder_test.go +++ b/go/vt/vttablet/tabletserver/vstreamer/planbuilder_test.go @@ -275,36 +275,6 @@ func TestPlanbuilder(t *testing.T) { }}, VindexColumn: 1, }, - }, { - inTable: t1, - inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val, month(val) m, day(id), hour(val) from t1 where in_keyrange(m, 'hash', '-80')"}, - outPlan: &Plan{ - ColExprs: []ColExpr{{ - ColNum: 0, - Alias: sqlparser.NewColIdent("id"), - Type: sqltypes.Int64, - }, { - ColNum: 1, - Alias: sqlparser.NewColIdent("val"), - Type: sqltypes.VarBinary, - }, { - ColNum: 1, - Alias: sqlparser.NewColIdent("m"), - Type: sqltypes.VarBinary, - Operation: OpMonth, - }, { - ColNum: 0, - Alias: sqlparser.NewColIdent("day(id)"), - Type: sqltypes.VarBinary, - Operation: OpDay, - }, { - ColNum: 1, - Alias: sqlparser.NewColIdent("hour(val)"), - Type: sqltypes.VarBinary, - Operation: OpHour, - }}, - VindexColumn: 2, - }, }, { inTable: t2, inRule: &binlogdatapb.Rule{Match: "/t1/"}, @@ -335,35 +305,35 @@ func TestPlanbuilder(t *testing.T) { }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "delete from t1"}, - outErr: `unexpected: delete from t1`, + outErr: `unsupported: delete from t1`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select * from t1, t2"}, - outErr: `unexpected: select * from t1, t2`, + outErr: `unsupported: select * from t1, t2`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select * from t1 join t2"}, - outErr: `unexpected: select * from t1 join t2`, + outErr: `unsupported: select * from t1 join t2`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select * from a.t1"}, - outErr: `unexpected: select * from a.t1`, + outErr: `unsupported: select * from a.t1`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select * from t2"}, - outErr: `unexpected: select expression table t2 does not match the table entry name t1`, + outErr: `unsupported: select expression table t2 does not match the table entry name t1`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select *, id from t1"}, - outErr: `unexpected: select *, id from t1`, + outErr: `unsupported: select *, id from t1`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val from t1 where id=1"}, - outErr: `unexpected where clause: where id = 1`, + outErr: `unsupported where clause: where id = 1`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val from t1 where max(id)"}, - outErr: `unexpected where clause: where max(id)`, + outErr: `unsupported where clause: where max(id)`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val from t1 where in_keyrange(id)"}, @@ -375,7 +345,7 @@ func TestPlanbuilder(t *testing.T) { }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val from t1 where in_keyrange(1, 'hash', '-80')"}, - outErr: `unsupported: in_keyrange(1, 'hash', '-80')`, + outErr: `unexpected: in_keyrange(1, 'hash', '-80')`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val from t1 where in_keyrange(none, 'hash', '-80')"}, @@ -396,31 +366,11 @@ func TestPlanbuilder(t *testing.T) { // analyzeExpr tests. inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, * from t1"}, - outErr: `unexpected: *`, + outErr: `unsupported: *`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select none from t1"}, outErr: `column none not found in table t1`, - }, { - inTable: t1, - inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val, hour(distinct a) from t1"}, - outErr: `unsupported: hour(distinct a)`, - }, { - inTable: t1, - inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val, hour(a, b) from t1"}, - outErr: `unsupported: hour(a, b)`, - }, { - inTable: t1, - inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val, hour(*) from t1"}, - outErr: `unsupported: hour(*)`, - }, { - inTable: t1, - inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val, hour(val+1) from t1"}, - outErr: `unsupported: hour(val + 1)`, - }, { - inTable: t1, - inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val, hour(none) from t1"}, - outErr: `column none not found in table t1`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val, max(val) from t1"}, @@ -428,16 +378,20 @@ func TestPlanbuilder(t *testing.T) { }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id+1, val from t1"}, - outErr: `unexpected: id + 1`, + outErr: `unsupported: id + 1`, + }, { + inTable: t1, + inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select t1.id, val from t1"}, + outErr: `unsupported qualifier for column: t1.id`, }, { // selString inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val from t1 where in_keyrange(id, *, '-80')"}, - outErr: `unexpected: *`, + outErr: `unsupported: *`, }, { inTable: t1, inRule: &binlogdatapb.Rule{Match: "t1", Filter: "select id, val from t1 where in_keyrange(id, 1+1, '-80')"}, - outErr: `unexpected: 1 + 1`, + outErr: `unsupported: 1 + 1`, }} for _, tcase := range testcases { diff --git a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go index 2aac52449b5..4d8ceccb157 100644 --- a/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go +++ b/go/vt/vttablet/tabletserver/vstreamer/vstreamer_test.go @@ -309,56 +309,6 @@ func TestSelectFilter(t *testing.T) { runCases(t, filter, testcases) } -func TestSelectExpressions(t *testing.T) { - if testing.Short() { - t.Skip() - } - - execStatements(t, []string{ - "create table expr_test(id int, val bigint, primary key(id))", - }) - defer execStatements(t, []string{ - "drop table expr_test", - }) - engine.se.Reload(context.Background()) - - filter := &binlogdatapb.Filter{ - Rules: []*binlogdatapb.Rule{{ - Match: "expr_test", - Filter: "select id, val, month(val), day(val), hour(val) from expr_test", - }}, - } - - testcases := []testcase{{ - input: []string{ - "begin", - "insert into expr_test values (1, 1546392881)", - "commit", - }, - // MySQL issues GTID->BEGIN. - // MariaDB issues BEGIN->GTID. - output: [][]string{{ - `gtid|begin`, - `gtid|begin`, - `type:FIELD field_event: ` + - `fields: ` + - `fields: ` + - `fields: ` + - `fields: > `, - `type:ROW row_event: > > `, - `commit`, - }}, - }} - runCases(t, filter, testcases) -} - func TestDDLAddColumn(t *testing.T) { if testing.Short() { t.Skip() From 3d917789201468b342a3af2f96970adfb6afe105 Mon Sep 17 00:00:00 2001 From: Sugu Sougoumarane Date: Sat, 23 Feb 2019 16:36:00 -0800 Subject: [PATCH 188/196] vplayer: use new new way to apply events This new way, as described in #4604, is more flexible and will make it easer to support copy functionality. Signed-off-by: Sugu Sougoumarane --- .../tabletmanager/vreplication/player_plan.go | 418 ++------------- .../vreplication/player_plan_test.go | 212 +++----- .../vreplication/table_plan_builder.go | 498 ++++++++++++++++++ .../tabletmanager/vreplication/vplayer.go | 102 ++-- .../vreplication/vplayer_test.go | 30 +- 5 files changed, 682 insertions(+), 578 deletions(-) create mode 100644 go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go diff --git a/go/vt/vttablet/tabletmanager/vreplication/player_plan.go b/go/vt/vttablet/tabletmanager/vreplication/player_plan.go index ab960c90a2b..dc7bebf084e 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/player_plan.go +++ b/go/vt/vttablet/tabletmanager/vreplication/player_plan.go @@ -17,9 +17,6 @@ limitations under the License. package vreplication import ( - "fmt" - "strings" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/sqlparser" @@ -34,386 +31,85 @@ type PlayerPlan struct { } // TablePlan is the execution plan for a table within a player stream. -// There are two incarantions of this per table. The first one is built -// while analyzing the inital stream request. A tentative plan is built -// without knowing the table info. The second incarnation is built when -// we receive the field info for a table. At that time, we copy the -// original TablePlan into a separate map and populate the Fields and -// PKCols members. type TablePlan struct { - Name string - ColExprs []*ColExpr `json:",omitempty"` - OnInsert InsertType `json:",omitempty"` - - Fields []*querypb.Field `json:",omitempty"` - PKCols []*ColExpr `json:",omitempty"` -} - -// ColExpr describes the processing to be performed to -// compute the value of the target table column. -type ColExpr struct { - ColName sqlparser.ColIdent - ColNum int - Operation Operation `json:",omitempty"` - IsGrouped bool `json:",omitempty"` + Name string + PKReferences []string `json:",omitempty"` + Insert *sqlparser.ParsedQuery `json:",omitempty"` + Update *sqlparser.ParsedQuery `json:",omitempty"` + Delete *sqlparser.ParsedQuery `json:",omitempty"` + Fields []*querypb.Field `json:",omitempty"` } -// Operation is the opcode for the ColExpr. -type Operation int - -// The following values are the various ColExpr opcodes. -const ( - OpNone = Operation(iota) - OpCount - OpSum -) - -// InsertType describes the type of insert statement to generate. -type InsertType int - -// The following values are the various insert types. -const ( - InsertNormal = InsertType(iota) - InsertOndup - InsertIgnore -) - -func buildPlayerPlan(filter *binlogdatapb.Filter) (*PlayerPlan, error) { - plan := &PlayerPlan{ - VStreamFilter: &binlogdatapb.Filter{ - Rules: make([]*binlogdatapb.Rule, len(filter.Rules)), - }, - TablePlans: make(map[string]*TablePlan), - } - for i, rule := range filter.Rules { - if strings.HasPrefix(rule.Match, "/") { - plan.VStreamFilter.Rules[i] = rule - continue - } - sendRule, tp, err := buildTablePlan(rule) - if err != nil { - return nil, err +func (tp *TablePlan) generateStatements(rowChange *binlogdatapb.RowChange) ([]string, error) { + // MakeRowTrusted is needed here because Proto3ToResult is not convenient. + var before, after bool + bindvars := make(map[string]*querypb.BindVariable) + if rowChange.Before != nil { + before = true + vals := sqltypes.MakeRowTrusted(tp.Fields, rowChange.Before) + for i, field := range tp.Fields { + bindvars["b_"+field.Name] = sqltypes.ValueBindVariable(vals[i]) } - plan.VStreamFilter.Rules[i] = sendRule - plan.TablePlans[sendRule.Match] = tp - } - return plan, nil -} - -func buildTablePlan(rule *binlogdatapb.Rule) (*binlogdatapb.Rule, *TablePlan, error) { - statement, err := sqlparser.Parse(rule.Filter) - if err != nil { - return nil, nil, err } - sel, ok := statement.(*sqlparser.Select) - if !ok { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(statement)) - } - if sel.Distinct != "" { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) - } - if len(sel.From) > 1 { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) - } - node, ok := sel.From[0].(*sqlparser.AliasedTableExpr) - if !ok { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) - } - fromTable := sqlparser.GetTableName(node.Expr) - if fromTable.IsEmpty() { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) - } - - if _, ok := sel.SelectExprs[0].(*sqlparser.StarExpr); ok { - if len(sel.SelectExprs) != 1 { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) - } - sendRule := &binlogdatapb.Rule{ - Match: fromTable.String(), - Filter: rule.Filter, + if rowChange.After != nil { + after = true + vals := sqltypes.MakeRowTrusted(tp.Fields, rowChange.After) + for i, field := range tp.Fields { + bindvars["a_"+field.Name] = sqltypes.ValueBindVariable(vals[i]) } - return sendRule, &TablePlan{Name: rule.Match}, nil - } - - tp := &TablePlan{ - Name: rule.Match, } - sendSelect := &sqlparser.Select{ - From: sel.From, - Where: sel.Where, - } - for _, expr := range sel.SelectExprs { - selExpr, cExpr, err := analyzeExpr(expr) + switch { + case !before && after: + query, err := tp.Insert.GenerateQuery(bindvars, nil) if err != nil { - return nil, nil, err + return nil, err } - if selExpr != nil { - sendSelect.SelectExprs = append(sendSelect.SelectExprs, selExpr) - cExpr.ColNum = len(sendSelect.SelectExprs) - 1 + return []string{query}, nil + case before && !after: + if tp.Delete == nil { + return nil, nil } - tp.ColExprs = append(tp.ColExprs, cExpr) - } - - if sel.GroupBy != nil { - if err := analyzeGroupBy(sel.GroupBy, tp); err != nil { - return nil, nil, err + query, err := tp.Delete.GenerateQuery(bindvars, nil) + if err != nil { + return nil, err } - tp.OnInsert = InsertIgnore - for _, cExpr := range tp.ColExprs { - if !cExpr.IsGrouped { - tp.OnInsert = InsertOndup - break + return []string{query}, nil + case before && after: + if !tp.pkChanged(bindvars) { + query, err := tp.Update.GenerateQuery(bindvars, nil) + if err != nil { + return nil, err } + return []string{query}, nil } - } - sendRule := &binlogdatapb.Rule{ - Match: fromTable.String(), - Filter: sqlparser.String(sendSelect), - } - return sendRule, tp, nil -} -func analyzeExpr(selExpr sqlparser.SelectExpr) (sqlparser.SelectExpr, *ColExpr, error) { - aliased, ok := selExpr.(*sqlparser.AliasedExpr) - if !ok { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(selExpr)) - } - as := aliased.As - if as.IsEmpty() { - as = sqlparser.NewColIdent(sqlparser.String(aliased.Expr)) - } - switch expr := aliased.Expr.(type) { - case *sqlparser.ColName: - return selExpr, &ColExpr{ColName: as}, nil - case *sqlparser.FuncExpr: - if expr.Distinct || len(expr.Exprs) != 1 { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) - } - if aliased.As.IsEmpty() { - return nil, nil, fmt.Errorf("expression needs an alias: %v", sqlparser.String(expr)) - } - switch fname := expr.Name.Lowered(); fname { - case "month", "day", "hour": - return selExpr, &ColExpr{ColName: as}, nil - case "count": - if _, ok := expr.Exprs[0].(*sqlparser.StarExpr); !ok { - return nil, nil, fmt.Errorf("only count(*) is supported: %v", sqlparser.String(expr)) - } - return nil, &ColExpr{ColName: as, Operation: OpCount}, nil - case "sum": - aInner, ok := expr.Exprs[0].(*sqlparser.AliasedExpr) - if !ok { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) + queries := make([]string, 0, 2) + if tp.Delete != nil { + query, err := tp.Delete.GenerateQuery(bindvars, nil) + if err != nil { + return nil, err } - innerCol, ok := aInner.Expr.(*sqlparser.ColName) - if !ok { - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) - } - return &sqlparser.AliasedExpr{Expr: innerCol}, &ColExpr{ColName: as, Operation: OpSum}, nil - default: - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) - } - default: - return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) - } -} - -func analyzeGroupBy(groupBy sqlparser.GroupBy, tp *TablePlan) error { - for _, expr := range groupBy { - colname, ok := expr.(*sqlparser.ColName) - if !ok { - return fmt.Errorf("unexpected: %v", sqlparser.String(expr)) - } - cExpr := tp.FindCol(colname.Name) - if cExpr == nil { - return fmt.Errorf("group by expression does not reference an alias in the select list: %v", sqlparser.String(expr)) + queries = append(queries, query) } - if cExpr.Operation != OpNone { - return fmt.Errorf("group by expression is not allowed to reference an aggregate expression: %v", sqlparser.String(expr)) - } - cExpr.IsGrouped = true - } - return nil -} - -//-------------------------------------------------------------- -// TablePlan support functions. - -// FindCol finds the ColExpr. It returns nil if not found. -func (tp *TablePlan) FindCol(name sqlparser.ColIdent) *ColExpr { - for _, cExpr := range tp.ColExprs { - if cExpr.ColName.Equal(name) { - return cExpr - } - } - return nil -} - -// GenerateStatements must be called only after Fields and PKCols have been populated. -func (tp *TablePlan) GenerateStatements(rowChange *binlogdatapb.RowChange) []string { - // MakeRowTrusted is needed here because Proto3ToResult is not convenient. - var before, after []sqltypes.Value - if rowChange.Before != nil { - before = sqltypes.MakeRowTrusted(tp.Fields, rowChange.Before) - } - if rowChange.After != nil { - after = sqltypes.MakeRowTrusted(tp.Fields, rowChange.After) - } - var query string - switch { - case before == nil && after != nil: - query = tp.generateInsert(after) - case before != nil && after != nil: - pkChanged := false - for _, cExpr := range tp.PKCols { - if !valsEqual(before[cExpr.ColNum], after[cExpr.ColNum]) { - pkChanged = true - break - } - } - if pkChanged { - queries := make([]string, 0, 2) - if query := tp.generateDelete(before); query != "" { - queries = append(queries, query) - } - if query := tp.generateInsert(after); query != "" { - queries = append(queries, query) - } - return queries - } - query = tp.generateUpdate(before, after) - case before != nil && after == nil: - query = tp.generateDelete(before) - case before == nil && after == nil: - // unreachable - } - if query != "" { - return []string{query} - } - return nil -} - -func (tp *TablePlan) generateInsert(after []sqltypes.Value) string { - sql := sqlparser.NewTrackedBuffer(nil) - if tp.OnInsert == InsertIgnore { - sql.Myprintf("insert ignore into %v set ", sqlparser.NewTableIdent(tp.Name)) - } else { - sql.Myprintf("insert into %v set ", sqlparser.NewTableIdent(tp.Name)) - } - tp.generateInsertValues(sql, after) - if tp.OnInsert == InsertOndup { - sql.Myprintf(" on duplicate key update ") - _ = tp.generateUpdateValues(sql, nil, after) - } - return sql.String() -} - -func (tp *TablePlan) generateUpdate(before, after []sqltypes.Value) string { - if tp.OnInsert == InsertIgnore { - return tp.generateInsert(after) - } - sql := sqlparser.NewTrackedBuffer(nil) - sql.Myprintf("update %v set ", sqlparser.NewTableIdent(tp.Name)) - if ok := tp.generateUpdateValues(sql, before, after); !ok { - return "" - } - sql.Myprintf(" where ") - tp.generateWhereValues(sql, before) - return sql.String() -} - -func (tp *TablePlan) generateDelete(before []sqltypes.Value) string { - sql := sqlparser.NewTrackedBuffer(nil) - switch tp.OnInsert { - case InsertOndup: - return tp.generateUpdate(before, nil) - case InsertIgnore: - return "" - default: // insertNormal - sql.Myprintf("delete from %v where ", sqlparser.NewTableIdent(tp.Name)) - tp.generateWhereValues(sql, before) - } - return sql.String() -} - -func (tp *TablePlan) generateInsertValues(sql *sqlparser.TrackedBuffer, after []sqltypes.Value) { - separator := "" - for _, cExpr := range tp.ColExprs { - sql.Myprintf("%s%v=", separator, cExpr.ColName) - separator = ", " - if cExpr.Operation == OpCount { - sql.WriteString("1") - } else { - if cExpr.Operation == OpSum && after[cExpr.ColNum].IsNull() { - sql.WriteString("0") - } else { - encodeValue(sql, after[cExpr.ColNum]) - } + query, err := tp.Insert.GenerateQuery(bindvars, nil) + if err != nil { + return nil, err } + queries = append(queries, query) + return queries, nil } + return nil, nil } -// generateUpdateValues returns true if at least one value was set. Otherwise, it returns false. -func (tp *TablePlan) generateUpdateValues(sql *sqlparser.TrackedBuffer, before, after []sqltypes.Value) bool { - separator := "" - hasSet := false - for _, cExpr := range tp.ColExprs { - if cExpr.IsGrouped { - continue - } - if len(before) != 0 && len(after) != 0 { - if cExpr.Operation == OpCount { - continue - } - if valsEqual(before[cExpr.ColNum], after[cExpr.ColNum]) { - continue - } - } - sql.Myprintf("%s%v=", separator, cExpr.ColName) - separator = ", " - hasSet = true - if cExpr.Operation == OpCount || cExpr.Operation == OpSum { - sql.Myprintf("%v", cExpr.ColName) - } - if len(before) != 0 { - switch cExpr.Operation { - case OpNone: - if len(after) == 0 { - sql.WriteString("NULL") - } - case OpCount: - sql.WriteString("-1") - case OpSum: - if !before[cExpr.ColNum].IsNull() { - sql.WriteString("-") - encodeValue(sql, before[cExpr.ColNum]) - } - } - } - if len(after) != 0 { - switch cExpr.Operation { - case OpNone: - encodeValue(sql, after[cExpr.ColNum]) - case OpCount: - sql.WriteString("+1") - case OpSum: - if !after[cExpr.ColNum].IsNull() { - sql.WriteString("+") - encodeValue(sql, after[cExpr.ColNum]) - } - } +func (tp *TablePlan) pkChanged(bindvars map[string]*querypb.BindVariable) bool { + for _, pkref := range tp.PKReferences { + v1, _ := sqltypes.BindVariableToValue(bindvars["b_"+pkref]) + v2, _ := sqltypes.BindVariableToValue(bindvars["a_"+pkref]) + if !valsEqual(v1, v2) { + return true } } - return hasSet -} - -func (tp *TablePlan) generateWhereValues(sql *sqlparser.TrackedBuffer, before []sqltypes.Value) { - separator := "" - for _, cExpr := range tp.PKCols { - sql.Myprintf("%s%v=", separator, cExpr.ColName) - separator = " and " - encodeValue(sql, before[cExpr.ColNum]) - } + return false } func valsEqual(v1, v2 sqltypes.Value) bool { diff --git a/go/vt/vttablet/tabletmanager/vreplication/player_plan_test.go b/go/vt/vttablet/tabletmanager/vreplication/player_plan_test.go index bf5066002f2..2baa5cc9599 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/player_plan_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/player_plan_test.go @@ -21,13 +21,25 @@ import ( "testing" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" - "vitess.io/vitess/go/vt/sqlparser" ) -func TestPlayerPlan(t *testing.T) { +type TestPlayerPlan struct { + VStreamFilter *binlogdatapb.Filter + TablePlans map[string]*TestTablePlan +} + +type TestTablePlan struct { + Name string + PKReferences []string `json:",omitempty"` + Insert string `json:",omitempty"` + Update string `json:",omitempty"` + Delete string `json:",omitempty"` +} + +func TestBuildPlayerPlan(t *testing.T) { testcases := []struct { input *binlogdatapb.Filter - plan *PlayerPlan + plan *TestPlayerPlan err string }{{ // Regular expression @@ -36,13 +48,13 @@ func TestPlayerPlan(t *testing.T) { Match: "/.*", }}, }, - plan: &PlayerPlan{ + plan: &TestPlayerPlan{ VStreamFilter: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "/.*", }}, }, - TablePlans: map[string]*TablePlan{}, + TablePlans: map[string]*TestTablePlan{}, }, }, { // '*' expression @@ -52,14 +64,14 @@ func TestPlayerPlan(t *testing.T) { Filter: "select * from t2", }}, }, - plan: &PlayerPlan{ + plan: &TestPlayerPlan{ VStreamFilter: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "t2", Filter: "select * from t2", }}, }, - TablePlans: map[string]*TablePlan{ + TablePlans: map[string]*TestTablePlan{ "t2": { Name: "t1", }, @@ -73,183 +85,117 @@ func TestPlayerPlan(t *testing.T) { Filter: "select c1, c2 from t2", }}, }, - plan: &PlayerPlan{ + plan: &TestPlayerPlan{ VStreamFilter: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "t2", Filter: "select c1, c2 from t2", }}, }, - TablePlans: map[string]*TablePlan{ + TablePlans: map[string]*TestTablePlan{ "t2": { - Name: "t1", - ColExprs: []*ColExpr{{ - ColName: sqlparser.NewColIdent("c1"), - ColNum: 0, - }, { - ColName: sqlparser.NewColIdent("c2"), - ColNum: 1, - }}, + Name: "t1", + PKReferences: []string{"c1"}, + Insert: "insert into t1 set c1=:a_c1, c2=:a_c2", + Update: "update t1 set c2=:a_c2 where c1=:b_c1", + Delete: "delete from t1 where c1=:b_c1", }, }, }, }, { - // func expr + // partial group by input: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "t1", - Filter: "select hour(c1) as hc1, day(c2) as dc2 from t2", + Filter: "select c1, c2, c3 from t2 group by c3, c1", }}, }, - plan: &PlayerPlan{ + plan: &TestPlayerPlan{ VStreamFilter: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "t2", - Filter: "select hour(c1) as hc1, day(c2) as dc2 from t2", + Filter: "select c1, c2, c3 from t2", }}, }, - TablePlans: map[string]*TablePlan{ + TablePlans: map[string]*TestTablePlan{ "t2": { - Name: "t1", - ColExprs: []*ColExpr{{ - ColName: sqlparser.NewColIdent("hc1"), - ColNum: 0, - }, { - ColName: sqlparser.NewColIdent("dc2"), - ColNum: 1, - }}, + Name: "t1", + PKReferences: []string{"c1"}, + Insert: "insert into t1 set c1=:a_c1, c2=:a_c2, c3=:a_c3 on duplicate key update c2=:a_c2", + Update: "update t1 set c2=:a_c2 where c1=:b_c1", + Delete: "update t1 set c2=null where c1=:b_c1", }, }, }, }, { - // count expr + // full group by input: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "t1", - Filter: "select hour(c1) as hc1, count(*) as c, day(c2) as dc2 from t2", + Filter: "select c1, c2, c3 from t2 group by c3, c1, c2", }}, }, - plan: &PlayerPlan{ + plan: &TestPlayerPlan{ VStreamFilter: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "t2", - Filter: "select hour(c1) as hc1, day(c2) as dc2 from t2", + Filter: "select c1, c2, c3 from t2", }}, }, - TablePlans: map[string]*TablePlan{ + TablePlans: map[string]*TestTablePlan{ "t2": { - Name: "t1", - ColExprs: []*ColExpr{{ - ColName: sqlparser.NewColIdent("hc1"), - ColNum: 0, - }, { - ColName: sqlparser.NewColIdent("c"), - Operation: OpCount, - }, { - ColName: sqlparser.NewColIdent("dc2"), - ColNum: 1, - }}, + Name: "t1", + PKReferences: []string{"c1"}, + Insert: "insert ignore into t1 set c1=:a_c1, c2=:a_c2, c3=:a_c3", + Update: "insert ignore into t1 set c1=:a_c1, c2=:a_c2, c3=:a_c3", }, }, }, }, { - // sum expr input: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "t1", - Filter: "select hour(c1) as hc1, sum(c3) as s, day(c2) as dc2 from t2", + Filter: "select foo(a) as c1, b c2 from t1", }}, }, - plan: &PlayerPlan{ + plan: &TestPlayerPlan{ VStreamFilter: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ - Match: "t2", - Filter: "select hour(c1) as hc1, c3, day(c2) as dc2 from t2", + Match: "t1", + Filter: "select a, b from t1", }}, }, - TablePlans: map[string]*TablePlan{ - "t2": { - Name: "t1", - ColExprs: []*ColExpr{{ - ColName: sqlparser.NewColIdent("hc1"), - ColNum: 0, - }, { - ColName: sqlparser.NewColIdent("s"), - ColNum: 1, - Operation: OpSum, - }, { - ColName: sqlparser.NewColIdent("dc2"), - ColNum: 2, - }}, + TablePlans: map[string]*TestTablePlan{ + "t1": { + Name: "t1", + PKReferences: []string{"a"}, + Insert: "insert into t1 set c1=foo(:a_a), c2=:a_b", + Update: "update t1 set c2=:a_b where c1=(foo(:b_a))", + Delete: "delete from t1 where c1=(foo(:b_a))", }, }, }, }, { - // partial group by input: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ Match: "t1", - Filter: "select c1, c2, c3 from t2 group by c3, c1", + Filter: "select a + b as c1, c as c2 from t1", }}, }, - plan: &PlayerPlan{ + plan: &TestPlayerPlan{ VStreamFilter: &binlogdatapb.Filter{ Rules: []*binlogdatapb.Rule{{ - Match: "t2", - Filter: "select c1, c2, c3 from t2", + Match: "t1", + Filter: "select a, b, c from t1", }}, }, - TablePlans: map[string]*TablePlan{ - "t2": { - Name: "t1", - ColExprs: []*ColExpr{{ - ColName: sqlparser.NewColIdent("c1"), - ColNum: 0, - IsGrouped: true, - }, { - ColName: sqlparser.NewColIdent("c2"), - ColNum: 1, - }, { - ColName: sqlparser.NewColIdent("c3"), - ColNum: 2, - IsGrouped: true, - }}, - OnInsert: InsertOndup, - }, - }, - }, - }, { - // full group by - input: &binlogdatapb.Filter{ - Rules: []*binlogdatapb.Rule{{ - Match: "t1", - Filter: "select c1, c2, c3 from t2 group by c3, c1, c2", - }}, - }, - plan: &PlayerPlan{ - VStreamFilter: &binlogdatapb.Filter{ - Rules: []*binlogdatapb.Rule{{ - Match: "t2", - Filter: "select c1, c2, c3 from t2", - }}, - }, - TablePlans: map[string]*TablePlan{ - "t2": { - Name: "t1", - ColExprs: []*ColExpr{{ - ColName: sqlparser.NewColIdent("c1"), - ColNum: 0, - IsGrouped: true, - }, { - ColName: sqlparser.NewColIdent("c2"), - ColNum: 1, - IsGrouped: true, - }, { - ColName: sqlparser.NewColIdent("c3"), - ColNum: 2, - IsGrouped: true, - }}, - OnInsert: InsertIgnore, + TablePlans: map[string]*TestTablePlan{ + "t1": { + Name: "t1", + PKReferences: []string{"a", "b"}, + Insert: "insert into t1 set c1=:a_a + :a_b, c2=:a_c", + Update: "update t1 set c2=:a_c where c1=(:b_a + :b_b)", + Delete: "delete from t1 where c1=(:b_a + :b_b)", }, }, }, @@ -370,24 +316,6 @@ func TestPlayerPlan(t *testing.T) { }}, }, err: "unexpected: sum(a + b)", - }, { - // unsupported func - input: &binlogdatapb.Filter{ - Rules: []*binlogdatapb.Rule{{ - Match: "t1", - Filter: "select foo(a) as c from t1", - }}, - }, - err: "unexpected: foo(a)", - }, { - // no complex expr in select - input: &binlogdatapb.Filter{ - Rules: []*binlogdatapb.Rule{{ - Match: "t1", - Filter: "select a + b from t1", - }}, - }, - err: "unexpected: a + b", }, { // no complex expr in group by input: &binlogdatapb.Filter{ @@ -417,8 +345,12 @@ func TestPlayerPlan(t *testing.T) { err: "group by expression is not allowed to reference an aggregate expression: a", }} + tableKeys := map[string][]string{ + "t1": {"c1"}, + } + for _, tcase := range testcases { - plan, err := buildPlayerPlan(tcase.input) + plan, err := buildPlayerPlan(tcase.input, tableKeys) gotPlan, _ := json.Marshal(plan) wantPlan, _ := json.Marshal(tcase.plan) if string(gotPlan) != string(wantPlan) { diff --git a/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go b/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go new file mode 100644 index 00000000000..4f6464cde9c --- /dev/null +++ b/go/vt/vttablet/tabletmanager/vreplication/table_plan_builder.go @@ -0,0 +1,498 @@ +/* +Copyright 2019 The Vitess 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 vreplication + +import ( + "fmt" + "sort" + "strings" + + "vitess.io/vitess/go/vt/sqlparser" + + binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" + querypb "vitess.io/vitess/go/vt/proto/query" +) + +type tablePlanBuilder struct { + name sqlparser.TableIdent + sendSelect *sqlparser.Select + selColumns map[string]bool + colExprs []*colExpr + onInsert insertType + pkCols []*colExpr +} + +// colExpr describes the processing to be performed to +// compute the value of the target table column. +type colExpr struct { + colName sqlparser.ColIdent + // operation==opExpr: full expression is set + // operation==opCount: nothing is set. + // operation==opSum: for 'sum(a)', expr is set to 'a'. + operation operation + expr sqlparser.Expr + // references contains all the column names referenced in the expression. + references map[string]bool + + isGrouped bool + isPK bool +} + +// operation is the opcode for the colExpr. +type operation int + +// The following values are the various colExpr opcodes. +const ( + opExpr = operation(iota) + opCount + opSum +) + +// insertType describes the type of insert statement to generate. +type insertType int + +// The following values are the various insert types. +const ( + insertNormal = insertType(iota) + insertOndup + insertIgnore +) + +func buildPlayerPlan(filter *binlogdatapb.Filter, tableKeys map[string][]string) (*PlayerPlan, error) { + plan := &PlayerPlan{ + VStreamFilter: &binlogdatapb.Filter{ + Rules: make([]*binlogdatapb.Rule, len(filter.Rules)), + }, + TablePlans: make(map[string]*TablePlan), + } + for i, rule := range filter.Rules { + if strings.HasPrefix(rule.Match, "/") { + plan.VStreamFilter.Rules[i] = rule + continue + } + sendRule, tablePlan, err := buildTablePlan(rule, tableKeys) + if err != nil { + return nil, err + } + plan.VStreamFilter.Rules[i] = sendRule + plan.TablePlans[sendRule.Match] = tablePlan + } + return plan, nil +} + +func buildTablePlan(rule *binlogdatapb.Rule, tableKeys map[string][]string) (*binlogdatapb.Rule, *TablePlan, error) { + sel, fromTable, err := analyzeSelectFrom(rule.Filter) + if err != nil { + return nil, nil, err + } + sendRule := &binlogdatapb.Rule{ + Match: fromTable, + } + + if expr, ok := sel.SelectExprs[0].(*sqlparser.StarExpr); ok { + if len(sel.SelectExprs) != 1 { + return nil, nil, fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + } + if !expr.TableName.IsEmpty() { + return nil, nil, fmt.Errorf("unsupported qualifier for '*' expression: %v", sqlparser.String(expr)) + } + sendRule.Filter = rule.Filter + return sendRule, &TablePlan{Name: rule.Match}, nil + } + + tpb := &tablePlanBuilder{ + name: sqlparser.NewTableIdent(rule.Match), + sendSelect: &sqlparser.Select{ + From: sel.From, + Where: sel.Where, + }, + selColumns: make(map[string]bool), + } + + if err := tpb.analyzeExprs(sel.SelectExprs); err != nil { + return nil, nil, err + } + if err := tpb.analyzeGroupBy(sel.GroupBy); err != nil { + return nil, nil, err + } + if err := tpb.analyzePK(tableKeys); err != nil { + return nil, nil, err + } + + sendRule.Filter = sqlparser.String(tpb.sendSelect) + tablePlan := tpb.generate(tableKeys) + return sendRule, tablePlan, nil +} + +func buildTablePlanFromFields(tableName string, fields []*querypb.Field, tableKeys map[string][]string) (*TablePlan, error) { + tpb := &tablePlanBuilder{ + name: sqlparser.NewTableIdent(tableName), + } + for _, field := range fields { + colName := sqlparser.NewColIdent(field.Name) + cexpr := &colExpr{ + colName: colName, + expr: &sqlparser.ColName{ + Name: colName, + }, + references: map[string]bool{ + field.Name: true, + }, + } + tpb.colExprs = append(tpb.colExprs, cexpr) + } + if err := tpb.analyzePK(tableKeys); err != nil { + return nil, err + } + return tpb.generate(tableKeys), nil +} + +func (tpb *tablePlanBuilder) generate(tableKeys map[string][]string) *TablePlan { + refmap := make(map[string]bool) + for _, cexpr := range tpb.pkCols { + for k := range cexpr.references { + refmap[k] = true + } + } + pkrefs := make([]string, 0, len(refmap)) + for k := range refmap { + pkrefs = append(pkrefs, k) + } + sort.Strings(pkrefs) + return &TablePlan{ + Name: tpb.name.String(), + PKReferences: pkrefs, + Insert: tpb.generateInsertStatement(), + Update: tpb.generateUpdateStatement(), + Delete: tpb.generateDeleteStatement(), + } +} + +func analyzeSelectFrom(query string) (sel *sqlparser.Select, from string, err error) { + statement, err := sqlparser.Parse(query) + if err != nil { + return nil, "", err + } + sel, ok := statement.(*sqlparser.Select) + if !ok { + return nil, "", fmt.Errorf("unexpected: %v", sqlparser.String(statement)) + } + if sel.Distinct != "" { + return nil, "", fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + } + if len(sel.From) > 1 { + return nil, "", fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + } + node, ok := sel.From[0].(*sqlparser.AliasedTableExpr) + if !ok { + return nil, "", fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + } + fromTable := sqlparser.GetTableName(node.Expr) + if fromTable.IsEmpty() { + return nil, "", fmt.Errorf("unexpected: %v", sqlparser.String(sel)) + } + return sel, fromTable.String(), nil +} + +func (tpb *tablePlanBuilder) analyzeExprs(selExprs sqlparser.SelectExprs) error { + for _, selExpr := range selExprs { + cexpr, err := tpb.analyzeExpr(selExpr) + if err != nil { + return err + } + tpb.colExprs = append(tpb.colExprs, cexpr) + } + return nil +} + +func (tpb *tablePlanBuilder) analyzeExpr(selExpr sqlparser.SelectExpr) (*colExpr, error) { + aliased, ok := selExpr.(*sqlparser.AliasedExpr) + if !ok { + return nil, fmt.Errorf("unexpected: %v", sqlparser.String(selExpr)) + } + as := aliased.As + if as.IsEmpty() { + as = sqlparser.NewColIdent(sqlparser.String(aliased.Expr)) + } + cexpr := &colExpr{ + colName: as, + references: make(map[string]bool), + } + if expr, ok := aliased.Expr.(*sqlparser.FuncExpr); ok { + if expr.Distinct || len(expr.Exprs) != 1 { + return nil, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) + } + if aliased.As.IsEmpty() { + return nil, fmt.Errorf("expression needs an alias: %v", sqlparser.String(expr)) + } + switch fname := expr.Name.Lowered(); fname { + case "count": + if _, ok := expr.Exprs[0].(*sqlparser.StarExpr); !ok { + return nil, fmt.Errorf("only count(*) is supported: %v", sqlparser.String(expr)) + } + cexpr.operation = opCount + return cexpr, nil + case "sum": + aInner, ok := expr.Exprs[0].(*sqlparser.AliasedExpr) + if !ok { + return nil, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) + } + innerCol, ok := aInner.Expr.(*sqlparser.ColName) + if !ok { + return nil, fmt.Errorf("unexpected: %v", sqlparser.String(expr)) + } + if !innerCol.Qualifier.IsEmpty() { + return nil, fmt.Errorf("unsupported qualifier for column: %v", sqlparser.String(innerCol)) + } + cexpr.operation = opSum + cexpr.expr = innerCol + tpb.addCol(innerCol.Name) + cexpr.references[innerCol.Name.Lowered()] = true + return cexpr, nil + } + } + err := sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { + switch node := node.(type) { + case *sqlparser.ColName: + if !node.Qualifier.IsEmpty() { + return false, fmt.Errorf("unsupported qualifier for column: %v", sqlparser.String(node)) + } + tpb.addCol(node.Name) + cexpr.references[node.Name.Lowered()] = true + case *sqlparser.Subquery: + return false, fmt.Errorf("unsupported subquery: %v", sqlparser.String(node)) + case *sqlparser.FuncExpr: + if node.IsAggregate() { + return false, fmt.Errorf("unexpected: %v", sqlparser.String(node)) + } + } + return true, nil + }, aliased.Expr) + if err != nil { + return nil, err + } + cexpr.expr = aliased.Expr + return cexpr, nil +} + +func (tpb *tablePlanBuilder) addCol(ident sqlparser.ColIdent) { + if tpb.selColumns[ident.Lowered()] { + return + } + tpb.selColumns[ident.Lowered()] = true + tpb.sendSelect.SelectExprs = append(tpb.sendSelect.SelectExprs, &sqlparser.AliasedExpr{ + Expr: &sqlparser.ColName{Name: ident}, + }) +} + +func (tpb *tablePlanBuilder) analyzeGroupBy(groupBy sqlparser.GroupBy) error { + if groupBy == nil { + return nil + } + for _, expr := range groupBy { + colname, ok := expr.(*sqlparser.ColName) + if !ok { + return fmt.Errorf("unexpected: %v", sqlparser.String(expr)) + } + cexpr := tpb.findCol(colname.Name) + if cexpr == nil { + return fmt.Errorf("group by expression does not reference an alias in the select list: %v", sqlparser.String(expr)) + } + if cexpr.operation != opExpr { + return fmt.Errorf("group by expression is not allowed to reference an aggregate expression: %v", sqlparser.String(expr)) + } + cexpr.isGrouped = true + } + tpb.onInsert = insertIgnore + for _, cExpr := range tpb.colExprs { + if !cExpr.isGrouped { + tpb.onInsert = insertOndup + break + } + } + return nil +} + +func (tpb *tablePlanBuilder) analyzePK(tableKeys map[string][]string) error { + pkcols, ok := tableKeys[tpb.name.String()] + if !ok { + return fmt.Errorf("table %s not found in schema", tpb.name) + } + for _, pkcol := range pkcols { + cexpr := tpb.findCol(sqlparser.NewColIdent(pkcol)) + if cexpr == nil { + return fmt.Errorf("primary key column %s not found in select list", pkcol) + } + if cexpr.operation != opExpr { + return fmt.Errorf("primary key column %s is not allowed to reference an aggregate expression", pkcol) + } + cexpr.isPK = true + tpb.pkCols = append(tpb.pkCols, cexpr) + } + return nil +} + +func (tpb *tablePlanBuilder) findCol(name sqlparser.ColIdent) *colExpr { + for _, cexpr := range tpb.colExprs { + if cexpr.colName.Equal(name) { + return cexpr + } + } + return nil +} + +func (tpb *tablePlanBuilder) generateInsertStatement() *sqlparser.ParsedQuery { + bvf := &bindvarFormatter{} + buf := sqlparser.NewTrackedBuffer(bvf.formatter) + if tpb.onInsert == insertIgnore { + buf.Myprintf("insert ignore into %v set ", tpb.name) + } else { + buf.Myprintf("insert into %v set ", tpb.name) + } + tpb.generateInsertValues(buf, bvf) + if tpb.onInsert == insertOndup { + buf.Myprintf(" on duplicate key update ") + tpb.generateUpdate(buf, bvf, false /* before */, true /* after */) + } + return buf.ParsedQuery() +} + +func (tpb *tablePlanBuilder) generateUpdateStatement() *sqlparser.ParsedQuery { + if tpb.onInsert == insertIgnore { + return tpb.generateInsertStatement() + } + bvf := &bindvarFormatter{} + buf := sqlparser.NewTrackedBuffer(bvf.formatter) + buf.Myprintf("update %v set ", tpb.name) + tpb.generateUpdate(buf, bvf, true /* before */, true /* after */) + tpb.generateWhere(buf, bvf) + return buf.ParsedQuery() +} + +func (tpb *tablePlanBuilder) generateDeleteStatement() *sqlparser.ParsedQuery { + bvf := &bindvarFormatter{} + buf := sqlparser.NewTrackedBuffer(bvf.formatter) + switch tpb.onInsert { + case insertNormal: + buf.Myprintf("delete from %v", tpb.name) + tpb.generateWhere(buf, bvf) + case insertOndup: + buf.Myprintf("update %v set ", tpb.name) + tpb.generateUpdate(buf, bvf, true /* before */, false /* after */) + tpb.generateWhere(buf, bvf) + case insertIgnore: + return nil + } + return buf.ParsedQuery() +} + +func (tpb *tablePlanBuilder) generateInsertValues(buf *sqlparser.TrackedBuffer, bvf *bindvarFormatter) { + bvf.mode = bvAfter + separator := "" + for _, cexpr := range tpb.colExprs { + buf.Myprintf("%s%s=", separator, cexpr.colName.String()) + separator = ", " + switch cexpr.operation { + case opExpr: + buf.Myprintf("%v", cexpr.expr) + case opCount: + buf.WriteString("1") + case opSum: + buf.Myprintf("ifnull(%v, 0)", cexpr.expr) + } + } +} + +func (tpb *tablePlanBuilder) generateUpdate(buf *sqlparser.TrackedBuffer, bvf *bindvarFormatter, before, after bool) { + separator := "" + for _, cexpr := range tpb.colExprs { + if cexpr.isGrouped || cexpr.isPK { + continue + } + buf.Myprintf("%s%s=", separator, cexpr.colName.String()) + separator = ", " + switch cexpr.operation { + case opExpr: + if after { + bvf.mode = bvAfter + buf.Myprintf("%v", cexpr.expr) + } else { + buf.WriteString("null") + } + case opCount: + switch { + case before && after: + buf.Myprintf("%s", cexpr.colName.String()) + case before: + buf.Myprintf("%s-1", cexpr.colName.String()) + case after: + buf.Myprintf("%s+1", cexpr.colName.String()) + } + case opSum: + buf.Myprintf("%s", cexpr.colName.String()) + if before { + bvf.mode = bvBefore + buf.Myprintf("-ifnull(%v, 0)", cexpr.expr) + } + if after { + bvf.mode = bvAfter + buf.Myprintf("+ifnull(%v, 0)", cexpr.expr) + } + } + } +} + +func (tpb *tablePlanBuilder) generateWhere(buf *sqlparser.TrackedBuffer, bvf *bindvarFormatter) { + buf.WriteString(" where ") + bvf.mode = bvBefore + separator := "" + for _, cexpr := range tpb.pkCols { + if _, ok := cexpr.expr.(*sqlparser.ColName); ok { + buf.Myprintf("%s%s=%v", separator, cexpr.colName.String(), cexpr.expr) + } else { + // Parenthesize non-trivial expressions. + buf.Myprintf("%s%s=(%v)", separator, cexpr.colName.String(), cexpr.expr) + } + separator = " and " + } +} + +type bindvarFormatter struct { + mode bindvarMode +} + +type bindvarMode int + +const ( + bvNone = bindvarMode(iota) + bvBefore + bvAfter +) + +func (bvf *bindvarFormatter) formatter(buf *sqlparser.TrackedBuffer, node sqlparser.SQLNode) { + if node, ok := node.(*sqlparser.ColName); ok { + switch bvf.mode { + case bvBefore: + buf.WriteArg(fmt.Sprintf(":b_%s", node.Name.String())) + return + case bvAfter: + buf.WriteArg(fmt.Sprintf(":a_%s", node.Name.String())) + return + } + } + node.Format(buf) +} diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go index 5bf9bcafd81..b1344c6ae75 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer.go @@ -25,12 +25,10 @@ import ( "golang.org/x/net/context" "vitess.io/vitess/go/mysql" - "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/binlog/binlogplayer" "vitess.io/vitess/go/vt/grpcclient" "vitess.io/vitess/go/vt/log" "vitess.io/vitess/go/vt/mysqlctl" - "vitess.io/vitess/go/vt/sqlparser" "vitess.io/vitess/go/vt/vttablet/tabletconn" binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" @@ -70,6 +68,8 @@ type vplayer struct { timeOffsetNs int64 stopPos mysql.Position + tableKeys map[string][]string + // pplan is built based on the source Filter at the beginning. pplan *PlayerPlan // tplans[table] is built for each table based on pplan and schema info @@ -130,7 +130,12 @@ func (vp *vplayer) play(ctx context.Context) error { } log.Infof("Starting VReplication player id: %v, startPos: %v, stop: %v, source: %v, filter: %v", vp.id, startPos, vp.stopPos, vp.sourceTablet, vp.source) - plan, err := buildPlayerPlan(vp.source.Filter) + tableKeys, err := vp.buildTableKeys() + if err != nil { + return err + } + vp.tableKeys = tableKeys + plan, err := buildPlayerPlan(vp.source.Filter, tableKeys) if err != nil { return err } @@ -198,6 +203,22 @@ func (vp *vplayer) play(ctx context.Context) error { } } +func (vp *vplayer) buildTableKeys() (map[string][]string, error) { + schema, err := vp.mysqld.GetSchema(vp.dbClient.DBName(), []string{"/.*/"}, nil, false) + if err != nil { + return nil, err + } + tableKeys := make(map[string][]string) + for _, td := range schema.TableDefinitions { + if len(td.PrimaryKeyColumns) != 0 { + tableKeys[td.Name] = td.PrimaryKeyColumns + } else { + tableKeys[td.Name] = td.Columns + } + } + return tableKeys, nil +} + func (vp *vplayer) applyEvents(ctx context.Context, relay *relayLog) error { for { items, err := relay.Fetch() @@ -384,58 +405,21 @@ func (vp *vplayer) setState(state, message string) error { func (vp *vplayer) updatePlan(fieldEvent *binlogdatapb.FieldEvent) error { prelim := vp.pplan.TablePlans[fieldEvent.TableName] - tplan := &TablePlan{ - Name: fieldEvent.TableName, - } - if prelim != nil { - *tplan = *prelim - } - tplan.Fields = fieldEvent.Fields - - if tplan.ColExprs == nil { - tplan.ColExprs = make([]*ColExpr, len(tplan.Fields)) - for i, field := range tplan.Fields { - tplan.ColExprs[i] = &ColExpr{ - ColName: sqlparser.NewColIdent(field.Name), - ColNum: i, - } - } - } else { - for _, cExpr := range tplan.ColExprs { - if cExpr.ColNum >= len(tplan.Fields) { - // Unreachable code. - return fmt.Errorf("columns received from vreplication: %v, do not match expected: %v", tplan.Fields, tplan.ColExprs) - } + if prelim == nil { + prelim = &TablePlan{ + Name: fieldEvent.TableName, } } - - pkcols, err := vp.mysqld.GetPrimaryKeyColumns(vp.dbClient.DBName(), tplan.Name) - if err != nil { - return fmt.Errorf("error fetching pk columns for %s: %v", tplan.Name, err) - } - if len(pkcols) == 0 { - // If the table doesn't have a PK, then we treat all columns as PK. - pkcols, err = vp.mysqld.GetColumns(vp.dbClient.DBName(), tplan.Name) - if err != nil { - return fmt.Errorf("error fetching pk columns for %s: %v", tplan.Name, err) - } + if prelim.Insert != nil { + prelim.Fields = fieldEvent.Fields + vp.tplans[fieldEvent.TableName] = prelim + return nil } - for _, pkcol := range pkcols { - found := false - for i, cExpr := range tplan.ColExprs { - if cExpr.ColName.EqualString(pkcol) { - found = true - tplan.PKCols = append(tplan.PKCols, &ColExpr{ - ColName: cExpr.ColName, - ColNum: i, - }) - break - } - } - if !found { - return fmt.Errorf("primary key column %s missing from select list for table %s", pkcol, tplan.Name) - } + tplan, err := buildTablePlanFromFields(prelim.Name, fieldEvent.Fields, vp.tableKeys) + if err != nil { + return err } + tplan.Fields = fieldEvent.Fields vp.tplans[fieldEvent.TableName] = tplan return nil } @@ -446,7 +430,11 @@ func (vp *vplayer) applyRowEvent(ctx context.Context, rowEvent *binlogdatapb.Row return fmt.Errorf("unexpected event on table %s", rowEvent.TableName) } for _, change := range rowEvent.RowChanges { - for _, query := range tplan.GenerateStatements(change) { + queries, err := tplan.generateStatements(change) + if err != nil { + return err + } + for _, query := range queries { if err := vp.exec(ctx, query); err != nil { return err } @@ -490,13 +478,3 @@ func (vp *vplayer) exec(ctx context.Context, sql string) error { } return nil } - -func encodeValue(sql *sqlparser.TrackedBuffer, value sqltypes.Value) { - // This is currently a separate function because special handling - // may be needed for certain types. - // Previously, this function used to convert timestamp to the session - // time zone, but we now set the session timezone to UTC. So, the timestamp - // value we receive as UTC can be sent as is. - // TODO(sougou): handle BIT data type here? - value.EncodeSQL(sql) -} diff --git a/go/vt/vttablet/tabletmanager/vreplication/vplayer_test.go b/go/vt/vttablet/tabletmanager/vreplication/vplayer_test.go index 3af90ad45f4..228dba7207f 100644 --- a/go/vt/vttablet/tabletmanager/vreplication/vplayer_test.go +++ b/go/vt/vttablet/tabletmanager/vreplication/vplayer_test.go @@ -129,7 +129,7 @@ func TestPlayerFilters(t *testing.T) { input: "insert into src2 values(1, 2, 3)", output: []string{ "begin", - "insert into dst2 set id=1, val1=2, sval2=3, rcount=1 on duplicate key update val1=2, sval2=sval2+3, rcount=rcount+1", + "insert into dst2 set id=1, val1=2, sval2=ifnull(3, 0), rcount=1 on duplicate key update val1=2, sval2=sval2+ifnull(3, 0), rcount=rcount+1", "/update _vt.vreplication set pos=", "commit", }, @@ -142,7 +142,7 @@ func TestPlayerFilters(t *testing.T) { input: "update src2 set val1=5, val2=1 where id=1", output: []string{ "begin", - "update dst2 set val1=5, sval2=sval2-3+1 where id=1", + "update dst2 set val1=5, sval2=sval2-ifnull(3, 0)+ifnull(1, 0), rcount=rcount where id=1", "/update _vt.vreplication set pos=", "commit", }, @@ -155,7 +155,7 @@ func TestPlayerFilters(t *testing.T) { input: "delete from src2 where id=1", output: []string{ "begin", - "update dst2 set val1=NULL, sval2=sval2-1, rcount=rcount-1 where id=1", + "update dst2 set val1=null, sval2=sval2-ifnull(1, 0), rcount=rcount-1 where id=1", "/update _vt.vreplication set pos=", "commit", }, @@ -310,7 +310,7 @@ func TestPlayerUpdates(t *testing.T) { }{{ // Start with all nulls input: "insert into t1 values(1, null, null, null)", - output: "insert into t1 set id=1, grouped=null, ungrouped=null, summed=0, rcount=1 on duplicate key update ungrouped=null, summed=summed, rcount=rcount+1", + output: "insert into t1 set id=1, grouped=null, ungrouped=null, summed=ifnull(null, 0), rcount=1 on duplicate key update ungrouped=null, summed=summed+ifnull(null, 0), rcount=rcount+1", table: "t1", data: [][]string{ {"1", "", "", "0", "1"}, @@ -318,7 +318,7 @@ func TestPlayerUpdates(t *testing.T) { }, { // null to null values input: "update t1 set grouped=1 where id=1", - output: "", + output: "update t1 set ungrouped=null, summed=summed-ifnull(null, 0)+ifnull(null, 0), rcount=rcount where id=1", table: "t1", data: [][]string{ {"1", "", "", "0", "1"}, @@ -326,7 +326,7 @@ func TestPlayerUpdates(t *testing.T) { }, { // null to non-null values input: "update t1 set ungrouped=1, summed=1 where id=1", - output: "update t1 set ungrouped=1, summed=summed+1 where id=1", + output: "update t1 set ungrouped=1, summed=summed-ifnull(null, 0)+ifnull(1, 0), rcount=rcount where id=1", table: "t1", data: [][]string{ {"1", "", "1", "1", "1"}, @@ -334,7 +334,7 @@ func TestPlayerUpdates(t *testing.T) { }, { // non-null to non-null values input: "update t1 set ungrouped=2, summed=2 where id=1", - output: "update t1 set ungrouped=2, summed=summed-1+2 where id=1", + output: "update t1 set ungrouped=2, summed=summed-ifnull(1, 0)+ifnull(2, 0), rcount=rcount where id=1", table: "t1", data: [][]string{ {"1", "", "2", "2", "1"}, @@ -342,7 +342,7 @@ func TestPlayerUpdates(t *testing.T) { }, { // non-null to null values input: "update t1 set ungrouped=null, summed=null where id=1", - output: "update t1 set ungrouped=null, summed=summed-2 where id=1", + output: "update t1 set ungrouped=null, summed=summed-ifnull(2, 0)+ifnull(null, 0), rcount=rcount where id=1", table: "t1", data: [][]string{ {"1", "", "", "0", "1"}, @@ -350,7 +350,7 @@ func TestPlayerUpdates(t *testing.T) { }, { // insert non-null values input: "insert into t1 values(2, 2, 3, 4)", - output: "insert into t1 set id=2, grouped=2, ungrouped=3, summed=4, rcount=1 on duplicate key update ungrouped=3, summed=summed+4, rcount=rcount+1", + output: "insert into t1 set id=2, grouped=2, ungrouped=3, summed=ifnull(4, 0), rcount=1 on duplicate key update ungrouped=3, summed=summed+ifnull(4, 0), rcount=rcount+1", table: "t1", data: [][]string{ {"1", "", "", "0", "1"}, @@ -359,7 +359,7 @@ func TestPlayerUpdates(t *testing.T) { }, { // delete non-null values input: "delete from t1 where id=2", - output: "update t1 set ungrouped=NULL, summed=summed-4, rcount=rcount-1 where id=2", + output: "update t1 set ungrouped=null, summed=summed-ifnull(4, 0), rcount=rcount-1 where id=2", table: "t1", data: [][]string{ {"1", "", "", "0", "1"}, @@ -416,9 +416,9 @@ func TestPlayerRowMove(t *testing.T) { }) expectDBClientQueries(t, []string{ "begin", - "insert into dst set val1=1, sval2=1, rcount=1 on duplicate key update sval2=sval2+1, rcount=rcount+1", - "insert into dst set val1=2, sval2=2, rcount=1 on duplicate key update sval2=sval2+2, rcount=rcount+1", - "insert into dst set val1=2, sval2=3, rcount=1 on duplicate key update sval2=sval2+3, rcount=rcount+1", + "insert into dst set val1=1, sval2=ifnull(1, 0), rcount=1 on duplicate key update sval2=sval2+ifnull(1, 0), rcount=rcount+1", + "insert into dst set val1=2, sval2=ifnull(2, 0), rcount=1 on duplicate key update sval2=sval2+ifnull(2, 0), rcount=rcount+1", + "insert into dst set val1=2, sval2=ifnull(3, 0), rcount=1 on duplicate key update sval2=sval2+ifnull(3, 0), rcount=rcount+1", "/update _vt.vreplication set pos=", "commit", }) @@ -432,8 +432,8 @@ func TestPlayerRowMove(t *testing.T) { }) expectDBClientQueries(t, []string{ "begin", - "update dst set sval2=sval2-3, rcount=rcount-1 where val1=2", - "insert into dst set val1=1, sval2=4, rcount=1 on duplicate key update sval2=sval2+4, rcount=rcount+1", + "update dst set sval2=sval2-ifnull(3, 0), rcount=rcount-1 where val1=2", + "insert into dst set val1=1, sval2=ifnull(4, 0), rcount=1 on duplicate key update sval2=sval2+ifnull(4, 0), rcount=rcount+1", "/update _vt.vreplication set pos=", "commit", }) From e32cc4df4127e6e05a6e12499c8ebd623d80349b Mon Sep 17 00:00:00 2001 From: Danny Wensley Date: Sat, 16 Mar 2019 21:54:59 +0000 Subject: [PATCH 189/196] Fix go panic caused by unaligned atomic fields on certain architectures. Signed-off-by: Danny Wensley --- go/pools/resource_pool.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/go/pools/resource_pool.go b/go/pools/resource_pool.go index 60717b3ec61..9adc2034ca0 100644 --- a/go/pools/resource_pool.go +++ b/go/pools/resource_pool.go @@ -48,19 +48,20 @@ type Resource interface { // ResourcePool allows you to use a pool of resources. type ResourcePool struct { - resources chan resourceWrapper - factory Factory - capacity sync2.AtomicInt64 - idleTimeout sync2.AtomicDuration - idleTimer *timer.Timer - - // stats + // stats. Atomic fields must remain at the top in order to prevent panics on certain architectures. available sync2.AtomicInt64 active sync2.AtomicInt64 inUse sync2.AtomicInt64 waitCount sync2.AtomicInt64 waitTime sync2.AtomicDuration idleClosed sync2.AtomicInt64 + + capacity sync2.AtomicInt64 + idleTimeout sync2.AtomicDuration + + resources chan resourceWrapper + factory Factory + idleTimer *timer.Timer } type resourceWrapper struct { From 5ff205ff8ea4027d3d1494b5d7525b0f604fe247 Mon Sep 17 00:00:00 2001 From: David Weitzman Date: Mon, 18 Mar 2019 12:03:35 -0700 Subject: [PATCH 190/196] vtgate executor: route "show create table" to the user-provided or vschema-indicated keyspace Previously the sql parser treated everything after `CREATE TABLE` as opaque. This change updates the sql parser to look at the create table argument to help direct queries to the appropriate keyspace. Signed-off-by: David Weitzman --- go/vt/sqlparser/ast.go | 10 + go/vt/sqlparser/parse_test.go | 2 +- go/vt/sqlparser/sql.go | 1812 ++++++++++++++++----------------- go/vt/sqlparser/sql.y | 4 +- go/vt/vtgate/executor.go | 19 + go/vt/vtgate/executor_test.go | 28 + 6 files changed, 962 insertions(+), 913 deletions(-) diff --git a/go/vt/sqlparser/ast.go b/go/vt/sqlparser/ast.go index 631e26ec499..fc7c4b45e8d 100644 --- a/go/vt/sqlparser/ast.go +++ b/go/vt/sqlparser/ast.go @@ -1517,6 +1517,7 @@ func (f *ForeignKeyDefinition) walkSubtree(visit Visit) error { type Show struct { Type string OnTable TableName + Table TableName ShowTablesOpt *ShowTablesOpt Scope string ShowCollationFilterOpt *Expr @@ -1547,6 +1548,9 @@ func (node *Show) Format(buf *TrackedBuffer) { if node.Type == "collation" && node.ShowCollationFilterOpt != nil { buf.Myprintf(" where %v", *node.ShowCollationFilterOpt) } + if node.HasTable() { + buf.Myprintf(" %v", node.Table) + } } // HasOnTable returns true if the show statement has an "on" clause @@ -1554,6 +1558,12 @@ func (node *Show) HasOnTable() bool { return node.OnTable.Name.v != "" } +// HasTable returns true if the show statement has a parsed table name. +// Not all show statements parse table names. +func (node *Show) HasTable() bool { + return node.Table.Name.v != "" +} + func (node *Show) walkSubtree(visit Visit) error { return nil } diff --git a/go/vt/sqlparser/parse_test.go b/go/vt/sqlparser/parse_test.go index fc1c98008b6..4ba5574c629 100644 --- a/go/vt/sqlparser/parse_test.go +++ b/go/vt/sqlparser/parse_test.go @@ -1107,7 +1107,7 @@ var ( output: "show create procedure", }, { input: "show create table t", - output: "show create table", + output: "show create table t", }, { input: "show create trigger t", output: "show create trigger", diff --git a/go/vt/sqlparser/sql.go b/go/vt/sqlparser/sql.go index 446f7e38514..65cb1ea8f66 100644 --- a/go/vt/sqlparser/sql.go +++ b/go/vt/sqlparser/sql.go @@ -711,424 +711,311 @@ var yyExca = [...]int{ const yyPrivate = 57344 -const yyLast = 12766 +const yyLast = 12688 var yyAct = [...]int{ - 269, 1432, 1386, 567, 1101, 1012, 1216, 273, 1422, 863, - 1329, 1294, 1156, 1030, 1190, 1013, 286, 247, 840, 1153, - 892, 299, 1157, 906, 1281, 838, 942, 862, 872, 57, - 566, 3, 81, 1036, 1169, 1163, 209, 1124, 339, 209, - 791, 859, 238, 781, 1055, 788, 721, 969, 1072, 842, - 1081, 876, 809, 827, 624, 758, 607, 499, 505, 790, - 902, 623, 333, 820, 440, 511, 271, 209, 81, 951, - 519, 256, 209, 330, 209, 328, 56, 300, 51, 1425, - 1409, 1420, 246, 1396, 1417, 1217, 1408, 239, 240, 241, - 242, 1395, 1146, 245, 581, 1253, 445, 61, 1185, 1186, - 1184, 582, 608, 473, 260, 853, 925, 1361, 532, 531, - 541, 542, 534, 535, 536, 537, 538, 539, 540, 533, - 924, 493, 543, 63, 64, 65, 66, 67, 471, 51, - 204, 200, 201, 202, 886, 244, 311, 252, 317, 318, - 315, 316, 314, 313, 312, 854, 855, 625, 929, 626, - 243, 1125, 319, 320, 489, 1043, 1063, 923, 1042, 885, - 1284, 1044, 490, 487, 488, 196, 458, 198, 1300, 475, - 893, 477, 1236, 1234, 237, 482, 483, 1104, 1103, 492, - 696, 694, 1419, 1416, 1387, 1100, 821, 1379, 1127, 877, - 1330, 1440, 459, 1031, 1033, 447, 336, 209, 198, 1105, - 209, 474, 476, 1332, 700, 687, 209, 920, 917, 918, - 1088, 916, 209, 879, 695, 81, 1338, 81, 1179, 81, - 81, 1129, 81, 1133, 81, 1128, 1178, 1126, 1436, 275, - 1177, 443, 1131, 81, 1368, 879, 697, 450, 211, 1086, - 879, 1130, 927, 930, 199, 936, 555, 556, 935, 860, - 1264, 203, 1097, 1111, 1132, 1134, 987, 963, 1099, 730, - 197, 523, 465, 81, 1056, 1202, 543, 727, 944, 441, - 1032, 1331, 533, 518, 722, 543, 517, 516, 922, 1362, - 507, 1377, 1347, 508, 1167, 627, 495, 496, 810, 472, - 1148, 441, 470, 518, 470, 689, 470, 470, 893, 470, - 921, 470, 1382, 810, 1394, 996, 1087, 765, 1061, 878, - 470, 1092, 1089, 1082, 1090, 1085, 1203, 1339, 1337, 1083, - 1084, 763, 764, 762, 439, 513, 209, 209, 209, 1400, - 51, 878, 81, 1091, 1434, 1441, 878, 1435, 81, 1433, - 1290, 875, 873, 926, 874, 552, 943, 882, 554, 871, - 877, 509, 606, 883, 1098, 723, 1096, 516, 928, 455, - 536, 537, 538, 539, 540, 533, 1375, 1402, 543, 461, - 462, 463, 1289, 518, 1442, 1076, 565, 446, 569, 570, - 571, 572, 573, 574, 575, 576, 577, 70, 580, 583, - 583, 583, 589, 583, 583, 589, 583, 597, 598, 599, - 600, 601, 602, 615, 612, 621, 54, 584, 586, 588, - 590, 592, 594, 595, 585, 587, 761, 591, 593, 782, - 596, 783, 452, 71, 453, 1075, 1064, 454, 1378, 613, - 541, 542, 534, 535, 536, 537, 538, 539, 540, 533, - 209, 1045, 543, 1046, 981, 81, 980, 748, 750, 751, - 209, 209, 81, 749, 448, 449, 209, 22, 1311, 209, - 336, 195, 209, 517, 516, 206, 209, 1287, 81, 81, - 1108, 733, 734, 81, 81, 81, 81, 81, 81, 1073, - 518, 1219, 982, 81, 81, 534, 535, 536, 537, 538, - 539, 540, 533, 1056, 812, 543, 329, 498, 298, 1051, - 553, 442, 784, 444, 709, 706, 517, 516, 960, 961, - 962, 81, 705, 1150, 690, 209, 688, 251, 685, 517, - 516, 81, 470, 518, 467, 735, 325, 326, 460, 470, - 79, 1344, 517, 516, 701, 707, 518, 1335, 1418, 1404, - 498, 729, 1335, 1390, 1343, 470, 470, 1199, 759, 518, - 470, 470, 470, 470, 470, 470, 611, 1335, 498, 880, - 470, 470, 756, 1335, 1369, 81, 338, 531, 541, 542, - 534, 535, 536, 537, 538, 539, 540, 533, 728, 823, - 543, 737, 800, 804, 1335, 1334, 1279, 1278, 811, 1266, - 498, 752, 1166, 754, 1154, 517, 516, 1166, 81, 81, - 795, 1263, 498, 1102, 824, 209, 289, 288, 291, 292, - 293, 294, 518, 209, 209, 290, 295, 209, 209, 1209, - 1208, 81, 785, 786, 1205, 1206, 451, 1205, 1204, 457, - 796, 797, 51, 618, 81, 464, 806, 975, 498, 824, - 498, 466, 848, 807, 24, 24, 817, 569, 793, 498, - 634, 633, 755, 847, 793, 617, 1259, 1346, 1114, 816, - 1037, 818, 819, 1037, 24, 991, 989, 58, 1007, 894, - 895, 896, 1008, 1316, 824, 619, 1207, 617, 846, 1047, - 852, 986, 1001, 850, 851, 984, 1000, 975, 209, 81, - 839, 81, 54, 54, 612, 81, 81, 209, 209, 867, - 209, 209, 975, 824, 209, 81, 1166, 975, 908, 990, - 988, 617, 54, 338, 620, 338, 731, 338, 338, 699, - 338, 209, 338, 209, 209, 985, 209, 253, 910, 983, - 54, 338, 829, 832, 833, 834, 830, 1410, 831, 835, - 1296, 497, 904, 905, 743, 887, 1271, 907, 1195, 336, - 1170, 1171, 948, 1050, 903, 605, 760, 614, 898, 897, - 1427, 521, 864, 1423, 1197, 1173, 470, 1154, 470, 756, - 1077, 725, 703, 1176, 1026, 54, 833, 834, 888, 889, - 890, 891, 470, 1024, 759, 1175, 1022, 1021, 1025, 1020, - 952, 1023, 1414, 953, 899, 900, 901, 257, 258, 1407, - 1110, 512, 959, 532, 531, 541, 542, 534, 535, 536, - 537, 538, 539, 540, 533, 1412, 510, 543, 965, 958, - 957, 1068, 500, 632, 468, 209, 209, 209, 209, 209, - 338, 1014, 1384, 964, 501, 1060, 629, 209, 1383, 1314, - 209, 1058, 611, 1052, 209, 1257, 611, 1292, 209, 974, - 913, 1009, 702, 837, 254, 255, 970, 512, 956, 755, - 248, 995, 1351, 81, 249, 58, 955, 993, 1350, 635, - 795, 1298, 1048, 1038, 1037, 491, 1429, 1428, 1429, 691, - 692, 1015, 1039, 720, 1018, 698, 266, 514, 329, 1027, - 1365, 704, 1285, 1035, 726, 60, 62, 616, 1010, 1011, - 55, 1, 612, 612, 612, 612, 612, 1040, 1421, 1065, - 1066, 81, 81, 1218, 1293, 919, 1385, 839, 1328, 1034, - 1189, 1057, 870, 861, 69, 612, 1053, 1054, 1016, 1017, - 438, 1019, 68, 1376, 1067, 869, 1069, 1070, 1071, 868, - 81, 1336, 1283, 338, 744, 881, 1062, 1074, 884, 1196, - 338, 1059, 1381, 640, 638, 209, 639, 637, 1080, 642, - 641, 636, 222, 331, 81, 836, 338, 338, 1093, 628, - 909, 338, 338, 338, 338, 338, 338, 515, 72, 1095, - 1094, 338, 338, 915, 485, 486, 224, 551, 1107, 470, - 954, 864, 760, 1041, 829, 832, 833, 834, 830, 337, - 831, 835, 1161, 736, 1170, 1171, 732, 504, 1349, 739, - 1117, 81, 81, 1155, 1118, 1014, 1123, 470, 1297, 521, - 1136, 994, 338, 1147, 578, 1135, 756, 808, 274, 747, - 1158, 287, 284, 285, 822, 81, 738, 1006, 525, 272, - 264, 1160, 610, 603, 828, 826, 1165, 849, 81, 825, - 81, 81, 1172, 1174, 611, 611, 611, 611, 611, 1188, - 1168, 792, 794, 787, 609, 1113, 1181, 1252, 1360, 611, - 1180, 742, 1183, 802, 802, 1187, 26, 611, 209, 802, - 1192, 59, 259, 19, 18, 17, 1159, 20, 51, 16, - 15, 14, 1116, 456, 30, 209, 814, 815, 1193, 1194, - 21, 81, 13, 12, 81, 81, 209, 1200, 1201, 11, - 10, 9, 81, 8, 7, 209, 1141, 911, 6, 338, - 5, 4, 250, 23, 1211, 2, 933, 934, 0, 937, - 938, 0, 338, 939, 1223, 0, 1212, 0, 1214, 0, - 1225, 0, 0, 0, 0, 0, 0, 1224, 0, 0, - 941, 0, 0, 1232, 0, 947, 0, 0, 0, 0, - 0, 0, 0, 557, 558, 559, 560, 561, 562, 563, - 564, 0, 0, 0, 1014, 1258, 864, 0, 864, 0, - 0, 0, 1268, 0, 0, 0, 0, 338, 81, 338, - 0, 0, 612, 931, 932, 1267, 81, 1048, 0, 1277, - 0, 0, 0, 338, 0, 0, 0, 262, 0, 0, - 0, 81, 0, 0, 0, 0, 0, 0, 81, 0, - 0, 0, 0, 0, 1251, 1286, 0, 1288, 0, 338, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1116, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1299, 0, 0, 0, 1273, 1274, 1275, 0, 0, - 1229, 1230, 0, 1231, 81, 81, 1233, 81, 1235, 0, - 0, 0, 81, 0, 81, 81, 81, 209, 0, 972, - 81, 1158, 1315, 973, 0, 1322, 0, 0, 470, 0, - 977, 978, 979, 1317, 1333, 1327, 1323, 81, 1324, 1325, - 1326, 992, 1340, 0, 0, 0, 998, 0, 999, 0, - 0, 1002, 1003, 1004, 1005, 0, 864, 0, 0, 0, - 0, 1348, 802, 0, 0, 0, 1280, 0, 1341, 1366, - 1342, 0, 0, 1029, 0, 0, 81, 1159, 1158, 1374, - 1318, 1373, 0, 0, 611, 0, 1295, 81, 81, 1367, - 0, 0, 0, 0, 0, 1392, 0, 1389, 1388, 0, - 0, 338, 0, 0, 0, 0, 0, 0, 0, 81, - 1345, 1397, 0, 1014, 0, 0, 0, 0, 0, 0, - 209, 0, 0, 0, 1112, 0, 0, 0, 81, 0, - 219, 0, 0, 0, 1159, 1406, 51, 0, 0, 0, - 0, 1249, 498, 0, 0, 0, 0, 1411, 0, 1078, - 338, 81, 757, 1413, 232, 766, 767, 768, 769, 770, - 771, 772, 773, 774, 775, 776, 777, 778, 779, 780, - 1426, 1437, 0, 0, 0, 1415, 0, 0, 338, 532, - 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, - 533, 0, 0, 543, 0, 0, 502, 506, 0, 0, - 0, 0, 338, 0, 0, 212, 0, 0, 0, 1122, - 813, 0, 215, 524, 0, 1295, 864, 0, 0, 0, - 223, 218, 0, 0, 0, 0, 338, 0, 0, 0, - 503, 0, 0, 469, 0, 0, 0, 1424, 0, 0, - 0, 0, 0, 0, 0, 0, 802, 1210, 568, 1162, - 1164, 0, 221, 0, 0, 0, 0, 579, 231, 0, - 0, 0, 0, 0, 1213, 0, 207, 0, 0, 236, - 0, 0, 0, 1164, 0, 1222, 0, 0, 0, 0, - 0, 0, 0, 0, 213, 0, 338, 0, 338, 1191, - 0, 0, 0, 0, 263, 0, 0, 207, 0, 0, - 0, 0, 207, 0, 207, 0, 0, 0, 0, 0, - 0, 225, 216, 0, 226, 227, 228, 230, 0, 229, - 235, 0, 0, 0, 217, 220, 0, 214, 234, 233, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 1215, - 0, 0, 1220, 1221, 0, 0, 0, 0, 0, 0, - 338, 0, 1226, 0, 0, 0, 0, 0, 0, 1228, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1237, 1238, 1239, 0, 1242, 0, 0, 1245, 0, 1248, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 966, 967, 968, 0, 1260, 1261, 1262, 0, 1265, 0, - 0, 0, 0, 0, 0, 802, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1276, 1250, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 338, 207, 0, 0, - 207, 1246, 498, 0, 1282, 0, 207, 0, 0, 724, - 0, 0, 207, 0, 0, 0, 0, 0, 0, 338, - 478, 0, 479, 480, 0, 481, 338, 484, 0, 0, - 0, 0, 0, 0, 745, 746, 494, 0, 0, 532, - 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, - 533, 0, 0, 543, 0, 0, 0, 1310, 0, 0, + 269, 1432, 1422, 1386, 1101, 1012, 1216, 1281, 567, 1294, + 1329, 299, 1030, 1156, 286, 273, 1190, 863, 840, 247, + 57, 906, 942, 1013, 1157, 1153, 1055, 862, 1169, 1163, + 1036, 238, 81, 872, 1124, 892, 209, 339, 969, 209, + 791, 788, 859, 1081, 471, 300, 51, 781, 721, 1072, + 838, 624, 842, 827, 566, 3, 607, 876, 758, 809, + 499, 790, 505, 902, 440, 820, 333, 209, 81, 623, + 271, 951, 209, 608, 209, 511, 239, 240, 241, 242, + 519, 328, 245, 256, 330, 311, 582, 317, 318, 315, + 316, 314, 313, 312, 56, 1425, 1409, 51, 1420, 1396, + 1417, 319, 320, 1217, 260, 252, 246, 581, 1408, 1395, + 1146, 1253, 336, 445, 625, 473, 626, 61, 886, 1361, 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, - 540, 533, 1319, 1320, 543, 1321, 0, 0, 0, 0, - 1282, 0, 1282, 1282, 1282, 0, 0, 568, 1191, 0, - 798, 799, 0, 0, 1243, 498, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1282, 1352, 1353, 1354, 1355, - 1356, 1357, 1358, 1359, 0, 0, 0, 1363, 1364, 1401, - 0, 0, 0, 0, 0, 0, 207, 207, 207, 1370, - 1371, 1372, 532, 531, 541, 542, 534, 535, 536, 537, - 538, 539, 540, 533, 1380, 858, 543, 0, 0, 0, - 0, 0, 0, 0, 0, 338, 338, 0, 0, 0, - 0, 0, 0, 0, 0, 1393, 0, 1120, 1121, 0, - 0, 0, 1398, 0, 802, 0, 0, 1399, 0, 0, - 1137, 1138, 1139, 1140, 0, 1142, 1143, 1144, 1145, 0, - 1403, 0, 0, 0, 0, 0, 1405, 1151, 1152, 0, - 0, 0, 0, 0, 527, 0, 530, 0, 0, 0, - 0, 0, 544, 545, 546, 547, 548, 549, 550, 1282, - 528, 529, 526, 532, 531, 541, 542, 534, 535, 536, - 537, 538, 539, 540, 533, 1438, 1439, 543, 0, 0, - 207, 0, 0, 0, 0, 0, 949, 950, 686, 506, - 207, 207, 1240, 498, 0, 693, 207, 1198, 0, 207, - 0, 0, 207, 0, 0, 0, 708, 0, 0, 0, - 0, 710, 711, 0, 0, 0, 712, 713, 714, 715, - 716, 717, 0, 0, 0, 0, 718, 719, 0, 0, - 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, - 540, 533, 498, 0, 543, 0, 0, 0, 0, 1247, - 0, 976, 0, 0, 0, 207, 1227, 0, 0, 0, - 0, 0, 0, 0, 708, 0, 0, 0, 997, 0, - 0, 0, 0, 0, 1119, 0, 0, 0, 0, 532, + 540, 533, 1185, 1186, 543, 854, 855, 925, 204, 200, + 201, 202, 1184, 63, 64, 65, 66, 67, 489, 1043, + 853, 924, 1042, 1125, 244, 1044, 490, 487, 488, 196, + 493, 198, 243, 1063, 885, 1284, 1300, 893, 1236, 1234, + 237, 469, 482, 483, 696, 458, 1104, 1103, 694, 929, + 1419, 475, 1416, 477, 1387, 877, 1100, 821, 923, 1379, + 1127, 1330, 1440, 1338, 459, 447, 198, 209, 1105, 700, + 209, 1088, 1031, 1033, 1332, 687, 209, 1179, 695, 1436, + 1178, 1177, 209, 474, 476, 81, 879, 81, 492, 81, + 81, 879, 81, 1129, 81, 1133, 443, 1128, 697, 1126, + 1086, 1097, 1368, 81, 1131, 450, 211, 1099, 920, 917, + 918, 199, 916, 1130, 936, 1056, 1264, 935, 555, 556, + 727, 1111, 987, 963, 197, 730, 1132, 1134, 523, 203, + 470, 465, 470, 81, 470, 470, 860, 470, 1202, 470, + 543, 507, 1331, 927, 930, 495, 496, 455, 470, 1032, 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, - 533, 0, 0, 543, 532, 531, 541, 542, 534, 535, - 536, 537, 538, 539, 540, 533, 263, 0, 543, 0, - 0, 263, 263, 0, 0, 803, 803, 263, 0, 0, - 0, 803, 1256, 532, 531, 541, 542, 534, 535, 536, - 537, 538, 539, 540, 533, 0, 0, 543, 0, 0, - 263, 263, 263, 263, 0, 207, 0, 0, 0, 0, - 0, 0, 0, 207, 844, 0, 0, 207, 207, 0, - 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, - 540, 533, 1255, 0, 543, 0, 0, 1301, 1302, 0, - 1303, 1304, 0, 1305, 1306, 0, 1307, 1308, 1309, 0, - 0, 0, 1312, 1313, 0, 0, 0, 0, 0, 0, - 0, 0, 1109, 0, 0, 0, 0, 0, 0, 0, - 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, - 540, 533, 0, 0, 543, 1244, 0, 0, 207, 0, - 0, 0, 912, 0, 914, 0, 0, 207, 207, 0, - 207, 207, 0, 1241, 207, 0, 0, 0, 940, 0, - 0, 0, 0, 0, 1149, 0, 0, 0, 0, 0, - 0, 207, 0, 945, 946, 0, 207, 0, 0, 0, - 0, 708, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 263, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 1182, 0, 0, 657, 532, + 533, 1362, 722, 543, 1339, 1337, 893, 1087, 51, 518, + 70, 472, 1092, 1089, 1082, 1090, 1085, 508, 944, 922, + 1083, 1084, 878, 552, 275, 1434, 554, 878, 1435, 1203, + 1433, 1377, 1394, 516, 1091, 1347, 209, 209, 209, 1167, + 627, 921, 81, 1098, 533, 1096, 71, 543, 81, 518, + 452, 1148, 453, 810, 565, 454, 569, 570, 571, 572, + 573, 574, 575, 576, 577, 1441, 580, 583, 583, 583, + 589, 583, 583, 589, 583, 597, 598, 599, 600, 601, + 602, 509, 612, 723, 926, 441, 336, 606, 461, 462, + 463, 810, 765, 996, 689, 879, 943, 446, 478, 928, + 479, 480, 1061, 481, 1442, 484, 763, 764, 762, 585, + 587, 1382, 591, 593, 494, 596, 733, 734, 439, 615, + 513, 748, 750, 751, 441, 1400, 621, 749, 1290, 812, + 584, 586, 588, 590, 592, 594, 595, 532, 531, 541, + 542, 534, 535, 536, 537, 538, 539, 540, 533, 54, + 209, 543, 982, 517, 516, 81, 517, 516, 1289, 761, + 209, 209, 81, 1150, 517, 516, 209, 1076, 1075, 209, + 518, 882, 209, 518, 448, 449, 209, 883, 81, 81, + 729, 518, 1064, 81, 81, 81, 209, 81, 81, 22, + 970, 878, 1402, 81, 81, 1378, 875, 873, 1311, 874, + 470, 1287, 517, 516, 871, 877, 1108, 470, 298, 960, + 961, 962, 1073, 709, 1249, 498, 498, 728, 782, 518, + 783, 81, 1375, 470, 470, 209, 195, 1219, 470, 470, + 470, 81, 470, 470, 517, 516, 1056, 735, 470, 470, + 79, 1246, 498, 54, 1045, 1051, 1046, 707, 759, 251, + 701, 518, 532, 531, 541, 542, 534, 535, 536, 537, + 538, 539, 540, 533, 1335, 1418, 543, 1404, 498, 1335, + 1390, 756, 1335, 498, 1344, 81, 338, 784, 755, 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, - 533, 0, 971, 543, 0, 0, 0, 532, 531, 541, - 542, 534, 535, 536, 537, 538, 539, 540, 533, 0, - 263, 543, 532, 531, 541, 542, 534, 535, 536, 537, - 538, 539, 540, 533, 0, 0, 543, 0, 263, 532, + 533, 325, 326, 543, 981, 553, 980, 1335, 1369, 1343, + 800, 804, 706, 737, 705, 754, 811, 690, 81, 81, + 51, 752, 688, 517, 516, 209, 1335, 1334, 1279, 1278, + 1266, 498, 1199, 209, 209, 569, 686, 209, 209, 685, + 518, 81, 467, 693, 795, 460, 785, 786, 1263, 498, + 1209, 1208, 796, 797, 81, 1205, 1206, 266, 806, 710, + 711, 611, 817, 58, 712, 713, 714, 1037, 716, 717, + 1205, 1204, 880, 807, 718, 719, 975, 498, 839, 824, + 498, 816, 612, 818, 819, 336, 497, 848, 618, 534, + 535, 536, 537, 538, 539, 540, 533, 823, 864, 543, + 846, 793, 498, 975, 894, 895, 896, 850, 209, 81, + 824, 81, 851, 634, 633, 81, 81, 209, 209, 867, + 209, 209, 824, 1166, 209, 81, 908, 1410, 1154, 24, + 619, 1166, 617, 338, 793, 338, 1114, 338, 338, 24, + 338, 209, 338, 209, 209, 991, 209, 1259, 847, 1037, + 617, 338, 989, 1007, 470, 1346, 470, 1008, 824, 1207, + 1047, 852, 1001, 1243, 498, 904, 905, 1316, 1000, 986, + 470, 536, 537, 538, 539, 540, 533, 54, 984, 543, + 975, 521, 888, 889, 890, 891, 975, 54, 756, 990, + 1240, 498, 1166, 617, 759, 755, 988, 620, 899, 900, + 901, 532, 531, 541, 542, 534, 535, 536, 537, 538, + 539, 540, 533, 985, 952, 543, 953, 24, 731, 699, + 1296, 964, 983, 887, 959, 1271, 907, 1195, 532, 531, + 541, 542, 534, 535, 536, 537, 538, 539, 540, 533, + 1050, 965, 543, 1170, 1171, 209, 209, 209, 209, 209, + 338, 903, 898, 897, 253, 1102, 629, 209, 910, 1014, + 209, 760, 1427, 743, 209, 54, 1423, 1197, 209, 1173, + 1154, 974, 829, 832, 833, 834, 830, 1077, 831, 835, + 912, 725, 914, 81, 703, 1176, 1010, 1011, 995, 993, + 612, 612, 612, 612, 612, 1009, 940, 1175, 1024, 1039, + 1048, 1015, 54, 1025, 1018, 839, 1022, 1034, 1021, 1027, + 1020, 1023, 1414, 612, 795, 1407, 1035, 1110, 1038, 1016, + 1017, 948, 1019, 1057, 1040, 1412, 1026, 864, 833, 834, + 958, 81, 81, 957, 557, 558, 559, 560, 561, 562, + 563, 564, 257, 258, 1065, 1066, 512, 611, 736, 1068, + 500, 611, 1053, 1054, 632, 1067, 468, 1069, 1070, 1071, + 81, 510, 501, 338, 1060, 1384, 1383, 1080, 1074, 1314, + 338, 1058, 1052, 1257, 1292, 209, 498, 470, 913, 702, + 837, 1093, 254, 255, 81, 512, 338, 338, 248, 956, + 1351, 338, 338, 338, 58, 338, 338, 955, 249, 1350, + 1298, 338, 338, 1037, 491, 470, 792, 794, 1429, 1428, + 1107, 720, 514, 532, 531, 541, 542, 534, 535, 536, + 537, 538, 539, 540, 533, 1118, 1117, 543, 1116, 739, + 1429, 81, 81, 1155, 1147, 1365, 1123, 1136, 1285, 521, + 1158, 726, 338, 1014, 60, 756, 62, 616, 55, 1135, + 1, 1421, 1141, 1218, 1293, 81, 289, 288, 291, 292, + 293, 294, 919, 1165, 1385, 290, 295, 1174, 81, 1328, + 81, 81, 1189, 870, 1159, 861, 51, 1181, 69, 438, + 68, 1376, 869, 787, 1180, 1160, 868, 1188, 1336, 1183, + 1283, 881, 1062, 802, 802, 1187, 884, 760, 209, 802, + 1193, 1194, 1196, 1079, 1059, 1192, 1381, 640, 638, 639, + 637, 642, 864, 641, 864, 209, 814, 815, 636, 222, + 331, 81, 836, 628, 81, 81, 209, 909, 1200, 1201, + 515, 1106, 81, 1211, 72, 209, 1095, 1094, 915, 338, + 485, 486, 224, 551, 954, 1212, 1041, 1214, 337, 1161, + 1223, 732, 338, 504, 1349, 1297, 994, 578, 808, 611, + 611, 611, 611, 611, 1224, 274, 747, 287, 284, 285, + 738, 1232, 1006, 525, 611, 272, 1116, 264, 610, 603, + 612, 828, 611, 757, 826, 1225, 766, 767, 768, 769, + 770, 771, 772, 773, 774, 775, 776, 777, 778, 779, + 780, 1258, 1014, 825, 1172, 1168, 1267, 338, 81, 338, + 1268, 609, 1251, 931, 932, 1113, 81, 1252, 1360, 742, + 26, 1277, 59, 338, 972, 1048, 259, 19, 973, 18, + 17, 81, 20, 16, 15, 977, 978, 979, 81, 14, + 456, 813, 30, 1273, 1274, 1275, 992, 21, 13, 338, + 12, 998, 864, 999, 11, 10, 1002, 1003, 1004, 1005, + 1286, 9, 1288, 8, 1229, 1230, 7, 1231, 6, 5, + 1233, 4, 1235, 250, 23, 2, 470, 0, 1029, 0, + 0, 0, 1295, 0, 81, 81, 1299, 81, 0, 0, + 0, 1158, 81, 0, 81, 81, 81, 209, 0, 1323, + 81, 1324, 1325, 1326, 1315, 262, 0, 1322, 0, 0, + 0, 0, 0, 0, 0, 1327, 1333, 81, 0, 0, + 1340, 0, 0, 0, 1348, 1159, 0, 0, 1318, 0, + 1280, 0, 0, 0, 0, 0, 0, 1317, 0, 0, + 0, 0, 802, 0, 0, 0, 0, 0, 1158, 1341, + 1366, 1342, 0, 0, 0, 0, 81, 0, 1345, 1374, + 1373, 0, 0, 0, 0, 0, 0, 81, 81, 0, + 0, 0, 0, 0, 0, 0, 1388, 0, 0, 0, + 1392, 338, 1159, 0, 51, 1389, 0, 0, 0, 81, + 0, 1397, 0, 1367, 0, 0, 503, 0, 0, 0, + 209, 1014, 1291, 0, 0, 0, 0, 0, 81, 0, + 0, 1295, 864, 0, 1122, 1406, 0, 0, 0, 0, + 0, 966, 967, 968, 0, 0, 0, 0, 1411, 1078, + 338, 81, 207, 1413, 0, 236, 0, 0, 1415, 0, + 0, 0, 0, 0, 1426, 0, 0, 0, 1256, 611, + 0, 1437, 0, 0, 0, 0, 0, 1250, 338, 0, + 263, 0, 0, 207, 0, 0, 0, 0, 207, 0, + 207, 1255, 541, 542, 534, 535, 536, 537, 538, 539, + 540, 533, 338, 219, 543, 1424, 532, 531, 541, 542, + 534, 535, 536, 537, 538, 539, 540, 533, 0, 0, + 543, 0, 0, 0, 0, 0, 338, 232, 0, 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, 540, - 533, 1430, 0, 543, 803, 207, 207, 207, 207, 207, - 0, 0, 0, 0, 0, 0, 645, 1028, 0, 0, - 207, 0, 0, 0, 844, 0, 0, 0, 207, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1254, 0, - 0, 0, 0, 658, 0, 0, 0, 568, 0, 0, - 0, 0, 0, 0, 0, 1269, 0, 0, 1270, 0, - 0, 1272, 0, 0, 0, 671, 674, 675, 676, 677, - 678, 679, 0, 680, 681, 682, 683, 684, 659, 660, - 661, 662, 643, 644, 672, 1079, 646, 0, 647, 648, - 649, 650, 651, 652, 653, 654, 655, 656, 663, 664, - 665, 666, 667, 668, 669, 670, 0, 0, 0, 0, - 0, 0, 0, 1106, 0, 24, 25, 52, 27, 28, - 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, - 0, 0, 0, 0, 43, 263, 0, 0, 0, 29, - 48, 49, 0, 0, 0, 0, 263, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 708, 38, - 673, 0, 0, 54, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 803, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 31, 32, 34, 33, 36, 0, - 50, 0, 0, 0, 0, 0, 0, 0, 1391, 568, - 0, 0, 0, 0, 0, 0, 0, 0, 207, 0, + 533, 0, 0, 543, 0, 0, 802, 0, 0, 1162, + 1164, 532, 531, 541, 542, 534, 535, 536, 537, 538, + 539, 540, 533, 0, 0, 543, 0, 0, 0, 0, + 0, 0, 0, 1164, 502, 506, 0, 1226, 212, 0, + 0, 0, 0, 0, 1228, 215, 338, 0, 338, 1191, + 0, 524, 0, 223, 218, 1237, 1238, 1239, 0, 1242, + 0, 0, 1245, 0, 1248, 0, 0, 0, 0, 613, + 0, 0, 0, 207, 0, 0, 207, 0, 0, 1260, + 1261, 1262, 207, 1265, 0, 221, 568, 0, 207, 0, + 0, 231, 0, 0, 0, 579, 0, 0, 0, 1215, + 1276, 0, 1220, 1221, 0, 206, 0, 0, 1120, 1121, + 338, 0, 0, 0, 0, 0, 0, 213, 0, 0, + 0, 1137, 1138, 1139, 1140, 0, 1142, 1143, 1144, 1145, + 0, 0, 0, 0, 0, 0, 329, 0, 1151, 1152, + 0, 442, 0, 444, 225, 216, 0, 226, 227, 228, + 230, 0, 229, 235, 1119, 0, 0, 217, 220, 0, + 214, 234, 233, 0, 0, 802, 0, 0, 0, 0, + 0, 0, 1310, 0, 532, 531, 541, 542, 534, 535, + 536, 537, 538, 539, 540, 533, 338, 0, 543, 829, + 832, 833, 834, 830, 1282, 831, 835, 0, 1198, 1170, + 1171, 0, 207, 207, 207, 0, 0, 0, 0, 338, + 0, 0, 0, 0, 0, 0, 338, 0, 0, 0, + 0, 1352, 1353, 1354, 1355, 1356, 1357, 1358, 1359, 0, + 0, 0, 1363, 1364, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1370, 1371, 1372, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1227, 0, 0, + 0, 0, 1319, 1320, 0, 1321, 451, 0, 0, 457, + 1282, 0, 1282, 1282, 1282, 464, 0, 724, 1191, 0, + 1393, 466, 0, 0, 0, 0, 0, 1398, 0, 0, + 0, 0, 0, 0, 0, 1282, 0, 0, 0, 0, + 0, 0, 745, 746, 0, 1403, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 207, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 207, 207, 0, 0, + 0, 0, 207, 0, 1380, 207, 0, 0, 207, 0, + 0, 0, 708, 0, 0, 338, 338, 0, 0, 0, + 1438, 1439, 207, 0, 0, 568, 0, 0, 798, 799, + 0, 0, 0, 0, 802, 0, 0, 1399, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1301, 1302, + 0, 1303, 1304, 0, 1305, 1306, 1405, 1307, 1308, 1309, + 0, 207, 0, 1312, 1313, 605, 0, 614, 0, 0, + 708, 0, 0, 0, 0, 0, 527, 0, 530, 1282, + 0, 0, 0, 858, 544, 545, 546, 547, 548, 549, + 550, 0, 528, 529, 526, 532, 531, 541, 542, 534, + 535, 536, 537, 538, 539, 540, 533, 0, 0, 543, + 971, 0, 263, 0, 0, 0, 0, 263, 263, 0, + 0, 803, 803, 263, 0, 0, 0, 803, 1247, 0, + 532, 531, 541, 542, 534, 535, 536, 537, 538, 539, + 540, 533, 0, 0, 543, 657, 263, 263, 263, 263, + 0, 207, 0, 0, 0, 0, 0, 0, 0, 207, + 844, 0, 0, 207, 207, 0, 532, 531, 541, 542, + 534, 535, 536, 537, 538, 539, 540, 533, 0, 635, + 543, 0, 0, 0, 949, 950, 0, 506, 0, 691, + 692, 0, 0, 0, 0, 698, 0, 0, 329, 0, + 0, 704, 532, 531, 541, 542, 534, 535, 536, 537, + 538, 539, 540, 533, 0, 715, 543, 0, 0, 0, + 0, 0, 0, 645, 0, 0, 0, 0, 0, 0, + 0, 0, 1430, 0, 207, 0, 0, 0, 0, 0, + 0, 0, 0, 207, 207, 0, 207, 207, 0, 976, + 207, 0, 0, 0, 744, 0, 0, 0, 0, 0, + 658, 0, 0, 0, 0, 0, 997, 207, 0, 945, + 946, 0, 207, 0, 0, 0, 0, 708, 0, 0, + 0, 0, 671, 674, 675, 676, 677, 678, 679, 263, + 680, 681, 682, 683, 684, 659, 660, 661, 662, 643, + 644, 672, 0, 646, 0, 647, 648, 649, 650, 651, + 652, 653, 654, 655, 656, 663, 664, 665, 666, 667, + 668, 669, 670, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 263, 1244, 0, 0, + 0, 0, 0, 0, 822, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 263, 0, 0, 849, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 803, 207, 207, 207, 207, 207, 0, 673, 0, 0, + 0, 0, 0, 1028, 0, 0, 207, 0, 0, 0, + 844, 0, 1241, 0, 207, 0, 0, 0, 0, 0, + 1109, 0, 0, 0, 0, 24, 25, 52, 27, 28, + 0, 532, 531, 541, 542, 534, 535, 536, 537, 538, + 539, 540, 533, 0, 43, 543, 0, 911, 0, 29, + 48, 49, 0, 0, 0, 0, 933, 934, 0, 937, + 938, 0, 0, 939, 0, 0, 0, 0, 0, 38, + 0, 0, 1149, 54, 0, 0, 0, 0, 0, 0, + 941, 0, 0, 0, 0, 947, 532, 531, 541, 542, + 534, 535, 536, 537, 538, 539, 540, 533, 0, 0, + 543, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1182, 0, 0, 0, 0, 0, 0, + 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 263, 0, 0, 31, 32, 34, 33, 36, 0, + 50, 0, 263, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 708, 0, 0, 0, 0, 0, 0, 37, 44, 45, 0, 0, 46, 47, 35, 0, - 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, - 0, 39, 40, 0, 41, 42, 207, 0, 0, 0, - 0, 0, 0, 0, 0, 207, 0, 0, 0, 0, + 0, 0, 0, 0, 803, 0, 0, 0, 0, 0, + 0, 39, 40, 0, 41, 42, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1254, 0, 0, 0, + 0, 0, 0, 0, 0, 568, 0, 0, 0, 0, + 0, 0, 0, 1269, 207, 0, 1270, 0, 0, 1272, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 803, 0, 0, + 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, + 53, 0, 207, 0, 0, 0, 0, 0, 0, 0, + 0, 207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 1291, 0, 0, 0, 0, 0, + 0, 0, 0, 803, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 426, 415, 844, 386, 429, - 364, 378, 437, 379, 380, 408, 350, 394, 139, 376, - 0, 367, 345, 373, 346, 365, 388, 103, 391, 363, - 417, 397, 428, 120, 435, 122, 402, 0, 159, 131, - 0, 0, 390, 419, 392, 413, 385, 409, 355, 401, - 430, 377, 406, 431, 0, 0, 0, 80, 0, 865, - 866, 0, 0, 0, 0, 0, 96, 0, 404, 425, - 375, 405, 407, 344, 403, 0, 348, 351, 436, 421, - 370, 371, 1049, 0, 0, 0, 0, 0, 0, 389, - 393, 410, 383, 0, 0, 0, 803, 0, 0, 0, - 0, 368, 0, 400, 0, 0, 0, 352, 349, 0, - 207, 387, 0, 0, 0, 354, 0, 369, 411, 0, - 343, 109, 414, 420, 384, 210, 424, 382, 381, 427, - 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, - 151, 155, 418, 366, 374, 99, 372, 153, 141, 175, - 399, 142, 152, 123, 167, 147, 174, 182, 183, 164, - 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, - 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, - 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, - 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, - 112, 144, 125, 145, 113, 133, 132, 134, 0, 347, - 0, 160, 177, 194, 94, 362, 165, 184, 185, 186, - 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, - 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, - 176, 158, 358, 361, 356, 357, 395, 396, 432, 433, - 434, 412, 353, 0, 359, 360, 0, 416, 422, 423, - 398, 82, 89, 121, 191, 148, 106, 178, 426, 415, - 0, 386, 429, 364, 378, 437, 379, 380, 408, 350, - 394, 139, 376, 0, 367, 345, 373, 346, 365, 388, - 103, 391, 363, 417, 397, 428, 120, 435, 122, 402, - 0, 159, 131, 0, 0, 390, 419, 392, 413, 385, - 409, 355, 401, 430, 377, 406, 431, 0, 0, 0, - 80, 0, 865, 866, 0, 0, 0, 0, 0, 96, - 0, 404, 425, 375, 405, 407, 344, 403, 0, 348, - 351, 436, 421, 370, 371, 0, 0, 0, 0, 0, - 0, 0, 389, 393, 410, 383, 0, 0, 0, 0, - 0, 0, 0, 0, 368, 0, 400, 0, 0, 0, - 352, 349, 0, 0, 387, 0, 0, 0, 354, 0, - 369, 411, 0, 343, 109, 414, 420, 384, 210, 424, - 382, 381, 427, 146, 0, 162, 111, 119, 83, 90, - 0, 110, 137, 151, 155, 418, 366, 374, 99, 372, - 153, 141, 175, 399, 142, 152, 123, 167, 147, 174, - 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, - 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, - 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, - 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, - 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, - 134, 0, 347, 0, 160, 177, 194, 94, 362, 165, - 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, - 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, - 140, 154, 98, 176, 158, 358, 361, 356, 357, 395, - 396, 432, 433, 434, 412, 353, 0, 359, 360, 0, - 416, 422, 423, 398, 82, 89, 121, 191, 148, 106, - 178, 426, 415, 0, 386, 429, 364, 378, 437, 379, - 380, 408, 350, 394, 139, 376, 0, 367, 345, 373, - 346, 365, 388, 103, 391, 363, 417, 397, 428, 120, - 435, 122, 402, 0, 159, 131, 0, 0, 390, 419, - 392, 413, 385, 409, 355, 401, 430, 377, 406, 431, - 54, 0, 0, 80, 0, 0, 0, 0, 0, 0, - 0, 0, 96, 0, 404, 425, 375, 405, 407, 344, - 403, 0, 348, 351, 436, 421, 370, 371, 0, 0, - 0, 0, 0, 0, 0, 389, 393, 410, 383, 0, - 0, 0, 0, 0, 0, 0, 0, 368, 0, 400, - 0, 0, 0, 352, 349, 0, 0, 387, 0, 0, - 0, 354, 0, 369, 411, 0, 343, 109, 414, 420, - 384, 210, 424, 382, 381, 427, 146, 0, 162, 111, - 119, 83, 90, 0, 110, 137, 151, 155, 418, 366, - 374, 99, 372, 153, 141, 175, 399, 142, 152, 123, - 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, - 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, - 0, 150, 102, 107, 101, 138, 168, 169, 100, 193, - 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, - 87, 170, 128, 126, 118, 105, 112, 144, 125, 145, - 113, 133, 132, 134, 0, 347, 0, 160, 177, 194, - 94, 362, 165, 184, 185, 186, 187, 188, 189, 0, - 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, - 124, 149, 192, 140, 154, 98, 176, 158, 358, 361, - 356, 357, 395, 396, 432, 433, 434, 412, 353, 0, - 359, 360, 0, 416, 422, 423, 398, 82, 89, 121, - 191, 148, 106, 178, 426, 415, 0, 386, 429, 364, - 378, 437, 379, 380, 408, 350, 394, 139, 376, 0, - 367, 345, 373, 346, 365, 388, 103, 391, 363, 417, - 397, 428, 120, 435, 122, 402, 0, 159, 131, 0, - 0, 390, 419, 392, 413, 385, 409, 355, 401, 430, - 377, 406, 431, 0, 0, 0, 80, 0, 0, 0, - 0, 0, 0, 0, 0, 96, 0, 404, 425, 375, - 405, 407, 344, 403, 0, 348, 351, 436, 421, 370, - 371, 0, 0, 0, 0, 0, 0, 0, 389, 393, - 410, 383, 0, 0, 0, 0, 0, 0, 1115, 0, - 368, 0, 400, 0, 0, 0, 352, 349, 0, 0, - 387, 0, 0, 0, 354, 0, 369, 411, 0, 343, - 109, 414, 420, 384, 210, 424, 382, 381, 427, 146, - 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, - 155, 418, 366, 374, 99, 372, 153, 141, 175, 399, - 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, - 190, 84, 163, 173, 97, 156, 86, 171, 161, 129, - 115, 116, 85, 0, 150, 102, 107, 101, 138, 168, - 169, 100, 193, 91, 180, 88, 92, 179, 136, 166, - 172, 130, 127, 87, 170, 128, 126, 118, 105, 112, - 144, 125, 145, 113, 133, 132, 134, 0, 347, 0, - 160, 177, 194, 94, 362, 165, 184, 185, 186, 187, - 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, - 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, - 158, 358, 361, 356, 357, 395, 396, 432, 433, 434, - 412, 353, 0, 359, 360, 0, 416, 422, 423, 398, - 82, 89, 121, 191, 148, 106, 178, 426, 415, 0, - 386, 429, 364, 378, 437, 379, 380, 408, 350, 394, - 139, 376, 0, 367, 345, 373, 346, 365, 388, 103, - 391, 363, 417, 397, 428, 120, 435, 122, 402, 0, - 159, 131, 0, 0, 390, 419, 392, 413, 385, 409, - 355, 401, 430, 377, 406, 431, 0, 0, 0, 268, - 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, - 404, 425, 375, 405, 407, 344, 403, 0, 348, 351, - 436, 421, 370, 371, 0, 0, 0, 0, 0, 0, - 0, 389, 393, 410, 383, 0, 0, 0, 0, 0, - 0, 753, 0, 368, 0, 400, 0, 0, 0, 352, - 349, 0, 0, 387, 0, 0, 0, 354, 0, 369, - 411, 0, 343, 109, 414, 420, 384, 210, 424, 382, - 381, 427, 146, 0, 162, 111, 119, 83, 90, 0, - 110, 137, 151, 155, 418, 366, 374, 99, 372, 153, - 141, 175, 399, 142, 152, 123, 167, 147, 174, 182, - 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, - 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, - 101, 138, 168, 169, 100, 193, 91, 180, 88, 92, - 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, - 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, - 0, 347, 0, 160, 177, 194, 94, 362, 165, 184, - 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, - 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, - 154, 98, 176, 158, 358, 361, 356, 357, 395, 396, - 432, 433, 434, 412, 353, 0, 359, 360, 0, 416, - 422, 423, 398, 82, 89, 121, 191, 148, 106, 178, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1391, 568, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1210, 0, 0, + 0, 0, 0, 844, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1213, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1222, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 426, 415, 0, 386, + 429, 364, 378, 437, 379, 380, 408, 350, 394, 139, + 376, 0, 367, 345, 373, 346, 365, 388, 103, 391, + 363, 417, 397, 428, 120, 435, 122, 402, 0, 159, + 131, 0, 0, 390, 419, 392, 413, 385, 409, 355, + 401, 430, 377, 406, 431, 0, 0, 0, 80, 0, + 865, 866, 803, 0, 0, 0, 0, 96, 0, 404, + 425, 375, 405, 407, 344, 403, 207, 348, 351, 436, + 421, 370, 371, 1049, 0, 0, 0, 0, 0, 0, + 389, 393, 410, 383, 0, 0, 0, 0, 0, 0, + 0, 0, 368, 0, 400, 0, 0, 0, 352, 349, + 0, 0, 387, 0, 0, 0, 354, 0, 369, 411, + 0, 343, 109, 414, 420, 384, 210, 424, 382, 381, + 427, 146, 0, 162, 111, 119, 83, 90, 0, 110, + 137, 151, 155, 418, 366, 374, 99, 372, 153, 141, + 175, 399, 142, 152, 123, 167, 147, 174, 182, 183, + 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, + 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, + 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, + 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, + 347, 0, 160, 177, 194, 94, 362, 165, 184, 185, + 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, + 98, 176, 158, 358, 361, 356, 357, 395, 396, 432, + 433, 434, 412, 353, 0, 359, 360, 0, 416, 422, + 423, 398, 82, 89, 121, 191, 148, 106, 178, 1401, 426, 415, 0, 386, 429, 364, 378, 437, 379, 380, 408, 350, 394, 139, 376, 0, 367, 345, 373, 346, 365, 388, 103, 391, 363, 417, 397, 428, 120, 435, 122, 402, 0, 159, 131, 0, 0, 390, 419, 392, 413, 385, 409, 355, 401, 430, 377, 406, 431, 0, - 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 80, 0, 865, 866, 0, 0, 0, 0, 0, 96, 0, 404, 425, 375, 405, 407, 344, 403, 0, 348, 351, 436, 421, 370, 371, 0, 0, 0, 0, 0, 0, 0, 389, 393, 410, 383, 0, 0, @@ -1154,7 +1041,7 @@ var yyAct = [...]int{ 345, 373, 346, 365, 388, 103, 391, 363, 417, 397, 428, 120, 435, 122, 402, 0, 159, 131, 0, 0, 390, 419, 392, 413, 385, 409, 355, 401, 430, 377, - 406, 431, 0, 0, 0, 268, 0, 0, 0, 0, + 406, 431, 54, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 404, 425, 375, 405, 407, 344, 403, 0, 348, 351, 436, 421, 370, 371, 0, 0, 0, 0, 0, 0, 0, 389, 393, 410, @@ -1185,7 +1072,7 @@ var yyAct = [...]int{ 425, 375, 405, 407, 344, 403, 0, 348, 351, 436, 421, 370, 371, 0, 0, 0, 0, 0, 0, 0, 389, 393, 410, 383, 0, 0, 0, 0, 0, 0, - 0, 0, 368, 0, 400, 0, 0, 0, 352, 349, + 1115, 0, 368, 0, 400, 0, 0, 0, 352, 349, 0, 0, 387, 0, 0, 0, 354, 0, 369, 411, 0, 343, 109, 414, 420, 384, 210, 424, 382, 381, 427, 146, 0, 162, 111, 119, 83, 90, 0, 110, @@ -1193,12 +1080,12 @@ var yyAct = [...]int{ 175, 399, 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, - 138, 168, 169, 100, 193, 91, 180, 88, 341, 179, + 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, 347, 0, 160, 177, 194, 94, 362, 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, - 342, 340, 114, 157, 117, 124, 149, 192, 140, 154, + 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 358, 361, 356, 357, 395, 396, 432, 433, 434, 412, 353, 0, 359, 360, 0, 416, 422, 423, 398, 82, 89, 121, 191, 148, 106, 178, 426, @@ -1207,11 +1094,11 @@ var yyAct = [...]int{ 388, 103, 391, 363, 417, 397, 428, 120, 435, 122, 402, 0, 159, 131, 0, 0, 390, 419, 392, 413, 385, 409, 355, 401, 430, 377, 406, 431, 0, 0, - 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 404, 425, 375, 405, 407, 344, 403, 0, 348, 351, 436, 421, 370, 371, 0, 0, 0, 0, 0, 0, 0, 389, 393, 410, 383, 0, 0, 0, - 0, 0, 0, 0, 0, 368, 0, 400, 0, 0, + 0, 0, 0, 753, 0, 368, 0, 400, 0, 0, 0, 352, 349, 0, 0, 387, 0, 0, 0, 354, 0, 369, 411, 0, 343, 109, 414, 420, 384, 210, 424, 382, 381, 427, 146, 0, 162, 111, 119, 83, @@ -1244,13 +1131,13 @@ var yyAct = [...]int{ 111, 119, 83, 90, 0, 110, 137, 151, 155, 418, 366, 374, 99, 372, 153, 141, 175, 399, 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, - 163, 622, 97, 156, 86, 171, 161, 129, 115, 116, + 163, 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, 168, 169, 100, - 193, 91, 180, 88, 341, 179, 136, 166, 172, 130, + 193, 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, 347, 0, 160, 177, 194, 94, 362, 165, 184, 185, 186, 187, 188, 189, - 0, 0, 95, 108, 104, 143, 342, 340, 114, 157, + 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 358, 361, 356, 357, 395, 396, 432, 433, 434, 412, 353, 0, 359, 360, 0, 416, 422, 423, 398, 82, 89, @@ -1259,7 +1146,7 @@ var yyAct = [...]int{ 0, 367, 345, 373, 346, 365, 388, 103, 391, 363, 417, 397, 428, 120, 435, 122, 402, 0, 159, 131, 0, 0, 390, 419, 392, 413, 385, 409, 355, 401, - 430, 377, 406, 431, 0, 0, 0, 80, 0, 0, + 430, 377, 406, 431, 0, 0, 0, 268, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 404, 425, 375, 405, 407, 344, 403, 0, 348, 351, 436, 421, 370, 371, 0, 0, 0, 0, 0, 0, 0, 389, @@ -1270,303 +1157,134 @@ var yyAct = [...]int{ 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, 418, 366, 374, 99, 372, 153, 141, 175, 399, 142, 152, 123, 167, 147, 174, 182, 183, 164, - 181, 190, 84, 163, 332, 97, 156, 86, 171, 161, - 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, - 168, 169, 100, 193, 91, 180, 88, 341, 179, 136, - 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, - 112, 144, 125, 145, 113, 133, 132, 134, 0, 347, - 0, 160, 177, 194, 94, 362, 165, 184, 185, 186, - 187, 188, 189, 0, 0, 95, 108, 104, 143, 342, - 340, 335, 334, 117, 124, 149, 192, 140, 154, 98, - 176, 158, 358, 361, 356, 357, 395, 396, 432, 433, - 434, 412, 353, 0, 359, 360, 0, 416, 422, 423, - 398, 82, 89, 121, 191, 148, 106, 178, 139, 0, - 0, 0, 0, 270, 0, 0, 0, 103, 0, 267, - 0, 0, 0, 120, 310, 122, 0, 0, 159, 131, - 0, 0, 0, 0, 301, 302, 0, 0, 0, 0, - 0, 0, 856, 0, 54, 0, 0, 268, 289, 288, - 291, 292, 293, 294, 0, 0, 96, 290, 295, 296, - 297, 857, 0, 0, 265, 282, 0, 309, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 279, 280, 0, - 0, 0, 0, 323, 0, 281, 0, 0, 276, 277, - 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 109, 0, 0, 0, 210, 0, 0, 321, 0, - 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, - 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, - 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, - 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, - 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, - 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, - 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, - 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, - 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, - 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, - 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, - 176, 158, 311, 322, 317, 318, 315, 316, 314, 313, - 312, 324, 303, 304, 305, 306, 308, 0, 319, 320, - 307, 82, 89, 121, 191, 148, 106, 178, 139, 0, - 0, 789, 0, 270, 0, 0, 0, 103, 0, 267, - 0, 0, 0, 120, 310, 122, 0, 0, 159, 131, - 0, 0, 0, 0, 301, 302, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 0, 268, 289, 288, - 291, 292, 293, 294, 0, 0, 96, 290, 295, 296, - 297, 0, 0, 0, 265, 282, 0, 309, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 279, 280, 261, - 0, 0, 0, 323, 0, 281, 0, 0, 276, 277, - 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 109, 0, 0, 0, 210, 0, 0, 321, 0, - 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, - 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, - 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, - 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, - 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, - 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, - 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, - 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, - 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, - 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, - 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, - 176, 158, 311, 322, 317, 318, 315, 316, 314, 313, - 312, 324, 303, 304, 305, 306, 308, 0, 319, 320, - 307, 82, 89, 121, 191, 148, 106, 178, 139, 0, - 0, 0, 0, 270, 0, 0, 0, 103, 0, 267, - 0, 0, 0, 120, 310, 122, 0, 0, 159, 131, - 0, 0, 0, 0, 301, 302, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 498, 268, 289, 288, - 291, 292, 293, 294, 0, 0, 96, 290, 295, 296, - 297, 0, 0, 0, 265, 282, 0, 309, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 279, 280, 0, - 0, 0, 0, 323, 0, 281, 0, 0, 276, 277, - 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 109, 0, 0, 0, 210, 0, 0, 321, 0, - 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, - 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, - 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, - 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, - 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, - 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, - 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, - 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, - 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, - 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, - 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, - 176, 158, 311, 322, 317, 318, 315, 316, 314, 313, - 312, 324, 303, 304, 305, 306, 308, 0, 319, 320, - 307, 82, 89, 121, 191, 148, 106, 178, 139, 0, - 0, 0, 0, 270, 0, 0, 0, 103, 0, 267, - 0, 0, 0, 120, 310, 122, 0, 0, 159, 131, - 0, 0, 0, 0, 301, 302, 0, 0, 0, 0, - 0, 0, 0, 0, 54, 0, 0, 268, 289, 288, - 291, 292, 293, 294, 0, 0, 96, 290, 295, 296, - 297, 0, 0, 0, 265, 282, 0, 309, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 279, 280, 261, - 0, 0, 0, 323, 0, 281, 0, 0, 276, 277, - 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 109, 0, 0, 0, 210, 0, 0, 321, 0, - 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, - 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, - 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, - 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, - 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 347, + 0, 160, 177, 194, 94, 362, 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, - 176, 158, 311, 322, 317, 318, 315, 316, 314, 313, - 312, 324, 303, 304, 305, 306, 308, 24, 319, 320, - 307, 82, 89, 121, 191, 148, 106, 178, 0, 139, - 0, 0, 0, 0, 270, 0, 0, 0, 103, 0, - 267, 0, 0, 0, 120, 310, 122, 0, 0, 159, - 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 0, 268, 289, - 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, - 296, 297, 0, 0, 0, 265, 282, 0, 309, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, - 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, - 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, - 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, - 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, - 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, - 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, - 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, - 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, - 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, - 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, - 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, - 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, - 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, - 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, - 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, - 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, - 0, 0, 0, 0, 270, 0, 0, 0, 103, 0, - 267, 0, 0, 0, 120, 310, 122, 0, 0, 159, - 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 0, 268, 289, - 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, - 296, 297, 0, 0, 0, 265, 282, 0, 309, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, - 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, - 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, - 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, - 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, - 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, - 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, - 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, - 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, - 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, - 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, - 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, - 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, - 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, - 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, - 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, - 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, - 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, - 0, 0, 0, 0, 120, 310, 122, 0, 0, 159, - 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 0, 268, 289, - 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, - 296, 297, 0, 0, 0, 0, 282, 0, 309, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, - 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, - 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, - 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, - 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, - 175, 1431, 142, 152, 123, 167, 147, 174, 182, 183, - 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, - 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, - 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, - 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, - 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, - 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, - 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, - 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, - 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, - 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, - 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, - 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, - 0, 0, 0, 0, 120, 310, 122, 0, 0, 159, - 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 498, 268, 289, - 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, - 296, 297, 0, 0, 0, 0, 282, 0, 309, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, - 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, - 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, - 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, - 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, - 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, - 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, - 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, - 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, - 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, - 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, - 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, - 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, - 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, - 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, - 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, - 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, - 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, - 0, 0, 0, 0, 120, 310, 122, 0, 0, 159, - 131, 0, 0, 0, 0, 301, 302, 0, 0, 0, - 0, 0, 0, 0, 0, 54, 0, 0, 268, 289, - 288, 291, 292, 293, 294, 0, 0, 96, 290, 295, - 296, 297, 0, 0, 0, 0, 282, 0, 309, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 279, 280, - 0, 0, 0, 0, 323, 0, 281, 0, 0, 276, - 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 109, 0, 0, 0, 210, 0, 0, 321, - 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, - 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, - 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, - 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, - 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, - 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, - 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, - 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, - 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, - 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, - 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, - 98, 176, 158, 311, 322, 317, 318, 315, 316, 314, - 313, 312, 324, 303, 304, 305, 306, 308, 0, 319, - 320, 307, 82, 89, 121, 191, 148, 106, 178, 139, - 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, - 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, - 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, - 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 532, 531, 541, 542, 534, 535, - 536, 537, 538, 539, 540, 533, 0, 0, 543, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 109, 0, 0, 0, 210, 0, 0, 0, - 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, - 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, - 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, - 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, - 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, - 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, - 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, - 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, - 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, - 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, - 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, - 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 82, 89, 121, 191, 148, 106, 178, 139, - 0, 0, 0, 520, 0, 0, 0, 0, 103, 0, - 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, - 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, - 522, 0, 0, 0, 0, 0, 0, 96, 0, 0, - 0, 0, 0, 517, 516, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 518, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 109, 0, 0, 0, 210, 0, 0, 0, - 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, - 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, - 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, - 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, - 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, - 138, 168, 169, 100, 193, 91, 180, 88, 92, 179, - 136, 166, 172, 130, 127, 87, 170, 128, 126, 118, - 105, 112, 144, 125, 145, 113, 133, 132, 134, 0, - 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, - 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, - 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, - 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 139, 0, 82, 89, 121, 191, 148, 106, 178, 103, - 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, - 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, + 176, 158, 358, 361, 356, 357, 395, 396, 432, 433, + 434, 412, 353, 0, 359, 360, 0, 416, 422, 423, + 398, 82, 89, 121, 191, 148, 106, 178, 426, 415, + 0, 386, 429, 364, 378, 437, 379, 380, 408, 350, + 394, 139, 376, 0, 367, 345, 373, 346, 365, 388, + 103, 391, 363, 417, 397, 428, 120, 435, 122, 402, + 0, 159, 131, 0, 0, 390, 419, 392, 413, 385, + 409, 355, 401, 430, 377, 406, 431, 0, 0, 0, + 80, 0, 0, 0, 0, 0, 0, 0, 0, 96, + 0, 404, 425, 375, 405, 407, 344, 403, 0, 348, + 351, 436, 421, 370, 371, 0, 0, 0, 0, 0, + 0, 0, 389, 393, 410, 383, 0, 0, 0, 0, + 0, 0, 0, 0, 368, 0, 400, 0, 0, 0, + 352, 349, 0, 0, 387, 0, 0, 0, 354, 0, + 369, 411, 0, 343, 109, 414, 420, 384, 210, 424, + 382, 381, 427, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 418, 366, 374, 99, 372, + 153, 141, 175, 399, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 341, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 347, 0, 160, 177, 194, 94, 362, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 342, 340, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 358, 361, 356, 357, 395, + 396, 432, 433, 434, 412, 353, 0, 359, 360, 0, + 416, 422, 423, 398, 82, 89, 121, 191, 148, 106, + 178, 426, 415, 0, 386, 429, 364, 378, 437, 379, + 380, 408, 350, 394, 139, 376, 0, 367, 345, 373, + 346, 365, 388, 103, 391, 363, 417, 397, 428, 120, + 435, 122, 402, 0, 159, 131, 0, 0, 390, 419, + 392, 413, 385, 409, 355, 401, 430, 377, 406, 431, + 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, + 0, 0, 96, 0, 404, 425, 375, 405, 407, 344, + 403, 0, 348, 351, 436, 421, 370, 371, 0, 0, + 0, 0, 0, 0, 0, 389, 393, 410, 383, 0, + 0, 0, 0, 0, 0, 0, 0, 368, 0, 400, + 0, 0, 0, 352, 349, 0, 0, 387, 0, 0, + 0, 354, 0, 369, 411, 0, 343, 109, 414, 420, + 384, 210, 424, 382, 381, 427, 146, 0, 162, 111, + 119, 83, 90, 0, 110, 137, 151, 155, 418, 366, + 374, 99, 372, 153, 141, 175, 399, 142, 152, 123, + 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, + 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, + 0, 150, 102, 107, 101, 138, 168, 169, 100, 193, + 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, + 87, 170, 128, 126, 118, 105, 112, 144, 125, 145, + 113, 133, 132, 134, 0, 347, 0, 160, 177, 194, + 94, 362, 165, 184, 185, 186, 187, 188, 189, 0, + 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, + 124, 149, 192, 140, 154, 98, 176, 158, 358, 361, + 356, 357, 395, 396, 432, 433, 434, 412, 353, 0, + 359, 360, 0, 416, 422, 423, 398, 82, 89, 121, + 191, 148, 106, 178, 426, 415, 0, 386, 429, 364, + 378, 437, 379, 380, 408, 350, 394, 139, 376, 0, + 367, 345, 373, 346, 365, 388, 103, 391, 363, 417, + 397, 428, 120, 435, 122, 402, 0, 159, 131, 0, + 0, 390, 419, 392, 413, 385, 409, 355, 401, 430, + 377, 406, 431, 0, 0, 0, 80, 0, 0, 0, + 0, 0, 0, 0, 0, 96, 0, 404, 425, 375, + 405, 407, 344, 403, 0, 348, 351, 436, 421, 370, + 371, 0, 0, 0, 0, 0, 0, 0, 389, 393, + 410, 383, 0, 0, 0, 0, 0, 0, 0, 0, + 368, 0, 400, 0, 0, 0, 352, 349, 0, 0, + 387, 0, 0, 0, 354, 0, 369, 411, 0, 343, + 109, 414, 420, 384, 210, 424, 382, 381, 427, 146, + 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, + 155, 418, 366, 374, 99, 372, 153, 141, 175, 399, + 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, + 190, 84, 163, 622, 97, 156, 86, 171, 161, 129, + 115, 116, 85, 0, 150, 102, 107, 101, 138, 168, + 169, 100, 193, 91, 180, 88, 341, 179, 136, 166, + 172, 130, 127, 87, 170, 128, 126, 118, 105, 112, + 144, 125, 145, 113, 133, 132, 134, 0, 347, 0, + 160, 177, 194, 94, 362, 165, 184, 185, 186, 187, + 188, 189, 0, 0, 95, 108, 104, 143, 342, 340, + 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, + 158, 358, 361, 356, 357, 395, 396, 432, 433, 434, + 412, 353, 0, 359, 360, 0, 416, 422, 423, 398, + 82, 89, 121, 191, 148, 106, 178, 426, 415, 0, + 386, 429, 364, 378, 437, 379, 380, 408, 350, 394, + 139, 376, 0, 367, 345, 373, 346, 365, 388, 103, + 391, 363, 417, 397, 428, 120, 435, 122, 402, 0, + 159, 131, 0, 0, 390, 419, 392, 413, 385, 409, + 355, 401, 430, 377, 406, 431, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, - 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 109, 76, 77, 0, 73, 0, 0, - 0, 78, 146, 0, 162, 111, 119, 83, 90, 0, + 404, 425, 375, 405, 407, 344, 403, 0, 348, 351, + 436, 421, 370, 371, 0, 0, 0, 0, 0, 0, + 0, 389, 393, 410, 383, 0, 0, 0, 0, 0, + 0, 0, 0, 368, 0, 400, 0, 0, 0, 352, + 349, 0, 0, 387, 0, 0, 0, 354, 0, 369, + 411, 0, 343, 109, 414, 420, 384, 210, 424, 382, + 381, 427, 146, 0, 162, 111, 119, 83, 90, 0, + 110, 137, 151, 155, 418, 366, 374, 99, 372, 153, + 141, 175, 399, 142, 152, 123, 167, 147, 174, 182, + 183, 164, 181, 190, 84, 163, 332, 97, 156, 86, + 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, + 101, 138, 168, 169, 100, 193, 91, 180, 88, 341, + 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, + 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, + 0, 347, 0, 160, 177, 194, 94, 362, 165, 184, + 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, + 143, 342, 340, 335, 334, 117, 124, 149, 192, 140, + 154, 98, 176, 158, 358, 361, 356, 357, 395, 396, + 432, 433, 434, 412, 353, 0, 359, 360, 0, 416, + 422, 423, 398, 82, 89, 121, 191, 148, 106, 178, + 139, 0, 0, 0, 0, 270, 0, 0, 0, 103, + 0, 267, 0, 0, 0, 120, 310, 122, 0, 0, + 159, 131, 0, 0, 0, 0, 301, 302, 0, 0, + 0, 0, 0, 0, 856, 0, 54, 0, 0, 268, + 289, 288, 291, 292, 293, 294, 0, 0, 96, 290, + 295, 296, 297, 857, 0, 0, 265, 282, 0, 309, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, + 280, 0, 0, 0, 0, 323, 0, 281, 0, 0, + 276, 277, 278, 283, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 109, 0, 0, 0, 210, 0, 0, + 321, 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, @@ -1577,21 +1295,71 @@ var yyAct = [...]int{ 0, 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, - 154, 98, 176, 158, 0, 75, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 82, 89, 121, 191, 148, 106, 178, - 139, 0, 0, 0, 843, 0, 0, 0, 0, 103, - 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, - 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, - 0, 845, 0, 0, 0, 0, 0, 0, 96, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 154, 98, 176, 158, 311, 322, 317, 318, 315, 316, + 314, 313, 312, 324, 303, 304, 305, 306, 308, 0, + 319, 320, 307, 82, 89, 121, 191, 148, 106, 178, + 139, 0, 0, 789, 0, 270, 0, 0, 0, 103, + 0, 267, 0, 0, 0, 120, 310, 122, 0, 0, + 159, 131, 0, 0, 0, 0, 301, 302, 0, 0, + 0, 0, 0, 0, 0, 0, 54, 0, 0, 268, + 289, 288, 291, 292, 293, 294, 0, 0, 96, 290, + 295, 296, 297, 0, 0, 0, 265, 282, 0, 309, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, + 280, 261, 0, 0, 0, 323, 0, 281, 0, 0, + 276, 277, 278, 283, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, 0, - 0, 0, 146, 0, 162, 111, 119, 83, 90, 0, + 321, 0, 146, 0, 162, 111, 119, 83, 90, 0, + 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, + 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, + 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, + 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, + 101, 138, 168, 169, 100, 193, 91, 180, 88, 92, + 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, + 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, + 0, 0, 0, 160, 177, 194, 94, 0, 165, 184, + 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, + 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, + 154, 98, 176, 158, 311, 322, 317, 318, 315, 316, + 314, 313, 312, 324, 303, 304, 305, 306, 308, 0, + 319, 320, 307, 82, 89, 121, 191, 148, 106, 178, + 139, 0, 0, 0, 0, 270, 0, 0, 0, 103, + 0, 267, 0, 0, 0, 120, 310, 122, 0, 0, + 159, 131, 0, 0, 0, 0, 301, 302, 0, 0, + 0, 0, 0, 0, 0, 0, 54, 0, 498, 268, + 289, 288, 291, 292, 293, 294, 0, 0, 96, 290, + 295, 296, 297, 0, 0, 0, 265, 282, 0, 309, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, + 280, 0, 0, 0, 0, 323, 0, 281, 0, 0, + 276, 277, 278, 283, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 109, 0, 0, 0, 210, 0, 0, + 321, 0, 146, 0, 162, 111, 119, 83, 90, 0, + 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, + 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, + 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, + 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, + 101, 138, 168, 169, 100, 193, 91, 180, 88, 92, + 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, + 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, + 0, 0, 0, 160, 177, 194, 94, 0, 165, 184, + 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, + 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, + 154, 98, 176, 158, 311, 322, 317, 318, 315, 316, + 314, 313, 312, 324, 303, 304, 305, 306, 308, 0, + 319, 320, 307, 82, 89, 121, 191, 148, 106, 178, + 139, 0, 0, 0, 0, 270, 0, 0, 0, 103, + 0, 267, 0, 0, 0, 120, 310, 122, 0, 0, + 159, 131, 0, 0, 0, 0, 301, 302, 0, 0, + 0, 0, 0, 0, 0, 0, 54, 0, 0, 268, + 289, 288, 291, 292, 293, 294, 0, 0, 96, 290, + 295, 296, 297, 0, 0, 0, 265, 282, 0, 309, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 279, + 280, 261, 0, 0, 0, 323, 0, 281, 0, 0, + 276, 277, 278, 283, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 109, 0, 0, 0, 210, 0, 0, + 321, 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, @@ -1602,16 +1370,167 @@ var yyAct = [...]int{ 0, 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, - 154, 98, 176, 158, 0, 0, 0, 0, 0, 24, + 154, 98, 176, 158, 311, 322, 317, 318, 315, 316, + 314, 313, 312, 324, 303, 304, 305, 306, 308, 24, + 319, 320, 307, 82, 89, 121, 191, 148, 106, 178, + 0, 139, 0, 0, 0, 0, 270, 0, 0, 0, + 103, 0, 267, 0, 0, 0, 120, 310, 122, 0, + 0, 159, 131, 0, 0, 0, 0, 301, 302, 0, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 268, 289, 288, 291, 292, 293, 294, 0, 0, 96, + 290, 295, 296, 297, 0, 0, 0, 265, 282, 0, + 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 139, 0, 82, 89, 121, 191, 148, 106, 178, + 279, 280, 0, 0, 0, 0, 323, 0, 281, 0, + 0, 276, 277, 278, 283, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, + 0, 321, 0, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, + 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 311, 322, 317, 318, 315, + 316, 314, 313, 312, 324, 303, 304, 305, 306, 308, + 0, 319, 320, 307, 82, 89, 121, 191, 148, 106, + 178, 139, 0, 0, 0, 0, 270, 0, 0, 0, + 103, 0, 267, 0, 0, 0, 120, 310, 122, 0, + 0, 159, 131, 0, 0, 0, 0, 301, 302, 0, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 268, 289, 288, 291, 292, 293, 294, 0, 0, 96, + 290, 295, 296, 297, 0, 0, 0, 265, 282, 0, + 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 279, 280, 0, 0, 0, 0, 323, 0, 281, 0, + 0, 276, 277, 278, 283, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, + 0, 321, 0, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, + 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 311, 322, 317, 318, 315, + 316, 314, 313, 312, 324, 303, 304, 305, 306, 308, + 0, 319, 320, 307, 82, 89, 121, 191, 148, 106, + 178, 139, 0, 0, 0, 0, 0, 0, 0, 0, + 103, 0, 0, 0, 0, 0, 120, 310, 122, 0, + 0, 159, 131, 0, 0, 0, 0, 301, 302, 0, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 268, 289, 288, 291, 292, 293, 294, 0, 0, 96, + 290, 295, 296, 297, 0, 0, 0, 0, 282, 0, + 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 279, 280, 0, 0, 0, 0, 323, 0, 281, 0, + 0, 276, 277, 278, 283, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, + 0, 321, 0, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, + 153, 141, 175, 1431, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 311, 322, 317, 318, 315, + 316, 314, 313, 312, 324, 303, 304, 305, 306, 308, + 0, 319, 320, 307, 82, 89, 121, 191, 148, 106, + 178, 139, 0, 0, 0, 0, 0, 0, 0, 0, + 103, 0, 0, 0, 0, 0, 120, 310, 122, 0, + 0, 159, 131, 0, 0, 0, 0, 301, 302, 0, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 498, + 268, 289, 288, 291, 292, 293, 294, 0, 0, 96, + 290, 295, 296, 297, 0, 0, 0, 0, 282, 0, + 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 279, 280, 0, 0, 0, 0, 323, 0, 281, 0, + 0, 276, 277, 278, 283, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, + 0, 321, 0, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, + 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 311, 322, 317, 318, 315, + 316, 314, 313, 312, 324, 303, 304, 305, 306, 308, + 0, 319, 320, 307, 82, 89, 121, 191, 148, 106, + 178, 139, 0, 0, 0, 0, 0, 0, 0, 0, + 103, 0, 0, 0, 0, 0, 120, 310, 122, 0, + 0, 159, 131, 0, 0, 0, 0, 301, 302, 0, + 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 268, 289, 288, 291, 292, 293, 294, 0, 0, 96, + 290, 295, 296, 297, 0, 0, 0, 0, 282, 0, + 309, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 279, 280, 0, 0, 0, 0, 323, 0, 281, 0, + 0, 276, 277, 278, 283, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, + 0, 321, 0, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, + 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 311, 322, 317, 318, 315, + 316, 314, 313, 312, 324, 303, 304, 305, 306, 308, + 0, 319, 320, 307, 82, 89, 121, 191, 148, 106, + 178, 139, 0, 0, 0, 0, 0, 0, 0, 0, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 54, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 532, 531, 541, 542, + 534, 535, 536, 537, 538, 539, 540, 533, 0, 0, + 543, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, + 0, 0, 0, 146, 0, 162, 111, 119, 83, 90, + 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, + 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, + 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, + 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, + 107, 101, 138, 168, 169, 100, 193, 91, 180, 88, + 92, 179, 136, 166, 172, 130, 127, 87, 170, 128, + 126, 118, 105, 112, 144, 125, 145, 113, 133, 132, + 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, + 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, + 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, + 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 82, 89, 121, 191, 148, 106, + 178, 139, 0, 0, 0, 520, 0, 0, 0, 0, + 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, + 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 80, 0, 522, 0, 0, 0, 0, 0, 0, 96, + 0, 0, 0, 0, 0, 517, 516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 518, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, @@ -1627,19 +1546,19 @@ var yyAct = [...]int{ 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, - 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 54, 0, - 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, - 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, + 96, 0, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, - 0, 0, 0, 0, 146, 0, 162, 111, 119, 83, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 109, 76, 77, 0, 73, + 0, 0, 0, 78, 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, @@ -1650,7 +1569,7 @@ var yyAct = [...]int{ 132, 134, 0, 0, 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, - 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, + 192, 140, 154, 98, 176, 158, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, 89, 121, 191, 148, 106, 178, 139, 0, 0, 0, 843, 0, 0, 0, @@ -1666,7 +1585,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, 0, 0, 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, - 0, 153, 141, 175, 0, 841, 152, 123, 167, 147, + 0, 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, 168, 169, 100, 193, 91, 180, @@ -1676,12 +1595,12 @@ var yyAct = [...]int{ 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 80, 0, 0, 740, 0, 0, 741, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 54, + 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1700,12 +1619,12 @@ var yyAct = [...]int{ 0, 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 82, 89, 121, 191, - 148, 106, 178, 103, 0, 631, 0, 0, 0, 120, + 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 80, 0, 630, 0, 0, 0, 0, + 54, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1725,12 +1644,37 @@ var yyAct = [...]int{ 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 82, 89, 121, + 191, 148, 106, 178, 139, 0, 0, 0, 843, 0, + 0, 0, 0, 103, 0, 0, 0, 0, 0, 120, + 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 208, 0, 845, 0, 0, 0, 0, + 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, + 0, 210, 0, 0, 0, 0, 146, 0, 162, 111, + 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, + 0, 99, 0, 153, 141, 175, 0, 841, 152, 123, + 167, 147, 174, 182, 183, 164, 181, 190, 84, 163, + 173, 97, 156, 86, 171, 161, 129, 115, 116, 85, + 0, 150, 102, 107, 101, 138, 168, 169, 100, 193, + 91, 180, 88, 92, 179, 136, 166, 172, 130, 127, + 87, 170, 128, 126, 118, 105, 112, 144, 125, 145, + 113, 133, 132, 134, 0, 0, 0, 160, 177, 194, + 94, 0, 165, 184, 185, 186, 187, 188, 189, 0, + 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, + 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 54, 0, 0, 208, 0, 0, 0, 0, 0, - 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 80, 0, 0, 740, 0, 0, + 741, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1750,10 +1694,10 @@ var yyAct = [...]int{ 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, 82, 89, - 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, + 121, 191, 148, 106, 178, 103, 0, 631, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 208, 0, 845, 0, 0, + 0, 0, 0, 0, 0, 80, 0, 630, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1777,7 +1721,7 @@ var yyAct = [...]int{ 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 268, 0, 805, 0, + 0, 0, 0, 54, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1801,7 +1745,7 @@ var yyAct = [...]int{ 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 268, 0, 801, + 0, 0, 0, 0, 0, 0, 0, 208, 0, 845, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1825,8 +1769,8 @@ var yyAct = [...]int{ 0, 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 80, 0, - 522, 0, 0, 0, 0, 0, 0, 96, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 268, 0, + 805, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1846,11 +1790,35 @@ var yyAct = [...]int{ 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 139, 82, 89, 121, 191, 148, 106, 178, 604, + 139, 0, 82, 89, 121, 191, 148, 106, 178, 103, + 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, + 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 268, + 0, 801, 0, 0, 0, 0, 0, 0, 96, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 109, 0, 0, 0, 210, 0, 0, + 0, 0, 146, 0, 162, 111, 119, 83, 90, 0, + 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, + 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, + 183, 164, 181, 190, 84, 163, 173, 97, 156, 86, + 171, 161, 129, 115, 116, 85, 0, 150, 102, 107, + 101, 138, 168, 169, 100, 193, 91, 180, 88, 92, + 179, 136, 166, 172, 130, 127, 87, 170, 128, 126, + 118, 105, 112, 144, 125, 145, 113, 133, 132, 134, + 0, 0, 0, 160, 177, 194, 94, 0, 165, 184, + 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, + 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, + 154, 98, 176, 158, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 139, 0, 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 208, 0, 0, 0, 0, 0, 0, 0, 0, 96, + 80, 0, 522, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1869,33 +1837,9 @@ var yyAct = [...]int{ 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, - 0, 0, 139, 0, 82, 89, 121, 191, 148, 106, - 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, - 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, - 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, - 0, 0, 0, 0, 146, 0, 162, 111, 119, 83, - 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, - 0, 153, 141, 175, 0, 142, 152, 123, 167, 147, - 174, 182, 183, 164, 181, 190, 84, 163, 173, 97, - 156, 86, 171, 161, 129, 115, 116, 85, 0, 150, - 102, 107, 101, 138, 168, 169, 100, 193, 91, 180, - 88, 92, 179, 136, 166, 172, 130, 127, 87, 170, - 128, 126, 118, 105, 112, 144, 125, 145, 113, 133, - 132, 134, 0, 0, 0, 160, 177, 194, 94, 0, - 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, - 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, - 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 139, 0, 82, 89, 121, 191, 148, - 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, + 0, 0, 0, 139, 82, 89, 121, 191, 148, 106, + 178, 604, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, @@ -1904,7 +1848,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 109, 0, 205, 0, + 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 210, 0, 0, 0, 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, 0, 142, 152, 123, 167, @@ -1917,12 +1861,12 @@ var yyAct = [...]int{ 0, 165, 184, 185, 186, 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 327, 0, 0, 0, 0, 0, 0, 139, 0, 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 208, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1953,7 +1897,7 @@ var yyAct = [...]int{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, - 0, 0, 210, 0, 0, 0, 0, 146, 0, 162, + 205, 0, 210, 0, 0, 0, 0, 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, 190, 84, @@ -1970,7 +1914,7 @@ var yyAct = [...]int{ 121, 191, 148, 106, 178, 103, 0, 0, 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 268, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -1990,19 +1934,67 @@ var yyAct = [...]int{ 189, 0, 0, 95, 108, 104, 143, 135, 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 82, - 89, 121, 191, 148, 106, 178, + 0, 0, 0, 0, 0, 0, 0, 139, 0, 82, + 89, 121, 191, 148, 106, 178, 103, 0, 0, 0, + 0, 0, 120, 0, 122, 0, 0, 159, 131, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 208, 0, 0, 0, + 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 109, 0, 0, 0, 210, 0, 0, 0, 0, 146, + 0, 162, 111, 119, 83, 90, 0, 110, 137, 151, + 155, 0, 0, 0, 99, 0, 153, 141, 175, 0, + 142, 152, 123, 167, 147, 174, 182, 183, 164, 181, + 190, 84, 163, 173, 97, 156, 86, 171, 161, 129, + 115, 116, 85, 0, 150, 102, 107, 101, 138, 168, + 169, 100, 193, 91, 180, 88, 92, 179, 136, 166, + 172, 130, 127, 87, 170, 128, 126, 118, 105, 112, + 144, 125, 145, 113, 133, 132, 134, 0, 0, 0, + 160, 177, 194, 94, 0, 165, 184, 185, 186, 187, + 188, 189, 0, 0, 95, 108, 104, 143, 135, 93, + 114, 157, 117, 124, 149, 192, 140, 154, 98, 176, + 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 139, 0, + 82, 89, 121, 191, 148, 106, 178, 103, 0, 0, + 0, 0, 0, 120, 0, 122, 0, 0, 159, 131, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 268, 0, 0, + 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 109, 0, 0, 0, 210, 0, 0, 0, 0, + 146, 0, 162, 111, 119, 83, 90, 0, 110, 137, + 151, 155, 0, 0, 0, 99, 0, 153, 141, 175, + 0, 142, 152, 123, 167, 147, 174, 182, 183, 164, + 181, 190, 84, 163, 173, 97, 156, 86, 171, 161, + 129, 115, 116, 85, 0, 150, 102, 107, 101, 138, + 168, 169, 100, 193, 91, 180, 88, 92, 179, 136, + 166, 172, 130, 127, 87, 170, 128, 126, 118, 105, + 112, 144, 125, 145, 113, 133, 132, 134, 0, 0, + 0, 160, 177, 194, 94, 0, 165, 184, 185, 186, + 187, 188, 189, 0, 0, 95, 108, 104, 143, 135, + 93, 114, 157, 117, 124, 149, 192, 140, 154, 98, + 176, 158, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 82, 89, 121, 191, 148, 106, 178, } var yyPact = [...]int{ - 2429, -1000, -192, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 2229, -1000, -174, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 850, 890, -1000, -1000, -1000, -1000, -1000, -1000, - 333, 8382, 40, 121, 8, 11775, 115, 1357, 12257, -1000, - 10, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -66, -81, - -1000, 658, -1000, -1000, -1000, -1000, -1000, 843, 848, 721, - 834, 757, -1000, 6390, 71, 71, 11534, 5390, -1000, -1000, - 234, 12257, 107, 12257, -155, 67, 67, 67, -1000, -1000, + -1000, -1000, 959, 1019, -1000, -1000, -1000, -1000, -1000, -1000, + 246, 8304, 34, 118, 16, 11697, 113, 1430, 12179, -1000, + 6, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -54, -62, + -1000, 791, -1000, -1000, -1000, -1000, -1000, 951, 962, 828, + 942, 882, -1000, 6312, 69, 69, 11456, 5312, -1000, -1000, + 318, 12179, 102, 12179, -138, 67, 67, 67, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -2014,22 +2006,22 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, 114, 12257, 307, -1000, 12257, - 64, 471, 64, 64, 64, 12257, -1000, 150, -1000, -1000, - -1000, 12257, 467, 794, 3286, 46, 3286, -1000, 3286, 3286, - -1000, 3286, 16, 3286, -62, 863, -1000, -1000, -1000, -1000, - -37, -1000, 3286, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 441, 803, 6891, 6891, - 850, -1000, 658, -1000, -1000, -1000, 780, -1000, -1000, 260, - 876, -1000, 8141, 149, -1000, 6891, 1820, 676, -1000, -1000, - 676, -1000, -1000, 133, -1000, -1000, 7641, 7641, 7641, 7641, - 7641, 7641, 7641, 7641, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 676, -1000, - 6641, 676, 676, 676, 676, 676, 676, 676, 676, 6891, - 676, 676, 676, 676, 676, 676, 676, 676, 676, 676, - 676, 676, 676, 676, 676, 11293, 10087, 12257, 622, -1000, - 659, 5127, -86, -1000, -1000, -1000, 203, 9846, -1000, -1000, - -1000, 793, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, 112, 12179, 225, -1000, 12179, + 66, 568, 66, 66, 66, 12179, -1000, 149, -1000, -1000, + -1000, 12179, 565, 906, 3208, 58, 3208, -1000, 3208, 3208, + -1000, 3208, 13, 3208, -68, 972, -1000, -1000, -1000, -1000, + 2, -1000, 3208, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 450, 911, 6813, 6813, + 959, -1000, 791, -1000, -1000, -1000, 905, -1000, -1000, 345, + 981, -1000, 8063, 146, -1000, 6813, 1832, 479, -1000, -1000, + 479, -1000, -1000, 135, -1000, -1000, 7563, 7563, 7563, 7563, + 7563, 7563, 7563, 7563, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 479, -1000, + 6563, 479, 479, 479, 479, 479, 479, 479, 479, 6813, + 479, 479, 479, 479, 479, 479, 479, 479, 479, 479, + 479, 479, 479, 479, 479, 11215, 10009, 12179, 657, -1000, + 722, 5049, -119, -1000, -1000, -1000, 248, 9768, -1000, -1000, + -1000, 904, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, @@ -2038,131 +2030,131 @@ var yyPact = [...]int{ -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 595, 12257, - -1000, 2218, -1000, 461, 3286, 80, 459, 221, 457, 12257, - 12257, 3286, 24, 57, 113, 12257, 664, 78, 12257, 829, - 720, 12257, 455, 448, -1000, 4864, -1000, 3286, 3286, -1000, - -1000, -1000, 3286, 3286, 3286, 3286, 3286, 3286, -1000, -1000, - -1000, -1000, 3286, 3286, -1000, 872, 263, -1000, -1000, -1000, - -1000, 6891, -1000, 719, -1000, -1000, -1000, -1000, -1000, -1000, - 885, 175, 523, 147, 661, -1000, 447, 843, 441, 757, - 9605, 701, -1000, -1000, 12257, -1000, 6891, 6891, 379, -1000, - 11051, -1000, -1000, 3812, 184, 7641, 352, 231, 7641, 7641, - 7641, 7641, 7641, 7641, 7641, 7641, 7641, 7641, 7641, 7641, - 7641, 7641, 7641, 362, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, 445, -1000, 658, 548, 548, 159, 159, 159, - 159, 159, 159, 159, 7891, 5890, 441, 593, 204, 6641, - 6390, 6390, 6891, 6891, 10810, 10569, 6390, 836, 210, 204, - 12498, -1000, -1000, 7391, -1000, -1000, -1000, -1000, -1000, 441, - -1000, -1000, -1000, -1000, -1000, -1000, -1000, 12016, 12016, 6390, - 6390, 6390, 6390, 35, 12257, -1000, 549, 690, -1000, -1000, - -1000, 831, 9114, 9364, 35, 600, 10087, 12257, -1000, -1000, - 4601, 659, -86, 625, -1000, -129, -91, 5640, 142, -1000, - -1000, -1000, -1000, 3023, 212, 503, 279, -53, -1000, -1000, - -1000, 691, -1000, 691, 691, 691, 691, -17, -17, -17, - -17, -1000, -1000, -1000, -1000, -1000, 705, 704, -1000, 691, - 691, 691, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, 638, 12179, + -1000, 1945, -1000, 562, 3208, 80, 545, 310, 540, 12179, + 12179, 3208, 21, 51, 105, 12179, 744, 73, 12179, 936, + 812, 12179, 537, 535, -1000, 4786, -1000, 3208, 3208, -1000, + -1000, -1000, 3208, 3208, 3208, 12179, 3208, 3208, -1000, -1000, + -1000, -1000, 3208, 3208, -1000, 980, 281, -1000, -1000, -1000, + -1000, 6813, -1000, 809, -1000, -1000, -1000, -1000, -1000, -1000, + 1012, 158, 452, 143, 743, -1000, 382, 951, 450, 882, + 9527, 800, -1000, -1000, 12179, -1000, 6813, 6813, 343, -1000, + 10973, -1000, -1000, 3734, 210, 7563, 385, 306, 7563, 7563, + 7563, 7563, 7563, 7563, 7563, 7563, 7563, 7563, 7563, 7563, + 7563, 7563, 7563, 451, -1000, -1000, -1000, -1000, -1000, -1000, + -1000, -1000, 510, -1000, 791, 978, 978, 163, 163, 163, + 163, 163, 163, 163, 7813, 5812, 450, 626, 371, 6563, + 6312, 6312, 6813, 6813, 10732, 10491, 6312, 944, 265, 371, + 12420, -1000, -1000, 7313, -1000, -1000, -1000, -1000, -1000, 450, + -1000, -1000, -1000, -1000, -1000, -1000, -1000, 11938, 11938, 6312, + 6312, 6312, 6312, 36, 12179, -1000, 647, 810, -1000, -1000, + -1000, 938, 9036, 9286, 36, 675, 10009, 12179, -1000, -1000, + 4523, 722, -119, 686, -1000, -84, -101, 5562, 159, -1000, + -1000, -1000, -1000, 2945, 357, 596, 393, -48, -1000, -1000, + -1000, 749, -1000, 749, 749, 749, 749, -20, -20, -20, + -20, -1000, -1000, -1000, -1000, -1000, 779, 778, -1000, 749, + 749, 749, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 700, 700, 700, 693, 693, 675, -1000, 12257, 3286, 827, - 3286, -1000, 91, -1000, 12016, 12016, 12257, 12257, 128, 12257, - 12257, 656, -1000, 12257, 3286, -1000, -1000, -1000, -1000, -1000, + 777, 777, 777, 752, 752, 785, -1000, 12179, 3208, 935, + 3208, -1000, 122, -1000, 11938, 11938, 12179, 12179, 127, 12179, + 12179, 718, -1000, 12179, 3208, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 12257, 256, 12257, 12257, 204, 12257, -1000, 714, 6891, 6891, - 4338, 6891, -1000, -1000, -1000, 803, -1000, 836, 847, -1000, - 786, 785, 6390, -1000, -1000, 184, 284, -1000, -1000, 440, - -1000, -1000, -1000, -1000, 145, 676, -1000, 2206, -1000, -1000, - -1000, -1000, 352, 7641, 7641, 7641, 710, 2206, 2189, 335, - 473, 159, 261, 261, 168, 168, 168, 168, 168, 388, - 388, -1000, -1000, -1000, 441, -1000, -1000, -1000, 441, 6390, - 632, -1000, -1000, 6891, -1000, 441, 582, 582, 391, 460, - 674, 670, -1000, 144, 655, 654, 582, 6390, 225, -1000, - 6891, 441, -1000, 1936, 631, 627, 582, 441, 582, 582, - 638, 676, -1000, 12498, 10087, 10087, 10087, 10087, 10087, -1000, - 747, 745, -1000, 744, 741, 732, 12257, -1000, 584, 9114, - 143, 676, -1000, 10328, -1000, -1000, 862, 10087, 648, -1000, - -1000, 625, -86, -80, -1000, -1000, -1000, -1000, 204, -1000, - 384, 624, 2760, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 699, 442, -1000, 815, 185, 207, 436, 813, -1000, -1000, - -1000, 806, -1000, 240, -57, -1000, -1000, 366, -17, -17, - -1000, -1000, 142, 791, 142, 142, 142, 420, 420, -1000, - -1000, -1000, -1000, 365, -1000, -1000, -1000, 315, -1000, 718, - 12016, 3286, -1000, -1000, -1000, -1000, 182, 182, 230, -1000, + 12179, 296, 12179, 12179, 371, 12179, -1000, 863, 6813, 6813, + 4260, 6813, -1000, -1000, -1000, 911, -1000, 944, 958, -1000, + 879, 876, 6312, -1000, -1000, 210, 250, -1000, -1000, 431, + -1000, -1000, -1000, -1000, 141, 479, -1000, 1903, -1000, -1000, + -1000, -1000, 385, 7563, 7563, 7563, 334, 1903, 1867, 1357, + 186, 163, 652, 652, 230, 230, 230, 230, 230, 572, + 572, -1000, -1000, -1000, 450, -1000, -1000, -1000, 450, 6312, + 711, -1000, -1000, 6813, -1000, 450, 601, 601, 531, 420, + 747, 738, -1000, 140, 721, 714, 601, 6312, 303, -1000, + 6813, 450, -1000, 900, 693, 687, 601, 450, 601, 601, + 703, 479, -1000, 12420, 10009, 10009, 10009, 10009, 10009, -1000, + 848, 846, -1000, 844, 836, 864, 12179, -1000, 604, 9036, + 152, 479, -1000, 10250, -1000, -1000, 971, 10009, 635, -1000, + -1000, 686, -119, -86, -1000, -1000, -1000, -1000, 371, -1000, + 477, 685, 2681, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 766, 478, -1000, 924, 193, 188, 469, 923, -1000, -1000, + -1000, 915, -1000, 324, -50, -1000, -1000, 412, -20, -20, + -1000, -1000, 159, 899, 159, 159, 159, 443, 443, -1000, + -1000, -1000, -1000, 398, -1000, -1000, -1000, 397, -1000, 805, + 11938, 3208, -1000, -1000, -1000, -1000, 173, 173, 209, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 34, 550, -1000, -1000, -1000, 21, 20, 73, -1000, 3286, - -1000, 263, -1000, 411, 6891, -1000, -1000, -1000, 761, 204, - 204, 141, -1000, -1000, 12257, -1000, -1000, -1000, -1000, 647, - -1000, -1000, -1000, 3549, 6390, -1000, 710, 2206, 1951, -1000, - 7641, 7641, -1000, -1000, 582, 6390, 204, -1000, -1000, -1000, - 43, 362, 43, 7641, 7641, 7641, 7641, 4338, 7641, 7641, - 7641, 7641, -169, 652, 209, -1000, 6891, 434, -1000, -1000, - 7641, 7641, -1000, -1000, -1000, -1000, 715, 12498, 676, -1000, - 8873, 12016, 651, -1000, 202, 690, 698, 713, 952, -1000, - -1000, -1000, -1000, 743, -1000, 731, -1000, -1000, -1000, -1000, - -1000, 106, 102, 94, 12016, -1000, 850, 6891, 648, -1000, - -1000, -1000, -135, -141, -1000, -1000, -1000, 3023, -1000, 3023, - 12016, 51, -1000, 436, 436, -1000, -1000, -1000, 694, 712, - 7641, -1000, -1000, -1000, 491, 142, 142, -1000, 208, -1000, - -1000, -1000, 572, -1000, 569, 621, 564, 12257, -1000, -1000, + 35, 782, -1000, -1000, -1000, 20, 19, 72, -1000, 3208, + -1000, 281, -1000, 437, 6813, -1000, -1000, -1000, 858, 371, + 371, 139, -1000, -1000, 12179, -1000, -1000, -1000, -1000, 705, + -1000, -1000, -1000, 3471, 6312, -1000, 334, 1903, 1581, -1000, + 7563, 7563, -1000, -1000, 601, 6312, 371, -1000, -1000, -1000, + 45, 451, 45, 7563, 7563, 7563, 7563, 4260, 7563, 7563, + 7563, 7563, -151, 628, 260, -1000, 6813, 374, -1000, -1000, + 7563, 7563, -1000, -1000, -1000, -1000, 798, 12420, 479, -1000, + 8795, 11938, 717, -1000, 247, 810, 771, 797, 1647, -1000, + -1000, -1000, -1000, 835, -1000, 823, -1000, -1000, -1000, -1000, + -1000, 87, 86, 83, 11938, -1000, 959, 6813, 635, -1000, + -1000, -1000, -93, -107, -1000, -1000, -1000, 2945, -1000, 2945, + 11938, 47, -1000, 469, 469, -1000, -1000, -1000, 753, 795, + 7563, -1000, -1000, -1000, 556, 159, 159, -1000, 211, -1000, + -1000, -1000, 595, -1000, 580, 684, 575, 12179, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - -1000, -1000, -1000, -1000, 12257, -1000, -1000, -1000, -1000, -1000, - 12016, -179, 424, 12016, 12016, 12257, -1000, 256, -1000, 204, - -1000, 4075, -1000, 862, 10087, -1000, -1000, 441, -1000, 7641, - 2206, 2206, -1000, -1000, 441, 691, 691, -1000, 691, 693, - -1000, 691, 1, 691, 0, 441, 441, 1887, 2174, 1729, - 2156, -1000, 1636, 1980, 1346, 1657, 676, -162, -1000, 204, - 6891, 2067, 2017, -1000, 818, 542, 601, -1000, -1000, 6140, - 441, 546, 138, 534, -1000, 850, 12498, 6891, -1000, -1000, - 6891, 692, -1000, 6891, -1000, -1000, -1000, 676, 676, 676, - 534, 843, 204, -1000, -1000, -1000, -1000, 2760, -1000, 531, - -1000, 691, -1000, -1000, -1000, 12016, -49, 883, 2206, -1000, - -1000, -1000, -1000, -1000, -17, 408, -17, 312, -1000, 280, - 3286, -1000, -1000, -1000, -1000, 821, -1000, 4075, -1000, -1000, - 686, -1000, -1000, -1000, 858, 619, -1000, 2206, -1000, -1000, - 111, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 7641, 7641, -1000, 7641, 7641, -1000, 7641, 7641, -1000, 7641, - 7641, 7641, 441, 399, 204, 7641, 7641, 811, -1000, 676, - -1000, -1000, 639, 12016, 12016, -1000, 12016, 843, -1000, 204, - 204, 12016, 204, 12016, 12016, 12016, 8632, -1000, 137, 12016, - -1000, 529, -1000, 188, -1000, -106, 142, -1000, 142, 488, - 475, -1000, 676, 602, -1000, 200, 12016, 854, 846, -1000, - -1000, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 1936, 15, - -1000, -1000, 1936, 1936, 881, -1000, 676, -1000, 658, 122, - -1000, -1000, -1000, 508, 502, 502, 502, 143, 137, -1000, - 309, 199, 369, -1000, 47, 12016, 236, 810, -1000, 804, - -1000, -1000, -1000, -1000, -1000, 33, 4075, 3023, 487, -1000, - 6891, 6891, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, - 441, 42, -182, -1000, -1000, 12498, 601, 441, 12016, -1000, - -1000, -1000, -1000, -1000, -1000, -1000, 269, -1000, -1000, 12257, - -1000, -1000, 308, -1000, -1000, 484, -1000, 12016, -1000, -1000, - 550, 204, 599, -1000, 760, -177, -186, 537, -1000, -1000, - -1000, 683, -1000, -1000, 33, 781, -179, -1000, 753, -1000, - 12016, -1000, 30, -1000, -180, 482, 28, -184, 711, 676, - -187, 708, -1000, 867, 7141, -1000, -1000, 869, 198, 198, - 1936, 441, -1000, -1000, -1000, 56, 306, -1000, -1000, -1000, + -1000, -1000, -1000, -1000, 12179, -1000, -1000, -1000, -1000, -1000, + 11938, -161, 460, 11938, 11938, 12179, -1000, 296, -1000, 371, + -1000, 3997, -1000, 971, 10009, -1000, -1000, 450, -1000, 7563, + 1903, 1903, -1000, -1000, 450, 749, 749, -1000, 749, 752, + -1000, 749, -3, 749, -4, 450, 450, 715, 2203, 688, + 2148, -1000, 476, 1939, 449, 1418, 479, -146, -1000, 371, + 6813, 1396, 1373, -1000, 926, 656, 672, -1000, -1000, 6062, + 450, 573, 134, 555, -1000, 959, 12420, 6813, -1000, -1000, + 6813, 751, -1000, 6813, -1000, -1000, -1000, 479, 479, 479, + 555, 951, 371, -1000, -1000, -1000, -1000, 2681, -1000, 553, + -1000, 749, -1000, -1000, -1000, 11938, -44, 1009, 1903, -1000, + -1000, -1000, -1000, -1000, -20, 432, -20, 388, -1000, 358, + 3208, -1000, -1000, -1000, -1000, 928, -1000, 3997, -1000, -1000, + 746, -1000, -1000, -1000, 967, 683, -1000, 1903, -1000, -1000, + 109, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 7563, 7563, -1000, 7563, 7563, -1000, 7563, 7563, -1000, 7563, + 7563, 7563, 450, 429, 371, 7563, 7563, 921, -1000, 479, + -1000, -1000, 713, 11938, 11938, -1000, 11938, 951, -1000, 371, + 371, 11938, 371, 11938, 11938, 11938, 8554, -1000, 138, 11938, + -1000, 551, -1000, 165, -1000, -157, 159, -1000, 159, 533, + 508, -1000, 479, 680, -1000, 243, 11938, 965, 954, -1000, + -1000, 900, 900, 900, 900, 900, 900, 900, 900, 27, + -1000, -1000, 900, 900, 1006, -1000, 479, -1000, 791, 120, + -1000, -1000, -1000, 532, 507, 507, 507, 152, 138, -1000, + 455, 239, 426, -1000, 49, 11938, 335, 918, -1000, 917, + -1000, -1000, -1000, -1000, -1000, 33, 3997, 2945, 504, -1000, + 6813, 6813, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000, + 450, 60, -166, -1000, -1000, 12420, 672, 450, 11938, -1000, + -1000, -1000, -1000, -1000, -1000, -1000, 355, -1000, -1000, 12179, + -1000, -1000, 423, -1000, -1000, 502, -1000, 11938, -1000, -1000, + 782, 371, 659, -1000, 856, -155, -170, 648, -1000, -1000, + -1000, 653, -1000, -1000, 33, 871, -161, -1000, 853, -1000, + 11938, -1000, 29, -1000, -164, 499, 26, -167, 794, 479, + -171, 790, -1000, 979, 7063, -1000, -1000, 1001, 179, 179, + 900, 450, -1000, -1000, -1000, 57, 326, -1000, -1000, -1000, -1000, -1000, -1000, } var yyPgo = [...]int{ - 0, 1125, 30, 457, 1123, 1122, 1121, 1120, 1118, 1114, - 1113, 1111, 1110, 1109, 1103, 1102, 1100, 1094, 1093, 1091, - 1090, 1089, 1087, 1085, 1084, 1083, 97, 1082, 1081, 1076, - 65, 1071, 71, 1068, 1067, 47, 59, 45, 40, 1207, - 1065, 25, 56, 102, 1064, 34, 1060, 1052, 75, 1049, - 53, 1045, 1044, 429, 1043, 1042, 13, 33, 1040, 1039, - 1038, 1037, 66, 886, 1036, 1033, 16, 1032, 1031, 101, - 1029, 55, 3, 12, 21, 22, 1028, 229, 7, 1027, - 52, 1024, 1021, 1018, 1008, 29, 1007, 58, 1006, 17, - 57, 1002, 24, 63, 35, 19, 5, 73, 61, 999, - 15, 62, 54, 993, 990, 461, 987, 986, 46, 985, - 984, 26, 166, 377, 983, 980, 979, 978, 38, 0, - 498, 128, 70, 977, 970, 969, 1490, 69, 49, 18, - 965, 42, 1493, 43, 963, 962, 37, 961, 960, 959, - 957, 956, 954, 953, 134, 952, 951, 949, 20, 41, - 948, 946, 60, 23, 945, 942, 941, 48, 64, 939, - 935, 51, 44, 933, 932, 930, 924, 923, 27, 9, - 922, 14, 920, 10, 918, 28, 916, 2, 915, 11, - 914, 6, 913, 4, 50, 1, 908, 8, 901, 900, - 77, 494, 897, 896, 94, + 0, 1255, 54, 479, 1254, 1253, 1251, 1249, 1248, 1246, + 1243, 1241, 1235, 1234, 1230, 1228, 1227, 1222, 1220, 1219, + 1214, 1213, 1212, 1210, 1209, 1207, 117, 1206, 1202, 1200, + 75, 1199, 83, 1198, 1197, 38, 61, 41, 40, 1285, + 1195, 50, 56, 73, 1191, 28, 1185, 1184, 81, 1183, + 53, 1164, 1161, 1569, 1159, 1158, 12, 30, 1157, 1155, + 1153, 1152, 70, 637, 1150, 1149, 14, 1148, 1147, 86, + 1146, 58, 8, 13, 11, 24, 1145, 314, 15, 1138, + 59, 1137, 1136, 1135, 1134, 20, 1133, 62, 1131, 19, + 60, 1129, 7, 65, 29, 25, 5, 84, 69, 1128, + 23, 66, 51, 1126, 1124, 516, 1123, 1122, 48, 1121, + 1120, 22, 175, 387, 1118, 1117, 1116, 1114, 37, 0, + 498, 44, 80, 1110, 1107, 1103, 1376, 71, 52, 18, + 1102, 31, 171, 47, 1100, 1099, 34, 1098, 1093, 1091, + 1090, 1089, 1088, 1087, 118, 1086, 1084, 1082, 35, 42, + 1076, 1072, 63, 21, 1071, 1070, 1068, 49, 64, 1066, + 1062, 57, 26, 1061, 1060, 1059, 1058, 1055, 27, 17, + 1053, 16, 1052, 10, 1049, 33, 1044, 3, 1042, 9, + 1034, 6, 1033, 4, 43, 1, 1031, 2, 1030, 1028, + 45, 419, 1027, 1026, 107, } var yyR1 = [...]int{ @@ -2415,7 +2407,7 @@ var yyChk = [...]int{ 175, 176, 177, 178, 179, 57, -132, 125, 57, 74, 57, -53, -53, -132, 157, 157, 123, 123, -53, 55, 126, -48, 23, 52, -53, 57, 57, -127, -126, -118, - -132, -132, -132, -132, -132, -132, -132, -132, -132, -132, + -132, -132, -132, -132, -132, -53, -132, -132, -132, -132, 11, -108, 11, 92, -39, 52, 9, 92, 55, 18, 112, 55, -88, 24, 25, -89, -191, -32, -64, -120, 60, 63, -31, 43, -53, -39, -39, -70, 68, 74, @@ -2539,7 +2531,7 @@ var yyDef = [...]int{ 81, 0, 79, 0, 856, 0, 0, 0, 0, 0, 0, 856, 0, 0, 0, 0, 241, 0, 0, 0, 0, 0, 0, 0, 249, 0, 251, 856, 856, 254, - 857, 858, 856, 856, 856, 856, 856, 856, 261, 263, + 857, 858, 856, 856, 856, 0, 856, 856, 261, 263, 264, 266, 856, 856, 268, 0, 289, 287, 288, 283, 284, 0, 278, 279, 282, 309, 310, 30, 854, 24, 0, 0, 569, 0, 561, 562, 565, 568, 29, 319, @@ -4463,7 +4455,7 @@ yydefault: yyDollar = yyS[yypt-4 : yypt+1] //line sql.y:1473 { - yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes)} + yyVAL.statement = &Show{Type: string(yyDollar[2].bytes) + " " + string(yyDollar[3].bytes), Table: yyDollar[4].tableName} } case 259: yyDollar = yyS[yypt-4 : yypt+1] diff --git a/go/vt/sqlparser/sql.y b/go/vt/sqlparser/sql.y index 149781ad6f1..f657ab8326a 100644 --- a/go/vt/sqlparser/sql.y +++ b/go/vt/sqlparser/sql.y @@ -1469,9 +1469,9 @@ show_statement: { $$ = &Show{Type: string($2) + " " + string($3)} } -| SHOW CREATE TABLE ddl_skip_to_end +| SHOW CREATE TABLE table_name { - $$ = &Show{Type: string($2) + " " + string($3)} + $$ = &Show{Type: string($2) + " " + string($3), Table: $4} } | SHOW CREATE TRIGGER ddl_skip_to_end { diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index 9eafc481079..8ebddca2055 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -747,6 +747,25 @@ func (e *Executor) handleShow(ctx context.Context, safeSession *SafeSession, sql Rows: rows, RowsAffected: 2, }, nil + case "create table": + if destKeyspace == "" && show.HasTable() { + // For "show create table", if there isn't a targeted keyspace already + // we can either get a keyspace from the statement or potentially from + // the vschema. + + if !show.Table.Qualifier.IsEmpty() { + // Explicit keyspace was passed. Use that for targeting but remove from the query itself. + destKeyspace = show.Table.Qualifier.String() + show.Table.Qualifier = sqlparser.NewTableIdent("") + sql = sqlparser.String(show) + } else { + // No keyspace was indicated. Try to find one using the vschema. + tbl, err := e.VSchema().FindTable("", show.Table.Name.String()) + if err == nil { + destKeyspace = tbl.Keyspace.Name + } + } + } case sqlparser.KeywordString(sqlparser.TABLES): if show.ShowTablesOpt != nil && show.ShowTablesOpt.DbName != "" { if destKeyspace == "" { diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index 1eb6d50aec0..365bfd55d52 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -674,6 +674,34 @@ func TestExecutorShow(t *testing.T) { t.Errorf("%v:\n%+v, want\n%+v", query, qr, wantqr) } + qr, err = executor.Execute(context.Background(), "TestExecute", session, "show create table unknown_table", nil) + if err != errNoKeyspace { + t.Errorf("Got: %v. Want: %v", err, errNoKeyspace) + } + + // SHOW CREATE table using vschema to find keyspace. + _, err = executor.Execute(context.Background(), "TestExecute", session, "show create table user_seq", nil) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + lastQuery := sbclookup.Queries[len(sbclookup.Queries)-1].Sql + wantQuery := "show create table user_seq" + if lastQuery != wantQuery { + t.Errorf("Got: %v. Want: %v", lastQuery, wantQuery) + } + + // SHOW CREATE table with query-provided keyspace + _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show create table %v.unknown", KsTestUnsharded), nil) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + lastQuery = sbclookup.Queries[len(sbclookup.Queries)-1].Sql + wantQuery = "show create table unknown" + if lastQuery != wantQuery { + t.Errorf("Got: %v. Want: %v", lastQuery, wantQuery) + } + for _, query := range []string{"show charset", "show charset like '%foo'", "show character set", "show character set like '%foo'"} { qr, err := executor.Execute(context.Background(), "TestExecute", session, query, nil) if err != nil { From e1ed744b18a976fc70f1021302ebb1212d2471bf Mon Sep 17 00:00:00 2001 From: deepthi Date: Mon, 18 Mar 2019 21:23:40 -0700 Subject: [PATCH 191/196] delete old website files, fix license in package.json Signed-off-by: deepthi --- vitess.io/.gitignore | 1 - vitess.io/CNAME | 1 - vitess.io/Gemfile | 27 - vitess.io/Gemfile.lock | 117 - vitess.io/Gruntfile.js | 95 - vitess.io/LICENSE | 21 - vitess.io/_config.yml | 45 - vitess.io/_config_dev.yml | 44 - vitess.io/_data/authors.yml | 11 - vitess.io/_data/footer.yml | 7 - vitess.io/_data/nav.yml | 24 - vitess.io/_data/navigation.yml | 21 - vitess.io/_includes/analytics.liquid | 8 - vitess.io/_includes/breadcrumbs.html | 13 - .../_includes/collection-pagination.html | 15 - vitess.io/_includes/comments.html | 14 - vitess.io/_includes/doc | 1 - vitess.io/_includes/end-of-page-styles.liquid | 9 - vitess.io/_includes/footer.html | 8 - vitess.io/_includes/google-analytics.html | 8 - vitess.io/_includes/header.html | 8 - vitess.io/_includes/image-credit.html | 1 - vitess.io/_includes/latest-posts-grid.html | 9 - vitess.io/_includes/latest-posts-list.html | 7 - vitess.io/_includes/left-nav-menu.html | 107 - vitess.io/_includes/meta.liquid | 21 - vitess.io/_includes/nav.html | 34 - vitess.io/_includes/nav.liquid | 9 - vitess.io/_includes/navigation-sliding.html | 17 - vitess.io/_includes/navigation.html | 11 - vitess.io/_includes/open-graph.html | 19 - vitess.io/_includes/page-author.html | 11 - vitess.io/_includes/page-meta.html | 3 - vitess.io/_includes/pagination.html | 15 - vitess.io/_includes/post-grid.html | 8 - vitess.io/_includes/post-list-bullets.html | 13 - vitess.io/_includes/post-list.html | 1 - vitess.io/_includes/scripts.liquid | 1 - vitess.io/_includes/scroll-cue.html | 3 - vitess.io/_includes/share-this.html | 5 - vitess.io/_includes/styles.liquid | 24 - vitess.io/_includes/toc.liquid | 23 - vitess.io/_layouts/archive.html | 25 - vitess.io/_layouts/article.html | 35 - vitess.io/_layouts/base.liquid | 33 - vitess.io/_layouts/default.liquid | 19 - vitess.io/_layouts/doc.liquid | 22 - vitess.io/_layouts/home.liquid | 26 - vitess.io/_redirects | 2 - vitess.io/_sass/_animations.scss | 30 - vitess.io/_sass/_badges.scss | 48 - vitess.io/_sass/_base.scss | 355 - vitess.io/_sass/_bullets.scss | 49 - vitess.io/_sass/_buttons.scss | 122 - vitess.io/_sass/_gist.scss | 20 - vitess.io/_sass/_grid-settings.scss | 11 - vitess.io/_sass/_helpers.scss | 123 - vitess.io/_sass/_layout.scss | 471 -- vitess.io/_sass/_mixins.scss | 94 - vitess.io/_sass/_notices.scss | 38 - vitess.io/_sass/_pygments.scss | 104 - vitess.io/_sass/_reset.scss | 143 - vitess.io/_sass/_sliding-menu.scss | 257 - vitess.io/_sass/_variables.scss | 82 - .../bourbon/_bourbon-deprecated-upcoming.scss | 8 - vitess.io/_sass/vendor/bourbon/_bourbon.scss | 78 - .../_sass/vendor/bourbon/addons/_button.scss | 374 - .../vendor/bourbon/addons/_clearfix.scss | 23 - .../bourbon/addons/_directional-values.scss | 111 - .../vendor/bourbon/addons/_ellipsis.scss | 7 - .../vendor/bourbon/addons/_font-family.scss | 5 - .../vendor/bourbon/addons/_hide-text.scss | 10 - .../bourbon/addons/_html5-input-types.scss | 86 - .../vendor/bourbon/addons/_position.scss | 32 - .../vendor/bourbon/addons/_prefixer.scss | 45 - .../vendor/bourbon/addons/_retina-image.scss | 31 - .../_sass/vendor/bourbon/addons/_size.scss | 16 - .../bourbon/addons/_timing-functions.scss | 32 - .../vendor/bourbon/addons/_triangle.scss | 83 - .../vendor/bourbon/addons/_word-wrap.scss | 8 - .../_sass/vendor/bourbon/css3/_animation.scss | 52 - .../vendor/bourbon/css3/_appearance.scss | 3 - .../bourbon/css3/_backface-visibility.scss | 6 - .../bourbon/css3/_background-image.scss | 42 - .../vendor/bourbon/css3/_background.scss | 55 - .../vendor/bourbon/css3/_border-image.scss | 59 - .../vendor/bourbon/css3/_border-radius.scss | 22 - .../vendor/bourbon/css3/_box-sizing.scss | 4 - .../_sass/vendor/bourbon/css3/_calc.scss | 4 - .../_sass/vendor/bourbon/css3/_columns.scss | 47 - .../_sass/vendor/bourbon/css3/_filter.scss | 5 - .../_sass/vendor/bourbon/css3/_flex-box.scss | 321 - .../_sass/vendor/bourbon/css3/_font-face.scss | 23 - .../bourbon/css3/_font-feature-settings.scss | 10 - .../bourbon/css3/_hidpi-media-query.scss | 10 - .../_sass/vendor/bourbon/css3/_hyphens.scss | 4 - .../vendor/bourbon/css3/_image-rendering.scss | 14 - .../_sass/vendor/bourbon/css3/_keyframes.scss | 35 - .../vendor/bourbon/css3/_linear-gradient.scss | 38 - .../vendor/bourbon/css3/_perspective.scss | 8 - .../vendor/bourbon/css3/_placeholder.scss | 8 - .../vendor/bourbon/css3/_radial-gradient.scss | 39 - .../_sass/vendor/bourbon/css3/_transform.scss | 15 - .../vendor/bourbon/css3/_transition.scss | 77 - .../vendor/bourbon/css3/_user-select.scss | 3 - .../vendor/bourbon/functions/_assign.scss | 11 - .../bourbon/functions/_color-lightness.scss | 13 - .../vendor/bourbon/functions/_flex-grid.scss | 39 - .../bourbon/functions/_golden-ratio.scss | 3 - .../vendor/bourbon/functions/_grid-width.scss | 13 - .../bourbon/functions/_modular-scale.scss | 66 - .../vendor/bourbon/functions/_px-to-em.scss | 13 - .../vendor/bourbon/functions/_px-to-rem.scss | 15 - .../bourbon/functions/_strip-units.scss | 5 - .../vendor/bourbon/functions/_tint-shade.scss | 9 - .../functions/_transition-property-name.scss | 22 - .../vendor/bourbon/functions/_unpack.scss | 17 - .../bourbon/helpers/_convert-units.scss | 15 - .../helpers/_gradient-positions-parser.scss | 13 - .../_sass/vendor/bourbon/helpers/_is-num.scss | 8 - .../bourbon/helpers/_linear-angle-parser.scss | 25 - .../helpers/_linear-gradient-parser.scss | 41 - .../helpers/_linear-positions-parser.scss | 61 - .../helpers/_linear-side-corner-parser.scss | 31 - .../bourbon/helpers/_radial-arg-parser.scss | 69 - .../helpers/_radial-gradient-parser.scss | 50 - .../helpers/_radial-positions-parser.scss | 18 - .../bourbon/helpers/_render-gradients.scss | 26 - .../bourbon/helpers/_shape-size-stripper.scss | 10 - .../vendor/bourbon/helpers/_str-to-num.scss | 50 - .../vendor/bourbon/settings/_prefixer.scss | 6 - .../vendor/bourbon/settings/_px-to-em.scss | 1 - .../_sass/vendor/neat/_neat-helpers.scss | 7 - vitess.io/_sass/vendor/neat/_neat.scss | 21 - .../neat/functions/_new-breakpoint.scss | 16 - .../_sass/vendor/neat/functions/_private.scss | 125 - .../_sass/vendor/neat/grid/_fill-parent.scss | 7 - vitess.io/_sass/vendor/neat/grid/_grid.scss | 5 - vitess.io/_sass/vendor/neat/grid/_media.scss | 38 - vitess.io/_sass/vendor/neat/grid/_omega.scss | 61 - .../vendor/neat/grid/_outer-container.scss | 8 - vitess.io/_sass/vendor/neat/grid/_pad.scss | 8 - .../_sass/vendor/neat/grid/_private.scss | 43 - vitess.io/_sass/vendor/neat/grid/_reset.scss | 12 - vitess.io/_sass/vendor/neat/grid/_row.scss | 17 - vitess.io/_sass/vendor/neat/grid/_shift.scss | 16 - .../_sass/vendor/neat/grid/_span-columns.scss | 43 - .../_sass/vendor/neat/grid/_to-deprecate.scss | 57 - .../_sass/vendor/neat/grid/_visual-grid.scss | 41 - .../_sass/vendor/neat/settings/_grid.scss | 7 - .../vendor/neat/settings/_visual-grid.scss | 5 - vitess.io/_templates/archive | 11 - vitess.io/_templates/page | 12 - vitess.io/_templates/post | 12 - vitess.io/advanced/index.md | 16 - vitess.io/advanced/messaging.md | 16 - vitess.io/assets/scripts/jquery-1.8.3.min.js | 2 - vitess.io/assets/scripts/jquery-ui.min.js | 9 - vitess.io/assets/scripts/main.js | 57 - vitess.io/assets/scripts/modernizr.js | 4 - vitess.io/assets/vendor/images/hamburger.svg | 1 - .../vendor/images/icons/icons-hinted.ttf | 0 .../assets/vendor/images/icons/icons.eot | Bin 3528 -> 0 bytes .../assets/vendor/images/icons/icons.svg | 1 - .../assets/vendor/images/icons/icons.ttf | Bin 3364 -> 0 bytes .../assets/vendor/images/icons/icons.woff | Bin 2292 -> 0 bytes .../assets/vendor/images/icons/icons.woff2 | Bin 1572 -> 0 bytes vitess.io/assets/vendor/styles/wsk.css | 1 - .../wsk/0.4.0/images/icons/icons-hinted.ttf | 0 .../vendor/wsk/0.4.0/images/icons/icons.eot | Bin 3528 -> 0 bytes .../vendor/wsk/0.4.0/images/icons/icons.svg | 1 - .../vendor/wsk/0.4.0/images/icons/icons.ttf | Bin 3364 -> 0 bytes .../vendor/wsk/0.4.0/images/icons/icons.woff | Bin 2292 -> 0 bytes .../vendor/wsk/0.4.0/images/icons/icons.woff2 | Bin 1572 -> 0 bytes .../assets/vendor/wsk/0.4.0/styles/wsk.css | 1 - vitess.io/contributing/code-reviews.md | 16 - vitess.io/contributing/github-workflow.md | 16 - vitess.io/contributing/index.md | 16 - vitess.io/css/components.css | 269 - vitess.io/css/main.scss | 20 - vitess.io/css/site.scss | 738 -- vitess.io/getting-started/docker-build.md | 17 - vitess.io/getting-started/index.md | 18 - vitess.io/getting-started/local-instance.md | 17 - vitess.io/go-import/messages.html | 4 - vitess.io/go-import/vitess.html | 4 - vitess.io/images/120x120.gif | Bin 425 -> 0 bytes vitess.io/images/1600x800.gif | Bin 7640 -> 0 bytes vitess.io/images/400x250.gif | Bin 1457 -> 0 bytes .../images/VitessTransportSecurityModel.svg | 4 - vitess.io/images/cncf-icon-color.svg | 28 - vitess.io/images/hamburger-white.svg | 6 - vitess.io/images/kubernetes.svg | 84 - vitess.io/images/left-nav-menu-expander.svg | 3 - vitess.io/images/users/axon_logo.png | Bin 38973 -> 0 bytes vitess.io/images/users/bettercloud_logo.png | Bin 11643 -> 0 bytes vitess.io/images/users/flipkart_logo.png | Bin 52688 -> 0 bytes vitess.io/images/users/hubspot_logo.png | Bin 42080 -> 0 bytes vitess.io/images/users/jd.jpg | Bin 11983 -> 0 bytes vitess.io/images/users/nozzle_logo.png | Bin 6119 -> 0 bytes .../images/users/pixel_federation_logo.png | Bin 20959 -> 0 bytes vitess.io/images/users/quiz_of_kings_logo.jpg | Bin 113783 -> 0 bytes vitess.io/images/users/slack_logo.png | Bin 40640 -> 0 bytes vitess.io/images/users/square_logo.png | Bin 24598 -> 0 bytes vitess.io/images/users/stitchlabs_logo.png | Bin 18772 -> 0 bytes vitess.io/images/users/youtube_logo.png | Bin 20462 -> 0 bytes vitess.io/images/vitess_logo.svg | 276 - vitess.io/images/vitess_logo_icon_size.png | Bin 1594 -> 0 bytes vitess.io/images/vitess_logo_icon_size.svg | 280 - vitess.io/images/vitess_logo_with_border.svg | 281 - vitess.io/images/wood-texture-1600x800.jpg | Bin 122000 -> 0 bytes vitess.io/index.md | 104 - vitess.io/internal/index.md | 16 - vitess.io/internal/publish-website.md | 16 - vitess.io/internal/release-instructions.md | 17 - vitess.io/js/_main.js | 24 - vitess.io/js/common.js | 142 - vitess.io/js/jquery.collapsible.js | 93 - vitess.io/js/main.js | 1 - vitess.io/js/plugins/jquery.fitvids.js | 83 - vitess.io/js/plugins/jquery.visible.js | 68 - vitess.io/js/plugins/toc.js | 192 - vitess.io/js/vendor/html5shiv.min.js | 8 - vitess.io/js/vendor/jquery-1.9.1.min.js | 5 - vitess.io/js/vendor/respond.min.js | 8 - .../libs/bootstrap/css/bootstrap-theme.css | 587 -- .../bootstrap/css/bootstrap-theme.css.map | 1 - .../bootstrap/css/bootstrap-theme.min.css | 5 - vitess.io/libs/bootstrap/css/bootstrap.css | 6800 ----------------- .../libs/bootstrap/css/bootstrap.css.map | 1 - .../libs/bootstrap/css/bootstrap.min.css | 5 - .../fonts/glyphicons-halflings-regular.eot | Bin 20127 -> 0 bytes .../fonts/glyphicons-halflings-regular.svg | 288 - .../fonts/glyphicons-halflings-regular.ttf | Bin 45404 -> 0 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 23424 -> 0 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 18028 -> 0 bytes vitess.io/libs/bootstrap/js/bootstrap.js | 2364 ------ vitess.io/libs/bootstrap/js/bootstrap.min.js | 7 - vitess.io/libs/bootstrap/js/npm.js | 13 - vitess.io/overview/concepts.md | 16 - vitess.io/overview/index.md | 17 - vitess.io/overview/scaling-mysql.md | 16 - vitess.io/package.json | 18 - vitess.io/preview-site.sh | 38 - vitess.io/publish-site.sh | 65 - vitess.io/reference/vitess-api.md | 18 - vitess.io/reference/vtctl.md | 18 - .../resources/coreos-meetup-2016-01-27.pdf | Bin 1027263 -> 0 bytes vitess.io/resources/design-docs.md | 16 - vitess.io/resources/openworld-2015-vitess.pdf | Bin 1072470 -> 0 bytes .../percona-2015-vitess-and-kubernetes.pdf | Bin 733151 -> 0 bytes vitess.io/resources/percona-2016.pdf | Bin 2054300 -> 0 bytes vitess.io/resources/presentations.md | 72 - vitess.io/resources/roadmap.md | 146 - vitess.io/resources/vitess-2014.pdf | Bin 4379379 -> 0 bytes vitess.io/search/index.md | 21 - vitess.io/terms/index.md | 62 - vitess.io/user-guide/backup-and-restore.md | 16 - vitess.io/user-guide/faq.md | 16 - .../horizontal-sharding-workflow.md | 16 - vitess.io/user-guide/horizontal-sharding.md | 16 - vitess.io/user-guide/introduction.md | 16 - vitess.io/user-guide/mysql-server-protocol.md | 16 - vitess.io/user-guide/production-planning.md | 16 - vitess.io/user-guide/reparenting.md | 16 - vitess.io/user-guide/row-based-replication.md | 16 - .../user-guide/scalability-philosophy.md | 16 - vitess.io/user-guide/schema-management.md | 16 - vitess.io/user-guide/schema-swap.md | 16 - vitess.io/user-guide/server-configuration.md | 16 - .../sharding-kubernetes-workflow.md | 16 - vitess.io/user-guide/sharding-kubernetes.md | 16 - vitess.io/user-guide/sharding.md | 16 - vitess.io/user-guide/topology-service.md | 16 - .../user-guide/transport-security-model.md | 16 - vitess.io/user-guide/troubleshooting.md | 16 - vitess.io/user-guide/twopc.md | 16 - vitess.io/user-guide/update-stream.md | 16 - vitess.io/user-guide/upgrading.md | 16 - vitess.io/user-guide/vitess-replication.md | 16 - vitess.io/user-guide/vitess-sequences.md | 16 - vitess.io/user-guide/vschema.md | 16 - vitess.io/user-guide/vtexplain.md | 16 - vitess.io/user-guide/vttablet-modes.md | 16 - web/vtctld2/package.json | 2 +- 285 files changed, 1 insertion(+), 20034 deletions(-) delete mode 100644 vitess.io/.gitignore delete mode 100644 vitess.io/CNAME delete mode 100644 vitess.io/Gemfile delete mode 100644 vitess.io/Gemfile.lock delete mode 100644 vitess.io/Gruntfile.js delete mode 100644 vitess.io/LICENSE delete mode 100644 vitess.io/_config.yml delete mode 100644 vitess.io/_config_dev.yml delete mode 100644 vitess.io/_data/authors.yml delete mode 100644 vitess.io/_data/footer.yml delete mode 100644 vitess.io/_data/nav.yml delete mode 100644 vitess.io/_data/navigation.yml delete mode 100644 vitess.io/_includes/analytics.liquid delete mode 100644 vitess.io/_includes/breadcrumbs.html delete mode 100644 vitess.io/_includes/collection-pagination.html delete mode 100644 vitess.io/_includes/comments.html delete mode 120000 vitess.io/_includes/doc delete mode 100644 vitess.io/_includes/end-of-page-styles.liquid delete mode 100644 vitess.io/_includes/footer.html delete mode 100644 vitess.io/_includes/google-analytics.html delete mode 100644 vitess.io/_includes/header.html delete mode 100644 vitess.io/_includes/image-credit.html delete mode 100644 vitess.io/_includes/latest-posts-grid.html delete mode 100644 vitess.io/_includes/latest-posts-list.html delete mode 100644 vitess.io/_includes/left-nav-menu.html delete mode 100644 vitess.io/_includes/meta.liquid delete mode 100644 vitess.io/_includes/nav.html delete mode 100644 vitess.io/_includes/nav.liquid delete mode 100644 vitess.io/_includes/navigation-sliding.html delete mode 100644 vitess.io/_includes/navigation.html delete mode 100644 vitess.io/_includes/open-graph.html delete mode 100644 vitess.io/_includes/page-author.html delete mode 100644 vitess.io/_includes/page-meta.html delete mode 100644 vitess.io/_includes/pagination.html delete mode 100644 vitess.io/_includes/post-grid.html delete mode 100644 vitess.io/_includes/post-list-bullets.html delete mode 100644 vitess.io/_includes/post-list.html delete mode 100644 vitess.io/_includes/scripts.liquid delete mode 100644 vitess.io/_includes/scroll-cue.html delete mode 100644 vitess.io/_includes/share-this.html delete mode 100644 vitess.io/_includes/styles.liquid delete mode 100644 vitess.io/_includes/toc.liquid delete mode 100644 vitess.io/_layouts/archive.html delete mode 100644 vitess.io/_layouts/article.html delete mode 100644 vitess.io/_layouts/base.liquid delete mode 100644 vitess.io/_layouts/default.liquid delete mode 100644 vitess.io/_layouts/doc.liquid delete mode 100644 vitess.io/_layouts/home.liquid delete mode 100644 vitess.io/_redirects delete mode 100644 vitess.io/_sass/_animations.scss delete mode 100644 vitess.io/_sass/_badges.scss delete mode 100644 vitess.io/_sass/_base.scss delete mode 100644 vitess.io/_sass/_bullets.scss delete mode 100644 vitess.io/_sass/_buttons.scss delete mode 100644 vitess.io/_sass/_gist.scss delete mode 100644 vitess.io/_sass/_grid-settings.scss delete mode 100644 vitess.io/_sass/_helpers.scss delete mode 100644 vitess.io/_sass/_layout.scss delete mode 100644 vitess.io/_sass/_mixins.scss delete mode 100644 vitess.io/_sass/_notices.scss delete mode 100644 vitess.io/_sass/_pygments.scss delete mode 100644 vitess.io/_sass/_reset.scss delete mode 100644 vitess.io/_sass/_sliding-menu.scss delete mode 100644 vitess.io/_sass/_variables.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/_bourbon-deprecated-upcoming.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/_bourbon.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_button.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_clearfix.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_directional-values.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_ellipsis.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_font-family.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_hide-text.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_html5-input-types.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_position.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_prefixer.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_retina-image.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_size.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_timing-functions.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_triangle.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/addons/_word-wrap.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_animation.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_appearance.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_backface-visibility.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_background-image.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_background.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_border-image.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_border-radius.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_box-sizing.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_calc.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_columns.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_filter.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_flex-box.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_font-face.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_font-feature-settings.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_hidpi-media-query.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_hyphens.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_image-rendering.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_keyframes.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_linear-gradient.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_perspective.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_placeholder.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_radial-gradient.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_transform.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_transition.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/css3/_user-select.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_assign.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_color-lightness.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_flex-grid.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_golden-ratio.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_grid-width.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_modular-scale.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_px-to-em.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_px-to-rem.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_strip-units.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_tint-shade.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_transition-property-name.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/functions/_unpack.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_convert-units.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_gradient-positions-parser.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_is-num.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_linear-angle-parser.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_linear-gradient-parser.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_linear-positions-parser.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_linear-side-corner-parser.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_radial-arg-parser.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_radial-gradient-parser.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_radial-positions-parser.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_render-gradients.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_shape-size-stripper.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/helpers/_str-to-num.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/settings/_prefixer.scss delete mode 100644 vitess.io/_sass/vendor/bourbon/settings/_px-to-em.scss delete mode 100644 vitess.io/_sass/vendor/neat/_neat-helpers.scss delete mode 100644 vitess.io/_sass/vendor/neat/_neat.scss delete mode 100644 vitess.io/_sass/vendor/neat/functions/_new-breakpoint.scss delete mode 100644 vitess.io/_sass/vendor/neat/functions/_private.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_fill-parent.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_grid.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_media.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_omega.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_outer-container.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_pad.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_private.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_reset.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_row.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_shift.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_span-columns.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_to-deprecate.scss delete mode 100644 vitess.io/_sass/vendor/neat/grid/_visual-grid.scss delete mode 100644 vitess.io/_sass/vendor/neat/settings/_grid.scss delete mode 100644 vitess.io/_sass/vendor/neat/settings/_visual-grid.scss delete mode 100644 vitess.io/_templates/archive delete mode 100644 vitess.io/_templates/page delete mode 100644 vitess.io/_templates/post delete mode 100644 vitess.io/advanced/index.md delete mode 100644 vitess.io/advanced/messaging.md delete mode 100644 vitess.io/assets/scripts/jquery-1.8.3.min.js delete mode 100644 vitess.io/assets/scripts/jquery-ui.min.js delete mode 100644 vitess.io/assets/scripts/main.js delete mode 100644 vitess.io/assets/scripts/modernizr.js delete mode 100644 vitess.io/assets/vendor/images/hamburger.svg delete mode 100644 vitess.io/assets/vendor/images/icons/icons-hinted.ttf delete mode 100644 vitess.io/assets/vendor/images/icons/icons.eot delete mode 100644 vitess.io/assets/vendor/images/icons/icons.svg delete mode 100644 vitess.io/assets/vendor/images/icons/icons.ttf delete mode 100644 vitess.io/assets/vendor/images/icons/icons.woff delete mode 100644 vitess.io/assets/vendor/images/icons/icons.woff2 delete mode 100644 vitess.io/assets/vendor/styles/wsk.css delete mode 100644 vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons-hinted.ttf delete mode 100644 vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.eot delete mode 100644 vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.svg delete mode 100644 vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.ttf delete mode 100644 vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.woff delete mode 100644 vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.woff2 delete mode 100644 vitess.io/assets/vendor/wsk/0.4.0/styles/wsk.css delete mode 100644 vitess.io/contributing/code-reviews.md delete mode 100644 vitess.io/contributing/github-workflow.md delete mode 100644 vitess.io/contributing/index.md delete mode 100644 vitess.io/css/components.css delete mode 100644 vitess.io/css/main.scss delete mode 100644 vitess.io/css/site.scss delete mode 100644 vitess.io/getting-started/docker-build.md delete mode 100644 vitess.io/getting-started/index.md delete mode 100644 vitess.io/getting-started/local-instance.md delete mode 100644 vitess.io/go-import/messages.html delete mode 100644 vitess.io/go-import/vitess.html delete mode 100644 vitess.io/images/120x120.gif delete mode 100644 vitess.io/images/1600x800.gif delete mode 100644 vitess.io/images/400x250.gif delete mode 100644 vitess.io/images/VitessTransportSecurityModel.svg delete mode 100644 vitess.io/images/cncf-icon-color.svg delete mode 100644 vitess.io/images/hamburger-white.svg delete mode 100644 vitess.io/images/kubernetes.svg delete mode 100644 vitess.io/images/left-nav-menu-expander.svg delete mode 100644 vitess.io/images/users/axon_logo.png delete mode 100644 vitess.io/images/users/bettercloud_logo.png delete mode 100644 vitess.io/images/users/flipkart_logo.png delete mode 100644 vitess.io/images/users/hubspot_logo.png delete mode 100644 vitess.io/images/users/jd.jpg delete mode 100644 vitess.io/images/users/nozzle_logo.png delete mode 100644 vitess.io/images/users/pixel_federation_logo.png delete mode 100644 vitess.io/images/users/quiz_of_kings_logo.jpg delete mode 100644 vitess.io/images/users/slack_logo.png delete mode 100644 vitess.io/images/users/square_logo.png delete mode 100644 vitess.io/images/users/stitchlabs_logo.png delete mode 100644 vitess.io/images/users/youtube_logo.png delete mode 100644 vitess.io/images/vitess_logo.svg delete mode 100644 vitess.io/images/vitess_logo_icon_size.png delete mode 100644 vitess.io/images/vitess_logo_icon_size.svg delete mode 100644 vitess.io/images/vitess_logo_with_border.svg delete mode 100644 vitess.io/images/wood-texture-1600x800.jpg delete mode 100644 vitess.io/index.md delete mode 100644 vitess.io/internal/index.md delete mode 100644 vitess.io/internal/publish-website.md delete mode 100644 vitess.io/internal/release-instructions.md delete mode 100644 vitess.io/js/_main.js delete mode 100644 vitess.io/js/common.js delete mode 100644 vitess.io/js/jquery.collapsible.js delete mode 100644 vitess.io/js/main.js delete mode 100644 vitess.io/js/plugins/jquery.fitvids.js delete mode 100644 vitess.io/js/plugins/jquery.visible.js delete mode 100644 vitess.io/js/plugins/toc.js delete mode 100644 vitess.io/js/vendor/html5shiv.min.js delete mode 100644 vitess.io/js/vendor/jquery-1.9.1.min.js delete mode 100644 vitess.io/js/vendor/respond.min.js delete mode 100644 vitess.io/libs/bootstrap/css/bootstrap-theme.css delete mode 100644 vitess.io/libs/bootstrap/css/bootstrap-theme.css.map delete mode 100644 vitess.io/libs/bootstrap/css/bootstrap-theme.min.css delete mode 100644 vitess.io/libs/bootstrap/css/bootstrap.css delete mode 100644 vitess.io/libs/bootstrap/css/bootstrap.css.map delete mode 100644 vitess.io/libs/bootstrap/css/bootstrap.min.css delete mode 100644 vitess.io/libs/bootstrap/fonts/glyphicons-halflings-regular.eot delete mode 100644 vitess.io/libs/bootstrap/fonts/glyphicons-halflings-regular.svg delete mode 100644 vitess.io/libs/bootstrap/fonts/glyphicons-halflings-regular.ttf delete mode 100644 vitess.io/libs/bootstrap/fonts/glyphicons-halflings-regular.woff delete mode 100644 vitess.io/libs/bootstrap/fonts/glyphicons-halflings-regular.woff2 delete mode 100644 vitess.io/libs/bootstrap/js/bootstrap.js delete mode 100644 vitess.io/libs/bootstrap/js/bootstrap.min.js delete mode 100644 vitess.io/libs/bootstrap/js/npm.js delete mode 100644 vitess.io/overview/concepts.md delete mode 100644 vitess.io/overview/index.md delete mode 100644 vitess.io/overview/scaling-mysql.md delete mode 100644 vitess.io/package.json delete mode 100755 vitess.io/preview-site.sh delete mode 100755 vitess.io/publish-site.sh delete mode 100644 vitess.io/reference/vitess-api.md delete mode 100644 vitess.io/reference/vtctl.md delete mode 100644 vitess.io/resources/coreos-meetup-2016-01-27.pdf delete mode 100644 vitess.io/resources/design-docs.md delete mode 100644 vitess.io/resources/openworld-2015-vitess.pdf delete mode 100644 vitess.io/resources/percona-2015-vitess-and-kubernetes.pdf delete mode 100644 vitess.io/resources/percona-2016.pdf delete mode 100644 vitess.io/resources/presentations.md delete mode 100644 vitess.io/resources/roadmap.md delete mode 100644 vitess.io/resources/vitess-2014.pdf delete mode 100644 vitess.io/search/index.md delete mode 100644 vitess.io/terms/index.md delete mode 100644 vitess.io/user-guide/backup-and-restore.md delete mode 100644 vitess.io/user-guide/faq.md delete mode 100644 vitess.io/user-guide/horizontal-sharding-workflow.md delete mode 100644 vitess.io/user-guide/horizontal-sharding.md delete mode 100644 vitess.io/user-guide/introduction.md delete mode 100644 vitess.io/user-guide/mysql-server-protocol.md delete mode 100644 vitess.io/user-guide/production-planning.md delete mode 100644 vitess.io/user-guide/reparenting.md delete mode 100644 vitess.io/user-guide/row-based-replication.md delete mode 100644 vitess.io/user-guide/scalability-philosophy.md delete mode 100644 vitess.io/user-guide/schema-management.md delete mode 100644 vitess.io/user-guide/schema-swap.md delete mode 100644 vitess.io/user-guide/server-configuration.md delete mode 100644 vitess.io/user-guide/sharding-kubernetes-workflow.md delete mode 100644 vitess.io/user-guide/sharding-kubernetes.md delete mode 100644 vitess.io/user-guide/sharding.md delete mode 100644 vitess.io/user-guide/topology-service.md delete mode 100644 vitess.io/user-guide/transport-security-model.md delete mode 100644 vitess.io/user-guide/troubleshooting.md delete mode 100644 vitess.io/user-guide/twopc.md delete mode 100644 vitess.io/user-guide/update-stream.md delete mode 100644 vitess.io/user-guide/upgrading.md delete mode 100644 vitess.io/user-guide/vitess-replication.md delete mode 100644 vitess.io/user-guide/vitess-sequences.md delete mode 100644 vitess.io/user-guide/vschema.md delete mode 100644 vitess.io/user-guide/vtexplain.md delete mode 100644 vitess.io/user-guide/vttablet-modes.md diff --git a/vitess.io/.gitignore b/vitess.io/.gitignore deleted file mode 100644 index 6a6dc3de324..00000000000 --- a/vitess.io/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/.sass-cache/ diff --git a/vitess.io/CNAME b/vitess.io/CNAME deleted file mode 100644 index d79d4050efd..00000000000 --- a/vitess.io/CNAME +++ /dev/null @@ -1 +0,0 @@ -vitess.io \ No newline at end of file diff --git a/vitess.io/Gemfile b/vitess.io/Gemfile deleted file mode 100644 index cfb190c8a4a..00000000000 --- a/vitess.io/Gemfile +++ /dev/null @@ -1,27 +0,0 @@ -# Note: When you change this file and run "bundle install", the Gemfile.lock -# file will be changed as well. Please always commit both files and do not -# ignore the changes in the .lock file. -source "https://rubygems.org" - -gem 'jekyll', '3.5.2' -gem 'jekyll-coffeescript', '1.0.1' -gem 'jekyll-sass-converter', '1.3.0' -gem 'kramdown', '1.5.0' -gem 'maruku', '0.7.0' -gem 'rdiscount', '2.1.7' -gem 'redcarpet', '3.3.2' -gem 'RedCloth', '~> 4.3.2' -gem 'liquid', '4.0.0' -gem 'pygments.rb' -gem 'jemoji', '0.5.0' -# Note that we cannot use 0.12.1 because it does not have the bugfix -# https://github.com/jekyll/jekyll-redirect-from/pull/142. Instead, -# we use a version which is not affected by issue -# https://github.com/jekyll/jekyll-redirect-from/issues/139. -gem 'jekyll-redirect-from', '0.11.0' -gem 'jekyll-sitemap', '1.1.1' -gem 'jekyll-feed', '0.3.1' -gem 'jekyll-seo-tag', '2.3.0' - -gem 'bourbon' -gem 'neat' diff --git a/vitess.io/Gemfile.lock b/vitess.io/Gemfile.lock deleted file mode 100644 index dec6fbb7f70..00000000000 --- a/vitess.io/Gemfile.lock +++ /dev/null @@ -1,117 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - RedCloth (4.3.2) - activesupport (5.1.4) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (~> 0.7) - minitest (~> 5.1) - tzinfo (~> 1.1) - addressable (2.5.2) - public_suffix (>= 2.0.2, < 4.0) - bourbon (4.3.4) - sass (~> 3.4) - thor (~> 0.19) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.12.2) - colorator (1.1.0) - concurrent-ruby (1.0.5) - execjs (2.7.0) - ffi (1.9.25) - forwardable-extended (2.6.0) - gemoji (2.1.0) - html-pipeline (1.11.0) - activesupport (>= 2) - nokogiri (~> 1.4) - i18n (0.8.6) - jekyll (3.6.3) - addressable (~> 2.4) - colorator (~> 1.0) - jekyll-sass-converter (~> 1.0) - jekyll-watch (~> 1.1) - kramdown (~> 1.3) - liquid (~> 4.0) - mercenary (~> 0.3.3) - pathutil (~> 0.9) - rouge (~> 1.7) - safe_yaml (~> 1.0) - jekyll-coffeescript (1.0.1) - coffee-script (~> 2.2) - jekyll-feed (0.3.1) - jekyll-redirect-from (0.11.0) - jekyll (>= 2.0) - jekyll-sass-converter (1.3.0) - sass (~> 3.2) - jekyll-seo-tag (2.3.0) - jekyll (~> 3.3) - jekyll-sitemap (1.1.1) - jekyll (~> 3.3) - jekyll-watch (1.5.0) - listen (~> 3.0, < 3.1) - jemoji (0.5.0) - gemoji (~> 2.0) - html-pipeline (~> 1.9) - jekyll (>= 2.0) - kramdown (1.5.0) - liquid (4.0.0) - listen (3.0.8) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - maruku (0.7.0) - mercenary (0.3.6) - mini_portile2 (2.3.0) - minitest (5.10.3) - multi_json (1.12.2) - neat (2.1.0) - sass (~> 3.4) - thor (~> 0.19) - nokogiri (1.8.5) - mini_portile2 (~> 2.3.0) - pathutil (0.14.0) - forwardable-extended (~> 2.6) - public_suffix (3.0.0) - pygments.rb (1.2.0) - multi_json (>= 1.0.0) - rb-fsevent (0.10.2) - rb-inotify (0.9.10) - ffi (>= 0.5.0, < 2) - rdiscount (2.1.7) - redcarpet (3.3.2) - rouge (1.11.1) - safe_yaml (1.0.4) - sass (3.5.1) - sass-listen (~> 4.0.0) - sass-listen (4.0.0) - rb-fsevent (~> 0.9, >= 0.9.4) - rb-inotify (~> 0.9, >= 0.9.7) - thor (0.20.0) - thread_safe (0.3.6) - tzinfo (1.2.3) - thread_safe (~> 0.1) - -PLATFORMS - ruby - -DEPENDENCIES - RedCloth (~> 4.3.2) - bourbon - jekyll (= 3.6.3) - jekyll-coffeescript (= 1.0.1) - jekyll-feed (= 0.3.1) - jekyll-redirect-from (= 0.11.0) - jekyll-sass-converter (= 1.3.0) - jekyll-seo-tag (= 2.3.0) - jekyll-sitemap (= 1.1.1) - jemoji (= 0.5.0) - kramdown (= 1.5.0) - liquid (= 4.0.0) - maruku (= 0.7.0) - neat - pygments.rb - rdiscount (= 2.1.7) - redcarpet (= 3.3.2) - -BUNDLED WITH - 1.16.0 diff --git a/vitess.io/Gruntfile.js b/vitess.io/Gruntfile.js deleted file mode 100644 index 6721d97cab5..00000000000 --- a/vitess.io/Gruntfile.js +++ /dev/null @@ -1,95 +0,0 @@ -'use strict'; -module.exports = function(grunt) { - - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - jshint: { - options: { - jshintrc: '.jshintrc' - }, - all: [ - 'Gruntfile.js', - 'js/*.js', - '!js/main.js' - ] - }, - watch: { - js: { - files: [ - '<%= jshint.all %>' - ], - tasks: ['jshint', 'uglify'], - options: { - livereload: true - } - }, - }, - uglify: { - dist: { - options: { - banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' + '<%= grunt.template.today("yyyy-mm-dd") %> */', - compress: true, - beautify: false, - mangle: false - }, - files: { - 'js/main.js': [ - 'js/plugins/*.js', - 'js/_*.js' - ] - } - } - }, - imagemin: { - dist: { - options: { - optimizationLevel: 7, - progressive: true - }, - files: [{ - expand: true, - cwd: 'images/', - src: '{,*/}*.{png,jpg,jpeg}', - dest: 'images/' - }] - } - }, - imgcompress: { - dist: { - options: { - optimizationLevel: 7, - progressive: true - }, - files: [{ - expand: true, - cwd: 'images/', - src: '{,*/}*.{png,jpg,jpeg}', - dest: 'images/' - }] - } - }, - svgmin: { - dist: { - files: [{ - expand: true, - cwd: 'images/', - src: '{,*/}*.svg', - dest: 'images/' - }] - } - }, - }); - - // Load tasks - grunt.loadNpmTasks('grunt-contrib-jshint'); - grunt.loadNpmTasks('grunt-contrib-watch'); - grunt.loadNpmTasks('grunt-contrib-uglify'); - grunt.loadNpmTasks('grunt-newer'); - grunt.loadNpmTasks('grunt-contrib-imagemin'); - grunt.loadNpmTasks('grunt-svgmin'); - grunt.loadNpmTasks('grunt-imgcompress'); - - // Register tasks - grunt.registerTask('scripts', ['watch', 'uglify']); - grunt.registerTask('images', ['newer:imgcompress', 'newer:svgmin']); -}; \ No newline at end of file diff --git a/vitess.io/LICENSE b/vitess.io/LICENSE deleted file mode 100644 index 4fe17285210..00000000000 --- a/vitess.io/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Michael Rose - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/vitess.io/_config.yml b/vitess.io/_config.yml deleted file mode 100644 index 4008883714f..00000000000 --- a/vitess.io/_config.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Site wide configuration - -title: Vitess -description: "Vitess is a database clustering system for horizontal scaling of MySQL." -logo: vitess_logo_with_border.svg -icon: vitess_logo_icon_size.png -teaser: 400x250.gif -locale: en_US -url: https://vitess.io -project-name: Vitess -repo: https://github.com/vitessio/vitess - -# Jekyll configuration -sass: - sass_dir: _sass - style: compressed -permalink: pretty -highlighter: pygments -plugins: - - jekyll-sitemap - - jekyll-redirect-from - - jekyll-seo-tag - -markdown: redcarpet - -analytics: - id: UA-60219601-1 - -redcarpet: - extensions: ["autolink", "fenced_code_blocks", "highlight", "no_intra_emphasis", "prettify", "tables", "with_toc_data"] - -# Site owner -owner: - name: Vitess Team - web: https://github.com/vitessio/vitess - email: - twitter: - bio: - avatar: - disqus-shortname: - - -exclude: ["config.rb", ".sass-cache", "Capfile", "config", "log", "Rakefile", "Rakefile.rb", "tmp", "*.sublime-project", "*.sublime-workspace", "Gemfile", "Gemfile.lock", "README.md", "LICENSE", "node_modules", "Gruntfile.js", "package.json", "preview-site.sh", "publish-site.sh"] -include: - - "_redirects" diff --git a/vitess.io/_config_dev.yml b/vitess.io/_config_dev.yml deleted file mode 100644 index 38c6ad25679..00000000000 --- a/vitess.io/_config_dev.yml +++ /dev/null @@ -1,44 +0,0 @@ -# Site wide configuration - -title: Vitess -description: "Vitess is a database clustering system for horizontal scaling of MySQL." -logo: vitess_logo_with_border.svg -icon: vitess_logo_icon_size.png -teaser: 400x250.gif -locale: en_US -url: -project-name: Vitess -repo: https://github.com/vitessio/vitess - -# Jekyll configuration -sass: - sass_dir: _sass - style: compressed -permalink: pretty -highlighter: pygments -plugins: - - jekyll-sitemap - - jekyll-redirect-from - - jekyll-seo-tag - -markdown: redcarpet - -redcarpet: - extensions: ["autolink", "fenced_code_blocks", "highlight", "no_intra_emphasis", "prettify", "tables", "with_toc_data"] - -# Site owner -owner: - name: Vitess Team - web: https://github.com/vitessio/vitess - email: - twitter: - bio: - avatar: - disqus-shortname: - - -exclude: ["config.rb", ".sass-cache", "Capfile", "config", "log", "Rakefile", "Rakefile.rb", "tmp", "*.sublime-project", "*.sublime-workspace", "Gemfile", "Gemfile.lock", "README.md", "LICENSE", "node_modules", "Gruntfile.js", "package.json", "preview-site.sh", "publish-site.sh"] - -# Open up "jekyll serve" because the requests via the Docker forwarding are not -# treated as incoming from "localhost". -host: 0.0.0.0 diff --git a/vitess.io/_data/authors.yml b/vitess.io/_data/authors.yml deleted file mode 100644 index f8b0ec994a9..00000000000 --- a/vitess.io/_data/authors.yml +++ /dev/null @@ -1,11 +0,0 @@ -# Authors - -shengzhe: - name: Shengzhe - web: - email: - bio: - avatar: - twitter: - google: - plus: diff --git a/vitess.io/_data/footer.yml b/vitess.io/_data/footer.yml deleted file mode 100644 index f68e1164b88..00000000000 --- a/vitess.io/_data/footer.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Footer navigation links - -- title: Home - url: / - -- title: GitHub - url: https://github.com/vitessio/vitess diff --git a/vitess.io/_data/nav.yml b/vitess.io/_data/nav.yml deleted file mode 100644 index a8feb9fe47a..00000000000 --- a/vitess.io/_data/nav.yml +++ /dev/null @@ -1,24 +0,0 @@ -# Site navigation links -# -#- title: Getting Started -# url: /overview/ -# excerpt: "Everything you need to know to get started with Vitess." -# image: 400x250.gif -# -#- title: Try It Out -# url: /doc/ -# excerpt: "Test Vitess on Kubernetes" -# image: 400x250.gif -# -#- title: GitHub -# url: https://github.com/vitessio/vitess/ -# excerpt: "Download the code from GitHub." -# image: 400x250.gif - -# TODO(mberlin): Check if we can remove this. - -- path: / -- path: overview/ - title: Guides -- path: reference/vtctl.html - title: Reference diff --git a/vitess.io/_data/navigation.yml b/vitess.io/_data/navigation.yml deleted file mode 100644 index 1998b1200f6..00000000000 --- a/vitess.io/_data/navigation.yml +++ /dev/null @@ -1,21 +0,0 @@ -# Site navigation links - -- title: Getting Started - url: /getting-started/ - excerpt: "Everything you need to know to get started with Vitess." - image: 400x250.gif - -- title: Documentation - url: /doc/ - excerpt: "Vitess Docs." - image: 400x250.gif - -- title: About - url: /about/ - excerpt: "All about Vitess." - image: 400x250.gif - -- title: FAQ - url: /faq/ - excerpt: "Vitess Faq." - image: 400x250.gif \ No newline at end of file diff --git a/vitess.io/_includes/analytics.liquid b/vitess.io/_includes/analytics.liquid deleted file mode 100644 index f4fce9bebc1..00000000000 --- a/vitess.io/_includes/analytics.liquid +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/vitess.io/_includes/breadcrumbs.html b/vitess.io/_includes/breadcrumbs.html deleted file mode 100644 index 2e7200de269..00000000000 --- a/vitess.io/_includes/breadcrumbs.html +++ /dev/null @@ -1,13 +0,0 @@ -{% if page.categories and page.categories != empty %} - -{% endif %} diff --git a/vitess.io/_includes/collection-pagination.html b/vitess.io/_includes/collection-pagination.html deleted file mode 100644 index 6a62925a34a..00000000000 --- a/vitess.io/_includes/collection-pagination.html +++ /dev/null @@ -1,15 +0,0 @@ - \ No newline at end of file diff --git a/vitess.io/_includes/comments.html b/vitess.io/_includes/comments.html deleted file mode 100644 index c30aeb7e967..00000000000 --- a/vitess.io/_includes/comments.html +++ /dev/null @@ -1,14 +0,0 @@ -
    -
    - - \ No newline at end of file diff --git a/vitess.io/_includes/doc b/vitess.io/_includes/doc deleted file mode 120000 index 7e57b0f5825..00000000000 --- a/vitess.io/_includes/doc +++ /dev/null @@ -1 +0,0 @@ -../../doc \ No newline at end of file diff --git a/vitess.io/_includes/end-of-page-styles.liquid b/vitess.io/_includes/end-of-page-styles.liquid deleted file mode 100644 index e13116701d8..00000000000 --- a/vitess.io/_includes/end-of-page-styles.liquid +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - diff --git a/vitess.io/_includes/footer.html b/vitess.io/_includes/footer.html deleted file mode 100644 index a23a6495942..00000000000 --- a/vitess.io/_includes/footer.html +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/vitess.io/_includes/google-analytics.html b/vitess.io/_includes/google-analytics.html deleted file mode 100644 index e727ff06cdc..00000000000 --- a/vitess.io/_includes/google-analytics.html +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/vitess.io/_includes/header.html b/vitess.io/_includes/header.html deleted file mode 100644 index 5fa1a10b9dd..00000000000 --- a/vitess.io/_includes/header.html +++ /dev/null @@ -1,8 +0,0 @@ -
    -
    - {{ site.title }} - -
    -
    diff --git a/vitess.io/_includes/image-credit.html b/vitess.io/_includes/image-credit.html deleted file mode 100644 index 6ac4b7d52fd..00000000000 --- a/vitess.io/_includes/image-credit.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/vitess.io/_includes/latest-posts-grid.html b/vitess.io/_includes/latest-posts-grid.html deleted file mode 100644 index 0479f114e15..00000000000 --- a/vitess.io/_includes/latest-posts-grid.html +++ /dev/null @@ -1,9 +0,0 @@ -
    -

    Latest {{ page.categories | first | replace: '-',' ' | capitalize }}

    -
      - {% capture category_name %}{{ page.categories | first }}{% endcapture %} - {% for post in site.categories.[category_name] limit:4 %} -
    • - {% endfor %} -
    -
    diff --git a/vitess.io/_includes/latest-posts-list.html b/vitess.io/_includes/latest-posts-list.html deleted file mode 100644 index 848bc6aea28..00000000000 --- a/vitess.io/_includes/latest-posts-list.html +++ /dev/null @@ -1,7 +0,0 @@ -

    Latest {{ page.categories | first | replace: '-',' ' | capitalize }}

    -
      -{% capture category_name %}{{ page.categories | first }}{% endcapture %} -{% for post in site.categories.[category_name] limit:3 %} -
    • {{ post.title }}
    • -{% endfor %} -
    \ No newline at end of file diff --git a/vitess.io/_includes/left-nav-menu.html b/vitess.io/_includes/left-nav-menu.html deleted file mode 100644 index 9375ce81bc1..00000000000 --- a/vitess.io/_includes/left-nav-menu.html +++ /dev/null @@ -1,107 +0,0 @@ -
  • - - - - - - - - -
    -
    - -
    -
    diff --git a/vitess.io/_includes/meta.liquid b/vitess.io/_includes/meta.liquid deleted file mode 100644 index f4a431b1986..00000000000 --- a/vitess.io/_includes/meta.liquid +++ /dev/null @@ -1,21 +0,0 @@ - - - - -{{ site.title }}{% if page.title and page.title != site.title %} - {{ page.title }}{% endif %} - - - - - - - - - - - - - - - - diff --git a/vitess.io/_includes/nav.html b/vitess.io/_includes/nav.html deleted file mode 100644 index bc8367c9a6e..00000000000 --- a/vitess.io/_includes/nav.html +++ /dev/null @@ -1,34 +0,0 @@ - diff --git a/vitess.io/_includes/nav.liquid b/vitess.io/_includes/nav.liquid deleted file mode 100644 index 1d0ebd360ad..00000000000 --- a/vitess.io/_includes/nav.liquid +++ /dev/null @@ -1,9 +0,0 @@ -{% assign nav__list = site.data.nav %} - diff --git a/vitess.io/_includes/navigation-sliding.html b/vitess.io/_includes/navigation-sliding.html deleted file mode 100644 index bf21e3087ea..00000000000 --- a/vitess.io/_includes/navigation-sliding.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - \ No newline at end of file diff --git a/vitess.io/_includes/navigation.html b/vitess.io/_includes/navigation.html deleted file mode 100644 index 386eadaba2d..00000000000 --- a/vitess.io/_includes/navigation.html +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/vitess.io/_includes/open-graph.html b/vitess.io/_includes/open-graph.html deleted file mode 100644 index 87bf165c8d2..00000000000 --- a/vitess.io/_includes/open-graph.html +++ /dev/null @@ -1,19 +0,0 @@ - - - {% if page.excerpt %}{% endif %} - {% if site.owner.twitter %}{% endif %} - {% if author.twitter %}{% endif %} - {% if page.image.feature %} - - - {% else %} - - - {% endif %} - - - - - {% if page.excerpt %}{% endif %} - - \ No newline at end of file diff --git a/vitess.io/_includes/page-author.html b/vitess.io/_includes/page-author.html deleted file mode 100644 index 02afa89f1f0..00000000000 --- a/vitess.io/_includes/page-author.html +++ /dev/null @@ -1,11 +0,0 @@ -{% if page.author %} - {% assign author = site.data.authors[page.author] %}{% else %}{% assign author = site.owner %} -{% endif %} - -
    - {{ author.name }} -
    -
    -

    Written by {% if author.web %}{% else %}{% endif %}

    -

    {{ author.bio }}

    -
    diff --git a/vitess.io/_includes/page-meta.html b/vitess.io/_includes/page-meta.html deleted file mode 100644 index bd29fcc42e3..00000000000 --- a/vitess.io/_includes/page-meta.html +++ /dev/null @@ -1,3 +0,0 @@ -{% if page.date %}
    -

    Updated {% if page.modified %}{% else %}

    {% endif %} -
    {% endif %} diff --git a/vitess.io/_includes/pagination.html b/vitess.io/_includes/pagination.html deleted file mode 100644 index f65d3eb1f8a..00000000000 --- a/vitess.io/_includes/pagination.html +++ /dev/null @@ -1,15 +0,0 @@ - \ No newline at end of file diff --git a/vitess.io/_includes/post-grid.html b/vitess.io/_includes/post-grid.html deleted file mode 100644 index 809fe422b94..00000000000 --- a/vitess.io/_includes/post-grid.html +++ /dev/null @@ -1,8 +0,0 @@ - diff --git a/vitess.io/_includes/post-list-bullets.html b/vitess.io/_includes/post-list-bullets.html deleted file mode 100644 index a647fac1fe7..00000000000 --- a/vitess.io/_includes/post-list-bullets.html +++ /dev/null @@ -1,13 +0,0 @@ -
    - {% for post in site.posts %} -
    -
    - -
    -
    -

    {{ post.title }}

    -

    {{ post.excerpt | remove: '

    ' | remove: '

    '}}

    -
    -
    - {% endfor %} -
    diff --git a/vitess.io/_includes/post-list.html b/vitess.io/_includes/post-list.html deleted file mode 100644 index 75da5845386..00000000000 --- a/vitess.io/_includes/post-list.html +++ /dev/null @@ -1 +0,0 @@ -
  • {% if post.date %}{{ post.date | date: "%B %d, %Y" }} » {% endif %}{{ post.title }}
  • \ No newline at end of file diff --git a/vitess.io/_includes/scripts.liquid b/vitess.io/_includes/scripts.liquid deleted file mode 100644 index 41b340f12c4..00000000000 --- a/vitess.io/_includes/scripts.liquid +++ /dev/null @@ -1 +0,0 @@ - diff --git a/vitess.io/_includes/scroll-cue.html b/vitess.io/_includes/scroll-cue.html deleted file mode 100644 index 8f0723efaf7..00000000000 --- a/vitess.io/_includes/scroll-cue.html +++ /dev/null @@ -1,3 +0,0 @@ -
    Scroll - -
    \ No newline at end of file diff --git a/vitess.io/_includes/share-this.html b/vitess.io/_includes/share-this.html deleted file mode 100644 index 17c372f87ac..00000000000 --- a/vitess.io/_includes/share-this.html +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/vitess.io/_includes/styles.liquid b/vitess.io/_includes/styles.liquid deleted file mode 100644 index a7bf514443d..00000000000 --- a/vitess.io/_includes/styles.liquid +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/vitess.io/_includes/toc.liquid b/vitess.io/_includes/toc.liquid deleted file mode 100644 index bd71f1ff885..00000000000 --- a/vitess.io/_includes/toc.liquid +++ /dev/null @@ -1,23 +0,0 @@ -{% if include.path %} - {% assign toc__top = site.data.navindex[include.path] %} - {% assign toc__list = toc__top.sub %} - {% if include.title %} -

    - {{ toc__top.page.title }} -

    - {% endif %} -{% else %} - {% assign toc__list = site.data.nav %} -{% endif %} - diff --git a/vitess.io/_layouts/archive.html b/vitess.io/_layouts/archive.html deleted file mode 100644 index 569c8467225..00000000000 --- a/vitess.io/_layouts/archive.html +++ /dev/null @@ -1,25 +0,0 @@ ---- -layout: default ---- - -
    -
    - {% if page.image.feature %} -
    -
    - {{ page.title }} - {% if page.image.credit %}{% include image-credit.html %}{% endif %} -
    -
    - {% endif %} -
    -

    {{ page.title }}

    - {% if page.excerpt %}

    {{ page.excerpt }}

    {% endif %} -
    -
    -
    - {{ content }} -
    -
    -
    -
    diff --git a/vitess.io/_layouts/article.html b/vitess.io/_layouts/article.html deleted file mode 100644 index 3f9abd3b91e..00000000000 --- a/vitess.io/_layouts/article.html +++ /dev/null @@ -1,35 +0,0 @@ ---- -layout: default ---- - -
    -
    - {% if page.image.feature %} -
    -
    - {{ page.title }} - {% if page.image.credit %}{% include image-credit.html %}{% endif %} -
    -
    - {% endif %} - {% include breadcrumbs.html %} -
    -

    {{ page.title }}

    -
    -
    - -
    - {{ content }} -
    -
    - {% if page.categories %}{% include page-author.html %}{% endif %} - {% if page.share != false %}{% include share-this.html %}{% endif %} - {% include page-meta.html %} -
    - -
    -
    -
    -
    diff --git a/vitess.io/_layouts/base.liquid b/vitess.io/_layouts/base.liquid deleted file mode 100644 index 3afa021cc72..00000000000 --- a/vitess.io/_layouts/base.liquid +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - {% include styles.liquid %} - - - - {% if site.analytics.id %} - {% include analytics.liquid %} - {% endif %} - - - {% seo %} - - -{% if page.tocDepth %} - -{% else %} - -{% endif %} - - {% include nav.html %} - {{ content }} -
    - {% include footer.html %} - - {% include end-of-page-styles.liquid %} - - diff --git a/vitess.io/_layouts/default.liquid b/vitess.io/_layouts/default.liquid deleted file mode 100644 index 3b4ad1a0525..00000000000 --- a/vitess.io/_layouts/default.liquid +++ /dev/null @@ -1,19 +0,0 @@ ---- -layout: base ---- - -{% if page.title %} -
    -
    -
    -
    -

    {{ page.title }}

    -
    -
    -
    -
    -{% endif %} - -
    - {{ content }} -
    diff --git a/vitess.io/_layouts/doc.liquid b/vitess.io/_layouts/doc.liquid deleted file mode 100644 index b8ba18e200d..00000000000 --- a/vitess.io/_layouts/doc.liquid +++ /dev/null @@ -1,22 +0,0 @@ ---- -layout: default -bodyclass: docs ---- - -
    -
    - -
    -
    - -
    -
    -
    - {{ content }} -
    -
    -
    diff --git a/vitess.io/_layouts/home.liquid b/vitess.io/_layouts/home.liquid deleted file mode 100644 index f4c2e7e93c1..00000000000 --- a/vitess.io/_layouts/home.liquid +++ /dev/null @@ -1,26 +0,0 @@ ---- -layout: base ---- - -
    -
    -
    - -

    {{ site.description }}

    -

    - - Quickstart - Manual Build - Learn More -

    -
    -
    -
    - -
    -
    - - {{ content}} - -
    -
    diff --git a/vitess.io/_redirects b/vitess.io/_redirects deleted file mode 100644 index 5f15ceeb5ab..00000000000 --- a/vitess.io/_redirects +++ /dev/null @@ -1,2 +0,0 @@ -/vitess/* go-get=1 /go-import/vitess.html 200 -/messages/* go-get=1 /go-import/messages.html 200 diff --git a/vitess.io/_sass/_animations.scss b/vitess.io/_sass/_animations.scss deleted file mode 100644 index c1c58495c46..00000000000 --- a/vitess.io/_sass/_animations.scss +++ /dev/null @@ -1,30 +0,0 @@ -// ANIMATIONS -// -------------------------------------------------- - -@include keyframes(wiggle) { - 25%, 50%, 75%, 100% { @include transform-origin(top center); } - 25% { @include transform(rotate(8deg)); } - 50% { @include transform(rotate(-4deg)); } - 75% { @include transform(rotate(2deg)); } - 100% { @include transform(rotate(0deg)); } -} - - -@include keyframes(pop) { - 50% { @include transform(scale(1.1)); } - 100% { @include transform(scale(1)); } -} - - -@include keyframes(hang) { - 50% { @include transform(translateY(-3px)); } - 100% { @include transform(translateY(-6px)); } -} -.hang { - display: inline-block; - @include animation-name(hang); - @include animation-duration(0.5s); - @include animation-timing-function(linear); - @include animation-iteration-count(infinite); - @include animation-direction(alternate); -} \ No newline at end of file diff --git a/vitess.io/_sass/_badges.scss b/vitess.io/_sass/_badges.scss deleted file mode 100644 index a6ea9cd0f8d..00000000000 --- a/vitess.io/_sass/_badges.scss +++ /dev/null @@ -1,48 +0,0 @@ -// BADGES -// -------------------------------------------------- - -.badge { - $badge-background: $primary-color; - $badge-dark-color: $black; - $badge-danger-color: $danger-color; - $badge-info-color: $info-color; - $badge-warning-color: $warning-color; - $badge-success-color: $success-color; - $badge-font-color: #fff; - - display: inline-block; - background: $badge-background; - border-radius: 2em; - color: $badge-font-color; - font-family: $alt-font; - @include font-size(12,no); - font-weight: 600; - line-height: 1; - padding: .25em 1em; - text-align: center; - - &.inverse { - background: $white; - color: $text-color; - } - - &.info { - background: $badge-info-color; - color: $white; - } - - &.danger { - background: $badge-danger-color; - color: $white; - } - - &.warning { - background: $badge-warning-color; - color: darken($badge-warning-color, 60); - } - - &.success { - background: $badge-success-color; - color: darken($badge-success-color, 60); - } -} \ No newline at end of file diff --git a/vitess.io/_sass/_base.scss b/vitess.io/_sass/_base.scss deleted file mode 100644 index 3a45c8ea716..00000000000 --- a/vitess.io/_sass/_base.scss +++ /dev/null @@ -1,355 +0,0 @@ -// TYPOGRAPHY -// -------------------------------------------------- - -body { - font-family: $base-font; - color: $text-color; - @include font-size(16); -} - -p { - @include font-size(18,yes,28); -} - -li { - @include font-size(16,12,24); -} - -// Headings -h1, h2, h3, h4, h5, h6 { - font-family: $heading-font; - text-rendering: optimizeLegibility; // Fix the character spacing for headings -} -h1 { - @include font-size(36); -} -h2 { - @include font-size(32); -} -h3 { - @include font-size(28); -} -h4 { - @include font-size(24); -} -h5 { - @include font-size(20); -} -h6 { - @include font-size(18); -} - -u, -ins { - text-decoration: none; - border-bottom: 1px solid $text-color; -} - -// Links -a { - color: $link-color; - &:hover { - color: darken($link-color, 20); - } - &:focus { - @extend %tab-focus; - } - &:hover, - &:active { - outline: 0; - } -} - -// Captions -figcaption { - padding-left: 2 * $gutter; - padding-right: 2 * $gutter; - font-family: $alt-font; - @include font-size(12,no,15); - color: lighten($text-color, 10); - text-align: center; - clear: both; - @include media($large) { - position: absolute; - top: 1px; - right: (3 * $column + $gutter) * -1; - padding-top: 10px; - padding-left: 0; - padding-right: 0; - width: (3 * $column); - text-align: left; - &:before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 50px; - height: 1px; - background: lighten($black, 70); - } - } - a { - text-decoration: none; - } -} - -// Blockquotes -blockquote { - padding-left: $gutter; - padding-right: $gutter; - font-style: italic; - p { - @include font-size(16); - } -} - -// Code -tt, code, kbd, samp, pre { - font-family: $code-font; -} -pre { - overflow-x: auto; // add scrollbars to wide code blocks -} -p code, -li code { - @include font-size(16,no); - color: $text-color; - white-space: nowrap; - margin: 0 2px; - padding: 0 5px; - border: 1px solid $border-color; - background-color: lighten($primary-color, 95); - border-radius: $border-radius; -} - -// Tables -table { - border-collapse: collapse; - margin: ((0px + $doc-line-height) / 2) 0; - margin: ((0rem + ($doc-line-height / $doc-font-size)) / 2) 0; - width: 100%; -} -tbody { - tr:hover > td, tr:hover > th { - background-color: $table-hover-color; - } -} -thead { - tr:first-child td { - border-bottom: 2px solid $table-border-color; - } -} -th { - padding: (0px + $doc-line-height) / 2; - padding: (0rem + ($doc-line-height / $doc-font-size)) / 2; - font-family: $alt-font; - font-weight: bold; - text-align: left; - background-color: $table-header-color; - border-bottom: 1px solid darken($border-color, 15%); -} -td { - border-bottom: 1px solid $border-color; - padding: (0px + $doc-line-height) / 2; - padding: (0rem + ($doc-line-height / $doc-font-size)) / 2; -} -tr, td, th { - vertical-align: middle; -} - -// ELEMENTS (MEDIA, EMBEDS, BUTTONS, ETC.) -// -------------------------------------------------- - -// Line rules -hr { - display: block; - position: relative; - margin: 0px + (2 * $doc-line-height) 0; - margin: 0rem + ((2 * $doc-line-height) / $doc-font-size) 0; - padding: 0; - height: 5px; - border: 0; - &:before { - content: ''; - position: absolute; - top: 0; - left: 0; - width: 2 * $column; - height: 1px; - background: $border-color; - } -} - -// Figures and images -figure { - margin-left: -1 * $gutter; - margin-right: -1 * $gutter; - // full width figures on small screens - @include media($medium) { - margin-left: 0; - margin-right: 0; - position: relative; - } - @include clearfix; - img { - margin-bottom: 0px + $doc-line-height; - margin-bottom: 0rem + ($doc-line-height / $doc-font-size); - } - a { - img { - // Image hover animation - &:hover { - @include animation(pop .3s 0 linear); - box-shadow: 0 0 10px rgba($black, .20); - } - } - } - &.half { - @include outer-container; - @include media($medium) { - a, - > img { - @include span-columns(6); - @include omega(2n); - } - figcaption { - clear: left; - } - } - } - &.third { - @include outer-container; - @include media($medium) { - a, - > img { - @include span-columns(4); - @include omega(3n); - } - figcaption { - clear: left; - } - } - } -} - -// Fix IE9 SVG bug -svg:not(:root) { - overflow: hidden; -} - - -// FORMS -// -------------------------------------------------- - -fieldset { - background: lighten($border-color, 10); - border: 1px solid $border-color; - margin-bottom: 0px + $doc-line-height; - margin-bottom: 0rem + ($doc-line-height / $doc-font-size); - padding: $gutter; - border-radius: $border-radius; -} - -input, -label, -select { - display: block; - @include font-size($form-font-size,no); -} - -label { - font-weight: bold; - font-family: $alt-font; - margin-bottom: (0px + $doc-line-height) / 4; - margin-bottom: (0rem + ($doc-line-height / $doc-font-size)) / 4; - &.required:after { - content: "*"; - } - abbr { - display: none; - } -} - -textarea, -#{$all-text-inputs}, -select, -select[multiple=multiple] { - @include box-sizing(border-box); - @include transition(border-color); - background-color: white; - border-radius: $form-border-radius; - border: 1px solid $form-border-color; - box-shadow: $form-box-shadow; - font-family: $form-font-family; - font-size: $form-font-size; - margin-bottom: (0px + $doc-line-height) / 2; - margin-bottom: (0rem + ($doc-line-height / $doc-font-size)) / 2; - padding: ((0px + $doc-line-height) / 3) ((0px + $doc-line-height) / 3); - padding: ((0rem + ($doc-line-height / $doc-font-size)) / 3) ((0rem + ($doc-line-height / $doc-font-size)) / 3); - width: 100%; - &:hover { - border-color: $form-border-color-hover; - } - &:focus { - border-color: $form-border-color-focus; - box-shadow: $form-box-shadow-focus; - outline: none; - } -} - -textarea { - resize: vertical; -} - -input[type="search"] { - @include appearance(none); -} - -input[type="checkbox"], input[type="radio"] { - display: inline; - margin-right: (0px + $doc-line-height) / 4; - margin-right: (0rem + ($doc-line-height / $doc-font-size)) / 4; -} - -input[type="file"] { - width: 100%; -} - -select { - width: auto; - max-width: 100%; - margin-bottom: 0px + $doc-line-height; - margin-bottom: 0rem + ($doc-line-height / $doc-font-size); -} - -form button, -input[type="submit"] { - @extend .btn; - @include appearance(none); - cursor: pointer; - user-select: none; - vertical-align: middle; - white-space: nowrap; -} - -// NAVIGATION -// -------------------------------------------------- - -nav { - ul { - margin: 0; - padding: 0; - } - li { - list-style: none; - } - a { - text-decoration: none; - } -} - -// GLOBAL TRANSITION -// -------------------------------------------------- -b, i, strong, em, blockquote, p, q, span, figure, img, h1, h2, header, input, a, tr, td, .highlight { - @include transition (color 0.2s ease-out, opacity 0.2s ease-out, background 0.2s ease-out, border-color 0.2s ease-out); -} \ No newline at end of file diff --git a/vitess.io/_sass/_bullets.scss b/vitess.io/_sass/_bullets.scss deleted file mode 100644 index 643d18e1184..00000000000 --- a/vitess.io/_sass/_bullets.scss +++ /dev/null @@ -1,49 +0,0 @@ -// VISUAL BULLETS (IMAGE + TEXT) -// -------------------------------------------------- - -.bullets { - $icon-bullet-size: $column; - overflow: auto; - - // change ".three-col-bullet" class to this for two bullet layout - .two-col-bullet { - @include media($large) { - @include span-columns(6); - @include omega(2n); - } - } - .three-col-bullet { - @include media($large) { - @include span-columns(4); - @include omega(3n); - } - } - // change ".three-col-bullet" class to this for four bullet layout - .four-col-bullet { - @include media($large) { - @include span-columns(3); - @include omega(4n); - } - } - - .bullet-icon { - float: left; - background: $base-color; - padding: $icon-bullet-size /4; - border-radius: 50%; - width: $icon-bullet-size * 1.25; - height: $icon-bullet-size * 1.25; - } - .bullet-content { - margin-left: $icon-bullet-size * 1.4; - margin-bottom: 2em; - } - h2 { - margin-top: 0; - @include font-size(20,no); - display: inline-block; - } - p { - @include font-size(14); - } -} \ No newline at end of file diff --git a/vitess.io/_sass/_buttons.scss b/vitess.io/_sass/_buttons.scss deleted file mode 100644 index 003b119d05c..00000000000 --- a/vitess.io/_sass/_buttons.scss +++ /dev/null @@ -1,122 +0,0 @@ -// BUTTONS -// -------------------------------------------------- - -// call to action -.btn { - display: inline-block; - padding: 8px 20px; - @include font-size(14); - font-family: $alt-font; - background-color: $primary-color; - color: $white; - text-decoration: none; - border: 0 !important; - border-radius: 10 * $border-radius; - @include transition(background 0.2s, border 0.2s); - &:hover { - color: $white; - background-color: lighten($primary-color, 10); - } - &:active { - // move button slightly on click - @include transform(translateY(1px)); - } -} -.btn-inverse { - @extend .btn; - background-color: $white; - color: $text-color; - &:visited, - &:active { - color: $text-color; - } - &:hover { - color: $white; - background-color: $text-color; - } -} -.btn-info { - @extend .btn; - background-color: $info-color; - color: $white; - &:visited { - color: $white; - } - &:hover { - background-color: lighten($info-color, 10); - } -} -.btn-warning { - @extend .btn; - background-color: $warning-color; - color: $white; - &:visited { - color: $white; - } - &:hover { - background-color: lighten($warning-color ,10); - } -} -.btn-success { - @extend .btn; - background-color: $success-color; - color: $white; - &:visited { - color: $white; - } - &:hover { - background-color:lighten($success-color, 10); - } -} -.btn-danger { - @extend .btn; - background-color: $danger-color; - color: $white; - &:visited { - color: $white; - } - &:hover { - background-color: lighten($danger-color, 10); - } -} -.btn-social { - $social: - (facebook, $facebook-color), - (flickr, $flickr-color), - (foursquare, $foursquare-color), - (google-plus, $google-plus-color), - (instagram, $instagram-color), - (linkedin, $linkedin-color), - (pinterest, $pinterest-color), - (rss, $rss-color), - (tumblr, $tumblr-color), - (twitter, $twitter-color), - (vimeo, $vimeo-color), - (youtube, $youtube-color); - @extend .btn-inverse; - color: $text-color !important; - &:visited, - &:active { - color: $text-color; - } - border: 1px solid $border-color !important; - @each $socialnetwork, $color in $social { - i.fa-#{$socialnetwork} { - color: $color; - } - } - &:hover { - color: $white !important; - } - @each $socialnetwork, $color in $social { - &.#{$socialnetwork}:hover { - background: $color; - border-color: $color; - @each $socialnetwork, $color in $social { - i.fa-#{$socialnetwork} { - color: $white; - } - } - } - } -} \ No newline at end of file diff --git a/vitess.io/_sass/_gist.scss b/vitess.io/_sass/_gist.scss deleted file mode 100644 index 456a2cf5f3a..00000000000 --- a/vitess.io/_sass/_gist.scss +++ /dev/null @@ -1,20 +0,0 @@ -//Set max height of embedded gist -.gist div { - max-height:75em; -} - -//Remove extra padding -.gist table { - margin-top:0px; - -} - -//Remove hover effect -.gist tbody -{ - tr:hover > td, tr:hover > th { - background-color:transparent; - }; - background-color:white; //Background color white -} - diff --git a/vitess.io/_sass/_grid-settings.scss b/vitess.io/_sass/_grid-settings.scss deleted file mode 100644 index 452872c18af..00000000000 --- a/vitess.io/_sass/_grid-settings.scss +++ /dev/null @@ -1,11 +0,0 @@ -@import "vendor/neat/neat-helpers"; - -// Change the grid settings -$visual_grid: false; - -// Define your breakpoints -$short: new-breakpoint(max-height em(700) 12); -$micro: new-breakpoint(min-width em(240) max-width em(480) 12); -$small: new-breakpoint(min-width em(480) max-width em(767) 12); -$medium: new-breakpoint(min-width em(768) 12); -$large: new-breakpoint(min-width em(1000) 12); \ No newline at end of file diff --git a/vitess.io/_sass/_helpers.scss b/vitess.io/_sass/_helpers.scss deleted file mode 100644 index 15227f61ae0..00000000000 --- a/vitess.io/_sass/_helpers.scss +++ /dev/null @@ -1,123 +0,0 @@ -// GLOBAL -// -------------------------------------------------- - -.wrap { - @include outer-container; -} - -.come-in { - @include transform(translateY(20px)); - @include animation(pop 0.5s ease forwards); -} - -.already-visible { - @include transform(translateY(0)); - @include animation(none); -} - -.hidden, -.load { - display: none; -} - -.no-scroll { - overflow: hidden; -} - -.inline-btn { - @include clearfix; - a, btn { - display: inline-block; - margin-right: $gutter / 2; - &:last-child { - margin-right: 0; - } - } -} - -// shorten length to improve readability -@include media($medium) { - .shorten { - width: percentage(8/12); - } -} - -.center { - text-align: center; -} - -.image-right { - display: block; - margin-left: auto; - margin-right: auto; - @include media($medium) { - float: right; - margin-left: $gutter; - } -} - - -// thumbnail image grid default -.th-grid { - @include row($direction: LTR); - @include clearfix; - margin: 0; - padding: 0; - li { - list-style: none; - @include span-columns(3); - @include omega(4n); - margin-bottom: flex-gutter($grid-columns); - } - a { - img { - // Image hover animation - &:hover { - @include animation(pop .3s 0 linear); - box-shadow: 0 0 10px rgba($black, .20); - } - } - } -} -// thumbnail image grid oversized -.th-grid-full { - @include clearfix; - margin: 0; - padding: 0; - @include media($large) { - margin-right: -29em; // magic number ugh - } - @at-root { - .archive-wrap & { - margin-right: 0; - } - } - li { - list-style: none; - margin-bottom: flex-gutter($grid-columns); - @include media($micro) { - @include span-columns(3); - @include omega(4n); - } - @media screen and (min-width: em(480)) and (max-width: em(999)) { - @include span-columns(3); - @include omega(4n); - } - @include media($large) { - float: left; - width: 6.575em; - margin-right: .25em; // magic number ugh - margin-bottom: .25em; // magic number ugh - @include omega(9n); - } - } - a { - img { - // Image hover animation - &:hover { - @include animation(pop .3s 0 linear); - box-shadow: 0 0 10px rgba($black, .20); - } - } - } -} diff --git a/vitess.io/_sass/_layout.scss b/vitess.io/_sass/_layout.scss deleted file mode 100644 index 8eaa2fc5f65..00000000000 --- a/vitess.io/_sass/_layout.scss +++ /dev/null @@ -1,471 +0,0 @@ -// MASTHEAD -// -------------------------------------------------- - -#masthead { - padding: $gutter; - z-index: 5; - @include transform(translate(0,0)); - @include transition(500ms cubic-bezier(.645,.045,.355,1.000)); - &.slide { - @include transform(translate(-1600px,0)); - } - .inner-wrap { - @include outer-container; - } -} -.site-title { - @include row; - @include media($large) { - @include span-columns(4); - } - padding: (.25 * $masthead-height) 0; // fourth the height to center vertically - height: $masthead-height; - text-decoration: none; - color: $black; - font-family: $alt-font; - font-weight: 700; - @include font-size(20,no); - line-height: .5 * $masthead-height; // half the height to center vertically - text-transform: uppercase; -} - - -// NAVIGATIONS -// -------------------------------------------------- - -.menu { - li { - float: left; - &:last-child a { - @include media($medium) { - margin-right: 0; // remove spacing from last menu link - } - } - a { - // line hover effect - position: relative; - display: block; - margin-right: $gutter; - padding: (.25 * $masthead-height) 0 (.25 * $masthead-height) ; - height: $masthead-height; - font-family: $alt-font; - &:before, - &:after { - content: ''; - display: block; - position: absolute; - top: 0; - left: 0; - height: 2px; - @include transition(width 0.3s); - } - &:before { - width: 100%; - background: transparent; - } - &:after { - width: 0; - background: $black; - } - &:active:after, - &:hover:after { - width: 100%; - } - } - } -} - -.top-menu { - display: none; - position: relative; - @include media($medium) { - @include span-columns(12); - } - @include media($large) { - @include span-columns(7); - ul { - position: absolute; - right: 0; - } - } - .home, - .sub-menu-item { - display: none; - } - li { - a { - font-weight: 700; - @include font-size(16,no); - line-height: .5 * $masthead-height; // half the height to center vertically - color: $black; - text-transform: uppercase; - } - } -} -.bottom-menu { - @include clearfix; - font-weight: 700; - a { - color: lighten($black,60); - } -} - - -// PAGE WRAPPER -// -------------------------------------------------- - -#page-wrapper { - padding: 0 $gutter; // add white space for smaller screens - @include size(100% 100%); - -webkit-overflow-scrolling: touch; - z-index: 2; - @include transform(translate(0,0)); - @include transition(500ms cubic-bezier(.645,.045,.355,1.000)); - &.slide { - @include transform(translate(-60rem,0)); - } -} - - -// BROWSER UPGRADE -// -------------------------------------------------- - -.upgrade { - text-align: center; - a { - text-decoration: none; - } -} - - -// MAIN -// -------------------------------------------------- - -#main { - .inner-wrap { - @include media($medium) { - @include span-columns(12); - } - } - .toc { - @include media($medium) { - @include row($direction: RTL); - } - @include media($large) { - @include span-columns(2 of 9); - } - } - .page-title { - @include fill-parent; - } - @at-root { - .page-content { - @include media($medium) { - @include row($direction: RTL); - //@include span-columns(7 of 9); - } - @include media($large) { - @include span-columns(7 of 9); - } - // larger font for intro paragraph - > p { - &:first-child { - @include font-size(20,yes,30); - } - } - // cleaner underlines for links - a { text-decoration: none; } - p > a, - li > a { - border-bottom: 1px dotted lighten($link-color, 50); - &:hover { - border-bottom-style: solid; - } - } - p > a.reversefootnote { - border-bottom-width: 0; - } - .page-footer, - .pagination { - @include fill-parent; - } - .page-meta { - p{ - @include font-size(14,no); - font-family: $alt-font; - color: lighten($black,60); - } - } - } - } - @at-root { - .archive-wrap { - @include fill-parent; - .page-content { - @include reset-all; - @include fill-parent; - } - } - } - .ads { - position: relative; - text-align: center; - margin-top: $gutter; - margin-left: -$gutter; - margin-right: -$gutter; - padding: 10px 0 20px; - background: lighten($border-color,5); - @include media($medium) { - @include span-columns(3); - margin-left: 0; - margin-right: 0; - } - &:after { - content: 'Advertisement'; - position: absolute; - bottom: 0; - width: 100%; - text-align: center; - display: block; - @include font-size(9,no); - font-family: $alt-font; - } - ins { - border-width: 0; - } - } -} -// page lead -.page-lead { - background-position: center top; - background-repeat: no-repeat; - background-attachment: fixed; - text-align: center; - color: $white; - @include media($large) { - background-size: cover; - } -} -.page-lead-content { - padding: 1em; - @include media($medium) { - padding: 2em; - } - @include media($large) { - padding: 3em; - } - h1 { - @include font-size(48); - @include media($medium) { - @include font-size(60); - } - @include media($large) { - @include font-size(72); - } - } - h2 { - @include font-size(20); - @include media($medium) { - @include font-size(24); - } - @include media($large) { - @include font-size(32); - } - } -} -// page header -.page-feature { - @include fill-parent; - // expand image to cover full width of header - img { - width: 100%; - } -} -// make image flush with edges on small screens -.page-image { - position: relative; - margin-left: -1 * $gutter; - margin-right: -1 * $gutter; - // Feature Image Caption - .image-credit { - position: absolute; - bottom: 0; - right: 0; - margin: 0 auto; - padding: 10px 15px; - background-color: rgba($black,.5); - color: $white; - font-family: $alt-font; - @include font-size(12,no); - text-align: right; - z-index: 10; - a { - color: $white; - text-decoration: none; - } - } -} -// breadcrumbs -.breadcrumbs { - @include row; - margin-top: $gutter; - @include font-size(10,no); - a { - display: inline-block; - font-family: $alt-font; - font-weight: 700; - text-align: left; - text-transform: uppercase; - } -} -// table of contents -.toc { - min-height: 1px; - ul { - margin-top: $gutter; - border: 1px solid $border-color; - border-radius: $border-radius; - } - li { - @include media($micro) { @include font-size(16,no,18); } - @include media($small) { @include font-size(16,no,18); } - @include font-size(12,no,16); - border-bottom: 1px solid $border-color; - } - font-family: $alt-font; - a { - display: block; - padding: (.25 * $gutter) (.5 * $gutter); - border-left: 2px solid transparent; - &:hover, - &:focus { - background: lighten($border-color,5); - } - } -} -// tiles -.tile { - @include outer-container; - margin-bottom: $gutter; - @include media($micro) { - @include fill-parent; - } - @include media($small) { - @include span-columns(6); - @include omega(2n); - } - @include media($medium) { - @include span-columns(3); - @include omega(4n); - } - .entry-date { - @include font-size(16,no); - color: lighten($text-color,25); - } - .post-title { - @include font-size(18,no); - } - .post-excerpt { - @include font-size(16); - } - .post-teaser { - position: relative; - display: block; - &:after { - content: ''; - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - background: rgba($base-color,0); - pointer-events: none; - @include transition(background 0.3s); - } - &:hover { - &:after { - background: rgba($base-color,0.2); - } - } - } -} -// footnotes -.footnotes { - font-family: $alt-font; - p, li { - @include font-size(12,no); - } - &:before { - content: 'Footnotes:'; - font-weight: 700; - } -} -// page footer -.page-footer { - position: relative; -} -.author-image { - position: absolute; - left: 0; - img { - width: 80px; - height: 80px; - border-radius: $border-radius; - } -} -.author-content { - word-wrap: break-word; - padding-left: 100px; //avatar width + 20px padding - min-height: 80px; //mirrors avatar height -} -.author-name { - @include font-size(20,no); -} -.author-bio { - margin-top: 0; - @include font-size(16); -} - - -// SCROLL ARROW CUE -// -------------------------------------------------- - -#scroll-cue { - position: fixed; - bottom: 100px; - @include media($short) { - bottom: 0; - } - left: 50%; - width: 2 * $button-size; - height: 2 * $button-size; - text-align: center; - cursor: pointer; - color: $white; - @include font-size(12); - font-family: $alt-font; - text-decoration: none; - text-transform: uppercase; - text-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5); - letter-spacing: 2px; -} - - -// FOOTER -// -------------------------------------------------- - -#site-footer { - @include outer-container; - margin-top: (3 * (0px + $doc-line-height)); - margin-top: (3 * (0rem + ($doc-line-height / $doc-font-size))); - padding-bottom: $gutter; - font-family: $alt-font; - .copyright { - @include font-size(12); - color: lighten($black,60); - a { - color: lighten($black,60); - text-decoration: none; - } - } -} \ No newline at end of file diff --git a/vitess.io/_sass/_mixins.scss b/vitess.io/_sass/_mixins.scss deleted file mode 100644 index 5c7f3956360..00000000000 --- a/vitess.io/_sass/_mixins.scss +++ /dev/null @@ -1,94 +0,0 @@ -// MIXINS -// -------------------------------------------------- - -%tab-focus { - // Default - outline: thin dotted #333; - // Webkit - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px; -} - - -// Typography -// -------------------------------------------------- - -/* Vertical Rhythm - https://github.com/sturobson/Sassifaction - - In this mixin you can specify the font size in PX and - it will calculate the REM based on your $doc-font-size - & $doc-line-height variables. - - @include font-size(24); - - It will also create a bottom margin based on the - $doc-font-size & $doc-line-height variables unless you - specify that it shouldn't have one. - - @include font-size(24, no); - - Or if you want to specify a different bottom margin to - be generated. - - @include font-size(24,32); - - This mixin also generates a pixel-less line height by - default unless you specify that you either don't want - one where I'd suggest declaring 1 within the mixin. - - @include font-size(24, yes, 1); - - There's also the option to specify a different line-height - for it to generate to, where you would specify the - line-height in (effectively) it's pixel value. - - @include font-size(24, yes, 40); -*/ - -@mixin font-size($size, $margin: yes, $line-height: $doc-line-height) { - - // generates the font-size in REMs with a PX fallback - font-size: 0px + $size; - font-size: 0rem + $size / $doc-font-size; - - // line-height functions - //////////////////////// - - // if you a line-height is specified in the mixin - @if $line-height != $doc-line-height and $line-height != 1 { - line-height: ceil($size / $line-height) * ($line-height / $size); - } - - // if $line-height == 1 - // because, typing 1 is quicker than 16 - @else if $line-height == 1 { - line-height: 1; - } - - // normal $line-height - // if the line-height is left. - @else { - line-height: ceil($size / $doc-line-height) * ($doc-line-height / $size); - } - - // margin-bottom functions - ////////////////////////// - - // if no is bottom margin is required - @if $margin == no { - margin-bottom: 0; - } - - // if a specific bottom margin is required - @else if $margin != yes and $margin != no { - margin-bottom: 0px + $margin; - margin-bottom: 0rem + ($margin / $doc-font-size); - } - - // if you're keeping the vertical rhythm with the margin - @else { - margin-bottom: 0px + $doc-line-height; - margin-bottom: 0rem + ($doc-line-height / $doc-font-size); - } -} \ No newline at end of file diff --git a/vitess.io/_sass/_notices.scss b/vitess.io/_sass/_notices.scss deleted file mode 100644 index 9edec71bdfb..00000000000 --- a/vitess.io/_sass/_notices.scss +++ /dev/null @@ -1,38 +0,0 @@ -// NOTICES -// -------------------------------------------------- - -@mixin notice($notice-color) { - position: relative; - padding: 1.5em; - font-family: $alt-font; - @include font-size(14,39); - color: $white; - background-color: $notice-color; - border-radius: $border-radius; - a { - color: $white; - border-bottom: 1px dotted $white; - } -} -.notice { - @include notice($primary-color); -} -.notice-inverse { - @include notice($white); - color: $text-color; - a { - color: $text-color; - } -} -.notice-info { - @include notice($info-color); -} -.notice-warning { - @include notice($warning-color); -} -.notice-success { - @include notice($success-color); -} -.notice-danger { - @include notice($danger-color); -} \ No newline at end of file diff --git a/vitess.io/_sass/_pygments.scss b/vitess.io/_sass/_pygments.scss deleted file mode 100644 index 0bf086629ac..00000000000 --- a/vitess.io/_sass/_pygments.scss +++ /dev/null @@ -1,104 +0,0 @@ -// PYGMENTS.RB SYNTAX HIGHLIGHTING -// -------------------------------------------------- - -.linenos, -.code { - padding: 0; - border-top: 0 solid transparent; - border-bottom: 0 solid transparent; -} - -.highlight { - overflow-x: auto; - @include font-size(16); - border: 1px solid darken($body-color, 5); - border-radius: $border-radius; - pre { - position: relative; - margin: 0; - padding: 1em; - } - &:hover { - border: 1px solid $form-border-color-hover; - } -} - -.highlighttable { - tr:hover>td, - tr:hover>th { - background: transparent - } -} - -.hll { background-color: #ffffcc } - -.err { color: #a61717; background-color: #e3d2d2 } // Error - -.k { color: #000000; font-weight: bold } // Keyword - -.o { color: #000000; font-weight: bold } // Operator - -.c { color: #999988; font-style: italic } // Comment -.cm { color: #999988; font-style: italic } // Comment.Multiline -.cp { color: #999999; font-weight: bold; font-style: italic } // Comment.Preproc -.c1 { color: #999988; font-style: italic } // Comment.Single -.cs { color: #999999; font-weight: bold; font-style: italic } // Comment.Special - - -.gd { color: #000000; background-color: #ffdddd } // Generic.Deleted -.ge { color: #000000; font-style: italic } // Generic.Emph -.gr { color: #aa0000 } // Generic.Error -.gh { color: #999999 } // Generic.Heading -.gi { color: #000000; background-color: #ddffdd } // Generic.Inserted -.go { color: #888888 } // Generic.Output -.gp { color: #555555 } // Generic.Prompt -.gs { font-weight: bold } // Generic.Strong -.gu { color: #aaaaaa } // Generic.Subheading -.gt { color: #aa0000 } // Generic.Traceback - -.kc { color: #000000; font-weight: bold } // Keyword.Constant -.kd { color: #000000; font-weight: bold } // Keyword.Declaration -.kn { color: #000000; font-weight: bold } // Keyword.Namespace -.kp { color: #000000; font-weight: bold } // Keyword.Pseudo -.kr { color: #000000; font-weight: bold } // Keyword.Reserved -.kt { color: #445588; font-weight: bold } // Keyword.Type - -.m { color: #009999 } // Literal.Number -.mf { color: #009999 } // Literal.Number.Float -.mh { color: #009999 } // Literal.Number.Hex -.mi { color: #009999 } // Literal.Number.Integer -.mo { color: #009999 } // Literal.Number.Oct -.il { color: #009999 } // Literal.Number.Integer.Long -.s { color: #d01040 } // Literal.String -.sb { color: #d01040 } // Literal.String.Backtick -.sc { color: #d01040 } // Literal.String.Char -.sd { color: #d01040 } // Literal.String.Doc -.s2 { color: #d01040 } // Literal.String.Double -.se { color: #d01040 } // Literal.String.Escape -.sh { color: #d01040 } // Literal.String.Heredoc -.si { color: #d01040 } // Literal.String.Interpol -.sx { color: #d01040 } // Literal.String.Other -.sr { color: #009926 } // Literal.String.Regex -.s1 { color: #d01040 } // Literal.String.Single -.ss { color: #990073 } // Literal.String.Symbol - -.na { color: #008080 } // Name.Attribute -.nb { color: #0086B3 } // Name.Builtin -.nc { color: #445588; font-weight: bold } // Name.Class -.no { color: #008080 } // Name.Constant -.nd { color: #3c5d5d; font-weight: bold } // Name.Decorator -.ni { color: #800080 } // Name.Entity -.ne { color: #990000; font-weight: bold } // Name.Exception -.nf { color: #990000; font-weight: bold } // Name.Function -.nl { color: #990000; font-weight: bold } // Name.Label -.nn { color: #555555 } // Name.Namespace -.nt { color: #000080 } // Name.Tag -.bp { color: #999999 } // Name.Builtin.Pseudo -.nv { color: #008080 } // Name.Variable -.vc { color: #008080 } // Name.Variable.Class -.vg { color: #008080 } // Name.Variable.Global -.vi { color: #008080 } // Name.Variable.Instance - -.ow { color: #000000; font-weight: bold } // Operator.Word - -.w { color: #bbbbbb } // Text.Whitespace \ No newline at end of file diff --git a/vitess.io/_sass/_reset.scss b/vitess.io/_sass/_reset.scss deleted file mode 100644 index b91409ba1e6..00000000000 --- a/vitess.io/_sass/_reset.scss +++ /dev/null @@ -1,143 +0,0 @@ -// STYLE RESETS -// Adapted from http://github.com/necolas/normalize.css -// -------------------------------------------------- - -// Apply a natural box layout model to all elements -*, *:before, *:after { - -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; - } - -// Remove margin -body { margin: 0; } - -// Display HTML5 elements in IE6-9 and FF3 -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -nav, -section { - display: block; -} - -// Display block in IE6-9 and FF3 -audio, -canvas, -video { - display: inline-block; - *display: inline; - *zoom: 1; -} - -// Prevents modern browsers from displaying 'audio' without controls -audio:not([controls]) { - display: none; -} - -// Base font settings -html { - font-size: 100%; - -webkit-text-size-adjust: 100%; - -ms-text-size-adjust: 100%; -} -// Apply focus state -a:focus { - @extend %tab-focus; -} - -// Remove outline -a:hover, -a:active { - outline: 0; -} - -// Prevent sub and sup affecting line-height in all browsers -sub, -sup { - position: relative; - font-size: 75%; - line-height: 0; - vertical-align: baseline; -} -sup { - top: -0.5em; -} -sub { - bottom: -0.25em; -} - -// Normalize blockquotes -blockquote { - margin: 0; -} - -// Img border in a's and image quality -img { - // Responsive images (ensure images don't scale beyond their parents) - max-width: 100%; // Part 1: Set a maximum relative to the parent - width: auto\9; // IE7-8 need help adjusting responsive images - height: auto; // Part 2: Scale the height according to the width, otherwise you get stretching - - vertical-align: middle; - border: 0; - -ms-interpolation-mode: bicubic; -} - -// Prevent max-width from affecting Google Maps -#map_canvas img, -.google-maps img { - max-width: none; -} - -// Consistent form font size in all browsers, margin changes, misc -button, -input, -select, -textarea { - margin: 0; - font-size: 100%; - vertical-align: middle; -} -button, -input { - *overflow: visible; // Inner spacing ie IE6/7 - line-height: normal; // FF3/4 have !important on line-height in UA stylesheet -} -button::-moz-focus-inner, -input::-moz-focus-inner { // Inner padding and border oddities in FF3/4 - padding: 0; - border: 0; -} -button, -html input[type="button"], // Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` and `video` controls. -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; // Corrects inability to style clickable `input` types in iOS. - cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. -} -label, -select, -button, -input[type="button"], -input[type="reset"], -input[type="submit"], -input[type="radio"], -input[type="checkbox"] { - cursor: pointer; // Improves usability and consistency of cursor style between image-type `input` and others. -} -input[type="search"] { // Appearance in Safari/Chrome - @include box-sizing(content-box); - -webkit-appearance: textfield; -} -input[type="search"]::-webkit-search-decoration, -input[type="search"]::-webkit-search-cancel-button { - -webkit-appearance: none; // Inner-padding issues in Chrome OSX, Safari 5 -} -textarea { - overflow: auto; // Remove vertical scrollbar in IE6-9 - vertical-align: top; // Readability and alignment cross-browser -} \ No newline at end of file diff --git a/vitess.io/_sass/_sliding-menu.scss b/vitess.io/_sass/_sliding-menu.scss deleted file mode 100644 index b023cf967ca..00000000000 --- a/vitess.io/_sass/_sliding-menu.scss +++ /dev/null @@ -1,257 +0,0 @@ -// OFF CANVAS SLIDING MENU -// Based on code by Diego Eis -// -------------------------------------------------- - -.sliding-menu-button { - position: fixed; - top: $gutter; - right: $gutter; - display: block; - width: $button-size * 2; - height: $button-size * 2; - background: #000; - outline: 0; - padding: 0; - border: 2.5px solid transparent; - cursor: pointer; - z-index: 5; - -moz-box-sizing: border-box; - -webkit-box-sizing: border-box; - box-sizing: border-box; - @include media($medium) { - @include transform(0); - } - @include transition(right 500ms cubic-bezier(.645,.045,.355,1.000)); - &.slide { - @include media($medium) { - right: 90%; - } - @include transition(right 500ms ease-in-out); - } -} - -.sliding-menu-content { - position: fixed; - top: 0; - right: 0; - padding: em(22) 0; - text-align: center; - visibility: hidden; - @include media($medium) { - text-align: left; - } - @include size(100% 100%); - @include media($medium) { - @include size(87% 100%); - } - @include transform(translateX(100%)); - @include transition(500ms cubic-bezier(.645,.045,.355,1.000)); - background: $sliding-menu-background; - z-index: 5; - overflow-y: auto; - overflow-x: hidden; - -webkit-overflow-scrolling: touch; - &.is-visible { - visibility: visible; - @include transform(translateX(0)); - @include transition(500ms ease-in-out); - } - ul { - margin: 0 10%; - } - ul, - li { - list-style: none; - } - li { - display: block; - position: relative; - padding: 1em 0; - } - .menu-item > li { - a { - color: $white; - text-decoration: none; - } - .teaser { - width: 150px; - border: 2px solid $white; - margin-bottom: ($gutter / 2); - @include media($medium) { - position: absolute; - top: 20px; - left: 0; - margin-bottom: 0; - } - } - .title { - display: block; - font-family: $alt-font; - @include font-size(32,no); - font-weight: 700; - @include media($medium) { - margin-left: 170px; - } - } - .excerpt { - color: $white; - margin-top: 0; - @include media($medium) { - margin-left: 170px; - } - } - } - .sub-menu-item > li a { - display: block; - color: $white; - font-style: italic; - } - .menu-item .home a { - @include font-size(32); - } -} - -.menu-screen { - @include position(fixed, 0px 0px 0px 0px); - @include transition; - background: $sliding-menu-border-color; - opacity: 0; - visibility: hidden; - z-index: 4; - &.is-visible { - opacity: .4; - visibility: visible; - &:hover { - cursor: pointer; - } - } -} - -// animated navicons -// https://github.com/SaraSoueidan/navicon-transformicons -// common to all three-liners -@mixin menuline { - display: inline-block; - width: $button-size; - height: $button-size/7; - background: $white; - border-radius: $button-size/14; - transition: $transition; -} -// common to all three-liners -.menulines { - @include menuline; - position: relative; - &:before, &:after { - @include menuline; - position: absolute; - left:0; - content: ''; - -webkit-transform-origin: $button-size/14 center; - transform-origin: $button-size/14 center; - } - &:before { - top: $button-size/4; - } - &:after { - top: -$button-size/4; - } -} -// common to all three-liners -.menulines-button:hover { - .menulines { - &:before { - top: $button-size/3.5; - } - &:after { - top: -$button-size/3.5; - } - } -} -// for both the arrow up and left icons -.menulines-button.arrow.close { - .menulines { - &:before, - &:after { - top: 0; - width: $button-size/1.8; - } - &:before { - -webkit-transform: rotate3d(0,0,1,40deg); - transform: rotate3d(0,0,1,40deg); - } - &:after { - -webkit-transform: rotate3d(0,0,1,-40deg); - transform: rotate3d(0,0,1,-40deg); - } - } -} -// arrow up only: just rotate by 90degrees -.menulines-button.arrow-up.close { - -webkit-transform: scale3d(.8,.8,.8) rotate3d(0,0,1,90deg); - transform: scale3d(.8,.8,.8) rotate3d(0, 0, 1,90deg); -} -// three-lines to minus only -.menulines-button.minus.close{ - .lines { - &:before, &:after{ - -webkit-transform: none; - transform: none; - top:0; - width: $button-size; - } - } -} -// three-lines to x -.menulines-button.x.close{ - .menulines { - background: transparent; - &:before, &:after{ - -webkit-transform-origin: 50% 50%; - transform-origin: 50% 50%; - top:0; - width: $button-size; - } - &:before{ - -webkit-transform: rotate3d(0,0,1,45deg); - transform: rotate3d(0,0,1,45deg); - } - &:after{ - -webkit-transform: rotate3d(0,0,1,-45deg); - transform: rotate3d(0,0,1,-45deg); - } - } -} -// three-lines to x method 2 -.menulines-button.x2{ - .menulines{ - transition: background .3s .5s ease; - &:before, &:after{ - //set transform origin - -webkit-transform-origin: 50% 50%; - transform-origin: 50% 50%; - transition: top .3s .6s ease, -webkit-transform .3s ease; - transition: top .3s .6s ease, transform .3s ease; - } - } -} -.menulines-button.x2.close{ - .menulines { - transition: background .3s 0s ease; - background: transparent; - &:before, &:after{ - transition: top .3s ease, -webkit-transform .3s .5s ease;//delay the formation of the x till the minus is formed - transition: top .3s ease, transform .3s .5s ease;//delay the formation of the x till the minus is formed - top:0; - width: $button-size; - } - &:before{ - -webkit-transform: rotate3d(0,0,1,45deg); - transform: rotate3d(0,0,1,45deg); - } - &:after{ - -webkit-transform: rotate3d(0,0,1,-45deg); - transform: rotate3d(0,0,1,-45deg); - } - } -} \ No newline at end of file diff --git a/vitess.io/_sass/_variables.scss b/vitess.io/_sass/_variables.scss deleted file mode 100644 index 8537f74953f..00000000000 --- a/vitess.io/_sass/_variables.scss +++ /dev/null @@ -1,82 +0,0 @@ -// SASS VARIABLES -// -------------------------------------------------- - -// Typography variables - -$base-font : Georgia,Times,"Times New Roman",serif; -$heading-font : "Helvetica Neue","Segoe UI",Arial,sans-serif; -$caption-font : $base-font; -$code-font : monospace; -$alt-font : $heading-font; - -$doc-font-size : 16; -$doc-line-height : 24; - -$border-radius : 3px; - - -// Color variables - -$body-color : #ebebeb; -$text-color : #313130; -$base-color : #343434; -$comp-color : complement($base-color); -$border-color : #ddd; -$white : #fff; -$black : #000; -$link-color : #222; -$primary-color : $black; -$success-color : #2ecc71; -$warning-color : #f1c40f; -$danger-color : #e74c3c; -$info-color : #3498db; - -$table-border-color : $border-color; -$table-border : 1px solid $table-border-color; -$table-background : $body-color; -$table-header-color : lighten($table-background, 10); -$table-hover-color : darken($table-background, 2); -$table-stripe-color : darken($table-background, 4); -$table-stripe-color-hover : darken($table-stripe-color, 5); - -$facebook-color : #3b5998; -$flickr-color : #ff0084; -$foursquare-color : #0cbadf; -$google-plus-color : #dd4b39; -$instagram-color : #4e433c; -$linkedin-color : #4875b4; -$pinterest-color : #cb2027; -$rss-color : #fa9b39; -$tumblr-color : #2c4762; -$twitter-color : #55acee; -$vimeo-color : #1ab7ea; -$youtube-color : #ff3333; - - -// Form variables - -$form-border-color : $border-color; -$form-border-color-hover : darken($border-color, 10); -$form-border-color-focus : $primary-color; -$form-border-radius : $border-radius; -$form-box-shadow : inset 0 1px 3px hsla(0, 0%, 0%, 0.06); -$form-box-shadow-focus : $form-box-shadow, 0 0 5px rgba(darken($form-border-color-focus, 5), 0.7); -$form-font-family : $base-font; -$form-font-size : $doc-font-size; - - -// Sliding Menu Navigation - -$sliding-menu-border-color : $black; -$sliding-menu-background : $black; -$sliding-menu-color : $white; -$sliding-menu-background-hover : $black; -$sliding-menu-color-hover : $white; -$sliding-menu-border : 1px solid $sliding-menu-border-color; -$button-size : 30px; -$transition : .3s; // increase this to see the transformations in slow-motion - - -// Masthead - -$masthead-height: $button-size * 2; \ No newline at end of file diff --git a/vitess.io/_sass/vendor/bourbon/_bourbon-deprecated-upcoming.scss b/vitess.io/_sass/vendor/bourbon/_bourbon-deprecated-upcoming.scss deleted file mode 100644 index f946b3b456d..00000000000 --- a/vitess.io/_sass/vendor/bourbon/_bourbon-deprecated-upcoming.scss +++ /dev/null @@ -1,8 +0,0 @@ -//************************************************************************// -// These mixins/functions are deprecated -// They will be removed in the next MAJOR version release -//************************************************************************// -@mixin inline-block { - display: inline-block; - @warn "inline-block mixin is deprecated and will be removed in the next major version release"; -} diff --git a/vitess.io/_sass/vendor/bourbon/_bourbon.scss b/vitess.io/_sass/vendor/bourbon/_bourbon.scss deleted file mode 100644 index 11d52d7c17d..00000000000 --- a/vitess.io/_sass/vendor/bourbon/_bourbon.scss +++ /dev/null @@ -1,78 +0,0 @@ -// Settings -@import "settings/prefixer"; -@import "settings/px-to-em"; - -// Custom Helpers -@import "helpers/convert-units"; -@import "helpers/gradient-positions-parser"; -@import "helpers/is-num"; -@import "helpers/linear-angle-parser"; -@import "helpers/linear-gradient-parser"; -@import "helpers/linear-positions-parser"; -@import "helpers/linear-side-corner-parser"; -@import "helpers/radial-arg-parser"; -@import "helpers/radial-positions-parser"; -@import "helpers/radial-gradient-parser"; -@import "helpers/render-gradients"; -@import "helpers/shape-size-stripper"; -@import "helpers/str-to-num"; - -// Custom Functions -@import "functions/assign"; -@import "functions/color-lightness"; -@import "functions/flex-grid"; -@import "functions/golden-ratio"; -@import "functions/grid-width"; -@import "functions/modular-scale"; -@import "functions/px-to-em"; -@import "functions/px-to-rem"; -@import "functions/strip-units"; -@import "functions/tint-shade"; -@import "functions/transition-property-name"; -@import "functions/unpack"; - -// CSS3 Mixins -@import "css3/animation"; -@import "css3/appearance"; -@import "css3/backface-visibility"; -@import "css3/background"; -@import "css3/background-image"; -@import "css3/border-image"; -@import "css3/border-radius"; -@import "css3/box-sizing"; -@import "css3/calc"; -@import "css3/columns"; -@import "css3/filter"; -@import "css3/flex-box"; -@import "css3/font-face"; -@import "css3/font-feature-settings"; -@import "css3/hyphens"; -@import "css3/hidpi-media-query"; -@import "css3/image-rendering"; -@import "css3/keyframes"; -@import "css3/linear-gradient"; -@import "css3/perspective"; -@import "css3/radial-gradient"; -@import "css3/transform"; -@import "css3/transition"; -@import "css3/user-select"; -@import "css3/placeholder"; - -// Addons & other mixins -@import "addons/button"; -@import "addons/clearfix"; -@import "addons/directional-values"; -@import "addons/ellipsis"; -@import "addons/font-family"; -@import "addons/hide-text"; -@import "addons/html5-input-types"; -@import "addons/position"; -@import "addons/prefixer"; -@import "addons/retina-image"; -@import "addons/size"; -@import "addons/timing-functions"; -@import "addons/triangle"; -@import "addons/word-wrap"; - -// Soon to be deprecated Mixins -@import "bourbon-deprecated-upcoming"; diff --git a/vitess.io/_sass/vendor/bourbon/addons/_button.scss b/vitess.io/_sass/vendor/bourbon/addons/_button.scss deleted file mode 100644 index 14a89e480c1..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_button.scss +++ /dev/null @@ -1,374 +0,0 @@ -@mixin button ($style: simple, $base-color: #4294f0, $text-size: inherit, $padding: 7px 18px) { - - @if type-of($style) == string and type-of($base-color) == color { - @include buttonstyle($style, $base-color, $text-size, $padding); - } - - @if type-of($style) == string and type-of($base-color) == number { - $padding: $text-size; - $text-size: $base-color; - $base-color: #4294f0; - - @if $padding == inherit { - $padding: 7px 18px; - } - - @include buttonstyle($style, $base-color, $text-size, $padding); - } - - @if type-of($style) == color and type-of($base-color) == color { - $base-color: $style; - $style: simple; - @include buttonstyle($style, $base-color, $text-size, $padding); - } - - @if type-of($style) == color and type-of($base-color) == number { - $padding: $text-size; - $text-size: $base-color; - $base-color: $style; - $style: simple; - - @if $padding == inherit { - $padding: 7px 18px; - } - - @include buttonstyle($style, $base-color, $text-size, $padding); - } - - @if type-of($style) == number { - $padding: $base-color; - $text-size: $style; - $base-color: #4294f0; - $style: simple; - - @if $padding == #4294f0 { - $padding: 7px 18px; - } - - @include buttonstyle($style, $base-color, $text-size, $padding); - } - - &:disabled { - opacity: 0.5; - cursor: not-allowed; - } -} - - -// Selector Style Button -//************************************************************************// -@mixin buttonstyle($type, $b-color, $t-size, $pad) { - // Grayscale button - @if $type == simple and $b-color == grayscale($b-color) { - @include simple($b-color, true, $t-size, $pad); - } - - @if $type == shiny and $b-color == grayscale($b-color) { - @include shiny($b-color, true, $t-size, $pad); - } - - @if $type == pill and $b-color == grayscale($b-color) { - @include pill($b-color, true, $t-size, $pad); - } - - @if $type == flat and $b-color == grayscale($b-color) { - @include flat($b-color, true, $t-size, $pad); - } - - // Colored button - @if $type == simple { - @include simple($b-color, false, $t-size, $pad); - } - - @else if $type == shiny { - @include shiny($b-color, false, $t-size, $pad); - } - - @else if $type == pill { - @include pill($b-color, false, $t-size, $pad); - } - - @else if $type == flat { - @include flat($b-color, false, $t-size, $pad); - } -} - - -// Simple Button -//************************************************************************// -@mixin simple($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { - $color: hsl(0, 0, 100%); - $border: adjust-color($base-color, $saturation: 9%, $lightness: -14%); - $inset-shadow: adjust-color($base-color, $saturation: -8%, $lightness: 15%); - $stop-gradient: adjust-color($base-color, $saturation: 9%, $lightness: -11%); - $text-shadow: adjust-color($base-color, $saturation: 15%, $lightness: -18%); - - @if is-light($base-color) { - $color: hsl(0, 0, 20%); - $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); - } - - @if $grayscale == true { - $border: grayscale($border); - $inset-shadow: grayscale($inset-shadow); - $stop-gradient: grayscale($stop-gradient); - $text-shadow: grayscale($text-shadow); - } - - border: 1px solid $border; - border-radius: 3px; - box-shadow: inset 0 1px 0 0 $inset-shadow; - color: $color; - display: inline-block; - font-size: $textsize; - font-weight: bold; - @include linear-gradient ($base-color, $stop-gradient); - padding: $padding; - text-decoration: none; - text-shadow: 0 1px 0 $text-shadow; - background-clip: padding-box; - - &:hover:not(:disabled) { - $base-color-hover: adjust-color($base-color, $saturation: -4%, $lightness: -5%); - $inset-shadow-hover: adjust-color($base-color, $saturation: -7%, $lightness: 5%); - $stop-gradient-hover: adjust-color($base-color, $saturation: 8%, $lightness: -14%); - - @if $grayscale == true { - $base-color-hover: grayscale($base-color-hover); - $inset-shadow-hover: grayscale($inset-shadow-hover); - $stop-gradient-hover: grayscale($stop-gradient-hover); - } - - box-shadow: inset 0 1px 0 0 $inset-shadow-hover; - cursor: pointer; - @include linear-gradient ($base-color-hover, $stop-gradient-hover); - } - - &:active:not(:disabled), - &:focus:not(:disabled) { - $border-active: adjust-color($base-color, $saturation: 9%, $lightness: -14%); - $inset-shadow-active: adjust-color($base-color, $saturation: 7%, $lightness: -17%); - - @if $grayscale == true { - $border-active: grayscale($border-active); - $inset-shadow-active: grayscale($inset-shadow-active); - } - - border: 1px solid $border-active; - box-shadow: inset 0 0 8px 4px $inset-shadow-active, inset 0 0 8px 4px $inset-shadow-active; - } -} - - -// Shiny Button -//************************************************************************// -@mixin shiny($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { - $color: hsl(0, 0, 100%); - $border: adjust-color($base-color, $red: -117, $green: -111, $blue: -81); - $border-bottom: adjust-color($base-color, $red: -126, $green: -127, $blue: -122); - $fourth-stop: adjust-color($base-color, $red: -79, $green: -70, $blue: -46); - $inset-shadow: adjust-color($base-color, $red: 37, $green: 29, $blue: 12); - $second-stop: adjust-color($base-color, $red: -56, $green: -50, $blue: -33); - $text-shadow: adjust-color($base-color, $red: -140, $green: -141, $blue: -114); - $third-stop: adjust-color($base-color, $red: -86, $green: -75, $blue: -48); - - @if is-light($base-color) { - $color: hsl(0, 0, 20%); - $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); - } - - @if $grayscale == true { - $border: grayscale($border); - $border-bottom: grayscale($border-bottom); - $fourth-stop: grayscale($fourth-stop); - $inset-shadow: grayscale($inset-shadow); - $second-stop: grayscale($second-stop); - $text-shadow: grayscale($text-shadow); - $third-stop: grayscale($third-stop); - } - - border: 1px solid $border; - border-bottom: 1px solid $border-bottom; - border-radius: 5px; - box-shadow: inset 0 1px 0 0 $inset-shadow; - color: $color; - display: inline-block; - font-size: $textsize; - font-weight: bold; - @include linear-gradient(top, $base-color 0%, $second-stop 50%, $third-stop 50%, $fourth-stop 100%); - padding: $padding; - text-align: center; - text-decoration: none; - text-shadow: 0 -1px 1px $text-shadow; - - &:hover:not(:disabled) { - $first-stop-hover: adjust-color($base-color, $red: -13, $green: -15, $blue: -18); - $second-stop-hover: adjust-color($base-color, $red: -66, $green: -62, $blue: -51); - $third-stop-hover: adjust-color($base-color, $red: -93, $green: -85, $blue: -66); - $fourth-stop-hover: adjust-color($base-color, $red: -86, $green: -80, $blue: -63); - - @if $grayscale == true { - $first-stop-hover: grayscale($first-stop-hover); - $second-stop-hover: grayscale($second-stop-hover); - $third-stop-hover: grayscale($third-stop-hover); - $fourth-stop-hover: grayscale($fourth-stop-hover); - } - - cursor: pointer; - @include linear-gradient(top, $first-stop-hover 0%, - $second-stop-hover 50%, - $third-stop-hover 50%, - $fourth-stop-hover 100%); - } - - &:active:not(:disabled), - &:focus:not(:disabled) { - $inset-shadow-active: adjust-color($base-color, $red: -111, $green: -116, $blue: -122); - - @if $grayscale == true { - $inset-shadow-active: grayscale($inset-shadow-active); - } - - box-shadow: inset 0 0 20px 0 $inset-shadow-active; - } -} - - -// Pill Button -//************************************************************************// -@mixin pill($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { - $color: hsl(0, 0, 100%); - $border-bottom: adjust-color($base-color, $hue: 8, $saturation: -11%, $lightness: -26%); - $border-sides: adjust-color($base-color, $hue: 4, $saturation: -21%, $lightness: -21%); - $border-top: adjust-color($base-color, $hue: -1, $saturation: -30%, $lightness: -15%); - $inset-shadow: adjust-color($base-color, $hue: -1, $saturation: -1%, $lightness: 7%); - $stop-gradient: adjust-color($base-color, $hue: 8, $saturation: 14%, $lightness: -10%); - $text-shadow: adjust-color($base-color, $hue: 5, $saturation: -19%, $lightness: -15%); - - @if is-light($base-color) { - $color: hsl(0, 0, 20%); - $text-shadow: adjust-color($base-color, $saturation: 10%, $lightness: 4%); - } - - @if $grayscale == true { - $border-bottom: grayscale($border-bottom); - $border-sides: grayscale($border-sides); - $border-top: grayscale($border-top); - $inset-shadow: grayscale($inset-shadow); - $stop-gradient: grayscale($stop-gradient); - $text-shadow: grayscale($text-shadow); - } - - border: 1px solid $border-top; - border-color: $border-top $border-sides $border-bottom; - border-radius: 16px; - box-shadow: inset 0 1px 0 0 $inset-shadow; - color: $color; - display: inline-block; - font-size: $textsize; - font-weight: normal; - line-height: 1; - @include linear-gradient ($base-color, $stop-gradient); - padding: $padding; - text-align: center; - text-decoration: none; - text-shadow: 0 -1px 1px $text-shadow; - background-clip: padding-box; - - &:hover:not(:disabled) { - $base-color-hover: adjust-color($base-color, $lightness: -4.5%); - $border-bottom: adjust-color($base-color, $hue: 8, $saturation: 13.5%, $lightness: -32%); - $border-sides: adjust-color($base-color, $hue: 4, $saturation: -2%, $lightness: -27%); - $border-top: adjust-color($base-color, $hue: -1, $saturation: -17%, $lightness: -21%); - $inset-shadow-hover: adjust-color($base-color, $saturation: -1%, $lightness: 3%); - $stop-gradient-hover: adjust-color($base-color, $hue: 8, $saturation: -4%, $lightness: -15.5%); - $text-shadow-hover: adjust-color($base-color, $hue: 5, $saturation: -5%, $lightness: -22%); - - @if $grayscale == true { - $base-color-hover: grayscale($base-color-hover); - $border-bottom: grayscale($border-bottom); - $border-sides: grayscale($border-sides); - $border-top: grayscale($border-top); - $inset-shadow-hover: grayscale($inset-shadow-hover); - $stop-gradient-hover: grayscale($stop-gradient-hover); - $text-shadow-hover: grayscale($text-shadow-hover); - } - - border: 1px solid $border-top; - border-color: $border-top $border-sides $border-bottom; - box-shadow: inset 0 1px 0 0 $inset-shadow-hover; - cursor: pointer; - @include linear-gradient ($base-color-hover, $stop-gradient-hover); - text-shadow: 0 -1px 1px $text-shadow-hover; - background-clip: padding-box; - } - - &:active:not(:disabled), - &:focus:not(:disabled) { - $active-color: adjust-color($base-color, $hue: 4, $saturation: -12%, $lightness: -10%); - $border-active: adjust-color($base-color, $hue: 6, $saturation: -2.5%, $lightness: -30%); - $border-bottom-active: adjust-color($base-color, $hue: 11, $saturation: 6%, $lightness: -31%); - $inset-shadow-active: adjust-color($base-color, $hue: 9, $saturation: 2%, $lightness: -21.5%); - $text-shadow-active: adjust-color($base-color, $hue: 5, $saturation: -12%, $lightness: -21.5%); - - @if $grayscale == true { - $active-color: grayscale($active-color); - $border-active: grayscale($border-active); - $border-bottom-active: grayscale($border-bottom-active); - $inset-shadow-active: grayscale($inset-shadow-active); - $text-shadow-active: grayscale($text-shadow-active); - } - - background: $active-color; - border: 1px solid $border-active; - border-bottom: 1px solid $border-bottom-active; - box-shadow: inset 0 0 6px 3px $inset-shadow-active; - text-shadow: 0 -1px 1px $text-shadow-active; - } -} - - - -// Flat Button -//************************************************************************// -@mixin flat($base-color, $grayscale: false, $textsize: inherit, $padding: 7px 18px) { - $color: hsl(0, 0, 100%); - - @if is-light($base-color) { - $color: hsl(0, 0, 20%); - } - - background-color: $base-color; - border-radius: 3px; - border: none; - color: $color; - display: inline-block; - font-size: inherit; - font-weight: bold; - padding: 7px 18px; - text-decoration: none; - background-clip: padding-box; - - &:hover:not(:disabled){ - $base-color-hover: adjust-color($base-color, $saturation: 4%, $lightness: 5%); - - @if $grayscale == true { - $base-color-hover: grayscale($base-color-hover); - } - - background-color: $base-color-hover; - cursor: pointer; - } - - &:active:not(:disabled), - &:focus:not(:disabled) { - $base-color-active: adjust-color($base-color, $saturation: -4%, $lightness: -5%); - - @if $grayscale == true { - $base-color-active: grayscale($base-color-active); - } - - background-color: $base-color-active; - cursor: pointer; - } -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_clearfix.scss b/vitess.io/_sass/vendor/bourbon/addons/_clearfix.scss deleted file mode 100644 index 783cfbc7922..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_clearfix.scss +++ /dev/null @@ -1,23 +0,0 @@ -// Modern micro clearfix provides an easy way to contain floats without adding additional markup. -// -// Example usage: -// -// // Contain all floats within .wrapper -// .wrapper { -// @include clearfix; -// .content, -// .sidebar { -// float : left; -// } -// } - -@mixin clearfix { - &:after { - content:""; - display:table; - clear:both; - } -} - -// Acknowledgements -// Beat *that* clearfix: [Thierry Koblentz](http://www.css-101.org/articles/clearfix/latest-new-clearfix-so-far.php) diff --git a/vitess.io/_sass/vendor/bourbon/addons/_directional-values.scss b/vitess.io/_sass/vendor/bourbon/addons/_directional-values.scss deleted file mode 100644 index 742f1031a48..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_directional-values.scss +++ /dev/null @@ -1,111 +0,0 @@ -// directional-property mixins are shorthands -// for writing properties like the following -// -// @include margin(null 0 10px); -// ------ -// margin-right: 0; -// margin-bottom: 10px; -// margin-left: 0; -// -// - or - -// -// @include border-style(dotted null); -// ------ -// border-top-style: dotted; -// border-bottom-style: dotted; -// -// ------ -// -// Note: You can also use false instead of null - -@function collapse-directionals($vals) { - $output: null; - - $A: nth( $vals, 1 ); - $B: if( length($vals) < 2, $A, nth($vals, 2)); - $C: if( length($vals) < 3, $A, nth($vals, 3)); - $D: if( length($vals) < 2, $A, nth($vals, if( length($vals) < 4, 2, 4) )); - - @if $A == 0 { $A: 0 } - @if $B == 0 { $B: 0 } - @if $C == 0 { $C: 0 } - @if $D == 0 { $D: 0 } - - @if $A == $B and $A == $C and $A == $D { $output: $A } - @else if $A == $C and $B == $D { $output: $A $B } - @else if $B == $D { $output: $A $B $C } - @else { $output: $A $B $C $D } - - @return $output; -} - -@function contains-falsy($list) { - @each $item in $list { - @if not $item { - @return true; - } - } - - @return false; -} - -@mixin directional-property($pre, $suf, $vals) { - // Property Names - $top: $pre + "-top" + if($suf, "-#{$suf}", ""); - $bottom: $pre + "-bottom" + if($suf, "-#{$suf}", ""); - $left: $pre + "-left" + if($suf, "-#{$suf}", ""); - $right: $pre + "-right" + if($suf, "-#{$suf}", ""); - $all: $pre + if($suf, "-#{$suf}", ""); - - $vals: collapse-directionals($vals); - - @if contains-falsy($vals) { - @if nth($vals, 1) { #{$top}: nth($vals, 1); } - - @if length($vals) == 1 { - @if nth($vals, 1) { #{$right}: nth($vals, 1); } - } @else { - @if nth($vals, 2) { #{$right}: nth($vals, 2); } - } - - // prop: top/bottom right/left - @if length($vals) == 2 { - @if nth($vals, 1) { #{$bottom}: nth($vals, 1); } - @if nth($vals, 2) { #{$left}: nth($vals, 2); } - - // prop: top right/left bottom - } @else if length($vals) == 3 { - @if nth($vals, 3) { #{$bottom}: nth($vals, 3); } - @if nth($vals, 2) { #{$left}: nth($vals, 2); } - - // prop: top right bottom left - } @else if length($vals) == 4 { - @if nth($vals, 3) { #{$bottom}: nth($vals, 3); } - @if nth($vals, 4) { #{$left}: nth($vals, 4); } - } - - // prop: top/right/bottom/left - } @else { - #{$all}: $vals; - } -} - -@mixin margin($vals...) { - @include directional-property(margin, false, $vals...); -} - -@mixin padding($vals...) { - @include directional-property(padding, false, $vals...); -} - -@mixin border-style($vals...) { - @include directional-property(border, style, $vals...); -} - -@mixin border-color($vals...) { - @include directional-property(border, color, $vals...); -} - -@mixin border-width($vals...) { - @include directional-property(border, width, $vals...); -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_ellipsis.scss b/vitess.io/_sass/vendor/bourbon/addons/_ellipsis.scss deleted file mode 100644 index a8ea2a4a867..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_ellipsis.scss +++ /dev/null @@ -1,7 +0,0 @@ -@mixin ellipsis($width: 100%) { - display: inline-block; - max-width: $width; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_font-family.scss b/vitess.io/_sass/vendor/bourbon/addons/_font-family.scss deleted file mode 100644 index 31f5d9ca75c..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_font-family.scss +++ /dev/null @@ -1,5 +0,0 @@ -$georgia: Georgia, Cambria, "Times New Roman", Times, serif; -$helvetica: "Helvetica Neue", Helvetica, Roboto, Arial, sans-serif; -$lucida-grande: "Lucida Grande", Tahoma, Verdana, Arial, sans-serif; -$monospace: "Bitstream Vera Sans Mono", Consolas, Courier, monospace; -$verdana: Verdana, Geneva, sans-serif; diff --git a/vitess.io/_sass/vendor/bourbon/addons/_hide-text.scss b/vitess.io/_sass/vendor/bourbon/addons/_hide-text.scss deleted file mode 100644 index fc7943811d3..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_hide-text.scss +++ /dev/null @@ -1,10 +0,0 @@ -@mixin hide-text { - overflow: hidden; - - &:before { - content: ""; - display: block; - width: 0; - height: 100%; - } -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_html5-input-types.scss b/vitess.io/_sass/vendor/bourbon/addons/_html5-input-types.scss deleted file mode 100644 index 9e9324ae0a7..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_html5-input-types.scss +++ /dev/null @@ -1,86 +0,0 @@ -//************************************************************************// -// Generate a variable ($all-text-inputs) with a list of all html5 -// input types that have a text-based input, excluding textarea. -// http://diveintohtml5.org/forms.html -//************************************************************************// -$inputs-list: 'input[type="email"]', - 'input[type="number"]', - 'input[type="password"]', - 'input[type="search"]', - 'input[type="tel"]', - 'input[type="text"]', - 'input[type="url"]', - - // Webkit & Gecko may change the display of these in the future - 'input[type="color"]', - 'input[type="date"]', - 'input[type="datetime"]', - 'input[type="datetime-local"]', - 'input[type="month"]', - 'input[type="time"]', - 'input[type="week"]'; - -// Bare inputs -//************************************************************************// -$all-text-inputs: assign-inputs($inputs-list); - -// Hover Pseudo-class -//************************************************************************// -$all-text-inputs-hover: assign-inputs($inputs-list, hover); - -// Focus Pseudo-class -//************************************************************************// -$all-text-inputs-focus: assign-inputs($inputs-list, focus); - - - -// You must use interpolation on the variable: -// #{$all-text-inputs} -// #{$all-text-inputs-hover} -// #{$all-text-inputs-focus} - -// Example -//************************************************************************// -// #{$all-text-inputs}, textarea { -// border: 1px solid red; -// } - - - -//************************************************************************// -// Generate a variable ($all-button-inputs) with a list of all html5 -// input types that have a button-based input, excluding button. -//************************************************************************// -$inputs-button-list: 'input[type="button"]', - 'input[type="reset"]', - 'input[type="submit"]'; - -// Bare inputs -//************************************************************************// -$all-button-inputs: assign-inputs($inputs-button-list); - -// Hover Pseudo-class -//************************************************************************// -$all-button-inputs-hover: assign-inputs($inputs-button-list, hover); - -// Focus Pseudo-class -//************************************************************************// -$all-button-inputs-focus: assign-inputs($inputs-button-list, focus); - -// Active Pseudo-class -//************************************************************************// -$all-button-inputs-active: assign-inputs($inputs-button-list, active); - - - -// You must use interpolation on the variable: -// #{$all-button-inputs} -// #{$all-button-inputs-hover} -// #{$all-button-inputs-focus} -// #{$all-button-inputs-active} - -// Example -//************************************************************************// -// #{$all-button-inputs}, button { -// border: 1px solid red; -// } diff --git a/vitess.io/_sass/vendor/bourbon/addons/_position.scss b/vitess.io/_sass/vendor/bourbon/addons/_position.scss deleted file mode 100644 index 7de75182bc0..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_position.scss +++ /dev/null @@ -1,32 +0,0 @@ -@mixin position ($position: relative, $coordinates: null null null null) { - - @if type-of($position) == list { - $coordinates: $position; - $position: relative; - } - - $coordinates: unpack($coordinates); - - $top: nth($coordinates, 1); - $right: nth($coordinates, 2); - $bottom: nth($coordinates, 3); - $left: nth($coordinates, 4); - - position: $position; - - @if ($top and $top == auto) or (type-of($top) == number) { - top: $top; - } - - @if ($right and $right == auto) or (type-of($right) == number) { - right: $right; - } - - @if ($bottom and $bottom == auto) or (type-of($bottom) == number) { - bottom: $bottom; - } - - @if ($left and $left == auto) or (type-of($left) == number) { - left: $left; - } -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_prefixer.scss b/vitess.io/_sass/vendor/bourbon/addons/_prefixer.scss deleted file mode 100644 index c32f502758f..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_prefixer.scss +++ /dev/null @@ -1,45 +0,0 @@ -//************************************************************************// -// Example: @include prefixer(border-radius, $radii, webkit ms spec); -//************************************************************************// -// Variables located in /settings/_prefixer.scss - -@mixin prefixer ($property, $value, $prefixes) { - @each $prefix in $prefixes { - @if $prefix == webkit { - @if $prefix-for-webkit { - -webkit-#{$property}: $value; - } - } - @else if $prefix == moz { - @if $prefix-for-mozilla { - -moz-#{$property}: $value; - } - } - @else if $prefix == ms { - @if $prefix-for-microsoft { - -ms-#{$property}: $value; - } - } - @else if $prefix == o { - @if $prefix-for-opera { - -o-#{$property}: $value; - } - } - @else if $prefix == spec { - @if $prefix-for-spec { - #{$property}: $value; - } - } - @else { - @warn "Unrecognized prefix: #{$prefix}"; - } - } -} - -@mixin disable-prefix-for-all() { - $prefix-for-webkit: false !global; - $prefix-for-mozilla: false !global; - $prefix-for-microsoft: false !global; - $prefix-for-opera: false !global; - $prefix-for-spec: false !global; -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_retina-image.scss b/vitess.io/_sass/vendor/bourbon/addons/_retina-image.scss deleted file mode 100644 index 7931bd13330..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_retina-image.scss +++ /dev/null @@ -1,31 +0,0 @@ -@mixin retina-image($filename, $background-size, $extension: png, $retina-filename: null, $retina-suffix: _2x, $asset-pipeline: false) { - @if $asset-pipeline { - background-image: image-url("#{$filename}.#{$extension}"); - } - @else { - background-image: url("#{$filename}.#{$extension}"); - } - - @include hidpi { - @if $asset-pipeline { - @if $retina-filename { - background-image: image-url("#{$retina-filename}.#{$extension}"); - } - @else { - background-image: image-url("#{$filename}#{$retina-suffix}.#{$extension}"); - } - } - - @else { - @if $retina-filename { - background-image: url("#{$retina-filename}.#{$extension}"); - } - @else { - background-image: url("#{$filename}#{$retina-suffix}.#{$extension}"); - } - } - - background-size: $background-size; - - } -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_size.scss b/vitess.io/_sass/vendor/bourbon/addons/_size.scss deleted file mode 100644 index ac705e26c6e..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_size.scss +++ /dev/null @@ -1,16 +0,0 @@ -@mixin size($size) { - $height: nth($size, 1); - $width: $height; - - @if length($size) > 1 { - $height: nth($size, 2); - } - - @if $height == auto or (type-of($height) == number and not unitless($height)) { - height: $height; - } - - @if $width == auto or (type-of($height) == number and not unitless($width)) { - width: $width; - } -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_timing-functions.scss b/vitess.io/_sass/vendor/bourbon/addons/_timing-functions.scss deleted file mode 100644 index 51b24109149..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_timing-functions.scss +++ /dev/null @@ -1,32 +0,0 @@ -// CSS cubic-bezier timing functions. Timing functions courtesy of jquery.easie (github.com/jaukia/easie) -// Timing functions are the same as demo'ed here: http://jqueryui.com/demos/effect/easing.html - -// EASE IN -$ease-in-quad: cubic-bezier(0.550, 0.085, 0.680, 0.530); -$ease-in-cubic: cubic-bezier(0.550, 0.055, 0.675, 0.190); -$ease-in-quart: cubic-bezier(0.895, 0.030, 0.685, 0.220); -$ease-in-quint: cubic-bezier(0.755, 0.050, 0.855, 0.060); -$ease-in-sine: cubic-bezier(0.470, 0.000, 0.745, 0.715); -$ease-in-expo: cubic-bezier(0.950, 0.050, 0.795, 0.035); -$ease-in-circ: cubic-bezier(0.600, 0.040, 0.980, 0.335); -$ease-in-back: cubic-bezier(0.600, -0.280, 0.735, 0.045); - -// EASE OUT -$ease-out-quad: cubic-bezier(0.250, 0.460, 0.450, 0.940); -$ease-out-cubic: cubic-bezier(0.215, 0.610, 0.355, 1.000); -$ease-out-quart: cubic-bezier(0.165, 0.840, 0.440, 1.000); -$ease-out-quint: cubic-bezier(0.230, 1.000, 0.320, 1.000); -$ease-out-sine: cubic-bezier(0.390, 0.575, 0.565, 1.000); -$ease-out-expo: cubic-bezier(0.190, 1.000, 0.220, 1.000); -$ease-out-circ: cubic-bezier(0.075, 0.820, 0.165, 1.000); -$ease-out-back: cubic-bezier(0.175, 0.885, 0.320, 1.275); - -// EASE IN OUT -$ease-in-out-quad: cubic-bezier(0.455, 0.030, 0.515, 0.955); -$ease-in-out-cubic: cubic-bezier(0.645, 0.045, 0.355, 1.000); -$ease-in-out-quart: cubic-bezier(0.770, 0.000, 0.175, 1.000); -$ease-in-out-quint: cubic-bezier(0.860, 0.000, 0.070, 1.000); -$ease-in-out-sine: cubic-bezier(0.445, 0.050, 0.550, 0.950); -$ease-in-out-expo: cubic-bezier(1.000, 0.000, 0.000, 1.000); -$ease-in-out-circ: cubic-bezier(0.785, 0.135, 0.150, 0.860); -$ease-in-out-back: cubic-bezier(0.680, -0.550, 0.265, 1.550); diff --git a/vitess.io/_sass/vendor/bourbon/addons/_triangle.scss b/vitess.io/_sass/vendor/bourbon/addons/_triangle.scss deleted file mode 100644 index 573954e41e3..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_triangle.scss +++ /dev/null @@ -1,83 +0,0 @@ -@mixin triangle ($size, $color, $direction) { - height: 0; - width: 0; - - $width: nth($size, 1); - $height: nth($size, length($size)); - - $foreground-color: nth($color, 1); - $background-color: if(length($color) == 2, nth($color, 2), transparent); - - @if ($direction == up) or ($direction == down) or ($direction == right) or ($direction == left) { - - $width: $width / 2; - $height: if(length($size) > 1, $height, $height/2); - - @if $direction == up { - border-left: $width solid $background-color; - border-right: $width solid $background-color; - border-bottom: $height solid $foreground-color; - - } @else if $direction == right { - border-top: $width solid $background-color; - border-bottom: $width solid $background-color; - border-left: $height solid $foreground-color; - - } @else if $direction == down { - border-left: $width solid $background-color; - border-right: $width solid $background-color; - border-top: $height solid $foreground-color; - - } @else if $direction == left { - border-top: $width solid $background-color; - border-bottom: $width solid $background-color; - border-right: $height solid $foreground-color; - } - } - - @else if ($direction == up-right) or ($direction == up-left) { - border-top: $height solid $foreground-color; - - @if $direction == up-right { - border-left: $width solid $background-color; - - } @else if $direction == up-left { - border-right: $width solid $background-color; - } - } - - @else if ($direction == down-right) or ($direction == down-left) { - border-bottom: $height solid $foreground-color; - - @if $direction == down-right { - border-left: $width solid $background-color; - - } @else if $direction == down-left { - border-right: $width solid $background-color; - } - } - - @else if ($direction == inset-up) { - border-width: $height $width; - border-style: solid; - border-color: $background-color $background-color $foreground-color; - } - - @else if ($direction == inset-down) { - border-width: $height $width; - border-style: solid; - border-color: $foreground-color $background-color $background-color; - } - - @else if ($direction == inset-right) { - border-width: $width $height; - border-style: solid; - border-color: $background-color $background-color $background-color $foreground-color; - } - - @else if ($direction == inset-left) { - border-width: $width $height; - border-style: solid; - border-color: $background-color $foreground-color $background-color $background-color; - } -} diff --git a/vitess.io/_sass/vendor/bourbon/addons/_word-wrap.scss b/vitess.io/_sass/vendor/bourbon/addons/_word-wrap.scss deleted file mode 100644 index 9734a597cd0..00000000000 --- a/vitess.io/_sass/vendor/bourbon/addons/_word-wrap.scss +++ /dev/null @@ -1,8 +0,0 @@ -@mixin word-wrap($wrap: break-word) { - word-wrap: $wrap; - - @if $wrap == break-word { - overflow-wrap: break-word; - word-break: break-all; - } -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_animation.scss b/vitess.io/_sass/vendor/bourbon/css3/_animation.scss deleted file mode 100644 index 08c3dbf157c..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_animation.scss +++ /dev/null @@ -1,52 +0,0 @@ -// http://www.w3.org/TR/css3-animations/#the-animation-name-property- -// Each of these mixins support comma separated lists of values, which allows different transitions for individual properties to be described in a single style rule. Each value in the list corresponds to the value at that same position in the other properties. - -// Official animation shorthand property. -@mixin animation ($animations...) { - @include prefixer(animation, $animations, webkit moz spec); -} - -// Individual Animation Properties -@mixin animation-name ($names...) { - @include prefixer(animation-name, $names, webkit moz spec); -} - - -@mixin animation-duration ($times...) { - @include prefixer(animation-duration, $times, webkit moz spec); -} - - -@mixin animation-timing-function ($motions...) { -// ease | linear | ease-in | ease-out | ease-in-out - @include prefixer(animation-timing-function, $motions, webkit moz spec); -} - - -@mixin animation-iteration-count ($values...) { -// infinite | - @include prefixer(animation-iteration-count, $values, webkit moz spec); -} - - -@mixin animation-direction ($directions...) { -// normal | alternate - @include prefixer(animation-direction, $directions, webkit moz spec); -} - - -@mixin animation-play-state ($states...) { -// running | paused - @include prefixer(animation-play-state, $states, webkit moz spec); -} - - -@mixin animation-delay ($times...) { - @include prefixer(animation-delay, $times, webkit moz spec); -} - - -@mixin animation-fill-mode ($modes...) { -// none | forwards | backwards | both - @include prefixer(animation-fill-mode, $modes, webkit moz spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_appearance.scss b/vitess.io/_sass/vendor/bourbon/css3/_appearance.scss deleted file mode 100644 index 3eb16e45de7..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_appearance.scss +++ /dev/null @@ -1,3 +0,0 @@ -@mixin appearance ($value) { - @include prefixer(appearance, $value, webkit moz ms o spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_backface-visibility.scss b/vitess.io/_sass/vendor/bourbon/css3/_backface-visibility.scss deleted file mode 100644 index 1161fe60dd1..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_backface-visibility.scss +++ /dev/null @@ -1,6 +0,0 @@ -//************************************************************************// -// Backface-visibility mixin -//************************************************************************// -@mixin backface-visibility($visibility) { - @include prefixer(backface-visibility, $visibility, webkit spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_background-image.scss b/vitess.io/_sass/vendor/bourbon/css3/_background-image.scss deleted file mode 100644 index 6abe88be9a5..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_background-image.scss +++ /dev/null @@ -1,42 +0,0 @@ -//************************************************************************// -// Background-image property for adding multiple background images with -// gradients, or for stringing multiple gradients together. -//************************************************************************// - -@mixin background-image($images...) { - $webkit-images: (); - $spec-images: (); - - @each $image in $images { - $webkit-image: (); - $spec-image: (); - - @if (type-of($image) == string) { - $url-str: str-slice($image, 0, 3); - $gradient-type: str-slice($image, 0, 6); - - @if $url-str == "url" { - $webkit-image: $image; - $spec-image: $image; - } - - @else if $gradient-type == "linear" { - $gradients: _linear-gradient-parser($image); - $webkit-image: map-get($gradients, webkit-image); - $spec-image: map-get($gradients, spec-image); - } - - @else if $gradient-type == "radial" { - $gradients: _radial-gradient-parser($image); - $webkit-image: map-get($gradients, webkit-image); - $spec-image: map-get($gradients, spec-image); - } - } - - $webkit-images: append($webkit-images, $webkit-image, comma); - $spec-images: append($spec-images, $spec-image, comma); - } - - background-image: $webkit-images; - background-image: $spec-images; -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_background.scss b/vitess.io/_sass/vendor/bourbon/css3/_background.scss deleted file mode 100644 index 9bce9308bf9..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_background.scss +++ /dev/null @@ -1,55 +0,0 @@ -//************************************************************************// -// Background property for adding multiple backgrounds using shorthand -// notation. -//************************************************************************// - -@mixin background($backgrounds...) { - $webkit-backgrounds: (); - $spec-backgrounds: (); - - @each $background in $backgrounds { - $webkit-background: (); - $spec-background: (); - $background-type: type-of($background); - - @if $background-type == string or list { - $background-str: if($background-type == list, nth($background, 1), $background); - - $url-str: str-slice($background-str, 0, 3); - $gradient-type: str-slice($background-str, 0, 6); - - @if $url-str == "url" { - $webkit-background: $background; - $spec-background: $background; - } - - @else if $gradient-type == "linear" { - $gradients: _linear-gradient-parser("#{$background}"); - $webkit-background: map-get($gradients, webkit-image); - $spec-background: map-get($gradients, spec-image); - } - - @else if $gradient-type == "radial" { - $gradients: _radial-gradient-parser("#{$background}"); - $webkit-background: map-get($gradients, webkit-image); - $spec-background: map-get($gradients, spec-image); - } - - @else { - $webkit-background: $background; - $spec-background: $background; - } - } - - @else { - $webkit-background: $background; - $spec-background: $background; - } - - $webkit-backgrounds: append($webkit-backgrounds, $webkit-background, comma); - $spec-backgrounds: append($spec-backgrounds, $spec-background, comma); - } - - background: $webkit-backgrounds; - background: $spec-backgrounds; -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_border-image.scss b/vitess.io/_sass/vendor/bourbon/css3/_border-image.scss deleted file mode 100644 index e338c2dcd24..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_border-image.scss +++ /dev/null @@ -1,59 +0,0 @@ -@mixin border-image($borders...) { - $webkit-borders: (); - $spec-borders: (); - - @each $border in $borders { - $webkit-border: (); - $spec-border: (); - $border-type: type-of($border); - - @if $border-type == string or list { - $border-str: if($border-type == list, nth($border, 1), $border); - - $url-str: str-slice($border-str, 0, 3); - $gradient-type: str-slice($border-str, 0, 6); - - @if $url-str == "url" { - $webkit-border: $border; - $spec-border: $border; - } - - @else if $gradient-type == "linear" { - $gradients: _linear-gradient-parser("#{$border}"); - $webkit-border: map-get($gradients, webkit-image); - $spec-border: map-get($gradients, spec-image); - } - - @else if $gradient-type == "radial" { - $gradients: _radial-gradient-parser("#{$border}"); - $webkit-border: map-get($gradients, webkit-image); - $spec-border: map-get($gradients, spec-image); - } - - @else { - $webkit-border: $border; - $spec-border: $border; - } - } - - @else { - $webkit-border: $border; - $spec-border: $border; - } - - $webkit-borders: append($webkit-borders, $webkit-border, comma); - $spec-borders: append($spec-borders, $spec-border, comma); - } - - -webkit-border-image: $webkit-borders; - border-image: $spec-borders; - border-style: solid; -} - -//Examples: -// @include border-image(url("image.png")); -// @include border-image(url("image.png") 20 stretch); -// @include border-image(linear-gradient(45deg, orange, yellow)); -// @include border-image(linear-gradient(45deg, orange, yellow) stretch); -// @include border-image(linear-gradient(45deg, orange, yellow) 20 30 40 50 stretch round); -// @include border-image(radial-gradient(top, cover, orange, yellow, orange)); diff --git a/vitess.io/_sass/vendor/bourbon/css3/_border-radius.scss b/vitess.io/_sass/vendor/bourbon/css3/_border-radius.scss deleted file mode 100644 index 7c171901090..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_border-radius.scss +++ /dev/null @@ -1,22 +0,0 @@ -//************************************************************************// -// Shorthand Border-radius mixins -//************************************************************************// -@mixin border-top-radius($radii) { - @include prefixer(border-top-left-radius, $radii, spec); - @include prefixer(border-top-right-radius, $radii, spec); -} - -@mixin border-bottom-radius($radii) { - @include prefixer(border-bottom-left-radius, $radii, spec); - @include prefixer(border-bottom-right-radius, $radii, spec); -} - -@mixin border-left-radius($radii) { - @include prefixer(border-top-left-radius, $radii, spec); - @include prefixer(border-bottom-left-radius, $radii, spec); -} - -@mixin border-right-radius($radii) { - @include prefixer(border-top-right-radius, $radii, spec); - @include prefixer(border-bottom-right-radius, $radii, spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_box-sizing.scss b/vitess.io/_sass/vendor/bourbon/css3/_box-sizing.scss deleted file mode 100644 index f07e1d412e3..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_box-sizing.scss +++ /dev/null @@ -1,4 +0,0 @@ -@mixin box-sizing ($box) { -// content-box | border-box | inherit - @include prefixer(box-sizing, $box, webkit moz spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_calc.scss b/vitess.io/_sass/vendor/bourbon/css3/_calc.scss deleted file mode 100644 index 94d7e4cef3c..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_calc.scss +++ /dev/null @@ -1,4 +0,0 @@ -@mixin calc($property, $value) { - #{$property}: -webkit-calc(#{$value}); - #{$property}: calc(#{$value}); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_columns.scss b/vitess.io/_sass/vendor/bourbon/css3/_columns.scss deleted file mode 100644 index 96f601c1a81..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_columns.scss +++ /dev/null @@ -1,47 +0,0 @@ -@mixin columns($arg: auto) { -// || - @include prefixer(columns, $arg, webkit moz spec); -} - -@mixin column-count($int: auto) { -// auto || integer - @include prefixer(column-count, $int, webkit moz spec); -} - -@mixin column-gap($length: normal) { -// normal || length - @include prefixer(column-gap, $length, webkit moz spec); -} - -@mixin column-fill($arg: auto) { -// auto || length - @include prefixer(column-fill, $arg, webkit moz spec); -} - -@mixin column-rule($arg) { -// || || - @include prefixer(column-rule, $arg, webkit moz spec); -} - -@mixin column-rule-color($color) { - @include prefixer(column-rule-color, $color, webkit moz spec); -} - -@mixin column-rule-style($style: none) { -// none | hidden | dashed | dotted | double | groove | inset | inset | outset | ridge | solid - @include prefixer(column-rule-style, $style, webkit moz spec); -} - -@mixin column-rule-width ($width: none) { - @include prefixer(column-rule-width, $width, webkit moz spec); -} - -@mixin column-span($arg: none) { -// none || all - @include prefixer(column-span, $arg, webkit moz spec); -} - -@mixin column-width($length: auto) { -// auto || length - @include prefixer(column-width, $length, webkit moz spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_filter.scss b/vitess.io/_sass/vendor/bourbon/css3/_filter.scss deleted file mode 100644 index 8560d77676d..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_filter.scss +++ /dev/null @@ -1,5 +0,0 @@ -@mixin filter($function: none) { - // [ - @include prefixer(perspective, $depth, webkit moz spec); -} - -@mixin perspective-origin($value: 50% 50%) { - @include prefixer(perspective-origin, $value, webkit moz spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_placeholder.scss b/vitess.io/_sass/vendor/bourbon/css3/_placeholder.scss deleted file mode 100644 index 5682fd097a5..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_placeholder.scss +++ /dev/null @@ -1,8 +0,0 @@ -@mixin placeholder { - $placeholders: ":-webkit-input" ":-moz" "-moz" "-ms-input"; - @each $placeholder in $placeholders { - &:#{$placeholder}-placeholder { - @content; - } - } -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_radial-gradient.scss b/vitess.io/_sass/vendor/bourbon/css3/_radial-gradient.scss deleted file mode 100644 index 7a8c3765f16..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_radial-gradient.scss +++ /dev/null @@ -1,39 +0,0 @@ -// Requires Sass 3.1+ -@mixin radial-gradient($G1, $G2, - $G3: null, $G4: null, - $G5: null, $G6: null, - $G7: null, $G8: null, - $G9: null, $G10: null, - $pos: null, - $shape-size: null, - $fallback: null) { - - $data: _radial-arg-parser($G1, $G2, $pos, $shape-size); - $G1: nth($data, 1); - $G2: nth($data, 2); - $pos: nth($data, 3); - $shape-size: nth($data, 4); - - $full: $G1, $G2, $G3, $G4, $G5, $G6, $G7, $G8, $G9, $G10; - - // Strip deprecated cover/contain for spec - $shape-size-spec: _shape-size-stripper($shape-size); - - // Set $G1 as the default fallback color - $first-color: nth($full, 1); - $fallback-color: nth($first-color, 1); - - @if (type-of($fallback) == color) or ($fallback == "transparent") { - $fallback-color: $fallback; - } - - // Add Commas and spaces - $shape-size: if($shape-size, '#{$shape-size}, ', null); - $pos: if($pos, '#{$pos}, ', null); - $pos-spec: if($pos, 'at #{$pos}', null); - $shape-size-spec: if(($shape-size-spec != ' ') and ($pos == null), '#{$shape-size-spec}, ', '#{$shape-size-spec} '); - - background-color: $fallback-color; - background-image: -webkit-radial-gradient(unquote(#{$pos}#{$shape-size}#{$full})); - background-image: unquote("radial-gradient(#{$shape-size-spec}#{$pos-spec}#{$full})"); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_transform.scss b/vitess.io/_sass/vendor/bourbon/css3/_transform.scss deleted file mode 100644 index 8cc35963d55..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_transform.scss +++ /dev/null @@ -1,15 +0,0 @@ -@mixin transform($property: none) { -// none | - @include prefixer(transform, $property, webkit moz ms o spec); -} - -@mixin transform-origin($axes: 50%) { -// x-axis - left | center | right | length | % -// y-axis - top | center | bottom | length | % -// z-axis - length - @include prefixer(transform-origin, $axes, webkit moz ms o spec); -} - -@mixin transform-style ($style: flat) { - @include prefixer(transform-style, $style, webkit moz ms o spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_transition.scss b/vitess.io/_sass/vendor/bourbon/css3/_transition.scss deleted file mode 100644 index 5ad4c0aed23..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_transition.scss +++ /dev/null @@ -1,77 +0,0 @@ -// Shorthand mixin. Supports multiple parentheses-deliminated values for each variable. -// Example: @include transition (all 2s ease-in-out); -// @include transition (opacity 1s ease-in 2s, width 2s ease-out); -// @include transition-property (transform, opacity); - -@mixin transition ($properties...) { - // Fix for vendor-prefix transform property - $needs-prefixes: false; - $webkit: (); - $moz: (); - $spec: (); - - // Create lists for vendor-prefixed transform - @each $list in $properties { - @if nth($list, 1) == "transform" { - $needs-prefixes: true; - $list1: -webkit-transform; - $list2: -moz-transform; - $list3: (); - - @each $var in $list { - $list3: join($list3, $var); - - @if $var != "transform" { - $list1: join($list1, $var); - $list2: join($list2, $var); - } - } - - $webkit: append($webkit, $list1); - $moz: append($moz, $list2); - $spec: append($spec, $list3); - } - - // Create lists for non-prefixed transition properties - @else { - $webkit: append($webkit, $list, comma); - $moz: append($moz, $list, comma); - $spec: append($spec, $list, comma); - } - } - - @if $needs-prefixes { - -webkit-transition: $webkit; - -moz-transition: $moz; - transition: $spec; - } - @else { - @if length($properties) >= 1 { - @include prefixer(transition, $properties, webkit moz spec); - } - - @else { - $properties: all 0.15s ease-out 0s; - @include prefixer(transition, $properties, webkit moz spec); - } - } -} - -@mixin transition-property ($properties...) { - -webkit-transition-property: transition-property-names($properties, 'webkit'); - -moz-transition-property: transition-property-names($properties, 'moz'); - transition-property: transition-property-names($properties, false); -} - -@mixin transition-duration ($times...) { - @include prefixer(transition-duration, $times, webkit moz spec); -} - -@mixin transition-timing-function ($motions...) { -// ease | linear | ease-in | ease-out | ease-in-out | cubic-bezier() - @include prefixer(transition-timing-function, $motions, webkit moz spec); -} - -@mixin transition-delay ($times...) { - @include prefixer(transition-delay, $times, webkit moz spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/css3/_user-select.scss b/vitess.io/_sass/vendor/bourbon/css3/_user-select.scss deleted file mode 100644 index 1380aa8baa9..00000000000 --- a/vitess.io/_sass/vendor/bourbon/css3/_user-select.scss +++ /dev/null @@ -1,3 +0,0 @@ -@mixin user-select($arg: none) { - @include prefixer(user-select, $arg, webkit moz ms spec); -} diff --git a/vitess.io/_sass/vendor/bourbon/functions/_assign.scss b/vitess.io/_sass/vendor/bourbon/functions/_assign.scss deleted file mode 100644 index 9a1db93ef74..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_assign.scss +++ /dev/null @@ -1,11 +0,0 @@ -@function assign-inputs($inputs, $pseudo: null) { - $list : (); - - @each $input in $inputs { - $input: unquote($input); - $input: if($pseudo, $input + ":" + $pseudo, $input); - $list: append($list, $input, comma); - } - - @return $list; -} \ No newline at end of file diff --git a/vitess.io/_sass/vendor/bourbon/functions/_color-lightness.scss b/vitess.io/_sass/vendor/bourbon/functions/_color-lightness.scss deleted file mode 100644 index 8c6df4e2564..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_color-lightness.scss +++ /dev/null @@ -1,13 +0,0 @@ -// Programatically determines whether a color is light or dark -// Returns a boolean -// More details here http://robots.thoughtbot.com/closer-look-color-lightness - -@function is-light($hex-color) { - $-local-red: red(rgba($hex-color, 1.0)); - $-local-green: green(rgba($hex-color, 1.0)); - $-local-blue: blue(rgba($hex-color, 1.0)); - - $-local-lightness: ($-local-red * 0.2126 + $-local-green * 0.7152 + $-local-blue * 0.0722) / 255; - - @return $-local-lightness > .6; -} diff --git a/vitess.io/_sass/vendor/bourbon/functions/_flex-grid.scss b/vitess.io/_sass/vendor/bourbon/functions/_flex-grid.scss deleted file mode 100644 index 3bbd8665732..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_flex-grid.scss +++ /dev/null @@ -1,39 +0,0 @@ -// Flexible grid -@function flex-grid($columns, $container-columns: $fg-max-columns) { - $width: $columns * $fg-column + ($columns - 1) * $fg-gutter; - $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter; - @return percentage($width / $container-width); -} - -// Flexible gutter -@function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) { - $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter; - @return percentage($gutter / $container-width); -} - -// The $fg-column, $fg-gutter and $fg-max-columns variables must be defined in your base stylesheet to properly use the flex-grid function. -// This function takes the fluid grid equation (target / context = result) and uses columns to help define each. -// -// The calculation presumes that your column structure will be missing the last gutter: -// -// -- column -- gutter -- column -- gutter -- column -// -// $fg-column: 60px; // Column Width -// $fg-gutter: 25px; // Gutter Width -// $fg-max-columns: 12; // Total Columns For Main Container -// -// div { -// width: flex-grid(4); // returns (315px / 995px) = 31.65829%; -// margin-left: flex-gutter(); // returns (25px / 995px) = 2.51256%; -// -// p { -// width: flex-grid(2, 4); // returns (145px / 315px) = 46.031746%; -// float: left; -// margin: flex-gutter(4); // returns (25px / 315px) = 7.936508%; -// } -// -// blockquote { -// float: left; -// width: flex-grid(2, 4); // returns (145px / 315px) = 46.031746%; -// } -// } \ No newline at end of file diff --git a/vitess.io/_sass/vendor/bourbon/functions/_golden-ratio.scss b/vitess.io/_sass/vendor/bourbon/functions/_golden-ratio.scss deleted file mode 100644 index 463d14a00c1..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_golden-ratio.scss +++ /dev/null @@ -1,3 +0,0 @@ -@function golden-ratio($value, $increment) { - @return modular-scale($value, $increment, $golden) -} diff --git a/vitess.io/_sass/vendor/bourbon/functions/_grid-width.scss b/vitess.io/_sass/vendor/bourbon/functions/_grid-width.scss deleted file mode 100644 index 8e63d83d602..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_grid-width.scss +++ /dev/null @@ -1,13 +0,0 @@ -@function grid-width($n) { - @return $n * $gw-column + ($n - 1) * $gw-gutter; -} - -// The $gw-column and $gw-gutter variables must be defined in your base stylesheet to properly use the grid-width function. -// -// $gw-column: 100px; // Column Width -// $gw-gutter: 40px; // Gutter Width -// -// div { -// width: grid-width(4); // returns 520px; -// margin-left: $gw-gutter; // returns 40px; -// } diff --git a/vitess.io/_sass/vendor/bourbon/functions/_modular-scale.scss b/vitess.io/_sass/vendor/bourbon/functions/_modular-scale.scss deleted file mode 100644 index afc59eb954d..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_modular-scale.scss +++ /dev/null @@ -1,66 +0,0 @@ -// Scaling Variables -$golden: 1.618; -$minor-second: 1.067; -$major-second: 1.125; -$minor-third: 1.2; -$major-third: 1.25; -$perfect-fourth: 1.333; -$augmented-fourth: 1.414; -$perfect-fifth: 1.5; -$minor-sixth: 1.6; -$major-sixth: 1.667; -$minor-seventh: 1.778; -$major-seventh: 1.875; -$octave: 2; -$major-tenth: 2.5; -$major-eleventh: 2.667; -$major-twelfth: 3; -$double-octave: 4; - -@function modular-scale($value, $increment, $ratio) { - $v1: nth($value, 1); - $v2: nth($value, length($value)); - $value: $v1; - - // scale $v2 to just above $v1 - @while $v2 > $v1 { - $v2: ($v2 / $ratio); // will be off-by-1 - } - @while $v2 < $v1 { - $v2: ($v2 * $ratio); // will fix off-by-1 - } - - // check AFTER scaling $v2 to prevent double-counting corner-case - $double-stranded: $v2 > $v1; - - @if $increment > 0 { - @for $i from 1 through $increment { - @if $double-stranded and ($v1 * $ratio) > $v2 { - $value: $v2; - $v2: ($v2 * $ratio); - } @else { - $v1: ($v1 * $ratio); - $value: $v1; - } - } - } - - @if $increment < 0 { - // adjust $v2 to just below $v1 - @if $double-stranded { - $v2: ($v2 / $ratio); - } - - @for $i from $increment through -1 { - @if $double-stranded and ($v1 / $ratio) < $v2 { - $value: $v2; - $v2: ($v2 / $ratio); - } @else { - $v1: ($v1 / $ratio); - $value: $v1; - } - } - } - - @return $value; -} diff --git a/vitess.io/_sass/vendor/bourbon/functions/_px-to-em.scss b/vitess.io/_sass/vendor/bourbon/functions/_px-to-em.scss deleted file mode 100644 index 4832245e455..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_px-to-em.scss +++ /dev/null @@ -1,13 +0,0 @@ -// Convert pixels to ems -// eg. for a relational value of 12px write em(12) when the parent is 16px -// if the parent is another value say 24px write em(12, 24) - -@function em($pxval, $base: $em-base) { - @if not unitless($pxval) { - $pxval: strip-units($pxval); - } - @if not unitless($base) { - $base: strip-units($base); - } - @return ($pxval / $base) * 1em; -} diff --git a/vitess.io/_sass/vendor/bourbon/functions/_px-to-rem.scss b/vitess.io/_sass/vendor/bourbon/functions/_px-to-rem.scss deleted file mode 100644 index 96b244e4cb1..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_px-to-rem.scss +++ /dev/null @@ -1,15 +0,0 @@ -// Convert pixels to rems -// eg. for a relational value of 12px write rem(12) -// Assumes $em-base is the font-size of - -@function rem($pxval) { - @if not unitless($pxval) { - $pxval: strip-units($pxval); - } - - $base: $em-base; - @if not unitless($base) { - $base: strip-units($base); - } - @return ($pxval / $base) * 1rem; -} diff --git a/vitess.io/_sass/vendor/bourbon/functions/_strip-units.scss b/vitess.io/_sass/vendor/bourbon/functions/_strip-units.scss deleted file mode 100644 index 6afc6e601c0..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_strip-units.scss +++ /dev/null @@ -1,5 +0,0 @@ -// Srtips the units from a value. e.g. 12px -> 12 - -@function strip-units($val) { - @return ($val / ($val * 0 + 1)); -} diff --git a/vitess.io/_sass/vendor/bourbon/functions/_tint-shade.scss b/vitess.io/_sass/vendor/bourbon/functions/_tint-shade.scss deleted file mode 100644 index f7172004ac6..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_tint-shade.scss +++ /dev/null @@ -1,9 +0,0 @@ -// Add percentage of white to a color -@function tint($color, $percent){ - @return mix(white, $color, $percent); -} - -// Add percentage of black to a color -@function shade($color, $percent){ - @return mix(black, $color, $percent); -} diff --git a/vitess.io/_sass/vendor/bourbon/functions/_transition-property-name.scss b/vitess.io/_sass/vendor/bourbon/functions/_transition-property-name.scss deleted file mode 100644 index 54cd4228112..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_transition-property-name.scss +++ /dev/null @@ -1,22 +0,0 @@ -// Return vendor-prefixed property names if appropriate -// Example: transition-property-names((transform, color, background), moz) -> -moz-transform, color, background -//************************************************************************// -@function transition-property-names($props, $vendor: false) { - $new-props: (); - - @each $prop in $props { - $new-props: append($new-props, transition-property-name($prop, $vendor), comma); - } - - @return $new-props; -} - -@function transition-property-name($prop, $vendor: false) { - // put other properties that need to be prefixed here aswell - @if $vendor and $prop == transform { - @return unquote('-'+$vendor+'-'+$prop); - } - @else { - @return $prop; - } -} \ No newline at end of file diff --git a/vitess.io/_sass/vendor/bourbon/functions/_unpack.scss b/vitess.io/_sass/vendor/bourbon/functions/_unpack.scss deleted file mode 100644 index 377596365c8..00000000000 --- a/vitess.io/_sass/vendor/bourbon/functions/_unpack.scss +++ /dev/null @@ -1,17 +0,0 @@ -// Convert shorthand to the 4-value syntax - -@function unpack($shorthand) { - @if length($shorthand) == 1 { - @return nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1) nth($shorthand, 1); - } - @else if length($shorthand) == 2 { - @return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 1) nth($shorthand, 2); - } - @else if length($shorthand) == 3 { - @return nth($shorthand, 1) nth($shorthand, 2) nth($shorthand, 3) nth($shorthand, 2); - } - @else { - @return $shorthand; - } -} - diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_convert-units.scss b/vitess.io/_sass/vendor/bourbon/helpers/_convert-units.scss deleted file mode 100644 index 3443db397c2..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_convert-units.scss +++ /dev/null @@ -1,15 +0,0 @@ -//************************************************************************// -// Helper function for str-to-num fn. -// Source: http://sassmeister.com/gist/9647408 -//************************************************************************// -@function _convert-units($number, $unit) { - $strings: 'px' 'cm' 'mm' '%' 'ch' 'pica' 'in' 'em' 'rem' 'pt' 'pc' 'ex' 'vw' 'vh' 'vmin' 'vmax', 'deg', 'rad', 'grad', 'turn'; - $units: 1px 1cm 1mm 1% 1ch 1pica 1in 1em 1rem 1pt 1pc 1ex 1vw 1vh 1vmin 1vmax, 1deg, 1rad, 1grad, 1turn; - $index: index($strings, $unit); - - @if not $index { - @warn "Unknown unit `#{$unit}`."; - @return false; - } - @return $number * nth($units, $index); -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_gradient-positions-parser.scss b/vitess.io/_sass/vendor/bourbon/helpers/_gradient-positions-parser.scss deleted file mode 100644 index 07d30b6cf95..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_gradient-positions-parser.scss +++ /dev/null @@ -1,13 +0,0 @@ -@function _gradient-positions-parser($gradient-type, $gradient-positions) { - @if $gradient-positions - and ($gradient-type == linear) - and (type-of($gradient-positions) != color) { - $gradient-positions: _linear-positions-parser($gradient-positions); - } - @else if $gradient-positions - and ($gradient-type == radial) - and (type-of($gradient-positions) != color) { - $gradient-positions: _radial-positions-parser($gradient-positions); - } - @return $gradient-positions; -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_is-num.scss b/vitess.io/_sass/vendor/bourbon/helpers/_is-num.scss deleted file mode 100644 index 71459e1404a..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_is-num.scss +++ /dev/null @@ -1,8 +0,0 @@ -//************************************************************************// -// Helper for linear-gradient-parser -//************************************************************************// -@function _is-num($char) { - $values: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' 0 1 2 3 4 5 6 7 8 9; - $index: index($values, $char); - @return if($index, true, false); -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_linear-angle-parser.scss b/vitess.io/_sass/vendor/bourbon/helpers/_linear-angle-parser.scss deleted file mode 100644 index e0401ed8df1..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_linear-angle-parser.scss +++ /dev/null @@ -1,25 +0,0 @@ -// Private function for linear-gradient-parser -@function _linear-angle-parser($image, $first-val, $prefix, $suffix) { - $offset: null; - $unit-short: str-slice($first-val, str-length($first-val) - 2, str-length($first-val)); - $unit-long: str-slice($first-val, str-length($first-val) - 3, str-length($first-val)); - - @if ($unit-long == "grad") or - ($unit-long == "turn") { - $offset: if($unit-long == "grad", -100grad * 3, -0.75turn); - } - - @else if ($unit-short == "deg") or - ($unit-short == "rad") { - $offset: if($unit-short == "deg", -90 * 3, 1.6rad); - } - - @if $offset { - $num: _str-to-num($first-val); - - @return ( - webkit-image: -webkit- + $prefix + ($offset - $num) + $suffix, - spec-image: $image - ); - } -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_linear-gradient-parser.scss b/vitess.io/_sass/vendor/bourbon/helpers/_linear-gradient-parser.scss deleted file mode 100644 index 12bcdcda8fd..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_linear-gradient-parser.scss +++ /dev/null @@ -1,41 +0,0 @@ -@function _linear-gradient-parser($image) { - $image: unquote($image); - $gradients: (); - $start: str-index($image, "("); - $end: str-index($image, ","); - $first-val: str-slice($image, $start + 1, $end - 1); - - $prefix: str-slice($image, 0, $start); - $suffix: str-slice($image, $end, str-length($image)); - - $has-multiple-vals: str-index($first-val, " "); - $has-single-position: unquote(_position-flipper($first-val) + ""); - $has-angle: _is-num(str-slice($first-val, 0, 0)); - - @if $has-multiple-vals { - $gradients: _linear-side-corner-parser($image, $first-val, $prefix, $suffix, $has-multiple-vals); - } - - @else if $has-single-position != "" { - $pos: unquote($has-single-position + ""); - - $gradients: ( - webkit-image: -webkit- + $image, - spec-image: $prefix + "to " + $pos + $suffix - ); - } - - @else if $has-angle { - // Rotate degree for webkit - $gradients: _linear-angle-parser($image, $first-val, $prefix, $suffix); - } - - @else { - $gradients: ( - webkit-image: -webkit- + $image, - spec-image: $image - ); - } - - @return $gradients; -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_linear-positions-parser.scss b/vitess.io/_sass/vendor/bourbon/helpers/_linear-positions-parser.scss deleted file mode 100644 index d26383edce1..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_linear-positions-parser.scss +++ /dev/null @@ -1,61 +0,0 @@ -@function _linear-positions-parser($pos) { - $type: type-of(nth($pos, 1)); - $spec: null; - $degree: null; - $side: null; - $corner: null; - $length: length($pos); - // Parse Side and corner positions - @if ($length > 1) { - @if nth($pos, 1) == "to" { // Newer syntax - $side: nth($pos, 2); - - @if $length == 2 { // eg. to top - // Swap for backwards compatability - $degree: _position-flipper(nth($pos, 2)); - } - @else if $length == 3 { // eg. to top left - $corner: nth($pos, 3); - } - } - @else if $length == 2 { // Older syntax ("top left") - $side: _position-flipper(nth($pos, 1)); - $corner: _position-flipper(nth($pos, 2)); - } - - @if ("#{$side} #{$corner}" == "left top") or ("#{$side} #{$corner}" == "top left") { - $degree: _position-flipper(#{$side}) _position-flipper(#{$corner}); - } - @else if ("#{$side} #{$corner}" == "right top") or ("#{$side} #{$corner}" == "top right") { - $degree: _position-flipper(#{$side}) _position-flipper(#{$corner}); - } - @else if ("#{$side} #{$corner}" == "right bottom") or ("#{$side} #{$corner}" == "bottom right") { - $degree: _position-flipper(#{$side}) _position-flipper(#{$corner}); - } - @else if ("#{$side} #{$corner}" == "left bottom") or ("#{$side} #{$corner}" == "bottom left") { - $degree: _position-flipper(#{$side}) _position-flipper(#{$corner}); - } - $spec: to $side $corner; - } - @else if $length == 1 { - // Swap for backwards compatability - @if $type == string { - $degree: $pos; - $spec: to _position-flipper($pos); - } - @else { - $degree: -270 - $pos; //rotate the gradient opposite from spec - $spec: $pos; - } - } - $degree: unquote($degree + ","); - $spec: unquote($spec + ","); - @return $degree $spec; -} - -@function _position-flipper($pos) { - @return if($pos == left, right, null) - if($pos == right, left, null) - if($pos == top, bottom, null) - if($pos == bottom, top, null); -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_linear-side-corner-parser.scss b/vitess.io/_sass/vendor/bourbon/helpers/_linear-side-corner-parser.scss deleted file mode 100644 index 86ad88fbb7d..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_linear-side-corner-parser.scss +++ /dev/null @@ -1,31 +0,0 @@ -// Private function for linear-gradient-parser -@function _linear-side-corner-parser($image, $first-val, $prefix, $suffix, $has-multiple-vals) { - $val-1: str-slice($first-val, 0, $has-multiple-vals - 1 ); - $val-2: str-slice($first-val, $has-multiple-vals + 1, str-length($first-val)); - $val-3: null; - $has-val-3: str-index($val-2, " "); - - @if $has-val-3 { - $val-3: str-slice($val-2, $has-val-3 + 1, str-length($val-2)); - $val-2: str-slice($val-2, 0, $has-val-3 - 1); - } - - $pos: _position-flipper($val-1) _position-flipper($val-2) _position-flipper($val-3); - $pos: unquote($pos + ""); - - // Use old spec for webkit - @if $val-1 == "to" { - @return ( - webkit-image: -webkit- + $prefix + $pos + $suffix, - spec-image: $image - ); - } - - // Bring the code up to spec - @else { - @return ( - webkit-image: -webkit- + $image, - spec-image: $prefix + "to " + $pos + $suffix - ); - } -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_radial-arg-parser.scss b/vitess.io/_sass/vendor/bourbon/helpers/_radial-arg-parser.scss deleted file mode 100644 index a3a3704af5e..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_radial-arg-parser.scss +++ /dev/null @@ -1,69 +0,0 @@ -@function _radial-arg-parser($G1, $G2, $pos, $shape-size) { - @each $value in $G1, $G2 { - $first-val: nth($value, 1); - $pos-type: type-of($first-val); - $spec-at-index: null; - - // Determine if spec was passed to mixin - @if type-of($value) == list { - $spec-at-index: if(index($value, at), index($value, at), false); - } - @if $spec-at-index { - @if $spec-at-index > 1 { - @for $i from 1 through ($spec-at-index - 1) { - $shape-size: $shape-size nth($value, $i); - } - @for $i from ($spec-at-index + 1) through length($value) { - $pos: $pos nth($value, $i); - } - } - @else if $spec-at-index == 1 { - @for $i from ($spec-at-index + 1) through length($value) { - $pos: $pos nth($value, $i); - } - } - $G1: null; - } - - // If not spec calculate correct values - @else { - @if ($pos-type != color) or ($first-val != "transparent") { - @if ($pos-type == number) - or ($first-val == "center") - or ($first-val == "top") - or ($first-val == "right") - or ($first-val == "bottom") - or ($first-val == "left") { - - $pos: $value; - - @if $pos == $G1 { - $G1: null; - } - } - - @else if - ($first-val == "ellipse") - or ($first-val == "circle") - or ($first-val == "closest-side") - or ($first-val == "closest-corner") - or ($first-val == "farthest-side") - or ($first-val == "farthest-corner") - or ($first-val == "contain") - or ($first-val == "cover") { - - $shape-size: $value; - - @if $value == $G1 { - $G1: null; - } - - @else if $value == $G2 { - $G2: null; - } - } - } - } - } - @return $G1, $G2, $pos, $shape-size; -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_radial-gradient-parser.scss b/vitess.io/_sass/vendor/bourbon/helpers/_radial-gradient-parser.scss deleted file mode 100644 index 6dde50f0640..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_radial-gradient-parser.scss +++ /dev/null @@ -1,50 +0,0 @@ -@function _radial-gradient-parser($image) { - $image: unquote($image); - $gradients: (); - $start: str-index($image, "("); - $end: str-index($image, ","); - $first-val: str-slice($image, $start + 1, $end - 1); - - $prefix: str-slice($image, 0, $start); - $suffix: str-slice($image, $end, str-length($image)); - - $is-spec-syntax: str-index($first-val, "at"); - - @if $is-spec-syntax and $is-spec-syntax > 1 { - $keyword: str-slice($first-val, 1, $is-spec-syntax - 2); - $pos: str-slice($first-val, $is-spec-syntax + 3, str-length($first-val)); - $pos: append($pos, $keyword, comma); - - $gradients: ( - webkit-image: -webkit- + $prefix + $pos + $suffix, - spec-image: $image - ) - } - - @else if $is-spec-syntax == 1 { - $pos: str-slice($first-val, $is-spec-syntax + 3, str-length($first-val)); - - $gradients: ( - webkit-image: -webkit- + $prefix + $pos + $suffix, - spec-image: $image - ) - } - - @else if str-index($image, "cover") or str-index($image, "contain") { - @warn "Radial-gradient needs to be updated to conform to latest spec."; - - $gradients: ( - webkit-image: null, - spec-image: $image - ) - } - - @else { - $gradients: ( - webkit-image: -webkit- + $image, - spec-image: $image - ) - } - - @return $gradients; -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_radial-positions-parser.scss b/vitess.io/_sass/vendor/bourbon/helpers/_radial-positions-parser.scss deleted file mode 100644 index 6a5b4777781..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_radial-positions-parser.scss +++ /dev/null @@ -1,18 +0,0 @@ -@function _radial-positions-parser($gradient-pos) { - $shape-size: nth($gradient-pos, 1); - $pos: nth($gradient-pos, 2); - $shape-size-spec: _shape-size-stripper($shape-size); - - $pre-spec: unquote(if($pos, "#{$pos}, ", null)) - unquote(if($shape-size, "#{$shape-size},", null)); - $pos-spec: if($pos, "at #{$pos}", null); - - $spec: "#{$shape-size-spec} #{$pos-spec}"; - - // Add comma - @if ($spec != ' ') { - $spec: "#{$spec}," - } - - @return $pre-spec $spec; -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_render-gradients.scss b/vitess.io/_sass/vendor/bourbon/helpers/_render-gradients.scss deleted file mode 100644 index 5765676838d..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_render-gradients.scss +++ /dev/null @@ -1,26 +0,0 @@ -// User for linear and radial gradients within background-image or border-image properties - -@function _render-gradients($gradient-positions, $gradients, $gradient-type, $vendor: false) { - $pre-spec: null; - $spec: null; - $vendor-gradients: null; - @if $gradient-type == linear { - @if $gradient-positions { - $pre-spec: nth($gradient-positions, 1); - $spec: nth($gradient-positions, 2); - } - } - @else if $gradient-type == radial { - $pre-spec: nth($gradient-positions, 1); - $spec: nth($gradient-positions, 2); - } - - @if $vendor { - $vendor-gradients: -#{$vendor}-#{$gradient-type}-gradient(#{$pre-spec} $gradients); - } - @else if $vendor == false { - $vendor-gradients: "#{$gradient-type}-gradient(#{$spec} #{$gradients})"; - $vendor-gradients: unquote($vendor-gradients); - } - @return $vendor-gradients; -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_shape-size-stripper.scss b/vitess.io/_sass/vendor/bourbon/helpers/_shape-size-stripper.scss deleted file mode 100644 index ee5eda42205..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_shape-size-stripper.scss +++ /dev/null @@ -1,10 +0,0 @@ -@function _shape-size-stripper($shape-size) { - $shape-size-spec: null; - @each $value in $shape-size { - @if ($value == "cover") or ($value == "contain") { - $value: null; - } - $shape-size-spec: "#{$shape-size-spec} #{$value}"; - } - @return $shape-size-spec; -} diff --git a/vitess.io/_sass/vendor/bourbon/helpers/_str-to-num.scss b/vitess.io/_sass/vendor/bourbon/helpers/_str-to-num.scss deleted file mode 100644 index b3d616824d3..00000000000 --- a/vitess.io/_sass/vendor/bourbon/helpers/_str-to-num.scss +++ /dev/null @@ -1,50 +0,0 @@ -//************************************************************************// -// Helper function for linear/radial-gradient-parsers. -// Source: http://sassmeister.com/gist/9647408 -//************************************************************************// -@function _str-to-num($string) { - // Matrices - $strings: '0' '1' '2' '3' '4' '5' '6' '7' '8' '9'; - $numbers: 0 1 2 3 4 5 6 7 8 9; - - // Result - $result: 0; - $divider: 0; - $minus: false; - - // Looping through all characters - @for $i from 1 through str-length($string) { - $character: str-slice($string, $i, $i); - $index: index($strings, $character); - - @if $character == '-' { - $minus: true; - } - - @else if $character == '.' { - $divider: 1; - } - - @else { - @if not $index { - $result: if($minus, $result * -1, $result); - @return _convert-units($result, str-slice($string, $i)); - } - - $number: nth($numbers, $index); - - @if $divider == 0 { - $result: $result * 10; - } - - @else { - // Move the decimal dot to the left - $divider: $divider * 10; - $number: $number / $divider; - } - - $result: $result + $number; - } - } - @return if($minus, $result * -1, $result); -} diff --git a/vitess.io/_sass/vendor/bourbon/settings/_prefixer.scss b/vitess.io/_sass/vendor/bourbon/settings/_prefixer.scss deleted file mode 100644 index ecab49fb542..00000000000 --- a/vitess.io/_sass/vendor/bourbon/settings/_prefixer.scss +++ /dev/null @@ -1,6 +0,0 @@ -// Variable settings for /addons/prefixer.scss -$prefix-for-webkit: true !default; -$prefix-for-mozilla: true !default; -$prefix-for-microsoft: true !default; -$prefix-for-opera: true !default; -$prefix-for-spec: true !default; // required for keyframe mixin diff --git a/vitess.io/_sass/vendor/bourbon/settings/_px-to-em.scss b/vitess.io/_sass/vendor/bourbon/settings/_px-to-em.scss deleted file mode 100644 index f2f9a3e8dee..00000000000 --- a/vitess.io/_sass/vendor/bourbon/settings/_px-to-em.scss +++ /dev/null @@ -1 +0,0 @@ -$em-base: 16px !default; diff --git a/vitess.io/_sass/vendor/neat/_neat-helpers.scss b/vitess.io/_sass/vendor/neat/_neat-helpers.scss deleted file mode 100644 index e915c698b94..00000000000 --- a/vitess.io/_sass/vendor/neat/_neat-helpers.scss +++ /dev/null @@ -1,7 +0,0 @@ -// Functions -@import "functions/private"; -@import "functions/new-breakpoint"; - -// Settings -@import "settings/grid"; -@import "settings/visual-grid"; diff --git a/vitess.io/_sass/vendor/neat/_neat.scss b/vitess.io/_sass/vendor/neat/_neat.scss deleted file mode 100644 index e93d636e6b6..00000000000 --- a/vitess.io/_sass/vendor/neat/_neat.scss +++ /dev/null @@ -1,21 +0,0 @@ -// Bourbon Neat 1.6.0.pre -// MIT Licensed -// Copyright (c) 2012-2013 thoughtbot, inc. - -// Helpers -@import "neat-helpers"; - -// Grid -@import "grid/private"; -@import "grid/reset"; -@import "grid/grid"; -@import "grid/omega"; -@import "grid/outer-container"; -@import "grid/span-columns"; -@import "grid/row"; -@import "grid/shift"; -@import "grid/pad"; -@import "grid/fill-parent"; -@import "grid/media"; -@import "grid/to-deprecate"; -@import "grid/visual-grid"; diff --git a/vitess.io/_sass/vendor/neat/functions/_new-breakpoint.scss b/vitess.io/_sass/vendor/neat/functions/_new-breakpoint.scss deleted file mode 100644 index a89c9ce6bba..00000000000 --- a/vitess.io/_sass/vendor/neat/functions/_new-breakpoint.scss +++ /dev/null @@ -1,16 +0,0 @@ -@function new-breakpoint($query:$feature $value $columns, $total-columns: $grid-columns) { - - @if length($query) == 1 { - $query: $default-feature nth($query, 1) $total-columns; - } - - @else if length($query) % 2 == 0 { - $query: append($query, $total-columns); - } - - @if not belongs-to($query, $visual-grid-breakpoints) { - $visual-grid-breakpoints: append($visual-grid-breakpoints, $query, comma) !global; - } - - @return $query; -} diff --git a/vitess.io/_sass/vendor/neat/functions/_private.scss b/vitess.io/_sass/vendor/neat/functions/_private.scss deleted file mode 100644 index 6f03cfcc7c7..00000000000 --- a/vitess.io/_sass/vendor/neat/functions/_private.scss +++ /dev/null @@ -1,125 +0,0 @@ -// Checks if a number is even -@function is-even($int) { - @if $int%2 == 0 { - @return true; - } - - @return false; -} - -// Checks if an element belongs to a list -@function belongs-to($tested-item, $list) { - @each $item in $list { - @if $item == $tested-item { - @return true; - } - } - - @return false; -} - -// Contains display value -@function contains-display-value($query) { - @if belongs-to(table, $query) or belongs-to(block, $query) or belongs-to(inline-block, $query) or belongs-to(inline, $query) { - @return true; - } - - @return false; -} - -// Parses the first argument of span-columns() -@function container-span($span: $span) { - @if length($span) == 3 { - $container-columns: nth($span, 3); - @return $container-columns; - } - - @else if length($span) == 2 { - $container-columns: nth($span, 2); - @return $container-columns; - } - - @else { - @return $grid-columns; - } -} - -@function container-shift($shift: $shift) { - $parent-columns: $grid-columns !global !default; - - @if length($shift) == 3 { - $container-columns: nth($shift, 3); - @return $container-columns; - } - - @else if length($shift) == 2 { - $container-columns: nth($shift, 2); - @return $container-columns; - } - - @else { - @return $parent-columns; - } -} - -// Generates a striped background -@function gradient-stops($grid-columns, $color: $visual-grid-color) { - $transparent: rgba(0,0,0,0); - - $column-width: flex-grid(1, $grid-columns); - $gutter-width: flex-gutter($grid-columns); - $column-offset: $column-width; - - $values: ($transparent 0, $color 0); - - @for $i from 1 to $grid-columns*2 { - @if is-even($i) { - $values: append($values, $transparent $column-offset, comma); - $values: append($values, $color $column-offset, comma); - $column-offset: $column-offset + $column-width; - } - - @else { - $values: append($values, $color $column-offset, comma); - $values: append($values, $transparent $column-offset, comma); - $column-offset: $column-offset + $gutter-width; - } - } - - @return $values; -} - -// Layout direction -@function get-direction($layout, $default) { - $direction: nil; - - @if $layout == LTR or $layout == RTL { - $direction: direction-from-layout($layout); - } @else { - $direction: direction-from-layout($default); - } - - @return $direction; -} - -@function direction-from-layout($layout) { - $direction: nil; - - @if $layout == LTR { - $direction: right; - } @else { - $direction: left; - } - - @return $direction; -} - -@function get-opposite-direction($direction) { - $opposite-direction: left; - - @if $direction == left { - $opposite-direction: right; - } - - @return $opposite-direction; -} diff --git a/vitess.io/_sass/vendor/neat/grid/_fill-parent.scss b/vitess.io/_sass/vendor/neat/grid/_fill-parent.scss deleted file mode 100644 index 859c97790bf..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_fill-parent.scss +++ /dev/null @@ -1,7 +0,0 @@ -@mixin fill-parent() { - width: 100%; - - @if $border-box-sizing == false { - @include box-sizing(border-box); - } -} diff --git a/vitess.io/_sass/vendor/neat/grid/_grid.scss b/vitess.io/_sass/vendor/neat/grid/_grid.scss deleted file mode 100644 index e074b6c536c..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_grid.scss +++ /dev/null @@ -1,5 +0,0 @@ -@if $border-box-sizing == true { - * { - @include box-sizing(border-box); - } -} diff --git a/vitess.io/_sass/vendor/neat/grid/_media.scss b/vitess.io/_sass/vendor/neat/grid/_media.scss deleted file mode 100644 index bf27f70ee5c..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_media.scss +++ /dev/null @@ -1,38 +0,0 @@ -@mixin media($query:$feature $value $columns, $total-columns: $grid-columns) { - @if length($query) == 1 { - @media screen and ($default-feature: nth($query, 1)) { - $default-grid-columns: $grid-columns; - $grid-columns: $total-columns !global; - @content; - $grid-columns: $default-grid-columns !global; - } - } - - @else { - $loopTo: length($query); - $mediaQuery: 'screen and '; - $default-grid-columns: $grid-columns; - $grid-columns: $total-columns !global; - - @if length($query) % 2 != 0 { - $grid-columns: nth($query, $loopTo) !global; - $loopTo: $loopTo - 1; - } - - $i: 1; - @while $i <= $loopTo { - $mediaQuery: $mediaQuery + '(' + nth($query, $i) + ': ' + nth($query, $i + 1) + ') '; - - @if ($i + 1) != $loopTo { - $mediaQuery: $mediaQuery + 'and '; - } - - $i: $i + 2; - } - - @media #{$mediaQuery} { - @content; - $grid-columns: $default-grid-columns !global; - } - } -} diff --git a/vitess.io/_sass/vendor/neat/grid/_omega.scss b/vitess.io/_sass/vendor/neat/grid/_omega.scss deleted file mode 100644 index c99ed6cf8a9..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_omega.scss +++ /dev/null @@ -1,61 +0,0 @@ -// Remove last element gutter -@mixin omega($query: block, $direction: default) { - $table: if(belongs-to(table, $query), true, false); - $auto: if(belongs-to(auto, $query), true, false); - - @if $direction != default { - @warn "The omega mixin will no longer take a $direction argument. To change the layout direction, use row($direction) or set $default-layout-direction instead." - } @else { - $direction: get-direction($layout-direction, $default-layout-direction); - } - - @if $table { - @warn "The omega mixin no longer removes padding in table layouts." - } - - @if length($query) == 1 { - @if $auto { - &:last-child { - margin-#{$direction}: 0; - } - } - - @else if contains-display-value($query) and $table == false { - margin-#{$direction}: 0; - } - - @else { - @include nth-child($query, $direction); - } - } - - @else if length($query) == 2 { - @if $auto { - &:last-child { - margin-#{$direction}: 0; - } - } - - @else { - @include nth-child(nth($query, 1), $direction); - } - } - - @else { - @warn "Too many arguments passed to the omega() mixin." - } -} - -@mixin nth-child($query, $direction) { - $opposite-direction: get-opposite-direction($direction); - - &:nth-child(#{$query}) { - margin-#{$direction}: 0; - } - - @if type-of($query) == number { - &:nth-child(#{$query}+1) { - clear: $opposite-direction; - } - } -} diff --git a/vitess.io/_sass/vendor/neat/grid/_outer-container.scss b/vitess.io/_sass/vendor/neat/grid/_outer-container.scss deleted file mode 100644 index 22c541f4553..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_outer-container.scss +++ /dev/null @@ -1,8 +0,0 @@ -@mixin outer-container { - @include clearfix; - max-width: $max-width; - margin: { - left: auto; - right: auto; - } -} diff --git a/vitess.io/_sass/vendor/neat/grid/_pad.scss b/vitess.io/_sass/vendor/neat/grid/_pad.scss deleted file mode 100644 index 3ef5d80e45b..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_pad.scss +++ /dev/null @@ -1,8 +0,0 @@ -@mixin pad($padding: flex-gutter()) { - $padding-list: null; - @each $value in $padding { - $value: if($value == 'default', flex-gutter(), $value); - $padding-list: join($padding-list, $value); - } - padding: $padding-list; -} diff --git a/vitess.io/_sass/vendor/neat/grid/_private.scss b/vitess.io/_sass/vendor/neat/grid/_private.scss deleted file mode 100644 index b1953368d7c..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_private.scss +++ /dev/null @@ -1,43 +0,0 @@ -$parent-columns: $grid-columns !default; -$fg-column: $column; -$fg-gutter: $gutter; -$fg-max-columns: $grid-columns; -$container-display-table: false !default; -$layout-direction: nil !default; - -@function flex-grid($columns, $container-columns: $fg-max-columns) { - $width: $columns * $fg-column + ($columns - 1) * $fg-gutter; - $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter; - @return percentage($width / $container-width); -} - -@function flex-gutter($container-columns: $fg-max-columns, $gutter: $fg-gutter) { - $container-width: $container-columns * $fg-column + ($container-columns - 1) * $fg-gutter; - @return percentage($gutter / $container-width); -} - -@function grid-width($n) { - @return $n * $gw-column + ($n - 1) * $gw-gutter; -} - -@function get-parent-columns($columns) { - @if $columns != $grid-columns { - $parent-columns: $columns !global; - } @else { - $parent-columns: $grid-columns !global; - } - - @return $parent-columns; -} - -@function is-display-table($container-is-display-table, $display) { - $display-table: false; - - @if $container-is-display-table == true { - $display-table: true; - } @else if $display == table { - $display-table: true; - } - - @return $display-table; -} diff --git a/vitess.io/_sass/vendor/neat/grid/_reset.scss b/vitess.io/_sass/vendor/neat/grid/_reset.scss deleted file mode 100644 index 496c4a775ba..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_reset.scss +++ /dev/null @@ -1,12 +0,0 @@ -@mixin reset-display { - $container-display-table: false !global; -} - -@mixin reset-layout-direction { - $layout-direction: $default-layout-direction !global; -} - -@mixin reset-all { - @include reset-display; - @include reset-layout-direction; -} diff --git a/vitess.io/_sass/vendor/neat/grid/_row.scss b/vitess.io/_sass/vendor/neat/grid/_row.scss deleted file mode 100644 index 81da6d36a6c..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_row.scss +++ /dev/null @@ -1,17 +0,0 @@ -@mixin row($display: block, $direction: $default-layout-direction) { - @include clearfix; - $layout-direction: $direction !global; - - @if $display == table { - display: table; - @include fill-parent; - table-layout: fixed; - $container-display-table: true !global; - } - - @else { - display: block; - $container-display-table: false !global; - } -} - diff --git a/vitess.io/_sass/vendor/neat/grid/_shift.scss b/vitess.io/_sass/vendor/neat/grid/_shift.scss deleted file mode 100644 index 1d27b9b77f9..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_shift.scss +++ /dev/null @@ -1,16 +0,0 @@ -@mixin shift($n-columns: 1) { - @include shift-in-context($n-columns); -} - -@mixin shift-in-context($shift: $columns of $container-columns) { - $n-columns: nth($shift, 1); - $parent-columns: container-shift($shift) !global; - - $direction: get-direction($layout-direction, $default-layout-direction); - $opposite-direction: get-opposite-direction($direction); - - margin-#{$opposite-direction}: $n-columns * flex-grid(1, $parent-columns) + $n-columns * flex-gutter($parent-columns); - - // Reset nesting context - $parent-columns: $grid-columns !global; -} diff --git a/vitess.io/_sass/vendor/neat/grid/_span-columns.scss b/vitess.io/_sass/vendor/neat/grid/_span-columns.scss deleted file mode 100644 index c79193d93cf..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_span-columns.scss +++ /dev/null @@ -1,43 +0,0 @@ -@mixin span-columns($span: $columns of $container-columns, $display: block) { - $columns: nth($span, 1); - $container-columns: container-span($span); - - // Set nesting context (used by shift()) - $parent-columns: get-parent-columns($container-columns) !global; - - $direction: get-direction($layout-direction, $default-layout-direction); - $opposite-direction: get-opposite-direction($direction); - - $display-table: is-display-table($container-display-table, $display); - - @if $display-table { - display: table-cell; - width: percentage($columns / $container-columns); - } @else { - float: #{$opposite-direction}; - - @if $display != no-display { - display: block; - } - - @if $display == collapse { - @warn "The 'collapse' argument will be deprecated. Use 'block-collapse' instead." - } - - @if $display == collapse or $display == block-collapse { - width: flex-grid($columns, $container-columns) + flex-gutter($container-columns); - - &:last-child { - width: flex-grid($columns, $container-columns); - } - - } @else { - margin-#{$direction}: flex-gutter($container-columns); - width: flex-grid($columns, $container-columns); - - &:last-child { - margin-#{$direction}: 0; - } - } - } -} diff --git a/vitess.io/_sass/vendor/neat/grid/_to-deprecate.scss b/vitess.io/_sass/vendor/neat/grid/_to-deprecate.scss deleted file mode 100644 index d0a681fd12e..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_to-deprecate.scss +++ /dev/null @@ -1,57 +0,0 @@ -@mixin breakpoint($query:$feature $value $columns, $total-columns: $grid-columns) { - @warn "The breakpoint() mixin was renamed to media() in Neat 1.0. Please update your project with the new syntax before the next version bump."; - - @if length($query) == 1 { - @media screen and ($default-feature: nth($query, 1)) { - $default-grid-columns: $grid-columns; - $grid-columns: $total-columns; - @content; - $grid-columns: $default-grid-columns; - } - } - - @else if length($query) == 2 { - @media screen and (nth($query, 1): nth($query, 2)) { - $default-grid-columns: $grid-columns; - $grid-columns: $total-columns; - @content; - $grid-columns: $default-grid-columns; - } - } - - @else if length($query) == 3 { - @media screen and (nth($query, 1): nth($query, 2)) { - $default-grid-columns: $grid-columns; - $grid-columns: nth($query, 3); - @content; - $grid-columns: $default-grid-columns; - } - } - - @else if length($query) == 4 { - @media screen and (nth($query, 1): nth($query, 2)) and (nth($query, 3): nth($query, 4)) { - $default-grid-columns: $grid-columns; - $grid-columns: $total-columns; - @content; - $grid-columns: $default-grid-columns; - } - } - - @else if length($query) == 5 { - @media screen and (nth($query, 1): nth($query, 2)) and (nth($query, 3): nth($query, 4)) { - $default-grid-columns: $grid-columns; - $grid-columns: nth($query, 5); - @content; - $grid-columns: $default-grid-columns; - } - } - - @else { - @warn "Wrong number of arguments for breakpoint(). Read the documentation for more details."; - } -} - -@mixin nth-omega($nth, $display: block, $direction: default) { - @warn "The nth-omega() mixin is deprecated. Please use omega() instead."; - @include omega($nth $display, $direction); -} diff --git a/vitess.io/_sass/vendor/neat/grid/_visual-grid.scss b/vitess.io/_sass/vendor/neat/grid/_visual-grid.scss deleted file mode 100644 index 1c822fd3220..00000000000 --- a/vitess.io/_sass/vendor/neat/grid/_visual-grid.scss +++ /dev/null @@ -1,41 +0,0 @@ -@mixin grid-column-gradient($values...) { - background-image: deprecated-webkit-gradient(linear, left top, left bottom, $values); - background-image: -webkit-linear-gradient(left, $values); - background-image: -moz-linear-gradient(left, $values); - background-image: -ms-linear-gradient(left, $values); - background-image: -o-linear-gradient(left, $values); - background-image: unquote("linear-gradient(left, #{$values})"); -} - -@if $visual-grid == true or $visual-grid == yes { - body:before { - content: ''; - display: inline-block; - @include grid-column-gradient(gradient-stops($grid-columns)); - height: 100%; - left: 0; - margin: 0 auto; - max-width: $max-width; - opacity: $visual-grid-opacity; - position: fixed; - right: 0; - width: 100%; - pointer-events: none; - - @if $visual-grid-index == back { - z-index: -1; - } - - @else if $visual-grid-index == front { - z-index: 9999; - } - - @each $breakpoint in $visual-grid-breakpoints { - @if $breakpoint != nil { - @include media($breakpoint) { - @include grid-column-gradient(gradient-stops($grid-columns)); - } - } - } - } -} diff --git a/vitess.io/_sass/vendor/neat/settings/_grid.scss b/vitess.io/_sass/vendor/neat/settings/_grid.scss deleted file mode 100644 index f1dcda47804..00000000000 --- a/vitess.io/_sass/vendor/neat/settings/_grid.scss +++ /dev/null @@ -1,7 +0,0 @@ -$column: golden-ratio(1em, 3) !default; // Column width -$gutter: golden-ratio(1em, 1) !default; // Gutter between each two columns -$grid-columns: 12 !default; // Total number of columns in the grid -$max-width: em(1088) !default; // Max-width of the outer container -$border-box-sizing: true !default; // Makes all elements have a border-box layout -$default-feature: min-width; // Default @media feature for the breakpoint() mixin -$default-layout-direction: LTR !default; diff --git a/vitess.io/_sass/vendor/neat/settings/_visual-grid.scss b/vitess.io/_sass/vendor/neat/settings/_visual-grid.scss deleted file mode 100644 index 611c2b37274..00000000000 --- a/vitess.io/_sass/vendor/neat/settings/_visual-grid.scss +++ /dev/null @@ -1,5 +0,0 @@ -$visual-grid: false !default; // Display the base grid -$visual-grid-color: #EEE !default; -$visual-grid-index: back !default; // Show grid behind content (back) or overlay it over the content (front) -$visual-grid-opacity: 0.4 !default; -$visual-grid-breakpoints: () !default; diff --git a/vitess.io/_templates/archive b/vitess.io/_templates/archive deleted file mode 100644 index b13a701f52f..00000000000 --- a/vitess.io/_templates/archive +++ /dev/null @@ -1,11 +0,0 @@ ---- -layout: archive -title: {{ title }} -date: {{ date }} -modified: -excerpt: -image: - feature: - teaser: - thumb: ---- diff --git a/vitess.io/_templates/page b/vitess.io/_templates/page deleted file mode 100644 index 50f15fea3e1..00000000000 --- a/vitess.io/_templates/page +++ /dev/null @@ -1,12 +0,0 @@ ---- -layout: {{ layout }} -title: {{ title }} -date: {{ date }} -modified: -excerpt: -image: - feature: - teaser: - thumb: -ads: false ---- diff --git a/vitess.io/_templates/post b/vitess.io/_templates/post deleted file mode 100644 index e01e5bad66e..00000000000 --- a/vitess.io/_templates/post +++ /dev/null @@ -1,12 +0,0 @@ ---- -layout: {{ layout }} -title: {{ title }} -modified: -categories: {{ dir }} -excerpt: -tags: [] -image: - feature: - teaser: - thumb: ---- diff --git a/vitess.io/advanced/index.md b/vitess.io/advanced/index.md deleted file mode 100644 index ad49349f48e..00000000000 --- a/vitess.io/advanced/index.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: doc -title: "Advanced Features: Overview" -description: -modified: -excerpt: -tags: [] -image: - feature: - teaser: - thumb: -toc: true -share: false ---- - -{% include doc/AdvancedFeaturesIndex.md %} diff --git a/vitess.io/advanced/messaging.md b/vitess.io/advanced/messaging.md deleted file mode 100644 index bf89f1fb33a..00000000000 --- a/vitess.io/advanced/messaging.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: doc -title: "Messaging" -description: -modified: -excerpt: -tags: [] -image: - feature: - teaser: - thumb: -toc: true -share: false ---- - -{% include doc/Messaging.md %} diff --git a/vitess.io/assets/scripts/jquery-1.8.3.min.js b/vitess.io/assets/scripts/jquery-1.8.3.min.js deleted file mode 100644 index 38837795279..00000000000 --- a/vitess.io/assets/scripts/jquery-1.8.3.min.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! jQuery v1.8.3 jquery.com | jquery.org/license */ -(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
    a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
    t
    ",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
    ",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
    ",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

    ",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
    ","
    "]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
    ").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); \ No newline at end of file diff --git a/vitess.io/assets/scripts/jquery-ui.min.js b/vitess.io/assets/scripts/jquery-ui.min.js deleted file mode 100644 index 3754411dcbf..00000000000 --- a/vitess.io/assets/scripts/jquery-ui.min.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - * jQuery UI 1.7.3 - * - * Copyright (c) 2009 AUTHORS.txt (http://jqueryui.com/about) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * http://docs.jquery.com/UI - */ jQuery.ui||(function(c){var i=c.fn.remove,d=c.browser.mozilla&&(parseFloat(c.browser.version)<1.9);c.ui={version:"1.7.3",plugin:{add:function(k,l,n){var m=c.ui[k].prototype;for(var j in n){m.plugins[j]=m.plugins[j]||[];m.plugins[j].push([l,n[j]])}},call:function(j,l,k){var n=j.plugins[l];if(!n||!j.element[0].parentNode){return}for(var m=0;m0){return true}m[j]=1;l=(m[j]>0);m[j]=0;return l},isOverAxis:function(k,j,l){return(k>j)&&(k<(j+l))},isOver:function(o,k,n,m,j,l){return c.ui.isOverAxis(o,n,j)&&c.ui.isOverAxis(k,m,l)},keyCode:{BACKSPACE:8,CAPS_LOCK:20,COMMA:188,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38}};if(d){var f=c.attr,e=c.fn.removeAttr,h="http://www.w3.org/2005/07/aaa",a=/^aria-/,b=/^wairole:/;c.attr=function(k,j,l){var m=l!==undefined;return(j=="role"?(m?f.call(this,k,j,"wairole:"+l):(f.apply(this,arguments)||"").replace(b,"")):(a.test(j)?(m?k.setAttributeNS(h,j.replace(a,"aaa:"),l):f.call(this,k,j.replace(a,"aaa:"))):f.apply(this,arguments)))};c.fn.removeAttr=function(j){return(a.test(j)?this.each(function(){this.removeAttributeNS(h,j.replace(a,""))}):e.call(this,j))}}c.fn.extend({remove:function(j,k){return this.each(function(){if(!k){if(!j||c.filter(j,[this]).length){c("*",this).add(this).each(function(){c(this).triggerHandler("remove")})}}return i.call(c(this),j,k)})},enableSelection:function(){return this.attr("unselectable","off").css("MozUserSelect","").unbind("selectstart.ui")},disableSelection:function(){return this.attr("unselectable","on").css("MozUserSelect","none").bind("selectstart.ui",function(){return false})},scrollParent:function(){var j;if((c.browser.msie&&(/(static|relative)/).test(this.css("position")))||(/absolute/).test(this.css("position"))){j=this.parents().filter(function(){return(/(relative|absolute|fixed)/).test(c.curCSS(this,"position",1))&&(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}else{j=this.parents().filter(function(){return(/(auto|scroll)/).test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0)}return(/fixed/).test(this.css("position"))||!j.length?c(document):j}});c.extend(c.expr[":"],{data:function(l,k,j){return !!c.data(l,j[3])},focusable:function(k){var l=k.nodeName.toLowerCase(),j=c.attr(k,"tabindex");return(/input|select|textarea|button|object/.test(l)?!k.disabled:"a"==l||"area"==l?k.href||!isNaN(j):!isNaN(j))&&!c(k)["area"==l?"parents":"closest"](":hidden").length},tabbable:function(k){var j=c.attr(k,"tabindex");return(isNaN(j)||j>=0)&&c(k).is(":focusable")}});function g(m,n,o,l){function k(q){var p=c[m][n][q]||[];return(typeof p=="string"?p.split(/,?\s+/):p)}var j=k("getter");if(l.length==1&&typeof l[0]=="string"){j=j.concat(k("getterSetter"))}return(c.inArray(o,j)!=-1)}c.widget=function(k,j){var l=k.split(".")[0];k=k.split(".")[1];c.fn[k]=function(p){var n=(typeof p=="string"),o=Array.prototype.slice.call(arguments,1);if(n&&p.substring(0,1)=="_"){return this}if(n&&g(l,k,p,o)){var m=c.data(this[0],k);return(m?m[p].apply(m,o):undefined)}return this.each(function(){var q=c.data(this,k);(!q&&!n&&c.data(this,k,new c[l][k](this,p))._init());(q&&n&&c.isFunction(q[p])&&q[p].apply(q,o))})};c[l]=c[l]||{};c[l][k]=function(o,n){var m=this;this.namespace=l;this.widgetName=k;this.widgetEventPrefix=c[l][k].eventPrefix||k;this.widgetBaseClass=l+"-"+k;this.options=c.extend({},c.widget.defaults,c[l][k].defaults,c.metadata&&c.metadata.get(o)[k],n);this.element=c(o).bind("setData."+k,function(q,p,r){if(q.target==o){return m._setData(p,r)}}).bind("getData."+k,function(q,p){if(q.target==o){return m._getData(p)}}).bind("remove",function(){return m.destroy()})};c[l][k].prototype=c.extend({},c.widget.prototype,j);c[l][k].getterSetter="option"};c.widget.prototype={_init:function(){},destroy:function(){this.element.removeData(this.widgetName).removeClass(this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").removeAttr("aria-disabled")},option:function(l,m){var k=l,j=this;if(typeof l=="string"){if(m===undefined){return this._getData(l)}k={};k[l]=m}c.each(k,function(n,o){j._setData(n,o)})},_getData:function(j){return this.options[j]},_setData:function(j,k){this.options[j]=k;if(j=="disabled"){this.element[k?"addClass":"removeClass"](this.widgetBaseClass+"-disabled "+this.namespace+"-state-disabled").attr("aria-disabled",k)}},enable:function(){this._setData("disabled",false)},disable:function(){this._setData("disabled",true)},_trigger:function(l,m,n){var p=this.options[l],j=(l==this.widgetEventPrefix?l:this.widgetEventPrefix+l);m=c.Event(m);m.type=j;if(m.originalEvent){for(var k=c.event.props.length,o;k;){o=c.event.props[--k];m[o]=m.originalEvent[o]}}this.element.trigger(m,n);return !(c.isFunction(p)&&p.call(this.element[0],m,n)===false||m.isDefaultPrevented())}};c.widget.defaults={disabled:false};c.ui.mouse={_mouseInit:function(){var j=this;this.element.bind("mousedown."+this.widgetName,function(k){return j._mouseDown(k)}).bind("click."+this.widgetName,function(k){if(j._preventClickEvent){j._preventClickEvent=false;k.stopImmediatePropagation();return false}});if(c.browser.msie){this._mouseUnselectable=this.element.attr("unselectable");this.element.attr("unselectable","on")}this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName);(c.browser.msie&&this.element.attr("unselectable",this._mouseUnselectable))},_mouseDown:function(l){l.originalEvent=l.originalEvent||{};if(l.originalEvent.mouseHandled){return}(this._mouseStarted&&this._mouseUp(l));this._mouseDownEvent=l;var k=this,m=(l.which==1),j=(typeof this.options.cancel=="string"?c(l.target).parents().add(l.target).filter(this.options.cancel).length:false);if(!m||j||!this._mouseCapture(l)){return true}this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet){this._mouseDelayTimer=setTimeout(function(){k.mouseDelayMet=true},this.options.delay)}if(this._mouseDistanceMet(l)&&this._mouseDelayMet(l)){this._mouseStarted=(this._mouseStart(l)!==false);if(!this._mouseStarted){l.preventDefault();return true}}this._mouseMoveDelegate=function(n){return k._mouseMove(n)};this._mouseUpDelegate=function(n){return k._mouseUp(n)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);(c.browser.safari||l.preventDefault());l.originalEvent.mouseHandled=true;return true},_mouseMove:function(j){if(c.browser.msie&&!j.button){return this._mouseUp(j)}if(this._mouseStarted){this._mouseDrag(j);return j.preventDefault()}if(this._mouseDistanceMet(j)&&this._mouseDelayMet(j)){this._mouseStarted=(this._mouseStart(this._mouseDownEvent,j)!==false);(this._mouseStarted?this._mouseDrag(j):this._mouseUp(j))}return !this._mouseStarted},_mouseUp:function(j){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=(j.target==this._mouseDownEvent.target);this._mouseStop(j)}return false},_mouseDistanceMet:function(j){return(Math.max(Math.abs(this._mouseDownEvent.pageX-j.pageX),Math.abs(this._mouseDownEvent.pageY-j.pageY))>=this.options.distance)},_mouseDelayMet:function(j){return this.mouseDelayMet},_mouseStart:function(j){},_mouseDrag:function(j){},_mouseStop:function(j){},_mouseCapture:function(j){return true}};c.ui.mouse.defaults={cancel:null,distance:1,delay:0}})(jQuery);(function(a){a.widget("ui.draggable",a.extend({},a.ui.mouse,{_init:function(){if(this.options.helper=="original"&&!(/^(?:r|a|f)/).test(this.element.css("position"))){this.element[0].style.position="relative"}(this.options.addClasses&&this.element.addClass("ui-draggable"));(this.options.disabled&&this.element.addClass("ui-draggable-disabled"));this._mouseInit()},destroy:function(){if(!this.element.data("draggable")){return}this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy()},_mouseCapture:function(b){var c=this.options;if(this.helper||c.disabled||a(b.target).is(".ui-resizable-handle")){return false}this.handle=this._getHandle(b);if(!this.handle){return false}return true},_mouseStart:function(b){var c=this.options;this.helper=this._createHelper(b);this._cacheHelperProportions();if(a.ui.ddmanager){a.ui.ddmanager.current=this}this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.element.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};a.extend(this.offset,{click:{left:b.pageX-this.offset.left,top:b.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(b);this.originalPageX=b.pageX;this.originalPageY=b.pageY;if(c.cursorAt){this._adjustOffsetFromHelper(c.cursorAt)}if(c.containment){this._setContainment()}this._trigger("start",b);this._cacheHelperProportions();if(a.ui.ddmanager&&!c.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,b)}this.helper.addClass("ui-draggable-dragging");this._mouseDrag(b,true);return true},_mouseDrag:function(b,d){this.position=this._generatePosition(b);this.positionAbs=this._convertPositionTo("absolute");if(!d){var c=this._uiHash();this._trigger("drag",b,c);this.position=c.position}if(!this.options.axis||this.options.axis!="y"){this.helper[0].style.left=this.position.left+"px"}if(!this.options.axis||this.options.axis!="x"){this.helper[0].style.top=this.position.top+"px"}if(a.ui.ddmanager){a.ui.ddmanager.drag(this,b)}return false},_mouseStop:function(c){var d=false;if(a.ui.ddmanager&&!this.options.dropBehaviour){d=a.ui.ddmanager.drop(this,c)}if(this.dropped){d=this.dropped;this.dropped=false}if((this.options.revert=="invalid"&&!d)||(this.options.revert=="valid"&&d)||this.options.revert===true||(a.isFunction(this.options.revert)&&this.options.revert.call(this.element,d))){var b=this;a(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){b._trigger("stop",c);b._clear()})}else{this._trigger("stop",c);this._clear()}return false},_getHandle:function(b){var c=!this.options.handle||!a(this.options.handle,this.element).length?true:false;a(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==b.target){c=true}});return c},_createHelper:function(c){var d=this.options;var b=a.isFunction(d.helper)?a(d.helper.apply(this.element[0],[c])):(d.helper=="clone"?this.element.clone():this.element);if(!b.parents("body").length){b.appendTo((d.appendTo=="parent"?this.element[0].parentNode:d.appendTo))}if(b[0]!=this.element[0]&&!(/(fixed|absolute)/).test(b.css("position"))){b.css("position","absolute")}return b},_adjustOffsetFromHelper:function(b){if(b.left!=undefined){this.offset.click.left=b.left+this.margins.left}if(b.right!=undefined){this.offset.click.left=this.helperProportions.width-b.right+this.margins.left}if(b.top!=undefined){this.offset.click.top=b.top+this.margins.top}if(b.bottom!=undefined){this.offset.click.top=this.helperProportions.height-b.bottom+this.margins.top}},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var b=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0])){b.left+=this.scrollParent.scrollLeft();b.top+=this.scrollParent.scrollTop()}if((this.offsetParent[0]==document.body)||(this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&a.browser.msie)){b={top:0,left:0}}return{top:b.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:b.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var b=this.element.position();return{top:b.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:b.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else{return{top:0,left:0}}},_cacheMargins:function(){this.margins={left:(parseInt(this.element.css("marginLeft"),10)||0),top:(parseInt(this.element.css("marginTop"),10)||0)}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var e=this.options;if(e.containment=="parent"){e.containment=this.helper[0].parentNode}if(e.containment=="document"||e.containment=="window"){this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,a(e.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a(e.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top]}if(!(/^(document|window|parent)$/).test(e.containment)&&e.containment.constructor!=Array){var c=a(e.containment)[0];if(!c){return}var d=a(e.containment).offset();var b=(a(c).css("overflow")!="hidden");this.containment=[d.left+(parseInt(a(c).css("borderLeftWidth"),10)||0)+(parseInt(a(c).css("paddingLeft"),10)||0)-this.margins.left,d.top+(parseInt(a(c).css("borderTopWidth"),10)||0)+(parseInt(a(c).css("paddingTop"),10)||0)-this.margins.top,d.left+(b?Math.max(c.scrollWidth,c.offsetWidth):c.offsetWidth)-(parseInt(a(c).css("borderLeftWidth"),10)||0)-(parseInt(a(c).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,d.top+(b?Math.max(c.scrollHeight,c.offsetHeight):c.offsetHeight)-(parseInt(a(c).css("borderTopWidth"),10)||0)-(parseInt(a(c).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}else{if(e.containment.constructor==Array){this.containment=e.containment}}},_convertPositionTo:function(f,h){if(!h){h=this.position}var c=f=="absolute"?1:-1;var e=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,g=(/(html|body)/i).test(b[0].tagName);return{top:(h.top+this.offset.relative.top*c+this.offset.parent.top*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():(g?0:b.scrollTop()))*c)),left:(h.left+this.offset.relative.left*c+this.offset.parent.left*c-(a.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():g?0:b.scrollLeft())*c))}},_generatePosition:function(e){var h=this.options,b=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&a.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,i=(/(html|body)/i).test(b[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0])){this.offset.relative=this._getRelativeOffset()}var d=e.pageX;var c=e.pageY;if(this.originalPosition){if(this.containment){if(e.pageX-this.offset.click.leftthis.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.topthis.containment[3])?g:(!(g-this.offset.click.topthis.containment[2])?f:(!(f-this.offset.click.left
    ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1000}).css(a(this).offset()).appendTo("body")})},stop:function(b,c){a("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});a.ui.plugin.add("draggable","opacity",{start:function(c,d){var b=a(d.helper),e=a(this).data("draggable").options;if(b.css("opacity")){e._opacity=b.css("opacity")}b.css("opacity",e.opacity)},stop:function(b,c){var d=a(this).data("draggable").options;if(d._opacity){a(c.helper).css("opacity",d._opacity)}}});a.ui.plugin.add("draggable","scroll",{start:function(c,d){var b=a(this).data("draggable");if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){b.overflowOffset=b.scrollParent.offset()}},drag:function(d,e){var c=a(this).data("draggable"),f=c.options,b=false;if(c.scrollParent[0]!=document&&c.scrollParent[0].tagName!="HTML"){if(!f.axis||f.axis!="x"){if((c.overflowOffset.top+c.scrollParent[0].offsetHeight)-d.pageY=0;v--){var s=g.snapElements[v].left,n=s+g.snapElements[v].width,m=g.snapElements[v].top,A=m+g.snapElements[v].height;if(!((s-y=p&&n<=k)||(m>=p&&m<=k)||(nk))&&((e>=g&&e<=c)||(d>=g&&d<=c)||(ec));break;default:return false;break}};a.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(e,g){var b=a.ui.ddmanager.droppables[e.options.scope];var f=g?g.type:null;var h=(e.currentItem||e.element).find(":data(droppable)").andSelf();droppablesLoop:for(var d=0;d').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=j.handles||(!c(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all"){this.handles="n,e,s,w,se,sw,ne,nw"}var k=this.handles.split(",");this.handles={};for(var f=0;f');if(/sw|se|ne|nw/.test(h)){g.css({zIndex:++j.zIndex})}if("se"==h){g.addClass("ui-icon ui-icon-gripsmall-diagonal-se")}this.handles[h]=".ui-resizable-"+h;this.element.append(g)}}this._renderAxis=function(p){p=p||this.element;for(var m in this.handles){if(this.handles[m].constructor==String){this.handles[m]=c(this.handles[m],this.element).show()}if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var n=c(this.handles[m],this.element),o=0;o=/sw|ne|nw|se|n|s/.test(m)?n.outerHeight():n.outerWidth();var l=["padding",/ne|nw|n/.test(m)?"Top":/se|sw|s/.test(m)?"Bottom":/^e$/.test(m)?"Right":"Left"].join("");p.css(l,o);this._proportionallyResize()}if(!c(this.handles[m]).length){continue}}};this._renderAxis(this.element);this._handles=c(".ui-resizable-handle",this.element).disableSelection();this._handles.mouseover(function(){if(!e.resizing){if(this.className){var i=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)}e.axis=i&&i[1]?i[1]:"se"}});if(j.autoHide){this._handles.hide();c(this.element).addClass("ui-resizable-autohide").hover(function(){c(this).removeClass("ui-resizable-autohide");e._handles.show()},function(){if(!e.resizing){c(this).addClass("ui-resizable-autohide");e._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var d=function(f){c(f).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){d(this.element);var e=this.element;e.parent().append(this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")})).end().remove()}this.originalElement.css("resize",this.originalResizeStyle);d(this.originalElement)},_mouseCapture:function(e){var f=false;for(var d in this.handles){if(c(this.handles[d])[0]==e.target){f=true}}return this.options.disabled||!!f},_mouseStart:function(f){var i=this.options,e=this.element.position(),d=this.element;this.resizing=true;this.documentScroll={top:c(document).scrollTop(),left:c(document).scrollLeft()};if(d.is(".ui-draggable")||(/absolute/).test(d.css("position"))){d.css({position:"absolute",top:e.top,left:e.left})}if(c.browser.opera&&(/relative/).test(d.css("position"))){d.css({position:"relative",top:"auto",left:"auto"})}this._renderProxy();var j=b(this.helper.css("left")),g=b(this.helper.css("top"));if(i.containment){j+=c(i.containment).scrollLeft()||0;g+=c(i.containment).scrollTop()||0}this.offset=this.helper.offset();this.position={left:j,top:g};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:j,top:g};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:f.pageX,top:f.pageY};this.aspectRatio=(typeof i.aspectRatio=="number")?i.aspectRatio:((this.originalSize.width/this.originalSize.height)||1);var h=c(".ui-resizable-"+this.axis).css("cursor");c("body").css("cursor",h=="auto"?this.axis+"-resize":h);d.addClass("ui-resizable-resizing");this._propagate("start",f);return true},_mouseDrag:function(d){var g=this.helper,f=this.options,l={},p=this,i=this.originalMousePosition,m=this.axis;var q=(d.pageX-i.left)||0,n=(d.pageY-i.top)||0;var h=this._change[m];if(!h){return false}var k=h.apply(this,[d,q,n]),j=c.browser.msie&&c.browser.version<7,e=this.sizeDiff;if(this._aspectRatio||d.shiftKey){k=this._updateRatio(k,d)}k=this._respectSize(k,d);this._propagate("resize",d);g.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});if(!this._helper&&this._proportionallyResizeElements.length){this._proportionallyResize()}this._updateCache(k);this._trigger("resize",d,this.ui());return false},_mouseStop:function(g){this.resizing=false;var h=this.options,l=this;if(this._helper){var f=this._proportionallyResizeElements,d=f.length&&(/textarea/i).test(f[0].nodeName),e=d&&c.ui.hasScroll(f[0],"left")?0:l.sizeDiff.height,j=d?0:l.sizeDiff.width;var m={width:(l.size.width-j),height:(l.size.height-e)},i=(parseInt(l.element.css("left"),10)+(l.position.left-l.originalPosition.left))||null,k=(parseInt(l.element.css("top"),10)+(l.position.top-l.originalPosition.top))||null;if(!h.animate){this.element.css(c.extend(m,{top:k,left:i}))}l.helper.height(l.size.height);l.helper.width(l.size.width);if(this._helper&&!h.animate){this._proportionallyResize()}}c("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",g);if(this._helper){this.helper.remove()}return false},_updateCache:function(d){var e=this.options;this.offset=this.helper.offset();if(a(d.left)){this.position.left=d.left}if(a(d.top)){this.position.top=d.top}if(a(d.height)){this.size.height=d.height}if(a(d.width)){this.size.width=d.width}},_updateRatio:function(g,f){var h=this.options,i=this.position,e=this.size,d=this.axis;if(g.height){g.width=(e.height*this.aspectRatio)}else{if(g.width){g.height=(e.width/this.aspectRatio)}}if(d=="sw"){g.left=i.left+(e.width-g.width);g.top=null}if(d=="nw"){g.top=i.top+(e.height-g.height);g.left=i.left+(e.width-g.width)}return g},_respectSize:function(k,f){var i=this.helper,h=this.options,q=this._aspectRatio||f.shiftKey,p=this.axis,s=a(k.width)&&h.maxWidth&&(h.maxWidthk.width),r=a(k.height)&&h.minHeight&&(h.minHeight>k.height);if(g){k.width=h.minWidth}if(r){k.height=h.minHeight}if(s){k.width=h.maxWidth}if(l){k.height=h.maxHeight}var e=this.originalPosition.left+this.originalSize.width,n=this.position.top+this.size.height;var j=/sw|nw|w/.test(p),d=/nw|ne|n/.test(p);if(g&&j){k.left=e-h.minWidth}if(s&&j){k.left=e-h.maxWidth}if(r&&d){k.top=n-h.minHeight}if(l&&d){k.top=n-h.maxHeight}var m=!k.width&&!k.height;if(m&&!k.left&&k.top){k.top=null}else{if(m&&!k.top&&k.left){k.left=null}}return k},_proportionallyResize:function(){var j=this.options;if(!this._proportionallyResizeElements.length){return}var f=this.helper||this.element;for(var e=0;e');var d=c.browser.msie&&c.browser.version<7,f=(d?1:0),g=(d?2:-1);this.helper.addClass(this._helper).css({width:this.element.outerWidth()+g,height:this.element.outerHeight()+g,position:"absolute",left:this.elementOffset.left-f+"px",top:this.elementOffset.top-f+"px",zIndex:++h.zIndex});this.helper.appendTo("body").disableSelection()}else{this.helper=this.element}},_change:{e:function(f,e,d){return{width:this.originalSize.width+e}},w:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{left:h.left+e,width:f.width-e}},n:function(g,e,d){var i=this.options,f=this.originalSize,h=this.originalPosition;return{top:h.top+d,height:f.height-d}},s:function(f,e,d){return{height:this.originalSize.height+d}},se:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},sw:function(f,e,d){return c.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[f,e,d]))},ne:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[f,e,d]))},nw:function(f,e,d){return c.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[f,e,d]))}},_propagate:function(e,d){c.ui.plugin.call(this,e,[d,this.ui()]);(e!="resize"&&this._trigger(e,d,this.ui()))},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}));c.extend(c.ui.resizable,{version:"1.7.3",eventPrefix:"resize",defaults:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,cancel:":input,option",containment:false,delay:0,distance:1,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1000}});c.ui.plugin.add("resizable","alsoResize",{start:function(e,f){var d=c(this).data("resizable"),g=d.options;_store=function(h){c(h).each(function(){c(this).data("resizable-alsoresize",{width:parseInt(c(this).width(),10),height:parseInt(c(this).height(),10),left:parseInt(c(this).css("left"),10),top:parseInt(c(this).css("top"),10)})})};if(typeof(g.alsoResize)=="object"&&!g.alsoResize.parentNode){if(g.alsoResize.length){g.alsoResize=g.alsoResize[0];_store(g.alsoResize)}else{c.each(g.alsoResize,function(h,i){_store(h)})}}else{_store(g.alsoResize)}},resize:function(f,h){var e=c(this).data("resizable"),i=e.options,g=e.originalSize,k=e.originalPosition;var j={height:(e.size.height-g.height)||0,width:(e.size.width-g.width)||0,top:(e.position.top-k.top)||0,left:(e.position.left-k.left)||0},d=function(l,m){c(l).each(function(){var p=c(this),q=c(this).data("resizable-alsoresize"),o={},n=m&&m.length?m:["width","height","top","left"];c.each(n||["width","height","top","left"],function(r,u){var s=(q[u]||0)+(j[u]||0);if(s&&s>=0){o[u]=s||null}});if(/relative/.test(p.css("position"))&&c.browser.opera){e._revertToRelativePosition=true;p.css({position:"absolute",top:"auto",left:"auto"})}p.css(o)})};if(typeof(i.alsoResize)=="object"&&!i.alsoResize.nodeType){c.each(i.alsoResize,function(l,m){d(l,m)})}else{d(i.alsoResize)}},stop:function(e,f){var d=c(this).data("resizable");if(d._revertToRelativePosition&&c.browser.opera){d._revertToRelativePosition=false;el.css({position:"relative"})}c(this).removeData("resizable-alsoresize-start")}});c.ui.plugin.add("resizable","animate",{stop:function(h,m){var n=c(this).data("resizable"),i=n.options;var g=n._proportionallyResizeElements,d=g.length&&(/textarea/i).test(g[0].nodeName),e=d&&c.ui.hasScroll(g[0],"left")?0:n.sizeDiff.height,k=d?0:n.sizeDiff.width;var f={width:(n.size.width-k),height:(n.size.height-e)},j=(parseInt(n.element.css("left"),10)+(n.position.left-n.originalPosition.left))||null,l=(parseInt(n.element.css("top"),10)+(n.position.top-n.originalPosition.top))||null;n.element.animate(c.extend(f,l&&j?{top:l,left:j}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var o={width:parseInt(n.element.css("width"),10),height:parseInt(n.element.css("height"),10),top:parseInt(n.element.css("top"),10),left:parseInt(n.element.css("left"),10)};if(g&&g.length){c(g[0]).css({width:o.width,height:o.height})}n._updateCache(o);n._propagate("resize",h)}})}});c.ui.plugin.add("resizable","containment",{start:function(e,q){var s=c(this).data("resizable"),i=s.options,k=s.element;var f=i.containment,j=(f instanceof c)?f.get(0):(/parent/.test(f))?k.parent().get(0):f;if(!j){return}s.containerElement=c(j);if(/document/.test(f)||f==document){s.containerOffset={left:0,top:0};s.containerPosition={left:0,top:0};s.parentData={element:c(document),left:0,top:0,width:c(document).width(),height:c(document).height()||document.body.parentNode.scrollHeight}}else{var m=c(j),h=[];c(["Top","Right","Left","Bottom"]).each(function(p,o){h[p]=b(m.css("padding"+o))});s.containerOffset=m.offset();s.containerPosition=m.position();s.containerSize={height:(m.innerHeight()-h[3]),width:(m.innerWidth()-h[1])};var n=s.containerOffset,d=s.containerSize.height,l=s.containerSize.width,g=(c.ui.hasScroll(j,"left")?j.scrollWidth:l),r=(c.ui.hasScroll(j)?j.scrollHeight:d);s.parentData={element:j,left:n.left,top:n.top,width:g,height:r}}},resize:function(f,p){var s=c(this).data("resizable"),h=s.options,e=s.containerSize,n=s.containerOffset,l=s.size,m=s.position,q=s._aspectRatio||f.shiftKey,d={top:0,left:0},g=s.containerElement;if(g[0]!=document&&(/static/).test(g.css("position"))){d=n}if(m.left<(s._helper?n.left:0)){s.size.width=s.size.width+(s._helper?(s.position.left-n.left):(s.position.left-d.left));if(q){s.size.height=s.size.width/h.aspectRatio}s.position.left=h.helper?n.left:0}if(m.top<(s._helper?n.top:0)){s.size.height=s.size.height+(s._helper?(s.position.top-n.top):s.position.top);if(q){s.size.width=s.size.height*h.aspectRatio}s.position.top=s._helper?n.top:0}s.offset.left=s.parentData.left+s.position.left;s.offset.top=s.parentData.top+s.position.top;var k=Math.abs((s._helper?s.offset.left-d.left:(s.offset.left-d.left))+s.sizeDiff.width),r=Math.abs((s._helper?s.offset.top-d.top:(s.offset.top-n.top))+s.sizeDiff.height);var j=s.containerElement.get(0)==s.element.parent().get(0),i=/relative|absolute/.test(s.containerElement.css("position"));if(j&&i){k-=s.parentData.left}if(k+s.size.width>=s.parentData.width){s.size.width=s.parentData.width-k;if(q){s.size.height=s.size.width/s.aspectRatio}}if(r+s.size.height>=s.parentData.height){s.size.height=s.parentData.height-r;if(q){s.size.width=s.size.height*s.aspectRatio}}},stop:function(e,m){var p=c(this).data("resizable"),f=p.options,k=p.position,l=p.containerOffset,d=p.containerPosition,g=p.containerElement;var i=c(p.helper),q=i.offset(),n=i.outerWidth()-p.sizeDiff.width,j=i.outerHeight()-p.sizeDiff.height;if(p._helper&&!f.animate&&(/relative/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}if(p._helper&&!f.animate&&(/static/).test(g.css("position"))){c(this).css({left:q.left-d.left-l.left,width:n,height:j})}}});c.ui.plugin.add("resizable","ghost",{start:function(f,g){var d=c(this).data("resizable"),h=d.options,e=d.size;d.ghost=d.originalElement.clone();d.ghost.css({opacity:0.25,display:"block",position:"relative",height:e.height,width:e.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof h.ghost=="string"?h.ghost:"");d.ghost.appendTo(d.helper)},resize:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost){d.ghost.css({position:"relative",height:d.size.height,width:d.size.width})}},stop:function(e,f){var d=c(this).data("resizable"),g=d.options;if(d.ghost&&d.helper){d.helper.get(0).removeChild(d.ghost.get(0))}}});c.ui.plugin.add("resizable","grid",{resize:function(d,l){var n=c(this).data("resizable"),g=n.options,j=n.size,h=n.originalSize,i=n.originalPosition,m=n.axis,k=g._aspectRatio||d.shiftKey;g.grid=typeof g.grid=="number"?[g.grid,g.grid]:g.grid;var f=Math.round((j.width-h.width)/(g.grid[0]||1))*(g.grid[0]||1),e=Math.round((j.height-h.height)/(g.grid[1]||1))*(g.grid[1]||1);if(/^(se|s|e)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e}else{if(/^(ne)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e}else{if(/^(sw)$/.test(m)){n.size.width=h.width+f;n.size.height=h.height+e;n.position.left=i.left-f}else{n.size.width=h.width+f;n.size.height=h.height+e;n.position.top=i.top-e;n.position.left=i.left-f}}}}});var b=function(d){return parseInt(d,10)||0};var a=function(d){return !isNaN(parseInt(d,10))}})(jQuery);(function(a){a.widget("ui.selectable",a.extend({},a.ui.mouse,{_init:function(){var b=this;this.element.addClass("ui-selectable");this.dragged=false;var c;this.refresh=function(){c=a(b.options.filter,b.element[0]);c.each(function(){var d=a(this);var e=d.offset();a.data(this,"selectable-item",{element:this,$element:d,left:e.left,top:e.top,right:e.left+d.outerWidth(),bottom:e.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=c.addClass("ui-selectee");this._mouseInit();this.helper=a(document.createElement("div")).css({border:"1px dotted black"}).addClass("ui-selectable-helper")},destroy:function(){this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy()},_mouseStart:function(d){var b=this;this.opos=[d.pageX,d.pageY];if(this.options.disabled){return}var c=this.options;this.selectees=a(c.filter,this.element[0]);this._trigger("start",d);a(c.appendTo).append(this.helper);this.helper.css({"z-index":100,position:"absolute",left:d.clientX,top:d.clientY,width:0,height:0});if(c.autoRefresh){this.refresh()}this.selectees.filter(".ui-selected").each(function(){var e=a.data(this,"selectable-item");e.startselected=true;if(!d.metaKey){e.$element.removeClass("ui-selected");e.selected=false;e.$element.addClass("ui-unselecting");e.unselecting=true;b._trigger("unselecting",d,{unselecting:e.element})}});a(d.target).parents().andSelf().each(function(){var e=a.data(this,"selectable-item");if(e){e.$element.removeClass("ui-unselecting").addClass("ui-selecting");e.unselecting=false;e.selecting=true;e.selected=true;b._trigger("selecting",d,{selecting:e.element});return false}})},_mouseDrag:function(i){var c=this;this.dragged=true;if(this.options.disabled){return}var e=this.options;var d=this.opos[0],h=this.opos[1],b=i.pageX,g=i.pageY;if(d>b){var f=b;b=d;d=f}if(h>g){var f=g;g=h;h=f}this.helper.css({left:d,top:h,width:b-d,height:g-h});this.selectees.each(function(){var j=a.data(this,"selectable-item");if(!j||j.element==c.element[0]){return}var k=false;if(e.tolerance=="touch"){k=(!(j.left>b||j.rightg||j.bottomd&&j.righth&&j.bottom=0;b--){this.items[b].item.removeData("sortable-item")}},_mouseCapture:function(e,f){if(this.reverting){return false}if(this.options.disabled||this.options.type=="static"){return false}this._refreshItems(e);var d=null,c=this,b=a(e.target).parents().each(function(){if(a.data(this,"sortable-item")==c){d=a(this);return false}});if(a.data(e.target,"sortable-item")==c){d=a(e.target)}if(!d){return false}if(this.options.handle&&!f){var g=false;a(this.options.handle,d).find("*").andSelf().each(function(){if(this==e.target){g=true}});if(!g){return false}}this.currentItem=d;this._removeCurrentsFromItems();return true},_mouseStart:function(e,f,b){var g=this.options,c=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(e);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");a.extend(this.offset,{click:{left:e.pageX-this.offset.left,top:e.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(e);this.originalPageX=e.pageX;this.originalPageY=e.pageY;if(g.cursorAt){this._adjustOffsetFromHelper(g.cursorAt)}this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};if(this.helper[0]!=this.currentItem[0]){this.currentItem.hide()}this._createPlaceholder();if(g.containment){this._setContainment()}if(g.cursor){if(a("body").css("cursor")){this._storedCursor=a("body").css("cursor")}a("body").css("cursor",g.cursor)}if(g.opacity){if(this.helper.css("opacity")){this._storedOpacity=this.helper.css("opacity")}this.helper.css("opacity",g.opacity)}if(g.zIndex){if(this.helper.css("zIndex")){this._storedZIndex=this.helper.css("zIndex")}this.helper.css("zIndex",g.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){this.overflowOffset=this.scrollParent.offset()}this._trigger("start",e,this._uiHash());if(!this._preserveHelperProportions){this._cacheHelperProportions()}if(!b){for(var d=this.containers.length-1;d>=0;d--){this.containers[d]._trigger("activate",e,c._uiHash(this))}}if(a.ui.ddmanager){a.ui.ddmanager.current=this}if(a.ui.ddmanager&&!g.dropBehaviour){a.ui.ddmanager.prepareOffsets(this,e)}this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(e);return true},_mouseDrag:function(f){this.position=this._generatePosition(f);this.positionAbs=this._convertPositionTo("absolute");if(!this.lastPositionAbs){this.lastPositionAbs=this.positionAbs}if(this.options.scroll){var g=this.options,b=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if((this.overflowOffset.top+this.scrollParent[0].offsetHeight)-f.pageY=0;d--){var e=this.items[d],c=e.item[0],h=this._intersectsWithPointer(e);if(!h){continue}if(c!=this.currentItem[0]&&this.placeholder[h==1?"next":"prev"]()[0]!=c&&!a.ui.contains(this.placeholder[0],c)&&(this.options.type=="semi-dynamic"?!a.ui.contains(this.element[0],c):true)){this.direction=h==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(e)){this._rearrange(f,e)}else{break}this._trigger("change",f,this._uiHash());break}}this._contactContainers(f);if(a.ui.ddmanager){a.ui.ddmanager.drag(this,f)}this._trigger("sort",f,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(c,d){if(!c){return}if(a.ui.ddmanager&&!this.options.dropBehaviour){a.ui.ddmanager.drop(this,c)}if(this.options.revert){var b=this;var e=b.placeholder.offset();b.reverting=true;a(this.helper).animate({left:e.left-this.offset.parent.left-b.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:e.top-this.offset.parent.top-b.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){b._clear(c)})}else{this._clear(c,d)}return false},cancel:function(){var b=this;if(this.dragging){this._mouseUp();if(this.options.helper=="original"){this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else{this.currentItem.show()}for(var c=this.containers.length-1;c>=0;c--){this.containers[c]._trigger("deactivate",null,b._uiHash(this));if(this.containers[c].containerCache.over){this.containers[c]._trigger("out",null,b._uiHash(this));this.containers[c].containerCache.over=0}}}if(this.placeholder[0].parentNode){this.placeholder[0].parentNode.removeChild(this.placeholder[0])}if(this.options.helper!="original"&&this.helper&&this.helper[0].parentNode){this.helper.remove()}a.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});if(this.domPosition.prev){a(this.domPosition.prev).after(this.currentItem)}else{a(this.domPosition.parent).prepend(this.currentItem)}return true},serialize:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};a(b).each(function(){var e=(a(d.item||this).attr(d.attribute||"id")||"").match(d.expression||(/(.+)[-=_](.+)/));if(e){c.push((d.key||e[1]+"[]")+"="+(d.key&&d.expression?e[1]:e[2]))}});return c.join("&")},toArray:function(d){var b=this._getItemsAsjQuery(d&&d.connected);var c=[];d=d||{};b.each(function(){c.push(a(d.item||this).attr(d.attribute||"id")||"")});return c},_intersectsWith:function(m){var e=this.positionAbs.left,d=e+this.helperProportions.width,k=this.positionAbs.top,j=k+this.helperProportions.height;var f=m.left,c=f+m.width,n=m.top,i=n+m.height;var o=this.offset.click.top,h=this.offset.click.left;var g=(k+o)>n&&(k+o)f&&(e+h)m[this.floating?"width":"height"])){return g}else{return(f0?"down":"up")},_getDragHorizontalDirection:function(){var b=this.positionAbs.left-this.lastPositionAbs.left;return b!=0&&(b>0?"right":"left")},refresh:function(b){this._refreshItems(b);this.refreshPositions()},_connectWith:function(){var b=this.options;return b.connectWith.constructor==String?[b.connectWith]:b.connectWith},_getItemsAsjQuery:function(b){var l=this;var g=[];var e=[];var h=this._connectWith();if(h&&b){for(var d=h.length-1;d>=0;d--){var k=a(h[d]);for(var c=k.length-1;c>=0;c--){var f=a.data(k[c],"sortable");if(f&&f!=this&&!f.options.disabled){e.push([a.isFunction(f.options.items)?f.options.items.call(f.element):a(f.options.items,f.element).not(".ui-sortable-helper"),f])}}}}e.push([a.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):a(this.options.items,this.element).not(".ui-sortable-helper"),this]);for(var d=e.length-1;d>=0;d--){e[d][0].each(function(){g.push(this)})}return a(g)},_removeCurrentsFromItems:function(){var d=this.currentItem.find(":data(sortable-item)");for(var c=0;c=0;e--){var m=a(l[e]);for(var d=m.length-1;d>=0;d--){var g=a.data(m[d],"sortable");if(g&&g!=this&&!g.options.disabled){f.push([a.isFunction(g.options.items)?g.options.items.call(g.element[0],b,{item:this.currentItem}):a(g.options.items,g.element),g]);this.containers.push(g)}}}}for(var e=f.length-1;e>=0;e--){var k=f[e][1];var c=f[e][0];for(var d=0,n=c.length;d=0;d--){var e=this.items[d];if(e.instance!=this.currentContainer&&this.currentContainer&&e.item[0]!=this.currentItem[0]){continue}var c=this.options.toleranceElement?a(this.options.toleranceElement,e.item):e.item;if(!b){e.width=c.outerWidth();e.height=c.outerHeight()}var f=c.offset();e.left=f.left;e.top=f.top}if(this.options.custom&&this.options.custom.refreshContainers){this.options.custom.refreshContainers.call(this)}else{for(var d=this.containers.length-1;d>=0;d--){var f=this.containers[d].element.offset();this.containers[d].containerCache.left=f.left;this.containers[d].containerCache.top=f.top;this.containers[d].containerCache.width=this.containers[d].element.outerWidth();this.containers[d].containerCache.height=this.containers[d].element.outerHeight()}}},_createPlaceholder:function(d){var b=d||this,e=b.options;if(!e.placeholder||e.placeholder.constructor==String){var c=e.placeholder;e.placeholder={element:function(){var f=a(document.createElement(b.currentItem[0].nodeName)).addClass(c||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];if(!c){f.style.visibility="hidden"}return f},update:function(f,g){if(c&&!e.forcePlaceholderSize){return}if(!g.height()){g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10))}if(!g.width()){g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=a(e.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);e.placeholder.update(b,b.placeholder)},_contactContainers:function(d){for(var c=this.containers.length-1;c>=0;c--){if(this._intersectsWith(this.containers[c].containerCache)){if(!this.containers[c].containerCache.over){if(this.currentContainer!=this.containers[c]){var h=10000;var g=null;var e=this.positionAbs[this.containers[c].floating?"left":"top"];for(var b=this.items.length-1;b>=0;b--){if(!a.ui.contains(this.containers[c].element[0],this.items[b].item[0])){continue}var f=this.items[b][this.containers[c].floating?"left":"top"];if(Math.abs(f-e)this.containment[2]){d=this.containment[2]+this.offset.click.left}if(e.pageY-this.offset.click.top>this.containment[3]){c=this.containment[3]+this.offset.click.top}}if(h.grid){var g=this.originalPageY+Math.round((c-this.originalPageY)/h.grid[1])*h.grid[1];c=this.containment?(!(g-this.offset.click.topthis.containment[3])?g:(!(g-this.offset.click.topthis.containment[2])?f:(!(f-this.offset.click.left=0;c--){if(a.ui.contains(this.containers[c].element[0],this.currentItem[0])&&!e){f.push((function(g){return function(h){g._trigger("receive",h,this._uiHash(this))}}).call(this,this.containers[c]));f.push((function(g){return function(h){g._trigger("update",h,this._uiHash(this))}}).call(this,this.containers[c]))}}}for(var c=this.containers.length-1;c>=0;c--){if(!e){f.push((function(g){return function(h){g._trigger("deactivate",h,this._uiHash(this))}}).call(this,this.containers[c]))}if(this.containers[c].containerCache.over){f.push((function(g){return function(h){g._trigger("out",h,this._uiHash(this))}}).call(this,this.containers[c]));this.containers[c].containerCache.over=0}}if(this._storedCursor){a("body").css("cursor",this._storedCursor)}if(this._storedOpacity){this.helper.css("opacity",this._storedOpacity)}if(this._storedZIndex){this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex)}this.dragging=false;if(this.cancelHelperRemoval){if(!e){this._trigger("beforeStop",d,this._uiHash());for(var c=0;c *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1000}})})(jQuery);jQuery.effects||(function(d){d.effects={version:"1.7.3",save:function(g,h){for(var f=0;f');var j=f.parent();if(f.css("position")=="static"){j.css({position:"relative"});f.css({position:"relative"})}else{var i=f.css("top");if(isNaN(parseInt(i,10))){i="auto"}var h=f.css("left");if(isNaN(parseInt(h,10))){h="auto"}j.css({position:f.css("position"),top:i,left:h,zIndex:f.css("z-index")}).show();f.css({position:"relative",top:0,left:0})}j.css(g);return j},removeWrapper:function(f){if(f.parent().is(".ui-effects-wrapper")){return f.parent().replaceWith(f)}return f},setTransition:function(g,i,f,h){h=h||{};d.each(i,function(k,j){unit=g.cssUnit(j);if(unit[0]>0){h[j]=unit[0]*f+unit[1]}});return h},animateClass:function(h,i,k,j){var f=(typeof k=="function"?k:(j?j:null));var g=(typeof k=="string"?k:null);return this.each(function(){var q={};var o=d(this);var p=o.attr("style")||"";if(typeof p=="object"){p=p.cssText}if(h.toggle){o.hasClass(h.toggle)?h.remove=h.toggle:h.add=h.toggle}var l=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.addClass(h.add)}if(h.remove){o.removeClass(h.remove)}var m=d.extend({},(document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle));if(h.add){o.removeClass(h.add)}if(h.remove){o.addClass(h.remove)}for(var r in m){if(typeof m[r]!="function"&&m[r]&&r.indexOf("Moz")==-1&&r.indexOf("length")==-1&&m[r]!=l[r]&&(r.match(/color/i)||(!r.match(/color/i)&&!isNaN(parseInt(m[r],10))))&&(l.position!="static"||(l.position=="static"&&!r.match(/left|top|bottom|right/)))){q[r]=m[r]}}o.animate(q,i,g,function(){if(typeof d(this).attr("style")=="object"){d(this).attr("style")["cssText"]="";d(this).attr("style")["cssText"]=p}else{d(this).attr("style",p)}if(h.add){d(this).addClass(h.add)}if(h.remove){d(this).removeClass(h.remove)}if(f){f.apply(this,arguments)}})})}};function c(g,f){var i=g[1]&&g[1].constructor==Object?g[1]:{};if(f){i.mode=f}var h=g[1]&&g[1].constructor!=Object?g[1]:(i.duration?i.duration:g[2]);h=d.fx.off?0:typeof h==="number"?h:d.fx.speeds[h]||d.fx.speeds._default;var j=i.callback||(d.isFunction(g[1])&&g[1])||(d.isFunction(g[2])&&g[2])||(d.isFunction(g[3])&&g[3]);return[g[0],i,h,j]}d.fn.extend({_show:d.fn.show,_hide:d.fn.hide,__toggle:d.fn.toggle,_addClass:d.fn.addClass,_removeClass:d.fn.removeClass,_toggleClass:d.fn.toggleClass,effect:function(g,f,h,i){return d.effects[g]?d.effects[g].call(this,{method:g,options:f||{},duration:h,callback:i}):null},show:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._show.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"show"))}},hide:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))){return this._hide.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"hide"))}},toggle:function(){if(!arguments[0]||(arguments[0].constructor==Number||(/(slow|normal|fast)/).test(arguments[0]))||(d.isFunction(arguments[0])||typeof arguments[0]=="boolean")){return this.__toggle.apply(this,arguments)}else{return this.effect.apply(this,c(arguments,"toggle"))}},addClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{add:g},f,i,h]):this._addClass(g)},removeClass:function(g,f,i,h){return f?d.effects.animateClass.apply(this,[{remove:g},f,i,h]):this._removeClass(g)},toggleClass:function(g,f,i,h){return((typeof f!=="boolean")&&f)?d.effects.animateClass.apply(this,[{toggle:g},f,i,h]):this._toggleClass(g,f)},morph:function(f,h,g,j,i){return d.effects.animateClass.apply(this,[{add:h,remove:f},g,j,i])},switchClass:function(){return this.morph.apply(this,arguments)},cssUnit:function(f){var g=this.css(f),h=[];d.each(["em","px","%","pt"],function(j,k){if(g.indexOf(k)>0){h=[parseFloat(g),k]}});return h}});d.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor","borderTopColor","color","outlineColor"],function(g,f){d.fx.step[f]=function(h){if(h.state==0){h.start=e(h.elem,f);h.end=b(h.end)}h.elem.style[f]="rgb("+[Math.max(Math.min(parseInt((h.pos*(h.end[0]-h.start[0]))+h.start[0],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[1]-h.start[1]))+h.start[1],10),255),0),Math.max(Math.min(parseInt((h.pos*(h.end[2]-h.start[2]))+h.start[2],10),255),0)].join(",")+")"}});function b(g){var f;if(g&&g.constructor==Array&&g.length==3){return g}if(f=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(g)){return[parseInt(f[1],10),parseInt(f[2],10),parseInt(f[3],10)]}if(f=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(g)){return[parseFloat(f[1])*2.55,parseFloat(f[2])*2.55,parseFloat(f[3])*2.55]}if(f=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(g)){return[parseInt(f[1],16),parseInt(f[2],16),parseInt(f[3],16)]}if(f=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(g)){return[parseInt(f[1]+f[1],16),parseInt(f[2]+f[2],16),parseInt(f[3]+f[3],16)]}if(f=/rgba\(0, 0, 0, 0\)/.exec(g)){return a.transparent}return a[d.trim(g).toLowerCase()]}function e(h,f){var g;do{g=d.curCSS(h,f);if(g!=""&&g!="transparent"||d.nodeName(h,"body")){break}f="backgroundColor"}while(h=h.parentNode);return b(g)}var a={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]};d.easing.jswing=d.easing.swing;d.extend(d.easing,{def:"easeOutQuad",swing:function(g,h,f,j,i){return d.easing[d.easing.def](g,h,f,j,i)},easeInQuad:function(g,h,f,j,i){return j*(h/=i)*h+f},easeOutQuad:function(g,h,f,j,i){return -j*(h/=i)*(h-2)+f},easeInOutQuad:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h+f}return -j/2*((--h)*(h-2)-1)+f},easeInCubic:function(g,h,f,j,i){return j*(h/=i)*h*h+f},easeOutCubic:function(g,h,f,j,i){return j*((h=h/i-1)*h*h+1)+f},easeInOutCubic:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h+f}return j/2*((h-=2)*h*h+2)+f},easeInQuart:function(g,h,f,j,i){return j*(h/=i)*h*h*h+f},easeOutQuart:function(g,h,f,j,i){return -j*((h=h/i-1)*h*h*h-1)+f},easeInOutQuart:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h+f}return -j/2*((h-=2)*h*h*h-2)+f},easeInQuint:function(g,h,f,j,i){return j*(h/=i)*h*h*h*h+f},easeOutQuint:function(g,h,f,j,i){return j*((h=h/i-1)*h*h*h*h+1)+f},easeInOutQuint:function(g,h,f,j,i){if((h/=i/2)<1){return j/2*h*h*h*h*h+f}return j/2*((h-=2)*h*h*h*h+2)+f},easeInSine:function(g,h,f,j,i){return -j*Math.cos(h/i*(Math.PI/2))+j+f},easeOutSine:function(g,h,f,j,i){return j*Math.sin(h/i*(Math.PI/2))+f},easeInOutSine:function(g,h,f,j,i){return -j/2*(Math.cos(Math.PI*h/i)-1)+f},easeInExpo:function(g,h,f,j,i){return(h==0)?f:j*Math.pow(2,10*(h/i-1))+f},easeOutExpo:function(g,h,f,j,i){return(h==i)?f+j:j*(-Math.pow(2,-10*h/i)+1)+f},easeInOutExpo:function(g,h,f,j,i){if(h==0){return f}if(h==i){return f+j}if((h/=i/2)<1){return j/2*Math.pow(2,10*(h-1))+f}return j/2*(-Math.pow(2,-10*--h)+2)+f},easeInCirc:function(g,h,f,j,i){return -j*(Math.sqrt(1-(h/=i)*h)-1)+f},easeOutCirc:function(g,h,f,j,i){return j*Math.sqrt(1-(h=h/i-1)*h)+f},easeInOutCirc:function(g,h,f,j,i){if((h/=i/2)<1){return -j/2*(Math.sqrt(1-h*h)-1)+f}return j/2*(Math.sqrt(1-(h-=2)*h)+1)+f},easeInElastic:function(g,i,f,m,l){var j=1.70158;var k=0;var h=m;if(i==0){return f}if((i/=l)==1){return f+m}if(!k){k=l*0.3}if(h").css({position:"absolute",visibility:"visible",left:-d*(g/e),top:-f*(c/k)}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:g/e,height:c/k,left:l.left+d*(g/e)+(b.options.mode=="show"?(d-Math.floor(e/2))*(g/e):0),top:l.top+f*(c/k)+(b.options.mode=="show"?(f-Math.floor(k/2))*(c/k):0),opacity:b.options.mode=="show"?0:1}).animate({left:l.left+d*(g/e)+(b.options.mode=="show"?0:(d-Math.floor(e/2))*(g/e)),top:l.top+f*(c/k)+(b.options.mode=="show"?0:(f-Math.floor(k/2))*(c/k)),opacity:b.options.mode=="show"?1:0},b.duration||500)}}setTimeout(function(){b.options.mode=="show"?h.css({visibility:"visible"}):h.css({visibility:"visible"}).hide();if(b.callback){b.callback.apply(h[0])}h.dequeue();a("div.ui-effects-explode").remove()},b.duration||500)})}})(jQuery);(function(a){a.effects.fold=function(b){return this.queue(function(){var e=a(this),k=["position","top","left"];var h=a.effects.setMode(e,b.options.mode||"hide");var o=b.options.size||15;var n=!(!b.options.horizFirst);var g=b.duration?b.duration/2:a.fx.speeds._default/2;a.effects.save(e,k);e.show();var d=a.effects.createWrapper(e).css({overflow:"hidden"});var i=((h=="show")!=n);var f=i?["width","height"]:["height","width"];var c=i?[d.width(),d.height()]:[d.height(),d.width()];var j=/([0-9]+)%/.exec(o);if(j){o=parseInt(j[1],10)/100*c[h=="hide"?0:1]}if(h=="show"){d.css(n?{height:0,width:o}:{height:o,width:0})}var m={},l={};m[f[0]]=h=="show"?c[0]:o;l[f[1]]=h=="show"?c[1]:0;d.animate(m,g,b.options.easing).animate(l,g,b.options.easing,function(){if(h=="hide"){e.hide()}a.effects.restore(e,k);a.effects.removeWrapper(e);if(b.callback){b.callback.apply(e[0],arguments)}e.dequeue()})})}})(jQuery);(function(a){a.effects.highlight=function(b){return this.queue(function(){var e=a(this),d=["backgroundImage","backgroundColor","opacity"];var h=a.effects.setMode(e,b.options.mode||"show");var c=b.options.color||"#ffff99";var g=e.css("backgroundColor");a.effects.save(e,d);e.show();e.css({backgroundImage:"none",backgroundColor:c});var f={backgroundColor:g};if(h=="hide"){f.opacity=0}e.animate(f,{queue:false,duration:b.duration,easing:b.options.easing,complete:function(){if(h=="hide"){e.hide()}a.effects.restore(e,d);if(h=="show"&&a.browser.msie){this.style.removeAttribute("filter")}if(b.callback){b.callback.apply(this,arguments)}e.dequeue()}})})}})(jQuery);(function(a){a.effects.pulsate=function(b){return this.queue(function(){var d=a(this);var g=a.effects.setMode(d,b.options.mode||"show");var f=b.options.times||5;var e=b.duration?b.duration/2:a.fx.speeds._default/2;if(g=="hide"){f--}if(d.is(":hidden")){d.css("opacity",0);d.show();d.animate({opacity:1},e,b.options.easing);f=f-2}for(var c=0;c').appendTo(document.body).addClass(b.options.className).css({top:d.top,left:d.left,height:f.innerHeight(),width:f.innerWidth(),position:"absolute"}).animate(g,b.duration,b.options.easing,function(){c.remove();(b.callback&&b.callback.apply(f[0],arguments));f.dequeue()})})}})(jQuery);(function(a){a.widget("ui.accordion",{_init:function(){var d=this.options,b=this;this.running=0;if(d.collapsible==a.ui.accordion.defaults.collapsible&&d.alwaysOpen!=a.ui.accordion.defaults.alwaysOpen){d.collapsible=!d.alwaysOpen}if(d.navigation){var c=this.element.find("a").filter(d.navigationFilter);if(c.length){if(c.filter(d.header).length){this.active=c}else{this.active=c.parent().parent().prev();c.addClass("ui-accordion-content-active")}}}this.element.addClass("ui-accordion ui-widget ui-helper-reset");if(this.element[0].nodeName=="UL"){this.element.children("li").addClass("ui-accordion-li-fix")}this.headers=this.element.find(d.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){a(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){a(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){a(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){a(this).removeClass("ui-state-focus")});this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");this.active=this._findActive(this.active||d.active).toggleClass("ui-state-default").toggleClass("ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");this.active.next().addClass("ui-accordion-content-active");a("").addClass("ui-icon "+d.icons.header).prependTo(this.headers);this.active.find(".ui-icon").toggleClass(d.icons.header).toggleClass(d.icons.headerSelected);if(a.browser.msie){this.element.find("a").css("zoom","1")}this.resize();this.element.attr("role","tablist");this.headers.attr("role","tab").bind("keydown",function(e){return b._keydown(e)}).next().attr("role","tabpanel");this.headers.not(this.active||"").attr("aria-expanded","false").attr("tabIndex","-1").next().hide();if(!this.active.length){this.headers.eq(0).attr("tabIndex","0")}else{this.active.attr("aria-expanded","true").attr("tabIndex","0")}if(!a.browser.safari){this.headers.find("a").attr("tabIndex","-1")}if(d.event){this.headers.bind((d.event)+".accordion",function(e){return b._clickHandler.call(b,e,this)})}},destroy:function(){var c=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role").unbind(".accordion").removeData("accordion");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabindex");this.headers.find("a").removeAttr("tabindex");this.headers.children(".ui-icon").remove();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active");if(c.autoHeight||c.fillHeight){b.css("height","")}},_setData:function(b,c){if(b=="alwaysOpen"){b="collapsible";c=!c}a.widget.prototype._setData.apply(this,arguments)},_keydown:function(e){var g=this.options,f=a.ui.keyCode;if(g.disabled||e.altKey||e.ctrlKey){return}var d=this.headers.length;var b=this.headers.index(e.target);var c=false;switch(e.keyCode){case f.RIGHT:case f.DOWN:c=this.headers[(b+1)%d];break;case f.LEFT:case f.UP:c=this.headers[(b-1+d)%d];break;case f.SPACE:case f.ENTER:return this._clickHandler({target:e.target},e.target)}if(c){a(e.target).attr("tabIndex","-1");a(c).attr("tabIndex","0");c.focus();return false}return true},resize:function(){var e=this.options,d;if(e.fillSpace){if(a.browser.msie){var b=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}d=this.element.parent().height();if(a.browser.msie){this.element.parent().css("overflow",b)}this.headers.each(function(){d-=a(this).outerHeight()});var c=0;this.headers.next().each(function(){c=Math.max(c,a(this).innerHeight()-a(this).height())}).height(Math.max(0,d-c)).css("overflow","auto")}else{if(e.autoHeight){d=0;this.headers.next().each(function(){d=Math.max(d,a(this).outerHeight())}).height(d)}}},activate:function(b){var c=this._findActive(b)[0];this._clickHandler({target:c},c)},_findActive:function(b){return b?typeof b=="number"?this.headers.filter(":eq("+b+")"):this.headers.not(this.headers.not(b)):b===false?a([]):this.headers.filter(":eq(0)")},_clickHandler:function(b,f){var d=this.options;if(d.disabled){return false}if(!b.target&&d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var h=this.active.next(),e={options:d,newHeader:a([]),oldHeader:d.active,newContent:a([]),oldContent:h},c=(this.active=a([]));this._toggle(c,h,e);return false}var g=a(b.currentTarget||f);var i=g[0]==this.active[0];if(this.running||(!d.collapsible&&i)){return false}this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").find(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");if(!i){g.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").find(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);g.next().addClass("ui-accordion-content-active")}var c=g.next(),h=this.active.next(),e={options:d,newHeader:i&&d.collapsible?a([]):g,oldHeader:this.active,newContent:i&&d.collapsible?a([]):c.find("> *"),oldContent:h.find("> *")},j=this.headers.index(this.active[0])>this.headers.index(g[0]);this.active=i?a([]):g;this._toggle(c,h,e,i,j);return false},_toggle:function(b,i,g,j,k){var d=this.options,m=this;this.toShow=b;this.toHide=i;this.data=g;var c=function(){if(!m){return}return m._completed.apply(m,arguments)};this._trigger("changestart",null,this.data);this.running=i.size()===0?b.size():i.size();if(d.animated){var f={};if(d.collapsible&&j){f={toShow:a([]),toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}else{f={toShow:b,toHide:i,complete:c,down:k,autoHeight:d.autoHeight||d.fillSpace}}if(!d.proxied){d.proxied=d.animated}if(!d.proxiedDuration){d.proxiedDuration=d.duration}d.animated=a.isFunction(d.proxied)?d.proxied(f):d.proxied;d.duration=a.isFunction(d.proxiedDuration)?d.proxiedDuration(f):d.proxiedDuration;var l=a.ui.accordion.animations,e=d.duration,h=d.animated;if(!l[h]){l[h]=function(n){this.slide(n,{easing:h,duration:e||700})}}l[h](f)}else{if(d.collapsible&&j){b.toggle()}else{i.hide();b.show()}c(true)}i.prev().attr("aria-expanded","false").attr("tabIndex","-1").blur();b.prev().attr("aria-expanded","true").attr("tabIndex","0").focus()},_completed:function(b){var c=this.options;this.running=b?0:--this.running;if(this.running){return}if(c.clearStyle){this.toShow.add(this.toHide).css({height:"",overflow:""})}this._trigger("change",null,this.data)}});a.extend(a.ui.accordion,{version:"1.7.3",defaults:{active:null,alwaysOpen:true,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()==location.href.toLowerCase()}},animations:{slide:function(j,h){j=a.extend({easing:"swing",duration:300},j,h);if(!j.toHide.size()){j.toShow.animate({height:"show"},j);return}if(!j.toShow.size()){j.toHide.animate({height:"hide"},j);return}var c=j.toShow.css("overflow"),g,d={},f={},e=["height","paddingTop","paddingBottom"],b;var i=j.toShow;b=i[0].style.width;i.width(parseInt(i.parent().width(),10)-parseInt(i.css("paddingLeft"),10)-parseInt(i.css("paddingRight"),10)-(parseInt(i.css("borderLeftWidth"),10)||0)-(parseInt(i.css("borderRightWidth"),10)||0));a.each(e,function(k,m){f[m]="hide";var l=(""+a.css(j.toShow[0],m)).match(/^([\d+-.]+)(.*)$/);d[m]={value:l[1],unit:l[2]||"px"}});j.toShow.css({height:0,overflow:"hidden"}).show();j.toHide.filter(":hidden").each(j.complete).end().filter(":visible").animate(f,{step:function(k,l){if(l.prop=="height"){g=(l.now-l.start)/(l.end-l.start)}j.toShow[0].style[l.prop]=(g*d[l.prop].value)+d[l.prop].unit},duration:j.duration,easing:j.easing,complete:function(){if(!j.autoHeight){j.toShow.css("height","")}j.toShow.css("width",b);j.toShow.css({overflow:c});j.complete()}})},bounceslide:function(b){this.slide(b,{easing:b.down?"easeOutBounce":"swing",duration:b.down?1000:200})},easeslide:function(b){this.slide(b,{easing:"easeinout",duration:700})}}})})(jQuery);(function($){$.extend($.ui,{datepicker:{version:"1.7.3"}});var PROP_NAME="datepicker";function Datepicker(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._datepickerShowing=false;this._inDialog=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass="ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],dateFormat:"mm/dd/yy",firstDay:0,isRTL:false};this._defaults={showOn:"focus",showAnim:"show",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,showMonthAfterYear:false,yearRange:"-10:+10",showOtherMonths:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"normal",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false};$.extend(this._defaults,this.regional[""]);this.dpDiv=$('
    ')}$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",log:function(){if(this.debug){console.log.apply("",arguments)}},setDefaults:function(settings){extendRemove(this._defaults,settings||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase();var inline=(nodeName=="div"||nodeName=="span");if(!target.id){target.id="dp"+(++this.uuid)}var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{});if(nodeName=="input"){this._connectDatepicker(target,inst)}else{if(inline){this._inlineDatepicker(target,inst)}}},_newInst:function(target,inline){var id=target[0].id.replace(/([:\[\]\.])/g,"\\\\$1");return{id:id,input:target,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:inline,dpDiv:(!inline?this.dpDiv:$('
    '))}},_connectDatepicker:function(target,inst){var input=$(target);inst.append=$([]);inst.trigger=$([]);if(input.hasClass(this.markerClassName)){return}var appendText=this._get(inst,"appendText");var isRTL=this._get(inst,"isRTL");if(appendText){inst.append=$(''+appendText+"");input[isRTL?"before":"after"](inst.append)}var showOn=this._get(inst,"showOn");if(showOn=="focus"||showOn=="both"){input.focus(this._showDatepicker)}if(showOn=="button"||showOn=="both"){var buttonText=this._get(inst,"buttonText");var buttonImage=this._get(inst,"buttonImage");inst.trigger=$(this._get(inst,"buttonImageOnly")?$("").addClass(this._triggerClass).attr({src:buttonImage,alt:buttonText,title:buttonText}):$('').addClass(this._triggerClass).html(buttonImage==""?buttonText:$("").attr({src:buttonImage,alt:buttonText,title:buttonText})));input[isRTL?"before":"after"](inst.trigger);inst.trigger.click(function(){if($.datepicker._datepickerShowing&&$.datepicker._lastInput==target){$.datepicker._hideDatepicker()}else{$.datepicker._showDatepicker(target)}return false})}input.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst)},_inlineDatepicker:function(target,inst){var divSpan=$(target);if(divSpan.hasClass(this.markerClassName)){return}divSpan.addClass(this.markerClassName).append(inst.dpDiv).bind("setData.datepicker",function(event,key,value){inst.settings[key]=value}).bind("getData.datepicker",function(event,key){return this._get(inst,key)});$.data(target,PROP_NAME,inst);this._setDate(inst,this._getDefaultDate(inst));this._updateDatepicker(inst);this._updateAlternate(inst)},_dialogDatepicker:function(input,dateText,onSelect,settings,pos){var inst=this._dialogInst;if(!inst){var id="dp"+(++this.uuid);this._dialogInput=$('');this._dialogInput.keydown(this._doKeyDown);$("body").append(this._dialogInput);inst=this._dialogInst=this._newInst(this._dialogInput,false);inst.settings={};$.data(this._dialogInput[0],PROP_NAME,inst)}extendRemove(inst.settings,settings||{});this._dialogInput.val(dateText);this._pos=(pos?(pos.length?pos:[pos.pageX,pos.pageY]):null);if(!this._pos){var browserWidth=window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth;var browserHeight=window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight;var scrollX=document.documentElement.scrollLeft||document.body.scrollLeft;var scrollY=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[(browserWidth/2)-100+scrollX,(browserHeight/2)-150+scrollY]}this._dialogInput.css("left",this._pos[0]+"px").css("top",this._pos[1]+"px");inst.settings.onSelect=onSelect;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);this._showDatepicker(this._dialogInput[0]);if($.blockUI){$.blockUI(this.dpDiv)}$.data(this._dialogInput[0],PROP_NAME,inst);return this},_destroyDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();$.removeData(target,PROP_NAME);if(nodeName=="input"){inst.append.remove();inst.trigger.remove();$target.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress)}else{if(nodeName=="div"||nodeName=="span"){$target.removeClass(this.markerClassName).empty()}}},_enableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=false;inst.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().removeClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)})},_disableDatepicker:function(target){var $target=$(target);var inst=$.data(target,PROP_NAME);if(!$target.hasClass(this.markerClassName)){return}var nodeName=target.nodeName.toLowerCase();if(nodeName=="input"){target.disabled=true;inst.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else{if(nodeName=="div"||nodeName=="span"){var inline=$target.children("."+this._inlineClass);inline.children().addClass("ui-state-disabled")}}this._disabledInputs=$.map(this._disabledInputs,function(value){return(value==target?null:value)});this._disabledInputs[this._disabledInputs.length]=target},_isDisabledDatepicker:function(target){if(!target){return false}for(var i=0;i-1)}},_showDatepicker:function(input){input=input.target||input;if(input.nodeName.toLowerCase()!="input"){input=$("input",input.parentNode)[0]}if($.datepicker._isDisabledDatepicker(input)||$.datepicker._lastInput==input){return}var inst=$.datepicker._getInst(input);var beforeShow=$.datepicker._get(inst,"beforeShow");extendRemove(inst.settings,(beforeShow?beforeShow.apply(input,[input,inst]):{}));$.datepicker._hideDatepicker(null,"");$.datepicker._lastInput=input;$.datepicker._setDateFromField(inst);if($.datepicker._inDialog){input.value=""}if(!$.datepicker._pos){$.datepicker._pos=$.datepicker._findPos(input);$.datepicker._pos[1]+=input.offsetHeight}var isFixed=false;$(input).parents().each(function(){isFixed|=$(this).css("position")=="fixed";return !isFixed});if(isFixed&&$.browser.opera){$.datepicker._pos[0]-=document.documentElement.scrollLeft;$.datepicker._pos[1]-=document.documentElement.scrollTop}var offset={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null;inst.rangeStart=null;inst.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});$.datepicker._updateDatepicker(inst);offset=$.datepicker._checkOffset(inst,offset,isFixed);inst.dpDiv.css({position:($.datepicker._inDialog&&$.blockUI?"static":(isFixed?"fixed":"absolute")),display:"none",left:offset.left+"px",top:offset.top+"px"});if(!inst.inline){var showAnim=$.datepicker._get(inst,"showAnim")||"show";var duration=$.datepicker._get(inst,"duration");var postProcess=function(){$.datepicker._datepickerShowing=true;if($.browser.msie&&parseInt($.browser.version,10)<7){$("iframe.ui-datepicker-cover").css({width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4})}};if($.effects&&$.effects[showAnim]){inst.dpDiv.show(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[showAnim](duration,postProcess)}if(duration==""){postProcess()}if(inst.input[0].type!="hidden"){inst.input[0].focus()}$.datepicker._curInst=inst}},_updateDatepicker:function(inst){var dims={width:inst.dpDiv.width()+4,height:inst.dpDiv.height()+4};var self=this;inst.dpDiv.empty().append(this._generateHTML(inst)).find("iframe.ui-datepicker-cover").css({width:dims.width,height:dims.height}).end().find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",function(){$(this).removeClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).removeClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).removeClass("ui-datepicker-next-hover")}}).bind("mouseover",function(){if(!self._isDisabledDatepicker(inst.inline?inst.dpDiv.parent()[0]:inst.input[0])){$(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");$(this).addClass("ui-state-hover");if(this.className.indexOf("ui-datepicker-prev")!=-1){$(this).addClass("ui-datepicker-prev-hover")}if(this.className.indexOf("ui-datepicker-next")!=-1){$(this).addClass("ui-datepicker-next-hover")}}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();var numMonths=this._getNumberOfMonths(inst);var cols=numMonths[1];var width=17;if(cols>1){inst.dpDiv.addClass("ui-datepicker-multi-"+cols).css("width",(width*cols)+"em")}else{inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("")}inst.dpDiv[(numMonths[0]!=1||numMonths[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");inst.dpDiv[(this._get(inst,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");if(inst.input&&inst.input[0].type!="hidden"&&inst==$.datepicker._curInst){$(inst.input[0]).focus()}},_checkOffset:function(inst,offset,isFixed){var dpWidth=inst.dpDiv.outerWidth();var dpHeight=inst.dpDiv.outerHeight();var inputWidth=inst.input?inst.input.outerWidth():0;var inputHeight=inst.input?inst.input.outerHeight():0;var viewWidth=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)+$(document).scrollLeft();var viewHeight=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)+$(document).scrollTop();offset.left-=(this._get(inst,"isRTL")?(dpWidth-inputWidth):0);offset.left-=(isFixed&&offset.left==inst.input.offset().left)?$(document).scrollLeft():0;offset.top-=(isFixed&&offset.top==(inst.input.offset().top+inputHeight))?$(document).scrollTop():0;offset.left-=(offset.left+dpWidth>viewWidth&&viewWidth>dpWidth)?Math.abs(offset.left+dpWidth-viewWidth):0;offset.top-=(offset.top+dpHeight>viewHeight&&viewHeight>dpHeight)?Math.abs(offset.top+dpHeight+inputHeight*2-viewHeight):0;return offset},_findPos:function(obj){while(obj&&(obj.type=="hidden"||obj.nodeType!=1)){obj=obj.nextSibling}var position=$(obj).offset();return[position.left,position.top]},_hideDatepicker:function(input,duration){var inst=this._curInst;if(!inst||(input&&inst!=$.data(input,PROP_NAME))){return}if(inst.stayOpen){this._selectDate("#"+inst.id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear))}inst.stayOpen=false;if(this._datepickerShowing){duration=(duration!=null?duration:this._get(inst,"duration"));var showAnim=this._get(inst,"showAnim");var postProcess=function(){$.datepicker._tidyDialog(inst)};if(duration!=""&&$.effects&&$.effects[showAnim]){inst.dpDiv.hide(showAnim,$.datepicker._get(inst,"showOptions"),duration,postProcess)}else{inst.dpDiv[(duration==""?"hide":(showAnim=="slideDown"?"slideUp":(showAnim=="fadeIn"?"fadeOut":"hide")))](duration,postProcess)}if(duration==""){this._tidyDialog(inst)}var onClose=this._get(inst,"onClose");if(onClose){onClose.apply((inst.input?inst.input[0]:null),[(inst.input?inst.input.val():""),inst])}this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if($.blockUI){$.unblockUI();$("body").append(this.dpDiv)}}this._inDialog=false}this._curInst=null},_tidyDialog:function(inst){inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(event){if(!$.datepicker._curInst){return}var $target=$(event.target);if(($target.parents("#"+$.datepicker._mainDivId).length==0)&&!$target.hasClass($.datepicker.markerClassName)&&!$target.hasClass($.datepicker._triggerClass)&&$.datepicker._datepickerShowing&&!($.datepicker._inDialog&&$.blockUI)){$.datepicker._hideDatepicker(null,"")}},_adjustDate:function(id,offset,period){var target=$(id);var inst=this._getInst(target[0]);if(this._isDisabledDatepicker(target[0])){return}this._adjustInstDate(inst,offset+(period=="M"?this._get(inst,"showCurrentAtPos"):0),period);this._updateDatepicker(inst)},_gotoToday:function(id){var target=$(id);var inst=this._getInst(target[0]);if(this._get(inst,"gotoCurrent")&&inst.currentDay){inst.selectedDay=inst.currentDay;inst.drawMonth=inst.selectedMonth=inst.currentMonth;inst.drawYear=inst.selectedYear=inst.currentYear}else{var date=new Date();inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear()}this._notifyChange(inst);this._adjustDate(target)},_selectMonthYear:function(id,select,period){var target=$(id);var inst=this._getInst(target[0]);inst._selectingMonthYear=false;inst["selected"+(period=="M"?"Month":"Year")]=inst["draw"+(period=="M"?"Month":"Year")]=parseInt(select.options[select.selectedIndex].value,10);this._notifyChange(inst);this._adjustDate(target)},_clickMonthYear:function(id){var target=$(id);var inst=this._getInst(target[0]);if(inst.input&&inst._selectingMonthYear&&!$.browser.msie){inst.input[0].focus()}inst._selectingMonthYear=!inst._selectingMonthYear},_selectDay:function(id,month,year,td){var target=$(id);if($(td).hasClass(this._unselectableClass)||this._isDisabledDatepicker(target[0])){return}var inst=this._getInst(target[0]);inst.selectedDay=inst.currentDay=$("a",td).html();inst.selectedMonth=inst.currentMonth=month;inst.selectedYear=inst.currentYear=year;if(inst.stayOpen){inst.endDay=inst.endMonth=inst.endYear=null}this._selectDate(id,this._formatDate(inst,inst.currentDay,inst.currentMonth,inst.currentYear));if(inst.stayOpen){inst.rangeStart=this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay));this._updateDatepicker(inst)}},_clearDate:function(id){var target=$(id);var inst=this._getInst(target[0]);inst.stayOpen=false;inst.endDay=inst.endMonth=inst.endYear=inst.rangeStart=null;this._selectDate(target,"")},_selectDate:function(id,dateStr){var target=$(id);var inst=this._getInst(target[0]);dateStr=(dateStr!=null?dateStr:this._formatDate(inst));if(inst.input){inst.input.val(dateStr)}this._updateAlternate(inst);var onSelect=this._get(inst,"onSelect");if(onSelect){onSelect.apply((inst.input?inst.input[0]:null),[dateStr,inst])}else{if(inst.input){inst.input.trigger("change")}}if(inst.inline){this._updateDatepicker(inst)}else{if(!inst.stayOpen){this._hideDatepicker(null,this._get(inst,"duration"));this._lastInput=inst.input[0];if(typeof(inst.input[0])!="object"){inst.input[0].focus()}this._lastInput=null}}},_updateAlternate:function(inst){var altField=this._get(inst,"altField");if(altField){var altFormat=this._get(inst,"altFormat")||this._get(inst,"dateFormat");var date=this._getDate(inst);dateStr=this.formatDate(altFormat,date,this._getFormatConfig(inst));$(altField).each(function(){$(this).val(dateStr)})}},noWeekends:function(date){var day=date.getDay();return[(day>0&&day<6),""]},iso8601Week:function(date){var checkDate=new Date(date.getFullYear(),date.getMonth(),date.getDate());var firstMon=new Date(checkDate.getFullYear(),1-1,4);var firstDay=firstMon.getDay()||7;firstMon.setDate(firstMon.getDate()+1-firstDay);if(firstDay<4&&checkDatenew Date(checkDate.getFullYear(),12-1,28)){firstDay=new Date(checkDate.getFullYear()+1,1-1,4).getDay()||7;if(firstDay>4&&(checkDate.getDay()||7)0&&iValue="0"&&value.charAt(iValue)<="9"){num=num*10+parseInt(value.charAt(iValue++),10);size--}if(size==origSize){throw"Missing number at position "+iValue}return num};var getName=function(match,shortNames,longNames){var names=(lookAhead(match)?longNames:shortNames);var size=0;for(var j=0;j0&&iValue-1){month=1;day=doy;do{var dim=this._getDaysInMonth(year,month-1);if(day<=dim){break}month++;day-=dim}while(true)}var date=this._daylightSavingAdjust(new Date(year,month-1,day));if(date.getFullYear()!=year||date.getMonth()+1!=month||date.getDate()!=day){throw"Invalid date"}return date},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TIMESTAMP:"@",W3C:"yy-mm-dd",formatDate:function(format,date,settings){if(!date){return""}var dayNamesShort=(settings?settings.dayNamesShort:null)||this._defaults.dayNamesShort;var dayNames=(settings?settings.dayNames:null)||this._defaults.dayNames;var monthNamesShort=(settings?settings.monthNamesShort:null)||this._defaults.monthNamesShort;var monthNames=(settings?settings.monthNames:null)||this._defaults.monthNames;var lookAhead=function(match){var matches=(iFormat+1=0;m--){doy+=this._getDaysInMonth(date.getFullYear(),m)}output+=formatNumber("o",doy,3);break;case"m":output+=formatNumber("m",date.getMonth()+1,2);break;case"M":output+=formatName("M",date.getMonth(),monthNamesShort,monthNames);break;case"y":output+=(lookAhead("y")?date.getFullYear():(date.getYear()%100<10?"0":"")+date.getYear()%100);break;case"@":output+=date.getTime();break;case"'":if(lookAhead("'")){output+="'"}else{literal=true}break;default:output+=format.charAt(iFormat)}}}}return output},_possibleChars:function(format){var chars="";var literal=false;for(var iFormat=0;iFormatmaxDate?maxDate:date);return date},_determineDate:function(date,defaultDate){var offsetNumeric=function(offset){var date=new Date();date.setDate(date.getDate()+offset);return date};var offsetString=function(offset,getDaysInMonth){var date=new Date();var year=date.getFullYear();var month=date.getMonth();var day=date.getDate();var pattern=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g;var matches=pattern.exec(offset);while(matches){switch(matches[2]||"d"){case"d":case"D":day+=parseInt(matches[1],10);break;case"w":case"W":day+=parseInt(matches[1],10)*7;break;case"m":case"M":month+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break;case"y":case"Y":year+=parseInt(matches[1],10);day=Math.min(day,getDaysInMonth(year,month));break}matches=pattern.exec(offset)}return new Date(year,month,day)};date=(date==null?defaultDate:(typeof date=="string"?offsetString(date,this._getDaysInMonth):(typeof date=="number"?(isNaN(date)?defaultDate:offsetNumeric(date)):date)));date=(date&&date.toString()=="Invalid Date"?defaultDate:date);if(date){date.setHours(0);date.setMinutes(0);date.setSeconds(0);date.setMilliseconds(0)}return this._daylightSavingAdjust(date)},_daylightSavingAdjust:function(date){if(!date){return null}date.setHours(date.getHours()>12?date.getHours()+2:0);return date},_setDate:function(inst,date,endDate){var clear=!(date);var origMonth=inst.selectedMonth;var origYear=inst.selectedYear;date=this._determineDate(date,new Date());inst.selectedDay=inst.currentDay=date.getDate();inst.drawMonth=inst.selectedMonth=inst.currentMonth=date.getMonth();inst.drawYear=inst.selectedYear=inst.currentYear=date.getFullYear();if(origMonth!=inst.selectedMonth||origYear!=inst.selectedYear){this._notifyChange(inst)}this._adjustInstDate(inst);if(inst.input){inst.input.val(clear?"":this._formatDate(inst))}},_getDate:function(inst){var startDate=(!inst.currentYear||(inst.input&&inst.input.val()=="")?null:this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return startDate},_generateHTML:function(inst){var today=new Date();today=this._daylightSavingAdjust(new Date(today.getFullYear(),today.getMonth(),today.getDate()));var isRTL=this._get(inst,"isRTL");var showButtonPanel=this._get(inst,"showButtonPanel");var hideIfNoPrevNext=this._get(inst,"hideIfNoPrevNext");var navigationAsDateFormat=this._get(inst,"navigationAsDateFormat");var numMonths=this._getNumberOfMonths(inst);var showCurrentAtPos=this._get(inst,"showCurrentAtPos");var stepMonths=this._get(inst,"stepMonths");var stepBigMonths=this._get(inst,"stepBigMonths");var isMultiMonth=(numMonths[0]!=1||numMonths[1]!=1);var currentDate=this._daylightSavingAdjust((!inst.currentDay?new Date(9999,9,9):new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");var drawMonth=inst.drawMonth-showCurrentAtPos;var drawYear=inst.drawYear;if(drawMonth<0){drawMonth+=12;drawYear--}if(maxDate){var maxDraw=this._daylightSavingAdjust(new Date(maxDate.getFullYear(),maxDate.getMonth()-numMonths[1]+1,maxDate.getDate()));maxDraw=(minDate&&maxDrawmaxDraw){drawMonth--;if(drawMonth<0){drawMonth=11;drawYear--}}}inst.drawMonth=drawMonth;inst.drawYear=drawYear;var prevText=this._get(inst,"prevText");prevText=(!navigationAsDateFormat?prevText:this.formatDate(prevText,this._daylightSavingAdjust(new Date(drawYear,drawMonth-stepMonths,1)),this._getFormatConfig(inst)));var prev=(this._canAdjustMonth(inst,-1,drawYear,drawMonth)?''+prevText+"":(hideIfNoPrevNext?"":''+prevText+""));var nextText=this._get(inst,"nextText");nextText=(!navigationAsDateFormat?nextText:this.formatDate(nextText,this._daylightSavingAdjust(new Date(drawYear,drawMonth+stepMonths,1)),this._getFormatConfig(inst)));var next=(this._canAdjustMonth(inst,+1,drawYear,drawMonth)?''+nextText+"":(hideIfNoPrevNext?"":''+nextText+""));var currentText=this._get(inst,"currentText");var gotoDate=(this._get(inst,"gotoCurrent")&&inst.currentDay?currentDate:today);currentText=(!navigationAsDateFormat?currentText:this.formatDate(currentText,gotoDate,this._getFormatConfig(inst)));var controls=(!inst.inline?'":"");var buttonPanel=(showButtonPanel)?'
    '+(isRTL?controls:"")+(this._isInRange(inst,gotoDate)?'":"")+(isRTL?"":controls)+"
    ":"";var firstDay=parseInt(this._get(inst,"firstDay"),10);firstDay=(isNaN(firstDay)?0:firstDay);var dayNames=this._get(inst,"dayNames");var dayNamesShort=this._get(inst,"dayNamesShort");var dayNamesMin=this._get(inst,"dayNamesMin");var monthNames=this._get(inst,"monthNames");var monthNamesShort=this._get(inst,"monthNamesShort");var beforeShowDay=this._get(inst,"beforeShowDay");var showOtherMonths=this._get(inst,"showOtherMonths");var calculateWeek=this._get(inst,"calculateWeek")||this.iso8601Week;var endDate=inst.endDay?this._daylightSavingAdjust(new Date(inst.endYear,inst.endMonth,inst.endDay)):currentDate;var defaultDate=this._getDefaultDate(inst);var html="";for(var row=0;row'+(/all|left/.test(cornerClass)&&row==0?(isRTL?next:prev):"")+(/all|right/.test(cornerClass)&&row==0?(isRTL?prev:next):"")+this._generateMonthYearHeader(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,row>0||col>0,monthNames,monthNamesShort)+'
    ';var thead="";for(var dow=0;dow<7;dow++){var day=(dow+firstDay)%7;thead+="=5?' class="ui-datepicker-week-end"':"")+'>'+dayNamesMin[day]+""}calender+=thead+"";var daysInMonth=this._getDaysInMonth(drawYear,drawMonth);if(drawYear==inst.selectedYear&&drawMonth==inst.selectedMonth){inst.selectedDay=Math.min(inst.selectedDay,daysInMonth)}var leadDays=(this._getFirstDayOfMonth(drawYear,drawMonth)-firstDay+7)%7;var numRows=(isMultiMonth?6:Math.ceil((leadDays+daysInMonth)/7));var printDate=this._daylightSavingAdjust(new Date(drawYear,drawMonth,1-leadDays));for(var dRow=0;dRow";var tbody="";for(var dow=0;dow<7;dow++){var daySettings=(beforeShowDay?beforeShowDay.apply((inst.input?inst.input[0]:null),[printDate]):[true,""]);var otherMonth=(printDate.getMonth()!=drawMonth);var unselectable=otherMonth||!daySettings[0]||(minDate&&printDatemaxDate);tbody+='";printDate.setDate(printDate.getDate()+1);printDate=this._daylightSavingAdjust(printDate)}calender+=tbody+""}drawMonth++;if(drawMonth>11){drawMonth=0;drawYear++}calender+="
    =currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" "+this._currentClass:"")+(printDate.getTime()==today.getTime()?" ui-datepicker-today":""))+'"'+((!otherMonth||showOtherMonths)&&daySettings[2]?' title="'+daySettings[2]+'"':"")+(unselectable?"":" onclick=\"DP_jQuery.datepicker._selectDay('#"+inst.id+"',"+drawMonth+","+drawYear+', this);return false;"')+">"+(otherMonth?(showOtherMonths?printDate.getDate():" "):(unselectable?''+printDate.getDate()+"":'=currentDate.getTime()&&printDate.getTime()<=endDate.getTime()?" ui-state-active":"")+'" href="#">'+printDate.getDate()+""))+"
    "+(isMultiMonth?""+((numMonths[0]>0&&col==numMonths[1]-1)?'
    ':""):"");group+=calender}html+=group}html+=buttonPanel+($.browser.msie&&parseInt($.browser.version,10)<7&&!inst.inline?'':"");inst._keyEvent=false;return html},_generateMonthYearHeader:function(inst,drawMonth,drawYear,minDate,maxDate,selectedDate,secondary,monthNames,monthNamesShort){minDate=(inst.rangeStart&&minDate&&selectedDate "}else{var inMinYear=(minDate&&minDate.getFullYear()==drawYear);var inMaxYear=(maxDate&&maxDate.getFullYear()==drawYear);monthHtml+='"}if(!showMonthAfterYear){html+=monthHtml+((secondary||changeMonth||changeYear)&&(!(changeMonth&&changeYear))?" ":"")}if(secondary||!changeYear){html+=''+drawYear+""}else{var years=this._get(inst,"yearRange").split(":");var year=0;var endYear=0;if(years.length!=2){year=drawYear-10;endYear=drawYear+10}else{if(years[0].charAt(0)=="+"||years[0].charAt(0)=="-"){year=drawYear+parseInt(years[0],10);endYear=drawYear+parseInt(years[1],10)}else{year=parseInt(years[0],10);endYear=parseInt(years[1],10)}}year=(minDate?Math.max(year,minDate.getFullYear()):year);endYear=(maxDate?Math.min(endYear,maxDate.getFullYear()):endYear);html+='"}if(showMonthAfterYear){html+=(secondary||changeMonth||changeYear?" ":"")+monthHtml}html+="";return html},_adjustInstDate:function(inst,offset,period){var year=inst.drawYear+(period=="Y"?offset:0);var month=inst.drawMonth+(period=="M"?offset:0);var day=Math.min(inst.selectedDay,this._getDaysInMonth(year,month))+(period=="D"?offset:0);var date=this._daylightSavingAdjust(new Date(year,month,day));var minDate=this._getMinMaxDate(inst,"min",true);var maxDate=this._getMinMaxDate(inst,"max");date=(minDate&&datemaxDate?maxDate:date);inst.selectedDay=date.getDate();inst.drawMonth=inst.selectedMonth=date.getMonth();inst.drawYear=inst.selectedYear=date.getFullYear();if(period=="M"||period=="Y"){this._notifyChange(inst)}},_notifyChange:function(inst){var onChange=this._get(inst,"onChangeMonthYear");if(onChange){onChange.apply((inst.input?inst.input[0]:null),[inst.selectedYear,inst.selectedMonth+1,inst])}},_getNumberOfMonths:function(inst){var numMonths=this._get(inst,"numberOfMonths");return(numMonths==null?[1,1]:(typeof numMonths=="number"?[1,numMonths]:numMonths))},_getMinMaxDate:function(inst,minMax,checkRange){var date=this._determineDate(this._get(inst,minMax+"Date"),null);return(!checkRange||!inst.rangeStart?date:(!date||inst.rangeStart>date?inst.rangeStart:date))},_getDaysInMonth:function(year,month){return 32-new Date(year,month,32).getDate()},_getFirstDayOfMonth:function(year,month){return new Date(year,month,1).getDay()},_canAdjustMonth:function(inst,offset,curYear,curMonth){var numMonths=this._getNumberOfMonths(inst);var date=this._daylightSavingAdjust(new Date(curYear,curMonth+(offset<0?offset:numMonths[1]),1));if(offset<0){date.setDate(this._getDaysInMonth(date.getFullYear(),date.getMonth()))}return this._isInRange(inst,date)},_isInRange:function(inst,date){var newMinDate=(!inst.rangeStart?null:this._daylightSavingAdjust(new Date(inst.selectedYear,inst.selectedMonth,inst.selectedDay)));newMinDate=(newMinDate&&inst.rangeStart=minDate)&&(!maxDate||date<=maxDate))},_getFormatConfig:function(inst){var shortYearCutoff=this._get(inst,"shortYearCutoff");shortYearCutoff=(typeof shortYearCutoff!="string"?shortYearCutoff:new Date().getFullYear()%100+parseInt(shortYearCutoff,10));return{shortYearCutoff:shortYearCutoff,dayNamesShort:this._get(inst,"dayNamesShort"),dayNames:this._get(inst,"dayNames"),monthNamesShort:this._get(inst,"monthNamesShort"),monthNames:this._get(inst,"monthNames")}},_formatDate:function(inst,day,month,year){if(!day){inst.currentDay=inst.selectedDay;inst.currentMonth=inst.selectedMonth;inst.currentYear=inst.selectedYear}var date=(day?(typeof day=="object"?day:this._daylightSavingAdjust(new Date(year,month,day))):this._daylightSavingAdjust(new Date(inst.currentYear,inst.currentMonth,inst.currentDay)));return this.formatDate(this._get(inst,"dateFormat"),date,this._getFormatConfig(inst))}});function extendRemove(target,props){$.extend(target,props);for(var name in props){if(props[name]==null||props[name]==undefined){target[name]=props[name]}}return target}function isArray(a){return(a&&(($.browser.safari&&typeof a=="object"&&a.length)||(a.constructor&&a.constructor.toString().match(/\Array\(\)/))))}$.fn.datepicker=function(options){if(!$.datepicker.initialized){$(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv);$.datepicker.initialized=true}var otherArgs=Array.prototype.slice.call(arguments,1);if(typeof options=="string"&&(options=="isDisabled"||options=="getDate")){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}if(options=="option"&&arguments.length==2&&typeof arguments[1]=="string"){return $.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this[0]].concat(otherArgs))}return this.each(function(){typeof options=="string"?$.datepicker["_"+options+"Datepicker"].apply($.datepicker,[this].concat(otherArgs)):$.datepicker._attachDatepicker(this,options)})};$.datepicker=new Datepicker();$.datepicker.initialized=false;$.datepicker.uuid=new Date().getTime();$.datepicker.version="1.7.3";window.DP_jQuery=$})(jQuery);(function(c){var b={dragStart:"start.draggable",drag:"drag.draggable",dragStop:"stop.draggable",maxHeight:"maxHeight.resizable",minHeight:"minHeight.resizable",maxWidth:"maxWidth.resizable",minWidth:"minWidth.resizable",resizeStart:"start.resizable",resize:"drag.resizable",resizeStop:"stop.resizable"},a="ui-dialog ui-widget ui-widget-content ui-corner-all ";c.widget("ui.dialog",{_init:function(){this.originalTitle=this.element.attr("title");var l=this,m=this.options,j=m.title||this.originalTitle||" ",e=c.ui.dialog.getTitleId(this.element),k=(this.uiDialog=c("
    ")).appendTo(document.body).hide().addClass(a+m.dialogClass).css({position:"absolute",overflow:"hidden",zIndex:m.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(n){(m.closeOnEscape&&n.keyCode&&n.keyCode==c.ui.keyCode.ESCAPE&&l.close(n))}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(n){l.moveToTop(false,n)}),g=this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(k),f=(this.uiDialogTitlebar=c("
    ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(k),i=c('').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){i.addClass("ui-state-hover")},function(){i.removeClass("ui-state-hover")}).focus(function(){i.addClass("ui-state-focus")}).blur(function(){i.removeClass("ui-state-focus")}).mousedown(function(n){n.stopPropagation()}).click(function(n){l.close(n);return false}).appendTo(f),h=(this.uiDialogTitlebarCloseText=c("")).addClass("ui-icon ui-icon-closethick").text(m.closeText).appendTo(i),d=c("").addClass("ui-dialog-title").attr("id",e).html(j).prependTo(f);f.find("*").add(f).disableSelection();(m.draggable&&c.fn.draggable&&this._makeDraggable());(m.resizable&&c.fn.resizable&&this._makeResizable());this._createButtons(m.buttons);this._isOpen=false;(m.bgiframe&&c.fn.bgiframe&&k.bgiframe());(m.autoOpen&&this.open())},destroy:function(){(this.overlay&&this.overlay.destroy());this.uiDialog.hide();this.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");this.uiDialog.remove();(this.originalTitle&&this.element.attr("title",this.originalTitle))},close:function(f){var d=this;if(false===d._trigger("beforeclose",f)){return}(d.overlay&&d.overlay.destroy());d.uiDialog.unbind("keypress.ui-dialog");(d.options.hide?d.uiDialog.hide(d.options.hide,function(){d._trigger("close",f)}):d.uiDialog.hide()&&d._trigger("close",f));c.ui.dialog.overlay.resize();d._isOpen=false;if(d.options.modal){var e=0;c(".ui-dialog").each(function(){if(this!=d.uiDialog[0]){e=Math.max(e,c(this).css("z-index"))}});c.ui.dialog.maxZ=e}},isOpen:function(){return this._isOpen},moveToTop:function(f,e){if((this.options.modal&&!f)||(!this.options.stack&&!this.options.modal)){return this._trigger("focus",e)}if(this.options.zIndex>c.ui.dialog.maxZ){c.ui.dialog.maxZ=this.options.zIndex}(this.overlay&&this.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=++c.ui.dialog.maxZ));var d={scrollTop:this.element.attr("scrollTop"),scrollLeft:this.element.attr("scrollLeft")};this.uiDialog.css("z-index",++c.ui.dialog.maxZ);this.element.attr(d);this._trigger("focus",e)},open:function(){if(this._isOpen){return}var e=this.options,d=this.uiDialog;this.overlay=e.modal?new c.ui.dialog.overlay(this):null;(d.next().length&&d.appendTo("body"));this._size();this._position(e.position);d.show(e.show);this.moveToTop(true);(e.modal&&d.bind("keypress.ui-dialog",function(h){if(h.keyCode!=c.ui.keyCode.TAB){return}var g=c(":tabbable",this),i=g.filter(":first")[0],f=g.filter(":last")[0];if(h.target==f&&!h.shiftKey){setTimeout(function(){i.focus()},1)}else{if(h.target==i&&h.shiftKey){setTimeout(function(){f.focus()},1)}}}));c([]).add(d.find(".ui-dialog-content :tabbable:first")).add(d.find(".ui-dialog-buttonpane :tabbable:first")).add(d).filter(":first").focus();this._trigger("open");this._isOpen=true},_createButtons:function(g){var f=this,d=false,e=c("
    ").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix");this.uiDialog.find(".ui-dialog-buttonpane").remove();(typeof g=="object"&&g!==null&&c.each(g,function(){return !(d=true)}));if(d){c.each(g,function(h,i){c('').addClass("ui-state-default ui-corner-all").text(h).click(function(){i.apply(f.element[0],arguments)}).hover(function(){c(this).addClass("ui-state-hover")},function(){c(this).removeClass("ui-state-hover")}).focus(function(){c(this).addClass("ui-state-focus")}).blur(function(){c(this).removeClass("ui-state-focus")}).appendTo(e)});e.appendTo(this.uiDialog)}},_makeDraggable:function(){var d=this,f=this.options,e;this.uiDialog.draggable({cancel:".ui-dialog-content",handle:".ui-dialog-titlebar",containment:"document",start:function(){e=f.height;c(this).height(c(this).height()).addClass("ui-dialog-dragging");(f.dragStart&&f.dragStart.apply(d.element[0],arguments))},drag:function(){(f.drag&&f.drag.apply(d.element[0],arguments))},stop:function(){c(this).removeClass("ui-dialog-dragging").height(e);(f.dragStop&&f.dragStop.apply(d.element[0],arguments));c.ui.dialog.overlay.resize()}})},_makeResizable:function(g){g=(g===undefined?this.options.resizable:g);var d=this,f=this.options,e=typeof g=="string"?g:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",alsoResize:this.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:f.minHeight,start:function(){c(this).addClass("ui-dialog-resizing");(f.resizeStart&&f.resizeStart.apply(d.element[0],arguments))},resize:function(){(f.resize&&f.resize.apply(d.element[0],arguments))},handles:e,stop:function(){c(this).removeClass("ui-dialog-resizing");f.height=c(this).height();f.width=c(this).width();(f.resizeStop&&f.resizeStop.apply(d.element[0],arguments));c.ui.dialog.overlay.resize()}}).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_position:function(i){var e=c(window),f=c(document),g=f.scrollTop(),d=f.scrollLeft(),h=g;if(c.inArray(i,["center","top","right","bottom","left"])>=0){i=[i=="right"||i=="left"?i:"center",i=="top"||i=="bottom"?i:"middle"]}if(i.constructor!=Array){i=["center","middle"]}if(i[0].constructor==Number){d+=i[0]}else{switch(i[0]){case"left":d+=0;break;case"right":d+=e.width()-this.uiDialog.outerWidth();break;default:case"center":d+=(e.width()-this.uiDialog.outerWidth())/2}}if(i[1].constructor==Number){g+=i[1]}else{switch(i[1]){case"top":g+=0;break;case"bottom":g+=e.height()-this.uiDialog.outerHeight();break;default:case"middle":g+=(e.height()-this.uiDialog.outerHeight())/2}}g=Math.max(g,h);this.uiDialog.css({top:g,left:d})},_setData:function(e,f){(b[e]&&this.uiDialog.data(b[e],f));switch(e){case"buttons":this._createButtons(f);break;case"closeText":this.uiDialogTitlebarCloseText.text(f);break;case"dialogClass":this.uiDialog.removeClass(this.options.dialogClass).addClass(a+f);break;case"draggable":(f?this._makeDraggable():this.uiDialog.draggable("destroy"));break;case"height":this.uiDialog.height(f);break;case"position":this._position(f);break;case"resizable":var d=this.uiDialog,g=this.uiDialog.is(":data(resizable)");(g&&!f&&d.resizable("destroy"));(g&&typeof f=="string"&&d.resizable("option","handles",f));(g||this._makeResizable(f));break;case"title":c(".ui-dialog-title",this.uiDialogTitlebar).html(f||" ");break;case"width":this.uiDialog.width(f);break}c.widget.prototype._setData.apply(this,arguments)},_size:function(){var e=this.options;this.element.css({height:0,minHeight:0,width:"auto"});var d=this.uiDialog.css({height:"auto",width:e.width}).height();this.element.css({minHeight:Math.max(e.minHeight-d,0),height:e.height=="auto"?"auto":Math.max(e.height-d,0)})}});c.extend(c.ui.dialog,{version:"1.7.3",defaults:{autoOpen:true,bgiframe:false,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:"center",resizable:true,show:null,stack:true,title:"",width:300,zIndex:1000},getter:"isOpen",uuid:0,maxZ:0,getTitleId:function(d){return"ui-dialog-title-"+(d.attr("id")||++this.uuid)},overlay:function(d){this.$el=c.ui.dialog.overlay.create(d)}});c.extend(c.ui.dialog.overlay,{instances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(d){return d+".dialog-overlay"}).join(" "),create:function(e){if(this.instances.length===0){setTimeout(function(){if(c.ui.dialog.overlay.instances.length){c(document).bind(c.ui.dialog.overlay.events,function(f){var g=c(f.target).parents(".ui-dialog").css("zIndex")||0;return(g>c.ui.dialog.overlay.maxZ)})}},1);c(document).bind("keydown.dialog-overlay",function(f){(e.options.closeOnEscape&&f.keyCode&&f.keyCode==c.ui.keyCode.ESCAPE&&e.close(f))});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var d=c("
    ").appendTo(document.body).addClass("ui-widget-overlay").css({width:this.width(),height:this.height()});(e.options.bgiframe&&c.fn.bgiframe&&d.bgiframe());this.instances.push(d);return d},destroy:function(d){this.instances.splice(c.inArray(this.instances,d),1);if(this.instances.length===0){c([document,window]).unbind(".dialog-overlay")}d.remove();var e=0;c.each(this.instances,function(){e=Math.max(e,this.css("z-index"))});this.maxZ=e},height:function(){if(c.browser.msie&&c.browser.version<7){var e=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);var d=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);if(e
    ').appendTo(this.element);this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow").removeData("progressbar").unbind(".progressbar");this.valueDiv.remove();a.widget.prototype.destroy.apply(this,arguments)},value:function(b){if(b===undefined){return this._value()}this._setData("value",b);return this},_setData:function(b,c){switch(b){case"value":this.options.value=c;this._refreshValue();this._trigger("change",null,{});break}a.widget.prototype._setData.apply(this,arguments)},_value:function(){var b=this.options.value;if(bthis._valueMax()){b=this._valueMax()}return b},_valueMin:function(){var b=0;return b},_valueMax:function(){var b=100;return b},_refreshValue:function(){var b=this.value();this.valueDiv[b==this._valueMax()?"addClass":"removeClass"]("ui-corner-right");this.valueDiv.width(b+"%");this.element.attr("aria-valuenow",b)}});a.extend(a.ui.progressbar,{version:"1.7.3",defaults:{value:0}})})(jQuery);(function(a){a.widget("ui.slider",a.extend({},a.ui.mouse,{_init:function(){var b=this,c=this.options;this._keySliding=false;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");this.range=a([]);if(c.range){if(c.range===true){this.range=a("
    ");if(!c.values){c.values=[this._valueMin(),this._valueMin()]}if(c.values.length&&c.values.length!=2){c.values=[c.values[0],c.values[0]]}}else{this.range=a("
    ")}this.range.appendTo(this.element).addClass("ui-slider-range");if(c.range=="min"||c.range=="max"){this.range.addClass("ui-slider-range-"+c.range)}this.range.addClass("ui-widget-header")}if(a(".ui-slider-handle",this.element).length==0){a('
    ').appendTo(this.element).addClass("ui-slider-handle")}if(c.values&&c.values.length){while(a(".ui-slider-handle",this.element).length').appendTo(this.element).addClass("ui-slider-handle")}}this.handles=a(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(d){d.preventDefault()}).hover(function(){if(!c.disabled){a(this).addClass("ui-state-hover")}},function(){a(this).removeClass("ui-state-hover")}).focus(function(){if(!c.disabled){a(".ui-slider .ui-state-focus").removeClass("ui-state-focus");a(this).addClass("ui-state-focus")}else{a(this).blur()}}).blur(function(){a(this).removeClass("ui-state-focus")});this.handles.each(function(d){a(this).data("index.ui-slider-handle",d)});this.handles.keydown(function(i){var f=true;var e=a(this).data("index.ui-slider-handle");if(b.options.disabled){return}switch(i.keyCode){case a.ui.keyCode.HOME:case a.ui.keyCode.END:case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:f=false;if(!b._keySliding){b._keySliding=true;a(this).addClass("ui-state-active");b._start(i,e)}break}var g,d,h=b._step();if(b.options.values&&b.options.values.length){g=d=b.values(e)}else{g=d=b.value()}switch(i.keyCode){case a.ui.keyCode.HOME:d=b._valueMin();break;case a.ui.keyCode.END:d=b._valueMax();break;case a.ui.keyCode.UP:case a.ui.keyCode.RIGHT:if(g==b._valueMax()){return}d=g+h;break;case a.ui.keyCode.DOWN:case a.ui.keyCode.LEFT:if(g==b._valueMin()){return}d=g-h;break}b._slide(i,e,d);return f}).keyup(function(e){var d=a(this).data("index.ui-slider-handle");if(b._keySliding){b._stop(e,d);b._change(e,d);b._keySliding=false;a(this).removeClass("ui-state-active")}});this._refreshValue()},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");this._mouseDestroy()},_mouseCapture:function(d){var e=this.options;if(e.disabled){return false}this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();var h={x:d.pageX,y:d.pageY};var j=this._normValueFromMouse(h);var c=this._valueMax()-this._valueMin()+1,f;var k=this,i;this.handles.each(function(l){var m=Math.abs(j-k.values(l));if(c>m){c=m;f=a(this);i=l}});if(e.range==true&&this.values(1)==e.min){f=a(this.handles[++i])}this._start(d,i);k._handleIndex=i;f.addClass("ui-state-active").focus();var g=f.offset();var b=!a(d.target).parents().andSelf().is(".ui-slider-handle");this._clickOffset=b?{left:0,top:0}:{left:d.pageX-g.left-(f.width()/2),top:d.pageY-g.top-(f.height()/2)-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};j=this._normValueFromMouse(h);this._slide(d,i,j);return true},_mouseStart:function(b){return true},_mouseDrag:function(d){var b={x:d.pageX,y:d.pageY};var c=this._normValueFromMouse(b);this._slide(d,this._handleIndex,c);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._handleIndex=null;this._clickOffset=null;return false},_detectOrientation:function(){this.orientation=this.options.orientation=="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(d){var c,h;if("horizontal"==this.orientation){c=this.elementSize.width;h=d.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{c=this.elementSize.height;h=d.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}var f=(h/c);if(f>1){f=1}if(f<0){f=0}if("vertical"==this.orientation){f=1-f}var e=this._valueMax()-this._valueMin(),i=f*e,b=i%this.options.step,g=this._valueMin()+i-b;if(b>(this.options.step/2)){g+=this.options.step}return parseFloat(g.toFixed(5))},_start:function(d,c){var b={handle:this.handles[c],value:this.value()};if(this.options.values&&this.options.values.length){b.value=this.values(c);b.values=this.values()}this._trigger("start",d,b)},_slide:function(f,e,d){var g=this.handles[e];if(this.options.values&&this.options.values.length){var b=this.values(e?0:1);if((this.options.values.length==2&&this.options.range===true)&&((e==0&&d>b)||(e==1&&d1){this.options.values[b]=e;this._refreshValue(c);if(!d){this._change(null,b)}}if(arguments.length){if(this.options.values&&this.options.values.length){return this._values(b)}else{return this.value()}}else{return this._values()}},_setData:function(b,d,c){a.widget.prototype._setData.apply(this,arguments);switch(b){case"disabled":if(d){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled")}else{this.handles.removeAttr("disabled")}case"orientation":this._detectOrientation();this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue(c);break;case"value":this._refreshValue(c);break}},_step:function(){var b=this.options.step;return b},_value:function(){var b=this.options.value;if(bthis._valueMax()){b=this._valueMax()}return b},_values:function(b){if(arguments.length){var c=this.options.values[b];if(cthis._valueMax()){c=this._valueMax()}return c}else{return this.options.values}},_valueMin:function(){var b=this.options.min;return b},_valueMax:function(){var b=this.options.max;return b},_refreshValue:function(c){var f=this.options.range,d=this.options,l=this;if(this.options.values&&this.options.values.length){var i,h;this.handles.each(function(p,n){var o=(l.values(p)-l._valueMin())/(l._valueMax()-l._valueMin())*100;var m={};m[l.orientation=="horizontal"?"left":"bottom"]=o+"%";a(this).stop(1,1)[c?"animate":"css"](m,d.animate);if(l.options.range===true){if(l.orientation=="horizontal"){(p==0)&&l.range.stop(1,1)[c?"animate":"css"]({left:o+"%"},d.animate);(p==1)&&l.range[c?"animate":"css"]({width:(o-lastValPercent)+"%"},{queue:false,duration:d.animate})}else{(p==0)&&l.range.stop(1,1)[c?"animate":"css"]({bottom:(o)+"%"},d.animate);(p==1)&&l.range[c?"animate":"css"]({height:(o-lastValPercent)+"%"},{queue:false,duration:d.animate})}}lastValPercent=o})}else{var j=this.value(),g=this._valueMin(),k=this._valueMax(),e=k!=g?(j-g)/(k-g)*100:0;var b={};b[l.orientation=="horizontal"?"left":"bottom"]=e+"%";this.handle.stop(1,1)[c?"animate":"css"](b,d.animate);(f=="min")&&(this.orientation=="horizontal")&&this.range.stop(1,1)[c?"animate":"css"]({width:e+"%"},d.animate);(f=="max")&&(this.orientation=="horizontal")&&this.range[c?"animate":"css"]({width:(100-e)+"%"},{queue:false,duration:d.animate});(f=="min")&&(this.orientation=="vertical")&&this.range.stop(1,1)[c?"animate":"css"]({height:e+"%"},d.animate);(f=="max")&&(this.orientation=="vertical")&&this.range[c?"animate":"css"]({height:(100-e)+"%"},{queue:false,duration:d.animate})}}}));a.extend(a.ui.slider,{getter:"value values",version:"1.7.3",eventPrefix:"slide",defaults:{animate:false,delay:0,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null}})})(jQuery);(function(c){var b=0,a=0;c.widget("ui.tabs",{_init:function(){if(this.options.deselectable!==undefined){this.options.collapsible=this.options.deselectable}this._tabify(true)},_setData:function(d,e){if(d=="selected"){if(this.options.collapsible&&e==this.options.selected){return}this.select(e)}else{this.options[d]=e;if(d=="deselectable"){this.options.collapsible=e}this._tabify()}},_tabId:function(d){return d.title&&d.title.replace(/\s/g,"_").replace(/[^A-Za-z0-9\-_:\.]/g,"")||this.options.idPrefix+(++b)},_sanitizeSelector:function(d){return d.replace(/:/g,"\\:")},_cookie:function(){var d=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+(++a));return c.cookie.apply(null,[d].concat(c.makeArray(arguments)))},_ui:function(e,d){return{tab:e,panel:d,index:this.anchors.index(e)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var d=c(this);d.html(d.data("label.tabs")).removeData("label.tabs")})},_tabify:function(q){this.list=this.element.children("ul:first");this.lis=c("li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return c("a",this)[0]});this.panels=c([]);var r=this,f=this.options;var e=/^#.+/;this.anchors.each(function(u,o){var s=c(o).attr("href");var v=s.split("#")[0],w;if(v&&(v===location.toString().split("#")[0]||(w=c("base")[0])&&v===w.href)){s=o.hash;o.href=s}if(e.test(s)){r.panels=r.panels.add(r._sanitizeSelector(s))}else{if(s!="#"){c.data(o,"href.tabs",s);c.data(o,"load.tabs",s.replace(/#.*$/,""));var y=r._tabId(o);o.href="#"+y;var x=c("#"+y);if(!x.length){x=c(f.panelTemplate).attr("id",y).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(r.panels[u-1]||r.list);x.data("destroy.tabs",true)}r.panels=r.panels.add(x)}else{f.disabled.push(u)}}});if(q){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(f.selected===undefined){if(location.hash){this.anchors.each(function(s,o){if(o.hash==location.hash){f.selected=s;return false}})}if(typeof f.selected!="number"&&f.cookie){f.selected=parseInt(r._cookie(),10)}if(typeof f.selected!="number"&&this.lis.filter(".ui-tabs-selected").length){f.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}f.selected=f.selected||0}else{if(f.selected===null){f.selected=-1}}f.selected=((f.selected>=0&&this.anchors[f.selected])||f.selected<0)?f.selected:0;f.disabled=c.unique(f.disabled.concat(c.map(this.lis.filter(".ui-state-disabled"),function(s,o){return r.lis.index(s)}))).sort();if(c.inArray(f.selected,f.disabled)!=-1){f.disabled.splice(c.inArray(f.selected,f.disabled),1)}this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");if(f.selected>=0&&this.anchors.length){this.panels.eq(f.selected).removeClass("ui-tabs-hide");this.lis.eq(f.selected).addClass("ui-tabs-selected ui-state-active");r.element.queue("tabs",function(){r._trigger("show",null,r._ui(r.anchors[f.selected],r.panels[f.selected]))});this.load(f.selected)}c(window).bind("unload",function(){r.lis.add(r.anchors).unbind(".tabs");r.lis=r.anchors=r.panels=null})}else{f.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"))}this.element[f.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");if(f.cookie){this._cookie(f.selected,f.cookie)}for(var j=0,p;(p=this.lis[j]);j++){c(p)[c.inArray(j,f.disabled)!=-1&&!c(p).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled")}if(f.cache===false){this.anchors.removeData("cache.tabs")}this.lis.add(this.anchors).unbind(".tabs");if(f.event!="mouseover"){var h=function(o,i){if(i.is(":not(.ui-state-disabled)")){i.addClass("ui-state-"+o)}};var l=function(o,i){i.removeClass("ui-state-"+o)};this.lis.bind("mouseover.tabs",function(){h("hover",c(this))});this.lis.bind("mouseout.tabs",function(){l("hover",c(this))});this.anchors.bind("focus.tabs",function(){h("focus",c(this).closest("li"))});this.anchors.bind("blur.tabs",function(){l("focus",c(this).closest("li"))})}var d,k;if(f.fx){if(c.isArray(f.fx)){d=f.fx[0];k=f.fx[1]}else{d=k=f.fx}}function g(i,o){i.css({display:""});if(c.browser.msie&&o.opacity){i[0].style.removeAttribute("filter")}}var m=k?function(i,o){c(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.hide().removeClass("ui-tabs-hide").animate(k,k.duration||"normal",function(){g(o,k);r._trigger("show",null,r._ui(i,o[0]))})}:function(i,o){c(i).closest("li").removeClass("ui-state-default").addClass("ui-tabs-selected ui-state-active");o.removeClass("ui-tabs-hide");r._trigger("show",null,r._ui(i,o[0]))};var n=d?function(o,i){i.animate(d,d.duration||"normal",function(){r.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");g(i,d);r.element.dequeue("tabs")})}:function(o,i,s){r.lis.removeClass("ui-tabs-selected ui-state-active").addClass("ui-state-default");i.addClass("ui-tabs-hide");r.element.dequeue("tabs")};this.anchors.bind(f.event+".tabs",function(){var o=this,u=c(this).closest("li"),i=r.panels.filter(":not(.ui-tabs-hide)"),s=c(r._sanitizeSelector(this.hash));if((u.hasClass("ui-tabs-selected")&&!f.collapsible)||u.hasClass("ui-state-disabled")||u.hasClass("ui-state-processing")||r._trigger("select",null,r._ui(this,s[0]))===false){this.blur();return false}f.selected=r.anchors.index(this);r.abort();if(f.collapsible){if(u.hasClass("ui-tabs-selected")){f.selected=-1;if(f.cookie){r._cookie(f.selected,f.cookie)}r.element.queue("tabs",function(){n(o,i)}).dequeue("tabs");this.blur();return false}else{if(!i.length){if(f.cookie){r._cookie(f.selected,f.cookie)}r.element.queue("tabs",function(){m(o,s)});r.load(r.anchors.index(this));this.blur();return false}}}if(f.cookie){r._cookie(f.selected,f.cookie)}if(s.length){if(i.length){r.element.queue("tabs",function(){n(o,i)})}r.element.queue("tabs",function(){m(o,s)});r.load(r.anchors.index(this))}else{throw"jQuery UI Tabs: Mismatching fragment identifier."}if(c.browser.msie){this.blur()}});this.anchors.bind("click.tabs",function(){return false})},destroy:function(){var d=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=c.data(this,"href.tabs");if(e){this.href=e}var f=c(this).unbind(".tabs");c.each(["href","load","cache"],function(g,h){f.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){if(c.data(this,"destroy.tabs")){c(this).remove()}else{c(this).removeClass(["ui-state-default","ui-corner-top","ui-tabs-selected","ui-state-active","ui-state-hover","ui-state-focus","ui-state-disabled","ui-tabs-panel","ui-widget-content","ui-corner-bottom","ui-tabs-hide"].join(" "))}});if(d.cookie){this._cookie(null,d.cookie)}},add:function(g,f,e){if(e===undefined){e=this.anchors.length}var d=this,i=this.options,k=c(i.tabTemplate.replace(/#\{href\}/g,g).replace(/#\{label\}/g,f)),j=!g.indexOf("#")?g.replace("#",""):this._tabId(c("a",k)[0]);k.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var h=c("#"+j);if(!h.length){h=c(i.panelTemplate).attr("id",j).data("destroy.tabs",true)}h.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(e>=this.lis.length){k.appendTo(this.list);h.appendTo(this.list[0].parentNode)}else{k.insertBefore(this.lis[e]);h.insertBefore(this.panels[e])}i.disabled=c.map(i.disabled,function(m,l){return m>=e?++m:m});this._tabify();if(this.anchors.length==1){k.addClass("ui-tabs-selected ui-state-active");h.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){d._trigger("show",null,d._ui(d.anchors[0],d.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[e],this.panels[e]))},remove:function(d){var f=this.options,g=this.lis.eq(d).remove(),e=this.panels.eq(d).remove();if(g.hasClass("ui-tabs-selected")&&this.anchors.length>1){this.select(d+(d+1=d?--j:j});this._tabify();this._trigger("remove",null,this._ui(g.find("a")[0],e[0]))},enable:function(d){var e=this.options;if(c.inArray(d,e.disabled)==-1){return}this.lis.eq(d).removeClass("ui-state-disabled");e.disabled=c.grep(e.disabled,function(g,f){return g!=d});this._trigger("enable",null,this._ui(this.anchors[d],this.panels[d]))},disable:function(e){var d=this,f=this.options;if(e!=f.selected){this.lis.eq(e).addClass("ui-state-disabled");f.disabled.push(e);f.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[e],this.panels[e]))}},select:function(d){if(typeof d=="string"){d=this.anchors.index(this.anchors.filter("[href$="+d+"]"))}else{if(d===null){d=-1}}if(d==-1&&this.options.collapsible){d=this.options.selected}this.anchors.eq(d).trigger(this.options.event+".tabs")},load:function(g){var e=this,i=this.options,d=this.anchors.eq(g)[0],f=c.data(d,"load.tabs");this.abort();if(!f||this.element.queue("tabs").length!==0&&c.data(d,"cache.tabs")){this.element.dequeue("tabs");return}this.lis.eq(g).addClass("ui-state-processing");if(i.spinner){var h=c("span",d);h.data("label.tabs",h.html()).html(i.spinner)}this.xhr=c.ajax(c.extend({},i.ajaxOptions,{url:f,success:function(k,j){c(e._sanitizeSelector(d.hash)).html(k);e._cleanup();if(i.cache){c.data(d,"cache.tabs",true)}e._trigger("load",null,e._ui(e.anchors[g],e.panels[g]));try{i.ajaxOptions.success(k,j)}catch(l){}e.element.dequeue("tabs")}}))},abort:function(){this.element.queue([]);this.panels.stop(false,true);if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup()},url:function(e,d){this.anchors.eq(e).removeData("cache.tabs").data("load.tabs",d)},length:function(){return this.anchors.length}});c.extend(c.ui.tabs,{version:"1.7.3",getter:"length",defaults:{ajaxOptions:null,cache:false,cookie:null,collapsible:false,disabled:[],event:"click",fx:null,idPrefix:"ui-tabs-",panelTemplate:"
    ",spinner:"Loading…",tabTemplate:'
  • #{label}
  • '}});c.extend(c.ui.tabs.prototype,{rotation:null,rotate:function(f,h){var d=this,i=this.options;var e=d._rotate||(d._rotate=function(j){clearTimeout(d.rotation);d.rotation=setTimeout(function(){var k=i.selected;d.select(++k= 80 && previous < 80) { - body.className = body.className + ' scrolled'; - } else if (current < 80 && previous >= 80) { - body.className = body.className.replace(' scrolled', ''); - } - previous = current; - } - - // Menu - main.addEventListener('click', closeMenu); - menu.addEventListener('click', toggleMenu); - nav.addEventListener('click', handleNavClick); - window.addEventListener('scroll', handleScroll); -})(); diff --git a/vitess.io/assets/scripts/modernizr.js b/vitess.io/assets/scripts/modernizr.js deleted file mode 100644 index 5b3820f868e..00000000000 --- a/vitess.io/assets/scripts/modernizr.js +++ /dev/null @@ -1,4 +0,0 @@ -/* Modernizr 2.7.1 (Custom Build) | MIT & BSD - * Build: http://modernizr.com/download/#-fontface-borderradius-opacity-rgba-cssanimations-generatedcontent-input-inputtypes-shiv-mq-teststyles-testprop-testallprops-prefixes-domprefixes-load - */ -;window.Modernizr=function(a,b,c){function A(a){i.cssText=a}function B(a,b){return A(m.join(a+";")+(b||""))}function C(a,b){return typeof a===b}function D(a,b){return!!~(""+a).indexOf(b)}function E(a,b){for(var d in a){var e=a[d];if(!D(e,"-")&&i[e]!==c)return b=="pfx"?e:!0}return!1}function F(a,b,d){for(var e in a){var f=b[a[e]];if(f!==c)return d===!1?a[e]:C(f,"function")?f.bind(d||b):f}return!1}function G(a,b,c){var d=a.charAt(0).toUpperCase()+a.slice(1),e=(a+" "+o.join(d+" ")+d).split(" ");return C(b,"string")||C(b,"undefined")?E(e,b):(e=(a+" "+p.join(d+" ")+d).split(" "),F(e,b,c))}function H(){e.input=function(c){for(var d=0,e=c.length;d',a,""].join(""),l.id=g,(m?l:n).innerHTML+=h,n.appendChild(l),m||(n.style.background="",n.style.overflow="hidden",k=f.style.overflow,f.style.overflow="hidden",f.appendChild(n)),i=c(l,a),m?l.parentNode.removeChild(l):(n.parentNode.removeChild(n),f.style.overflow=k),!!i},x=function(b){var c=a.matchMedia||a.msMatchMedia;if(c)return c(b).matches;var d;return w("@media "+b+" { #"+g+" { position: absolute; } }",function(b){d=(a.getComputedStyle?getComputedStyle(b,null):b.currentStyle)["position"]=="absolute"}),d},y={}.hasOwnProperty,z;!C(y,"undefined")&&!C(y.call,"undefined")?z=function(a,b){return y.call(a,b)}:z=function(a,b){return b in a&&C(a.constructor.prototype[b],"undefined")},Function.prototype.bind||(Function.prototype.bind=function(b){var c=this;if(typeof c!="function")throw new TypeError;var d=u.call(arguments,1),e=function(){if(this instanceof e){var a=function(){};a.prototype=c.prototype;var f=new a,g=c.apply(f,d.concat(u.call(arguments)));return Object(g)===g?g:f}return c.apply(b,d.concat(u.call(arguments)))};return e}),q.rgba=function(){return A("background-color:rgba(150,255,150,.5)"),D(i.backgroundColor,"rgba")},q.borderradius=function(){return G("borderRadius")},q.opacity=function(){return B("opacity:.55"),/^0.55$/.test(i.opacity)},q.cssanimations=function(){return G("animationName")},q.fontface=function(){var a;return w('@font-face {font-family:"font";src:url("https://")}',function(c,d){var e=b.getElementById("smodernizr"),f=e.sheet||e.styleSheet,g=f?f.cssRules&&f.cssRules[0]?f.cssRules[0].cssText:f.cssText||"":"";a=/src/i.test(g)&&g.indexOf(d.split(" ")[0])===0}),a},q.generatedcontent=function(){var a;return w(["#",g,"{font:0/0 a}#",g,':after{content:"',k,'";visibility:hidden;font:3px/1 a}'].join(""),function(b){a=b.offsetHeight>=3}),a};for(var I in q)z(q,I)&&(v=I.toLowerCase(),e[v]=q[I](),t.push((e[v]?"":"no-")+v));return e.input||H(),e.addTest=function(a,b){if(typeof a=="object")for(var d in a)z(a,d)&&e.addTest(d,a[d]);else{a=a.toLowerCase();if(e[a]!==c)return e;b=typeof b=="function"?b():b,typeof enableClasses!="undefined"&&enableClasses&&(f.className+=" "+(b?"":"no-")+a),e[a]=b}return e},A(""),h=j=null,function(a,b){function l(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function m(){var a=s.elements;return typeof a=="string"?a.split(" "):a}function n(a){var b=j[a[h]];return b||(b={},i++,a[h]=i,j[i]=b),b}function o(a,c,d){c||(c=b);if(k)return c.createElement(a);d||(d=n(c));var g;return d.cache[a]?g=d.cache[a].cloneNode():f.test(a)?g=(d.cache[a]=d.createElem(a)).cloneNode():g=d.createElem(a),g.canHaveChildren&&!e.test(a)&&!g.tagUrn?d.frag.appendChild(g):g}function p(a,c){a||(a=b);if(k)return a.createDocumentFragment();c=c||n(a);var d=c.frag.cloneNode(),e=0,f=m(),g=f.length;for(;e",g="hidden"in a,k=a.childNodes.length==1||function(){b.createElement("a");var a=b.createDocumentFragment();return typeof a.cloneNode=="undefined"||typeof a.createDocumentFragment=="undefined"||typeof a.createElement=="undefined"}()}catch(c){g=!0,k=!0}})();var s={elements:d.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:c,shivCSS:d.shivCSS!==!1,supportsUnknownElements:k,shivMethods:d.shivMethods!==!1,type:"default",shivDocument:r,createElement:o,createDocumentFragment:p};a.html5=s,r(b)}(this,b),e._version=d,e._prefixes=m,e._domPrefixes=p,e._cssomPrefixes=o,e.mq=x,e.testProp=function(a){return E([a])},e.testAllProps=G,e.testStyles=w,e}(this,this.document),function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f \ No newline at end of file diff --git a/vitess.io/assets/vendor/images/icons/icons-hinted.ttf b/vitess.io/assets/vendor/images/icons/icons-hinted.ttf deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/vitess.io/assets/vendor/images/icons/icons.eot b/vitess.io/assets/vendor/images/icons/icons.eot deleted file mode 100644 index ee360b9b27cb30a82a6d9f0fad93008dc237c3cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3528 zcmds4Z){W76+h?MelI}4F^>NbLh}+kF%-rB9fvHi1RA3@P62JD0n(L#W9*DLA$g2K zrEJow2~Cxt6G}_j1WG>?b=4%;Rw_1ap4JbP1$8Y<>bf#9@nw~YG_6qW19JAe*EbNR zYWu$XeBU|uoO91P_ndR@yS}oVD2UFak!Tv}Hi>|8mj#yHUL8}Ng5Xr!_4B1q7HALQ zQYzAZ8mAIXfmlleG(tJh4$~OMChf#{61<|6F)4~CMqvq~;1fNn0R&-iIem|8v^|sg z=D@f2K06IU4XBOVz7dH>y9PEuXb|JQ`^SbS$a(wsScwVR=KbHXOmguPM7A9G_5;IH z6Z7-X1chid2M!+1e^K-OJK&!qa(rGG8O~Afz4hRIir!HG!S)ZvI=LR>U}4O9A@p5x zVf-$}g@fb!hwFZ`@-56SVB9%2{K5q7qhatnF*ZxXV((soC2dxFSNjr)6?s0*&migsg)cBgx-S}b zx)Z;kJ3j5cXw!hw1)Cr{1o@(&^Zo9N2=|?M!j*7^60U&j_>p{`pQ-%RCF(<@L{&ZV z>Txx@H0sf)A_FfnvRm#5QM(>TYs#U~JRX#H`SrQE*RQGh@VYGO+m&z|0e9i*)x!H+ zuAl~lDD-op%1^rkHh1Fesk5g}oh?f>3w9pLK!+{h780jW^i>U2KNtDpNVPgVESd17 zZSM57Yo}!qKUj+a*L)muv%&mcccr_#TLLZ%oZpi#VH}mH=7cCh)N1I4&j{&G4usl5 zMkw7D;Z(XK9ZLH;zRn4s*O&Gg-X^xkJCbcJdc8&icAMEgP^+6grqkZv{+O=y_iK7n zd)Dp*saDUnH|bio^3hOl@6hIR4+vR@2ANs|GDaI&ydn`B^4pLg|E&PWX&K`Y(q@ zM-LT$F5mj)YOBVBk3;8bY7+7ggihHLMgo%)o`CFu5UAHS_%r^ecR8QlP>F!-YQy~rCCQYrJ99|w;G|9C8T3_l5<^82CB zj;=xHG<2>cFPZo_B0TQ4KnqGUu#uA;iMY?^ONWfKcMaF;o>1G(%=ni4t}UA#`pjsl zf3D$X!;1B*IAzl^8K&%}O}lNj(V6X)`@S#zxk%z`nx@<9R|`82YG2lm8`WdO>TYH- zH^mA?_&AVJay*C}m=r`!B(WhjaVi;tQ@RHmB`tjNdg|dJ9*=>7$+=dp_czoz*LclC z%#l=IHWg{`uk+RzMxl_6u4;I!Zta@Jm9EA{ZENeg@Vc#!x3+j!xSdTe?-21u&Z~7z zjMIRvD{qSvMR<%R`7(zq;0^V6{;Bk z&%nP)TsMbtvk;e16F0M?c=rO&No*S~qGRBfa2+-22;LSIfMw+6)RJ(L4q&!Pad}BK zX)PoyJQLJ~lQ}|pB`aW6HVmzKNS83rqIC$<-dP)@Dg6i%ea=8^9puy9lLlX zySbh{?8TSX&#R2XrD7ipD;QTWpY%6?4Qk16{xWj`kVN8rXPqr)OBa~o$r5ODE-gnt7wpKRU$ diff --git a/vitess.io/assets/vendor/images/icons/icons.svg b/vitess.io/assets/vendor/images/icons/icons.svg deleted file mode 100644 index 2293e8b4250..00000000000 --- a/vitess.io/assets/vendor/images/icons/icons.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/vitess.io/assets/vendor/images/icons/icons.ttf b/vitess.io/assets/vendor/images/icons/icons.ttf deleted file mode 100644 index 5c9b6b90b241c9dbd88c08a3d9e9b9e884517210..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3364 zcmds4|8G;*6+h?MelL)K<2e435So|RiJ>U|?l@$ICD0hPaSCWF4Un!RaU44%PDmc3 zP$`?VYC=;b=!DWzHi6O~R&CWJ*j6ewZJyR2+ALAm!lbS%6BECzQjw;$RQmxr``qUn zl6}$sfZdmS&$;KGd(OG%eD3oLF%fN|Z;^!#q|;v=`1-M@=OCzpv}ylWLeX&dz)m6_ z#QfOksfwhm(JM$1&{>C4{Rz2qa{G{<*;G5*Y{4LD$$EQYzYkyVuBka#(-ZeS= z+%%2QFxI;;*NelGV}Fsx~<*+OBmnPQ>HrmTm8ro_s>;m^e? zXE+DRK1uIW1HFJ~NkyJkTkR?XdLY-ArP3X~$_&=ERLb95fH`v+HXBS-ldpWy}mCBMUe zSGFlB#ZX>Q7L>P?FHl%f=ZpLlvaV6^DpM$RO|#Oy=vCGBaq5~y0ZUgcLTnS_YnsXr zQrD2~d(oI9<_N?bKF8Tpxg0-L{;@;gLzG0K9(8p&S{w@XC{#8RFDi1xyb%JsE?Zl| zrqBu=z`OM7($cHTazCOj34A+ZPR-}cFD~Za9aUvmoHqtaN%;v zG_&ewO$RnCKBv&Q0MJ(~RN`D0i!IS+bFsOISlX8^E-zm+LHzJ68bb4Mz{wi(+o^IY zl`;vJ1kZ1qgK!Qc$~^%J5w&Tm=FtMGoqd7!fEGx$hd7b!Oa_vk&M$M!x=`A*xX`9nGqeDSt53+dH)9%0ofM zra-4ggN{~%ZHg_Ev09om_3+1GyD=prj8a_9bG5 zXj6Q!OwUvO$=wFtJpxt0#tnJKYO<3P zIBRjVv|(^2T3j~S`9?X-uaylSr^`3Y?g0kL!ylA`{7fj64+aatpooF`OiYWMAtR1; zHU#i1osCT9l}zU4Oa}Vm9{d16xhr-!{n|ZLGC#b?YaXLy5jjBGl;J?yl0bd_EIyXndr0+t#K! zM^lrsuWfs9`@TopTHTwS_U0E4ihQHy6?{ z?ug#JS-3Tne<{z`%a2F-y2PI8M+5FWxDNq*n$)YU?eWfNCvLx6yal4}ibT%+a?ahY z;nvph)`|Z9iT+>D4Gzu?K3F_=Zt+}s;nw{8t@#hdYHJ#c{SzZt9Gv?(7SAnS!rJ^T zM7o)NVj>SL?WMDlXQ1vw$%|X`spKuBb3*b~vhj%IZB)zOmAnf14{>g`Zh+12pjUXt zU0jm9LN)Yf$y=z0K9jtaHu53K+u$oNdE8^Zg!pD?3}0gg#w<`WLZ>nIg3p@Veww98 ztQV;O`6-MB<-w(C3Npi_Gc=CfIz{o-6b9V}4Fk_Kb>qz(qMXzfw4xh?)f}{o*k{mo zq-kbs*ci*|Bd7J=Z1%Lie|B=XSkO-ujJ%$nDjMmjnej0_8Vu{(@`f?p9SY?j%?W96 zHWw_888A|yQPa~b*wLvX$bfmO0-eMeXkaW`I0^c{LhnZSYi4vDK&LM1pagmphl@}g z2L2_WZryaIck5jpiH>ME0*y5jtC1W+Br`a5!HiIcDPc_HOFTN!p|P3S!c~R5T6S<9JGq`+?8Yyx zmm9Q`#X=t(OB$6lCTU#KgruF4CME5Xbf=`flJ1doucVJj+9zqcLL*^GrT>WZACdke i(tkwyk4XO!=|3X=kH8nJnH?5sS=zPmo}lahNBAcIoLm+F diff --git a/vitess.io/assets/vendor/images/icons/icons.woff b/vitess.io/assets/vendor/images/icons/icons.woff deleted file mode 100644 index 77e1d5da0f60803974f63524e1c761142f2fdd82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2292 zcmY*ac{r478-HdorV};U8kB~RGBK7SDH%&O88a;?q8Wpx8e^NX*9@sFokT=gLbf^C zQkJ1?lN6FdNBOche3H{3WSQ^P>7Va;uityWzu$dd&;7fe_qy&UkYZ~KU;tX^8L)0O z%AWX_uYUjkvb8-y1^{LasVWdQU7$H#K4@)Y3u!cnZ-#&ahX9gtT;CAVxDY2npb^Z- zdl=qyUr1|%I1!3Ouzt9SafyQi0FHq)^v^AsGAm1aKf*(4HU^ z(y``XW-us?L8H+;K!j06?3>83Y5AN+x-lRfL1h52n)9I11`zIRP#Bs!4N2UN^MXxd zffN%!hxsc{H*cAb;wABTo!1R+@^}rKNmo4MJ(zSFRL}6@B4EfwbzJ+dsKI(fv$R~C z^vV|6TZVc408sF6#jBN;0LP_D;;a3l=AfhD_ zp60Mb@`oKYNhXdZL(oQSm5-;nACQWZX;K5g>LIEeG6ekt=naF;9UheCd4j_FbOI~c zzqf*ylvkW+I*~bgD>21zSK*N6XOiPR$64bc@&x@@jVJf5&N-xAQiQfyp=fiwGc~D5 zwcvQ5rTbl_leum!bZJNDXzzX82l?rj23{BXFJug}70Z`1GV7-1F0VYFyWEdh=K)SO zuC0$mjyqhn^COEJEP5S|&ev2m2N+*<$Vip)a!a)C(=ApnSADELaqZD7lVUP?P)a1N zEbDH?UDlTVThku>+8{NOzHSpYdA*)sKW~2o(NN#Flwy)F`J<<2(%WahmkYL+s!1+n zvmLk4-}m}hruH)z$Tq`@j9|ZDKfmhncbk?(TGvd2$n+aFtPq(Jp~gre5#w?j*>WjwWVTVZB4@rWtgJjBh0z1zz#bj+B zn;#X}Nwwk^lCsc0A4i?up@%XxofytpKKn^H=G!%;JGVu?+CNo(>vBa0C2x1pVN7Qn=*fBQ6QR_l7gGYow*itd?HSvZ6Z3KRd|RUUtbFtJQTGT;9%#vgf3k*OgNFcb;d(x~;vX zi;rCvDYTM*#-e@VKMRg-Bl}jf9;}3YVK09k7R1~uulbQbEw!#^LZN1$xqNUm2)Xni z-qzh8e>gqimXuV<;5EkJzWm~>QC1aMOEw~gl4k7o#)CgT!!c`j=ay|$$x^(%-j6U? zsnX-UnC#vE#G4Y@-`Qv$FsH5*XV7L8`vRpzmtOy}`5{qoG?A@8P9!8#G>gkcW*K6X zz5G0Iqvi0A} zmUP7u|2w$7#FcV;(UL+AkWL)o8|A)#iY8EW4+kM;i(_;b?3ysLPA z>zSLOBFiHmxEvMQ@`uH*)_&b#ReB#?CW;atIyhD)tPEJX&$eG!S&W|5x0oLpUhm|e znY_h2a{(WCVP-Ljt}p6mexnqnP3PgZ*A{z}SuDjQE5{!uI*-$H25V-lL(0ATv=jzkC5{4Xpv z1&d4RMBlinj@3pr$!Jk`ZKj57%u^{1LSn4CBcP!jg?s|F-|_1)h3*|^zyg;+Jm7u1;T-r?cs9HW{^PfYcrOBt<_TchI4=(ny@xQyLxQ!c zKnQsZkGEtu5->J(Je;C~!>s`=SBxD}?lr$aZm;mqeVFS(mJxDWg;IRJ(-=%JaX5rq z91`&@gtvl?<;$JNchsiFN#bM&P(B#b@by7rJZ7LN0O1`L%qGU%7Ae8Y#G3{j%|qEn zlGmh8f&0vueK-DXLyZVk{C&JSIy5YlowZdd1M%avd1dOA!7wf33H?-hv!N66L)@_x65^N zPH*WxYM(HoBkI1Csv1n#o%mj(@_lw6Q#p!s$>>6$UtOl*{hr=ZQqyUd80;h0{Fo{| ze?e+ZQbR^yz1=o1ill$cV6LQXyIRim4S~WK*foWDBP!n2=%=4gS8Nw8=v;!-r#o>s zTaS>s-Ls}IGVq*JsTy}lvc%jwwKy>%x4`oRbf(_zN8}o)3O1cJXE2iaM8oL7aE*J` zZ8irxmfB=qoHKLCcMNbTopPhJPWJa?GI$4wk=i?tedLV2%jw{%D{pPKOEF};iO|v& x&-m4K8wmPZiuztX!;e@di*+bsyl(LAr?o3HI^BV@uHjDozk+^0I@@Ff{12s>(1!p3 diff --git a/vitess.io/assets/vendor/images/icons/icons.woff2 b/vitess.io/assets/vendor/images/icons/icons.woff2 deleted file mode 100644 index 0ed2d705bfd96a85fe91bae7a480d6f052dee4b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1572 zcmV+<2HW{}Pew8T0RR9100txg4FCWD01YGn00qtf0RR9100000000000000000000 z0000#Mn+Uk90p(jf3TL*#|8)*v2j?-l}pf=w8 zhj-IIHwm;0b;-=AJ2Qi%9jya}39Dpo?aYNYQ-5C;3ia;Qt5&0C4D&z6T%Enm!LQp# zn)Nah!$cyPN+XJDXoQxDg+)Ar2`_V~-|bHUAON_Mw&pqjT%X-rlKVOOi~djn)R`;* z+QFrN3p4>>pk~pV=fNLCcT1iLju-SIfE_vd0I0m@|W(Vs?y|wKS1AsyAk3)cwp5+1{MY(Wx@cHq8I3PQ~gg^@iK)b?xQcOna zni#N9-FhjSxR5-xs<<9Yo#40@&ZA93IF>`NJIABGq1ZWR%4%2*Bid*3P`PuJ(2HbX zH3fQJk_@~kEzlW8Pc!OCGN7`Dsi)E0-BO{S=VM3}sfL~x7x?MZr5Ykh3;o3mLk&q| znC~m4=?5BK)ZZU_ukOy6%}&ruJgeb&(nwo$=%v^u@vNAY8IeXW0&nBR`rR-Vh*AOn zXl(r$)|GRqU|kp^xuO((EV+vkW!mQ^rSDUAcw0r<@yJfCp%kukf3t5&_xL*f9X(Gp z_P(axkl#{jrO((6jG2dyON=L^?_GX-Z0oHl8+X#!pe20WCh&guGOlatyBx=uHro={ z1s7J?2>5iLoc^?_a9^?j`rGzdPnm-Mz7s zc=aSt!xY0H4@-7yy9QL3+iva)k{O4IO8S2~C7@8PwXc;uU?j$v0qI~n~thG)W1KVw+O zE1g24-h}h^_Uv?ISZAYer|`Bj3o|o|v1?&gRv{cp?@H9#^#5OiLq8k4L!1q?naVzd3|pr4zEsv|2F#2sA~7h z2eox;ZzRdRAH#73N7ne=ns%#EVT3LsuTrbi=2^A=TF9NzSy{-;1=rv;bU@=5Gi+!~ zr;o0_0Q-KurvTqNXP$$UCHibDacOCO5+ODEZb-P{66-M-7d2Wp8UPgwPMG( z6oyf8Ij!*Iqz<|#ji3W6Iz>7MZXdlcH00-tP``gdstLL`?ejW!`OvP_yy}TXHTH0I zy|srGwI|Oj+b$^Bzj}X6^zn#yT?gQ|CRJMi6f{8rSbt-QP3dtf&meqKc2CZ6HQlA~>>gtw|Q)4cZ%_gCIsE}nc*(agdI+fURPH-5a`G zP=gHv(SIyvHrWQsw2ymZGGQCa$%aI2#hIN%ixedmj>eHJ>`5lOOl%w1HaapY_9U31 zuLiZLJQNT_ZpomPCqxoJG}qMH2H1tj$S7@OZ%JVbs@HEz#UT*&3kDDvQoq0wM=Da2 z6FE}@;z>g;7B diff --git a/vitess.io/assets/vendor/styles/wsk.css b/vitess.io/assets/vendor/styles/wsk.css deleted file mode 100644 index dcccc347dd9..00000000000 --- a/vitess.io/assets/vendor/styles/wsk.css +++ /dev/null @@ -1 +0,0 @@ -html,button,input,select,textarea{color:#222}body{font-size:1em;line-height:1.4}a{color:#00e}a:visited{color:#551a8b}a:hover{color:#06e}img{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}.nocallout{-webkit-touch-callout:none}.pressed{background-color:rgba(0,0,0,0.7)}textarea[contenteditable]{-webkit-appearance:none}.gifhidden{position:absolute;left:-100%}.ir{background-color:transparent;background-repeat:no-repeat;border:0;direction:ltr;display:block;overflow:hidden;text-align:left;text-indent:-999em}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.clearfix::before,.clearfix::after{content:"";display:table}.clearfix::after{clear:both}/*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}blockquote{margin:0}*,*::before,*::after{box-sizing:border-box}html,body,button{-webkit-font-smoothing:antialiased;font-smoothing:antialiased}body{font-family:Helvetica, Arial, sans-serif;font-size:16px;line-height:1.6250em;font-weight:300;color:#404040;position:relative}body::after{content:"";position:absolute;top:0;left:0;bottom:0;right:0;width:100%;z-index:9;display:none;background-image:-webkit-linear-gradient(top, rgba(0,0,0,0.15) 95%, rgba(0,0,0,0.15) 100%);background-image:linear-gradient(to bottom, rgba(0,0,0,0.15) 95%, rgba(0,0,0,0.15) 100%);background-size:100% 26px}body.debug::after{display:block;pointer-events:none}pre{background:#f0f0f0;padding:13px}.main-container{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto}@media only screen and (min-width: 620px){.main-container{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 800px){.main-container{padding-left:4.4%;padding-right:4.4%;max-width:864px}}.container{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto}@media only screen and (min-width: 620px){.container{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 800px){.container{padding-left:4.4%;padding-right:4.4%;max-width:864px}}@media only screen and (min-width: 620px){.container-medium{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto}}@media only screen and (min-width: 620px) and (min-width: 620px){.container-medium{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 620px) and (min-width: 800px){.container-medium{padding-left:4.4%;padding-right:4.4%;max-width:864px}}@media only screen and (max-width: 619px){.container-small{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto}}@media only screen and (max-width: 619px) and (min-width: 620px){.container-small{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (max-width: 619px) and (min-width: 800px){.container-small{padding-left:4.4%;padding-right:4.4%;max-width:864px}}@media only screen and (min-width: 800px){.content{margin-right:25.9%}.content pre{margin-right:-25.9%}}@font-face{font-family:"icons";src:url("../images/icons/icons.eot");src:url("../images/icons/icons.eot?#iefix") format("embedded-opentype"),url("../images/icons/icons.woff2") format("woff2"),url("../images/icons/icons.woff") format("woff"),url("../images/icons/icons.ttf") format("truetype"),url("../images/icons/icons.svg?#icons") format("svg");font-weight:normal;font-style:normal}.icon{font-family:"icons";display:inline-block;vertical-align:top;line-height:1;font-weight:normal;font-style:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-bullet::before,ul li::before,ul.list-links a::before,.list-anchor a::before{content:"\e001"}.icon-chevron-down::before{content:"\e002"}.icon-chevron-large::before{content:"\e003"}.icon-chevron-left::before,.article-nav-link--prev::before{content:"\e004"}.icon-chevron-right::before,.article-nav-link--next::before,ul.list-links.list-links--primary a::before{content:"\e005"}.icon-chevron-up::before{content:"\e006"}.icon-close::before{content:"\e007"}.icon-cog::before{content:"\e008"}.icon-diamond::before{content:"\e009"}.icon-exclamation::before{content:"\e00a"}.icon-google-dev::before{content:"\e00b"}.icon-hash::before{content:"\e00c"}.icon-introduction-to-media::before{content:"\e00d"}.icon-lessons::before{content:"\e00e"}.icon-menu::before{content:"\e00f"}.icon-minus::before{content:"\e010"}.icon-multi-device-layouts::before{content:"\e011"}.icon-performance::before{content:"\e012"}.icon-plus::before{content:"\e013"}.icon-question::before{content:"\e014"}.icon-slash::before{content:"\e015"}.icon-star::before{content:"\e016"}.icon-tick::before{content:"\e017"}.icon-user-input::before{content:"\e018"}.highlight-module{overflow:hidden;margin-top:52px;margin-bottom:26px;position:relative}.highlight-module::after{background:#f0f0f0;content:"";height:100%;position:absolute;top:0;bottom:0;z-index:0;width:100%;right:0;left:0}.highlight-module ul,.highlight-module ol{padding-left:0}.highlight-module__container{box-sizing:content-box;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto;padding-bottom:78px;z-index:1;position:relative}@media only screen and (min-width: 620px){.highlight-module__container{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 800px){.highlight-module__container{padding-left:4.4%;padding-right:4.4%;max-width:864px}}.highlight-module__container::before{display:none}@media only screen and (min-width: 620px){.highlight-module__container::before{display:block;position:absolute;top:106px;right:45px;font-family:"icons";font-size:130px;line-height:1px;text-align:center;height:100%;width:30.3%;color:#ffffff}}.highlight-module--left .highlight-module__container::before{right:auto;left:45px}@media only screen and (min-width: 800px){.highlight-module__container::before{top:134px;width:22.2%;font-size:180px}.highlight-module--large .highlight-module__container::before{font-size:430px}}@media only screen and (min-width: 620px){.highlight-module__container{padding-bottom:52px}}@media only screen and (min-width: 800px){.highlight-module__container{min-height:208px}}.highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0;padding-top:26px}@media only screen and (min-width: 800px){.highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:110px;font-weight:300;line-height:1.19em;padding-top:0.2364em;padding-bottom:0}}@media only screen and (min-width: 800px){.highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0}}@media only screen and (min-width: 800px) and (min-width: 800px){.highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0}}.highlight-module__cta{display:block}.highlight-module--learning{color:#ffffff}.highlight-module--learning::after{background-color:#da2e75}.highlight-module--learning a{color:#ffffff;text-decoration:underline}.highlight-module--remember{color:#ffffff}.highlight-module--remember::after{background-color:#09829a}.highlight-module--remember a{color:#ffffff;text-decoration:underline}.highlight-module--code{overflow:visible;margin-bottom:52px}.highlight-module--code pre{margin:0;padding-top:26px;font-size:14px;line-height:26px;padding-bottom:0;padding-left:0;padding-right:0}.highlight-module--code pre span{margin:0;padding:0;display:inline-block}.highlight-module--code code{margin:0;padding:0;word-spacing:-2px;display:block}.highlight-module--code .highlight-module__container{padding-bottom:0}.highlight-module--code .highlight-module__cta{position:absolute;bottom:-26px}@media only screen and (min-width: 800px){.highlight-module--left::after{width:80%;right:20%}}@media only screen and (min-width: 800px){.highlight-module--right::after{width:80%;left:20%}}@media only screen and (min-width: 800px){.highlight-module--right.highlight-module--code::after{width:100%;left:0}}.highlight-module--inline{color:#404040;overflow:visible;margin:26px 0 0}.highlight-module--inline .highlight-module__container{padding-bottom:0}.highlight-module--inline .highlight-module__container::before{display:none}.highlight-module--inline .highlight-module__content{border-color:#e0e0e0;border-style:solid;border-width:1px;border-left-width:0;border-right-width:0;margin-bottom:-2px;padding:0 0 26px}.highlight-module--inline .highlight-module__title{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}@media only screen and (min-width: 800px){.highlight-module--inline .highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0}}.highlight-module--inline.highlight-module--remember .highlight-module__title,.highlight-module--inline.highlight-module--remember li::before{color:#09829a}.highlight-module--inline.highlight-module--learning .highlight-module__title,.highlight-module--inline.highlight-module--learning li::before{color:#da2e75}.highlight-module--inline::after{display:none !important}div.highlight>pre>code,code .highlight{background:transparent}div.highlight>pre>code .c,code .highlight .c{color:#999988;font-style:italic}div.highlight>pre>code .err,code .highlight .err{color:#a61717;background-color:#e3d2d2}div.highlight>pre>code .cm,code .highlight .cm{color:#999988;font-style:italic}div.highlight>pre>code .cp,code .highlight .cp{color:#737373}div.highlight>pre>code .c1,code .highlight .c1{color:#999988;font-style:italic}div.highlight>pre>code .cs,code .highlight .cs{color:#737373;font-style:italic}div.highlight>pre>code .gs,code .highlight .gd{color:#000000;background-color:#ffdddd}div.highlight>pre>code .gd .x,code .highlight .gd .x{color:#000000;background-color:#ffaaaa}div.highlight>pre>code .ge,code .highlight .ge{font-style:italic}div.highlight>pre>code .gr,code .highlight .gr{color:#aa0000}div.highlight>pre>code .gh,code .highlight .gh{color:#737373}div.highlight>pre>code .gi,code .highlight .gi{color:#000000;background-color:#ddffdd}div.highlight>pre>code .gi .x,code .highlight .gi .x{color:#000000;background-color:#aaffaa}div.highlight>pre>code .go,code .highlight .go{color:#888888}div.highlight>pre>code .gp,code .highlight .gp{color:#555555}div.highlight>pre>code .gu,code .highlight .gu{color:#aaaaaa}div.highlight>pre>code .gt,code .highlight .gt{color:#aa0000}div.highlight>pre>code .kt,code .highlight .kt{color:#445588}div.highlight>pre>code .m,code .highlight .m{color:#009999}div.highlight>pre>code .s,code .highlight .s{color:#da2e75}div.highlight>pre>code .na,code .highlight .na{color:teal}div.highlight>pre>code .nb,code .highlight .nb{color:#0086b3}div.highlight>pre>code .nc,code .highlight .nc{color:#445588}div.highlight>pre>code .no,code .highlight .no{color:teal}div.highlight>pre>code .ni,code .highlight .ni{color:purple}div.highlight>pre>code .ne,code .highlight .ne{color:#990000}div.highlight>pre>code .nf,code .highlight .nf{color:#990000}div.highlight>pre>code .nn,code .highlight .nn{color:#555555}div.highlight>pre>code .nt,code .highlight .nt{color:#09829a}div.highlight>pre>code .nv,code .highlight .nv{color:teal}div.highlight>pre>code .w,code .highlight .w{color:#bbbbbb}div.highlight>pre>code .mf,code .highlight .mf{color:#009999}div.highlight>pre>code .mh,code .highlight .mh{color:#009999}div.highlight>pre>code .mi,code .highlight .mi{color:#009999}div.highlight>pre>code .mo,code .highlight .mo{color:#009999}div.highlight>pre>code .sb,code .highlight .sb{color:#da2e75}div.highlight>pre>code .sc,code .highlight .sc{color:#da2e75}div.highlight>pre>code .sd,code .highlight .sd{color:#da2e75}div.highlight>pre>code .s2,code .highlight .s2{color:#da2e75}div.highlight>pre>code .se,code .highlight .se{color:#da2e75}div.highlight>pre>code .sh,code .highlight .sh{color:#da2e75}div.highlight>pre>code .si,code .highlight .si{color:#da2e75}div.highlight>pre>code .sx,code .highlight .sx{color:#da2e75}div.highlight>pre>code .sr,code .highlight .sr{color:#009926}div.highlight>pre>code .s1,code .highlight .s1{color:#da2e75}div.highlight>pre>code .ss,code .highlight .ss{color:#990073}div.highlight>pre>code .bp,code .highlight .bp{color:#737373}div.highlight>pre>code .vc,code .highlight .vc{color:teal}div.highlight>pre>code .vg,code .highlight .vg{color:teal}div.highlight>pre>code .vi,code .highlight .vi{color:teal}div.highlight>pre>code .il,code .highlight .il{color:#009999}.editorial-header{overflow:hidden}.editorial-header .breadcrumbs{color:#3372df}.editorial-header .breadcrumbs a{color:#3372df}@media only screen and (min-width: 620px){.editorial-header .container{position:relative}.editorial-header .container::before{content:"\e003";font-family:"icons";font-size:1000px;line-height:0;display:block;position:absolute;top:0;right:100%;color:#f0f0f0;margin:168px -35px 0 0}}.editorial-header__excerpt{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0;font-family:"Roboto Condensed", Helvetica, sans-serif}.editorial-header .tag{padding-top:52px}.editorial-header__subtitle{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0;padding-top:0;color:#3372df}@media only screen and (min-width: 800px){.editorial-header__subtitle{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0}}@media only screen and (min-width: 620px){.editorial-header__subtitle{padding-top:0;padding-bottom:26px}}.editorial-header__toc{margin-top:26px}.editorial-header__toc ol{padding-top:0}@media only screen and (min-width: 620px){.editorial-header__toc ol{padding-top:0}}.editorial-header__toc-title{font-family:"Roboto Condensed", Helvetica, sans-serif;border-bottom:1px solid #e0e0e0;margin-bottom:13px;padding-bottom:13px !important;color:#3372df}.summary-header{background-color:#3372df;padding-bottom:78px;color:#ffffff;margin-bottom:26px;box-shadow:inset 0 2px 0 0 #fff}.summary-header .breadcrumbs__link{color:#ffffff}.summary-header__anchor-list{margin-top:52px}.summary-header__anchors-item a{color:#ffffff}.related-guides{margin-top:78px;padding-bottom:50px;border-top:2px solid #e0e0e0;padding-top:50px}.related-guides__list .list-links{padding-top:0}.related-guides__list a{display:block}.related-guides__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0;padding-top:0}@media only screen and (min-width: 800px){.related-guides__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0}}@media only screen and (min-width: 620px){.related-guides__title{padding-top:0}}.related-guides__main-link{text-transform:uppercase}.related-guides__main-link::before{content:"#";display:inline-block;padding-right:2px}.in-this-guide{margin-top:-78px}.in-this-guide__title{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0;font-family:"Roboto Condensed", Helvetica, sans-serif;margin-bottom:26px}.articles-section{background:#f0f0f0;text-align:center;padding:26px 0 104px}.articles-count{color:#3372df;font-family:"Roboto Condensed", Helvetica, sans-serif;font-weight:400}.article-section__icon{top:-26px}@media only screen and (min-width: 620px){.article-section__icon{top:-39px}}.guides-section{background:#f0f0f0;text-align:center;padding:26px 0 104px}.page-header{text-align:center}.page-header .breadcrumbs{text-align:left;color:#3372df}.page-header .breadcrumbs a{color:#3372df}.page-header h3{color:#404040;padding-top:52px}.page-header__excerpt{position:relative;padding-top:0}.page-header__excerpt:last-child{padding-bottom:78px}.featured-section{background:#f0f0f0}.featured-spotlight{background:#404040;color:#ffffff;overflow:hidden;padding-bottom:77px;margin-top:52px}.featured-spotlight p{padding-bottom:26px}.featured-spotlight .cta--primary{color:#ffffff}.featured-spotlight .cta--primary:hover{color:#ffffff}.featured-spotlight__container{position:relative}@media only screen and (max-width: 619px){.featured-spotlight__img{padding-top:58.4%;padding-bottom:0;height:0;overflow:hidden;position:relative;width:100%}}.featured-spotlight__img img{margin:0 auto;display:block;width:100%;position:absolute;left:0;top:0;margin:0}@media only screen and (min-width: 620px){.featured-spotlight__img img{width:auto;max-width:none;left:109%}}@media only screen and (min-width: 800px){.featured-spotlight__img img{left:107.4%}}.quote__content{position:relative;font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;padding-top:104px;padding-left:26px}@media only screen and (min-width: 800px){.quote__content{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}}@media only screen and (min-width: 620px){.quote__content{padding-top:52px;padding-left:0}}.quote__content p{border-top:1px solid #e0e0e0;text-align:right;font-weight:500;margin-top:12px;padding-top:13px}.quote__content::before{content:open-quote;display:block;position:absolute;font-family:"Roboto Condensed", Helvetica, sans-serif;font-weight:700;color:#f0f0f0;top:90px;left:26px;font-size:260px}@media only screen and (min-width: 620px){.quote__content::before{top:225px;left:-210px;font-size:540px}}.article-nav{overflow:hidden;position:relative}.article-nav::before{content:"";border-left:2px solid #e0e0e0;height:100%;position:absolute;top:0;left:50%}.article-nav-link{padding:26px 32px;float:left;width:50%;position:relative}.article-nav-link::before{position:absolute;top:21px;font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:20px;font-weight:400}@media only screen and (min-width: 620px){.article-nav-link::before{top:25px;font-size:26px;display:block;padding:13px 10px;color:#ffffff;background:#3372df}}.article-nav p{padding:0;margin:0}.article-nav-link--prev{text-align:right}.article-nav-link--prev::before{font-family:"icons";left:32px}@media only screen and (min-width: 620px){.article-nav-link--prev p{padding-left:52px}}.article-nav-link--next::before{font-family:"icons";right:32px}@media only screen and (min-width: 620px){.article-nav-link--next p{padding-right:52px}}.article-nav-count{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0;font-weight:700}@media only screen and (min-width: 800px){.article-nav-count{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0}}@media only screen and (min-width: 620px){.article-nav-count{font-weight:400}}@media only screen and (min-width: 620px){.did-you-know ol{padding-top:0 !important}}.did-you-know .cta--primary{margin-top:26px;font-weight:500}.did-you-know>.g--half{position:relative;padding-left:0}@media only screen and (min-width: 620px){.did-you-know>.g--half{padding-left:32px}}.did-you-know__symbol{padding-bottom:312px}@media only screen and (min-width: 620px){.did-you-know__symbol{padding-bottom:26px}}.did-you-know__symbol::after{content:"\e014";color:#3372df;font-family:"icons";font-size:300px;top:150px;left:30%;position:relative;display:block;width:0}@media only screen and (min-width: 620px){.did-you-know__symbol::after{position:absolute;font-size:400px;top:200px;left:110%}}@media only screen and (min-width: 800px){.did-you-know__symbol::after{position:absolute;font-size:400px;top:200px;left:124%}}.toc__title{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;font-family:"Roboto Condensed", Helvetica, sans-serif;padding-bottom:13px;margin-bottom:12px;border-bottom:1px solid #e0e0e0}@media only screen and (min-width: 800px){.toc__title{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}}@media only screen and (min-width: 620px){.toc__title{padding-bottom:13px;margin-bottom:13px}}.toc__list{padding-top:0;border-bottom:1px solid #e0e0e0;padding-bottom:12px;margin-bottom:13px}.toc__list a{display:block}.toc__sublist{padding-top:0}.next-lessons{background:#404040;padding:26px 26px 52px;margin-top:26px;color:#ffffff;position:relative}@media only screen and (min-width: 620px){.next-lessons h3 i{display:none}}.next-lessons::before,.next-lessons::after{color:rgba(255,255,255,0.5);position:absolute;display:none}@media only screen and (min-width: 620px){.next-lessons::before,.next-lessons::after{display:inline-block}}@media only screen and (min-width: 620px){.next-lessons::before{content:attr(data-current-lesson);font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:16px;font-weight:400;line-height:1;background:#404040;display:inline-block;padding:5px 7px;right:127px;top:143px;z-index:1;color:rgba(255,255,255,0.5)}}@media only screen and (min-width: 800px){.next-lessons::before{font-size:20px;padding-left:15px;padding-right:15px;top:126px;right:230px}}@media only screen and (min-width: 620px){.next-lessons::after{content:"\e00e";font-family:"icons";font-size:150px;right:40px;top:185px}}@media only screen and (min-width: 800px){.next-lessons::after{font-size:210px;right:120px}}@media only screen and (min-width: 620px) and (max-width: 799px){.g-medium--1{float:left;margin-right:4.5%;width:30.3%}.g-medium--push-1{margin-left:34.8%}.g-medium--pull-1{margin-right:34.8%}.g-medium--2{float:left;margin-right:4.5%;width:65.1%}.g-medium--push-2{margin-left:69.6%}.g-medium--pull-2{margin-right:69.6%}.g-medium--3{float:left;margin-right:4.5%;width:99.9%;margin-right:0}.g-medium--full{float:left;margin-right:4.5%;margin-right:0;width:100%}.g--third{float:left;margin-right:4.5%;width:30.3%}.g--half,.g-medium--half{float:left;margin-right:4.5%;width:47.75%}.g-medium--last{margin-right:0}.g-medium--last+.g-medium--half{clear:left}.g--pull-half{margin-right:52.25%}}@media only screen and (min-width: 800px){.g-wide--1{float:left;margin-right:3.7%;width:22.2%}.g-wide--push-1{margin-left:25.9%}.g-wide--pull-1{margin-right:25.9%}.g-wide--2{float:left;margin-right:3.7%;width:48.1%}.g-wide--push-2{margin-left:51.8%}.g-wide--pull-2{margin-right:51.8%}.g-wide--3{float:left;margin-right:3.7%;width:74%}.g-wide--push-3{margin-left:77.7%}.g-wide--pull-3{margin-right:77.7%}.g-wide--4{float:left;margin-right:3.7%;width:99.9%;margin-right:0}.g-wide--last{margin-right:0}.g-wide--full{float:left;margin-right:3.7%;margin-right:0;width:100%}.g--third{float:left;margin-right:3.7%;width:30.8%}.g--half,.g-wide--half{float:left;margin-right:3.7%;width:48.15%}.g--pull-half{margin-right:51.85%}}.g--last{margin-right:0}.g--centered{float:none;margin-left:auto;margin-right:auto}.grid-overlay{display:none;pointer-events:none}.debug .grid-overlay{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto;position:absolute;top:0;bottom:0;left:0;right:0;height:100%;display:block}@media only screen and (min-width: 620px){.debug .grid-overlay{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 800px){.debug .grid-overlay{padding-left:4.4%;padding-right:4.4%;max-width:864px}}.debug .grid-overlay [class*="g-"]{height:100%;background-color:rgba(89,89,89,0.2)}@media only screen and (min-width: 620px) and (max-width: 799px){.debug .grid-overlay .g-wide--last{display:none}}@media only screen and (max-width: 619px){.debug .grid-overlay{display:none}}h1,h2,h3,h4,h5,p{margin:0}.small,small{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0}.base,p,ul,ol{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0}.medium,h4{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0}@media only screen and (min-width: 800px){.medium,h4{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}}.large,h3{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}@media only screen and (min-width: 800px){.large,h3{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0}}.xlarge,h2{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0}@media only screen and (min-width: 800px){.xlarge,h2{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0}}.xxlarge,h1{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0}@media only screen and (min-width: 800px){.xxlarge,h1{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0}}.huge{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0}@media only screen and (min-width: 800px){.huge{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:110px;font-weight:300;line-height:1.19em;padding-top:0.2364em;padding-bottom:0}}li>p{padding-top:0}.button,.button--primary,.button--secondary,.button--secondary-variation{display:inline-block;padding:12px 32px;margin-bottom:13px;margin-top:13px;min-height:26px;text-align:center;font-family:"Roboto Condensed", Helvetica, sans-serif;font-weight:600;text-decoration:none;outline:0;-webkit-transition:none;transition:none}.button:hover,.button--primary:hover,.button--secondary:hover,.button--secondary-variation:hover{background:#4d4d4d;color:#ffffff;border:1px solid #4d4d4d;text-decoration:none}.button--primary{background:#4285f4;color:white;border:1px solid #1266f1}.button--secondary{background:white;color:#3372df;border:1px solid #e6e6e6}.button--secondary-variation{background:white;color:#3372df;border:1px solid #e6e6e6;border-color:transparent}ul,ol{list-style:none;margin:0}@media only screen and (max-width: 619px){ul,ol{padding-left:0}}ul li{position:relative;padding-left:16px}ul li::before{font-family:"icons";font-size:13px;display:block;font-weight:400;position:absolute;top:0;left:0;line-height:26px}ul li::before{font-size:4px}ol{counter-reset:list}ol>li{position:relative;padding-left:32px}ol>li::before{counter-increment:list;content:"0" counter(list);color:inherit;font-weight:400;display:inline-block;position:absolute;left:0}ol>li:nth-child(10n) ~ li::before,ol>li:nth-child(10n)::before{content:counter(list)}ul ol,ol ul{padding-top:0}ul.list-links li::before{display:none}ul.list-links a{font-weight:400}ul.list-links a::before{font-family:"icons";font-size:13px;display:block;font-weight:400;position:absolute;top:0;left:0;line-height:26px}ul.list-links a::before{font-size:4px}ul.list-links.list-links--primary a{font-weight:400;font-family:"Roboto Condensed", Helvetica, sans-serif;line-height:1;text-decoration:none}ul.list-links.list-links--primary a::before{font-family:"icons";font-size:13px;display:block;font-weight:400;position:absolute;top:0;left:0;line-height:26px}ol.list-links li::before{display:none}ol.list-links li a{display:inline-block;font-weight:300}ol.list-links li a::before{counter-increment:list;content:"0" counter(list);color:inherit;font-weight:400;display:inline-block;position:absolute;left:0}ol.list-links li:nth-child(10n) ~ li a::before,ol.list-links li:nth-child(10n) a::before{content:counter(list)}ol.list-links.list-links--secondary a::before{display:none}.list-links--secondary{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;padding-left:0}.list-links--secondary li{padding-left:0}.list-anchor{padding-left:0}.list-anchor li{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;padding-top:0;padding-left:0}.list-anchor li::before{display:none}.list-anchor a{line-height:1;display:inline-block;padding-left:16px}.list-anchor a::before{font-family:"icons";font-size:13px;display:block;font-weight:400;position:absolute;top:0;left:0;line-height:26px}.list-anchor a::before{font-size:4px}@media only screen and (min-width: 620px){.list-small li{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;padding-top:0}}.list-centered{text-align:center;padding-left:0}.featured-list{padding-top:78px;padding-bottom:78px}.featured-list__item{background:#ffffff;padding-left:0;padding-top:26px;padding-bottom:26px;margin-top:26px}@media only screen and (min-width: 620px){.featured-list__item{min-height:338px;padding:52px 32px}}.featured-list__item:first-child{margin-top:0}.featured-list__item p{margin-bottom:26px}.featured-list__img-wrapper{display:none;position:relative;padding-top:26px;margin:0 -5%}@media only screen and (min-width: 620px){.featured-list__img-wrapper{display:block;padding-top:0;margin:0}}@media only screen and (min-width: 620px){.featured-list__img{padding-top:60.8%;padding-bottom:0;height:0;overflow:hidden;position:absolute;width:100%}}.featured-list__img img{display:block;margin:0 auto;max-width:100%}@media only screen and (min-width: 620px){.featured-list__img img{margin:0;position:absolute;top:0;height:100%;width:100%;left:0}}.related-guides-list{font-family:"Roboto Condensed", Helvetica, sans-serif;padding-top:0;padding-left:0}@media only screen and (min-width: 620px){.related-guides-list{padding-top:26px}}@media only screen and (min-width: 800px){.related-guides-list{padding-top:0}}.related-guides-list p{padding-top:0}.related-guides-list .tag{padding-top:0}.related-guides-list li{padding-top:26px;padding-bottom:25px;border-bottom:1px solid #e0e0e0}.related-guides-list li:last-child{border-color:transparent}@media only screen and (min-width: 620px){.related-guides-list li{padding-top:0;padding-bottom:0;border-color:transparent}}.list--reset{padding-left:0}.list--reset li{padding-left:0}.list--reset.list-links a::before,.list--reset li::before{display:none !important}.list-lessons{padding-left:0}.list-lessons a{color:#ffffff}.list-lessons .current,.list-lessons .current a{text-decoration:none;cursor:default}.list-lessons .current .icon{font-size:13px;display:inline-block;background:rgba(0,0,0,0.2);border-radius:100%;width:26px;line-height:26px;text-align:center;margin-left:7px}.list-guides-intro{margin-bottom:52px}@media only screen and (max-width: 619px){.list-guides-intro{padding-top:52px}}.list-guides-intro li{border-bottom:1px solid #e0e0e0;padding-bottom:51px;margin-bottom:52px}@media only screen and (min-width: 620px){.list-guides-intro li{border-color:transparent;padding-bottom:0}}.list-guides-intro li:last-child{border-bottom:transparent;margin-bottom:0}a{color:#3372df}a:hover{text-decoration:none}.cta--primary{font-family:"Roboto Condensed", Helvetica, sans-serif;color:#3372df;font-weight:400;display:inline-block;line-height:1;text-decoration:none}.cta--primary:hover{color:#404040}.cta--primary::before{display:inline-block;padding-right:10px;font-family:"icons";line-height:25px;font-size:13px;content:"\e005"}.cta--secondary{font-family:"Roboto Condensed", Helvetica, sans-serif;color:#3372df;font-weight:400;display:inline-block;line-height:1}.cta--secondary:hover{color:#404040}table{margin-top:26px;width:100%}table thead{background:#3372df;color:#ffffff}table th{text-align:center;display:none;font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0}@media only screen and (min-width: 800px){table th{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}}@media only screen and (min-width: 620px){table tr{border-bottom:1px solid #ffffff}}table tbody{background:#f0f0f0}table td{display:block;padding-top:13px;padding-bottom:13px}table td::before{content:attr(data-th) " :";display:inline-block;color:#ffffff;background:#3372df;border-right:2px solid #ffffff;position:absolute;top:0;left:0;bottom:0;width:100px;max-height:100%;font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:16px;font-weight:400;padding-left:13px;padding-top:13px}@media only screen and (min-width: 620px){table td::before{display:none}}table th,table td{position:relative;padding-left:140px}@media only screen and (min-width: 620px){table th,table td{display:table-cell}}@media only screen and (min-width: 620px){table th{padding:26px;padding-top:13px;padding-bottom:12px}}@media only screen and (min-width: 620px){table td{padding:26px;padding-bottom:25px}}td:last-child::after{content:"";display:block;background:#ffffff;height:1px;left:0;position:absolute;bottom:0;width:100%}@media only screen and (min-width: 620px){td:last-child::after{display:none}}.table-2 col{width:344px}@media only screen and (min-width: 800px){.table-2 col{width:432px}}@media only screen and (min-width: 620px){.table-2 th:first-child,.table-2 td:first-child{border-right:2px solid #ffffff}}.table-3 col{width:229.3333333333px}@media only screen and (min-width: 800px){.table-3 col{width:288px}}@media only screen and (min-width: 620px){.table-3 th:nth-child(2),.table-3 td:nth-child(2){border-left:2px solid #ffffff;border-right:2px solid #ffffff}}.table-4 col{width:172px}@media only screen and (min-width: 800px){.table-4 col{width:216px}}@media only screen and (min-width: 620px){.table-4 th:nth-child(2),.table-4 th:nth-child(3),.table-4 td:nth-child(2),.table-4 td:nth-child(3){border-left:2px solid #ffffff;border-right:2px solid #ffffff}}img,video,object{max-width:100%}.content img{margin-top:26px;margin-bottom:26px}.breadcrumbs{display:none;position:relative;z-index:1}@media only screen and (min-width: 620px){.breadcrumbs{display:block}}.breadcrumbs p{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;padding-top:26px}.breadcrumbs__link{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;color:black;font-weight:400;padding-top:0}@media only screen and (min-width: 620px){.breadcrumbs__link{padding-top:0}}.subsection-title{color:#404040;margin-top:52px}.subsection-number{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;padding-top:0;display:block}.articles-list{padding-left:0}.articles-list__item{padding-bottom:52px;padding-left:0}.articles-list__item:last-child{padding-bottom:53px}.articles-list__item::before{content:"";display:block;width:40%;height:1px;box-shadow:inset 0 1px 0 0 #e0e0e0;margin-right:0;margin-left:30%}.articles-list__item h3 a:hover{text-decoration:none}.articles-list__item p{margin-top:26px;margin-bottom:26px}.articles-list__item:first-child{padding-top:0}@media only screen and (min-width: 620px){.articles-list__item:first-child{padding-top:24px}}.articles-list__item:first-child::before{display:none}.guides-list{overflow:hidden}@media only screen and (min-width: 620px){.guides-list{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-top:52px}}.guides-list__item{padding:0;background:#ffffff;margin-top:26px;margin-bottom:0}@media only screen and (min-width: 620px){.guides-list__item{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}}.guides-list__item h3{margin:0 32px}.guides-list__item p{margin:26px 32px 0}@media only screen and (min-width: 620px){.guides-list__item .primary-content{-webkit-flex:1;-ms-flex:1;flex:1}}.guides-list__item .secondary-content{position:relative;margin-top:51px;border-top:1px solid #e0e0e0}@media only screen and (min-width: 620px){.guides-list__item .secondary-content{width:100%}}.guides-list__item .secondary-content .icon-circle{position:absolute;top:-28px;left:50%;margin-left:-21px;border:2px solid #ffffff}.guides-list__item .secondary-content .icon-circle i{font-size:23px}.guides-list__item ol{margin:26px 0 0;padding:52px 0 52px;margin-top:0}.guides-list__item::before{display:none}.icon-circle,.icon-circle--large{height:0;width:0;background:#737373;display:block;position:relative;border-radius:100%;font-size:0;padding:22px;margin:4px auto}.icon-circle i,.icon-circle span,.icon-circle--large i,.icon-circle--large span{position:absolute;line-height:0px;top:50%;width:100%;left:0;text-align:center;color:#ffffff;font-size:26px}.icon-circle span,.icon-circle--large span{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:700}@media only screen and (min-width: 620px){.icon-circle span,.icon-circle--large span{font-size:42px}}.icon-circle--large{margin-top:0;margin-bottom:0;padding:26px;position:relative}.icon-circle--large i{font-size:26px}@media only screen and (min-width: 620px){.icon-circle--large i{font-size:42px}}@media only screen and (min-width: 620px){.icon-circle--large{padding:37px;border:2px solid #ffffff}a .icon-circle--large{padding:38px;box-shadow:inset 0px 0px 0px 1px rgba(255,255,255,0.42);border:1px solid;-webkit-transition:all 100ms linear;transition:all 100ms linear;-webkit-transform:translateZ(0);transform:translateZ(0)}.no-touch a:hover .icon-circle--large{box-shadow:inset 0px 0px 0px 1px #ffffff;-webkit-transform:scale(1.1);transform:scale(1.1)}}.icon-circle--nav{height:0;width:0;background:#737373;display:block;position:relative;border-radius:100%;font-size:0;padding:13px;margin:0 auto}@media only screen and (min-width: 620px){.icon-circle--nav{padding:22px;margin-top:4px;margin-bottom:4px}}.icon-circle--nav i{position:absolute;line-height:1px;top:50%;width:100%;left:0;text-align:center;color:#ffffff;font-size:16px}@media only screen and (min-width: 620px){.icon-circle--nav i{font-size:26px}}.theme--multi-device-layouts .themed{color:#297ea9}.theme--introduction-to-media .themed{color:#cf423a}.theme--user-input .themed{color:#2c8566}.theme--performance .themed{color:#7b5294}.theme--multi-device-layouts .themed--background,.theme--multi-device-layouts .themed--background.next-lessons::before{background-color:#297ea9}.theme--introduction-to-media .themed--background,.theme--introduction-to-media .themed--background.next-lessons::before{background-color:#cf423a}.theme--user-input .themed--background,.theme--user-input .themed--background.next-lessons::before{background-color:#2c8566}.theme--performance .themed--background,.theme--performance .themed--background.next-lessons::before{background-color:#7b5294}.theme--multi-device-layouts .themed--hover:hover{color:#297ea9}.theme--introduction-to-media .themed--hover:hover{color:#cf423a}.theme--user-input .themed--hover:hover{color:#2c8566}.theme--performance .themed--hover:hover{color:#7b5294}.theme--multi-device-layouts .themed--hover-secondary:hover{color:#89c4e2}.theme--introduction-to-media .themed--hover-secondary:hover{color:#edb8b5}.theme--user-input .themed--hover-secondary:hover{color:#78d2b3}.theme--performance .themed--hover-secondary:hover{color:#c4add2}.article--multi-device-layouts .article-container h1,.article--multi-device-layouts .article-container h2{color:#297ea9}.article--introduction-to-media .article-container h1,.article--introduction-to-media .article-container h2{color:#cf423a}.article--user-input .article-container h1,.article--user-input .article-container h2{color:#2c8566}.article--performance .article-container h1,.article--performance .article-container h2{color:#7b5294}.nav-theme--multi-device-layouts .themed--hover:hover{color:#297ea9}.nav-theme--introduction-to-media .themed--hover:hover{color:#cf423a}.nav-theme--user-input .themed--hover:hover{color:#2c8566}.nav-theme--performance .themed--hover:hover{color:#7b5294}.nav-theme--multi-device-layouts .themed{color:#297ea9}.nav-theme--introduction-to-media .themed{color:#cf423a}.nav-theme--user-input .themed{color:#2c8566}.nav-theme--performance .themed{color:#7b5294}.nav-theme--multi-device-layouts .themed--background{background-color:#297ea9}.nav-theme--introduction-to-media .themed--background{background-color:#cf423a}.nav-theme--user-input .themed--background{background-color:#2c8566}.nav-theme--performance .themed--background{background-color:#7b5294}.page--styleguide .styleguide__module-title{margin-bottom:26px}.page--styleguide section{margin-bottom:52px;border-bottom:1px solid #ccc;padding-bottom:77px}.page--styleguide .styleguide__color-list{text-align:center}.page--styleguide .styleguide__color-list li{border-bottom:52px solid;margin-bottom:26px;position:relative}.page--styleguide .styleguide__breadcrumb .breadcrumbs{display:block}.page--styleguide .styleguide__lists ul,.page--styleguide .styleguide__lists ol{margin-bottom:26px}.page--styleguide .styleguide__inverted-block{background:#e8e8e8;padding:0 13px}.page--styleguide .styleguide__theme-block{background:#297ea9;padding:0 13px}.demo{margin-bottom:26px;margin-top:26px}.demo [class*="g-"]{background-color:#eeeeee;position:relative;margin-bottom:26px;min-height:156px}.demo [class*="g-"]::before,.demo [class*="g-"]::after{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;display:block;margin:0 10px}.demo [class*="g-"]::before{content:"HTML classes: ";font-weight:700}.demo [class*="g-"]::after{content:attr(class);word-spacing:15px}.page--resources .article-section__icon,.page--resources .articles-count,.page--resources .guides-list__item .secondary-content{display:none}.page--resources .primary-content{padding-top:26px;padding-bottom:52px}.page--resources .primary-content p{margin-top:0}.clear::before,.clear::after{content:"";display:table}.clear::after{clear:both}.color--blue{color:#3372df}.color--red{color:#cb4437}.color--green{color:#0f9d58}.color--yellow{color:#f4b400}.color--blue-secondary{color:#b7cdf4}.color--red-secondary{color:#ebb6b0}.color--green-secondary{color:#56efa5}.color--yellow-secondary{color:#ffd45b}.color--gray-background{color:#f0f0f0}.color--gray-keyline{color:#e0e0e0}.color--gray{color:#737373}.color--gray-dark{color:#404040}.color--text{color:#404040}.color--highlight{color:#3372df}.color--warning{color:#ffd45b}.color--danger{color:#cb4437}.color--muted{color:#737373}.color--remember{color:#09829a}.color--learning{color:#da2e75}.color--layouts{color:#297ea9}.color--user{color:#2c8566}.color--media{color:#cf423a}.color--performance{color:#7b5294}.color--layouts-secondary{color:#89c4e2}.color--user-secondary{color:#78d2b3}.color--media-secondary{color:#edb8b5}.color--performance-secondary{color:#c4add2}.text-divider{position:relative;margin-bottom:26px}.text-divider::after{content:"";display:block;position:absolute;width:40%;height:1px;box-shadow:0 1px 0 0 #e0e0e0;left:30%;bottom:-13px}.text-divider.xlarge{margin-bottom:52px}.text-divider.xlarge::after{bottom:-26px}.text-divider.xxlarge{margin-bottom:78px}.text-divider.xxlarge::after{bottom:-39px}.text-divider.huge{margin-bottom:78px}.text-divider.huge::after{bottom:-39px}.centered{text-align:center}.tag{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;font-family:"Roboto Condensed", Helvetica, sans-serif;text-transform:uppercase;font-weight:700;display:inline-block;text-decoration:none}.tag:hover{color:#404040}.tag::before{content:"# ";display:inline-block}html,body{width:100%;height:100%;margin:0;padding:0}body{position:relative;font-family:'Roboto Condensed', 'Helvetica', 'Arial', sans-serif;font-weight:300;background-color:#FFFFFF;box-sizing:border-box;min-height:100%}body.open{overflow:hidden}.app-bar{display:block;width:100%;position:fixed;top:0;left:0;background-color:#4285f4;overflow:hidden;z-index:1}.app-bar-container{display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;height:60px;position:relative;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;margin:0 auto}.app-bar.open,.app-bar.open ~ main{-webkit-transform:translate(250px, 0);transform:translate(250px, 0)}.app-bar .logo{-webkit-flex:1;-ms-flex:1;flex:1;font-size:2em;line-height:60px;margin:0 16px;padding:0;color:#fefefe;float:none;max-width:none;font-weight:300}.app-bar .logo a{text-decoration:none;color:inherit;font-weight:normal}.app-bar-actions{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;z-index:2}.app-bar button{width:60px;height:60px;background-image:none;background-color:transparent;border:none;padding:0;-webkit-transition:background-color 0.2s ease-out;transition:background-color 0.2s ease-out;-webkit-tap-highlight-color:transparent}.app-bar button img{width:60px;height:60px}.app-bar button:hover{background-color:rgba(255,255,255,0.1)}.app-bar button:focus{background-color:rgba(255,255,255,0.2);outline:0}.app-bar button:active{background-color:rgba(255,255,255,0.4)}button.menu img{height:24px;width:24px}.promote-layer{-webkit-backface-visibility:hidden;backface-visibility:hidden}.base,p,ul,ol{font-size:19px}.navdrawer-container{z-index:1;position:fixed;top:0;bottom:0;width:250px;height:100%;background-color:#3367D6;color:#fefefe;-webkit-transform:translate(-250px, 0);transform:translate(-250px, 0);overflow-y:auto}.navdrawer-container.open{-webkit-transform:translate(0, 0);transform:translate(0, 0)}.app-bar,.navdrawer-container,main{-webkit-transition:-webkit-transform 0.3s ease-out;transition:transform 0.3s ease-out}.navdrawer-container h4,.navdrawer-container ul li a{height:auto;padding:17px 20px;line-height:1.4}.navdrawer-container h4{background-color:white;color:#3367D6}.navdrawer-container ul{padding:0;margin:0;list-style-type:none}.navdrawer-container ul li a{display:block;text-decoration:none;color:white;-webkit-transition:background-color 0.2s ease-out;transition:background-color 0.2s ease-out;white-space:nowrap}.navdrawer-container ul li{border-bottom-style:solid;border-width:1px;border-color:white;padding:0}.navdrawer-container ul li::before{content:none}.navdrawer-container ul li a:hover{background-color:rgba(255,255,255,0.2)}.navdrawer-container ul li a:focus{background-color:rgba(255,255,255,0.3);outline:0}.navdrawer-container ul li a:active{background-color:rgba(255,255,255,0.4)}main{margin:0 auto;padding:60px 16px 16px 16px;min-height:100%}@media all and (min-width: 990px){.app-bar{position:relative}.app-bar.open,.app-bar.open ~ main{-webkit-transform:translate(0px, 0);transform:translate(0px, 0)}.app-bar-container{display:block;height:130px;max-width:864px;padding:0 16px;box-sizing:border-box;background-color:#4285f4}.app-bar .logo{float:left;margin:0;padding:0;line-height:130px;font-size:46px}.app-bar-actions{float:right}.app-bar::after{content:' ';display:block;height:0;overflow:hidden;clear:both}button.menu{display:none}nav{display:block;margin-top:130px}.navdrawer-container{position:relative;width:100%;height:auto;margin-top:130px;-webkit-transform:translate(0, 0);transform:translate(0, 0);-webkit-transition:none;transition:none;overflow-y:auto}.navdrawer-container h4{display:none}.navdrawer-container ul{display:-webkit-flex;display:-ms-flexbox;display:flex;max-width:864px;margin:0 auto;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.navdrawer-container ul li{border:none}main{max-width:864px;padding-top:0;min-height:initial}body{overflow-y:scroll}.navdrawer-container{position:relative;margin-top:0}}@font-face{font-family:'Roboto Condensed';font-style:normal;font-weight:300;src:url(/fonts/RobotoCondensed-Light.eot);src:local("Roboto Condensed Light"),local("RobotoCondensed-Light"),url(/fonts/RobotoCondensed-Light.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-Light.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:normal;font-weight:400;src:url(/fonts/RobotoCondensed-Regular.eot);src:local("Roboto Condensed Regular"),local("RobotoCondensed-Regular"),url(/fonts/RobotoCondensed-Regular.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-Regular.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:normal;font-weight:700;src:url(/fonts/RobotoCondensed-Bold.eot);src:local("Roboto Condensed Regular"),local("RobotoCondensed-Bold"),url(/fonts/RobotoCondensed-Bold.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-Bold.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:italic;font-weight:300;src:url(/fonts/RobotoCondensed-LightItalic.eot);src:local("Roboto Condensed Light Italic"),local("RobotoCondensed-LightItalic"),url(/fonts/RobotoCondensed-LightItalic.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-LightItalic.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:italic;font-weight:400;src:url(/fonts/RobotoCondensed-Italic.eot);src:local("Roboto Condensed Italic"),local("RobotoCondensed-Italic"),url(/fonts/RobotoCondensed-Italic.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-Italic.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:italic;font-weight:700;src:url(/fonts/RobotoCondensed-BoldItalic.eot);src:local("Roboto Condensed Bold Italic"),local("RobotoCondensed-BoldItalic"),url(/fonts/RobotoCondensed-BoldItalic.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-BoldItalic.woff) format("woff")} diff --git a/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons-hinted.ttf b/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons-hinted.ttf deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.eot b/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.eot deleted file mode 100644 index ee360b9b27cb30a82a6d9f0fad93008dc237c3cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3528 zcmds4Z){W76+h?MelI}4F^>NbLh}+kF%-rB9fvHi1RA3@P62JD0n(L#W9*DLA$g2K zrEJow2~Cxt6G}_j1WG>?b=4%;Rw_1ap4JbP1$8Y<>bf#9@nw~YG_6qW19JAe*EbNR zYWu$XeBU|uoO91P_ndR@yS}oVD2UFak!Tv}Hi>|8mj#yHUL8}Ng5Xr!_4B1q7HALQ zQYzAZ8mAIXfmlleG(tJh4$~OMChf#{61<|6F)4~CMqvq~;1fNn0R&-iIem|8v^|sg z=D@f2K06IU4XBOVz7dH>y9PEuXb|JQ`^SbS$a(wsScwVR=KbHXOmguPM7A9G_5;IH z6Z7-X1chid2M!+1e^K-OJK&!qa(rGG8O~Afz4hRIir!HG!S)ZvI=LR>U}4O9A@p5x zVf-$}g@fb!hwFZ`@-56SVB9%2{K5q7qhatnF*ZxXV((soC2dxFSNjr)6?s0*&migsg)cBgx-S}b zx)Z;kJ3j5cXw!hw1)Cr{1o@(&^Zo9N2=|?M!j*7^60U&j_>p{`pQ-%RCF(<@L{&ZV z>Txx@H0sf)A_FfnvRm#5QM(>TYs#U~JRX#H`SrQE*RQGh@VYGO+m&z|0e9i*)x!H+ zuAl~lDD-op%1^rkHh1Fesk5g}oh?f>3w9pLK!+{h780jW^i>U2KNtDpNVPgVESd17 zZSM57Yo}!qKUj+a*L)muv%&mcccr_#TLLZ%oZpi#VH}mH=7cCh)N1I4&j{&G4usl5 zMkw7D;Z(XK9ZLH;zRn4s*O&Gg-X^xkJCbcJdc8&icAMEgP^+6grqkZv{+O=y_iK7n zd)Dp*saDUnH|bio^3hOl@6hIR4+vR@2ANs|GDaI&ydn`B^4pLg|E&PWX&K`Y(q@ zM-LT$F5mj)YOBVBk3;8bY7+7ggihHLMgo%)o`CFu5UAHS_%r^ecR8QlP>F!-YQy~rCCQYrJ99|w;G|9C8T3_l5<^82CB zj;=xHG<2>cFPZo_B0TQ4KnqGUu#uA;iMY?^ONWfKcMaF;o>1G(%=ni4t}UA#`pjsl zf3D$X!;1B*IAzl^8K&%}O}lNj(V6X)`@S#zxk%z`nx@<9R|`82YG2lm8`WdO>TYH- zH^mA?_&AVJay*C}m=r`!B(WhjaVi;tQ@RHmB`tjNdg|dJ9*=>7$+=dp_czoz*LclC z%#l=IHWg{`uk+RzMxl_6u4;I!Zta@Jm9EA{ZENeg@Vc#!x3+j!xSdTe?-21u&Z~7z zjMIRvD{qSvMR<%R`7(zq;0^V6{;Bk z&%nP)TsMbtvk;e16F0M?c=rO&No*S~qGRBfa2+-22;LSIfMw+6)RJ(L4q&!Pad}BK zX)PoyJQLJ~lQ}|pB`aW6HVmzKNS83rqIC$<-dP)@Dg6i%ea=8^9puy9lLlX zySbh{?8TSX&#R2XrD7ipD;QTWpY%6?4Qk16{xWj`kVN8rXPqr)OBa~o$r5ODE-gnt7wpKRU$ diff --git a/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.svg b/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.svg deleted file mode 100644 index 2293e8b4250..00000000000 --- a/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.ttf b/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.ttf deleted file mode 100644 index 5c9b6b90b241c9dbd88c08a3d9e9b9e884517210..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3364 zcmds4|8G;*6+h?MelL)K<2e435So|RiJ>U|?l@$ICD0hPaSCWF4Un!RaU44%PDmc3 zP$`?VYC=;b=!DWzHi6O~R&CWJ*j6ewZJyR2+ALAm!lbS%6BECzQjw;$RQmxr``qUn zl6}$sfZdmS&$;KGd(OG%eD3oLF%fN|Z;^!#q|;v=`1-M@=OCzpv}ylWLeX&dz)m6_ z#QfOksfwhm(JM$1&{>C4{Rz2qa{G{<*;G5*Y{4LD$$EQYzYkyVuBka#(-ZeS= z+%%2QFxI;;*NelGV}Fsx~<*+OBmnPQ>HrmTm8ro_s>;m^e? zXE+DRK1uIW1HFJ~NkyJkTkR?XdLY-ArP3X~$_&=ERLb95fH`v+HXBS-ldpWy}mCBMUe zSGFlB#ZX>Q7L>P?FHl%f=ZpLlvaV6^DpM$RO|#Oy=vCGBaq5~y0ZUgcLTnS_YnsXr zQrD2~d(oI9<_N?bKF8Tpxg0-L{;@;gLzG0K9(8p&S{w@XC{#8RFDi1xyb%JsE?Zl| zrqBu=z`OM7($cHTazCOj34A+ZPR-}cFD~Za9aUvmoHqtaN%;v zG_&ewO$RnCKBv&Q0MJ(~RN`D0i!IS+bFsOISlX8^E-zm+LHzJ68bb4Mz{wi(+o^IY zl`;vJ1kZ1qgK!Qc$~^%J5w&Tm=FtMGoqd7!fEGx$hd7b!Oa_vk&M$M!x=`A*xX`9nGqeDSt53+dH)9%0ofM zra-4ggN{~%ZHg_Ev09om_3+1GyD=prj8a_9bG5 zXj6Q!OwUvO$=wFtJpxt0#tnJKYO<3P zIBRjVv|(^2T3j~S`9?X-uaylSr^`3Y?g0kL!ylA`{7fj64+aatpooF`OiYWMAtR1; zHU#i1osCT9l}zU4Oa}Vm9{d16xhr-!{n|ZLGC#b?YaXLy5jjBGl;J?yl0bd_EIyXndr0+t#K! zM^lrsuWfs9`@TopTHTwS_U0E4ihQHy6?{ z?ug#JS-3Tne<{z`%a2F-y2PI8M+5FWxDNq*n$)YU?eWfNCvLx6yal4}ibT%+a?ahY z;nvph)`|Z9iT+>D4Gzu?K3F_=Zt+}s;nw{8t@#hdYHJ#c{SzZt9Gv?(7SAnS!rJ^T zM7o)NVj>SL?WMDlXQ1vw$%|X`spKuBb3*b~vhj%IZB)zOmAnf14{>g`Zh+12pjUXt zU0jm9LN)Yf$y=z0K9jtaHu53K+u$oNdE8^Zg!pD?3}0gg#w<`WLZ>nIg3p@Veww98 ztQV;O`6-MB<-w(C3Npi_Gc=CfIz{o-6b9V}4Fk_Kb>qz(qMXzfw4xh?)f}{o*k{mo zq-kbs*ci*|Bd7J=Z1%Lie|B=XSkO-ujJ%$nDjMmjnej0_8Vu{(@`f?p9SY?j%?W96 zHWw_888A|yQPa~b*wLvX$bfmO0-eMeXkaW`I0^c{LhnZSYi4vDK&LM1pagmphl@}g z2L2_WZryaIck5jpiH>ME0*y5jtC1W+Br`a5!HiIcDPc_HOFTN!p|P3S!c~R5T6S<9JGq`+?8Yyx zmm9Q`#X=t(OB$6lCTU#KgruF4CME5Xbf=`flJ1doucVJj+9zqcLL*^GrT>WZACdke i(tkwyk4XO!=|3X=kH8nJnH?5sS=zPmo}lahNBAcIoLm+F diff --git a/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.woff b/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.woff deleted file mode 100644 index 77e1d5da0f60803974f63524e1c761142f2fdd82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2292 zcmY*ac{r478-HdorV};U8kB~RGBK7SDH%&O88a;?q8Wpx8e^NX*9@sFokT=gLbf^C zQkJ1?lN6FdNBOche3H{3WSQ^P>7Va;uityWzu$dd&;7fe_qy&UkYZ~KU;tX^8L)0O z%AWX_uYUjkvb8-y1^{LasVWdQU7$H#K4@)Y3u!cnZ-#&ahX9gtT;CAVxDY2npb^Z- zdl=qyUr1|%I1!3Ouzt9SafyQi0FHq)^v^AsGAm1aKf*(4HU^ z(y``XW-us?L8H+;K!j06?3>83Y5AN+x-lRfL1h52n)9I11`zIRP#Bs!4N2UN^MXxd zffN%!hxsc{H*cAb;wABTo!1R+@^}rKNmo4MJ(zSFRL}6@B4EfwbzJ+dsKI(fv$R~C z^vV|6TZVc408sF6#jBN;0LP_D;;a3l=AfhD_ zp60Mb@`oKYNhXdZL(oQSm5-;nACQWZX;K5g>LIEeG6ekt=naF;9UheCd4j_FbOI~c zzqf*ylvkW+I*~bgD>21zSK*N6XOiPR$64bc@&x@@jVJf5&N-xAQiQfyp=fiwGc~D5 zwcvQ5rTbl_leum!bZJNDXzzX82l?rj23{BXFJug}70Z`1GV7-1F0VYFyWEdh=K)SO zuC0$mjyqhn^COEJEP5S|&ev2m2N+*<$Vip)a!a)C(=ApnSADELaqZD7lVUP?P)a1N zEbDH?UDlTVThku>+8{NOzHSpYdA*)sKW~2o(NN#Flwy)F`J<<2(%WahmkYL+s!1+n zvmLk4-}m}hruH)z$Tq`@j9|ZDKfmhncbk?(TGvd2$n+aFtPq(Jp~gre5#w?j*>WjwWVTVZB4@rWtgJjBh0z1zz#bj+B zn;#X}Nwwk^lCsc0A4i?up@%XxofytpKKn^H=G!%;JGVu?+CNo(>vBa0C2x1pVN7Qn=*fBQ6QR_l7gGYow*itd?HSvZ6Z3KRd|RUUtbFtJQTGT;9%#vgf3k*OgNFcb;d(x~;vX zi;rCvDYTM*#-e@VKMRg-Bl}jf9;}3YVK09k7R1~uulbQbEw!#^LZN1$xqNUm2)Xni z-qzh8e>gqimXuV<;5EkJzWm~>QC1aMOEw~gl4k7o#)CgT!!c`j=ay|$$x^(%-j6U? zsnX-UnC#vE#G4Y@-`Qv$FsH5*XV7L8`vRpzmtOy}`5{qoG?A@8P9!8#G>gkcW*K6X zz5G0Iqvi0A} zmUP7u|2w$7#FcV;(UL+AkWL)o8|A)#iY8EW4+kM;i(_;b?3ysLPA z>zSLOBFiHmxEvMQ@`uH*)_&b#ReB#?CW;atIyhD)tPEJX&$eG!S&W|5x0oLpUhm|e znY_h2a{(WCVP-Ljt}p6mexnqnP3PgZ*A{z}SuDjQE5{!uI*-$H25V-lL(0ATv=jzkC5{4Xpv z1&d4RMBlinj@3pr$!Jk`ZKj57%u^{1LSn4CBcP!jg?s|F-|_1)h3*|^zyg;+Jm7u1;T-r?cs9HW{^PfYcrOBt<_TchI4=(ny@xQyLxQ!c zKnQsZkGEtu5->J(Je;C~!>s`=SBxD}?lr$aZm;mqeVFS(mJxDWg;IRJ(-=%JaX5rq z91`&@gtvl?<;$JNchsiFN#bM&P(B#b@by7rJZ7LN0O1`L%qGU%7Ae8Y#G3{j%|qEn zlGmh8f&0vueK-DXLyZVk{C&JSIy5YlowZdd1M%avd1dOA!7wf33H?-hv!N66L)@_x65^N zPH*WxYM(HoBkI1Csv1n#o%mj(@_lw6Q#p!s$>>6$UtOl*{hr=ZQqyUd80;h0{Fo{| ze?e+ZQbR^yz1=o1ill$cV6LQXyIRim4S~WK*foWDBP!n2=%=4gS8Nw8=v;!-r#o>s zTaS>s-Ls}IGVq*JsTy}lvc%jwwKy>%x4`oRbf(_zN8}o)3O1cJXE2iaM8oL7aE*J` zZ8irxmfB=qoHKLCcMNbTopPhJPWJa?GI$4wk=i?tedLV2%jw{%D{pPKOEF};iO|v& x&-m4K8wmPZiuztX!;e@di*+bsyl(LAr?o3HI^BV@uHjDozk+^0I@@Ff{12s>(1!p3 diff --git a/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.woff2 b/vitess.io/assets/vendor/wsk/0.4.0/images/icons/icons.woff2 deleted file mode 100644 index 0ed2d705bfd96a85fe91bae7a480d6f052dee4b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1572 zcmV+<2HW{}Pew8T0RR9100txg4FCWD01YGn00qtf0RR9100000000000000000000 z0000#Mn+Uk90p(jf3TL*#|8)*v2j?-l}pf=w8 zhj-IIHwm;0b;-=AJ2Qi%9jya}39Dpo?aYNYQ-5C;3ia;Qt5&0C4D&z6T%Enm!LQp# zn)Nah!$cyPN+XJDXoQxDg+)Ar2`_V~-|bHUAON_Mw&pqjT%X-rlKVOOi~djn)R`;* z+QFrN3p4>>pk~pV=fNLCcT1iLju-SIfE_vd0I0m@|W(Vs?y|wKS1AsyAk3)cwp5+1{MY(Wx@cHq8I3PQ~gg^@iK)b?xQcOna zni#N9-FhjSxR5-xs<<9Yo#40@&ZA93IF>`NJIABGq1ZWR%4%2*Bid*3P`PuJ(2HbX zH3fQJk_@~kEzlW8Pc!OCGN7`Dsi)E0-BO{S=VM3}sfL~x7x?MZr5Ykh3;o3mLk&q| znC~m4=?5BK)ZZU_ukOy6%}&ruJgeb&(nwo$=%v^u@vNAY8IeXW0&nBR`rR-Vh*AOn zXl(r$)|GRqU|kp^xuO((EV+vkW!mQ^rSDUAcw0r<@yJfCp%kukf3t5&_xL*f9X(Gp z_P(axkl#{jrO((6jG2dyON=L^?_GX-Z0oHl8+X#!pe20WCh&guGOlatyBx=uHro={ z1s7J?2>5iLoc^?_a9^?j`rGzdPnm-Mz7s zc=aSt!xY0H4@-7yy9QL3+iva)k{O4IO8S2~C7@8PwXc;uU?j$v0qI~n~thG)W1KVw+O zE1g24-h}h^_Uv?ISZAYer|`Bj3o|o|v1?&gRv{cp?@H9#^#5OiLq8k4L!1q?naVzd3|pr4zEsv|2F#2sA~7h z2eox;ZzRdRAH#73N7ne=ns%#EVT3LsuTrbi=2^A=TF9NzSy{-;1=rv;bU@=5Gi+!~ zr;o0_0Q-KurvTqNXP$$UCHibDacOCO5+ODEZb-P{66-M-7d2Wp8UPgwPMG( z6oyf8Ij!*Iqz<|#ji3W6Iz>7MZXdlcH00-tP``gdstLL`?ejW!`OvP_yy}TXHTH0I zy|srGwI|Oj+b$^Bzj}X6^zn#yT?gQ|CRJMi6f{8rSbt-QP3dtf&meqKc2CZ6HQlA~>>gtw|Q)4cZ%_gCIsE}nc*(agdI+fURPH-5a`G zP=gHv(SIyvHrWQsw2ymZGGQCa$%aI2#hIN%ixedmj>eHJ>`5lOOl%w1HaapY_9U31 zuLiZLJQNT_ZpomPCqxoJG}qMH2H1tj$S7@OZ%JVbs@HEz#UT*&3kDDvQoq0wM=Da2 z6FE}@;z>g;7B diff --git a/vitess.io/assets/vendor/wsk/0.4.0/styles/wsk.css b/vitess.io/assets/vendor/wsk/0.4.0/styles/wsk.css deleted file mode 100644 index 30d322f39a8..00000000000 --- a/vitess.io/assets/vendor/wsk/0.4.0/styles/wsk.css +++ /dev/null @@ -1 +0,0 @@ -html,button,input,select,textarea{color:#222}body{font-size:1em;line-height:1.4}a{color:#00e}a:visited{color:#551a8b}a:hover{color:#06e}img{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}.nocallout{-webkit-touch-callout:none}.pressed{background-color:rgba(0,0,0,0.7)}textarea[contenteditable]{-webkit-appearance:none}.gifhidden{position:absolute;left:-100%}.ir{background-color:transparent;background-repeat:no-repeat;border:0;direction:ltr;display:block;overflow:hidden;text-align:left;text-indent:-999em}.ir br{display:none}.hidden{display:none !important;visibility:hidden}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.clearfix::before,.clearfix::after{content:"";display:table}.clearfix::after{clear:both}/*! normalize.css v3.0.1 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,main,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}mark{background:#ff0;color:#000}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}blockquote{margin:0}*,*::before,*::after{box-sizing:border-box}html,body,button{-webkit-font-smoothing:antialiased;font-smoothing:antialiased}body{font-family:Helvetica, Arial, sans-serif;font-size:16px;line-height:1.6250em;font-weight:300;color:#404040;position:relative}body::after{content:"";position:absolute;top:0;left:0;bottom:0;right:0;width:100%;z-index:9;display:none;background-image:-webkit-linear-gradient(top, rgba(0,0,0,0.15) 95%, rgba(0,0,0,0.15) 100%);background-image:linear-gradient(to bottom, rgba(0,0,0,0.15) 95%, rgba(0,0,0,0.15) 100%);background-size:100% 26px}body.debug::after{display:block;pointer-events:none}pre{background:#f0f0f0;padding:13px}.main-container{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto}@media only screen and (min-width: 620px){.main-container{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 800px){.main-container{padding-left:4.4%;padding-right:4.4%;max-width:864px}}.container{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto}@media only screen and (min-width: 620px){.container{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 800px){.container{padding-left:4.4%;padding-right:4.4%;max-width:864px}}@media only screen and (min-width: 620px){.container-medium{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto}}@media only screen and (min-width: 620px) and (min-width: 620px){.container-medium{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 620px) and (min-width: 800px){.container-medium{padding-left:4.4%;padding-right:4.4%;max-width:864px}}@media only screen and (max-width: 619px){.container-small{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto}}@media only screen and (max-width: 619px) and (min-width: 620px){.container-small{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (max-width: 619px) and (min-width: 800px){.container-small{padding-left:4.4%;padding-right:4.4%;max-width:864px}}@media only screen and (min-width: 800px){.content{margin-right:25.9%}.content pre{margin-right:-25.9%}}@font-face{font-family:"icons";src:url("../images/icons/icons.eot");src:url("../images/icons/icons.eot?#iefix") format("embedded-opentype"),url("../images/icons/icons.woff2") format("woff2"),url("../images/icons/icons.woff") format("woff"),url("../images/icons/icons.ttf") format("truetype"),url("../images/icons/icons.svg?#icons") format("svg");font-weight:normal;font-style:normal}.icon{font-family:"icons";display:inline-block;vertical-align:top;line-height:1;font-weight:normal;font-style:normal;speak:none;text-decoration:inherit;text-transform:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.icon-bullet::before,ul li::before,ul.list-links a::before,.list-anchor a::before{content:"\e001"}.icon-chevron-down::before{content:"\e002"}.icon-chevron-large::before{content:"\e003"}.icon-chevron-left::before,.article-nav-link--prev::before{content:"\e004"}.icon-chevron-right::before,.article-nav-link--next::before,ul.list-links.list-links--primary a::before{content:"\e005"}.icon-chevron-up::before{content:"\e006"}.icon-close::before{content:"\e007"}.icon-cog::before{content:"\e008"}.icon-diamond::before{content:"\e009"}.icon-exclamation::before{content:"\e00a"}.icon-google-dev::before{content:"\e00b"}.icon-hash::before{content:"\e00c"}.icon-introduction-to-media::before{content:"\e00d"}.icon-lessons::before{content:"\e00e"}.icon-menu::before{content:"\e00f"}.icon-minus::before{content:"\e010"}.icon-multi-device-layouts::before{content:"\e011"}.icon-performance::before{content:"\e012"}.icon-plus::before{content:"\e013"}.icon-question::before{content:"\e014"}.icon-slash::before{content:"\e015"}.icon-star::before{content:"\e016"}.icon-tick::before{content:"\e017"}.icon-user-input::before{content:"\e018"}.highlight-module{overflow:hidden;margin-top:52px;margin-bottom:26px;position:relative}.highlight-module::after{background:#f0f0f0;content:"";height:100%;position:absolute;top:0;bottom:0;z-index:0;width:100%;right:0;left:0}.highlight-module ul,.highlight-module ol{padding-left:0}.highlight-module__container{box-sizing:content-box;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto;padding-bottom:78px;z-index:1;position:relative}@media only screen and (min-width: 620px){.highlight-module__container{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 800px){.highlight-module__container{padding-left:4.4%;padding-right:4.4%;max-width:864px}}.highlight-module__container::before{display:none}@media only screen and (min-width: 620px){.highlight-module__container::before{display:block;position:absolute;top:106px;right:45px;font-family:"icons";font-size:130px;line-height:1px;text-align:center;height:100%;width:30.3%;color:#ffffff}}.highlight-module--left .highlight-module__container::before{right:auto;left:45px}@media only screen and (min-width: 800px){.highlight-module__container::before{top:134px;width:22.2%;font-size:180px}.highlight-module--large .highlight-module__container::before{font-size:430px}}@media only screen and (min-width: 620px){.highlight-module__container{padding-bottom:52px}}@media only screen and (min-width: 800px){.highlight-module__container{min-height:208px}}.highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0;padding-top:26px}@media only screen and (min-width: 800px){.highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:110px;font-weight:300;line-height:1.19em;padding-top:0.2364em;padding-bottom:0}}@media only screen and (min-width: 800px){.highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0}}@media only screen and (min-width: 800px) and (min-width: 800px){.highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0}}.highlight-module__cta{display:block}.highlight-module--learning{color:#ffffff}.highlight-module--learning::after{background-color:#da2e75}.highlight-module--learning a{color:#ffffff;text-decoration:underline}.highlight-module--remember{color:#ffffff}.highlight-module--remember::after{background-color:#09829a}.highlight-module--remember a{color:#ffffff;text-decoration:underline}.highlight-module--code{overflow:visible;margin-bottom:52px}.highlight-module--code pre{margin:0;padding-top:26px;font-size:14px;line-height:26px;padding-bottom:0;padding-left:0;padding-right:0}.highlight-module--code pre span{margin:0;padding:0;display:inline-block}.highlight-module--code code{margin:0;padding:0;word-spacing:-2px;display:block}.highlight-module--code .highlight-module__container{padding-bottom:0}.highlight-module--code .highlight-module__cta{position:absolute;bottom:-26px}@media only screen and (min-width: 800px){.highlight-module--left::after{width:80%;right:20%}}@media only screen and (min-width: 800px){.highlight-module--right::after{width:80%;left:20%}}@media only screen and (min-width: 800px){.highlight-module--right.highlight-module--code::after{width:100%;left:0}}.highlight-module--inline{color:#404040;overflow:visible;margin:26px 0 0}.highlight-module--inline .highlight-module__container{padding-bottom:0}.highlight-module--inline .highlight-module__container::before{display:none}.highlight-module--inline .highlight-module__content{border-color:#e0e0e0;border-style:solid;border-width:1px;border-left-width:0;border-right-width:0;margin-bottom:-2px;padding:0 0 26px}.highlight-module--inline .highlight-module__title{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}@media only screen and (min-width: 800px){.highlight-module--inline .highlight-module__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0}}.highlight-module--inline.highlight-module--remember .highlight-module__title,.highlight-module--inline.highlight-module--remember li::before{color:#09829a}.highlight-module--inline.highlight-module--learning .highlight-module__title,.highlight-module--inline.highlight-module--learning li::before{color:#da2e75}.highlight-module--inline::after{display:none !important}div.highlight>pre>code,code .highlight{background:transparent}div.highlight>pre>code .c,code .highlight .c{color:#999988;font-style:italic}div.highlight>pre>code .err,code .highlight .err{color:#a61717;background-color:#e3d2d2}div.highlight>pre>code .cm,code .highlight .cm{color:#999988;font-style:italic}div.highlight>pre>code .cp,code .highlight .cp{color:#737373}div.highlight>pre>code .c1,code .highlight .c1{color:#999988;font-style:italic}div.highlight>pre>code .cs,code .highlight .cs{color:#737373;font-style:italic}div.highlight>pre>code .gs,code .highlight .gd{color:#000000;background-color:#ffdddd}div.highlight>pre>code .gd .x,code .highlight .gd .x{color:#000000;background-color:#ffaaaa}div.highlight>pre>code .ge,code .highlight .ge{font-style:italic}div.highlight>pre>code .gr,code .highlight .gr{color:#aa0000}div.highlight>pre>code .gh,code .highlight .gh{color:#737373}div.highlight>pre>code .gi,code .highlight .gi{color:#000000;background-color:#ddffdd}div.highlight>pre>code .gi .x,code .highlight .gi .x{color:#000000;background-color:#aaffaa}div.highlight>pre>code .go,code .highlight .go{color:#888888}div.highlight>pre>code .gp,code .highlight .gp{color:#555555}div.highlight>pre>code .gu,code .highlight .gu{color:#aaaaaa}div.highlight>pre>code .gt,code .highlight .gt{color:#aa0000}div.highlight>pre>code .kt,code .highlight .kt{color:#445588}div.highlight>pre>code .m,code .highlight .m{color:#009999}div.highlight>pre>code .s,code .highlight .s{color:#da2e75}div.highlight>pre>code .na,code .highlight .na{color:teal}div.highlight>pre>code .nb,code .highlight .nb{color:#0086b3}div.highlight>pre>code .nc,code .highlight .nc{color:#445588}div.highlight>pre>code .no,code .highlight .no{color:teal}div.highlight>pre>code .ni,code .highlight .ni{color:purple}div.highlight>pre>code .ne,code .highlight .ne{color:#990000}div.highlight>pre>code .nf,code .highlight .nf{color:#990000}div.highlight>pre>code .nn,code .highlight .nn{color:#555555}div.highlight>pre>code .nt,code .highlight .nt{color:#09829a}div.highlight>pre>code .nv,code .highlight .nv{color:teal}div.highlight>pre>code .w,code .highlight .w{color:#bbbbbb}div.highlight>pre>code .mf,code .highlight .mf{color:#009999}div.highlight>pre>code .mh,code .highlight .mh{color:#009999}div.highlight>pre>code .mi,code .highlight .mi{color:#009999}div.highlight>pre>code .mo,code .highlight .mo{color:#009999}div.highlight>pre>code .sb,code .highlight .sb{color:#da2e75}div.highlight>pre>code .sc,code .highlight .sc{color:#da2e75}div.highlight>pre>code .sd,code .highlight .sd{color:#da2e75}div.highlight>pre>code .s2,code .highlight .s2{color:#da2e75}div.highlight>pre>code .se,code .highlight .se{color:#da2e75}div.highlight>pre>code .sh,code .highlight .sh{color:#da2e75}div.highlight>pre>code .si,code .highlight .si{color:#da2e75}div.highlight>pre>code .sx,code .highlight .sx{color:#da2e75}div.highlight>pre>code .sr,code .highlight .sr{color:#009926}div.highlight>pre>code .s1,code .highlight .s1{color:#da2e75}div.highlight>pre>code .ss,code .highlight .ss{color:#990073}div.highlight>pre>code .bp,code .highlight .bp{color:#737373}div.highlight>pre>code .vc,code .highlight .vc{color:teal}div.highlight>pre>code .vg,code .highlight .vg{color:teal}div.highlight>pre>code .vi,code .highlight .vi{color:teal}div.highlight>pre>code .il,code .highlight .il{color:#009999}.editorial-header{overflow:hidden}.editorial-header .breadcrumbs{color:#3372df}.editorial-header .breadcrumbs a{color:#3372df}@media only screen and (min-width: 620px){.editorial-header .container{position:relative}.editorial-header .container::before{content:"\e003";font-family:"icons";font-size:1000px;line-height:0;display:block;position:absolute;top:0;right:100%;color:#f0f0f0;margin:168px -35px 0 0}}.editorial-header__excerpt{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0;font-family:"Roboto Condensed", Helvetica, sans-serif}.editorial-header .tag{padding-top:52px}.editorial-header__subtitle{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0;padding-top:0;color:#3372df}@media only screen and (min-width: 800px){.editorial-header__subtitle{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0}}@media only screen and (min-width: 620px){.editorial-header__subtitle{padding-top:0;padding-bottom:26px}}.editorial-header__toc{margin-top:26px}.editorial-header__toc ol{padding-top:0}@media only screen and (min-width: 620px){.editorial-header__toc ol{padding-top:0}}.editorial-header__toc-title{font-family:"Roboto Condensed", Helvetica, sans-serif;border-bottom:1px solid #e0e0e0;margin-bottom:13px;padding-bottom:13px !important;color:#3372df}.summary-header{background-color:#3372df;padding-bottom:78px;color:#ffffff;margin-bottom:26px;box-shadow:inset 0 2px 0 0 #fff}.summary-header .breadcrumbs__link{color:#ffffff}.summary-header__anchor-list{margin-top:52px}.summary-header__anchors-item a{color:#ffffff}.related-guides{margin-top:78px;padding-bottom:50px;border-top:2px solid #e0e0e0;padding-top:50px}.related-guides__list .list-links{padding-top:0}.related-guides__list a{display:block}.related-guides__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0;padding-top:0}@media only screen and (min-width: 800px){.related-guides__title{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0}}@media only screen and (min-width: 620px){.related-guides__title{padding-top:0}}.related-guides__main-link{text-transform:uppercase}.related-guides__main-link::before{content:"#";display:inline-block;padding-right:2px}.in-this-guide{margin-top:-78px}.in-this-guide__title{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0;font-family:"Roboto Condensed", Helvetica, sans-serif;margin-bottom:26px}.articles-section{background:#f0f0f0;text-align:center;padding:26px 0 104px}.articles-count{color:#3372df;font-family:"Roboto Condensed", Helvetica, sans-serif;font-weight:400}.article-section__icon{top:-26px}@media only screen and (min-width: 620px){.article-section__icon{top:-39px}}.guides-section{background:#f0f0f0;text-align:center;padding:26px 0 104px}.page-header{text-align:center}.page-header .breadcrumbs{text-align:left;color:#3372df}.page-header .breadcrumbs a{color:#3372df}.page-header h3{color:#404040;padding-top:52px}.page-header__excerpt{position:relative;padding-top:0}.page-header__excerpt:last-child{padding-bottom:78px}.featured-section{background:#f0f0f0}.featured-spotlight{background:#404040;color:#ffffff;overflow:hidden;padding-bottom:77px;margin-top:52px}.featured-spotlight p{padding-bottom:26px}.featured-spotlight .cta--primary{color:#ffffff}.featured-spotlight .cta--primary:hover{color:#ffffff}.featured-spotlight__container{position:relative}@media only screen and (max-width: 619px){.featured-spotlight__img{padding-top:58.4%;padding-bottom:0;height:0;overflow:hidden;position:relative;width:100%}}.featured-spotlight__img img{margin:0 auto;display:block;width:100%;position:absolute;left:0;top:0;margin:0}@media only screen and (min-width: 620px){.featured-spotlight__img img{width:auto;max-width:none;left:109%}}@media only screen and (min-width: 800px){.featured-spotlight__img img{left:107.4%}}.quote__content{position:relative;font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;padding-top:104px;padding-left:26px}@media only screen and (min-width: 800px){.quote__content{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}}@media only screen and (min-width: 620px){.quote__content{padding-top:52px;padding-left:0}}.quote__content p{border-top:1px solid #e0e0e0;text-align:right;font-weight:500;margin-top:12px;padding-top:13px}.quote__content::before{content:open-quote;display:block;position:absolute;font-family:"Roboto Condensed", Helvetica, sans-serif;font-weight:700;color:#f0f0f0;top:90px;left:26px;font-size:260px}@media only screen and (min-width: 620px){.quote__content::before{top:225px;left:-210px;font-size:540px}}.article-nav{overflow:hidden;position:relative}.article-nav::before{content:"";border-left:2px solid #e0e0e0;height:100%;position:absolute;top:0;left:50%}.article-nav-link{padding:26px 32px;float:left;width:50%;position:relative}.article-nav-link::before{position:absolute;top:21px;font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:20px;font-weight:400}@media only screen and (min-width: 620px){.article-nav-link::before{top:25px;font-size:26px;display:block;padding:13px 10px;color:#ffffff;background:#3372df}}.article-nav p{padding:0;margin:0}.article-nav-link--prev{text-align:right}.article-nav-link--prev::before{font-family:"icons";left:32px}@media only screen and (min-width: 620px){.article-nav-link--prev p{padding-left:52px}}.article-nav-link--next::before{font-family:"icons";right:32px}@media only screen and (min-width: 620px){.article-nav-link--next p{padding-right:52px}}.article-nav-count{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0;font-weight:700}@media only screen and (min-width: 800px){.article-nav-count{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0}}@media only screen and (min-width: 620px){.article-nav-count{font-weight:400}}@media only screen and (min-width: 620px){.did-you-know ol{padding-top:0 !important}}.did-you-know .cta--primary{margin-top:26px;font-weight:500}.did-you-know>.g--half{position:relative;padding-left:0}@media only screen and (min-width: 620px){.did-you-know>.g--half{padding-left:32px}}.did-you-know__symbol{padding-bottom:312px}@media only screen and (min-width: 620px){.did-you-know__symbol{padding-bottom:26px}}.did-you-know__symbol::after{content:"\e014";color:#3372df;font-family:"icons";font-size:300px;top:150px;left:30%;position:relative;display:block;width:0}@media only screen and (min-width: 620px){.did-you-know__symbol::after{position:absolute;font-size:400px;top:200px;left:110%}}@media only screen and (min-width: 800px){.did-you-know__symbol::after{position:absolute;font-size:400px;top:200px;left:124%}}.toc__title{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;font-family:"Roboto Condensed", Helvetica, sans-serif;padding-bottom:13px;margin-bottom:12px;border-bottom:1px solid #e0e0e0}@media only screen and (min-width: 800px){.toc__title{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}}@media only screen and (min-width: 620px){.toc__title{padding-bottom:13px;margin-bottom:13px}}.toc__list{padding-top:0;border-bottom:1px solid #e0e0e0;padding-bottom:12px;margin-bottom:13px}.toc__list a{display:block}.toc__sublist{padding-top:0}.next-lessons{background:#404040;padding:26px 26px 52px;margin-top:26px;color:#ffffff;position:relative}@media only screen and (min-width: 620px){.next-lessons h3 i{display:none}}.next-lessons::before,.next-lessons::after{color:rgba(255,255,255,0.5);position:absolute;display:none}@media only screen and (min-width: 620px){.next-lessons::before,.next-lessons::after{display:inline-block}}@media only screen and (min-width: 620px){.next-lessons::before{content:attr(data-current-lesson);font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:16px;font-weight:400;line-height:1;background:#404040;display:inline-block;padding:5px 7px;right:127px;top:143px;z-index:1;color:rgba(255,255,255,0.5)}}@media only screen and (min-width: 800px){.next-lessons::before{font-size:20px;padding-left:15px;padding-right:15px;top:126px;right:230px}}@media only screen and (min-width: 620px){.next-lessons::after{content:"\e00e";font-family:"icons";font-size:150px;right:40px;top:185px}}@media only screen and (min-width: 800px){.next-lessons::after{font-size:210px;right:120px}}@media only screen and (min-width: 620px) and (max-width: 799px){.g-medium--1{float:left;margin-right:4.5%;width:30.3%}.g-medium--push-1{margin-left:34.8%}.g-medium--pull-1{margin-right:34.8%}.g-medium--2{float:left;margin-right:4.5%;width:65.1%}.g-medium--push-2{margin-left:69.6%}.g-medium--pull-2{margin-right:69.6%}.g-medium--3{float:left;margin-right:4.5%;width:99.9%;margin-right:0}.g-medium--full{float:left;margin-right:4.5%;margin-right:0;width:100%}.g--third{float:left;margin-right:4.5%;width:30.3%}.g--half,.g-medium--half{float:left;margin-right:4.5%;width:47.75%}.g-medium--last{margin-right:0}.g-medium--last+.g-medium--half{clear:left}.g--pull-half{margin-right:52.25%}}@media only screen and (min-width: 800px){.g-wide--1{float:left;margin-right:3.7%;width:22.2%}.g-wide--push-1{margin-left:25.9%}.g-wide--pull-1{margin-right:25.9%}.g-wide--2{float:left;margin-right:3.7%;width:48.1%}.g-wide--push-2{margin-left:51.8%}.g-wide--pull-2{margin-right:51.8%}.g-wide--3{float:left;margin-right:3.7%;width:74%}.g-wide--push-3{margin-left:77.7%}.g-wide--pull-3{margin-right:77.7%}.g-wide--4{float:left;margin-right:3.7%;width:99.9%;margin-right:0}.g-wide--last{margin-right:0}.g-wide--full{float:left;margin-right:3.7%;margin-right:0;width:100%}.g--third{float:left;margin-right:3.7%;width:30.8%}.g--half,.g-wide--half{float:left;margin-right:3.7%;width:48.15%}.g--pull-half{margin-right:51.85%}}.g--last{margin-right:0}.g--centered{float:none;margin-left:auto;margin-right:auto}.grid-overlay{display:none;pointer-events:none}.debug .grid-overlay{box-sizing:content-box;position:relative;padding-left:5%;padding-right:5%;margin-left:auto;margin-right:auto;position:absolute;top:0;bottom:0;left:0;right:0;height:100%;display:block}@media only screen and (min-width: 620px){.debug .grid-overlay{padding-left:4.8%;padding-right:4.8%;max-width:688px}}@media only screen and (min-width: 800px){.debug .grid-overlay{padding-left:4.4%;padding-right:4.4%;max-width:864px}}.debug .grid-overlay [class*="g-"]{height:100%;background-color:rgba(89,89,89,0.2)}@media only screen and (min-width: 620px) and (max-width: 799px){.debug .grid-overlay .g-wide--last{display:none}}@media only screen and (max-width: 619px){.debug .grid-overlay{display:none}}h1,h2,h3,h4,h5,p{margin:0}.small,small{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0}.base,p,ul,ol{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0}.medium,h4{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0}@media only screen and (min-width: 800px){.medium,h4{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}}.large,h3{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}@media only screen and (min-width: 800px){.large,h3{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0}}.xlarge,h2{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:300;line-height:1.0000em;padding-top:1.0000em;padding-bottom:0}@media only screen and (min-width: 800px){.xlarge,h2{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0}}.xxlarge,h1{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:42px;font-weight:300;line-height:1.2381em;padding-top:0.6190em;padding-bottom:0}@media only screen and (min-width: 800px){.xxlarge,h1{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0}}.huge{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:68px;font-weight:300;line-height:1.1471em;padding-top:0.3824em;padding-bottom:0}@media only screen and (min-width: 800px){.huge{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:110px;font-weight:300;line-height:1.19em;padding-top:0.2364em;padding-bottom:0}}li>p{padding-top:0}.button,.button--primary,.button--secondary,.button--secondary-variation{display:inline-block;padding:12px 32px;margin-bottom:13px;margin-top:13px;min-height:26px;text-align:center;font-family:"Roboto Condensed", Helvetica, sans-serif;font-weight:600;text-decoration:none;outline:0;-webkit-transition:none;transition:none}.button:hover,.button--primary:hover,.button--secondary:hover,.button--secondary-variation:hover{background:#4d4d4d;color:#ffffff;border:1px solid #4d4d4d;text-decoration:none}.button--primary{background:#4285f4;color:white;border:1px solid #1266f1}.button--secondary{background:white;color:#3372df;border:1px solid #e6e6e6}.button--secondary-variation{background:white;color:#3372df;border:1px solid #e6e6e6;border-color:transparent}ul,ol{list-style:none;margin:0}@media only screen and (max-width: 619px){ul,ol{padding-left:0}}ul li{position:relative;padding-left:16px}ul li::before{font-family:"icons";font-size:13px;display:block;font-weight:400;position:absolute;top:0;left:0;line-height:26px}ul li::before{font-size:4px}ol{counter-reset:list}ol>li{position:relative;padding-left:32px}ol>li::before{counter-increment:list;content:"0" counter(list);color:inherit;font-weight:400;display:inline-block;position:absolute;left:0}ol>li:nth-child(10n) ~ li::before,ol>li:nth-child(10n)::before{content:counter(list)}ul ol,ol ul{padding-top:0}ul.list-links li::before{display:none}ul.list-links a{font-weight:400}ul.list-links a::before{font-family:"icons";font-size:13px;display:block;font-weight:400;position:absolute;top:0;left:0;line-height:26px}ul.list-links a::before{font-size:4px}ul.list-links.list-links--primary a{font-weight:400;font-family:"Roboto Condensed", Helvetica, sans-serif;line-height:1;text-decoration:none}ul.list-links.list-links--primary a::before{font-family:"icons";font-size:13px;display:block;font-weight:400;position:absolute;top:0;left:0;line-height:26px}ol.list-links li::before{display:none}ol.list-links li a{display:inline-block;font-weight:300}ol.list-links li a::before{counter-increment:list;content:"0" counter(list);color:inherit;font-weight:400;display:inline-block;position:absolute;left:0}ol.list-links li:nth-child(10n) ~ li a::before,ol.list-links li:nth-child(10n) a::before{content:counter(list)}ol.list-links.list-links--secondary a::before{display:none}.list-links--secondary{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;padding-left:0}.list-links--secondary li{padding-left:0}.list-anchor{padding-left:0}.list-anchor li{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;padding-top:0;padding-left:0}.list-anchor li::before{display:none}.list-anchor a{line-height:1;display:inline-block;padding-left:16px}.list-anchor a::before{font-family:"icons";font-size:13px;display:block;font-weight:400;position:absolute;top:0;left:0;line-height:26px}.list-anchor a::before{font-size:4px}@media only screen and (min-width: 620px){.list-small li{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;padding-top:0}}.list-centered{text-align:center;padding-left:0}.featured-list{padding-top:78px;padding-bottom:78px}.featured-list__item{background:#ffffff;padding-left:0;padding-top:26px;padding-bottom:26px;margin-top:26px}@media only screen and (min-width: 620px){.featured-list__item{min-height:338px;padding:52px 32px}}.featured-list__item:first-child{margin-top:0}.featured-list__item p{margin-bottom:26px}.featured-list__img-wrapper{display:none;position:relative;padding-top:26px;margin:0 -5%}@media only screen and (min-width: 620px){.featured-list__img-wrapper{display:block;padding-top:0;margin:0}}@media only screen and (min-width: 620px){.featured-list__img{padding-top:60.8%;padding-bottom:0;height:0;overflow:hidden;position:absolute;width:100%}}.featured-list__img img{display:block;margin:0 auto;max-width:100%}@media only screen and (min-width: 620px){.featured-list__img img{margin:0;position:absolute;top:0;height:100%;width:100%;left:0}}.related-guides-list{font-family:"Roboto Condensed", Helvetica, sans-serif;padding-top:0;padding-left:0}@media only screen and (min-width: 620px){.related-guides-list{padding-top:26px}}@media only screen and (min-width: 800px){.related-guides-list{padding-top:0}}.related-guides-list p{padding-top:0}.related-guides-list .tag{padding-top:0}.related-guides-list li{padding-top:26px;padding-bottom:25px;border-bottom:1px solid #e0e0e0}.related-guides-list li:last-child{border-color:transparent}@media only screen and (min-width: 620px){.related-guides-list li{padding-top:0;padding-bottom:0;border-color:transparent}}.list--reset{padding-left:0}.list--reset li{padding-left:0}.list--reset.list-links a::before,.list--reset li::before{display:none !important}.list-lessons{padding-left:0}.list-lessons a{color:#ffffff}.list-lessons .current,.list-lessons .current a{text-decoration:none;cursor:default}.list-lessons .current .icon{font-size:13px;display:inline-block;background:rgba(0,0,0,0.2);border-radius:100%;width:26px;line-height:26px;text-align:center;margin-left:7px}.list-guides-intro{margin-bottom:52px}@media only screen and (max-width: 619px){.list-guides-intro{padding-top:52px}}.list-guides-intro li{border-bottom:1px solid #e0e0e0;padding-bottom:51px;margin-bottom:52px}@media only screen and (min-width: 620px){.list-guides-intro li{border-color:transparent;padding-bottom:0}}.list-guides-intro li:last-child{border-bottom:transparent;margin-bottom:0}a{color:#3372df}a:hover{text-decoration:none}.cta--primary{font-family:"Roboto Condensed", Helvetica, sans-serif;color:#3372df;font-weight:400;display:inline-block;line-height:1;text-decoration:none}.cta--primary:hover{color:#404040}.cta--primary::before{display:inline-block;padding-right:10px;font-family:"icons";line-height:25px;font-size:13px;content:"\e005"}.cta--secondary{font-family:"Roboto Condensed", Helvetica, sans-serif;color:#3372df;font-weight:400;display:inline-block;line-height:1}.cta--secondary:hover{color:#404040}table{margin-top:26px;width:100%}table thead{background:#3372df;color:#ffffff}table th{text-align:center;display:none;font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0}@media only screen and (min-width: 800px){table th{font-size:20px;font-weight:300;line-height:1.3000em;padding-top:1.3000em;padding-bottom:0}}@media only screen and (min-width: 620px){table tr{border-bottom:1px solid #ffffff}}table tbody{background:#f0f0f0}table td{display:block;padding-top:13px;padding-bottom:13px}table td::before{content:attr(data-th) " :";display:inline-block;color:#ffffff;background:#3372df;border-right:2px solid #ffffff;position:absolute;top:0;left:0;bottom:0;width:100px;max-height:100%;font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:16px;font-weight:400;padding-left:13px;padding-top:13px}@media only screen and (min-width: 620px){table td::before{display:none}}table th,table td{position:relative;padding-left:140px}@media only screen and (min-width: 620px){table th,table td{display:table-cell}}@media only screen and (min-width: 620px){table th{padding:26px;padding-top:13px;padding-bottom:12px}}@media only screen and (min-width: 620px){table td{padding:26px;padding-bottom:25px}}td:last-child::after{content:"";display:block;background:#ffffff;height:1px;left:0;position:absolute;bottom:0;width:100%}@media only screen and (min-width: 620px){td:last-child::after{display:none}}.table-2 col{width:344px}@media only screen and (min-width: 800px){.table-2 col{width:432px}}@media only screen and (min-width: 620px){.table-2 th:first-child,.table-2 td:first-child{border-right:2px solid #ffffff}}.table-3 col{width:229.3333333333px}@media only screen and (min-width: 800px){.table-3 col{width:288px}}@media only screen and (min-width: 620px){.table-3 th:nth-child(2),.table-3 td:nth-child(2){border-left:2px solid #ffffff;border-right:2px solid #ffffff}}.table-4 col{width:172px}@media only screen and (min-width: 800px){.table-4 col{width:216px}}@media only screen and (min-width: 620px){.table-4 th:nth-child(2),.table-4 th:nth-child(3),.table-4 td:nth-child(2),.table-4 td:nth-child(3){border-left:2px solid #ffffff;border-right:2px solid #ffffff}}img,video,object{max-width:100%}.content img{margin-top:26px;margin-bottom:26px}.breadcrumbs{display:none;position:relative;z-index:1}@media only screen and (min-width: 620px){.breadcrumbs{display:block}}.breadcrumbs p{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;padding-top:26px}.breadcrumbs__link{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;color:black;font-weight:400;padding-top:0}@media only screen and (min-width: 620px){.breadcrumbs__link{padding-top:0}}.subsection-title{color:#404040;margin-top:52px}.subsection-number{font-size:16px;line-height:1.6250em;padding-top:1.6250em;padding-bottom:0;padding-top:0;display:block}.articles-list{padding-left:0}.articles-list__item{padding-bottom:52px;padding-left:0}.articles-list__item:last-child{padding-bottom:53px}.articles-list__item::before{content:"";display:block;width:40%;height:1px;box-shadow:inset 0 1px 0 0 #e0e0e0;margin-right:0;margin-left:30%}.articles-list__item h3 a:hover{text-decoration:none}.articles-list__item p{margin-top:26px;margin-bottom:26px}.articles-list__item:first-child{padding-top:0}@media only screen and (min-width: 620px){.articles-list__item:first-child{padding-top:24px}}.articles-list__item:first-child::before{display:none}.guides-list{overflow:hidden}@media only screen and (min-width: 620px){.guides-list{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;padding-top:52px}}.guides-list__item{padding:0;background:#ffffff;margin-top:26px;margin-bottom:0}@media only screen and (min-width: 620px){.guides-list__item{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}}.guides-list__item h3{margin:0 32px}.guides-list__item p{margin:26px 32px 0}@media only screen and (min-width: 620px){.guides-list__item .primary-content{-webkit-flex:1;-ms-flex:1;flex:1}}.guides-list__item .secondary-content{position:relative;margin-top:51px;border-top:1px solid #e0e0e0}@media only screen and (min-width: 620px){.guides-list__item .secondary-content{width:100%}}.guides-list__item .secondary-content .icon-circle{position:absolute;top:-28px;left:50%;margin-left:-21px;border:2px solid #ffffff}.guides-list__item .secondary-content .icon-circle i{font-size:23px}.guides-list__item ol{margin:26px 0 0;padding:52px 0 52px;margin-top:0}.guides-list__item::before{display:none}.icon-circle,.icon-circle--large{height:0;width:0;background:#737373;display:block;position:relative;border-radius:100%;font-size:0;padding:22px;margin:4px auto}.icon-circle i,.icon-circle span,.icon-circle--large i,.icon-circle--large span{position:absolute;line-height:0px;top:50%;width:100%;left:0;text-align:center;color:#ffffff;font-size:26px}.icon-circle span,.icon-circle--large span{font-family:"Roboto Condensed", Helvetica, sans-serif;font-size:26px;font-weight:700}@media only screen and (min-width: 620px){.icon-circle span,.icon-circle--large span{font-size:42px}}.icon-circle--large{margin-top:0;margin-bottom:0;padding:26px;position:relative}.icon-circle--large i{font-size:26px}@media only screen and (min-width: 620px){.icon-circle--large i{font-size:42px}}@media only screen and (min-width: 620px){.icon-circle--large{padding:37px;border:2px solid #ffffff}a .icon-circle--large{padding:38px;box-shadow:inset 0px 0px 0px 1px rgba(255,255,255,0.42);border:1px solid;-webkit-transition:all 100ms linear;transition:all 100ms linear;-webkit-transform:translateZ(0);transform:translateZ(0)}.no-touch a:hover .icon-circle--large{box-shadow:inset 0px 0px 0px 1px #ffffff;-webkit-transform:scale(1.1);transform:scale(1.1)}}.icon-circle--nav{height:0;width:0;background:#737373;display:block;position:relative;border-radius:100%;font-size:0;padding:13px;margin:0 auto}@media only screen and (min-width: 620px){.icon-circle--nav{padding:22px;margin-top:4px;margin-bottom:4px}}.icon-circle--nav i{position:absolute;line-height:1px;top:50%;width:100%;left:0;text-align:center;color:#ffffff;font-size:16px}@media only screen and (min-width: 620px){.icon-circle--nav i{font-size:26px}}.theme--multi-device-layouts .themed{color:#297ea9}.theme--introduction-to-media .themed{color:#cf423a}.theme--user-input .themed{color:#2c8566}.theme--performance .themed{color:#7b5294}.theme--multi-device-layouts .themed--background,.theme--multi-device-layouts .themed--background.next-lessons::before{background-color:#297ea9}.theme--introduction-to-media .themed--background,.theme--introduction-to-media .themed--background.next-lessons::before{background-color:#cf423a}.theme--user-input .themed--background,.theme--user-input .themed--background.next-lessons::before{background-color:#2c8566}.theme--performance .themed--background,.theme--performance .themed--background.next-lessons::before{background-color:#7b5294}.theme--multi-device-layouts .themed--hover:hover{color:#297ea9}.theme--introduction-to-media .themed--hover:hover{color:#cf423a}.theme--user-input .themed--hover:hover{color:#2c8566}.theme--performance .themed--hover:hover{color:#7b5294}.theme--multi-device-layouts .themed--hover-secondary:hover{color:#89c4e2}.theme--introduction-to-media .themed--hover-secondary:hover{color:#edb8b5}.theme--user-input .themed--hover-secondary:hover{color:#78d2b3}.theme--performance .themed--hover-secondary:hover{color:#c4add2}.article--multi-device-layouts .article-container h1,.article--multi-device-layouts .article-container h2{color:#297ea9}.article--introduction-to-media .article-container h1,.article--introduction-to-media .article-container h2{color:#cf423a}.article--user-input .article-container h1,.article--user-input .article-container h2{color:#2c8566}.article--performance .article-container h1,.article--performance .article-container h2{color:#7b5294}.nav-theme--multi-device-layouts .themed--hover:hover{color:#297ea9}.nav-theme--introduction-to-media .themed--hover:hover{color:#cf423a}.nav-theme--user-input .themed--hover:hover{color:#2c8566}.nav-theme--performance .themed--hover:hover{color:#7b5294}.nav-theme--multi-device-layouts .themed{color:#297ea9}.nav-theme--introduction-to-media .themed{color:#cf423a}.nav-theme--user-input .themed{color:#2c8566}.nav-theme--performance .themed{color:#7b5294}.nav-theme--multi-device-layouts .themed--background{background-color:#297ea9}.nav-theme--introduction-to-media .themed--background{background-color:#cf423a}.nav-theme--user-input .themed--background{background-color:#2c8566}.nav-theme--performance .themed--background{background-color:#7b5294}.page--styleguide .styleguide__module-title{margin-bottom:26px}.page--styleguide section{margin-bottom:52px;border-bottom:1px solid #ccc;padding-bottom:77px}.page--styleguide .styleguide__color-list{text-align:center}.page--styleguide .styleguide__color-list li{border-bottom:52px solid;margin-bottom:26px;position:relative}.page--styleguide .styleguide__breadcrumb .breadcrumbs{display:block}.page--styleguide .styleguide__lists ul,.page--styleguide .styleguide__lists ol{margin-bottom:26px}.page--styleguide .styleguide__inverted-block{background:#e8e8e8;padding:0 13px}.page--styleguide .styleguide__theme-block{background:#297ea9;padding:0 13px}.demo{margin-bottom:26px;margin-top:26px}.demo [class*="g-"]{background-color:#eeeeee;position:relative;margin-bottom:26px;min-height:156px}.demo [class*="g-"]::before,.demo [class*="g-"]::after{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;display:block;margin:0 10px}.demo [class*="g-"]::before{content:"HTML classes: ";font-weight:700}.demo [class*="g-"]::after{content:attr(class);word-spacing:15px}.page--resources .article-section__icon,.page--resources .articles-count,.page--resources .guides-list__item .secondary-content{display:none}.page--resources .primary-content{padding-top:26px;padding-bottom:52px}.page--resources .primary-content p{margin-top:0}.clear::before,.clear::after{content:"";display:table}.clear::after{clear:both}.color--blue{color:#3372df}.color--red{color:#cb4437}.color--green{color:#0f9d58}.color--yellow{color:#f4b400}.color--blue-secondary{color:#b7cdf4}.color--red-secondary{color:#ebb6b0}.color--green-secondary{color:#56efa5}.color--yellow-secondary{color:#ffd45b}.color--gray-background{color:#f0f0f0}.color--gray-keyline{color:#e0e0e0}.color--gray{color:#737373}.color--gray-dark{color:#404040}.color--text{color:#404040}.color--highlight{color:#3372df}.color--warning{color:#ffd45b}.color--danger{color:#cb4437}.color--muted{color:#737373}.color--remember{color:#09829a}.color--learning{color:#da2e75}.color--layouts{color:#297ea9}.color--user{color:#2c8566}.color--media{color:#cf423a}.color--performance{color:#7b5294}.color--layouts-secondary{color:#89c4e2}.color--user-secondary{color:#78d2b3}.color--media-secondary{color:#edb8b5}.color--performance-secondary{color:#c4add2}.text-divider{position:relative;margin-bottom:26px}.text-divider::after{content:"";display:block;position:absolute;width:40%;height:1px;box-shadow:0 1px 0 0 #e0e0e0;left:30%;bottom:-13px}.text-divider.xlarge{margin-bottom:52px}.text-divider.xlarge::after{bottom:-26px}.text-divider.xxlarge{margin-bottom:78px}.text-divider.xxlarge::after{bottom:-39px}.text-divider.huge{margin-bottom:78px}.text-divider.huge::after{bottom:-39px}.centered{text-align:center}.tag{font-size:13px;line-height:2.0000em;padding-top:2.0000em;padding-bottom:0;font-family:"Roboto Condensed", Helvetica, sans-serif;text-transform:uppercase;font-weight:700;display:inline-block;text-decoration:none}.tag:hover{color:#404040}.tag::before{content:"# ";display:inline-block}html,body{width:100%;height:100%;margin:0;padding:0}body{position:relative;font-family:'Roboto Condensed', 'Helvetica', 'Arial', sans-serif;font-weight:300;background-color:#FFFFFF;box-sizing:border-box;min-height:100%}body.open{overflow:hidden}.app-bar{display:block;width:100%;position:fixed;top:0;left:0;background-color:#4285f4;overflow:hidden;z-index:1}.app-bar-container{display:-webkit-flex;display:-ms-flexbox;display:flex;width:100%;height:60px;position:relative;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;margin:0 auto}.app-bar.open,.app-bar.open ~ main{-webkit-transform:translate(250px, 0);transform:translate(250px, 0)}.app-bar .logo{-webkit-flex:1;-ms-flex:1;flex:1;font-size:2em;line-height:60px;margin:0 16px;padding:0;color:#fefefe;float:none;max-width:none;font-weight:300;line-height:60px}.app-bar .logo a{text-decoration:none;color:inherit;font-weight:normal}.app-bar-actions{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;z-index:2}.app-bar button{width:60px;height:60px;background-image:none;background-color:transparent;border:none;padding:0;-webkit-transition:background-color 0.2s ease-out;transition:background-color 0.2s ease-out;-webkit-tap-highlight-color:transparent}.app-bar button img{width:60px;height:60px}.app-bar button:hover{background-color:rgba(255,255,255,0.1)}.app-bar button:focus{background-color:rgba(255,255,255,0.2);outline:0}.app-bar button:active{background-color:rgba(255,255,255,0.4)}button.menu img{height:24px;width:24px}.promote-layer{-webkit-backface-visibility:hidden;backface-visibility:hidden}.base,p,ul,ol{font-size:19px}.navdrawer-container{z-index:1;position:fixed;top:0;bottom:0;width:250px;height:100%;background-color:#3367D6;color:#fefefe;-webkit-transform:translate(-250px, 0);transform:translate(-250px, 0);overflow-y:auto}.navdrawer-container.open{-webkit-transform:translate(0, 0);transform:translate(0, 0)}.app-bar,.navdrawer-container,main{-webkit-transition:-webkit-transform 0.3s ease-out;transition:transform 0.3s ease-out}.navdrawer-container h4,.navdrawer-container ul li a{height:auto;padding:17px 20px;line-height:1.4}.navdrawer-container h4{background-color:white;color:#3367D6}.navdrawer-container ul{padding:0;margin:0;list-style-type:none}.navdrawer-container ul li a{display:block;text-decoration:none;color:white;-webkit-transition:background-color 0.2s ease-out;transition:background-color 0.2s ease-out;white-space:nowrap}.navdrawer-container ul li{border-bottom-style:solid;border-width:1px;border-color:white;padding:0}.navdrawer-container ul li::before{content:none}.navdrawer-container ul li a:hover{background-color:rgba(255,255,255,0.2)}.navdrawer-container ul li a:focus{background-color:rgba(255,255,255,0.3);outline:0}.navdrawer-container ul li a:active{background-color:rgba(255,255,255,0.4)}main{margin:0 auto;padding:60px 16px 16px 16px;min-height:100%}@media all and (min-width: 990px){.app-bar{position:relative}.app-bar.open,.app-bar.open ~ main{-webkit-transform:translate(0px, 0);transform:translate(0px, 0)}.app-bar-container{display:block;height:130px;max-width:864px;padding:0 16px;box-sizing:border-box;background-color:#4285f4}.app-bar .logo{float:left;margin:0;padding:0;line-height:130px;font-size:46px}.app-bar-actions{float:right}.app-bar::after{content:' ';display:block;height:0;overflow:hidden;clear:both}button.menu{display:none}nav{display:block;margin-top:130px}.navdrawer-container{position:relative;width:100%;height:auto;margin-top:130px;-webkit-transform:translate(0, 0);transform:translate(0, 0);-webkit-transition:none;transition:none;overflow-y:auto}.navdrawer-container h4{display:none}.navdrawer-container ul{display:-webkit-flex;display:-ms-flexbox;display:flex;max-width:864px;margin:0 auto;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.navdrawer-container ul li{border:none}main{max-width:864px;padding-top:0;min-height:initial}body{overflow-y:scroll}.navdrawer-container{position:relative;margin-top:0}}@font-face{font-family:'Roboto Condensed';font-style:normal;font-weight:300;src:url(/fonts/RobotoCondensed-Light.eot);src:local("Roboto Condensed Light"),local("RobotoCondensed-Light"),url(/fonts/RobotoCondensed-Light.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-Light.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:normal;font-weight:400;src:url(/fonts/RobotoCondensed-Regular.eot);src:local("Roboto Condensed Regular"),local("RobotoCondensed-Regular"),url(/fonts/RobotoCondensed-Regular.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-Regular.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:normal;font-weight:700;src:url(/fonts/RobotoCondensed-Bold.eot);src:local("Roboto Condensed Regular"),local("RobotoCondensed-Bold"),url(/fonts/RobotoCondensed-Bold.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-Bold.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:italic;font-weight:300;src:url(/fonts/RobotoCondensed-LightItalic.eot);src:local("Roboto Condensed Light Italic"),local("RobotoCondensed-LightItalic"),url(/fonts/RobotoCondensed-LightItalic.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-LightItalic.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:italic;font-weight:400;src:url(/fonts/RobotoCondensed-Italic.eot);src:local("Roboto Condensed Italic"),local("RobotoCondensed-Italic"),url(/fonts/RobotoCondensed-Italic.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-Italic.woff) format("woff")}@font-face{font-family:'Roboto Condensed';font-style:italic;font-weight:700;src:url(/fonts/RobotoCondensed-BoldItalic.eot);src:local("Roboto Condensed Bold Italic"),local("RobotoCondensed-BoldItalic"),url(/fonts/RobotoCondensed-BoldItalic.eot) format("embedded-opentype"),url(/fonts/RobotoCondensed-BoldItalic.woff) format("woff")} diff --git a/vitess.io/contributing/code-reviews.md b/vitess.io/contributing/code-reviews.md deleted file mode 100644 index 3653d8f45b5..00000000000 --- a/vitess.io/contributing/code-reviews.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: doc -title: "Code Reviews" -description: -modified: -excerpt: -tags: [] -image: - feature: - teaser: - thumb: -toc: true -share: false ---- - -{% include doc/CodeReviews.md %} diff --git a/vitess.io/contributing/github-workflow.md b/vitess.io/contributing/github-workflow.md deleted file mode 100644 index 48f5be968dc..00000000000 --- a/vitess.io/contributing/github-workflow.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: doc -title: "GitHub Workflow" -description: -modified: -excerpt: -tags: [] -image: - feature: - teaser: - thumb: -toc: true -share: false ---- - -{% include doc/GitHubWorkflow.md %} diff --git a/vitess.io/contributing/index.md b/vitess.io/contributing/index.md deleted file mode 100644 index 2d3cc117c9a..00000000000 --- a/vitess.io/contributing/index.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: doc -title: "Contributing to Vitess" -description: -modified: -excerpt: -tags: [] -image: - feature: - teaser: - thumb: -toc: true -share: false ---- - -{% include doc/Contributing.md %} diff --git a/vitess.io/css/components.css b/vitess.io/css/components.css deleted file mode 100644 index 1ee3426dd58..00000000000 --- a/vitess.io/css/components.css +++ /dev/null @@ -1,269 +0,0 @@ -/* Custom forms */ -form.customform input, form.customform select, form.customform textarea, form.customform button { - font-size:0.9em; - font-family:inherit; - margin-bottom:1.25em; -} -form.customform input, form.customform select {height: 2.7em;} -form.customform input, form.customform textarea, form.customform select { - background: none repeat scroll 0 0 #F5F5F5; - transition: background 0.20s linear 0s; - -o-transition: background 0.20s linear 0s; - -ms-transition: background 0.20s linear 0s; - -moz-transition: background 0.20s linear 0s; - -webkit-transition: background 0.20s linear 0s; -} -form.customform input:hover, form.customform textarea:hover, form.customform select:hover, form.customform input:focus, form.customform textarea:focus, form.customform select:focus {background: none repeat scroll 0 0 #fff;} -form.customform input, form.customform textarea, form.customform select { - background: none repeat scroll 0 0 #F5F5F5; - border: 1px solid #E0E0E0; - padding: 0.625em; - width: 100%; -} -form.customform input[type="file"] { - border: 1px solid #E0E0E0; - height: auto; - max-height: 2.7em; - min-height: 2.7em; - padding: 0.4em; - width: 100%; -} -form.customform input[type="radio"], form.customform input[type="checkbox"] { - margin-right: 0.625em; - width:auto; - padding:0; - height:auto; -} -form.customform option {padding: 0.625em;} -form.customform select[multiple="multiple"] {height: auto;} -form.customform button { - width: 100%; - background: none repeat scroll 0 0 #444444; - border: 0 none; - color: #FFFFFF; - height: 2.7em; - padding: 0.625em; - cursor:pointer; - width: 100%; - transition: background 0.20s linear 0s; - -o-transition: background 0.20s linear 0s; - -ms-transition: background 0.20s linear 0s; - -moz-transition: background 0.20s linear 0s; - -webkit-transition: background 0.20s linear 0s; -} -form.customform button:hover {background: none repeat scroll 0 0 #666666;} -/* Icon font - MFG labs */ -@font-face { - font-family: 'mfg'; - src: url('../font/mfglabsiconset-webfont.eot'); - src: url('../font/mfglabsiconset-webfont.svg#mfg_labs_iconsetregular') format('svg'), - url('../font/mfglabsiconset-webfont.eot?#iefix') format('embedded-opentype'), - url('../font/mfglabsiconset-webfont.woff') format('woff'), - url('../font/mfglabsiconset-webfont.ttf') format('truetype'); - font-weight: normal; - font-style: normal; -} -i, .icon { - font-family: 'mfg'; - font-size: 1em; - font-style: normal; - font-weight: normal; - color:#e3e3e3; -} -.icon2x {font-size: 2em;} -.icon3x {font-size: 3em;} -.gradient { - color: #999999; - text-shadow: 1px 1px 1px rgba(27, 27, 27, 0.19); - transition: all 0.1s ease-in-out 0s; -} -.gradient:hover, .gradient .current { - color: #EEEEEE; - text-shadow: 0 0 3px rgba(255, 255, 255, 0.25); -} -.icon-cloud:before { content: "\2601"; } -.icon-at:before { content: "\0040"; } -.icon-plus:before { content: "\002B"; } -.icon-minus:before { content: "\2212"; } -.icon-arrow_up:before { content: "\2191"; } -.icon-arrow_down:before { content: "\2193"; } -.icon-arrow_right:before { content: "\2192"; } -.icon-arrow_left:before { content: "\2190"; } -.icon-chevron_down:before { content: "\f004"; } -.icon-chevron_up:before { content: "\f005"; } -.icon-chevron_right:before { content: "\f006"; } -.icon-chevron_left:before { content: "\f007"; } -.icon-reorder:before { content: "\f008"; } -.icon-list:before { content: "\f009"; } -.icon-reorder_square:before { content: "\f00a"; } -.icon-reorder_square_line:before { content: "\f00b"; } -.icon-coverflow:before { content: "\f00c"; } -.icon-coverflow_line:before { content: "\f00d"; } -.icon-pause:before { content: "\f00e"; } -.icon-play:before { content: "\f00f"; } -.icon-step_forward:before { content: "\f010"; } -.icon-step_backward:before { content: "\f011"; } -.icon-fast_forward:before { content: "\f012"; } -.icon-fast_backward:before { content: "\f013"; } -.icon-cloud_upload:before { content: "\f014"; } -.icon-cloud_download:before { content: "\f015"; } -.icon-data_science:before { content: "\f016"; } -.icon-data_science_black:before { content: "\f017"; } -.icon-globe:before { content: "\f018"; } -.icon-globe_black:before { content: "\f019"; } -.icon-math_ico:before { content: "\f01a"; } -.icon-math:before { content: "\f01b"; } -.icon-math_black:before { content: "\f01c"; } -.icon-paperplane_ico:before { content: "\f01d"; } -.icon-paperplane:before { content: "\f01e"; } -.icon-paperplane_black:before { content: "\f01f"; } -.icon-color_balance:before { content: "\f020"; } -.icon-star:before { content: "\2605"; } -.icon-star_half:before { content: "\f022"; } -.icon-star_empty:before { content: "\2606"; } -.icon-star_half_empty:before { content: "\f024"; } -.icon-reload:before { content: "\f025"; } -.icon-heart:before { content: "\2665"; } -.icon-heart_broken:before { content: "\f028"; } -.icon-hashtag:before { content: "\f029"; } -.icon-reply:before { content: "\f02a"; } -.icon-retweet:before { content: "\f02b"; } -.icon-signin:before { content: "\f02c"; } -.icon-signout:before { content: "\f02d"; } -.icon-download:before { content: "\f02e"; } -.icon-upload:before { content: "\f02f"; } -.icon-placepin:before { content: "\f031"; } -.icon-display_screen:before { content: "\f032"; } -.icon-tablet:before { content: "\f033"; } -.icon-smartphone:before { content: "\f034"; } -.icon-connected_object:before { content: "\f035"; } -.icon-lock:before { content: "\F512"; } -.icon-unlock:before { content: "\F513"; } -.icon-camera:before { content: "\F4F7"; } -.icon-isight:before { content: "\f039"; } -.icon-video_camera:before { content: "\f03a"; } -.icon-random:before { content: "\f03b"; } -.icon-message:before { content: "\F4AC"; } -.icon-discussion:before { content: "\f03d"; } -.icon-calendar:before { content: "\F4C5"; } -.icon-ringbell:before { content: "\f03f"; } -.icon-movie:before { content: "\f040"; } -.icon-mail:before { content: "\2709"; } -.icon-pen:before { content: "\270F"; } -.icon-settings:before { content: "\9881"; } -.icon-measure:before { content: "\f044"; } -.icon-vector:before { content: "\f045"; } -.icon-vector_pen:before { content: "\2712"; } -.icon-mute_on:before { content: "\f047"; } -.icon-mute_off:before { content: "\f048"; } -.icon-home:before { content: "\2302"; } -.icon-sheet:before { content: "\f04a"; } -.icon-arrow_big_right:before { content: "\21C9"; } -.icon-arrow_big_left:before { content: "\21C7"; } -.icon-arrow_big_down:before { content: "\21CA"; } -.icon-arrow_big_up:before { content: "\21C8"; } -.icon-dribbble_circle:before { content: "\f04f"; } -.icon-dribbble:before { content: "\f050"; } -.icon-facebook_circle:before { content: "\f051"; } -.icon-facebook:before { content: "\f052"; } -.icon-git_circle_alt:before { content: "\f053"; } -.icon-git_circle:before { content: "\f054"; } -.icon-git:before { content: "\f055"; } -.icon-octopus:before { content: "\f056"; } -.icon-twitter_circle:before { content: "\f057"; } -.icon-twitter:before { content: "\f058"; } -.icon-google_plus_circle:before { content: "\f059"; } -.icon-google_plus:before { content: "\f05a"; } -.icon-linked_in_circle:before { content: "\f05b"; } -.icon-linked_in:before { content: "\f05c"; } -.icon-instagram:before { content: "\f05d"; } -.icon-instagram_circle:before { content: "\f05e"; } -.icon-mfg_icon:before { content: "\f05f"; } -.icon-xing:before { content: "\F532"; } -.icon-xing_circle:before { content: "\F533"; } -.icon-mfg_icon_circle:before { content: "\f060"; } -.icon-user:before { content: "\f061"; } -.icon-user_male:before { content: "\f062"; } -.icon-user_female:before { content: "\f063"; } -.icon-users:before { content: "\f064"; } -.icon-file_open:before { content: "\F4C2"; } -.icon-file_close:before { content: "\f067"; } -.icon-file_alt:before { content: "\f068"; } -.icon-file_close_alt:before { content: "\f069"; } -.icon-attachment:before { content: "\f06a"; } -.icon-check:before { content: "\2713"; } -.icon-cross_mark:before { content: "\274C"; } -.icon-cancel_circle:before { content: "\F06E"; } -.icon-check_circle:before { content: "\f06d"; } -.icon-magnifying:before { content: "\F50D"; } -.icon-inbox:before { content: "\f070"; } -.icon-clock:before { content: "\23F2"; } -.icon-stopwatch:before { content: "\23F1"; } -.icon-hourglass:before { content: "\231B"; } -.icon-trophy:before { content: "\f074"; } -.icon-unlock_alt:before { content: "\F075"; } -.icon-lock_alt:before { content: "\F510"; } -.icon-arrow_doubled_right:before { content: "\21D2"; } -.icon-arrow_doubled_left:before { content: "\21D0"; } -.icon-arrow_doubled_down:before { content: "\21D3"; } -.icon-arrow_doubled_up:before { content: "\21D1"; } -.icon-link:before { content: "\f07B"; } -.icon-warning:before { content: "\2757"; } -.icon-warning_alt:before { content: "\2755"; } -.icon-magnifying_plus:before { content: "\f07E"; } -.icon-magnifying_minus:before { content: "\f07F"; } -.icon-white_question:before { content: "\2754"; } -.icon-black_question:before { content: "\2753"; } -.icon-stop:before { content: "\f080"; } -.icon-share:before { content: "\f081"; } -.icon-eye:before { content: "\f082"; } -.icon-trash_can:before { content: "\f083"; } -.icon-hard_drive:before { content: "\f084"; } -.icon-information_black:before { content: "\f085"; } -.icon-information_white:before { content: "\f086"; } -.icon-printer:before { content: "\f087"; } -.icon-letter:before { content: "\f088"; } -.icon-soundcloud:before { content: "\f089"; } -.icon-soundcloud_circle:before { content: "\f08A"; } -.icon-anchor:before { content: "\2693"; } -.icon-female_sign:before { content: "\2640"; } -.icon-male_sign:before { content: "\2642"; } -.icon-joystick:before { content: "\F514"; } -.icon-high_voltage:before { content: "\26A1"; } -.icon-fire:before { content: "\F525"; } -.icon-newspaper:before { content: "\F4F0"; } -.icon-chart:before { content: "\F526"; } -.icon-spread:before { content: "\F527"; } -.icon-spinner_1:before { content: "\F528"; } -.icon-spinner_2:before { content: "\F529"; } -.icon-chart_alt:before { content: "\F530"; } -.icon-label:before { content: "\F531"; } -.icon-brush:before { content: "\E000"; } -.icon-refresh:before { content: "\E001"; } -.icon-node:before { content: "\E002"; } -.icon-node_2:before { content: "\E003"; } -.icon-node_3:before { content: "\E004"; } -.icon-link_2_nodes:before { content: "\E005"; } -.icon-link_3_nodes:before { content: "\E006"; } -.icon-link_loop_nodes:before { content: "\E007"; } -.icon-node_size:before { content: "\E008"; } -.icon-node_color:before { content: "\E009"; } -.icon-layout_directed:before { content: "\E010"; } -.icon-layout_radial:before { content: "\E011"; } -.icon-layout_hierarchical:before { content: "\E012"; } -.icon-node_link_direction:before { content: "\E013"; } -.icon-node_link_short_path:before { content: "\E014"; } -.icon-node_cluster:before { content: "\E015"; } -.icon-display_graph:before { content: "\E016"; } -.icon-node_link_weight:before { content: "\E017"; } -.icon-more_node_links:before { content: "\E018"; } -.icon-node_shape:before { content: "\E00A"; } -.icon-node_icon:before { content: "\E00B"; } -.icon-node_text:before { content: "\E00C"; } -.icon-node_link_text:before { content: "\E00D"; } -.icon-node_link_color:before { content: "\E00E"; } -.icon-node_link_shape:before { content: "\E00F"; } -.icon-credit_card:before { content: "\F4B3"; } -.icon-disconnect:before { content: "\F534"; } -.icon-graph:before { content: "\F535"; } -.icon-new_user:before { content: "\F536"; } \ No newline at end of file diff --git a/vitess.io/css/main.scss b/vitess.io/css/main.scss deleted file mode 100644 index 630636b82b2..00000000000 --- a/vitess.io/css/main.scss +++ /dev/null @@ -1,20 +0,0 @@ ---- ---- - -// Partials -@import "gist"; -@import "variables"; -@import "vendor/bourbon/bourbon"; -@import "grid-settings"; -@import "vendor/neat/neat"; -@import "mixins"; -@import "reset"; -@import "helpers"; -@import "buttons"; -@import "badges"; -@import "bullets"; -@import "sliding-menu"; -@import "notices"; -@import "animations"; -@import "layout"; -@import "pygments"; diff --git a/vitess.io/css/site.scss b/vitess.io/css/site.scss deleted file mode 100644 index 0d07efa878b..00000000000 --- a/vitess.io/css/site.scss +++ /dev/null @@ -1,738 +0,0 @@ ---- ---- - -@import url("https://ajax.googleapis.com/ajax/libs/jqueryui/1.10.3/themes/smoothness/jquery-ui.css"); - -// Colors -// We're using colors picked from images/vitess_logo.svg. -// Using the brightness principles in https://material.google.com/style/color.html#color-color-palette. -// Primary is a color of mid-range brighntess from the logo. -$primaryBrandColor: #296589; -// Darker is one of the darker colors from the logo. -$darkerBrandColor: #183B4F; -// The logo doesn't have a color light enough. So, we pick something similar from material design. -// Cyan 50 -$lighterBrandColor: #E0F7FA; -// Purple 800 -$accentColor: #6A1B9A; - -// This ensures that icons on the home page use 100% opacity -// with the $primaryBrandColor. Otherwise, the icons inherit -// opacity settings from the header or text is too dark. -$homePageHeaderColor: #757575; - -$linkColor: $primaryBrandColor; -$linkHoverColor: $darkerBrandColor; -$codeColor: $darkerBrandColor; -$codeBkColor: $lighterBrandColor; -$wellColor: #FAFAFA; -$textColor: #616161; -$linkDisabledColor: $textColor; - -$textOnlyLogoFontFamily: "Kavoon", serif; - -$fontFamily: "Roboto", "Helvetica Neue", Helvetica, Arial, sans-serif; - -// Override Bootstrap defaults -body { - color: $textColor; - font-family: $fontFamily; - padding-top: 50px; -} - -// Default link styles -a { - color: $primaryBrandColor; -} -a:hover, -a:focus { - color: $linkHoverColor; -} -a.disabled { - color: $linkDisabledColor; -} -a.external:after { - content: '➚'; -} - -// Paragraphs -p { - line-height: 22px; - margin: 0 0 1em; -} - -footer { - text-align: center; -} - -// Headers -h1, h2, h3, h4, h5, h6 { - color: #000; - opacity: 0.54; -} -h2, h3, h4, h5 { - margin-bottom: 0.8em; -} -#centerTextCol { - h2, h3, h4, h5, h6 { - // We need to set padding-top:50px so heading text isn't hidden - // by the nav bar when linking to a specific anchor. We then set - // a negative margin-top to try to close some of the gap back up, - // but we can only go as far as the margin-bottom of the previous - // paragraph, or else it will overlap and prevent links above from - // being clicked. - padding-top: 50px; - margin-top: -16px; - } -} - -// Code blocks ( +
    )
    -code {
    -  color: $codeColor;
    -  background-color: transparent;
    -  font-size: 14px;
    -  padding: 0;
    -}
    -
    -pre, pre.prettyprint {
    -  background-color: $codeBkColor;
    -  color: #000;
    -  border: none !important;
    -  font-size: 14px !important;
    -  margin: 0 0 1.2em;
    -  padding: 9.5px !important;
    -}
    -
    -// Callouts (note, caution, warning, special, success)
    -aside.note, div.note, p.note {
    -  background: #757575;
    -  color: #FFF;
    -  display: block;
    -  margin: 16px 0;
    -  padding: 24px 24px 24px 72px;
    -  ::before {
    -    content: url('https://developers.google.com/_static/d0cc006813/images/redesign-14/aside-note.svg');
    -    float: left;
    -    height: 24px;
    -    margin-left: -48px;
    -    width: 24px;
    -  }
    -}
    -aside.caution, div.caution, p.caution {
    -  background: #F4B400;
    -  color: #FFF;
    -  display: block;
    -  margin: 16px 0;
    -  padding: 24px 24px 24px 72px;
    -  ::before {
    -    content: url('https://developers.google.com/_static/d0cc006813/images/redesign-14/aside-caution.svg');
    -    float: left;
    -    height: 24px;
    -    margin-left: -48px;
    -    width: 24px;
    -  }
    -}
    -aside.warning, div.warning, p.warning {
    -  background: #DD2C00;
    -  color: #FFF;
    -  display: block;
    -  margin: 16px 0;
    -  padding: 24px 24px 24px 72px;
    -  ::before {
    -    content: url('https://developers.google.com/_static/d0cc006813/images/redesign-14/aside-warning.svg');
    -    float: left;
    -    height: 24px;
    -    margin-left: -48px;
    -    width: 24px;
    -  }
    -}
    -aside.special, div.special, p.special {
    -  background: #039BE5;
    -  color: #FFF;
    -  display: block;
    -  margin: 16px 0;
    -  padding: 24px 24px 24px 72px;
    -  ::before {
    -    content: url('https://developers.google.com/_static/d0cc006813/images/redesign-14/aside-special.svg');
    -    float: left;
    -    height: 24px;
    -    margin-left: -48px;
    -    width: 24px;
    -  }
    -}
    -aside.success, div.success, p.success {
    -  background: #0F9D58;
    -  color: #FFF;
    -  display: block;
    -  margin: 16px 0;
    -  padding: 24px 24px 24px 72px;
    -  ::before {
    -    content: url('https://developers.google.com/_static/d0cc006813/images/redesign-14/aside-success.svg');
    -    float: left;
    -    height: 24px;
    -    margin-left: -48px;
    -    width: 24px;
    -  }
    -}
    -// End callouts
    -
    -// Feature comparisons
    -.compare-no, .compare-yes {
    -  font-weight: bold;
    -}
    -.compare-no::before {
    -  background: url('https://developers.google.com/_static/d0cc006813/images/redesign-14/compare-no.svg')
    -}
    -.compare-yes::before {
    -  background: url('https://developers.google.com/_static/d0cc006813/images/redesign-14/compare-yes.svg')
    -}
    -.compare-no::before,
    -.compare-yes::before {
    -  content: '';
    -  display: inline-block;
    -  height: 24px;
    -  margin: -4px 4px 0 0;
    -  overflow: hidden;
    -  vertical-align: middle;
    -  width: 24px;
    -}
    -
    -// Navbar
    -
    -#common-nav{
    -  margin-bottom: 0px;
    -  background-color: $darkerBrandColor;
    -
    -  .logo {
    -    height: 34px;
    -  }
    -}
    -#common-nav > div {
    -  max-width: 100%;
    -}
    -
    -// Navbar colors
    -.inverse {
    -  background-color: $primaryBrandColor;
    -  color: white;
    -
    -  a {
    -    color: $lighterBrandColor;
    -  }
    -  a:hover,
    -  a:focus {
    -    color: $linkHoverColor;
    -  }
    -}
    -
    -.inverse .inverse-light {
    -  background-color: $lighterBrandColor;
    -}
    -
    -// Fix Bootstrap mobile menu colors on inverse navbar
    -.navbar-toggle .icon-bar {
    -  background-color: $lighterBrandColor;
    -}
    -
    -/* Home page styles */
    -#home {
    -  h2 {
    -    color: $homePageHeaderColor;
    -    opacity: 1;
    -    a {
    -      color: $homePageHeaderColor;
    -      text-decoration: none;
    -    }
    -    a:hover {
    -      color: $primaryBrandColor;
    -    }
    -  }
    -}
    -#home > div.container {
    -  max-width: 100%;
    -}
    -.home-full-width {
    -  width: 100%;
    -  padding-left: 0;
    -  padding-right: 0;
    -}
    -.container {
    -  .jumbotron {
    -    background: $darkerBrandColor;
    -    border-radius: 0px 0px 6px 6px;
    -    color: $lighterBrandColor;
    -    text-align: center;
    -    width: 100%;
    -  }
    -}
    -.page-title-bar{
    -  background-color: $lighterBrandColor;
    -  margin: 50px 0px 0px;
    -  padding-bottom: 10px;
    -  padding-top: 15px;
    -
    -  h1, h2, h3, h4, h5, h6 {
    -    color: $primaryBrandColor;
    -  }
    -}
    -.page-spacer {
    -  height: 2em;
    -}
    -#home-page-logo {
    -  margin: 40px;
    -  max-width: calc(100% - 80px);
    -  text-align: center;
    -  height: 228px;
    -}
    -#home-page-text-only-logo {
    -  font-family: $textOnlyLogoFontFamily;
    -  font-size: 96px;
    -}
    -.navbar-brand-text-only {
    -  line-height: 50px;
    -  .text-only-logo {
    -    font-family: $textOnlyLogoFontFamily;
    -    font-size: 24px;
    -  }
    -  :hover {
    -    color: $lighterBrandColor;
    -  }
    -}
    -.kavoon {
    -  font-family: $textOnlyLogoFontFamily;
    -}
    -// Docs layout specific
    -.docs-side-nav {
    -  margin-top: 40px;
    -}
    -
    -// User logos are centered and need the padding.
    -.logo-row {
    -  margin-top: 10px;
    -  text-align: center;
    -}
    -
    -// Table styles
    -table {
    -  background:none repeat scroll 0 0 #FFF;
    -  border:1px solid #D0D0D0;
    -  border-bottom:1px solid #D0D0D0;
    -  border-collapse:collapse;
    -  border-spacing:0;
    -  text-align:left;
    -  width:100%;
    -  margin-bottom: 2.125em;
    -}
    -
    -table thead {
    -  background: #757575;
    -  tr th {
    -    color: #FFF;
    -    font-weight: 500;
    -    text-align: left;
    -  }
    -}
    -
    -table tr th {
    -  color: #FFF;
    -  font-weight: 500;
    -  text-align: left;
    -}
    -
    -table tbody td {
    -  vertical-align: top;
    -}
    -
    -table tr td, table tr th {
    -  padding:0.625em;
    -}
    -table tfoot, table tr:nth-of-type(2n) {
    -  background:none repeat scroll 0 0 #F6F6F6;
    -}
    -table tbody {
    -  background:none repeat scroll 0 0 #FFF;
    -}
    -tbody th, tbody td {
    -  border-right:1px solid #E0E0E0;
    -}
    -
    -/*
    - * Responsive tables
    - */
    -table.responsive tr:not(.alt) td td:first-child,
    -table.responsive td tr:not(.alt) td:first-child {
    -  vertical-align: top;
    -}
    -table.responsive table.responsive {
    -  margin: 0;
    -}
    -
    -table.responsive tr:first-child {
    -  border-top: 0;
    -}
    -
    -table.responsive td tr:first-child td {
    -  padding-top: 0;
    -}
    -
    -table.responsive td tr:last-child td {
    -  padding-bottom: 0;
    -}
    -
    -table.responsive td td:first-child {
    -  padding-left: 0;
    -}
    -table.responsive th:not(:first-child) {
    -  display: none;
    -}
    -
    -#api-method-summary tr td.api-method-summary-group {
    -  background:#F6F6F6;
    -}
    -#api-method-summary tr {
    -  background:#FFF;
    -}
    -br.bigbreak {
    -  line-height: 2em;
    -}
    -div.indent-details {
    -  padding-left: 1.6250em;
    -}
    -
    -// Table of contents
    -#toc {
    -  border-left: solid 3px $primaryBrandColor;
    -  padding-left: 12px;
    -}
    -#toc ol, #toc ul {
    -  font-size: 13px;
    -  list-style: none;
    -  margin: 0;
    -  padding-left: 0;
    -  padding-right: 0;
    -}
    -#toc ol ol, #toc ol ul, #toc ul ol, #toc ul ul {
    -  padding-left: 25px;
    -  list-style: circle;
    -}
    -#toc li {
    -  margin-bottom: 0;
    -}
    -#toc-contents-header {
    -  font-size: 13px;
    -}
    -
    -// Lists
    -ol ol, ol ul, ul ol, ul ul {
    -  margin: 0.8em 0em;
    -}
    -ol ol li, ol ul li, ul ol li, ul ul li {
    -  margin: 0;
    -}
    -li {
    -  line-height: 22px;
    -  margin-bottom: 0.5em;
    -}
    -
    -/*
    - * Top nav
    - */
    -.icon-bar {
    -  background-color:#FFF;
    -}
    -
    -/*
    - * Left nav
    - */
    -#left-nav {
    -  overflow-x: hidden;
    -  overflow-y: auto;
    -}
    -
    -#sidebar > li > h4.no-top-margin {
    -  margin-top: 0;
    -}
    -#sidebar > li > h4 {
    -  font-size: 16px;
    -  margin-top: 0.8em;
    -}
    -.nav > li > h4.no-top-margin {
    -  margin-top: 0;
    -}
    -#sidebar > li > a {
    -  padding: 6px 15px 6px 0px;
    -}
    -#sidebar li a {
    -  font-size: 13px;
    -}
    -#sidebar li ul li, #sidebar li ol li {
    -  padding-bottom: 5px;
    -}
    -#sidebar li.submenu ul {
    -  display: none;
    -  li.submenu-parent {
    -    padding-bottom: 0;
    -    ul {
    -      display: block;
    -      list-style-type: none;
    -      margin: 0.4em 0 0 0;
    -    }
    -  }
    -}
    -#sidebar.affix-top {
    -  max-height: calc(100vh - 172px);
    -}
    -#sidebar.affix,#sidebar.affix-top{
    -  max-width: 170px;
    -  @media (min-width: 992px) {
    -    width: 228px;
    -  }
    -}
    -#sidebar.affix, #tocSidebar.affix {
    -  @media (min-width: 1200px) {
    -    position: fixed;
    -    top: 70px;
    -    bottom: 0px;
    -    overflow-x: hidden;
    -    overflow-y: auto;
    -  }
    -  @media (min-width: 992px) {
    -    position: fixed;
    -    top: 70px;
    -    bottom: 0px;
    -    overflow-x: hidden;
    -    overflow-y: auto;
    -  }
    -}
    -// collapsible menus
    -h4.arrow-d, h4.arrow-r {
    -  cursor: pointer;
    -}
    -
    -h4.arrow-r::before {
    -  content: "+ ";
    -  font-family: monospace;
    -  font-weight: bold;
    -}
    -
    -h4.arrow-d::before {
    -  content: "- ";
    -  font-family: monospace;
    -  font-weight: bold;
    -}
    -#search-form {
    -  padding: 4px 6px;
    -  width: 100%;
    -}
    -
    -#masthead {
    -  background-color: $lighterBrandColor;
    -  margin-bottom: 40px;
    -  min-height: 105px;
    -
    -  h1 {
    -    color: $primaryBrandColor;
    -    font-size: 36px;
    -    opacity: 1;
    -    padding: 18px;
    -    @media (min-width: 768px) {
    -      font-size: 40px;
    -    }
    -  }
    -}
    -
    -.navbar-brand {
    -  padding: 7px 15px;
    -
    -}
    -
    -.nav > li {
    -  margin-bottom: 0;
    -}
    -.nav li.active-item {
    -  font-weight: bold;
    -  text-decoration: none;
    -  ul, ol {
    -    font-weight: normal;
    -  }
    -}
    -.nav-stacked > li+li {
    -  margin-top: 0;
    -}
    -.nav ol, .nav ul {
    -  list-style: none;
    -  padding-left: 1.5em;
    -}
    -
    -.affix-top,.affix{
    -  position: static;
    -}
    -
    -// Accommodate different screen sizes
    -@media (min-width: 1200px) {
    -  body .home-full-width {
    -    max-width: 100%;
    -  }
    -  #tocSidebar.affix, #tocSidebar.affix-top {
    -  }
    -  #toc > ul > li > a {
    -    display: inline-block;
    -    padding-left: 10px;
    -    text-indent: -10px;
    -  }
    -}
    -@media (min-width: 992px) {
    -  #sidebar.affix-top, #tocSidebar.affix-top {
    -    position: static;
    -  }
    -}
    -@media (min-width: 768px) {
    -  body .home-full-width {
    -    width: 100%;
    -    margin: 0px;
    -  }
    -  #sidebar.affix {
    -    position: fixed;
    -    top: 70px;
    -    bottom: 0px;
    -    overflow-x: hidden;
    -    overflow-y: auto;
    -  }
    -}
    -
    -/* Three-column layout */
    -#leftCol {
    -  float: left;
    -  overflow-x: hidden;
    -  overflow-y: auto;
    -  @media screen and (max-width: 991px) {
    -    max-width: 200px;
    -  }
    -  @media screen and (max-width: 767px) {
    -    display: none;
    -  }
    -}
    -#centerCol {
    -  @media screen and (max-width: 1199px) {
    -    z-index: 1;
    -  }
    -  @media screen and (max-width: 991px) {
    -    margin-left: calc(25% + 15px);
    -    z-index: 1;
    -  }
    -  @media screen and (max-width: 767px) {
    -    margin-left: 0;
    -  }
    -}
    -#rightCol {
    -  float: right;
    -  overflow-x: hidden;
    -  overflow-y: auto;
    -  padding-right: 0px;
    -  position: static;
    -  z-index: 10000;
    -
    -  li.active > a {
    -    color: $accentColor;
    -    font-weight: bold;
    -  }
    -  @media (min-width: 1200px) {
    -    #tocSidebar.affix, #tocSidebar.affix-top {
    -      max-width: 210px;
    -    }
    -  }
    -  @media screen and (max-width: 1199px) {
    -    margin: 0;
    -  }
    -  @media screen and (max-width: 991px) {
    -    float: none;
    -    margin: 12px 0 30px calc(25% + 15px);
    -    max-width: 255px;
    -  }
    -  @media screen and (max-width: 767px) {
    -    margin: 12px 0 30px;
    -  }
    -}
    -
    -main .fa {
    -  color: $primaryBrandColor;
    -}
    -#mobile-left-nav-menu-button {
    -  display: none;
    -  background-color: transparent;
    -  background-image: url('/images/left-nav-menu-expander.svg');
    -  border: 0;
    -  height: 24px;
    -  margin-left: 10px;
    -  min-width: 24px;
    -  @media screen and (max-width: 767px) {
    -    display: block;
    -  }
    -}
    -#collapsed-left-menu {
    -  display: none;
    -  h4 {
    -    color: $lighterBrandColor;
    -  }
    -  #collapsed-left-menu-repo-link {
    -    font-size: 18px;
    -    margin-left: 0.25em;
    -  }
    -  @media screen and (max-width: 767px) {
    -    display: block;
    -    margin-top: 1em;
    -  }
    -}
    -.main-site-content {
    -  @media screen and (max-width: 991px) {
    -    padding: 0 24px;
    -  }
    -  @media screen and (max-width: 767px) {
    -    padding: 0 16px;
    -  }
    -}
    -@media screen and (max-width: 1199px) {
    -  #toc-content-row {
    -    position: relative;
    -    z-index: 1;
    -  }
    -}
    -@media screen and (max-width: 991px) {
    -  /*
    -   * Force responsive tables to lay out completely vertically. The "responsive"
    -   * class should only be applied to tables that are composed like a definition
    -   * list, with a "term" (say, a property name) in the first column and any
    -   * "definitions" (say, type, description, and a sample value) stacked on top
    -   * of each other in the second column. This makes it possible to lay out the
    -   * table vertically and keep it readable on smaller screens without horizontal
    -   * scrolling. This structure and behavior is documented.
    -   */
    -  table.responsive,
    -  table.responsive thead,
    -  table.responsive tbody,
    -  table.responsive tr,
    -  table.responsive th,
    -  table.responsive td {
    -    display: block;
    -  }
    -}
    -@media screen and (max-width: 767px) {
    -  #standard-menu-links {
    -    display: none;
    -  }
    -}
    -.reset-box-sizing,
    -.reset-box-sizing *,
    -.reset-box-sizing *:before,
    -.reset-box-sizing *:after {
    -  -webkit-box-sizing: content-box;
    -  -moz-box-sizing: content-box;
    -  box-sizing: content-box;
    -  border: none;
    -  margin: 0px;
    -  padding: 0px;
    -}
    -
    -.gsc-table-result td {
    -  padding-left: 8px;
    -}
    diff --git a/vitess.io/getting-started/docker-build.md b/vitess.io/getting-started/docker-build.md
    deleted file mode 100644
    index 36275eb4400..00000000000
    --- a/vitess.io/getting-started/docker-build.md
    +++ /dev/null
    @@ -1,17 +0,0 @@
    ----
    -layout: doc
    -title: "Custom Docker Build"
    -description: Build a custom Docker image for Vitess.
    -date: 
    -modified:
    -excerpt:
    -tags: []
    -image:
    -  feature:
    -  teaser:
    -  thumb:
    -toc: true
    -share: false
    ----
    -
    -{% include doc/DockerBuild.md %}
    diff --git a/vitess.io/getting-started/index.md b/vitess.io/getting-started/index.md
    deleted file mode 100644
    index 544b44a734d..00000000000
    --- a/vitess.io/getting-started/index.md
    +++ /dev/null
    @@ -1,18 +0,0 @@
    ----
    -layout: doc
    -title: "Running Vitess on Kubernetes"
    -description: Vitess runs best in a containerized environment like Kubernetes,
    -             which manages a cluster of Linux containers as a single system.
    -date: 
    -modified:
    -excerpt:
    -tags: []
    -image:
    -  feature:
    -  teaser:
    -  thumb:
    -toc: true
    -share: false
    ----
    -
    -{% include doc/GettingStartedKubernetes.md %}
    diff --git a/vitess.io/getting-started/local-instance.md b/vitess.io/getting-started/local-instance.md
    deleted file mode 100644
    index 9f228d4d7f3..00000000000
    --- a/vitess.io/getting-started/local-instance.md
    +++ /dev/null
    @@ -1,17 +0,0 @@
    ----
    -layout: doc
    -title: "Running Vitess on a Local Server"
    -description: Learn how to build Vitess on a local server.
    -date: 
    -modified:
    -excerpt:
    -tags: []
    -image:
    -  feature:
    -  teaser:
    -  thumb:
    -toc: true
    -share: false
    ----
    -
    -{% include doc/GettingStarted.md %}
    diff --git a/vitess.io/go-import/messages.html b/vitess.io/go-import/messages.html
    deleted file mode 100644
    index 9941d3e2b34..00000000000
    --- a/vitess.io/go-import/messages.html
    +++ /dev/null
    @@ -1,4 +0,0 @@
    -
    -
    -
    -
    diff --git a/vitess.io/go-import/vitess.html b/vitess.io/go-import/vitess.html
    deleted file mode 100644
    index c1a7742ce17..00000000000
    --- a/vitess.io/go-import/vitess.html
    +++ /dev/null
    @@ -1,4 +0,0 @@
    -
    -
    -
    -
    diff --git a/vitess.io/images/120x120.gif b/vitess.io/images/120x120.gif
    deleted file mode 100644
    index e71a7861e7962b2a53e96c4d2a17528782b45bef..0000000000000000000000000000000000000000
    GIT binary patch
    literal 0
    HcmV?d00001
    
    literal 425
    zcmV;a0apG;Nk%v~VR!&|0OJ4v%*@P|mX@ljs=mIyoSdAov9Y(ex5dT9qobn$00000
    z00000000000000000000EC2ui0C)g+000F35XecZy*TU5yZ>M)j$~<`XsWJk>%MR-
    z&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v&*-#z&2GEj
    z@VIDDk0gzM!1ObN<2m}TM2oePW
    z1_1>gnw%4#p`!q$r>Ro|1*H=P1F@Y5qrR%QodCMLp1-hExD^Bh5(KFQ&J?Vy70VRO
    z&(YJ$!=$DXsKyinr~$jz-@FFm(d$vz0Optga!>k-&hH;AT~rm@wB!PbN{a8%KqcHJjD|
    z=&P{E;yRq-fabeIsHoASNRujE%CxD|r%M)j$~<`XsWJk>%MR-
    z&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v&*-#z&2GEj
    z@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!o$SH#>dFX%FE2n&d<=%($mz{*4NnC
    z+S}aS-rwNi;^XAy=I7|?>g(+7?(gvN^7Hid_V@Vt`uqI-{{H|23LHqVpuvL(6DnND
    zu%W|;5F<*QNU@^Dix@L%+{m$`$B+IXLy8oJq5$&6_xL
    z>fFh*r_Y~2g9;r=w5ZXeNRujE%CxD|r%fOt?uiw9b0}CEZxUk{Fh!ZPb%($`R$B-jSo=my2
    z<;$2eYu?Pcv**vCLyI0wy0q!js8g$6&APSg*RW&Do=v;9?c2C>>)y?~x9{J;g9{%{
    zytwh>$dfBy&b+zv=g^}|pH98H_3PNPYv0bjyZ7(l!;2qJzP$PK=+moT&%V9;_weJ(
    zpHIKO{rmXy>)+46zyJRL2L34EfCLt3;DHDxsNjMOHt67k5Jo8BgcMe2;e{AxsNsej
    zcIe@UAciR7h$NP1;)y7xsN#w&w&>!EFvck3j5OA07|%v
    zs_CYjcIxS;poS{ysHB!^>Zz!vs_Lq&w(9Duu*NFuthCl@>#exvs_U-2_Uh}ezy>Sq
    zu*4Q??6JrutL(DO{x<9Ev(QE>?X=WZYwfkzW~=SC+;;2jx8Q~=?zrTZYwo$|rmOC{
    z?6&LfyYR*<@4WQZYwx}I=Bw|%{PyebzW@g;@W2EYZ1BMdC#>+o3^(lX!w^R-@x&BY
    zZ1KeyXRPtY9Cz&T#~_C+^2j8YZ1Tw{r>yeIEVu0P%P_|*^UO5YZ1c@H=dAP2JooJL
    z&p-z)^w2~XZS>JdC$03-OgHWH(@;k(_0&{XZS~byXRY*wdY`5+9+i=G%_uO>XZTH=H=dJhNeE045-+%`$_~3*WZusGdC$9M7j5qH1a4f!`s=XAF8l1X*KYgmxaY3>
    z?!5Qz`|rR9FZ}St7jOLW$S1G-^2|5y{PWO9Fa7k?S8x6G*k`Z(_S|>x{rBL9FaG%C
    zmv8?0=%=s#`s}yw{`>I9FaP}X*Khy*_~)p$JDv!V;SBgeXj*3PmOW1Pnj`PY{3s
    z27rJ9*zkrfGyn{vAVV775QhWMp*Ch%!vh>300A&!0dg2aBL2{ZIou%>dRW6JMlpQ?
    z7=Zp3x5z~;QlS7y48Q=EkVP}42rc}roUk(k`$
    z1PEc8)I6g#krB*nA`zK8z@|3?uuUL{)0^eQ9x7)U%_At&
    zke$qd05myHKDM(4^Q`AF@5zfo>JyE>lqWs^c>sRSAfNyIra_taPEam12>z_(0sa_?
    z0|N{+p#iX^4lIh%Gio##=S*liYrxTtBJraYy=X#F3cYm-^PxX5fG|fo1DTrCqZ_>`
    zPC=^ENZ!DvJ!L5kfT~lWGBleo?Eyk(d4Qkxbf-2TYEXd@Qj->dq)!c_QDGp}qC&5m
    zy-ey3mO9I=wt%cp6>AC5+EcZ%qN+Eg=~-2(Q@4(Qt#x%?L#b)k8{krq0i^+5b=uS#
    z4ECml-NjzBDn=O`)})D@!DBlbS>%;;oPDhUTm>mt7;HAKH2ADZJ3EW6GB%^0J*_rF
    ztJ*MdHE!@O{;N;n#=x|Y
    ztgH<1%GiR!fVx?=?kz;y)7Rb=xQKNw2C(~7?G7)tm^}h{>u6rqwib=vEdh6R8sAk2
    z;Jt1%s|e-`+86M5w8LX=LdENXzwS}LEV!>R5g^1Ff>)I;Q1DC}Jb(wMk-(fVFk@|-
    z0txq$!7y~NF)=&=56=?B01)v@gZJOC8UekARBjA3Y{^x+w6+BnW&vzWV>{LYy3r-T
    z4h28}3#Spm9_TR|cWi+hgObB5P;w}FtmEGaxT7Ra0gyRc(JE)4#V2LKmg@**3xFB5
    zvp92OF92gMqhQRg)WDgM`~f&yQqIDp^Xt^iP9m%~&Nu+GbS)tMWh9pQ1cK&3p#yN}
    zR+xB`X0>srGz&SX!8|w=IWmi)L&W5iCqP^N!ESlM1
    z_VlzryzLW1o7)|rwrg((>b44D*SOY!kq@bBVX9!=0eC37-zbY>XJFoLJORAr?d}xp
    zyWPFC9lo(F1X43w%;5F_m~-s`NmpCpy<~VP93IBNazNZ+CIQ8fcyItL{LKmPz{hI`
    zZ$4r?-a$Bd62s|hfIk@pU{315LkWwM%e>Us~IbX5v
    zw%eMiB-nWfB%k#PXrAYemz}c6B9Q&<
    zbGiFXy8d;KCH)0xZv#^6`K+ObIO9R@?Gb!_6~w=Hz(v6M%tt@i&42vzWd~j1W8nHS
    z`1`YYApSF2z5?YB{sE9b0PwGW{*%D}x3gET)B*PQ
    z0;udlHp9Ep&VU(1KbvQ$O%^PDgNCAcBg_o#tVE6&4I0BuRJd!v9
    zDmRFssDTR@g&Pod8`y+D$X71cZ$E&9%;$R}po`RpiyB~zn}>|U6N}5Ziah{tD6nZV
    z2ujl!gG@(Fh$sOn7e*;ph^z>X)woI5Sc4xRjVC~j%Hxb6aB@p%1L`=5Q@8=~XoHm$
    z1ljbC08nz?2n3SHZ`((J*f@^&7y|W3gVwk_?D&hDREG)1j7esJl2?iupo}`;O$dg1
    zXLL>3w*f8Ic`gW%9bl2t$BRz5kgN0Bptf7^I>JK2a}*^X_QjoB1w<1_?+26${%X?CTSDA0G0_?F?=
    zehPV%$cL3BMgV{WMM7o+emRHYxQ2px0({wv+4NdCX_Y{Le~UC^MMj4u(3mAKnOxYA
    zC?J~1Q5~9@Q2U8Q7@(Vs=9)x#S}%EN4Jx4znu{O0l@r=K=qUl&she16h0ZvU
    zwYW?u;G#zWf5x?O9ZG&#<&XhtpbQB~@!6s!$~!0OalN^sCh%`3AbI*I0Z3{BN}2>l
    zc4#f8p$1r?WQJi)x>g6N0a<#B1KEr`nxws{PzMU6UwQ#ux{Kym1n`GQj~NAE)t&Bn
    zp=P?K8<3{Qc&5Q~qL(>NOUeOw`iyqUrFBY-Pzp-A)uvT2M+s$0{#K|rc#e=7U4t2v
    zE`Xu-sRF>5j{bUTc(bIbo$3SW2W9`YmZNl2AD9B0>UE(y0jpX9TN;UBs-jHAt3Y66QZ%SdfS-_Ls`TiqAc(B4s;nIFs>Oqzefm$%<*fC`tUG9}8bGZ>
    zkbb|EemXiYN;%Msrs~_o|=&5D6aykuAFMGNT6herLR(O
    zmjnfMb1q0kH*!R)KrH>o2@)+
    zw#$mPN{LZ(nuSbdROKc}V_3K?tGJ1ax5;X`ChE5zKy0tYXYhKhnrpOtTe+AUvZZ?j
    zZkwM^0B=TGVy;`QqieXMOSwp^w{Y2S+5&23
    ztlj8VB44Aa
    z#c@0Vc}$&c45noaqJQj>_9mUQ8Jc@60V7wNo8-Yf(2b6qY)h;GJ?zFm%*g(g)NzZ9
    z$b-D6NjzLh>7Z|HmXq88l}yTqjE4t&z9WXkKbyuBu%3KqoUvTWZn??``@k!pa(i1z
    zW=P9ynaUe*%5W*nPH=MDd%RI>!htLS#2lEHY|6l_0kW*Zx~u}(#=?pGe$$M~(R|Cc
    zc>>kk1egY=+dQ6OEX}xF%-=lB-HZX_49M4<0%NzK%bWpP*_G++l$|VcYn%iN+qjZ!
    z%zwGgLVV5_(8pid&xX9uUE9q4Ys*Y*!+A=e{Rz<$u)!BS&xxdKp1J3A}A)3A)D
    z@{80it<>Kuk4vq(RO>eFDHx*dDZlQd2O
    z4UdT1vtr%LhUA@ZeYY^Zt{gqqW}Ue*O#wyuwV4c+8SJD8{j1}2!#H5Oc?(IMYt#&F
    zz!*KfgPl8G-PQpMiR#?W;7ppFjM++1zi9-uG=SJMo!9B9*{aOhlq}JpOwhR;*evkX
    z`)f#|yh+Ji%cG0|T&al;-2@pszBw?}kS)Bq&CXE?#o-)=|Ln<+-2uRj!dxA~k*&xr
    zXvcs}!%yJZZUown#n@a;-FIxg-d%y847B5&oZQ{iS&iNV{>i^rO{q?;-b)~~zU^1Z
    zos~gq)#;7Z>+QZrn$$?V+z5Qz8=$`WOxivD*G#$BI}1vYd;{41M%ul2sD0UuEZz#9
    z*lt$cvQ5{J)Zj#2-X3buvuV-9T}fj(+&)~~f=t^`U||n7-cJODo)0C
    z{f0-)zBqonasAWMd%1Nz!y7KukT!ELUQ@7Ld!c;RBu>Nz{?a~5<`*ucAYR&C&H<=b
    zhbc|fbB^Y(R?%dg1k|>#ES?0OIm_f4=)pbcbnfH+V14LD3E*(9+BN>>?#$W~?aP=9
    zNx$srMPOmw3g1Ie&M=JDiKyw$?CR(T>z3Wx*8SR14gjPk*sM-y=Y8g7P3cT-i>8j~
    zoF3^}9@~2)*S&t{MY!j*Q-$kN#vzD?^V9Jm_FdGT8guREw&azD!N7_iByz3cu=>fDU-
    zyb18JUg7FxOl?=ceP#0QKISQ4^Q$fC58eLf_AJr$i|_AQ?EVT>dJKL=zjSOAkieR+
    z2XEigZrp*K^f`U>VM_IA<~*p0(+I}(?^eJp`StxA_Dk?z_sQUCjlcJV^;O^A9p2EW
    zZjWzI$o}2c>CU~>M3)||0-C9YDi`5>PtA=^Mo%ns6u;k~-s*cF>i(XZD*v|z{rAy>
    zoY*a6mEW%GKAa@~@M!P&&+P;M^?Oq0;VppEjJB9A$f$Y$s1T@fZEoJJkH6A`o+^s^
    zM5dz0WlR%gYo8e5ua3Wo+WV}0>@V;0KCrspWY{ZTX~8e^E>OR_|9-+RJmqUlMgHIz
    z<@>mvkGiS+SI7NP%}P9K@eyybI{qAG;E%m9Ahq33>+f~#W9t1>UaM=p<0f1Gb!?@*
    zoBW6G&9y4@5CG&f!Csv8<~^7x6i1S*JTy(gvUOiLmS?)QZ#>s`zW0A%P&gzOjYnis
    zxnwq-&!9>=&E!s0?35)OWWAe#vHK-k!q8TseA%|HGEM8!qMM#o3UNT5G59Y0E}K%oOnsRJa=&XmtYJyICDvOtydV59njUCqf{)+?lA>PapP$EzqL40)pw)keq;6Nh}r6EKju^GjC88vR?
    z*wN!hkRglotFj}Uxi(_NaZ`DXWuZC@ngs`5$%dFBz2wdKCXno>HWvbhl?#0n|JI|NAuamwa`%K6a
    za6keJG%&Z`h7h1WJrK~(2>}KGFogjgd?LaLQK)d2GBkTZHV+^%AUG@v@URIC$=DE)
    z6u(&UKp10`aYh<9N{}1|zi^Nd0!Z|r0NM)akqRJv@ll1pXvmO*XC8_0NG4yj3CazM
    zbY#dWtgLZMF1z&dOX=jAuLuGVSQ3K+5D4-R0|r2#09g(w0D%EcRHV%}$Ue@eDl?J
    zUw-@b_g{bm7I6%QpLLw9{65ZMNHX`)#=6mV0ix>$dxD
    zy#DjndvCt`_WN(Z0~dU7!V5S2aKsZ=d~wDbcl>e4BbR(~$}6}0a?CT=d~?n__xy9v
    zLl=E?(n~k}bktKZ`Z@dhD~;etYh__x^kE!xw*i^2;~>eDu>-e|`4bcmI9(JqaAaUo7?1OH@*2yaE4Qy<0NM}&3R6Arc<5kWM@0w`A&GoQ=aprXFcuyc~5-iQ=j|f
    zXFvV3uS0S9r{p+MpU8`rD#PhdQpsKRHGZ^Xh%KzQILjI
    zq$4G1NlkiEl%`arD`ja*UHVd(##E*=rD;uVdQ+U{RHr-TX-|FnQ=kS_s6!=cQH^?3
    zq$X9VOJ!S>r0Si~bHafwZQViYGc
    G0suSI^J@YC
    
    diff --git a/vitess.io/images/400x250.gif b/vitess.io/images/400x250.gif
    deleted file mode 100644
    index a077326cbd5ee266d969e4c8fdfd6d0be02e636f..0000000000000000000000000000000000000000
    GIT binary patch
    literal 0
    HcmV?d00001
    
    literal 1457
    zcmV;i1y1@$Nk%v~VUPj(0OJ4v%*@P|mX@)xvBky3x3{;PoSdqvs-vT$zP`Qy00000
    z00000000000000000000EC2ui0FVLt000F35XecZy*TU5yZ>M)j$~<`XsWJk>%MR-
    z&vb3yc&_h!@BhG{a7Zi~kI1BQ$!t2G(5Q4uty-_xtai)odcWYXcuX#v&*-#z&2GEj
    z@VIs;jK6uCK7Mva__cwzs&sy1Tr+zQ4f1!o$SH#>dFX%FE2n&d<=%($mz{*4NnC
    z+S}aS-rwNi;^XAy=I7|?>g(+7?(gvN^7Hid_V@Vt`uqI-{{H|23LHqVpuvL(6DnND
    zu%W|;5F<*QNU@^Dix@L%+{m$`$B+IXLy8oJq5$&6_xL
    zdK56=!vF&X0t6^vpl64lL5CJKf&i#cq6jnyol3PTfelEXE-gqvC{GRos!kOER;w2HZ7U0K;CYaWD8?3s~S>p^Y(gJ)F40
    zOF=hs3Cfx87+hI*!YqgzVHfzrTzwhe|P~%m4NQ)RT~A_F<75Z;2Ag-g7}QK;02>yC&6L?
    zRFfZ@*@~k<6)p%XroCtqXjj3FjxTNy;q1=J|@ccUFlSUg{y4&I`VIM+h7trw=zsY5
    z*wcHSo!OhGL^_z_2OqX*LZePf@R?Adg^Hc0_6$}Rr+69$Dy*-L`oUn5VoJh`NZLvp
    zqsj^Cs;aooW1(ot{vO+FmbpS(D+uqIT7q%`L@L1m0;p9$YQXOHsjlNnTTi$hGD~i>
    zbWV%xy6lR8Eqf=}`7H+|Hb<3)&N>SZhv(_mDZKBR+i$WPGK3;lVmJmHg2Fp@up@<3
    z!^*V;IohN3x+_w^b=(uIZ8l*eU@0PoBNKQb-Cu)t&)X9Fow3b^ODGiD8q^3j$yNDm
    z!DCl9oj3*lD*xl`eNVF7vDHj_ez$PMO|3zYjB}}B^&wZ-c0LuiA!r%1&rTJefl
    z%%W=+x5&jVdhv^345JvwNX9an@r-CpqZ-%9#x}a~jc|;k9Op>KI@
    -
    -
    -
    diff --git a/vitess.io/images/cncf-icon-color.svg b/vitess.io/images/cncf-icon-color.svg
    deleted file mode 100644
    index adfcced9f7a..00000000000
    --- a/vitess.io/images/cncf-icon-color.svg
    +++ /dev/null
    @@ -1,28 +0,0 @@
    -
    -
    -
    -
    -
    -	
    -		
    -		
    -		
    -		
    -	
    -	
    -		
    -		
    -		
    -		
    -	
    -
    -
    diff --git a/vitess.io/images/hamburger-white.svg b/vitess.io/images/hamburger-white.svg
    deleted file mode 100644
    index d2f5d1943a7..00000000000
    --- a/vitess.io/images/hamburger-white.svg
    +++ /dev/null
    @@ -1,6 +0,0 @@
    -
    -
    -
    -
    -
    -
    diff --git a/vitess.io/images/kubernetes.svg b/vitess.io/images/kubernetes.svg
    deleted file mode 100644
    index bedd3b88e43..00000000000
    --- a/vitess.io/images/kubernetes.svg
    +++ /dev/null
    @@ -1,84 +0,0 @@
    -
    -
    -
    -
    -  
    -  
    -  
    -    
    -      
    -        image/svg+xml
    -        
    -        
    -      
    -    
    -  
    -  
    -    
    -      
    -      
    -    
    -  
    -
    diff --git a/vitess.io/images/left-nav-menu-expander.svg b/vitess.io/images/left-nav-menu-expander.svg
    deleted file mode 100644
    index 7a92adcbfa6..00000000000
    --- a/vitess.io/images/left-nav-menu-expander.svg
    +++ /dev/null
    @@ -1,3 +0,0 @@
    -
    -
    -
    diff --git a/vitess.io/images/users/axon_logo.png b/vitess.io/images/users/axon_logo.png
    deleted file mode 100644
    index 04bb390f64a67ae6364b3113e054a4f5c8f9ada1..0000000000000000000000000000000000000000
    GIT binary patch
    literal 0
    HcmV?d00001
    
    literal 38973
    zcmeFZ^_y-GYF02}m~rLrI8m
    z51;3`&-dORzW>4H_2R{xGyAN)*V=2nSL}6&*49$N$DzSNK|#S+Q+=k3f&#)qK|%Ef
    zV*+;CDK0iM{UOypTcQ1QB0SO5S
    zK7K(yK|vm11dsO{H<*<_kDE8-zli*AI?rsqUwb)vz#QG(7$50cS-bndq?wr?C;FeC
    z|5_)^(eD47$<6z}*#a2kd;Eq^fR~@|e`o`bNGsm-yufg
    zm5KrnrvTHFD4ghmK)UE9hI0Bu^mcUg^eV~-dBhif(TkeUd{7|_q{^qOum?w1P(A6m
    z4?eNY+uGUr-7(&BmDX|fX8ydg{_5wUiSxVFwmI`dlU2@uwxi#1A;kQkA4Gez74x3b
    z0e|j{>Id(g(c|Re87E4Ww;DbucZ12`a%N_~EbqQ_1YF6yMy~ZBVxydNA(rTZAtC8u
    zcw~i2{GgI&D6#V6njb~u6(kmN5AElw%_NJ{_9c0MVJV5gu&vBw31LvWvL!e5@e>

    5uhaZGI<+fSn3p+)w51Vfm(!`6+66A<^DskqRFf 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 WwXj3%x9AA~0000w;4TtwT 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 YoqAMeY8?NWFpZ)pt0q$^^)clC0HGpYIRF3v diff --git a/vitess.io/images/users/flipkart_logo.png b/vitess.io/images/users/flipkart_logo.png deleted file mode 100644 index 7047b8a52eeead578a66df11f9638c3646bebde1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52688 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 diff --git a/vitess.io/images/users/hubspot_logo.png b/vitess.io/images/users/hubspot_logo.png deleted file mode 100644 index 7d9f9556f19b82e842b393f527f3b49eb2c6b80d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 42080 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 z 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 P@Yd1NJCl9-ddU9)Hy%xt diff --git a/vitess.io/images/users/jd.jpg b/vitess.io/images/users/jd.jpg deleted file mode 100644 index affd8ad4ec3b9da1702e352716d67ff8b214a7f8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11983 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 Uxc;9B|DVU~|K692^K#;U0RR}d+yDRo diff --git a/vitess.io/images/users/nozzle_logo.png b/vitess.io/images/users/nozzle_logo.png deleted file mode 100644 index e3a5a731403fb9b713b6fefac67391a5d649ac7a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6119 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 diff --git a/vitess.io/images/users/pixel_federation_logo.png b/vitess.io/images/users/pixel_federation_logo.png deleted file mode 100644 index ff60a98fff48c1b1913b91de8adaddea49584ee2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20959 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 Cnv%}| diff --git a/vitess.io/images/users/quiz_of_kings_logo.jpg b/vitess.io/images/users/quiz_of_kings_logo.jpg deleted file mode 100644 index aa4078c7ffbdfac78d0bd436a2d9a218ecfe6d27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113783 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 HuXX>~b*DO9VL!S>0KC)1 zN@EFJ@NDE&olZ*4+t!j6`o>U-~41Y<{^Q1h+Gs6+<|NNU%xNTR!e|C2tA-G&j{xTu*vy3 zbiRCA1t?-cpUP`{Pj02**XWFnMcCeMP2850553Pa{GL6N{jEo+t0RrNrd*wdc39|L zI(9g{lA_l=#HWzqNZ~7I)^C62SSei1yA0g}<_;Q$F0cK_{><8MiLBOlF$fz7MZg&% z;HcZ#7Vilne$MNvV@cuUhCDOJ6~_hLD#kYp?U@gnH;tp6HotmfrXMRdv|b(@7coTr7fFT{U%F~W`FjwS3xdI5eUow1TL@mt z=AbK|PF~-n;B+2UgnL#WgmkfR6)LGt-#{317SJ5I;X_q41UZm8y=L zri@ys=gn`^mqC}KuarCB_jLHuok%ofFkwa8}KOD?WGVM`UBfXK? zSt2VC!c^OB#Sr1zd64};e5J)E>H`@4MLP0k%~-gGHS2{ zD7}pGUo_#UB7=Er!g3aV80n=v0lyn#1f2O?O0Zmc1>Yy%o}HmkmToun#ozbx*SEa? zc`qQ1AC?G=(nEY0U5#)ni}C!;GWUHD%<))V z+%SfSJp@S5ZIMnL&ja7R#ngp36@RrApHp@3^7`vpa|Uiu=#lx|8n&eoB^upyKxkol zsGqM|7shrOyL<8Z0Ry_1!DS6rG})yOCu)b7-sa3*UQt!2kH+?UoqzkoX3O#M^(|98 ztBUuL&QgHT!+VxbD3|7Ok^r{8wq>*a^`$sY+lpmtNpbJAkR_#kOKOHpTHb>Ds(>8s z!|nqt{_EoUkymg_P-7ndi}agMAdcM1Rpsy4)6Z?&Af!*=kKzA!iKc!U<*W-;`69O( zqsVYV7OiQEj9vf)5z!Xb_J0?YOD}@PaOSHjVWkp-V7q0~YvOn?U>7uCntv`~PvTE_ zlqFBdJUww%!qO59_YjExrKH}6n4KiPM{X%mGv##%$pHjG8csxC^MBOvj8NGGjxB+a zy;Np7JwockTq-w8CjM(@{lyf@ya%x~xm`BXTGkPnT(D2sZF@C+fd`n`UjhJby}3Dr zLz$G)HyT}o=l*;5XZ3(p2$8)pDe_yHGE$Zq)erR+jJH-vl z0O!EV-wNzMB1Y1;&L!SLnq*QI{jK@G1$9H9R3R}N-^}2yvVQ}CrX~t7M)jMQe`(CP z2*QolVH71os>x&j^}K(7s68!Mx@9Mk2-%p)|36QyBt{a=r&_gj?BXas``erVV*;q( z(0Au+TY5oa6$O{+R{Pt={`m~4ZQxcOj%yacjC1@y41sh|G zr36!&=XADNVt1?jH`yof{p$^lJ~;dx}Vu1h)KWy$`{p3M*XV#5qujQ$S0PI0O9;3eA2?>qRSbHM|3cBO(#WK zX7`Ll!19LdU%~D#Ut`R#+z%OZm}mULi3j-VyjCgoCpl!{P}mhsrqD^d8+<g<4dE# z0rT2rM~Rin0cAU*7&FculS~!{iojtyMj~O?$+Hpa>Bl#_`5y;Uqn5}}7>dS~%3Jas zr!f5ae!pe1I+t;5ZNylY9BD*$SetW;4<$lU>THvdzY?DU4t<#*LUY4Lx5;{d-!CHQ2A<;Kp z?;jr>T^<%y@N=zji+|y6Vu%zg9r&~b<3tBic(MOWmZWRX}D4*A_J|5=%`K#2U zrVk!$hNg9-O$v35mm!A+P0!AXr@85Xz;iAy%qr3U@0t}?NMulYz08l~j6j-a(i^#J zqo(l)>Xi{o?~*_Yt4m1%fDg}#;? zp6!#Ym)j)`0FeOyjd=pF;s0`{e+Ab?QaFN=)Gdp5?<=MDflC53V7K~!6KZ}+f%j{z{CP(K!!QVKXM^D)UH3a`XaKNd+xpkJPJ|K)e%3s%j zyFFmodSw+MSzGV-6YA1z|!>ne?lOX(xSET1wy~7Y5!g1)V^>8!6Csa zA0;>=STR;Nc^W@4QW;hJF(9_zzdW5ZLtQ1ENk^xS49(3FpMALv@VkT36FA@{4)A8VoAwSB32QNZa#XP0A)U*oL0Sw&;R(CFkKW1 zj(*naoY+mpX3g3+!0Onyju%5%HM(;5{KZ|%o!_@6AVoC|M}Go@T-@&YSXk<;%M>F# z?r1_K2@GS5-*V9AtRi9?h7;Wxetx2QbYLLLfmRLORP~S1lV~OHti} zRt@pV_D30s<%J!>dx8TSop% zi7&&UJdj(dUty?Jf=a2$L?n5GYYErXg(z3Xg(R1z=ny}Ly*1s3V{2{XmDWdSETu^H zK^*ZfN>CJO(3WIv=;2jhIDHu40u2=ZR~W(Q1Nq{c;czyS_^VL_9y5xX z+uml5bFMicso~le-^WLZdVSB(WL>=G6E0p)(7IId$HOy+V0uG0Qu|hw|MVrWwXi6O zK(F%fvW{KqZor~7?-bWIfO;N8uF@bx%6Afn=J*8!wfdBrqsVg3?T@nCGxvvG)g=_( zBChj7s+Jx0Lm(6QJU52?Z~0Z$2hND!<{3b=saXDr%`G*a=#G2B{tE^OIcAWXoylSw zp=P6tOxEh_d9Y{?9nv_;xtxE?15M>uy2{|EW=ovy8}pS%G2`*wWbOaBdenC!WZ8Ts zK$jUQg)_bOg9n)x)3GG$R0xgf=Vsru=8*PD+sGUUSe>@1%zpF*<3`w;JW$x+Ue?y;%J8rhn28Vj!&KZ>1L=@ zu2{9H{!{Jv+1 z9qzCd9eX-|Cypn?*Y-WTy1cHVX9T~-)L*-Ic@3nj%CV|L(a?ip22$|aK|6%fKc!o^ zTPjGGbN}M>PDAN+^wrsKK}05RH_kBF`;YfZ?Gw1g=%r;h#aRfth1KO2GXY_%=x(Tt zSmC;7M%#fsko$MGpy^1E=FX1bb8xw&C6CpaX|sY;IELo$gx!gy_Ri-x)2!GeCr&< zzdTn9UhL(#JifrGdYx0p5O_xlYa1t7dwx2T;w0WQutp1|@5z=sOt$cTUYGVB#RkEi ziOKXf!MSJadE~5E-l3_a-}~c5iOch$wE)Mf0X~I_<&3>ZZlu~$aH_^vpXFV!P zG%JRsUIzi`EI&02#MCpSm5(I8=%J5a_&TN^)|&=k0*t9jkHwqqubhE<#x`dhc*NGN zr@Jql&Xg}$0*BJHtDJbaVZ|RftJlgGA2pisdj+A+S8tujVFIgt3{!!u=Ro?E5ie}v zu!8wP4E-M@h*3^dohh1tsg=luuH#g6va#t*NwRtDyB&Pk_NC7H)%GocThxOPc*v=o zN{(B{#YbH#4{WVNy_e-gkFrv}xI>NK5PT##gUIHPh#%NIB9_5Lwz}7K4`z|%rFdd* zC%=v_OK!STlqRAzrNXc8Gsfwy{z_o;R)2!HM+r>_0w@|9|1 zkk*u237`UwyY9BjqjS)P$idCkE7tsi;m#Dt)I_!izZdW4lNz6L6oCXwM8!fIc%Ts> zp7S)~J3!jdxz9K3X{WdTF#A*EjYERj*_`jSt;DAi-iM*EWEHhGt-(|kSf5*o1M)w1 z+B%@bETOdAU(Z(mTuScOD#dfjTRC!eTbz^95>sRNtW}m3ooGR^cKD-qjWI(TpN>M5 zWroBXDTX#1yeeibEJTO&-dF} zfU%)iA>%afZ*G`zz+CbsKXL!)&Z2#Q*^8rtjO>zeM(JbL6kXa~>^GJADAZzjWQ}c1 z6p)#xW!`^D5D~gOf2iYJq33{PWrHD9+Y1eOVZG4R4`kUGn~X_bSXHnE4H))X^yLbD zqs3X#_(Q(0^nHRPQ}4}Vh~w{^v09EK^WNYyS!WKK8=smg-u4PgKKZ3aPtY6GTHJVok`~L|a@`NcBi8j8%$(Bd zha+A(u(`g-x{M79Na^}?;bp9rxe$2iK~h9pW=`U5G|BvvpYKtkAsMZYc+@vG(CO2A=K`v$nGIQv3^|T9$Ecu6@0DSpD^~N|!O7bBADc7U z8U6)Bvx$>`d{dZ8J&CFHW`iPl3nED%TNmd6Xfawd8l8gR@RGi=BU|GUY92V?f9GCQ@`tMUB56++HE>F}Cc zW@@2*nWKI~p+0B!hxn$8*R``r1yX{v);?)cbCGQw3CC~|X(GOH+IQCX_gx&%zxq8- zAP*cMAvfZOsoHbC*TRDeu}mA{OA%Oatc!BtH2pGddREtb{1ITa#}qD2 zwBs8O5}7F*PK4};w0_Rl#hjn=LD)DSTo8X|W8yEJrNC5gP5B(Y@CM(WNP7F{MOoAH zpbv|Up34$Xt>aewzbmNWS#(A{Dm|S#d^1-t`HHr0^R%$AxF0I@?nuI9N{p!uije{= zV!J)Q&h%6;Y%9&CVk@tN+_lOOWr@cYN&Il53TH&q!$U99v|NgZ8{W_*1P z>0XN8Ol#{9IkqsAo(*tE71sT+4|fVnC|A)&p<2<6trC6VJ>=@r<82-25Kt|-lL%so zKLPZvm3+60Q>}_f{87$vStY$%-&dcQp3Jg6^p6JJgO7Z6T?ScPAlLA3#?W}wdmA(9 zNualf_`QKfNIWNiE(rSh`z0C&$J2Z+t0!hgohqz%kEpt z9d_S~6xB&i#m1HA;h#YDy+M$ky*6xR8t(q9^EY(Fb5^4t%vYI znJ)68RprI^2dZN)6EFi~$9<2yv~+a|kG6B-DSCvzk=g`d)7(l*&4ajJ1SFG7|oNOQ6Ckp-$X=Ufw>=VmW^#!gfamwPKCEZY~ogQ{TFHek|=T{xD zRT5Y)U`th@GK7gdi5|463myhpegZZ3wx+SlOmG{g3<*o}p4r9;{M69}wquj*z`+`J z+T~IQ@>bFsmf@qA7(F1nCYnPQ4n&S1k#d{3k%c^-V|&;_URQMdkXMyu=IlKvu)QYx=GB<1}x zMi+ZjAZ0d$=puKIKsxbU;>(jA3F6*e@<WoXK9QGvu$n|vtLl|F_KfYNdU8MtG-P?9q1_0*}?&sDdVoO=9JsT3Ia7?AIQ>X zJL%Z;(+5OVmkh#8CYBrcHps46a7GL`O1v;q92%k~f|Fl52P%j56Hdy*J$YLq7DK~D zax{UE7{^G5N8Q^|bLY_!lODs6VYUQW$kTq%*&=ZJkL8SFY^8fWMA|xbEK_cMZ*d0q z5Mdl!^tKXBGXxNW_cjf9Rr+lu5^}m4h(wtMrjtfFVIh&(wyg!9xTstxH_26BlE`nV zv(zfUsp5_W!UylKXXzL>B&PN8mxR=$4KLN9{SF?uSX~Y-5ZMoYtN5jg(;4D3qlFUR zW^FVvdK_E-+xOBW2TGtv5vl`s!}XrTZL{25o^%61GOSN>!n?%!IDuaNv^`egJ^bsJ zTS9tnD*0yr%F!sMz?f&P$ibo}Zq#(tT5>$$-LvCMo|mGYLm{ag zC(q*Amdzku%i@tQtVm>}-UP)^=nKGHINrm}d&LI{<43x(lF6 zNgkP&Z!c;&{(wHSbsNP5@JL@;=cf0!ZFUEs;0+}e#0hO3WqxyNiHFtm6CT?5W=hq{ z$cFhB6xzxCr4^RiRhlH{Od6Ur6}Tg@M z6e;yn4y1`oP2aH{hJ4>52exF5p7TgA71Pru#z|>eZNA=C8gN1DK@|y-=N)*<;c@`e z&T3S->FEH&yl(#kU@A>~c{dpZhC3~LB-4+#RHzofwoWS!uiyzOlWtc8?ML2rrE4{r zM`Ye2oWtkdlEFH^e|-KEGTfyMM`V+IPM-MwG&WqO(|+WR?LG;^no+z~>c#4$Sjzm% zU2^em`)_wvHh%n}0sm1{8Q~G@?Q|56f=4XSi)jc-0d>1b^eXFds{D$u9iU; zrFvRhb}-p-0Y^&Jn@Q2vr)rKtD%+D3&~T{CaYmx>a~}RX_m=6SKa?GSm3}0D2CXh# zAzoMn^@#rB?2+2WFWB8S8upwZ@NrmH-HU%H=qN$5s-+N&1wM&oM?L{v?C_J0MfIyvGbyt2YKa$1SKRzzfS@!uf!(Suf9hv>_mSsMiMIi zArk0RMieiaT}1LOo-6%iLPMvVb-P~_HGp9id^T==eN%3|O4Z2%N;_8e0=i@3JLPXi zbiZiK)1|*@Kj}eyH0Pra)D;Hly94!2{_|N7CTK2Yo)rCLNRe8YcMptKqHgxlpJ_EU zrPdvZZtFN|>(EYYfUgVl=*IG?IlqJ0V!e_uMDXfB_t*8g&wF0hZe9v%daS(ck+zy| zUh2;27Ai$QG^lv$iyq(RgMaeyvw1x_%4wbNnB+>Kgm!N7T41Ig2`Q(nAS~ckW@sj~ zvfag{4;VWLVWm}pQ{9Cxh%F6Y*m)&lGV@NfVvh#rIpGUjzXs5wPg-3~Np#&cmkGk7 z{B|(RXVGOkYdaV=e65vS3iH%T$uTwX}O}tvZya#4x{d@PTQul{_Jhav? zXViYBYL!uRydGqyC#)ArI-&hiN4~K5X(-UbW9@!8bS=Cmso_d$NK;+E*~>977iCst zbAWe$$OZNwA8{k6k;V-qXNHkKI(=+o{rA|w2TeGF-k;4)qwHlv{Q1ieniOf{yR*zZ zr@7?hHK4t`i&U|kbF~!diNuk`&$a;OymjKkHl~E+NXTBj@OnIv_yW|Uu`B3J@DtBK zp7<@*3Ka!x#Ow;2-aoxXTkMc{;n43^Jtpy-+d!HHWfxuhWckCJ`+5(=Epslyee%t`=aFZeWyW{emxzvx$0KG5 z{C#77F1wqmKm?+}%hu>FYqwaqK3}>8#0jq*K2!LQRfdonQ%TT|6TU z+V-RzOTPy{!-j$Wcd!i&I4QuaZX=4jfi8*>XKFlRjJbIgYF)w$)E?-}HeKe-jg4r) z!Ody|eug;yR$qA~@N;ePD`!Z2X~7e%Ll^<*H^rRJ7uju}erRrgj?#4dqu=w$F>@*P zp=9fG76mLQ6w@`pNE?uE~@!#YCKG;T0`3`6)xm{@_$a5lU)N?ST=ug()|liJ3&<(wsxnsujBj(3s$@ z`GD`V@mTBfN=j7V*A#>BRFeh9KB6_p#;atlVE*~r zvdU^QdLQw9-iU`o=g0iX4j*=izq9H&Xmxt@stnSDTgAx(O+1UaX5m_1jZGLnc&-#> z@FIKu5FV3oFAC0M%F}TC=cvk|=2Z+d_Eb3Mpy>E-gymOd&T5E3(xZuQ{r3#ei0pbL zgm(NrSR8BmN_W?Q@vcwq;q|>a0e+6UCSZ45&SqoeJ*4ErPPT`Rr*&nvF>ke~9TryC zdZ;nraC0zSIMh7b`d&hLm1(R(i+g%JXW%f17KJ}}ZG?zUa?6NDBHR@ezZ%@*TzLNr z;dr6E$2C<0O+0zy9T4Vm22T^4a%(cj+zW~5FRP&PefF+JA*erLL5 zOO$!CH*5pjZbhH>*QX)sj)=0lu(qYbIkp2I(v>6V1!RFE_FY)dmbsLy*bwWxnQ#5G zM6H$2;ci>U`HUSGknuHapmQY8Dr!RRk7+I6V*6YG=F@Z}@+#WjKA#39qwNM`Fb@Yo z#}l=#W~!II>O7K`=*sTua{i_VA0K-=;;QbmE?)6bO0e`pbn5I0x_U)cxaoW&^qHs2 z1Fv0}IP0g}SWf{UfX-v(TU*U82m>OJ2(uif=rICw$@( zY=1mQ)`{gxjNH6}{}wdC9p_a}C#d$;Ok5M#5)1v9$##;xx?hsQGnD2jQ}oWrsWi;T zB-|$Y&$g|^+!Z^ZN%L4Yp%c$BqcK$sC(q1V0Uw@>c;#t%vfMm6d=B%LSu^GksLRBI-7 zkRbO0IIn+l4EwLsrxy#YUoQFro;YaO)&*aW7%{j4N`)sZM}2*7*#?w+kBq!}>b&0e zRiP~0ELE{3?jY4-UbhRLHe*X*dF=qQ%(iwvsZN_b=Tui6 zGO@9nsZ|6!97>?}ZyoAIrsA>4P2R5Z)5>s7g$-rjUd|fdQX7RA) zfi@8mw)Av}{!9zhe}JFYXjcN+t6bLh393?9Kv@DR92IbR z5L(Hf7VG|8OvC!~^@9`5zN4^hSmYdN0Zpe zz{0r$x^#2ch+Fvr6jgAyR_g)uEM(_Ue00ROVuMrc=SjMk+JzY0fIebdsYBQ4==G%LBU7F)>Qo+t95Q@E&i(BMOv0QfQa zH=6i+*NOL{T*(_O!iaK+s3Qg@gzLo1ZSxBZyi2j#J@5FFUnX!is=iTkEuqkD)>0W> zlidMtCGi!ev}(+|2fVp1Wg_C@eKoKbO!;fvLjwgmZB!}<7`HM0!tpRA@v}MC2_Dc} z6C18AK3m*;mV=R?FF0a_MgKg*lP ztQU_ZsIFOpo`-i)Hp(>XXgH@oQ49H&*~D7!upRq|%3O4;Q@gtw>$0_ohZ$q{sB_0x zT0ATK70Z444IAR{9-XO$Vr88?GrCCrO4C}PR*8G>3H_eqPJW2Hn8Cv+d3_#Vj9 z1wd0_NdU~9%V+b_|NO_|wM^g`bzAmvnaJ=~iA~N(rW?7$L~g1Fgzs^Cp;E>#o$Q@8 zJ0WY|d#C=oIup{5l*l`1;zI@TOF@cMi_~%N+ro(UaE}NAGN*(x+NGpq@l-sKiIZFk zA*Ybhpg^~owcIgAj@*zOP6j-g5uWt9wu;tAc_{--Z70g~;n3ly)=nk7E|cegkvSPv zBn&v<6>So6+a8^%G3F06&Ygd_8?4QpnJ3+kwOKjSzajx!^uS%pUX47B3Fx{vyrGHc zP^>rMS>t-S4Cjn9*ok}?h=7E%UDwK9q~GJdNarj#%0TK`^{@)bT7SBiyJ;WGgmb$qyFYZ88dV2Hu}o$9CCd~?jX=bq$0p7-&r_!sLyY5r6(Hy<~aFXvn(EvO~X z?rctn)gL{Q@%geH`Ly(urjAl9V7!Eqe!&;agCNi2g;>ID{}4v}*_B?VQ+CXfnLn zH(YhSZmu{2Wrdy=CB>ZZP70L~`m6U>!>MCHvKcVtwLML(Rp``xUWKE~+JJ3HYLDVH|CG__8&9tc{Tj&m5SyO}_KWcxzz zL<&Y?#OT=Stq{vaF?QtKM7>SCcmRa&VT?Q-WO$*M>WAITn3KVQiBcSBq_rfcrQICo z1UvQCB$VetmGWmbdIOoRY&4Jzf|@S7-5n*0fV1OHk}?K!u9zo(jMqH#4U+x#ka0#X z;ys$DJXbHCb4MFl;=Yae>`vV6Ea-#Fr*v_OwFLBbJg(`s%WF=o-OKXPrzfDq2qQuL z8S-v?Go>V^!*r3M*mO#OYkpdT79mF3`^|0Na-DjT%CBe>!p}aba-1|ric(C&E!P#R z7rljC|0N?dq6TYR_^^l;SQB|@7_LLdHAixGnvE$;Vl}V2y2I9;OgYfbJI@WHx}GlI z__$WndAul^z_~unqYNBK7Une|WW2ZvPrhaaI*jt$o)5TjKMe4`5Nr@tMsBbTzNdeh z?$CE?ZV|@=>%A0C%Eqik2zgtu_&85W?|1eqm2u~4-v>p>p3AWiQ-i}uit>!5@b;`& zs_gn~J}6Bw-&wa_+Qf2Dq}wQvQS}Z0^msK(J8BjkYG4^E`uNGSYRB&vJU@jB;@FB8R()44E(*Br<`9)v0NIU) zRn%755(lP-sss!z$eW5DZY_yK2vvx%w^=T$u9rD9RxLM}dm0Uzl;`>aAWiiRD(S%* zkl}GhTh!%~rJ~ikaBdc9%CNc&Dlpbx?7(RPQeVNGt_3kgFq6FpLA$lsX@OV}(itz| zO1Ja%_k z$i36mQJ`~-aY{&?>KB8=;?Z8PS2tC2Rf_gJD}=}af3>Z#!0B*3?^X43^v;9RJhB8r znd`AoM~V9EV=q}K2IFVuWu$u3353b76MAWUW={N;6TX%}tXR_kf_pCP|r!b(|IRmZOb>yl$fh4%Uqwy(3_1t?T#s-y6V4Hv?( z$caUnGM`CabKN!Ox*xuKsa%pE$yVg;vdR3O!LjyMmmdmdB%Nqf$NeY=qadB&(8CuW z`8@S$@b!A!_<E5O&P#kB5e&A!24_NP2c*7wzX9RDiz&P2UB>agZ z-s2Q>V0^dOb3^Hi(T1wJ4F9EpDrWz0(kt(k7i=YH7x1B&EZUsoHyiu=Kdps!2K=lJ z9%+;XywZ@kt#zNF-3Xl|orx3KEX1KNPCL^2#>v-(^#_s>F~JX`^4IP0%r`Ur{#Xrn z;xoy`NFDaWYai{POV6Li^u);5d@(8$M=6-E;xSsk%2bPz%EF5bIih!7V3)AEY!XqO zx4AZa$?({)U(azY}5wVBV{_D@`|#6RRVA-pJY^!XZ?I=b;K$zu%2#hEQM9qWfwwh5S$QX1H#e)uv{n5YpwJZ(2RwK;R&$$TVfH zs$~d=J|w~87dPSDOSLLJS>d^2WOUsZvF5r841S62#QkibG8*)X7}?@~m0M@GEux4l zKYOQGUkk;Lu5#1HCpLS&z6fWx0Ko zm5z6qH7L!!T=eo2#5Eq$gBI>}NZ_Qe(5Wc4kBBMag%TQuh_H`EG1+NZX$H0W-{89M zjNH$ZX1POij*{m5)KRDrH(f={y7cvE;)v@P#__k;%!bc=n+%_&`;@#TO&gYzNi{I4 z8sNX%3}k1x^IyvGp^vRYi-AVA@SY&LsuzvgCT_G$C>kF1;gdjG&)pAb03tb`R$=_( zr#F%AuB+CVoEc=Mgr0j6IBZ!=GUcvnYp>gTyV-1|Zryew_qSKcc(0A0PLGa^@^HS~ z-iL3P#HE&G)pX$Kk-)hU`QbECFY&|@s#M*Bh-_(9r|?iIg!s%KIP<3`zVIB|rK?3mfy3rnOoOntd{o zeo)XSO1I}U&qP0kngzoRjBh99K73<*;9CfB^|PZ}F!5Z=u&tgbRml3N zxfPuGaiHB87lgx8pzk&kVeuq?1$8pO@ALChE5c8^X|CHZw5?;ktwSwwx+sBOG(+7g zrb=K()BvGr)g$0Eq0VHhdC-2$c^($1n}I_5?YEq8RI?&DbIBacGIZ)!WcQX4nAx-$ zhs8RS5O7`#K3NRnqvn)Z34R2$#jx{-*lVDGuH9`KaMT+lPiAR)j0e{avM6vTTHTj4 z)nnpo_2`rPuzr_$&P0dqs)7sXkYCup_|e8-=K~GXJ82$ubECafPo$-V#zmOyM-oT& z%h5UC5A{lbBJV@}nie3b8oBbs^2ag7doRbI9M3!P6(#i~=G)RE`z+AjD&&4!6*IV- zNxzy1`O0`n^Ja_$yGhi2o!vxiV0Mk>xBX9N>&MUNGkBJU;L=und^^s>)OjRGyaZ0s zJ}O}ay8_+w9G8K{f-(@5|3;Ncm955lox|sNl*EsXD&|lL%KWL=6bBm4N39Ouseclj z%JI0He9V`7N&3f-A2t~3bYoF9w?!%PRQP@KKfa(Kbjeb_nUBIdnS|wbd9r!*h}adv zO^H501Zl+uHVSB+k~q~uQ+%9(LZk`mgv_wi+J`A7xswW)xZZBJtQV2eqV6*Gp2=w> zQEL%U&1wg>E(x`}p=!NzP*v93j*C@}+qiYXLhLD3VVA3SfXXG8zI8367Hbwq448_M zH@uZJJdl;bTKeut(IoKAO#=^%9j#Vgki3Pke@NF)ydtu}h1mYi5$(!98-JOlfIgUz zhcCQ@FL=%6jM4RF@Fj8XtW)-E*J527y58A{5?|1TTd4MNLmW{+>2u{|iGYN@?kgXc zuGRF8IsY2=+fW$0iUk5h3AbP%RyE+iDcbtnSO;Ik%&X!raQghA5t*AI2o!rawy@l> zT9R?z9NvN7cQi|j_T6-sz1)7%!nA^gNcu2NLIxT6o#;5j?m$O`JTn?5xq zS$ADw@U~H8&=>A@{2P<}|j6 zqt8AV06`1yL)l?Y*hNy1t|iB~L>(~fHeEX z2p4K6vY=OgdEr%RXx-^jc}QEwk2X*+@98LR87S$&j`B={^_bap2?Oh-|9TR_tCzh; za(0#n$xKbCc!__IbNqHo6#|tu1YnN3j|WbTkn1u zwLDCc@fgUhVh$3?zL`zK@lX5nQ|o1FVA>VVM*@k%(sA5m=1dFClmnNXQmdZNC<%>NxFo9c4x@~_H(edS)%fACS787V7~PZ(ps54*xkyHWn-$FnkJwgy*8-r_e!F-SA!C#F7Vl#~~faPpHe{{CttwILQbf$_pF0vk4pN6V`yyazTn*y_I24qy?Cdq_F% zBuwS(Pa7Zt9?KTxK%0Qjwk7tUjRU}fom;#UK;aj$*JQ6MdO;-P4mTrL?)}WvN`N#{ zLQN%UhDs=Ysd?Uq^YBM=-xwyAao&Wnn=eYjy3q_$sujQ{w6-qpPL@AsYXF^=d zAV1E3zuHZG7xS>04%RtKs@`&>(>lInO<3eW1ttJ?XDJk|&j;(@wEto*pAYJx+!bLU znp~S7tH?rtqJTQ%)Qd7;=EdNn18z7sAPnBODf+ub-(n>-t_b*J{$gUYK^0l>#xoS+ z!~Ldh$?3~b&S<22K;FWx44{rrkRSF3qK%P3<@$-JdyRyl{kqe!zT#nRWlc4GQ z8qN*Y0Y<7562ePg6CQ;g$$VT4N_tH%e@~rengQr{l|!Kfuca`;9$1UI>LRXaj8n5hFwQ z%9d2^x1Tu#X5g+mP=gzF9gu|w7R63|Jwi?BrwuZXff652+|JCLA#@)nAD?(_U9=~a zUFjk$isQlftpxz&pl{g(e9~>Y&g#wE{7kHaxs@*&y{8kpMm27Hw`#3!nlrAvJ*#?w}D$hQVh`xA!JC^LwbHl4)9mAiNppGmNrva_?Bkn3k7;^J}<+xH68?<0DNpy@`WBhy*y5duWanW8jnxGzA7iL}@wO~zlWYrYN z3#iRLy(!5`&KCpiSXka~0Ia5MVZ2{(!f^ukJcK_N*4aZM>A;(YhNZl-y_rN^5yIHn zB*pg*ks%=5WTLgZenH^wUcaQaj;yv0aG>cAXFeXrmYxjWU0h^K&J#Pna(LIh#Ejn)xF z^9$m=op~I_@5Kd2g{M6ETN~L)2s{4rTuHUMkJi36sy6Gc;zLnVOKn<@U?e(B#ID5D zgv7{4+KK%HT+-~yPGx^sD>ULSMiR>{>MJgOKiFJF0aa!<;hj5$*#U{#rj1uV{`*{nY@5WQ=%bfk^{7rzv06A8utoz7ZKC8@TTbAQ%B%o@) zaQ0d^Gg8`VepGQRn@wv@112L5*)ges+YkCB0=Chf>{vQ`i7#dC$rO_m7M0bh3FKCD zJWz!Fa39s)Hy7@UK^JZbuWap9**%ZSPAy+;6RA!uvveMq6YdLXc36`&fR$ydJT~f! zt*xINV-c>O7lz!az+G-FF^<+k?FvUH(MwdOm2i09KEw*BeBU0Q5mdbMi{dR~Lj%EY z9l>OVl^~<-V~oIP(3p`g+no;+Bozej<)5WBdf3MqYBun~`j2NM>8loLmZSmC^O#?` zZoNl#w&uhkiPQSF-MOgLsq@Fck83fR#IEwGm897oF7mu66i_rfn4b z=dP0Sx9qm-EfKhd_w7_*fc1j>qZXjXagZf}*?OinKf%@Yn}yMNlii2;==LdZm>@8{ zo1sTM6E^nUZ0EeNMgNxWMvr0Slkub=U8@yVTF6ShT?}!;s+=+{chlz%ZdmD7W&PgI zieDG1xeyKxtL9b9C}JdX_GMr4z2vUOc}Wcmf-ySZOC4@XVZ-gSc@ger^I~mNDODZ; z7GQwMj2HidDbUL}oK15wfvW=+2>uy=Hf=wLA3Skd#E>m}0kh zep!c~V;?XHqMy?>XlP>Pc8wUiNgZS8K@;Da4`V^xjKaFxS1!@kMV~#Jv(g+o&A0F0L+~sDVyb7daaU zDTX7lI=G@vVzCnFc8foMlxCWe8*Y_5NFiZ;`XT9SU9Ds>({EeD1oM@z)AL1gd+qK( z4`OBPs|lO>IN{v;fIN9l3H*H712YmH5dC^5(G^IUHOyW1!lUm2zZa>5_*K$S#Bb&S-La9qDS2$dLrnx z)p_)wjG#N6DL$FUHuPI|1ps*i2+wY#8c^t5)>(7Z<@O!?e+g{4bC2~lYo zh8#kWl2j3f2I&S#>6AuVP>C73J0yl~DdD9DLJI>}izkr9?b?$DA9)W*K$DCDE^~_dBb)^a^ELWd{UBfQr|vHe=V?(HvM^k3l8ioi1%qe ztl$d?Zd%3~JLv4@kbE;7`|tJbM6xyV^Cn&Q-K98-pn0Y0xtp<9q5K0ZxbZOtKTrZ&U%P;6lo2^k}J)}psPaarW-vvdtLDLtgeD;vg zI+@_*KlYe_vKQsggDqPYAEhFykN8ed4KA8Gk@HzLf@-bU!2T#qIDEfUrkxX>Aj|~^ zAr|p!CUn>Pbc5#@fJ z9ec1^xkex4*~CE=uN!rqvuo1TL4UDpb)FF#HptJPBW>^%Xran>&8(6igW+`%|H-Z> zGU@gXjf>lpsGfp6cCle97&Z+$N-)LRnKe1RQW#ULHlrSPWKdVfq!DvW&gKUF5 znE2q7qPP(IZ`NEnRw+KR^blt~r?bNIef-lfe^Y${Sl+Gw1;X=??O=yjg8^PH@5bT- zg@;ak%;{_7R&l*$E;!y0C}=b(8Ue1n5yu|?Wg6>VZmC@#V{k9QkZpkh8!PL3M8SeI z-b=qH3$OOcC((%f#3a}w-w6=hqD!@y?Tf@eO!Q0gIt)bb_>)wDyB``7@q%z7w}s04 zlEqC`aRR=}=l;fs#NN;HN#2jvxCOF3P^%E*lQP5@++VZkjXH6!w40E3Ma@h%+1*(S zoHH|y(_SZ8pj=-RX6`Wm5#=dL#RM!k;bMQG`Uv)CJJ`mpM|3G6Gmhap z9P;6QB)KpqX+%3NqLPln?Wr72Qj3xOC5hwmC&5DW6`Uc;cbm--OYKw57M%9ocqG;R zf`UKa8tYhfgj$6&=5pc1GsAON1_ysiH?-XAQoq|wFz-n!4wz1Igiv*}Oa4+eNv$XSG(fN9CzUsY28xL5h!>U7phBF;&1ns92|RpV7L8^Exe zt3J#jDur}EaI|9Vo-w2lKpW7@12_SKh3v5SyMko6gyquY4?BIX*u1qswdD3MGIS}F zPngM|Xzq7?kHh~M1`pIP-iV{a{1y&B49d&S0iFw-y(vU$}T3^`cm8k)whJpV> z;I_{~Kwi~SlRY@|vovH9a7y4y5+}tO2(Xi2NO5ZWM7n0&x5NsNyfZo!qxj{@vrxzo*uehHenl$jgTx#`T zPfCc6&+SRQ3im&SXK$1eDFn)7pb`PqIPAc=%XY-Hn-Hp`IkL}Uk6 z&-6XeQPpk_l1Av_kNi9;$EQ+H68Ml9A7ZRi8im31yQ!7mMkpa!+vbgtqu!p5c8W&% zTek0R{YXPRWS-vfbcEl)y};70yp40#P+%(XXn5IdAHXL_;Eps@55)W}&D3S%$gMKj zIH`}Ss!JwW<@&6y9?x!r^XJq5CsWovbMCnv-@R%{XECNX;aRQ`ne4Di{vSw&49a0asZY@3 zwv%tfApf7=2#Du67!qsZzyC5$ho8-dQdEp^$G)~H z4Hn=iJkl6wLCZHGsxgp*`z5qI-kbbX51IvQ5zAbf zm>_Zp3@%L3kWgGCWvj7$D{#6p(un8_2r?5W0O?|N`R=Ie>f&-6K7M5u1L5=wGAxv3 zg_pcfj5jJZWtInj|KWxB=hE*L@@@5+2^cc3jf_Qt;D|XUo|ZF-eFD@+5@Vy`DM_jS zlKKy2|2GxNs1DTp+$~c>7oq!)CO7He#+U=b`%jq(4*e)OfUhqKT2Ohp^c_sa1_}3w z>Xlh^(V8mQ+E5afiDHCt+3TNbll4p=u5yHs%h^~6NLd1u_6u%m>OVIJV?J-m)(7_S z1RN#pQVhNzq6E|8qyT~3#L+QBRAh>XmPdF}{M2lmbz1CIYAFY+ss2+UhJs@Q& z5Xag_6DSydq3XYkE`Z~MllFy4!Xffi0RjTJ3Qlri8wU-11mL_$9sciwYYYUVC}YPJahyo|d9=*MGR6B$x- zSyCrsS!^XD;L@cOn1>t}p~1YRZi31j{o9s%+Lk#=!zbABkX)9#nS7-q+J}QU0G8yy zm-a=PQ-;)O+5X88c@d6z0JDOzi))x=&Ba6EV#Km~Bu7~tWP(l(v4QuJR%b4jVcH{l z4s53O{O2>KHhdHbYIIFu%PrCV=ahUt2ru zZLs{-5cB;cUkdX({@9YD9}NwT_E_o@Cuj1_U%&-q_}XzS1#@f zkxPF~kVH~f8p~>fkZLaA!w)&!^1x52Elu>D6XI#`6;WIz({pJoY3kyKtChm9;xj-R zg&Sn@b^yPe>4WD?Q0SuUqkdM>iBM#vcB&x3_M-h{q_NBnEt(~`_%ngU>oEPk!zu=t zN2qB(+^>O&KB~> zNuhQ~o?ynS02yqj)4KH&->g9rQC$|fuSZjao0~j?4HTvG-;u-V7*DaDd_lDi8or*) z*~X-7sqrZ9f4a}boT~<*zo{q`@4{}X){TEEieBSZ*^>^{f9(Qn7Pc4T^zbrg*%Y}88J|{Da3Ee7Gkh9w&HEdE(NnUGvkw4tt$6H|7 zP7bnKfpF!RV24Igczh5X>&C~vck50|(exiiOj}@W07}B>X7M{kMVdG~YmA9ef_g~W z@&T(~vd}k3k*_*A)U3L*g60u)OPnzxH5N(hMQaOpG_my&6ySd2vq1rC@RaPX{x8VX z+u7klP=ohtEmV2wqgtweIk!3E6!JnDWX#_xMgr;LWU1Yr(jxO$$-Ez_t}bSfW=hQC zXG_(j_{h5^rkXDW96~)YlQ20}|0)iTnTTr`xEgYw{J6}!U;`oM=#8UlJO+KU8 zyRi+3O=!o&bFWJcQO*(EOr&6S6NwlqA_(Okb3p&ULZpIouQ2SvBvF4H=D{|t*gbr-=Z@ukbsE$EG=2)4V zg$>@hR|A$Dd&szP7v~x0CbQOaTys>wiP(^2CIxX9>dkX z>@iokKTXEdmiI=8^{Xfx_G34;0r-y9{7++NJk9NpfJ5XBlO3ly>3GOw56pZW z{X6dY&rbpJO}7KJfHv2#OAcMFOg0y$lT-iFAfjzbg4gu$C%b#zm+N6v>9$vTt#!#` z*p|$@&cP=ag61YeplW4B$_xJNPL)fw=nchUxTn&ne?vyshr;p*mIbd(Md_|FcQd&_ zaKyduZGe9NmTp1b#{`MNzg0IS!T5h(YX4Q@Lc=<4=KLq6^_Tr`-aJ-770C`y42L_?UGULi3HX25&!-NC~klOE_K)0M?qV%-1-7{cJMAw+M8C(b7g}F_W zwZtullyziJEtBBvzTOIsVh1{Op17EPYeAv&jWi4ev0C-GqA1D))N%f@>!k<5y0_=i zNv!eJuZV(HdF{|x9Y$FeC7NSQWQ*g?QSyk`4A#Bh9fhjf7U9Zdr{veWA9vlMtX3z_ z-Fze2Y&cr!5RiL5v{K)T7T7)wtLl{3YZ*28T^alYU7Va!-KW7hCcpnm{_hAGpl~?| zOp2661m>+Q491*@qWZWmsAn+{M>>7T!}h+#u0qNRxOVkj96nhOlI@7e4H8fA1T2W_ zuseTKC-;G^$kn~$Dz)JZAO6Bo+$rP9JrRY%w=Nay1rLi`>1>V!F>lpF-xwY4ot5PE zvZjr1lxmBTvB)*H3(79`p#Nfq#=CYX7#`4Xec`rm&NJ%KGC;6(? ztrYLNgy1ti@;M=mqgKN|&U7q(5Wt{Wims-=wdk(@ukXcXA1mn@SWHg)4M0K{b{his z@`Bc{y)uZ;oVRNk69nCU+>guc!~?CZbana2IO(nM-}MfbCbQhFi;ZZ$nux8~N(cQFN;GwVeWcXEx#Hg z{xZpDwo=gKzf3^iJ+_E}zuuQ>`(Q)V9A`k(&&=FR6cO#s`M&EkR?_5cD1t)A=I~wZ zcj>9rssajDxdA_Z@lQSh+!~rDiML^V_kAR zT7kkHW6~7Wi=*8Yb3%cY6Oa18^=kaO?O6-uc(;X+AEDD`@p6S1^%g<|d=jfx_d=Ih zMtCCDiKY+R@|^HL-IZLroBfZ#`uVJ_eCO6;N~t`)s9Qr-edRmu z6%a^_rX5|)eI{Lv9MQbq-?y~h^HJpEr9Npz07PHOQyC0m~Hw3@*AJojNM=|_%i&!(_s5!jVPVNBYtCN_(J z2X#URYyK6#rTdj}qTi9++hP#ywXpN_fUSr!M5|+=@BKbVo)nNjx4r5ZJdWj`a2MB) z$_Ik459;n&F|*^$gW1_x6XkeKZ7l>(nbnM9;^+{o7NvfLmebgnjG_KMfY^4ox`95* z7+qX3;8Vcym6Q}!5-@!xlL|&!Qxdd0OZt_Cnp`^gl$Qoqx2sGPb5E-^;@J)Vr&DV8 z|5wMpjxGAYSF=fg$9SE)I5?dPZ+nY#w|qp3WBt+SCw=WomH75%AE%y4nmF&zH$Ri! zi?%S!S%VW~N9M@=I8{FDNG@EnoJcFfsT^?>_BrG}K#C(g6#D@u+rEKUS#XII0>Flx z7I{aoasL1zy5qF|)BloVienimW*lXDcl&Gve+L?scwn?OiW5vL2GmUby2pW9tSVm;De>H%J_U4jIjf4}`t~`VZ4Pe+SJ{_;3tA!_Tc7p- z_?THQsrKe1DS@54)#9<4KZD$%KP`*`O5xnH^TQVWviEw1GhK)}q7PlCb&rnk;D;;I zRBUlZQMX?EC!;0MNk6)D2XbG=q@3w!>Z0ocB`o1bl|_cDoOwNjpp+MkSe;r#u}kl( zQiT;md=yNbMebJ6(cO=rxncYhBL&WTmH1k{Sm9y}J*4CO<9o$QKTV3|&jmdm19F7Hb*1|JY(GWr6eWI|GM`Uu;g4T1kb`fW8=2F6c?vsBbmn zIPfJ-g4M@~n|@m9;wSd*kp4`>$)fG=^hurtBO5q4jr*(yGf3J9QFmMxIgE4N%yNy4 za@TVKXsiK$PjANb*w8OZfq!gk=mUeSt<2`D?HWFAD@1>6BW?3$fhpDcHoE07*0ot3 z?*-*3kBuNlB*d~Mg$~_$ya#>clhfsJ3?$C{<3QMfN-IzaRro;nRrD$k^wPOPk!1C? zmV`|>OfcpkYVt1m5Djp|zEV+@jHVR5YHI4Jr=Z9ugWfgb!1RQO7oFz!HEc@(v*JHm zA^VHOX5X7sK@nX?-pjGl_vYOPOP_1GSn#WXv^e00*W!@(Js$$cD*v*SF5*VHJz|vR zFww9$msp%yG(c?wyqCLeF5jg%+TZ|NCJ^LWjc?->~!wORcm(Q>IyO+}lGh~%W9my#6yQblZQ8&;TX7zgVaO9a|BOVpIoRFUw zn9rT!E>6jgPZ;(Z7Y{D8A(N&q_I>dsa9E$ZNy6djPE)EZRx#8q!Uj4zN~UnRzqG1b=fI z0<8Ph#hUPcn;DfuKPyuz_6p|Zy~qKsY^v&wm%|V?xBj3Qs2Tk=FFNITfggXB~{tynCj2I=jjD^g!2z?E5Ca#Uo~;B@OT$+%b?J ztpfWDlZ8?bLcIU|0+(CGM5~2PfgOL&g2%@!2Vo%pfnKi8N~&yJLylJV)$T(v^-n0X?)#PZA}O^pCA+Y-6eo3B3Fa1 zYS)L1F@6UH><0?!5laPU_mDOS9l_NnB7@1a@vOk9@T0r4PZT0mZCm%3=4i}Ly~euf z%z2SnP4H7>s9C3#U=0UvdK_Qr^9*JZ#!4f_s($cN?^&(kAs;S?*ta@b9%6Jws~Tk{ zjYkW4@v!CN=wlVO(z3#rk{i+HW9kTJ9A`T;$sMl|#YCRJSA zYTzmn8}m0|rd}_$2<>xOeW1gXSrPJE&rA(y*jXFxnHZJ7z5CuM#o6P>!jZ_&%Nd`R zG(Xf8&LQyR$}!mpPb>%?KZTKaVFHg23`I#ghcV`@#!r;a@(%_&gmZDf3t#{~H7CR6 zoN32vGsIK43NG)E48jG#WLo7BkVPsaY-&rJQ*L~fgJY(G&&esK+j3txg2YU>mc9_5 zPbJ<>CZ5;1mP-pS%)`BPg9-bxc3U-G3EZM3Y#8m2R(q^V4A7s|)q%6%V1JR2RdzV= z!{o)^!JHP2Sk;7h+VnZ}1b2hivWXyFVg@)-4`n6PeeVw-9%e%AFByh)w)(}-UexpS zVw4Mge%zY_&$b@WAL(y{U@vE~8|l`v@Ekp8$^+LcE_easP#)Dac$nZ?U(fo|=Ed`M zD(h$SsH8u@jzXex%F}y^t`rFAX<0D*^4z z>SP7b#|)E|vSYa$n@ohw`@Bj>wf=~0RgHn#l0zKvfh;g6?B4M$7dmX2kdFMBe_f`Y*Ke8 z1C$AP^mal!7FNxBzw%t%ei8y5Wa(2!?CUk~6FRUd_G$@fv-*g>XY~?P|I{dUJ&F`b zO+4)_-g#~GQ3#{RakZPT)v|Xg@mK0fTXtkoznYAziREH7D>7w4bO44ogTYs4%f5^C zDkf}!NHo3VQsg_jfl|EN&$etVf$nF}aNu;VNL?I$Mt$_=pzh+A;+}SS-E`Jbwp$x^ z5WLh~XDwLZ;A)TW<|w6Vxk;a}=P1=RoVWX-+4Kkbm+x7<`QCpTpynWM+OOo@8`azV zJFlL~aW=ez^4V}zkpgOE9U7KVr6=aTnx``k*Vc%@?%h6O&rBGoD`ci)|D6xI z5nB)qE5!zyelY4enQv}GEt~x=qh!ar8=?1O(W1FXJ1b9ZQnb}{vj)wjuC}?2PJCJn zy+%jW<=<~w&YBCB6m~?bL7O}yXY4A?|7<2TJ1n2wJ+eo}rK$Oxy?a?)Ur@kf)r3|U zJ=n_ATJCWy-+6~k74K|2>x{Iwd3z1^we9jm{(F9c!drmJO zauQQb>>B&uE81x6&#$81|2fG~Frh9W$I9H2u`!j|#cB5hFnXf$SGSc^ps6bN>PJ8j zoP9FiMj)DTQA=EMv+qZCbm3h=(oR8oDAAHkH{n?yI~9i=Qu^eqvTeNKnMBmq$nH8C2NvDGHlGeRHzY5px{SfMDL zi!46^TXIu2CBI(f_2wN`sMxE_t*(lTq@GRoon;E*>Xq%T={I0EGOFVZjVzveE^x8F z5FyS|y%=coIEGxVE_}{sgu)Y(ecYhb>8h8MxG9bC_#Fv9yTHKK8&1ZcZkJ!X%a?Vp zy)|<$80$*=&vNGf8v>-2hYFgd-0>7WgL3n~+c*+`N0UidYcnSOoIF*j8v7x1)~c#= z<3m1pC6Gd{ET+3h8U$AwXIdQ;_?uIaO!B)jT;rsT7)^l!bWujaDW@-|0Pn-CQuWS0 zP&G|N_4)U8Hk+i+(Kx%dP#0O=$oilyc*=S^$TP_0z>~fPA8L8&C`f_-tul&Guvf>x zw46KS-?ZbvW+Q^0uEDN_4X{Ui9M&JD8~n#<(Hrjm<;QS{CNzdg|3dBctMz}G9l;ka z4$p(&;`%jOUvF3UC%hh1R=Q;6qu7E@w+3A$IwFukp&2MiN;Y2~w86qzMboVcxY*kd z$|?`Pk4|`Vgzk+!SK_Bq69gC11{8rMRul~O`KU@HSq*AL1`QTkh~uKYqx3D8U&)~e zsUG)niX5e$($E&0m87Y^@+mN=Y#LSY2bsH`yGe`a$y`7#Zv*!Ec;;d-Jq6TfZ%xE72z1@}BYLf$)2f!)1&yA0RwwOc zH8{KW&TWwyY&an(e?w>fj1&1Ur^_EP)hm+H$)>zUcX!l$XRxNq(DLvn`O`M+5u;-gKZ-mYpa z#!Jmu{I?M-pfq?Eq@D1ne2)_UXSxI;7^#P%7qfR{+|mIeO5L&8fy<$1&o z=gE~AOrCawy||Yz4*K{cTiqn(ODM@*b+Xip=RL$z(;klD-6efCCf)<(G#0%DFB*7i z2wh%vKj9*7#Qo_{$t*)v(P~E)9I}F?*Ph^b!Bja~ldi+2csT>k( zYTR3peDnF6d$O$-SINa*nGra(cgusyX|ATi1ru`KpaSoDs5~sCJ^Pl(hOrnm7HL~| zi!5AcA@J~zIQA5Ix;GN9lqv&uieoFLLZTfpyKZmm@mNBPs#K#A`9xmKhJbO$EJXHn zoAR)UwXfx2A96U~hRHqMSl051mciybUE!%**DsRrH^z=tv425aaf3OjLZhahkqMaO zHM-pd$(F0BoR<2D9$};oe?q*La10}n5@D9dJIo`}#N3+@>r~o*P^%*w`u9+DF7w-{ zJV!KRW>Vk``iYOHZhZD1gMWWZ&v||SL$kH%KPW`-Abtknr#HjqhQNR|A!WQev-ir* zZ%!z{m715d65TyTpm7$JSsbX2t3asydI3*FgoQ9Dv;o{cT}*;s`&vew>t=|dJCxBv zjSz%=#M`GZj~$WY^Qea9 zg#tmK?~oPQbw2Sd5QqZ6;0#^I_~}AUR#NrMU ze5s#y(Biq{Nt1w_7sWtrR4|*wkjGt6$<1g9iabBHxgmP}9h*R0h#C1V;o`hFLSS zm5Xjl7!50fno4tgt$yZm5tZbq8Y7ZGOW5xDBrk8a5p5dyWxm;cW&5{|V`8RfAz1ff ziENTEwov?8dh@wt&=!SQa~-FAOOg=VV)8eNC#!>^(ksM(Sn?!wm10AWqaM4@I)e$r zoiK3ys<5VKOf$lIVJ+zB=+BwR8=SyS_hpf@yHwu6%)u&>@*kohZw^wE%=O?y`W^i$ zrTS|nfgdW9&R!Vc&SBsqhh}FAPNaT{!RpNWPhKjqJ*wL$4!9SWUL)D1pG3s=q=h47 zzP*Rvu%Nmac08pku!&`VJId!cL}9CNzNiFxMHWYVOkvD6{=DH(sd|ESkAs~Td2oN5 ziG0b@f#dq~W$B`F+C~f-^p48EP)5ekLLd3{&2oAl2am*WQ?oYM^H!WL8aJkpW}-;> z;=2SD3T=4m`kn?$0kU3qE}rQm(#*^9K6UwSxp_Ynk&w)W@E0g?m_j8C2)>9-G{u)mZRM zZ;s*?ieAcj=-%1Il~B&v06n#U<@9sWp;JbN$t%{?yWPx}?Uk*+^6zeXg*Z(!Zhx(w&u3j) zzuwtj>qlKCKb-!I6$J0v+iMiUXpeOnh?s7BZwZVF#!ra{?$%6_2LEfnGp|y7FLQFH zAEW)jAeL{Zq4&3%HvI4Kk8J&@%Y!k>s;o^R6~y_-%W}V>p38hDoaRJQlkt`M-b+C! zSS?W^2^=gP1O8$ywp>`kxa9%Ibgvjei&gegM~I4B!Bb;!{l#e@hfu$=3p0p_+78eKM&1+$IzP@uE=$kn6%D+LA z4i`ywd3`&Ud3C^G!<5a7SH@dMdwm%JK^qf$&QfJg6s7$ETl!n-ua!Tn#o0!o!76#u zA_b&7UJ{7NOXZX0l=EsTyVTeUZYfhx!8+dM!8%nDRA@Rb&~64g9O-{nH5rhyH}TO! zO}?DBByRL*YcYX$zv3)Vgks3II;pUx?|nWFb7syoi+|bVu}(InLmbX5 zSSY?Z#%GP4lA$BucKj+YNAifMtLkGDTQHUt*K1IA?K+GkUPRxnoAhd%=kFa$${-(Q zuOA+ChZV&~7F<(&jQe}lEnUFxoj&?(N+Z!_hdx5xLn)EmYWb@m#4rBip-j`2srf1q z5YO*>s$+HECcWG3OPHq;>x{PN>ey()QdnS~=PuWaDwcL)6-0lP~eEBYe zPeCU1`ow&6oQtvqDKAvm;*~3Ta#O$h!R7dd+s3Z$IBvtygMD8-Wx_t}ESDz;j&AAr z&BrY7V#+NwMF>}9Aqi9*rGMx7H`s;OJ6*-P^dmcHnW9T zg~O~)w7FA4k@I`aJa<|W^AZ2mTTtiPI2e4nX{7ke08kfebtjlSKBCJQDZU^Pct}_` z&r|e8##*Q3kBfF|JYpDvi+G2lvx#3r^a8(xPIn*afL$``+INI!29@0u7+CAo6^qp$`lBe z@47chmMF(HIHa3#J+#55iBqSFKj}f3knjShMSDM`N3){VM`{hr8|9UE#Bo~ST-S0n z_}pkIX`%v=My%s>oWB>1_GE|*x>zj3w|7JHtz^Vb6|?LWlQ;q**oC)?gYpmZkm;&B ze@2loBOCJOM-dsL=%(ZZ(&r+{9Xufd;?Qg1u6B&@lCN&?@&aq_sayN#ZTFX(nGpAe z^n2$(6r-a6^zN}e?ZOYcW{|l~ddji=bsdlBGo}L+E2z7p!^{pJ-8hTupkbi@(d4N| zAd?uA-O;b=9q?R2g)8q)T!i1hSlui$=y;%^>V$`UvhgUL>UY+1WE8~dsC)6OCD~1R z=^uMM&__cz5jcYB5zNhgxviI=I$t)}drL0j51c?^0Ys{DLPd~L6uL6 zpFrggE?1X7!LEe0Oo#RPR`NHmtCJfamqQIIt=aY8xC$%D`M3+dA^IK``IZO2C+h6b zpa^nN185F1ktxHVnPNQiJ6xC6&c9DW7#q>Hd^aD$TOTFdxfMRiEO%XUGSgxxLpoTY zX8sK8T^EQNtln~DGQ~|frtFRx{j=_`3uNZ*%*w?|5NG2ew8ji+Nq|s`B<1`PCi^o4 zvbs*%1F~Q^%kQ1PMCBq@JX$GCJw^zKiu&5O=vP6RCLaq(%Cp?@E>>2g1-Z)7sXVe4 zBn2H!K@b9M|3OeFV0N0igo#i%nNa3a_DQ0HsQcWvmxh8U5#vHIuH*gPf^XS{!lQL( z%9igi_?6-{YhtajT{WGHInJsg-SrdC32plGcli2S-<1+lHLEaouS`bO1w8Eg?AxeX zsun+rxkK;@5u-&5Ab{N+)yas(G%3W4G=f=+l$wQ7h5||5FVl6~8s)fug6_CpjPB^> ziU6r~<5mcR9J4$K-wKlATbm4Wh!8h_xJ;zHO`6j zzoho?2DE4pX8k*}THz)W@_Auq3u9OwnX$_ zC%Hta@wllv?QTxsT=jfegZy!jw-Wf#qA&{br@UG^+nQbHT{S-k%hi=s@4bT|BY_oe zjQ-yl9cNHz3~}v@OA8Z)!?L*&%VcvdplDqBM5D905t1YYh3fB_;aV%~iwg7(_9K(W z%*FBXNw>zM`TY}wgvWxd#*(Q7=_bV>f%1G~z!P($UrQMN67WT(Ra73O^KL*I zUW!4ioMLbjAzCp!z+T6~z7<9u)$hV!y7snXIgTQ%E2D-0;_{^XoQHrkq(Up_q1 zt8tPLWy=l?BXN4T&j7T3F5qbi~i7v}Z>@7JXi?{<9 z7L{w8*>q*T^}wut@Uj(+Z{~M^J^uv;as{l(h5ZSIayD5uaNv%QMoPtCsVP4`F$|a%_A?3CdCpo;<=glDh;ja5gz9 zp!b~XzgpD@GttN;N~OB>D1)t$eWLZ|Y1Xo9d~CG?4;}v+}#f zEekkezcTrf>h{wLMls&xe?iISJsF)>Pe9jw;4u_08?IFvJ7G0x3isHLBIxN^tMg{a zooFg>D?|g&aTU3=7kKqi=9?1-g|h8#@Ot3SKa(x_cqHV}ARjwhz%+loGumGng|k&r z36AmI2s^#9I#`}!EA$WvAbr4)t2DmC>Rr|YsVR678vW{VRC$x;<0}}71%4xD% zfm)Ype3H*#IE8Ukz_T%D;<5$J=+|B954IHB6COGSS=m1W{^s58U_&OteMxr=rTLL<*et2e=Db zC14BVPO}jl7ai?GO-C7$2pIlJ=QzB>=*mn z9l(>1nkBv?FDI1?X$Oy{ong&e+->d{H`^Ip4r4dE_+F;pcpYR-;ZOFl1=fNIPki>( zs->3hpQ$*vI$0Nb$#{lw(8=QYF1Ed(bf)esJY3c_rugJ!j_F&n$Z@@TRA2Rb#JLlh zs<}@1*l;_$cw&H}YO;OSs!v~3%3JYjd)iPbBgC>~ZXN9&j*c5O&JD%>kMw{vcF<|L zgR+q`6N?T_$u_G0Rr^z`kYg8YDC`OP{-4EkKD^q%HZl$;q#;shF#Tx5D#vGH$;r85 z2OT4rDDw#K9>GfN8PuAdnu~S9x5gr9eV}9`Rlc|Z{8Ol&MZpVxZD7$q6p)rRGQRoU z&u*`6HF)5vo?KgP?v+O5=F+b02JlynL)Im~x!m<|%s-k3Z;#8IYuy(Z?$PoQ$FmBd zdtqw>J|a7Xx?Ct(@brre(wyC*%E>k;vvr&)%m@7 zc9~DnRx8I-;fMv)rE}(E*}j^{302oM!FB@i+5h2kQr%nrrXR^ezfkKI)&CrHEtWwo zD`;ga$LrScYDu|2Q@VXHB4Ol|205GqU$dp9O52B%=e8qMeRAY9ggp!3C5ZdCT@H3G z^^=_rrZ>%*dP&|2miGJ)4|3#wDwQ1o7N*(x*61v8S9l+_btJ@G713DGsh+g8=NdW7 zB;$2ZmH#CV^r^tRo3K2x8Asu>$Obrn{i<|J42OW(NN+sL?%tQp`gG^%s&__?HhW1^ zjT4yP1V-rTw$T***y9jkfV}VZL~=7ZVb6_L0RIEp1o69&P4F7m(zIu7{#>(d^j*l0 zN6zJ3+>~RXwtu~ns*_;}Gra_{H7oJpQ0-Xx1#=4^A!KYo(aGy!w-IVBb_H>pWej{=zE>RQDXe45mn{9|K%5gfJbuOmG z@|NqZ|6m$w*BI7pytl?W4jH_T|v1bIfd zN{JddwB`#Iur%-a&1jh}ZG`A)D?OUc>+IP1*T%igJ|@{kxJa`r0|ZnVE&NV#Q1FQ!J0F>OsL1+vwi0W*kn|edym_fRSgP-P(nYKy30BY0)%;Ni zRk3S=FXF*D@p-=C{q>-|y_H_Fdh1hqorl@3%WHY%5UhOkTh|7_x1mTXuZ-&?m}Pne zFb}~@2haJJs)X|U|5J^+#;Ufm(jbT=pUozhL#s1Wqf^D00j8BT3A;#;mpRa>%pJio z)Z@|*X}|4vXOggD<6?UJeOO-ad7gSqt!BIzarx^Lk(1Z10&MH}eCxr%XPwQ8E!=0_ z-==e8H$RCfim_CUW1)^jh>+i#DQt)7S5Q`C|DJ`lf3beve^pD7U@MRD;K7ps_&W(z zIV|#)eubw{1tUPU*Q8G|U*c`G{rQ+;{Ul}%{`-iNQO*|A&O+_W7EWm5$jASdEm;U* zqOi^(T-4r-b%cPC#nxk+nuLeiR)zh9e*eqU952X%d;``#eQhWJM=aCFtMoqUf4_@n zGsS(l{B#8_PO}_R`7=G-c3q{`^f91KO2XD$f1{rfQK)X8?+P*u%qdAMoEXKgdai2h z=c+Ge|9X;<|804Y`d0f#v`;8y*`2U&*v6w_*aBup_bd3tKh}phn{buzX@SkOoFbnl z1z$09i&q>JVRyd_DE$M7&c7@Ce43oQ6-}9`pzN= zQCAXEF$Hf0R->-*W33wGz3r2#r?dB~+_Bie+c6Bn_Syrq=})BxP~NLADeK6z|BKg) zc%EGHmW;UJT(izzq^o8N+7vbO4(`A8LR+UM`8G94{>^*-#!eqK{b$DzYNwR#Q^SsK z!D4ndg3+O$HCA&A8}qM+7CR>sCuZU)%iaOcFYB&+!+IVo>BVeaxi#;^sPWL-8Ilj@ zy9_u3&h>v8kF2nna@zVoZoNB7_U4ld=#MQ*sN6V=+=C897Wh+K^Lr*T3jDK2f zX3O~tpRcUGEt|+KSNy{iO`;&QjCHI@89uDa25)ox`;)66t8)*$dZu8hqrmF3!vl8{ zNDR^t9a5ihZ9262yU6+FuH)LV8vh~I3iZs}q)Mv=Gj9=v+s24ZPPy*cbDu4gaaGll zNeGUaQ1S-}-nVQh^q299Vs}4@Xg*Qry;v}_Z7(?&e4a4*&R0ZV()}=Pt4lhB^8~YG z`f{tDQdEOM^6GWtPum6`&I7Z?unZ6L?Quio=fDGr-zqQC1oMJWWO$McyKy&?~X<9%e=K;vP_=H-$1$Jq$SuLBPDOHn01Y9GrEi$rP9$kL2HQ!*%cbhMN{`Bq5GI62iVZcKgx zVG#5ta3I-n^Yf_qe5vJXd73HY9P(8xH~tf%c;VxIV6{`u=aaR}V$zxbLcVSi+BDGO z*M84eTHn)-n=#=e#@v9R11~4`!qvwlbhfve1Oc332$tIz1|TVls}FD+p;xZM3n@3A z)ElJ~6jSQQcR$K&ev>c-xf`h?P$&9&^jf7f%GNdIc#39%l+IBbn*UvZg-A$isD!kz z`C;M(B*n#5c8C>qtkIc#x#u)o^{HpVV4u*-tYo7}x+G~Qcfs_p^iH`KZg~MD0R?;U z{yDkJ(W_;q*3Hd7CE^dD^|I;%v( zS%yde4osSH1h^}-M^GG9gfQXe7u^Y`YrC(&Wuk<2z3TTbNar5O)LPuan2z#foh}t!Xd8c>u1M za#GfYRgC8#^nH(^xc+DM8*cZna}~?eG6FsHT8fes~m-ws?0EimqC^W^Ow&i-BlbiR2IlAMt4?}fXPovSnRG4O!i#7Ar1QmRZM>zanzQ;@08HR?37>7kezY&)# zBiw;{b`u~fzVgCB$krT|_VFbWuoQm(<_+R_zdQ8vyY!7(W{mB%*(bYGp}%e^9|pEE zU#k0J9Ww2*()Qf?Di+bM-Q0>?xjg;%P$VNGw3;#j$IWbuc4^`?VGiAK%iMCgLqsC? zD}HT}?Nj@w=+7c0_88N|-5<)K&u^k!%u)8l9gK@jb&*{nAKy*k)JyLcQHIZY=m{*v zNi_E#?@aeNXyBH7pv|dzxd27sk8}C%Zn&(*Mlq8gYmI2&sQKidbxXupXn2h4_8+aP z3_hP1`FJamq?VcBx$17?#GZL}U?WS453DWn%7( z&O6+!cvLx!p!0f{ZJy^}`T*VYygaVh(KE3C^Eu#zA#Hg^2@EYxtEa;SN*@bB(WM9h z<-ES>BscZ;4B@-2*+gF37zo(dEPGjS6g1~zE55e{It*d(#fY-ojr_1Dx>2i-CaT)X zXR3_H*?t47(=Uo46tiI2OVcJ?8ce%vzDf5j-rGw^FMeZIHm&U&`hEO|KJ>;Z`yY0Q zLq?=rUipi{G-+-g;`&Wg4bnMly&)uaEAuqs9ar-q$HA3VKe}6OPy411CE*7f7q&G= zE}~{Juchtxzod4L8x&tu;ui#{Vgz%MzbIqFcCz=0X3+ogCioS zV}q!OSP=_c8BqZh=PE@9MgiYW5CV7Z-1qLwmyhJ*to84*_FDU7pS}Jarf+_ra!W&I zMJ4ViHo^AL!413rIYmqbi@PWTr<*u;t+W zfYQv`h86qdt2U=}zvc|I^~o5*UkAxxC?#1RxMktE+CNr|Jl`T z!Icei!ahGjq;9RXhQ>>ef}DmLP3R!57^{Zf>4ACvWh?V|_nyrG2S8HeaxtJ@s}54@ z=U+%6{oE94QQ3jUCH;}xp7w>_cKvYi%UG83W&MK__BivE(-S(V;avH&lfNv_$Nxz?b`dcp1E{IVB=pE?!UXS)VA(4J(WX;MyvR^B!`o@K>ecuU| z^Z*;5)kYWabigRh^eZ zH$MKZWU$JhYk$1rcAbM76!1%|xuM`;RybeFbo6q%q@4qNFHHX(9k;ZZx zKSZ4GRZR)4HITP}gg|4xx2{dO4=wtU3s$>riP4TR-5}j3?TV*)sZZ}xJbiiy)6=Jsr? zsHndbtvGREI&_!)M{XLicf5Mha4k_1@X|Mbp{J`P#0yLc;qRSL$pA zD^ERvrQsPBZ4H^FHj{JD1vNc;5@=zZ;M3us7_sJ#IW}jn3@pgTrvN4z<6}C2dpAGt zaKe>!CG+u{-_N~lI&avE&9E1%uVtJ2pS^^8UB}Dvt68$EIQ+$h(4)%-`u1V??<#Y? ztlF^R_!Y9>n#;Y%nGq!L2r{Aru(o9%oCR0~%k{UdOd#AYu;M{H+GfemM6iia&F)#gES&?$utxd$#>Hc`GAl%i#iHbpSeIk|=@SccPGl*9o&p zehAh*R9Eke8UgV~NF|e4lbt0!rtU?W4LbzLZ2Wq^4eSG_~fK*3Ig4H8ZhDTj;)nT{b_W&HC_% zJyjeDN)u{mG;&JN$H)-iY$>4x7@i+S<@|1)j@fyX!*JIf)vrI&6&=wfX<(DO_@w@s zs;}j8Oid03umvcgr!Zhl6#MHXH>|pxJD{Y+cREt0aUx;{2hMnKM?v(`71N6-X2q&7 z75U;Lru=q8_`z=UOutRIQ+20suU86x13VmsSMRLi*U`KR*!m07bYQvlmDHmitFjB8 z6NV=h=zT7BYovQvr!HmoTv}O>HBCR*h^<>vS|M*Ws=rn+>!G=2<;7dAw#R62_X4hH z;%ei?hA&R5VyiX;FUwlgp1f>i0A^mJt;zmgqUUgx``t{mN6es0>{Sy;w|v|KG*Ls@ z;I1Y%N&~40VbN&tU`k1&|LpYE_%V0??Ja1_?>DRndYfq0+OT)1I|(a)=)5tw5&g1V)uE=yw9KCcPdL5-&GxMg4sC zW$R=iJ?NM7j}?NQ7#E|(`u}uy%FaJDGEv=F`0`qLjdEG-gYee{dASE%TTm1OS<0)H zUk1PGf9!j{pei^AbN=ciD%&Xn@&;oeraf;_sVanTie2wM!$`rPPxG|Tp0ek@`Me_= zIX0B>gA;7d8eO0LkkjK#F)>MN{@m-TOHVak9I_;0Bw)V^h<~{-#3m-h6Yz-|C|a9xd-m(gzTYGR2U1<5iTL|z#W^;dc0XsxV5k1H z{yc-vDXWT1ZW`6Ud0to`A8FIpc%&RxQ-D4b9JJ?jME-mf*DhdqjsxN6Jdc^D9M|j) zC_>ruY#G`(r-E)HhpVpzTUwq5Nm5Uqq-f{!t#F=$&lVaMx+enJwg33zsCL$b&DwW# zt*v{@Rx9QKaQBpR zTgJ5Ggp968iY_d!W?N_@0l=f}Fj72Qkpb_Y@1nB`oS>jB7fb7!IoLG$S_IbLB-v@y z-5n_0#oj+ZEo%NW>`V`rG3}6B&cHrsiL6Vnjmh3IrUICnQ@GfZ-es*55`HSv8V$}{ zD>G7XqEA^@vu)1pAETnavNJkGx2$!1-*=d?oqyp_y>cd{T?C7!lR%n^w%Y9%03(V+ zU(p&v8vnGq+Y$MK}&Tm5>F zoutLhOZM4T?2{&STzeTie^~buBEG! z_h0R4DOVx2ajr9LW{k0bM`j`EypFN1jTJb>MA$S7jf;#Qjh)o51S8P6zYU7$c1V~y zdNPI0u*wkg-R8z9UrUk2-K6_Fh>X#yk<9#Os9BF5iepq5#@$r!BGWM?!&y<8fkVelcPI=o*x~bcd91l3ePF-7daJ+Tk*WTp=@4o8QRrR#Y z%GOmLvK^&xLka>}Xe39JniNgxo6s-WH|O-WDgv}L%fRu}Bh1@GCNzAHY0O$XINAIN zq$q4PW))MdK5;iPBs4NizK2QV*PsTw`I0(gu`3q%sGlrQKqp95fAhhf;r z5IiUhB@Xpnf?h{L(>y)VLJ`72L`WP9K?@NP3lU1B0F4W<<0R-9L;^p-#XbW-i-&>u zaGaC_vm{axBKq%;_O90lH;X5erl-zp3~m z>p+7v@HnC)g!T>&^HG19q&wZw9mr`~E)-M4gaV1iUN{IP6bV>jM1t06MR^JYJZ7R0 ziCQY*^0<=3C?<)329-lY%EB5xfLQdcC@lp3e}f3{V0Z_4`T!UL5e@w+XkBhWhpH`erL|P2)~tNhrdhvIQ(DA2=PG2Y{qf zHHr&~0s|ZzOmHFNI7AW&=fZ~AIM|us>_q0U@I+^%eP6~RfTD5Aq3Q@gjNrz>JTGmv zG-zZm0z`2kkX(pMe7u(6@h*6h2Zihcc@gnsh~i0^{nL%r0BM%CJ|Gydx$2pcF#qO; zG_4n-K{x_2mxQ(rfLXwS1>)6qfla6x0Kk42AOJ)p5ToJ$Tx_fLqSnz>4ba5r|E%*g zMX&~Y9KB!^8W>>qxOP&jBAWMRHLB(r;$ItQK?O*G4c>n=-(JQ{m65*%V`2EkYonO zQvG0YI9JS#;UPim5Rp(FT2VeQPmCm*-)IA}^S;?;tSnOm$BBiodS*!+5~u#)nhL}< e-uw+ZFc^+S#3+1i%0JXjfueZ_dX+ATPW>MU=~Mjx diff --git a/vitess.io/images/users/square_logo.png b/vitess.io/images/users/square_logo.png deleted file mode 100644 index fc71fc855f2765729a6f7caf77d0a19be8d0a3e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24598 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 U#hNAvfc`-mDmuy~iVs8n5A!4(hX4Qo diff --git a/vitess.io/images/users/stitchlabs_logo.png b/vitess.io/images/users/stitchlabs_logo.png deleted file mode 100644 index 440307d1df615a98b57f0d7a464451663396c268..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18772 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

    Jckd=;mlsWc0 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 Ef=@t+;s5{u diff --git a/vitess.io/images/users/youtube_logo.png b/vitess.io/images/users/youtube_logo.png deleted file mode 100644 index 165e04b58292b0dbe6b27581eef634e8dac9107d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20462 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 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vitess.io/images/vitess_logo_icon_size.png b/vitess.io/images/vitess_logo_icon_size.png deleted file mode 100644 index 51b813d82d3759a33512fcdfff412035fec18f58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1594 zcmV-A2F3Y_P)w`XYKZaIx>4pg8+8}_XEy|rO?2smfxIw zr6zVc0nA*ot~_!4@G8I^FG`*EWKea&)#m^=)mD;A#USt#5Om-Qxf~Ql%5J}D*1QMS7{jb}Z(h{-clUH- zj3MpId_M^0WNR6X3=^<25v_B}=T?)5)^UDr@=TP9Qilc;r*28cT8;Rb;JRtkrRjha@@qshB{n(+{ zvFN^#vTRC(WvUm6-0S9E#tBX3Q(?#3Y%E@r6xm=(Ag zFh+pi<#nenT0!Numf^i_CcUlm#1Ts=3lSlm$%MTi7zjM)*NJG|P`>ak2_WB=9ea1Y zT0HsYBdOTQ5XutmIgoAY>M2z<-vZFe8@BLdeb?RT!GZbxoiP!WofHw01N|TOHNW@g zeA^WSFfzv`@Yjg4vgd;5V6qH^fgew)stKR2-$ui->D>H$V~MX>9sloPTPY=ofHB(i z#n9btD@V57r~sU<-wMFtmunhEF^&H%lauX*)fFq(y}?q4k@(OnVz@_ zGU+d=a8a4(I#&C^x2?fs(oUt)ekz^W+|jV>z-Vk2tbse9eMGV{JG0|4NoXBXy&zW`dblTk+dV!X7klb_)BcUid`@2|<`{d*%b?<3i~|H=UX z@+@fWdo_M~5Hr{pkm|GWUFG|ph)4iDGuB6|j753QragS}_cx2JqM|>Vz^ej5>wwN! zJ0h|fSPS^0jeg7k@^b5gOBW!r3n+G+wCU+gbSR}BNH*_p8LKTd9sr0O0Nxc5T*vW& zH^$?9+yIW(zvkvTBJDX&zmrLA982Y2w%odC8312>X!+i - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vitess.io/images/vitess_logo_with_border.svg b/vitess.io/images/vitess_logo_with_border.svg deleted file mode 100644 index 5c6b8a06cea..00000000000 --- a/vitess.io/images/vitess_logo_with_border.svg +++ /dev/null @@ -1,281 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vitess.io/images/wood-texture-1600x800.jpg b/vitess.io/images/wood-texture-1600x800.jpg deleted file mode 100644 index 2e671b89582bf6c15c6a042dfdece81777a64ce0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122000 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

    ^>kI&trR*DyyziVp5N5z7 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 diff --git a/vitess.io/index.md b/vitess.io/index.md deleted file mode 100644 index 8753f2b698f..00000000000 --- a/vitess.io/index.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -layout: home -permalink: / -title: Vitess - Database Clustering System for Horizontal Scaling of MySQL ---- - -

    -
    -
    -

     Connection pooling

    -

    Vitess eliminates the high-memory overhead of MySQL connections. Its gRPC-based protocol lets Vitess servers easily handle thousands of connections at once.

    -
    -
    -

     Shard Management

    -

    MySQL doesn't natively support sharding, but you will likely need it as your database grows. Vitess saves you from having to add sharding logic to your app and also enables live resharding with minimal read-only downtime.

    -
    -
    -

     Workflow

    -

    Vitess keeps track of all of the metadata about your cluster configuration so that the cluster view is always up-to-date and consistent for different clients.

    -
    -
    - -
    - - - -
    -
    -

     Who uses Vitess

    -
    -
    - YouTube -
    -
    - Axon -
    -
    - BetterCloud -
    -
    -
    -
    - Flipkart -
    -
    - Hubspot -
    -
    - JD -
    -
    -
    -
    - Slack -
    -
    - Pixel Federation -
    -
    - Quiz of Kings -
    -
    -
    -
    - Nozzle -
    -
    - Square -
    -
    - Stitch Labs -
    -
    -
    -
    -

     An Introduction to Vitess

    -
    -
    - -
    -
    -
    -
    - -
    -
    - -
    -

    We are a Cloud Native Computing Foundation project.

    -
    diff --git a/vitess.io/internal/index.md b/vitess.io/internal/index.md deleted file mode 100644 index ace3e50c678..00000000000 --- a/vitess.io/internal/index.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: doc -title: "Overview" -description: -modified: -excerpt: -tags: [] -image: - feature: - teaser: - thumb: -toc: true -share: false ---- - -{% include doc/internal/Overview.md %} diff --git a/vitess.io/internal/publish-website.md b/vitess.io/internal/publish-website.md deleted file mode 100644 index 0ceb6a539e2..00000000000 --- a/vitess.io/internal/publish-website.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -layout: doc -title: "Publish Website" -description: -modified: -excerpt: -tags: [] -image: - feature: - teaser: - thumb: -toc: true -share: false ---- - -{% include doc/internal/PublishWebsite.md %} diff --git a/vitess.io/internal/release-instructions.md b/vitess.io/internal/release-instructions.md deleted file mode 100644 index a9a8ce777dd..00000000000 --- a/vitess.io/internal/release-instructions.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -layout: doc -title: "Release Instructions" -served_from: /internal/release-instructions.html -description: -modified: -excerpt: -tags: [] -image: - feature: - teaser: - thumb: -toc: true -share: false ---- - -{% include doc/internal/ReleaseInstructions.md %} diff --git a/vitess.io/js/_main.js b/vitess.io/js/_main.js deleted file mode 100644 index 755380863ba..00000000000 --- a/vitess.io/js/_main.js +++ /dev/null @@ -1,24 +0,0 @@ -// Off Canvas Sliding - -$(document).ready(function(){ - $('.js-menu-trigger').on('click touchstart', function(e){ - $('body').toggleClass('no-scroll'); - $('.js-menu, .js-menu-screen').toggleClass('is-visible'); - $('.sliding-menu-button').toggleClass('slide close'); - $('#masthead, #page-wrapper').toggleClass('slide'); - e.preventDefault(); - }); - $('.js-menu-screen').on('click touchstart', function(e){ - $('body').toggleClass('no-scroll'); - $('.js-menu, .js-menu-screen').toggleClass('is-visible'); - $('.sliding-menu-button').toggleClass('slide close'); - $('#masthead, #page-wrapper').toggleClass('slide'); - e.preventDefault(); - }); -}); - -// FitVids -$(document).ready(function(){ - // Target your .container, .wrapper, .post, etc. - $("#main").fitVids(); -}); \ No newline at end of file diff --git a/vitess.io/js/common.js b/vitess.io/js/common.js deleted file mode 100644 index 09e917a9a95..00000000000 --- a/vitess.io/js/common.js +++ /dev/null @@ -1,142 +0,0 @@ -// Make the table of contents -// Fix the left and right nav so they remain visible while scrolling -// Highlight current section in TOC with ScrollSpy -$(document).ready(function() { - $('#toc').toc({ listType: 'ul' }); - - // Set active item - var url = window.location.href.split('#')[0]; - $('a').filter(function() { - return this.href == url; - }).parent('li').addClass('active-item'); - - $('#sidebar').affix({ - offset: { - top: 110 - } - }); - $('#tocSidebar').affix({ - offset: { - top: 110 - } - }); - - var $body = $(document.body); - var navHeight = $('.navbar').outerHeight(true) + 20; - - $body.scrollspy({ - target: '#rightCol', - offset: navHeight - }); - -}); - -// Prettyprint -$('pre').addClass("prettyprint"); -$.getScript("https://cdn.rawgit.com/google/code-prettify/master/loader/run_prettify.js", function(){ -}); - -// Collapsible side menus -$.getScript("/js/jquery.collapsible.js", function() { - highlightActive(); - $('.submenu').collapsible(); -}); - -// Add the 'external' class to every outbound link on the site. -// This class is not set in the default CSS. -//$('a').filter(function() { -// return this.hostname && this.hostname !== location.hostname; -//}).addClass("external"); - -// TOC script -// https://github.com/ghiculescu/jekyll-table-of-contents -(function($){ - $.fn.toc = function(options) { - var tocDepth = $('#toc-depth').attr('data-toc-depth') || '' - var defaults = { - noBackToTopLinks: false, - title: 'Contents', - minimumHeaders: 3, - headers: tocDepth || 'h1, h2, h3, h4, h5, h6', - listType: 'ol', // values: [ol|ul] - showEffect: 'show', // values: [show|slideDown|fadeIn|none] - showSpeed: 'slow' // set to 0 to deactivate effect - }, - settings = $.extend(defaults, options); - - function fixedEncodeURIComponent (str) { - return encodeURIComponent(str).replace(/[!'()*]/g, function(c) { - return '%' + c.charCodeAt(0).toString(16); - }); - } - - var headers = $(settings.headers).filter(function() { - // get all headers with an ID - var previousSiblingName = $(this).prev().attr( 'name' ); - if (!this.id && previousSiblingName) { - this.id = $(this).attr( 'id', previousSiblingName.replace(/\./g, '-') ); - } - return this.id; - }), output = $(this); - if (!headers.length || headers.length < settings.minimumHeaders || !output.length) { - return; - } - - if (0 === settings.showSpeed) { - settings.showEffect = 'none'; - } - - var render = { - show: function() { output.hide().html(html).show(settings.showSpeed); }, - slideDown: function() { output.hide().html(html).slideDown(settings.showSpeed); }, - fadeIn: function() { output.hide().html(html).fadeIn(settings.showSpeed); }, - none: function() { output.html(html); } - }; - - var get_level = function(ele) { return parseInt(ele.nodeName.replace('H', ''), 10); } - var highest_level = headers.map(function(_, ele) { return get_level(ele); }).get().sort()[0]; - var return_to_top = ' '; - - var level = get_level(headers[0]), - this_level, - html = ('
    ' + settings.title + '<'+settings.listType+'>'); - headers.on('click', function() { - if (!settings.noBackToTopLinks) { - window.location.hash = this.id; - } - }) - .addClass('clickable-header') - .each(function(_, header) { - this_level = get_level(header); - if (!settings.noBackToTopLinks && this_level === highest_level) { - $(header).addClass('top-level-header').after(return_to_top); - } - if (this_level === level) // same level as before; same indenting - html += "
  • " + header.innerHTML + ""; - else if (this_level <= level){ // higher level than before; end parent ol - for(i = this_level; i < level; i++) { - html += "
  • " - } - html += "
  • " + header.innerHTML + ""; - } - else if (this_level > level) { // lower level than before; expand the previous to contain a ol - for(i = this_level; i > level; i--) { - html += "<"+settings.listType+">
  • " - } - html += "" + header.innerHTML + ""; - } - level = this_level; // update for the next one - }); - html += ""; - if (!settings.noBackToTopLinks) { - $(document).on('click', '.back-to-top', function() { - $(window).scrollTop(0); - window.location.hash = ''; - }); - } - - render[settings.showEffect](); - }; - -})(jQuery); diff --git a/vitess.io/js/jquery.collapsible.js b/vitess.io/js/jquery.collapsible.js deleted file mode 100644 index 26e28f5b991..00000000000 --- a/vitess.io/js/jquery.collapsible.js +++ /dev/null @@ -1,93 +0,0 @@ -/*! -* Adapted from collapsible.js 1.0.0 -* https://github.com/jordnkr/collapsible -*/ - - function highlightActive() { - function stringEndsWith(str, endsWithString) { - var index = str.indexOf(endsWithString); - if (index >= 0 && str.length == endsWithString.length + index) { - return true; - } else { - return false; - } - } - - // First have to invalidate old active item. - $('#sidebar a.active').removeClass('active'); - var currentLocation = window.location.hostname + window.location.pathname; - $('#sidebar li a[href]').each(function(index, element) { - if (stringEndsWith(currentLocation, element.href.replace(/^.*\/\//,"").replace(/\:\d+/, ""))) { - $(element).addClass('active'); - } - }); - }; - - -(function($, undefined) { - $.fn.collapsible = function(effect, options) { - var defaults = { - accordionUpSpeed: 400, - accordionDownSpeed: 400, - collapseSpeed: 400, - contentOpen: 0, - arrowRclass: 'arrow-r', - arrowDclass: 'arrow-d', - animate: true - }; - - if (typeof effect === "object") { - var settings = $.extend(defaults, effect); - } else { - var settings = $.extend(defaults, options); - } - - return this.each(function() { - if (settings.animate === false) { - settings.accordionUpSpeed = 0; - settings.accordionDownSpeed = 0; - settings.collapseSpeed = 0; - } - - var $thisEven = $(this).children(':even'); - var $thisOdd = $(this).children(':odd'); - var accord = 'accordion-active'; - - - switch (effect) { - case 'accordion-open': - /* FALLTHROUGH */ - case 'accordion': - if (effect === 'accordion-open') { - $($thisEven[settings.contentOpen]).children(':first-child').toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); - $($thisOdd[settings.contentOpen]).show().addClass(accord); - } - $($thisEven).click(function() { - if ($(this).next().attr('class') === accord) { - $(this).next().slideUp(settings.accordionUpSpeed).removeClass(accord); - $(this).children(':first-child').toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); - } else { - $($thisEven).children().removeClass(settings.arrowDclass).addClass(settings.arrowRclass); - $($thisOdd).slideUp(settings.accordionUpSpeed).removeClass(accord); - $(this).next().slideDown(settings.accordionDownSpeed).addClass(accord); - $(this).children(':first-child').toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); - } - }); - break; - case 'default-open': - /* FALLTHROUGH */ - default: - // is everything open by default or do I have an active child? - if (effect === 'default-open'|| $(this).find("a.active").length) { - $($thisEven[settings.contentOpen]).toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); - $($thisOdd[settings.contentOpen]).show(); - } - $($thisEven).click(function() { - $(this).toggleClass(settings.arrowRclass + ' ' + settings.arrowDclass); - $(this).next().slideToggle(settings.collapseSpeed); - }); - break; - } - }); - }; -})(jQuery); diff --git a/vitess.io/js/main.js b/vitess.io/js/main.js deleted file mode 100644 index 43609d23107..00000000000 --- a/vitess.io/js/main.js +++ /dev/null @@ -1 +0,0 @@ -/*! skinny-bones-jekyll - v0.0.1 - 2014-08-27 */!function($){"use strict";$.fn.fitVids=function(options){var settings={customSelector:null,ignore:null};if(!document.getElementById("fit-vids-style")){var head=document.head||document.getElementsByTagName("head")[0],css=".fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}",div=document.createElement("div");div.innerHTML='

    x

    ",head.appendChild(div.childNodes[1])}return options&&$.extend(settings,options),this.each(function(){var selectors=["iframe[src*='player.vimeo.com']","iframe[src*='youtube.com']","iframe[src*='youtube-nocookie.com']","iframe[src*='kickstarter.com'][src*='video.html']","object","embed"];settings.customSelector&&selectors.push(settings.customSelector);var ignoreList=".fitvidsignore";settings.ignore&&(ignoreList=ignoreList+", "+settings.ignore);var $allVideos=$(this).find(selectors.join(","));$allVideos=$allVideos.not("object object"),$allVideos=$allVideos.not(ignoreList),$allVideos.each(function(){var $this=$(this);if(!($this.parents(ignoreList).length>0||"embed"===this.tagName.toLowerCase()&&$this.parent("object").length||$this.parent(".fluid-width-video-wrapper").length)){$this.css("height")||$this.css("width")||!isNaN($this.attr("height"))&&!isNaN($this.attr("width"))||($this.attr("height",9),$this.attr("width",16));var height="object"===this.tagName.toLowerCase()||$this.attr("height")&&!isNaN(parseInt($this.attr("height"),10))?parseInt($this.attr("height"),10):$this.height(),width=isNaN(parseInt($this.attr("width"),10))?$this.width():parseInt($this.attr("width"),10),aspectRatio=height/width;if(!$this.attr("id")){var videoID="fitvid"+Math.floor(999999*Math.random());$this.attr("id",videoID)}$this.wrap('
    ').parent(".fluid-width-video-wrapper").css("padding-top",100*aspectRatio+"%"),$this.removeAttr("height").removeAttr("width")}})})}}(window.jQuery||window.Zepto),function($){var $w=$(window);$.fn.visible=function(partial,hidden,direction){if(!(this.length<1)){var $t=this.length>1?this.eq(0):this,t=$t.get(0),vpWidth=$w.width(),vpHeight=$w.height(),direction=direction?direction:"both",clientSize=hidden===!0?t.offsetWidth*t.offsetHeight:!0;if("function"==typeof t.getBoundingClientRect){var rec=t.getBoundingClientRect(),tViz=rec.top>=0&&rec.top0&&rec.bottom<=vpHeight,lViz=rec.left>=0&&rec.left0&&rec.right<=vpWidth,vVisible=partial?tViz||bViz:tViz&&bViz,hVisible=partial?lViz||lViz:lViz&&rViz;if("both"===direction)return clientSize&&vVisible&&hVisible;if("vertical"===direction)return clientSize&&vVisible;if("horizontal"===direction)return clientSize&&hVisible}else{var viewTop=$w.scrollTop(),viewBottom=viewTop+vpHeight,viewLeft=$w.scrollLeft(),viewRight=viewLeft+vpWidth,offset=$t.offset(),_top=offset.top,_bottom=_top+$t.height(),_left=offset.left,_right=_left+$t.width(),compareTop=partial===!0?_bottom:_top,compareBottom=partial===!0?_top:_bottom,compareLeft=partial===!0?_right:_left,compareRight=partial===!0?_left:_right;if("both"===direction)return!!clientSize&&viewBottom>=compareBottom&&compareTop>=viewTop&&viewRight>=compareRight&&compareLeft>=viewLeft;if("vertical"===direction)return!!clientSize&&viewBottom>=compareBottom&&compareTop>=viewTop;if("horizontal"===direction)return!!clientSize&&viewRight>=compareRight&&compareLeft>=viewLeft}}}}(jQuery),function($){$.fn.smoothScroller=function(options){options=$.extend({},$.fn.smoothScroller.defaults,options);var el=$(this);return $(options.scrollEl).animate({scrollTop:el.offset().top-$(options.scrollEl).position().top-options.offset},options.speed,options.ease,function(){var hash=el.attr("id");hash.length&&(history.pushState?history.pushState(null,null,"#"+hash):document.location.hash=hash),el.trigger("smoothScrollerComplete")}),this},$.fn.smoothScroller.defaults={speed:400,ease:"swing",scrollEl:"body",offset:0},$("body").on("click","[data-smoothscroller]",function(e){e.preventDefault();var href=$(this).attr("href");0===href.indexOf("#")&&$(href).smoothScroller()})}(jQuery),function($){var verboseIdCache={};$.fn.toc=function(options){var timeout,self=this,opts=$.extend({},jQuery.fn.toc.defaults,options),container=$(opts.container),headings=$(opts.selectors,container),headingOffsets=[],activeClassName=opts.activeClass,scrollTo=function(e,callback){if(opts.smoothScrolling&&"function"==typeof opts.smoothScrolling){e.preventDefault();var elScrollTo=$(e.target).attr("href");opts.smoothScrolling(elScrollTo,opts,callback)}$("li",self).removeClass(activeClassName),$(e.target).parent().addClass(activeClassName)},highlightOnScroll=function(){timeout&&clearTimeout(timeout),timeout=setTimeout(function(){for(var highlighted,top=$(window).scrollTop(),closest=Number.MAX_VALUE,index=0,i=0,c=headingOffsets.length;c>i;i++){var currentClosest=Math.abs(headingOffsets[i]-top);closest>currentClosest&&(index=i,closest=currentClosest)}$("li",self).removeClass(activeClassName),highlighted=$("li:eq("+index+")",self).addClass(activeClassName),opts.onHighlight(highlighted)},50)};return opts.highlightOnScroll&&($(window).bind("scroll",highlightOnScroll),highlightOnScroll()),this.each(function(){var el=$(this),ul=$(opts.listType);headings.each(function(i,heading){var $h=$(heading);headingOffsets.push($h.offset().top-opts.highlightOffset);var anchorName=opts.anchorName(i,heading,opts.prefix);if(heading.id!==anchorName){$("").attr("id",anchorName).insertBefore($h)}var a=$("").text(opts.headerText(i,heading,$h)).attr("href","#"+anchorName).bind("click",function(e){$(window).unbind("scroll",highlightOnScroll),scrollTo(e,function(){$(window).bind("scroll",highlightOnScroll)}),el.trigger("selected",$(this).attr("href"))}),li=$("
  • ").addClass(opts.itemClass(i,heading,$h,opts.prefix)).append(a);ul.append(li)}),el.html(ul)})},jQuery.fn.toc.defaults={container:"body",listType:"