Merge pull request #1614 from sougou/v3

V3: More features
This commit is contained in:
sougou 2016-03-31 11:04:48 -07:00
Родитель 01af7d7182 d855f13571
Коммит 0698355fb7
34 изменённых файлов: 643 добавлений и 530 удалений

Просмотреть файл

@ -6,6 +6,21 @@
"delete from nouser" "delete from nouser"
"table nouser not found" "table nouser not found"
# explicit keyspace reference
"update main.m1 set val = 1"
{
"Original": "update main.m1 set val = 1",
"Instructions": {
"Opcode": "UpdateUnsharded",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"Query": "update m1 set val = 1",
"Table": "m1"
}
}
# update unsharded # update unsharded
"update main1 set val = 1" "update main1 set val = 1"
{ {

Просмотреть файл

@ -790,6 +790,25 @@
} }
} }
# implicit table reference for unsharded keyspace
"select main.foo.col from main.foo"
{
"Original": "select main.foo.col from main.foo",
"Instructions": {
"Opcode": "SelectUnsharded",
"Keyspace": {
"Name": "main",
"Sharded": false
},
"Query": "select foo.col from foo",
"FieldQuery": "select foo.col from foo where 1 != 1"
}
}
# implicit table reference for sharded keyspace
"select user.foo.col from user.foo"
"table foo not found"
# duplicate symbols # duplicate symbols
"select user.id from user join user" "select user.id from user join user"
"duplicate symbol: user" "duplicate symbol: user"

Просмотреть файл

@ -20,7 +20,7 @@
"Owner": "user" "Owner": "user"
} }
}, },
"Classes": { "Tables": {
"user": { "user": {
"ColVindexes": [ "ColVindexes": [
{ {
@ -77,23 +77,14 @@
} }
] ]
} }
},
"Tables": {
"user": "user",
"user_extra": "user_extra",
"music": "music",
"music_extra": "music_extra"
} }
}, },
"main": { "main": {
"Classes": { "Tables": {
"main1": {},
"seq": { "seq": {
"Type": "Sequence" "Type": "Sequence"
} }
},
"Tables": {
"main1": "",
"seq": "seq"
} }
} }
} }

Просмотреть файл

@ -146,10 +146,6 @@
"delete from user where col = (select id from main1)" "delete from user where col = (select id from main1)"
"unsupported: subqueries in DML" "unsupported: subqueries in DML"
# qualified table name in DMLs
"update u.user set id = 1"
"unsupported: compex table expression in DML"
# update with no where clause # update with no where clause
"update user set val = 1" "update user set val = 1"
"unsupported: multi-shard where clause in DML" "unsupported: multi-shard where clause in DML"

Просмотреть файл

@ -28,7 +28,7 @@
"Type": "numeric" "Type": "numeric"
} }
}, },
"Classes": { "Tables": {
"user": { "user": {
"ColVindexes": [ "ColVindexes": [
{ {
@ -89,26 +89,18 @@
} }
] ]
} }
},
"Tables": {
"user": "user",
"user_extra": "user_extra",
"music": "music",
"music_extra": "music_extra",
"music_user_idx": "music_user_idx"
} }
}, },
"lookup": { "lookup": {
"Sharded": false, "Sharded": false,
"Classes": {
"seq": {
"Type": "Sequence"
}
},
"Tables": { "Tables": {
"user_seq": "seq", "user_seq": {
"music_seq": "seq", "Type": "Sequence"
"name_user_idx": "" },
"music_seq": {
"Type": "Sequence"
},
"name_user_idx": {}
} }
} }
} }

Просмотреть файл

@ -65,11 +65,11 @@ func (c *callerIDClient) checkCallerID(ctx context.Context, received string) (bo
return true, fmt.Errorf("SUCCESS: callerid matches") return true, fmt.Errorf("SUCCESS: callerid matches")
} }
func (c *callerIDClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c *callerIDClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if ok, err := c.checkCallerID(ctx, sql); ok { if ok, err := c.checkCallerID(ctx, sql); ok {
return nil, err return nil, err
} }
return c.fallbackClient.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction) return c.fallbackClient.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
} }
func (c *callerIDClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c *callerIDClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -118,11 +118,11 @@ func (c *callerIDClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []
return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session) return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session)
} }
func (c *callerIDClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c *callerIDClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if ok, err := c.checkCallerID(ctx, sql); ok { if ok, err := c.checkCallerID(ctx, sql); ok {
return err return err
} }
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply) return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, keyspace, tabletType, sendReply)
} }
func (c *callerIDClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c *callerIDClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {

Просмотреть файл

@ -86,18 +86,19 @@ func echoQueryResult(vals map[string]interface{}) *sqltypes.Result {
return qr return qr
} }
func (c *echoClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c *echoClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if strings.HasPrefix(sql, EchoPrefix) { if strings.HasPrefix(sql, EchoPrefix) {
return echoQueryResult(map[string]interface{}{ return echoQueryResult(map[string]interface{}{
"callerId": callerid.EffectiveCallerIDFromContext(ctx), "callerId": callerid.EffectiveCallerIDFromContext(ctx),
"query": sql, "query": sql,
"bindVars": bindVariables, "bindVars": bindVariables,
"keyspace": keyspace,
"tabletType": tabletType, "tabletType": tabletType,
"session": session, "session": session,
"notInTransaction": notInTransaction, "notInTransaction": notInTransaction,
}), nil }), nil
} }
return c.fallbackClient.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction) return c.fallbackClient.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
} }
func (c *echoClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c *echoClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -205,17 +206,18 @@ func (c *echoClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtg
return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session) return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session)
} }
func (c *echoClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c *echoClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if strings.HasPrefix(sql, EchoPrefix) { if strings.HasPrefix(sql, EchoPrefix) {
sendReply(echoQueryResult(map[string]interface{}{ sendReply(echoQueryResult(map[string]interface{}{
"callerId": callerid.EffectiveCallerIDFromContext(ctx), "callerId": callerid.EffectiveCallerIDFromContext(ctx),
"query": sql, "query": sql,
"bindVars": bindVariables, "bindVars": bindVariables,
"keyspace": keyspace,
"tabletType": tabletType, "tabletType": tabletType,
})) }))
return nil return nil
} }
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply) return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, keyspace, tabletType, sendReply)
} }
func (c *echoClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c *echoClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {

Просмотреть файл

@ -118,14 +118,14 @@ func trimmedRequestToError(received string) error {
} }
} }
func (c *errorClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c *errorClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if err := requestToPartialError(sql, session); err != nil { if err := requestToPartialError(sql, session); err != nil {
return nil, err return nil, err
} }
if err := requestToError(sql); err != nil { if err := requestToError(sql); err != nil {
return nil, err return nil, err
} }
return c.fallbackClient.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction) return c.fallbackClient.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
} }
func (c *errorClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c *errorClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -192,11 +192,11 @@ func (c *errorClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vt
return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session) return c.fallbackClient.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session)
} }
func (c *errorClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c *errorClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if err := requestToError(sql); err != nil { if err := requestToError(sql); err != nil {
return err return err
} }
return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply) return c.fallbackClient.StreamExecute(ctx, sql, bindVariables, keyspace, tabletType, sendReply)
} }
func (c *errorClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c *errorClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {

Просмотреть файл

@ -27,8 +27,8 @@ func newFallbackClient(fallback vtgateservice.VTGateService) fallbackClient {
return fallbackClient{fallback: fallback} return fallbackClient{fallback: fallback}
} }
func (c fallbackClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c fallbackClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
return c.fallback.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction) return c.fallback.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
} }
func (c fallbackClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c fallbackClient) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -55,8 +55,8 @@ func (c fallbackClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*
return c.fallback.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session) return c.fallback.ExecuteBatchKeyspaceIds(ctx, queries, tabletType, asTransaction, session)
} }
func (c fallbackClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c fallbackClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
return c.fallback.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply) return c.fallback.StreamExecute(ctx, sql, bindVariables, keyspace, tabletType, sendReply)
} }
func (c fallbackClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c fallbackClient) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {

Просмотреть файл

@ -29,7 +29,7 @@ func newTerminalClient() *terminalClient {
return &terminalClient{} return &terminalClient{}
} }
func (c *terminalClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (c *terminalClient) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if sql == "quit://" { if sql == "quit://" {
log.Fatal("Received quit:// query. Going down.") log.Fatal("Received quit:// query. Going down.")
} }
@ -60,7 +60,7 @@ func (c *terminalClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []
return nil, errTerminal return nil, errTerminal
} }
func (c *terminalClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (c *terminalClient) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
return errTerminal return errTerminal
} }

Просмотреть файл

@ -114,6 +114,8 @@ type ExecuteRequest struct {
TabletType topodata.TabletType `protobuf:"varint,4,opt,name=tablet_type,json=tabletType,enum=topodata.TabletType" json:"tablet_type,omitempty"` TabletType topodata.TabletType `protobuf:"varint,4,opt,name=tablet_type,json=tabletType,enum=topodata.TabletType" json:"tablet_type,omitempty"`
// not_in_transaction is deprecated and should not be used. // not_in_transaction is deprecated and should not be used.
NotInTransaction bool `protobuf:"varint,5,opt,name=not_in_transaction,json=notInTransaction" json:"not_in_transaction,omitempty"` NotInTransaction bool `protobuf:"varint,5,opt,name=not_in_transaction,json=notInTransaction" json:"not_in_transaction,omitempty"`
// keyspace to target the query to.
Keyspace string `protobuf:"bytes,6,opt,name=keyspace" json:"keyspace,omitempty"`
} }
func (m *ExecuteRequest) Reset() { *m = ExecuteRequest{} } func (m *ExecuteRequest) Reset() { *m = ExecuteRequest{} }
@ -774,6 +776,8 @@ type StreamExecuteRequest struct {
Query *query.BoundQuery `protobuf:"bytes,2,opt,name=query" json:"query,omitempty"` Query *query.BoundQuery `protobuf:"bytes,2,opt,name=query" json:"query,omitempty"`
// tablet_type is the type of tablets that this query is targeted to. // tablet_type is the type of tablets that this query is targeted to.
TabletType topodata.TabletType `protobuf:"varint,3,opt,name=tablet_type,json=tabletType,enum=topodata.TabletType" json:"tablet_type,omitempty"` TabletType topodata.TabletType `protobuf:"varint,3,opt,name=tablet_type,json=tabletType,enum=topodata.TabletType" json:"tablet_type,omitempty"`
// keyspace to target the query to.
Keyspace string `protobuf:"bytes,4,opt,name=keyspace" json:"keyspace,omitempty"`
} }
func (m *StreamExecuteRequest) Reset() { *m = StreamExecuteRequest{} } func (m *StreamExecuteRequest) Reset() { *m = StreamExecuteRequest{} }
@ -1376,87 +1380,88 @@ func init() {
} }
var fileDescriptor0 = []byte{ var fileDescriptor0 = []byte{
// 1304 bytes of a gzipped FileDescriptorProto // 1316 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xd4, 0x59, 0x4f, 0x6f, 0xe3, 0x44, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xd4, 0x59, 0x4f, 0x6f, 0xe3, 0x44,
0x14, 0x97, 0xe3, 0x34, 0x69, 0x9e, 0x93, 0xb4, 0xf5, 0xb6, 0xdb, 0x10, 0x96, 0x6d, 0xb1, 0x40, 0x14, 0x97, 0xe3, 0x34, 0x69, 0x9e, 0x93, 0xb4, 0xeb, 0x6d, 0x77, 0x43, 0x58, 0xb6, 0xc5, 0x02,
0x5b, 0x60, 0x65, 0x69, 0xb3, 0xfc, 0x13, 0x42, 0x02, 0x1a, 0x2a, 0x14, 0x2d, 0xac, 0xca, 0xb4, 0x6d, 0x81, 0x95, 0xa5, 0xcd, 0xf2, 0x4f, 0x08, 0x09, 0x68, 0xa8, 0x50, 0xb4, 0xb0, 0x2a, 0xd3,
0x42, 0x1c, 0x40, 0x96, 0x9b, 0x8c, 0x5a, 0xd3, 0xc4, 0x0e, 0x9e, 0x71, 0xa0, 0x1c, 0xb8, 0x21, 0x0a, 0x71, 0x00, 0x59, 0x6e, 0x32, 0x6a, 0x4d, 0x13, 0x3b, 0x78, 0xc6, 0x81, 0x72, 0xe0, 0x86,
0x71, 0xdb, 0x13, 0x12, 0x42, 0x5c, 0x90, 0xf8, 0x02, 0x7c, 0x04, 0x4e, 0x1c, 0x39, 0x70, 0xe0, 0xc4, 0x6d, 0x0f, 0x08, 0x09, 0x21, 0x2e, 0x7c, 0x04, 0xbe, 0x01, 0x9c, 0x38, 0x72, 0xe0, 0xc0,
0xc6, 0x47, 0x80, 0x23, 0x17, 0x0e, 0x8c, 0x67, 0xc6, 0x7f, 0xe2, 0x36, 0x69, 0x9a, 0xb4, 0x55, 0x8d, 0x8f, 0x00, 0x5f, 0x80, 0x03, 0xe3, 0x99, 0xf1, 0x9f, 0xb8, 0x49, 0x9a, 0x26, 0x6d, 0x95,
0x7a, 0xaa, 0x67, 0xde, 0x9b, 0x79, 0xef, 0xfd, 0x7e, 0x6f, 0xde, 0xcc, 0x6b, 0xa0, 0x3c, 0xa0, 0x9e, 0xea, 0x99, 0xf7, 0x66, 0xde, 0x7b, 0xbf, 0xdf, 0x9b, 0x37, 0xf3, 0x1a, 0x28, 0x0f, 0xe8,
0x87, 0x36, 0xc5, 0x66, 0xdf, 0xf7, 0xa8, 0xa7, 0x17, 0xc4, 0xa8, 0xae, 0x7d, 0x1e, 0x60, 0xff, 0xa1, 0x4d, 0xb1, 0xd9, 0xf7, 0x3d, 0xea, 0xe9, 0x05, 0x31, 0xaa, 0x6b, 0x9f, 0x07, 0xd8, 0x3f,
0x44, 0x4c, 0xd6, 0xab, 0xd4, 0xeb, 0x7b, 0x1d, 0x9b, 0xda, 0x72, 0xac, 0x0d, 0xa8, 0xdf, 0x6f, 0x11, 0x93, 0xf5, 0x2a, 0xf5, 0xfa, 0x5e, 0xc7, 0xa6, 0xb6, 0x1c, 0x6b, 0x03, 0xea, 0xf7, 0xdb,
0x8b, 0x81, 0xf1, 0x87, 0x02, 0xc5, 0x3d, 0x4c, 0x88, 0xe3, 0xb9, 0xfa, 0xf3, 0x50, 0x75, 0x5c, 0x62, 0x60, 0xfc, 0xa9, 0x40, 0x71, 0x0f, 0x13, 0xe2, 0x78, 0xae, 0xfe, 0x3c, 0x54, 0x1d, 0xd7,
0x8b, 0xfa, 0xb6, 0x4b, 0xec, 0x36, 0x65, 0x33, 0x35, 0x65, 0x53, 0xd9, 0x5a, 0x44, 0x15, 0xc7, 0xa2, 0xbe, 0xed, 0x12, 0xbb, 0x4d, 0xd9, 0x4c, 0x4d, 0xd9, 0x54, 0xb6, 0x96, 0x51, 0xc5, 0x71,
0xdd, 0x4f, 0x26, 0xf5, 0x26, 0x54, 0xc9, 0x91, 0xed, 0x77, 0x2c, 0x22, 0xd6, 0x91, 0x5a, 0x6e, 0xf7, 0x93, 0x49, 0xbd, 0x09, 0x55, 0x72, 0x64, 0xfb, 0x1d, 0x8b, 0x88, 0x75, 0xa4, 0x96, 0xdb,
0x53, 0xdd, 0xd2, 0x1a, 0x77, 0x4c, 0xe9, 0x8b, 0xdc, 0xcf, 0xdc, 0x0b, 0xb5, 0xe4, 0x00, 0x55, 0x54, 0xb7, 0xb4, 0xc6, 0x1d, 0x53, 0xfa, 0x22, 0xf7, 0x33, 0xf7, 0x42, 0x2d, 0x39, 0x40, 0x15,
0x48, 0x6a, 0x44, 0xea, 0x9f, 0x40, 0x39, 0x2d, 0x66, 0xb6, 0x0b, 0xd4, 0xf6, 0x0f, 0x31, 0xe5, 0x92, 0x1a, 0x91, 0xfa, 0x27, 0x50, 0x4e, 0x8b, 0x99, 0xed, 0x02, 0xb5, 0xfd, 0x43, 0x4c, 0xb9,
0x36, 0xb5, 0x46, 0xc5, 0x14, 0x21, 0xec, 0xf3, 0x49, 0x24, 0x85, 0xa1, 0x8b, 0x29, 0xff, 0x2c, 0x4d, 0xad, 0x51, 0x31, 0x45, 0x08, 0xfb, 0x7c, 0x12, 0x49, 0x61, 0xe8, 0x62, 0xca, 0x3f, 0xcb,
0xa7, 0xc3, 0x6c, 0x2b, 0x5b, 0x2a, 0xaa, 0xa4, 0x66, 0x5b, 0x1d, 0xe3, 0x5f, 0x05, 0xaa, 0x3b, 0xe9, 0x30, 0xdb, 0xca, 0x96, 0x8a, 0x2a, 0xa9, 0xd9, 0x56, 0xc7, 0xf8, 0x2e, 0x07, 0xd5, 0x9d,
0x5f, 0xe2, 0x76, 0x40, 0x31, 0xc2, 0x6c, 0x23, 0x42, 0xf5, 0xfb, 0x50, 0x6a, 0xdb, 0xdd, 0x2e, 0x2f, 0x71, 0x3b, 0xa0, 0x18, 0x61, 0xb6, 0x11, 0xa1, 0xfa, 0x7d, 0x28, 0xb5, 0xed, 0x6e, 0x17,
0xf6, 0xc3, 0x45, 0xc2, 0xc6, 0x92, 0x29, 0x90, 0x68, 0xf2, 0xf9, 0xd6, 0xbb, 0x68, 0x51, 0x68, 0xfb, 0xe1, 0x22, 0x61, 0x63, 0xc5, 0x14, 0x48, 0x34, 0xf9, 0x7c, 0xeb, 0x5d, 0xb4, 0x2c, 0x34,
0xb4, 0x3a, 0xfa, 0x0b, 0x50, 0x94, 0xd1, 0x71, 0x03, 0x42, 0x37, 0x1d, 0x1c, 0x8a, 0xe4, 0xfa, 0x5a, 0x1d, 0xfd, 0x05, 0x28, 0xca, 0xe8, 0xb8, 0x01, 0xa1, 0x9b, 0x0e, 0x0e, 0x45, 0x72, 0xfd,
0x3d, 0x58, 0xe0, 0xae, 0xd6, 0x54, 0xae, 0xb8, 0x22, 0x1d, 0xdf, 0xf6, 0x02, 0xb7, 0xf3, 0x61, 0x1e, 0x2c, 0x71, 0x57, 0x6b, 0x2a, 0x57, 0xbc, 0x21, 0x1d, 0xdf, 0xf6, 0x02, 0xb7, 0xf3, 0x61,
0xf8, 0x89, 0x84, 0x5c, 0x7f, 0x05, 0x34, 0x6a, 0x1f, 0x74, 0x31, 0xb5, 0xe8, 0x49, 0x1f, 0xd7, 0xf8, 0x89, 0x84, 0x5c, 0x7f, 0x05, 0x34, 0x6a, 0x1f, 0x74, 0x31, 0xb5, 0xe8, 0x49, 0x1f, 0xd7,
0xf2, 0x4c, 0xbd, 0xda, 0x58, 0x35, 0x63, 0x76, 0xf6, 0xb9, 0x70, 0x9f, 0xc9, 0x10, 0xd0, 0xf8, 0xf2, 0x4c, 0xbd, 0xda, 0x58, 0x33, 0x63, 0x76, 0xf6, 0xb9, 0x70, 0x9f, 0xc9, 0x10, 0xd0, 0xf8,
0x9b, 0x39, 0xae, 0xbb, 0x1e, 0xb5, 0x32, 0xcc, 0x2c, 0x70, 0x66, 0x96, 0x99, 0xa4, 0x95, 0x26, 0x9b, 0x39, 0xae, 0xbb, 0x1e, 0xb5, 0x32, 0xcc, 0x2c, 0x71, 0x66, 0x56, 0x99, 0xa4, 0x35, 0x44,
0xc7, 0x78, 0xa2, 0xc0, 0x52, 0x1c, 0x39, 0xe9, 0x33, 0xa8, 0x31, 0x03, 0x6d, 0x01, 0xfb, 0xbe, 0x4e, 0x1d, 0x96, 0x8f, 0xf1, 0x09, 0xe9, 0xdb, 0x6d, 0x5c, 0x2b, 0x30, 0x9d, 0x12, 0x8a, 0xc7,
0xe7, 0x67, 0xc2, 0x46, 0xbb, 0xcd, 0x9d, 0x70, 0x1a, 0x09, 0xe9, 0x45, 0x62, 0x7e, 0x11, 0x0a, 0xc6, 0x13, 0x05, 0x56, 0x62, 0x54, 0x48, 0x9f, 0xd1, 0x80, 0x19, 0xa0, 0x4b, 0xd8, 0xf7, 0x3d,
0x3e, 0x26, 0x41, 0x97, 0xca, 0xa0, 0x75, 0x19, 0xb4, 0x88, 0x97, 0x4b, 0x90, 0xd4, 0x30, 0x7e, 0x3f, 0x03, 0x09, 0xda, 0x6d, 0xee, 0x84, 0xd3, 0x48, 0x48, 0xcf, 0x83, 0xc7, 0x8b, 0x50, 0xf0,
0xc9, 0xc1, 0xaa, 0xf4, 0x88, 0x33, 0x4e, 0xe6, 0x87, 0x91, 0x3a, 0x2c, 0x1e, 0xe3, 0x13, 0xd2, 0x31, 0x09, 0xba, 0x54, 0x02, 0xa2, 0x4b, 0x40, 0x04, 0x16, 0x5c, 0x82, 0xa4, 0x86, 0xf1, 0x4b,
0xb7, 0xdb, 0x82, 0x8e, 0x12, 0x8a, 0xc7, 0xfa, 0x6d, 0x28, 0xf0, 0x8c, 0x25, 0x0c, 0x6a, 0x95, 0x0e, 0xd6, 0xa4, 0x47, 0x3c, 0x1b, 0xc8, 0xe2, 0xb0, 0x95, 0x06, 0x32, 0x3f, 0x0c, 0xa4, 0x7e,
0x49, 0xe4, 0x28, 0xcb, 0x62, 0x61, 0x26, 0x16, 0x8b, 0x23, 0x58, 0xfc, 0x4e, 0x81, 0xb5, 0x0c, 0x0b, 0x0a, 0x3c, 0x9b, 0x09, 0xa3, 0x41, 0x65, 0x12, 0x39, 0xca, 0x32, 0x5c, 0x98, 0x8b, 0xe1,
0x66, 0x73, 0xc1, 0xe5, 0xaf, 0x39, 0x78, 0x4a, 0xfa, 0xf5, 0x48, 0x02, 0xd5, 0xba, 0x29, 0x84, 0xe2, 0x68, 0x86, 0x8d, 0xef, 0x15, 0x58, 0xcf, 0x60, 0xb6, 0x10, 0x5c, 0xfe, 0x96, 0x83, 0xa7,
0x3e, 0x0b, 0xe5, 0xe8, 0x9b, 0xf9, 0x27, 0x68, 0x2d, 0x23, 0xed, 0x38, 0x89, 0xe3, 0x7a, 0xb8, 0xa4, 0x5f, 0x8f, 0x24, 0x50, 0xad, 0xeb, 0x42, 0xe8, 0xb3, 0x50, 0x8e, 0xbe, 0x99, 0x7f, 0x82,
0xfd, 0x41, 0x81, 0xfa, 0x59, 0x18, 0xce, 0x05, 0xc1, 0xbf, 0xe7, 0x60, 0x3d, 0x71, 0x0e, 0xd9, 0xd6, 0x32, 0xd2, 0x8e, 0x93, 0x38, 0xae, 0x86, 0xdb, 0x1f, 0x15, 0xa8, 0x8f, 0xc2, 0x70, 0x21,
0xee, 0x21, 0xbe, 0x21, 0xf4, 0x3e, 0x00, 0x60, 0xdf, 0x96, 0xcf, 0x5d, 0xe6, 0xe4, 0x86, 0x91, 0x08, 0xfe, 0x23, 0x07, 0xb7, 0x13, 0xe7, 0x90, 0xed, 0x1e, 0xe2, 0x6b, 0x42, 0xef, 0x03, 0x00,
0xc6, 0xd4, 0x45, 0xd1, 0xa0, 0xd2, 0x71, 0x14, 0xd7, 0xf5, 0xd0, 0xfd, 0xbd, 0x02, 0xb5, 0xd3, 0xf6, 0x6d, 0xf9, 0xdc, 0x65, 0x4e, 0x6e, 0x18, 0x69, 0x4c, 0x5d, 0x14, 0x0d, 0x2a, 0x1d, 0x47,
0x88, 0xce, 0x05, 0xd9, 0xdf, 0xe6, 0x63, 0xb2, 0x77, 0x5c, 0xea, 0xd0, 0x93, 0x1b, 0x73, 0x96, 0x71, 0x5d, 0x0d, 0xdd, 0x3f, 0x28, 0x50, 0x3b, 0x8d, 0xe8, 0x42, 0x90, 0xfd, 0x6d, 0x3e, 0x26,
0x19, 0x05, 0x98, 0x7b, 0x6c, 0xb5, 0xbd, 0x6e, 0xd0, 0x73, 0x2d, 0xd7, 0xee, 0x61, 0x7e, 0x27, 0x7b, 0xc7, 0xa5, 0x0e, 0x3d, 0xb9, 0x36, 0x67, 0x99, 0x51, 0x80, 0xb9, 0xc7, 0x56, 0xdb, 0xeb,
0x96, 0xd0, 0xb2, 0x90, 0x34, 0xb9, 0xe0, 0x31, 0x9b, 0xd7, 0x3f, 0x86, 0x5b, 0x52, 0x7b, 0xa8, 0x06, 0x3d, 0xd7, 0x72, 0xed, 0x1e, 0xe6, 0xf7, 0x65, 0x09, 0xad, 0x0a, 0x49, 0x93, 0x0b, 0x1e,
0x00, 0x14, 0x78, 0x8e, 0x6c, 0x45, 0x9e, 0x8e, 0x40, 0xc2, 0x8c, 0x26, 0xd0, 0x8a, 0xd8, 0xe4, 0xb3, 0x79, 0xfd, 0x63, 0xb8, 0x29, 0xb5, 0x87, 0x0a, 0x40, 0x81, 0xe7, 0xc8, 0x56, 0xe4, 0xe9,
0xd1, 0xe8, 0x82, 0x51, 0x9c, 0x29, 0x83, 0x16, 0xcf, 0xce, 0xa0, 0xfa, 0x01, 0x2c, 0x46, 0x3e, 0x18, 0x24, 0xcc, 0x68, 0x02, 0xdd, 0x10, 0x9b, 0x3c, 0x1a, 0x5f, 0x30, 0x8a, 0x73, 0x65, 0xd0,
0xe8, 0x1b, 0x90, 0xe7, 0x96, 0x14, 0x6e, 0x49, 0x8b, 0x1e, 0x49, 0xa1, 0x01, 0x2e, 0xd0, 0x57, 0xf2, 0xe8, 0x0c, 0xaa, 0x1f, 0xc0, 0x72, 0xe4, 0x83, 0xbe, 0x01, 0x79, 0x6e, 0x49, 0xe1, 0x96,
0x61, 0x61, 0x60, 0x77, 0x03, 0xcc, 0x79, 0x28, 0x23, 0x31, 0x60, 0xcb, 0xb4, 0x54, 0xe8, 0x1c, 0xb4, 0xe8, 0x01, 0x15, 0x1a, 0xe0, 0x02, 0x7d, 0x0d, 0x96, 0x06, 0x76, 0x37, 0xc0, 0x9c, 0x87,
0xfa, 0x32, 0x82, 0xa4, 0xf4, 0xa5, 0xb3, 0x34, 0x05, 0xc0, 0x5c, 0x64, 0xa9, 0x0b, 0x4b, 0x3c, 0x32, 0x12, 0x03, 0xb6, 0x4c, 0x4b, 0x85, 0xce, 0xa1, 0x2f, 0x23, 0x48, 0x4a, 0x5f, 0x3a, 0x4b,
0x39, 0xf8, 0x45, 0xc8, 0x15, 0x92, 0x1c, 0x52, 0x2e, 0x90, 0x43, 0xb9, 0x91, 0x17, 0xbc, 0x9a, 0x53, 0x00, 0x2c, 0x44, 0x96, 0xba, 0xb0, 0xc2, 0x93, 0x83, 0x5f, 0x84, 0x5c, 0x21, 0xc9, 0x21,
0xbe, 0xe0, 0x8d, 0x6f, 0x92, 0x3b, 0x6e, 0xdb, 0xa6, 0xed, 0xa3, 0x6b, 0x7a, 0xb4, 0x3c, 0x80, 0xe5, 0x1c, 0x39, 0x94, 0x1b, 0x7b, 0xc1, 0xab, 0xe9, 0x0b, 0xde, 0xf8, 0x26, 0xb9, 0xe3, 0xb6,
0x62, 0xe8, 0xb3, 0x83, 0x85, 0x3f, 0x5a, 0x63, 0x3d, 0x52, 0xcd, 0x44, 0x8f, 0x22, 0xbd, 0x69, 0x6d, 0xda, 0x3e, 0xba, 0xa2, 0x47, 0xcb, 0x03, 0x28, 0x86, 0x3e, 0x3b, 0x58, 0xf8, 0xa3, 0x35,
0x1f, 0x94, 0xec, 0x0d, 0x6d, 0x93, 0x33, 0x1e, 0x93, 0x15, 0x9b, 0xa4, 0x0b, 0xd7, 0x8f, 0xc9, 0x6e, 0x47, 0xaa, 0x99, 0xe8, 0x51, 0xa4, 0x37, 0xeb, 0x63, 0x93, 0xbd, 0xaf, 0x6d, 0x32, 0xe2,
0x3d, 0x35, 0x84, 0xc3, 0x95, 0x25, 0xc5, 0x7d, 0x28, 0x0a, 0xca, 0x23, 0x04, 0xce, 0xca, 0x8a, 0xa1, 0x59, 0xb1, 0x49, 0xba, 0x70, 0xfd, 0x94, 0xdc, 0x53, 0x43, 0x38, 0x5c, 0x5a, 0x52, 0xdc,
0x48, 0xc5, 0xf8, 0x1a, 0x56, 0x39, 0x30, 0xc9, 0x71, 0xbc, 0xc4, 0xdc, 0xc8, 0xbe, 0x15, 0xd4, 0x87, 0xa2, 0xa0, 0x3c, 0x42, 0x60, 0x54, 0x56, 0x44, 0x2a, 0xc6, 0xd7, 0xb0, 0xc6, 0x81, 0x49,
0x53, 0x6f, 0x05, 0xe3, 0x49, 0x0e, 0xee, 0xa6, 0xe1, 0xb9, 0xce, 0xf7, 0xd0, 0xab, 0xd9, 0x5c, 0x8e, 0xe3, 0x05, 0xe6, 0x46, 0xf6, 0xad, 0xa0, 0x9e, 0x7a, 0x2b, 0x18, 0x4f, 0x72, 0x70, 0x37,
0xb9, 0x33, 0x94, 0x2b, 0x19, 0x48, 0xae, 0x2b, 0x61, 0x7e, 0x52, 0x60, 0x63, 0x24, 0x22, 0x73, 0x0d, 0xcf, 0x55, 0xbe, 0x87, 0x5e, 0xcd, 0xe6, 0xca, 0x9d, 0xa1, 0x5c, 0xc9, 0x40, 0x72, 0x55,
0x92, 0x35, 0x3f, 0x2b, 0xb0, 0xba, 0x47, 0x7d, 0x6c, 0xf7, 0x66, 0x6a, 0x0f, 0xe3, 0x24, 0xcb, 0x09, 0xf3, 0xb3, 0x02, 0x1b, 0x63, 0x11, 0x59, 0x90, 0xac, 0xf9, 0x55, 0x81, 0xb5, 0x3d, 0xea,
0x5d, 0xac, 0xe7, 0x53, 0x27, 0x43, 0xdc, 0x68, 0xc2, 0x5a, 0xc6, 0x4b, 0x89, 0x5f, 0x52, 0x38, 0x63, 0xbb, 0x37, 0x57, 0xeb, 0x18, 0x27, 0x59, 0xee, 0x7c, 0xfd, 0xa0, 0x3a, 0x25, 0xe2, 0x13,
0x95, 0x73, 0x0b, 0xe7, 0x5f, 0xec, 0x00, 0x0f, 0xed, 0x32, 0x4b, 0x25, 0x9b, 0x38, 0xe2, 0xf4, 0xee, 0x3e, 0xa3, 0x09, 0xeb, 0x99, 0x08, 0x24, 0xb6, 0x49, 0x51, 0x55, 0xce, 0x2c, 0xaa, 0x7f,
0xb1, 0x52, 0x47, 0x96, 0xdc, 0xfc, 0xb8, 0x9e, 0x6a, 0x61, 0x42, 0x94, 0x5a, 0xf0, 0xf4, 0x99, 0xb3, 0xc3, 0x3d, 0xb4, 0xcb, 0x3c, 0x55, 0x6e, 0x6a, 0x34, 0xd2, 0x61, 0xa9, 0x63, 0xcb, 0x71,
0xf1, 0x4d, 0x81, 0xd5, 0xdf, 0x2c, 0x77, 0x87, 0xf6, 0x9a, 0xf9, 0x38, 0x5f, 0x0a, 0x60, 0xd9, 0x7e, 0x52, 0xbf, 0xb5, 0x34, 0x1d, 0x82, 0x46, 0x0b, 0x9e, 0x1e, 0x19, 0xdf, 0x0c, 0x58, 0xfd,
0x3a, 0x94, 0x3f, 0xb7, 0x67, 0x99, 0x14, 0xbb, 0xc7, 0xb0, 0x39, 0x3a, 0xde, 0x29, 0x00, 0xfc, 0xc3, 0xf2, 0x7a, 0x68, 0xaf, 0xb9, 0x8f, 0xfa, 0x85, 0x00, 0x96, 0xad, 0x51, 0xf9, 0x33, 0xfb,
0x4f, 0x81, 0x67, 0xb2, 0x1b, 0xce, 0xd2, 0x3e, 0x5c, 0x0a, 0x7c, 0xc3, 0x3d, 0x41, 0x7e, 0x8a, 0x99, 0x69, 0xb1, 0x7b, 0x0c, 0x9b, 0xe3, 0xe3, 0x9d, 0x01, 0xc0, 0xff, 0x14, 0x78, 0x26, 0xbb,
0x9e, 0x60, 0x52, 0x38, 0xdf, 0x87, 0xbb, 0xa3, 0xa2, 0x9f, 0x02, 0xcc, 0x37, 0xa1, 0xbc, 0x8d, 0xe1, 0x3c, 0xad, 0xc5, 0x85, 0xc0, 0x37, 0xdc, 0x2f, 0xe4, 0x67, 0xe8, 0x17, 0xa6, 0x85, 0xf3,
0x0f, 0x1d, 0x77, 0x2a, 0xe8, 0x8c, 0x37, 0xa0, 0x22, 0x57, 0x4b, 0xd3, 0xa9, 0x6a, 0xaa, 0x8c, 0x7d, 0xb8, 0x3b, 0x2e, 0xfa, 0x19, 0xc0, 0x7c, 0x13, 0xca, 0xdb, 0xf8, 0xd0, 0x71, 0x67, 0x82,
0xaf, 0xa6, 0xc6, 0x11, 0x54, 0x9a, 0x5e, 0xaf, 0xe7, 0xd0, 0xab, 0xbe, 0xc3, 0x8c, 0x65, 0xa8, 0xce, 0x78, 0x03, 0x2a, 0x72, 0xb5, 0x34, 0x9d, 0xaa, 0xb4, 0xca, 0xe4, 0x4a, 0x6b, 0x1c, 0x41,
0x46, 0x96, 0x84, 0x9b, 0xc6, 0x67, 0xb0, 0x84, 0xbc, 0x6e, 0xf7, 0xc0, 0x6e, 0x1f, 0x5f, 0xb9, 0xa5, 0xe9, 0xf5, 0x7a, 0x0e, 0xbd, 0xec, 0xfb, 0xcd, 0x58, 0x85, 0x6a, 0x64, 0x49, 0xb8, 0x69,
0x75, 0x1d, 0x96, 0x13, 0x5b, 0xd2, 0xfe, 0x3f, 0x39, 0x58, 0xd9, 0xeb, 0x77, 0x1d, 0x2a, 0x29, 0x7c, 0x06, 0x2b, 0xc8, 0xeb, 0x76, 0x0f, 0xec, 0xf6, 0xf1, 0xa5, 0x5b, 0xd7, 0x61, 0x35, 0xb1,
0x99, 0xc6, 0x85, 0x71, 0x8f, 0x8a, 0x89, 0x3b, 0x1f, 0x76, 0xea, 0x49, 0xe8, 0x87, 0x6c, 0x6e, 0x25, 0xed, 0xff, 0x9b, 0x83, 0x1b, 0x7b, 0xfd, 0xae, 0x43, 0x25, 0x25, 0xb3, 0xb8, 0x30, 0xe9,
0x64, 0xb1, 0xd4, 0xf8, 0x9c, 0x68, 0x6b, 0xc2, 0x07, 0x7d, 0xa4, 0x12, 0xb8, 0x94, 0xa7, 0xa9, 0xc1, 0x31, 0x75, 0x57, 0xc4, 0x4e, 0x3d, 0x09, 0xfd, 0x90, 0x8d, 0x8f, 0x2c, 0x96, 0x1a, 0x9f,
0x8a, 0x40, 0x6a, 0xb0, 0x19, 0xfd, 0x65, 0x58, 0x77, 0x83, 0x9e, 0xe5, 0x7b, 0x5f, 0x10, 0xab, 0x13, 0x2d, 0x4f, 0xf8, 0xd8, 0x8f, 0x54, 0x02, 0x97, 0xf2, 0x34, 0x55, 0x11, 0x48, 0x0d, 0x36,
0xcf, 0x9c, 0xe7, 0x3b, 0x5b, 0x7d, 0xdb, 0xa7, 0xbc, 0xcf, 0x55, 0xd1, 0x2d, 0x26, 0x46, 0x4c, 0xa3, 0xbf, 0x0c, 0xb7, 0xdd, 0xa0, 0x67, 0xf9, 0xde, 0x17, 0xc4, 0xea, 0x33, 0xe7, 0xf9, 0xce,
0xba, 0x8b, 0x7d, 0x6e, 0x7c, 0x97, 0x89, 0xf4, 0xb7, 0xa1, 0x64, 0x77, 0x0f, 0x3d, 0xdf, 0xa1, 0x56, 0xdf, 0xf6, 0x29, 0xef, 0x81, 0x55, 0x74, 0x93, 0x89, 0x11, 0x93, 0xee, 0x62, 0x9f, 0x1b,
0x47, 0x3d, 0xd9, 0xcd, 0x18, 0xd2, 0xcd, 0x53, 0xc8, 0x98, 0xef, 0x44, 0x9a, 0x28, 0x59, 0xa4, 0xdf, 0x65, 0x22, 0xfd, 0x6d, 0x28, 0xd9, 0xdd, 0x43, 0xcf, 0x77, 0xe8, 0x51, 0x4f, 0x76, 0x3a,
0xbf, 0x04, 0x7a, 0x40, 0xb0, 0x25, 0x9c, 0x13, 0x46, 0x07, 0x0d, 0xd9, 0xda, 0x2c, 0x31, 0x49, 0x86, 0x74, 0xf3, 0x14, 0x32, 0xe6, 0x3b, 0x91, 0x26, 0x4a, 0x16, 0xe9, 0x2f, 0x81, 0x1e, 0x10,
0xb2, 0xcd, 0x47, 0x0d, 0xe3, 0x37, 0x15, 0xf4, 0xf4, 0xbe, 0x32, 0x5f, 0x5f, 0x63, 0xd7, 0x44, 0x6c, 0x09, 0xe7, 0x84, 0xd1, 0x41, 0x43, 0xb6, 0x3d, 0x2b, 0x4c, 0x92, 0x6c, 0xf3, 0x51, 0xc3,
0x38, 0x4b, 0x18, 0xde, 0xe1, 0x91, 0xdd, 0x88, 0x69, 0x3c, 0xa5, 0x6b, 0x86, 0x6e, 0x23, 0xa9, 0xf8, 0x5d, 0x05, 0x3d, 0xbd, 0xaf, 0xcc, 0xd7, 0xd7, 0xd8, 0x35, 0x11, 0xce, 0x12, 0x86, 0x77,
0x5e, 0xff, 0x14, 0xca, 0xd1, 0xc1, 0xe3, 0xe1, 0xa4, 0xd9, 0x50, 0xc6, 0xd6, 0x86, 0xdc, 0x04, 0x78, 0x64, 0x37, 0x62, 0x1a, 0x4f, 0xe9, 0x9a, 0xa1, 0xdb, 0x48, 0xaa, 0xd7, 0x3f, 0x85, 0x72,
0xb5, 0xa1, 0xfe, 0x16, 0x94, 0xf8, 0x15, 0x73, 0xee, 0xde, 0xc9, 0x3d, 0x97, 0x4b, 0xdf, 0x73, 0x74, 0xf0, 0x78, 0x38, 0x69, 0x36, 0x94, 0x89, 0xb5, 0x21, 0x37, 0x45, 0x6d, 0xa8, 0xbf, 0x05,
0xf5, 0x3f, 0x15, 0xc8, 0xf3, 0xc5, 0x13, 0x3f, 0x52, 0x3f, 0x80, 0x6a, 0xec, 0xa5, 0x60, 0x4f, 0x25, 0x7e, 0xc5, 0x9c, 0xb9, 0x77, 0x72, 0xcf, 0xe5, 0xd2, 0xf7, 0x5c, 0xfd, 0x2f, 0x05, 0xf2,
0x64, 0xf6, 0xbd, 0x31, 0x90, 0xa4, 0x21, 0x40, 0xe5, 0xe3, 0x34, 0x20, 0x4d, 0x00, 0xf1, 0xaf, 0x7c, 0xf1, 0xd4, 0x0f, 0xd8, 0x0f, 0xa0, 0x1a, 0x7b, 0x29, 0xd8, 0x13, 0x99, 0x7d, 0x6f, 0x02,
0x7b, 0xbe, 0x95, 0xc8, 0xc3, 0xe7, 0xc6, 0x6c, 0x15, 0x87, 0x8b, 0x4a, 0x24, 0x8e, 0x5c, 0x87, 0x24, 0x69, 0x08, 0x50, 0xf9, 0x38, 0x0d, 0x48, 0x13, 0x40, 0xfc, 0xcb, 0x9f, 0x6f, 0x25, 0xf2,
0x3c, 0x71, 0xbe, 0x12, 0xcf, 0x47, 0x15, 0xf1, 0x6f, 0xe3, 0x21, 0xac, 0xbd, 0x87, 0xe9, 0x9e, 0xf0, 0xb9, 0x09, 0x5b, 0xc5, 0xe1, 0xa2, 0x12, 0x89, 0x23, 0xd7, 0x21, 0x4f, 0x9c, 0xaf, 0xc4,
0x3f, 0x88, 0xee, 0x91, 0xe8, 0xf8, 0x8c, 0x81, 0xc9, 0x40, 0x70, 0x3b, 0xbb, 0x48, 0x66, 0xc0, 0xa3, 0x45, 0x45, 0xfc, 0xdb, 0x78, 0x08, 0xeb, 0xef, 0x61, 0xba, 0xe7, 0x0f, 0xa2, 0x7b, 0x24,
0xeb, 0xec, 0x04, 0xf8, 0x03, 0x6b, 0x68, 0xa5, 0xd6, 0x58, 0x4b, 0xe8, 0x49, 0x2f, 0xd2, 0x48, 0x3a, 0x3e, 0x13, 0x60, 0x32, 0x10, 0xdc, 0xca, 0x2e, 0x92, 0x19, 0xf0, 0x3a, 0x3b, 0x01, 0xfe,
0x32, 0xd8, 0xae, 0x43, 0xad, 0xed, 0xf5, 0xcc, 0x13, 0x2f, 0xa0, 0xc1, 0x01, 0x36, 0x07, 0x0e, 0xc0, 0x1a, 0x5a, 0xa9, 0x35, 0xd6, 0x13, 0x7a, 0xd2, 0x8b, 0x34, 0x92, 0x0c, 0xb6, 0xeb, 0x50,
0x65, 0x27, 0x5e, 0xfc, 0xd6, 0x71, 0x50, 0xe0, 0x7f, 0x1e, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff, 0x6b, 0x7b, 0x3d, 0xf3, 0xc4, 0x0b, 0x68, 0x70, 0x80, 0xcd, 0x81, 0x43, 0xd9, 0x89, 0x17, 0xbf,
0xad, 0x6e, 0xed, 0xad, 0x34, 0x19, 0x00, 0x00, 0x91, 0x1c, 0x14, 0xf8, 0x9f, 0x87, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x12, 0x77, 0x8b, 0xc2,
0x6c, 0x19, 0x00, 0x00,
} }

Просмотреть файл

@ -22,6 +22,7 @@ type fakeVTGateService struct {
type queryExecute struct { type queryExecute struct {
SQL string SQL string
BindVariables map[string]interface{} BindVariables map[string]interface{}
Keyspace string
TabletType topodatapb.TabletType TabletType topodatapb.TabletType
Session *vtgatepb.Session Session *vtgatepb.Session
NotInTransaction bool NotInTransaction bool
@ -36,7 +37,7 @@ type queryExecuteSpecificShard struct {
} }
// Execute is part of the VTGateService interface // Execute is part of the VTGateService interface
func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
execCase, ok := execMap[sql] execCase, ok := execMap[sql]
if !ok { if !ok {
return nil, fmt.Errorf("no match for: %s", sql) return nil, fmt.Errorf("no match for: %s", sql)
@ -44,6 +45,7 @@ func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariabl
query := &queryExecute{ query := &queryExecute{
SQL: sql, SQL: sql,
BindVariables: bindVariables, BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType, TabletType: tabletType,
Session: session, Session: session,
NotInTransaction: notInTransaction, NotInTransaction: notInTransaction,
@ -109,7 +111,7 @@ func (f *fakeVTGateService) ExecuteBatchKeyspaceIds(ctx context.Context, queries
} }
// StreamExecute is part of the VTGateService interface // StreamExecute is part of the VTGateService interface
func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
execCase, ok := execMap[sql] execCase, ok := execMap[sql]
if !ok { if !ok {
return fmt.Errorf("no match for: %s", sql) return fmt.Errorf("no match for: %s", sql)
@ -117,6 +119,7 @@ func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindV
query := &queryExecute{ query := &queryExecute{
SQL: sql, SQL: sql,
BindVariables: bindVariables, BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType, TabletType: tabletType,
} }
if !reflect.DeepEqual(query, execCase.execQuery) { if !reflect.DeepEqual(query, execCase.execQuery) {

Просмотреть файл

@ -37,7 +37,7 @@ func (vtg *VTGate) Execute(ctx context.Context, request *vtgatepb.ExecuteRequest
if err != nil { if err != nil {
return nil, vterrors.ToGRPCError(err) return nil, vterrors.ToGRPCError(err)
} }
result, err := vtg.server.Execute(ctx, string(request.Query.Sql), bv, request.TabletType, request.Session, request.NotInTransaction) result, err := vtg.server.Execute(ctx, string(request.Query.Sql), bv, request.Keyspace, request.TabletType, request.Session, request.NotInTransaction)
return &vtgatepb.ExecuteResponse{ return &vtgatepb.ExecuteResponse{
Result: sqltypes.ResultToProto3(result), Result: sqltypes.ResultToProto3(result),
Session: request.Session, Session: request.Session,
@ -196,6 +196,7 @@ func (vtg *VTGate) StreamExecute(request *vtgatepb.StreamExecuteRequest, stream
vtgErr := vtg.server.StreamExecute(ctx, vtgErr := vtg.server.StreamExecute(ctx,
string(request.Query.Sql), string(request.Query.Sql),
bv, bv,
request.Keyspace,
request.TabletType, request.TabletType,
func(value *sqltypes.Result) error { func(value *sqltypes.Result) error {
return stream.Send(&vtgatepb.StreamExecuteResponse{ return stream.Send(&vtgatepb.StreamExecuteResponse{

Просмотреть файл

@ -68,9 +68,15 @@ type builder interface {
SupplyCol(ref colref) int SupplyCol(ref colref) int
} }
// VSchema defines the interface for this package to fetch
// info about tables.
type VSchema interface {
Find(keyspace, tablename string) (table *vindexes.Table, err error)
}
// Build builds a plan for a query based on the specified vschema. // Build builds a plan for a query based on the specified vschema.
// It's the main entry point for this package. // It's the main entry point for this package.
func Build(query string, vschema *vindexes.VSchema) (*engine.Plan, error) { func Build(query string, vschema VSchema) (*engine.Plan, error) {
statement, err := sqlparser.Parse(query) statement, err := sqlparser.Parse(query)
if err != nil { if err != nil {
return nil, err return nil, err

Просмотреть файл

@ -14,15 +14,23 @@ import (
"github.com/youtube/vitess/go/vt/vtgate/vindexes" "github.com/youtube/vitess/go/vt/vtgate/vindexes"
) )
// dmlFormatter strips out keyspace name from dmls.
func dmlFormatter(buf *sqlparser.TrackedBuffer, node sqlparser.SQLNode) {
switch node := node.(type) {
case *sqlparser.TableName:
node.Name.Format(buf)
return
}
node.Format(buf)
}
// buildUpdatePlan builds the instructions for an UPDATE statement. // buildUpdatePlan builds the instructions for an UPDATE statement.
func buildUpdatePlan(upd *sqlparser.Update, vschema *vindexes.VSchema) (*engine.Route, error) { func buildUpdatePlan(upd *sqlparser.Update, vschema VSchema) (*engine.Route, error) {
route := &engine.Route{ route := &engine.Route{
Query: generateQuery(upd), Query: generateQuery(upd),
} }
// We allow only one table in an update.
tablename := sqlparser.GetTableName(upd.Table)
var err error var err error
route.Table, err = vschema.FindTable(tablename) route.Table, err = vschema.Find(string(upd.Table.Qualifier), string(upd.Table.Name))
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -47,7 +55,7 @@ func buildUpdatePlan(upd *sqlparser.Update, vschema *vindexes.VSchema) (*engine.
} }
func generateQuery(statement sqlparser.Statement) string { func generateQuery(statement sqlparser.Statement) string {
buf := sqlparser.NewTrackedBuffer(nil) buf := sqlparser.NewTrackedBuffer(dmlFormatter)
statement.Format(buf) statement.Format(buf)
return buf.String() return buf.String()
} }
@ -68,14 +76,12 @@ func isIndexChanging(setClauses sqlparser.UpdateExprs, colVindexes []*vindexes.C
} }
// buildUpdatePlan builds the instructions for a DELETE statement. // buildUpdatePlan builds the instructions for a DELETE statement.
func buildDeletePlan(del *sqlparser.Delete, vschema *vindexes.VSchema) (*engine.Route, error) { func buildDeletePlan(del *sqlparser.Delete, vschema VSchema) (*engine.Route, error) {
route := &engine.Route{ route := &engine.Route{
Query: generateQuery(del), Query: generateQuery(del),
} }
// We allow only one table in a delete.
tablename := sqlparser.GetTableName(del.Table)
var err error var err error
route.Table, err = vschema.FindTable(tablename) route.Table, err = vschema.Find(string(del.Table.Qualifier), string(del.Table.Name))
if err != nil { if err != nil {
return nil, err return nil, err
} }

Просмотреть файл

@ -13,12 +13,11 @@ import (
"github.com/youtube/vitess/go/vt/vtgate/vindexes" "github.com/youtube/vitess/go/vt/vtgate/vindexes"
) )
// This file has functions to analyze the FROM clause // This file has functions to analyze the FROM clause.
// for select statements.
// processTableExprs analyzes the FROM clause. It produces a builder // processTableExprs analyzes the FROM clause. It produces a builder
// with all the routes identified. // with all the routes identified.
func processTableExprs(tableExprs sqlparser.TableExprs, vschema *vindexes.VSchema) (builder, error) { func processTableExprs(tableExprs sqlparser.TableExprs, vschema VSchema) (builder, error) {
if len(tableExprs) != 1 { if len(tableExprs) != 1 {
return nil, errors.New("unsupported: ',' join operator") return nil, errors.New("unsupported: ',' join operator")
} }
@ -26,7 +25,7 @@ func processTableExprs(tableExprs sqlparser.TableExprs, vschema *vindexes.VSchem
} }
// processTableExpr produces a builder subtree for the given TableExpr. // processTableExpr produces a builder subtree for the given TableExpr.
func processTableExpr(tableExpr sqlparser.TableExpr, vschema *vindexes.VSchema) (builder, error) { func processTableExpr(tableExpr sqlparser.TableExpr, vschema VSchema) (builder, error) {
switch tableExpr := tableExpr.(type) { switch tableExpr := tableExpr.(type) {
case *sqlparser.AliasedTableExpr: case *sqlparser.AliasedTableExpr:
return processAliasedTable(tableExpr, vschema) return processAliasedTable(tableExpr, vschema)
@ -55,7 +54,7 @@ func processTableExpr(tableExpr sqlparser.TableExpr, vschema *vindexes.VSchema)
// vindex columns will be added to the tabsym. // vindex columns will be added to the tabsym.
// A symtab symbol can only point to a route. This means that we canoot // A symtab symbol can only point to a route. This means that we canoot
// support complex joins in subqueries yet. // support complex joins in subqueries yet.
func processAliasedTable(tableExpr *sqlparser.AliasedTableExpr, vschema *vindexes.VSchema) (builder, error) { func processAliasedTable(tableExpr *sqlparser.AliasedTableExpr, vschema VSchema) (builder, error) {
switch expr := tableExpr.Expr.(type) { switch expr := tableExpr.Expr.(type) {
case *sqlparser.TableName: case *sqlparser.TableName:
eroute, table, err := getTablePlan(expr, vschema) eroute, table, err := getTablePlan(expr, vschema)
@ -118,8 +117,8 @@ func processAliasedTable(tableExpr *sqlparser.AliasedTableExpr, vschema *vindexe
// getTablePlan produces the initial engine.Route for the specified TableName. // getTablePlan produces the initial engine.Route for the specified TableName.
// It also returns the associated vschema info (*Table) so that // It also returns the associated vschema info (*Table) so that
// it can be used to create the symbol table entry. // it can be used to create the symbol table entry.
func getTablePlan(tableName *sqlparser.TableName, vschema *vindexes.VSchema) (*engine.Route, *vindexes.Table, error) { func getTablePlan(tableName *sqlparser.TableName, vschema VSchema) (*engine.Route, *vindexes.Table, error) {
table, err := vschema.FindTable(string(tableName.Name)) table, err := vschema.Find(string(tableName.Qualifier), string(tableName.Name))
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
@ -140,7 +139,7 @@ func getTablePlan(tableName *sqlparser.TableName, vschema *vindexes.VSchema) (*e
// processJoin produces a builder subtree for the given Join. // processJoin produces a builder subtree for the given Join.
// If the left and right nodes can be part of the same route, // If the left and right nodes can be part of the same route,
// then it's a route. Otherwise, it's a join. // then it's a route. Otherwise, it's a join.
func processJoin(ajoin *sqlparser.JoinTableExpr, vschema *vindexes.VSchema) (builder, error) { func processJoin(ajoin *sqlparser.JoinTableExpr, vschema VSchema) (builder, error) {
switch ajoin.Join { switch ajoin.Join {
case sqlparser.JoinStr, sqlparser.StraightJoinStr, sqlparser.LeftJoinStr: case sqlparser.JoinStr, sqlparser.StraightJoinStr, sqlparser.LeftJoinStr:
case sqlparser.RightJoinStr: case sqlparser.RightJoinStr:

Просмотреть файл

@ -14,13 +14,12 @@ import (
) )
// buildInsertPlan builds the route for an INSERT statement. // buildInsertPlan builds the route for an INSERT statement.
func buildInsertPlan(ins *sqlparser.Insert, vschema *vindexes.VSchema) (*engine.Route, error) { func buildInsertPlan(ins *sqlparser.Insert, vschema VSchema) (*engine.Route, error) {
route := &engine.Route{ route := &engine.Route{
Query: generateQuery(ins), Query: generateQuery(ins),
} }
tablename := sqlparser.GetTableName(ins.Table)
var err error var err error
route.Table, err = vschema.FindTable(tablename) route.Table, err = vschema.Find(string(ins.Table.Qualifier), string(ins.Table.Name))
if err != nil { if err != nil {
return nil, err return nil, err
} }

Просмотреть файл

@ -36,7 +36,7 @@ type route struct {
ERoute *engine.Route ERoute *engine.Route
} }
func newRoute(from sqlparser.TableExprs, eroute *engine.Route, table *vindexes.Table, vschema *vindexes.VSchema, alias, astName sqlparser.SQLName) *route { func newRoute(from sqlparser.TableExprs, eroute *engine.Route, table *vindexes.Table, vschema VSchema, alias, astName sqlparser.SQLName) *route {
// We have some circular pointer references here: // We have some circular pointer references here:
// The route points to the symtab idicating // The route points to the symtab idicating
// the symtab that should be used to resolve symbols // the symtab that should be used to resolve symbols

Просмотреть файл

@ -13,7 +13,7 @@ import (
) )
// buildSelectPlan is the new function to build a Select plan. // buildSelectPlan is the new function to build a Select plan.
func buildSelectPlan(sel *sqlparser.Select, vschema *vindexes.VSchema) (primitive engine.Primitive, err error) { func buildSelectPlan(sel *sqlparser.Select, vschema VSchema) (primitive engine.Primitive, err error) {
bindvars := getBindvars(sel) bindvars := getBindvars(sel)
builder, err := processSelect(sel, vschema, nil) builder, err := processSelect(sel, vschema, nil)
if err != nil { if err != nil {
@ -43,7 +43,7 @@ func getBindvars(node sqlparser.SQLNode) map[string]struct{} {
} }
// processSelect builds a primitive tree for the given query or subquery. // processSelect builds a primitive tree for the given query or subquery.
func processSelect(sel *sqlparser.Select, vschema *vindexes.VSchema, outer builder) (builder, error) { func processSelect(sel *sqlparser.Select, vschema VSchema, outer builder) (builder, error) {
bldr, err := processTableExprs(sel.From, vschema) bldr, err := processTableExprs(sel.From, vschema)
if err != nil { if err != nil {
return nil, err return nil, err

Просмотреть файл

@ -50,12 +50,12 @@ type symtab struct {
Colsyms []*colsym Colsyms []*colsym
Externs []*sqlparser.ColName Externs []*sqlparser.ColName
Outer *symtab Outer *symtab
VSchema *vindexes.VSchema VSchema VSchema
} }
// newSymtab creates a new symtab initialized // newSymtab creates a new symtab initialized
// to contain the provided table alias. // to contain the provided table alias.
func newSymtab(vschema *vindexes.VSchema) *symtab { func newSymtab(vschema VSchema) *symtab {
return &symtab{ return &symtab{
VSchema: vschema, VSchema: vschema,
} }

Просмотреть файл

@ -45,14 +45,21 @@ func NewPlanner(vschema *vindexes.VSchema, cacheSize int) *Planner {
// GetPlan computes the plan for the given query. If one is in // GetPlan computes the plan for the given query. If one is in
// the cache, it reuses it. // the cache, it reuses it.
func (plr *Planner) GetPlan(sql string) (*engine.Plan, error) { func (plr *Planner) GetPlan(sql, keyspace string) (*engine.Plan, error) {
if plr.vschema == nil { if plr.vschema == nil {
return nil, errors.New("vschema not initialized") return nil, errors.New("vschema not initialized")
} }
if result, ok := plr.plans.Get(sql); ok { key := sql
if keyspace != "" {
key = keyspace + ":" + sql
}
if result, ok := plr.plans.Get(key); ok {
return result.(*engine.Plan), nil return result.(*engine.Plan), nil
} }
plan, err := planbuilder.Build(sql, plr.vschema) plan, err := planbuilder.Build(sql, &wrappedVSchema{
vschema: plr.vschema,
keyspace: keyspace,
})
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -95,3 +102,15 @@ func (plr *Planner) ServeHTTP(response http.ResponseWriter, request *http.Reques
response.WriteHeader(http.StatusNotFound) response.WriteHeader(http.StatusNotFound)
} }
} }
type wrappedVSchema struct {
vschema *vindexes.VSchema
keyspace string
}
func (vs *wrappedVSchema) Find(keyspace, tablename string) (table *vindexes.Table, err error) {
if keyspace == "" {
keyspace = vs.keyspace
}
return vs.vschema.Find(keyspace, tablename)
}

Просмотреть файл

@ -17,17 +17,19 @@ type requestContext struct {
ctx context.Context ctx context.Context
sql string sql string
bindVars map[string]interface{} bindVars map[string]interface{}
keyspace string
tabletType topodatapb.TabletType tabletType topodatapb.TabletType
session *vtgatepb.Session session *vtgatepb.Session
notInTransaction bool notInTransaction bool
router *Router router *Router
} }
func newRequestContext(ctx context.Context, sql string, bindVars map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool, router *Router) *requestContext { func newRequestContext(ctx context.Context, sql string, bindVars map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool, router *Router) *requestContext {
return &requestContext{ return &requestContext{
ctx: ctx, ctx: ctx,
sql: sql, sql: sql,
bindVars: bindVars, bindVars: bindVars,
keyspace: keyspace,
tabletType: tabletType, tabletType: tabletType,
session: session, session: session,
notInTransaction: notInTransaction, notInTransaction: notInTransaction,
@ -36,7 +38,9 @@ func newRequestContext(ctx context.Context, sql string, bindVars map[string]inte
} }
func (vc *requestContext) Execute(query string, bindvars map[string]interface{}) (*sqltypes.Result, error) { func (vc *requestContext) Execute(query string, bindvars map[string]interface{}) (*sqltypes.Result, error) {
return vc.router.Execute(vc.ctx, query, bindvars, vc.tabletType, vc.session, false) // We have to use an empty keyspace here, becasue vindexes that call back can reference
// any table.
return vc.router.Execute(vc.ctx, query, bindvars, "", vc.tabletType, vc.session, false)
} }
func (vc *requestContext) ExecuteRoute(route *engine.Route, joinvars map[string]interface{}) (*sqltypes.Result, error) { func (vc *requestContext) ExecuteRoute(route *engine.Route, joinvars map[string]interface{}) (*sqltypes.Result, error) {

Просмотреть файл

@ -59,12 +59,12 @@ func NewRouter(serv topo.SrvTopoServer, cell string, vschema *vindexes.VSchema,
} }
// Execute routes a non-streaming query. // Execute routes a non-streaming query.
func (rtr *Router) Execute(ctx context.Context, sql string, bindVars map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (rtr *Router) Execute(ctx context.Context, sql string, bindVars map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if bindVars == nil { if bindVars == nil {
bindVars = make(map[string]interface{}) bindVars = make(map[string]interface{})
} }
vcursor := newRequestContext(ctx, sql, bindVars, tabletType, session, notInTransaction, rtr) vcursor := newRequestContext(ctx, sql, bindVars, keyspace, tabletType, session, notInTransaction, rtr)
plan, err := rtr.planner.GetPlan(sql) plan, err := rtr.planner.GetPlan(sql, keyspace)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -72,12 +72,12 @@ func (rtr *Router) Execute(ctx context.Context, sql string, bindVars map[string]
} }
// StreamExecute executes a streaming query. // StreamExecute executes a streaming query.
func (rtr *Router) StreamExecute(ctx context.Context, sql string, bindVars map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (rtr *Router) StreamExecute(ctx context.Context, sql string, bindVars map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if bindVars == nil { if bindVars == nil {
bindVars = make(map[string]interface{}) bindVars = make(map[string]interface{})
} }
vcursor := newRequestContext(ctx, sql, bindVars, tabletType, nil, false, rtr) vcursor := newRequestContext(ctx, sql, bindVars, keyspace, tabletType, nil, false, rtr)
plan, err := rtr.planner.GetPlan(sql) plan, err := rtr.planner.GetPlan(sql, keyspace)
if err != nil { if err != nil {
return err return err
} }

Просмотреть файл

@ -55,7 +55,7 @@ var routerVSchema = createTestVSchema(`
"Type": "numeric" "Type": "numeric"
} }
}, },
"Classes": { "Tables": {
"user": { "user": {
"ColVindexes": [ "ColVindexes": [
{ {
@ -67,10 +67,10 @@ var routerVSchema = createTestVSchema(`
"Name": "name_user_map" "Name": "name_user_map"
} }
], ],
"Autoinc" : { "Autoinc" : {
"Col": "id", "Col": "id",
"Sequence": "user_seq" "Sequence": "user_seq"
} }
}, },
"user_extra": { "user_extra": {
"ColVindexes": [ "ColVindexes": [
@ -91,10 +91,10 @@ var routerVSchema = createTestVSchema(`
"Name": "music_user_map" "Name": "music_user_map"
} }
], ],
"Autoinc" : { "Autoinc" : {
"Col": "id", "Col": "id",
"Sequence": "user_seq" "Sequence": "user_seq"
} }
}, },
"music_extra": { "music_extra": {
"ColVindexes": [ "ColVindexes": [
@ -136,34 +136,22 @@ var routerVSchema = createTestVSchema(`
} }
] ]
} }
},
"Tables": {
"user": "user",
"user_extra": "user_extra",
"music": "music",
"music_extra": "music_extra",
"music_extra_reversed": "music_extra_reversed",
"noauto_table": "noauto_table",
"ksid_table": "ksid_table"
} }
}, },
"TestBadSharding": { "TestBadSharding": {
"Sharded": false, "Sharded": false,
"Tables": { "Tables": {
"sharded_table": "" "sharded_table": {}
} }
}, },
"TestUnsharded": { "TestUnsharded": {
"Sharded": false, "Sharded": false,
"Classes": {
"seq": {
"Type": "Sequence"
}
},
"Tables": { "Tables": {
"user_seq": "seq", "user_seq": {
"music_user_map": "", "Type": "Sequence"
"name_user_map": "" },
"music_user_map": {},
"name_user_map": {}
} }
} }
} }
@ -215,6 +203,7 @@ func routerExec(router *Router, sql string, bv map[string]interface{}) (*sqltype
return router.Execute(context.Background(), return router.Execute(context.Background(),
sql, sql,
bv, bv,
"",
topodatapb.TabletType_MASTER, topodatapb.TabletType_MASTER,
nil, nil,
false) false)
@ -222,7 +211,7 @@ func routerExec(router *Router, sql string, bv map[string]interface{}) (*sqltype
func routerStream(router *Router, sql string) (qr *sqltypes.Result, err error) { func routerStream(router *Router, sql string) (qr *sqltypes.Result, err error) {
results := make(chan *sqltypes.Result, 10) results := make(chan *sqltypes.Result, 10)
err = router.StreamExecute(context.Background(), sql, nil, topodatapb.TabletType_MASTER, func(qr *sqltypes.Result) error { err = router.StreamExecute(context.Background(), sql, nil, "", topodatapb.TabletType_MASTER, func(qr *sqltypes.Result) error {
results <- qr results <- qr
return nil return nil
}) })

Просмотреть файл

@ -6,7 +6,6 @@ package vindexes
import ( import (
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"sort" "sort"
@ -48,8 +47,8 @@ type ColVindex struct {
// KeyspaceSchema contains the schema(table) for a keyspace. // KeyspaceSchema contains the schema(table) for a keyspace.
type KeyspaceSchema struct { type KeyspaceSchema struct {
Sharded bool Keyspace *Keyspace
Tables map[string]*Table Tables map[string]*Table
} }
// Autoinc contains the auto-inc information for a table. // Autoinc contains the auto-inc information for a table.
@ -67,67 +66,58 @@ func BuildVSchema(source *VSchemaFormal) (vschema *VSchema, err error) {
tables: make(map[string]*Table), tables: make(map[string]*Table),
Keyspaces: make(map[string]*KeyspaceSchema), Keyspaces: make(map[string]*KeyspaceSchema),
} }
keyspaces := buildKeyspaces(source, vschema) buildKeyspaces(source, vschema)
// We have to build the sequences first to avoid // We have to build the sequences first to avoid
// forward reference errors. // forward reference errors.
err = buildSequences(source, vschema, keyspaces) err = buildSequences(source, vschema)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = buildTables(source, vschema, keyspaces) err = buildTables(source, vschema)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return vschema, nil return vschema, nil
} }
func buildKeyspaces(source *VSchemaFormal, vschema *VSchema) map[string]*Keyspace { func buildKeyspaces(source *VSchemaFormal, vschema *VSchema) {
k := make(map[string]*Keyspace)
for ksname, ks := range source.Keyspaces { for ksname, ks := range source.Keyspaces {
k[ksname] = &Keyspace{
Name: ksname,
Sharded: ks.Sharded,
}
vschema.Keyspaces[ksname] = &KeyspaceSchema{ vschema.Keyspaces[ksname] = &KeyspaceSchema{
Sharded: ks.Sharded, Keyspace: &Keyspace{
Tables: make(map[string]*Table), Name: ksname,
Sharded: ks.Sharded,
},
Tables: make(map[string]*Table),
} }
} }
return k
} }
func buildSequences(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*Keyspace) error { func buildSequences(source *VSchemaFormal, vschema *VSchema) error {
for ksname, ks := range source.Keyspaces { for ksname, ks := range source.Keyspaces {
keyspace := keyspaces[ksname] keyspace := vschema.Keyspaces[ksname].Keyspace
for tname, cname := range ks.Tables { for tname, table := range ks.Tables {
if cname == "" { if table.Type != "Sequence" {
continue continue
} }
class, ok := ks.Classes[cname] t := &Table{
if !ok { Name: tname,
return fmt.Errorf("class %s not found for table %s", cname, tname) Keyspace: keyspace,
IsSequence: true,
} }
if class.Type == "Sequence" { if _, ok := vschema.tables[tname]; ok {
t := &Table{ vschema.tables[tname] = nil
Name: tname, } else {
Keyspace: keyspace, vschema.tables[tname] = t
IsSequence: true,
}
if _, ok := vschema.tables[tname]; ok {
vschema.tables[tname] = nil
} else {
vschema.tables[tname] = t
}
vschema.Keyspaces[ksname].Tables[tname] = t
} }
vschema.Keyspaces[ksname].Tables[tname] = t
} }
} }
return nil return nil
} }
func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*Keyspace) error { func buildTables(source *VSchemaFormal, vschema *VSchema) error {
for ksname, ks := range source.Keyspaces { for ksname, ks := range source.Keyspaces {
keyspace := keyspaces[ksname] keyspace := vschema.Keyspaces[ksname].Keyspace
vindexes := make(map[string]Vindex) vindexes := make(map[string]Vindex)
for vname, vindexInfo := range ks.Vindexes { for vname, vindexInfo := range ks.Vindexes {
vindex, err := CreateVindex(vindexInfo.Type, vname, vindexInfo.Params) vindex, err := CreateVindex(vindexInfo.Type, vname, vindexInfo.Params)
@ -142,12 +132,8 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
} }
vindexes[vname] = vindex vindexes[vname] = vindex
} }
for tname, cname := range ks.Tables { for tname, table := range ks.Tables {
class, ok := ks.Classes[cname] if table.Type == "Sequence" {
if !ok && cname != "" {
return fmt.Errorf("class %s not found for table %s", cname, tname)
}
if class.Type == "Sequence" {
continue continue
} }
t := &Table{ t := &Table{
@ -163,10 +149,10 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
if !keyspace.Sharded { if !keyspace.Sharded {
continue continue
} }
for i, ind := range class.ColVindexes { for i, ind := range table.ColVindexes {
vindexInfo, ok := ks.Vindexes[ind.Name] vindexInfo, ok := ks.Vindexes[ind.Name]
if !ok { if !ok {
return fmt.Errorf("vindex %s not found for class %s", ind.Name, cname) return fmt.Errorf("vindex %s not found for table %s", ind.Name, tname)
} }
vindex := vindexes[ind.Name] vindex := vindexes[ind.Name]
owned := false owned := false
@ -183,10 +169,10 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
if i == 0 { if i == 0 {
// Perform Primary vindex check. // Perform Primary vindex check.
if _, ok := columnVindex.Vindex.(Unique); !ok { if _, ok := columnVindex.Vindex.(Unique); !ok {
return fmt.Errorf("primary vindex %s is not Unique for class %s", ind.Name, cname) return fmt.Errorf("primary vindex %s is not Unique for table %s", ind.Name, tname)
} }
if owned { if owned {
return fmt.Errorf("primary vindex %s cannot be owned for class %s", ind.Name, cname) return fmt.Errorf("primary vindex %s cannot be owned for table %s", ind.Name, tname)
} }
} }
t.ColVindexes = append(t.ColVindexes, columnVindex) t.ColVindexes = append(t.ColVindexes, columnVindex)
@ -195,11 +181,11 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
} }
} }
t.Ordered = colVindexSorted(t.ColVindexes) t.Ordered = colVindexSorted(t.ColVindexes)
if class.Autoinc != nil { if table.Autoinc != nil {
t.Autoinc = &Autoinc{Col: class.Autoinc.Col, ColVindexNum: -1} t.Autoinc = &Autoinc{Col: table.Autoinc.Col, ColVindexNum: -1}
seq, ok := vschema.tables[class.Autoinc.Sequence] seq, ok := vschema.tables[table.Autoinc.Sequence]
if !ok { if !ok {
return fmt.Errorf("sequence %s not found for class %s", class.Autoinc.Sequence, cname) return fmt.Errorf("sequence %s not found for table %s", table.Autoinc.Sequence, tname)
} }
t.Autoinc.Sequence = seq t.Autoinc.Sequence = seq
for i, cv := range t.ColVindexes { for i, cv := range t.ColVindexes {
@ -214,18 +200,43 @@ func buildTables(source *VSchemaFormal, vschema *VSchema, keyspaces map[string]*
return nil return nil
} }
// FindTable returns a pointer to the Table if found. // Find returns a pointer to the Table. If a keyspace is specified, only tables
// Otherwise, it returns a reason, which is equivalent to an error. // from that keyspace are searched. If the specified keyspace is unsharded
func (vschema *VSchema) FindTable(tablename string) (table *Table, err error) { // and no tables matched, it's considered valid: Find will construct a table
if tablename == "" { // of that name and return it. If no kesypace is specified, then a table is returned
return nil, errors.New("unsupported: compex table expression in DML") // only if its name is unique across all keyspaces. If there is only one
} // keyspace in the vschema, and it's unsharded, then all table requests are considered
table, ok := vschema.tables[tablename] // valid and belonging to that keyspace.
if table == nil { func (vschema *VSchema) Find(keyspace, tablename string) (table *Table, err error) {
if ok { if keyspace == "" {
return nil, fmt.Errorf("ambiguous table reference: %s", tablename) table, ok := vschema.tables[tablename]
if table == nil {
if ok {
return nil, fmt.Errorf("ambiguous table reference: %s", tablename)
}
if len(vschema.Keyspaces) != 1 {
return nil, fmt.Errorf("table %s not found", tablename)
}
// Loop happens only once.
for _, ks := range vschema.Keyspaces {
if ks.Keyspace.Sharded {
return nil, fmt.Errorf("table %s not found", tablename)
}
return &Table{Name: tablename, Keyspace: ks.Keyspace}, nil
}
} }
return nil, fmt.Errorf("table %s not found", tablename) return table, nil
}
ks, ok := vschema.Keyspaces[keyspace]
if !ok {
return nil, fmt.Errorf("keyspace %s not found in vschema", keyspace)
}
table = ks.Tables[tablename]
if table == nil {
if ks.Keyspace.Sharded {
return nil, fmt.Errorf("table %s not found", tablename)
}
return &Table{Name: tablename, Keyspace: ks.Keyspace}, nil
} }
return table, nil return table, nil
} }
@ -257,8 +268,7 @@ type VSchemaFormal struct {
type KeyspaceFormal struct { type KeyspaceFormal struct {
Sharded bool Sharded bool
Vindexes map[string]VindexFormal Vindexes map[string]VindexFormal
Classes map[string]ClassFormal Tables map[string]TableFormal
Tables map[string]string
} }
// VindexFormal is the info for each index as loaded from // VindexFormal is the info for each index as loaded from
@ -269,9 +279,9 @@ type VindexFormal struct {
Owner string Owner string
} }
// ClassFormal is the info for each table class as loaded from // TableFormal is the info for each table as loaded from
// the source. // the source.
type ClassFormal struct { type TableFormal struct {
Type string Type string
ColVindexes []ColVindexFormal ColVindexes []ColVindexFormal
Autoinc *AutoincFormal Autoinc *AutoincFormal

Просмотреть файл

@ -85,8 +85,8 @@ func TestUnshardedVSchema(t *testing.T) {
good := VSchemaFormal{ good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{ Keyspaces: map[string]KeyspaceFormal{
"unsharded": { "unsharded": {
Tables: map[string]string{ Tables: map[string]TableFormal{
"t1": "", "t1": {},
}, },
}, },
}, },
@ -95,11 +95,12 @@ func TestUnshardedVSchema(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
ks := &Keyspace{
Name: "unsharded",
}
t1 := &Table{ t1 := &Table{
Name: "t1", Name: "t1",
Keyspace: &Keyspace{ Keyspace: ks,
Name: "unsharded",
},
} }
want := &VSchema{ want := &VSchema{
tables: map[string]*Table{ tables: map[string]*Table{
@ -107,6 +108,7 @@ func TestUnshardedVSchema(t *testing.T) {
}, },
Keyspaces: map[string]*KeyspaceSchema{ Keyspaces: map[string]*KeyspaceSchema{
"unsharded": { "unsharded": {
Keyspace: ks,
Tables: map[string]*Table{ Tables: map[string]*Table{
"t1": t1, "t1": t1,
}, },
@ -136,7 +138,7 @@ func TestShardedVSchemaOwned(t *testing.T) {
Owner: "t1", Owner: "t1",
}, },
}, },
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
ColVindexes: []ColVindexFormal{ ColVindexes: []ColVindexFormal{
{ {
@ -149,9 +151,6 @@ func TestShardedVSchemaOwned(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
@ -159,12 +158,13 @@ func TestShardedVSchemaOwned(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
ks := &Keyspace{
Name: "sharded",
Sharded: true,
}
t1 := &Table{ t1 := &Table{
Name: "t1", Name: "t1",
Keyspace: &Keyspace{ Keyspace: ks,
Name: "sharded",
Sharded: true,
},
ColVindexes: []*ColVindex{ ColVindexes: []*ColVindex{
{ {
Col: "c1", Col: "c1",
@ -197,7 +197,7 @@ func TestShardedVSchemaOwned(t *testing.T) {
}, },
Keyspaces: map[string]*KeyspaceSchema{ Keyspaces: map[string]*KeyspaceSchema{
"sharded": { "sharded": {
Sharded: true, Keyspace: ks,
Tables: map[string]*Table{ Tables: map[string]*Table{
"t1": t1, "t1": t1,
}, },
@ -226,7 +226,7 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
Owner: "", Owner: "",
}, },
}, },
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
ColVindexes: []ColVindexFormal{ ColVindexes: []ColVindexFormal{
{ {
@ -239,9 +239,6 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
@ -249,12 +246,13 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
ks := &Keyspace{
Name: "sharded",
Sharded: true,
}
t1 := &Table{ t1 := &Table{
Name: "t1", Name: "t1",
Keyspace: &Keyspace{ Keyspace: ks,
Name: "sharded",
Sharded: true,
},
ColVindexes: []*ColVindex{ ColVindexes: []*ColVindex{
{ {
Col: "c1", Col: "c1",
@ -282,7 +280,7 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
}, },
Keyspaces: map[string]*KeyspaceSchema{ Keyspaces: map[string]*KeyspaceSchema{
"sharded": { "sharded": {
Sharded: true, Keyspace: ks,
Tables: map[string]*Table{ Tables: map[string]*Table{
"t1": t1, "t1": t1,
}, },
@ -308,39 +306,6 @@ func TestLoadVSchemaFail(t *testing.T) {
} }
} }
func TestBuildVSchemaClassNotFoundFail(t *testing.T) {
bad := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"sharded": {
Sharded: true,
Vindexes: map[string]VindexFormal{
"stfu": {
Type: "stfu",
},
},
Classes: map[string]ClassFormal{
"notexist": {
ColVindexes: []ColVindexFormal{
{
Col: "c1",
Name: "noexist",
},
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, err := BuildVSchema(&bad)
want := "class t1 not found for table t1"
if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
}
func TestBuildVSchemaVindexNotFoundFail(t *testing.T) { func TestBuildVSchemaVindexNotFoundFail(t *testing.T) {
bad := VSchemaFormal{ bad := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{ Keyspaces: map[string]KeyspaceFormal{
@ -351,7 +316,7 @@ func TestBuildVSchemaVindexNotFoundFail(t *testing.T) {
Type: "noexist", Type: "noexist",
}, },
}, },
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
ColVindexes: []ColVindexFormal{ ColVindexes: []ColVindexFormal{
{ {
@ -361,9 +326,6 @@ func TestBuildVSchemaVindexNotFoundFail(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
@ -384,7 +346,7 @@ func TestBuildVSchemaInvalidVindexFail(t *testing.T) {
Type: "stf", Type: "stf",
}, },
}, },
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
ColVindexes: []ColVindexFormal{ ColVindexes: []ColVindexFormal{
{ {
@ -394,9 +356,6 @@ func TestBuildVSchemaInvalidVindexFail(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
@ -411,40 +370,36 @@ func TestBuildVSchemaDupSeq(t *testing.T) {
good := VSchemaFormal{ good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{ Keyspaces: map[string]KeyspaceFormal{
"ksa": { "ksa": {
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"seq": { "t1": {
Type: "Sequence", Type: "Sequence",
}, },
}, },
Tables: map[string]string{
"t1": "seq",
},
}, },
"ksb": { "ksb": {
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"seq": { "t1": {
Type: "Sequence", Type: "Sequence",
}, },
}, },
Tables: map[string]string{
"t1": "seq",
},
}, },
}, },
} }
ksa := &Keyspace{
Name: "ksa",
}
ksb := &Keyspace{
Name: "ksb",
}
got, _ := BuildVSchema(&good) got, _ := BuildVSchema(&good)
t1a := &Table{ t1a := &Table{
Name: "t1", Name: "t1",
Keyspace: &Keyspace{ Keyspace: ksa,
Name: "ksa",
},
IsSequence: true, IsSequence: true,
} }
t1b := &Table{ t1b := &Table{
Name: "t1", Name: "t1",
Keyspace: &Keyspace{ Keyspace: ksb,
Name: "ksb",
},
IsSequence: true, IsSequence: true,
} }
want := &VSchema{ want := &VSchema{
@ -453,11 +408,13 @@ func TestBuildVSchemaDupSeq(t *testing.T) {
}, },
Keyspaces: map[string]*KeyspaceSchema{ Keyspaces: map[string]*KeyspaceSchema{
"ksa": { "ksa": {
Keyspace: ksa,
Tables: map[string]*Table{ Tables: map[string]*Table{
"t1": t1a, "t1": t1a,
}, },
}, },
"ksb": { "ksb": {
Keyspace: ksb,
Tables: map[string]*Table{ Tables: map[string]*Table{
"t1": t1b, "t1": t1b,
}, },
@ -475,29 +432,31 @@ func TestBuildVSchemaDupTable(t *testing.T) {
good := VSchemaFormal{ good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{ Keyspaces: map[string]KeyspaceFormal{
"ksa": { "ksa": {
Tables: map[string]string{ Tables: map[string]TableFormal{
"t1": "", "t1": {},
}, },
}, },
"ksb": { "ksb": {
Tables: map[string]string{ Tables: map[string]TableFormal{
"t1": "", "t1": {},
}, },
}, },
}, },
} }
got, _ := BuildVSchema(&good) got, _ := BuildVSchema(&good)
ksa := &Keyspace{
Name: "ksa",
}
t1a := &Table{ t1a := &Table{
Name: "t1", Name: "t1",
Keyspace: &Keyspace{ Keyspace: ksa,
Name: "ksa", }
}, ksb := &Keyspace{
Name: "ksb",
} }
t1b := &Table{ t1b := &Table{
Name: "t1", Name: "t1",
Keyspace: &Keyspace{ Keyspace: ksb,
Name: "ksb",
},
} }
want := &VSchema{ want := &VSchema{
tables: map[string]*Table{ tables: map[string]*Table{
@ -505,11 +464,13 @@ func TestBuildVSchemaDupTable(t *testing.T) {
}, },
Keyspaces: map[string]*KeyspaceSchema{ Keyspaces: map[string]*KeyspaceSchema{
"ksa": { "ksa": {
Keyspace: ksa,
Tables: map[string]*Table{ Tables: map[string]*Table{
"t1": t1a, "t1": t1a,
}, },
}, },
"ksb": { "ksb": {
Keyspace: ksb,
Tables: map[string]*Table{ Tables: map[string]*Table{
"t1": t1b, "t1": t1b,
}, },
@ -533,7 +494,7 @@ func TestBuildVSchemaNoindexFail(t *testing.T) {
Type: "stfu", Type: "stfu",
}, },
}, },
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
ColVindexes: []ColVindexFormal{ ColVindexes: []ColVindexFormal{
{ {
@ -543,14 +504,11 @@ func TestBuildVSchemaNoindexFail(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
_, err := BuildVSchema(&bad) _, err := BuildVSchema(&bad)
want := "vindex notexist not found for class t1" want := "vindex notexist not found for table t1"
if err == nil || err.Error() != want { if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want) t.Errorf("BuildVSchema: %v, want %v", err, want)
} }
@ -566,7 +524,7 @@ func TestBuildVSchemaNotUniqueFail(t *testing.T) {
Type: "stln", Type: "stln",
}, },
}, },
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
ColVindexes: []ColVindexFormal{ ColVindexes: []ColVindexFormal{
{ {
@ -576,14 +534,11 @@ func TestBuildVSchemaNotUniqueFail(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
_, err := BuildVSchema(&bad) _, err := BuildVSchema(&bad)
want := "primary vindex stln is not Unique for class t1" want := "primary vindex stln is not Unique for table t1"
if err == nil || err.Error() != want { if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want) t.Errorf("BuildVSchema: %v, want %v", err, want)
} }
@ -600,7 +555,7 @@ func TestBuildVSchemaPrimaryNonFunctionalFail(t *testing.T) {
Owner: "t1", Owner: "t1",
}, },
}, },
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
ColVindexes: []ColVindexFormal{ ColVindexes: []ColVindexFormal{
{ {
@ -610,14 +565,11 @@ func TestBuildVSchemaPrimaryNonFunctionalFail(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
_, err := BuildVSchema(&bad) _, err := BuildVSchema(&bad)
want := "primary vindex stlu cannot be owned for class t1" want := "primary vindex stlu cannot be owned for table t1"
if err == nil || err.Error() != want { if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want) t.Errorf("BuildVSchema: %v, want %v", err, want)
} }
@ -627,14 +579,11 @@ func TestSequence(t *testing.T) {
good := VSchemaFormal{ good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{ Keyspaces: map[string]KeyspaceFormal{
"unsharded": { "unsharded": {
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"seq": { "seq": {
Type: "Sequence", Type: "Sequence",
}, },
}, },
Tables: map[string]string{
"seq": "seq",
},
}, },
"sharded": { "sharded": {
Sharded: true, Sharded: true,
@ -646,7 +595,7 @@ func TestSequence(t *testing.T) {
}, },
}, },
}, },
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
ColVindexes: []ColVindexFormal{ ColVindexes: []ColVindexFormal{
{ {
@ -660,9 +609,6 @@ func TestSequence(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
@ -670,19 +616,21 @@ func TestSequence(t *testing.T) {
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
ksu := &Keyspace{
Name: "unsharded",
}
kss := &Keyspace{
Name: "sharded",
Sharded: true,
}
seq := &Table{ seq := &Table{
Name: "seq", Name: "seq",
Keyspace: &Keyspace{ Keyspace: ksu,
Name: "unsharded",
},
IsSequence: true, IsSequence: true,
} }
t1 := &Table{ t1 := &Table{
Name: "t1", Name: "t1",
Keyspace: &Keyspace{ Keyspace: kss,
Name: "sharded",
Sharded: true,
},
ColVindexes: []*ColVindex{ ColVindexes: []*ColVindex{
{ {
Col: "c1", Col: "c1",
@ -711,12 +659,13 @@ func TestSequence(t *testing.T) {
}, },
Keyspaces: map[string]*KeyspaceSchema{ Keyspaces: map[string]*KeyspaceSchema{
"unsharded": { "unsharded": {
Keyspace: ksu,
Tables: map[string]*Table{ Tables: map[string]*Table{
"seq": seq, "seq": seq,
}, },
}, },
"sharded": { "sharded": {
Sharded: true, Keyspace: kss,
Tables: map[string]*Table{ Tables: map[string]*Table{
"t1": t1, "t1": t1,
}, },
@ -735,7 +684,7 @@ func TestBadSequence(t *testing.T) {
Keyspaces: map[string]KeyspaceFormal{ Keyspaces: map[string]KeyspaceFormal{
"sharded": { "sharded": {
Sharded: true, Sharded: true,
Classes: map[string]ClassFormal{ Tables: map[string]TableFormal{
"t1": { "t1": {
Autoinc: &AutoincFormal{ Autoinc: &AutoincFormal{
Col: "c1", Col: "c1",
@ -743,14 +692,11 @@ func TestBadSequence(t *testing.T) {
}, },
}, },
}, },
Tables: map[string]string{
"t1": "t1",
},
}, },
}, },
} }
_, err := BuildVSchema(&bad) _, err := BuildVSchema(&bad)
want := "sequence seq not found for class t1" want := "sequence seq not found for table t1"
if err == nil || err.Error() != want { if err == nil || err.Error() != want {
t.Errorf("BuildVSchema: %v, want %v", err, want) t.Errorf("BuildVSchema: %v, want %v", err, want)
} }
@ -760,47 +706,108 @@ func TestFind(t *testing.T) {
input := VSchemaFormal{ input := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{ Keyspaces: map[string]KeyspaceFormal{
"ksa": { "ksa": {
Tables: map[string]string{ Tables: map[string]TableFormal{
"ta": "", "ta": {},
"t1": "", "t1": {},
}, },
}, },
"ksb": { "ksb": {
Tables: map[string]string{ Sharded: true,
"tb": "", Tables: map[string]TableFormal{
"t1": "", "tb": {},
"t1": {},
}, },
}, },
}, },
} }
vschema, _ := BuildVSchema(&input) vschema, _ := BuildVSchema(&input)
_, err := vschema.FindTable("") _, err := vschema.Find("", "t1")
wantErr := "unsupported: compex table expression in DML" wantErr := "ambiguous table reference: t1"
if err == nil || err.Error() != wantErr { if err == nil || err.Error() != wantErr {
t.Errorf("FindTable(\"\"): %v, want %s", err, wantErr) t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
} }
_, err = vschema.FindTable("t1") _, err = vschema.Find("", "none")
wantErr = "ambiguous table reference: t1"
if err == nil || err.Error() != wantErr {
t.Errorf("FindTable(\"\"): %v, want %s", err, wantErr)
}
_, err = vschema.FindTable("none")
wantErr = "table none not found" wantErr = "table none not found"
if err == nil || err.Error() != wantErr { if err == nil || err.Error() != wantErr {
t.Errorf("FindTable(\"\"): %v, want %s", err, wantErr) t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
} }
got, err := vschema.FindTable("ta") got, err := vschema.Find("", "ta")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
return return
} }
want := &Table{ ta := &Table{
Name: "ta", Name: "ta",
Keyspace: &Keyspace{ Keyspace: &Keyspace{
Name: "ksa", Name: "ksa",
}, },
} }
if !reflect.DeepEqual(got, want) { if !reflect.DeepEqual(got, ta) {
t.Errorf("FindTable(\"t1a\"): %+v, want %+v", got, want) t.Errorf("Find(\"t1a\"): %+v, want %+v", got, ta)
}
got, err = vschema.Find("ksa", "ta")
if !reflect.DeepEqual(got, ta) {
t.Errorf("Find(\"t1a\"): %+v, want %+v", got, ta)
}
none := &Table{
Name: "none",
Keyspace: &Keyspace{
Name: "ksa",
},
}
got, err = vschema.Find("ksa", "none")
if !reflect.DeepEqual(got, none) {
t.Errorf("Find(\"t1a\"): %+v, want %+v", got, none)
}
_, err = vschema.Find("ksb", "none")
wantErr = "table none not found"
if err == nil || err.Error() != wantErr {
t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
}
_, err = vschema.Find("none", "aa")
wantErr = "keyspace none not found in vschema"
if err == nil || err.Error() != wantErr {
t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
}
}
func TestFindSingleKeyspace(t *testing.T) {
input := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"ksa": {
Tables: map[string]TableFormal{
"ta": {},
"t1": {},
},
},
},
}
vschema, _ := BuildVSchema(&input)
none := &Table{
Name: "none",
Keyspace: &Keyspace{
Name: "ksa",
},
}
got, _ := vschema.Find("", "none")
if !reflect.DeepEqual(got, none) {
t.Errorf("Find(\"t1a\"): %+v, want %+v", got, none)
}
input = VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"ksb": {
Sharded: true,
Tables: map[string]TableFormal{
"tb": {},
"t1": {},
},
},
},
}
vschema, _ = BuildVSchema(&input)
_, err := vschema.Find("", "none")
wantErr := "table none not found"
if err == nil || err.Error() != wantErr {
t.Errorf("Find(\"\"): %v, want %s", err, wantErr)
} }
} }

Просмотреть файл

@ -157,7 +157,7 @@ func (vtg *VTGate) InitializeConnections(ctx context.Context) (err error) {
} }
// Execute executes a non-streaming query by routing based on the values in the query. // Execute executes a non-streaming query by routing based on the values in the query.
func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
startTime := time.Now() startTime := time.Now()
statsKey := []string{"Execute", "Any", strings.ToLower(tabletType.String())} statsKey := []string{"Execute", "Any", strings.ToLower(tabletType.String())}
defer vtg.timings.Record(statsKey, startTime) defer vtg.timings.Record(statsKey, startTime)
@ -168,7 +168,7 @@ func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[st
return nil, errTooManyInFlight return nil, errTooManyInFlight
} }
qr, err := vtg.router.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction) qr, err := vtg.router.Execute(ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
if err == nil { if err == nil {
vtg.rowsReturned.Add(statsKey, int64(len(qr.Rows))) vtg.rowsReturned.Add(statsKey, int64(len(qr.Rows)))
return qr, nil return qr, nil
@ -177,6 +177,7 @@ func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[st
query := map[string]interface{}{ query := map[string]interface{}{
"Sql": sql, "Sql": sql,
"BindVariables": bindVariables, "BindVariables": bindVariables,
"Keyspace": keyspace,
"TabletType": strings.ToLower(tabletType.String()), "TabletType": strings.ToLower(tabletType.String()),
"Session": session, "Session": session,
"NotInTransaction": notInTransaction, "NotInTransaction": notInTransaction,
@ -410,7 +411,7 @@ func (vtg *VTGate) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtgat
} }
// StreamExecute executes a streaming query by routing based on the values in the query. // StreamExecute executes a streaming query by routing based on the values in the query.
func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
startTime := time.Now() startTime := time.Now()
statsKey := []string{"StreamExecute", "Any", strings.ToLower(tabletType.String())} statsKey := []string{"StreamExecute", "Any", strings.ToLower(tabletType.String())}
defer vtg.timings.Record(statsKey, startTime) defer vtg.timings.Record(statsKey, startTime)
@ -426,6 +427,7 @@ func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables
ctx, ctx,
sql, sql,
bindVariables, bindVariables,
keyspace,
tabletType, tabletType,
func(reply *sqltypes.Result) error { func(reply *sqltypes.Result) error {
rowCount += int64(len(reply.Rows)) rowCount += int64(len(reply.Rows))
@ -438,6 +440,7 @@ func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables
query := map[string]interface{}{ query := map[string]interface{}{
"Sql": sql, "Sql": sql,
"BindVariables": bindVariables, "BindVariables": bindVariables,
"Keyspace": keyspace,
"TabletType": strings.ToLower(tabletType.String()), "TabletType": strings.ToLower(tabletType.String()),
} }
logError(err, query, vtg.logStreamExecute) logError(err, query, vtg.logStreamExecute)

Просмотреть файл

@ -35,7 +35,7 @@ func init() {
"TestUnsharded": { "TestUnsharded": {
"Sharded": false, "Sharded": false,
"Tables": { "Tables": {
"t1": "" "t1": {}
} }
} }
} }
@ -51,6 +51,7 @@ func TestVTGateExecute(t *testing.T) {
qr, err := rpcVTGate.Execute(context.Background(), qr, err := rpcVTGate.Execute(context.Background(),
"select id from t1", "select id from t1",
nil, nil,
"",
topodatapb.TabletType_MASTER, topodatapb.TabletType_MASTER,
nil, nil,
false) false)
@ -68,6 +69,7 @@ func TestVTGateExecute(t *testing.T) {
rpcVTGate.Execute(context.Background(), rpcVTGate.Execute(context.Background(),
"select id from t1", "select id from t1",
nil, nil,
"",
topodatapb.TabletType_MASTER, topodatapb.TabletType_MASTER,
session, session,
false) false)
@ -95,12 +97,43 @@ func TestVTGateExecute(t *testing.T) {
rpcVTGate.Execute(context.Background(), rpcVTGate.Execute(context.Background(),
"select id from t1", "select id from t1",
nil, nil,
"",
topodatapb.TabletType_MASTER, topodatapb.TabletType_MASTER,
session, session,
false) false)
rpcVTGate.Rollback(context.Background(), session) rpcVTGate.Rollback(context.Background(), session)
} }
func TestVTGateExecuteWithKeyspace(t *testing.T) {
sandbox := createSandbox(KsTestUnsharded)
sbc := &sandboxConn{}
sandbox.MapTestConn("0", sbc)
qr, err := rpcVTGate.Execute(context.Background(),
"select id from none",
nil,
KsTestUnsharded,
topodatapb.TabletType_MASTER,
nil,
false)
if err != nil {
t.Errorf("want nil, got %v", err)
}
if !reflect.DeepEqual(singleRowResult, qr) {
t.Errorf("want \n%+v, got \n%+v", singleRowResult, qr)
}
_, err = rpcVTGate.Execute(context.Background(),
"select id from none",
nil,
"aa",
topodatapb.TabletType_MASTER,
nil,
false)
want := "keyspace aa not found in vschema"
if err == nil || err.Error() != want {
t.Errorf("Execute: %v, want %s", err, want)
}
}
func TestVTGateExecuteShards(t *testing.T) { func TestVTGateExecuteShards(t *testing.T) {
sandbox := createSandbox("TestVTGateExecuteShards") sandbox := createSandbox("TestVTGateExecuteShards")
sbc := &sandboxConn{} sbc := &sandboxConn{}
@ -532,6 +565,7 @@ func TestVTGateStreamExecute(t *testing.T) {
err := rpcVTGate.StreamExecute(context.Background(), err := rpcVTGate.StreamExecute(context.Background(),
"select id from t1", "select id from t1",
nil, nil,
"",
topodatapb.TabletType_MASTER, topodatapb.TabletType_MASTER,
func(r *sqltypes.Result) error { func(r *sqltypes.Result) error {
qrs = append(qrs, r) qrs = append(qrs, r)

Просмотреть файл

@ -74,13 +74,14 @@ func (f *fakeVTGateService) checkCallerID(ctx context.Context, name string) {
type queryExecute struct { type queryExecute struct {
SQL string SQL string
BindVariables map[string]interface{} BindVariables map[string]interface{}
Keyspace string
TabletType topodatapb.TabletType TabletType topodatapb.TabletType
Session *vtgatepb.Session Session *vtgatepb.Session
NotInTransaction bool NotInTransaction bool
} }
// Execute is part of the VTGateService interface // Execute is part of the VTGateService interface
func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) { func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) {
if f.hasError { if f.hasError {
return nil, errTestVtGateError return nil, errTestVtGateError
} }
@ -95,6 +96,7 @@ func (f *fakeVTGateService) Execute(ctx context.Context, sql string, bindVariabl
query := &queryExecute{ query := &queryExecute{
SQL: sql, SQL: sql,
BindVariables: bindVariables, BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType, TabletType: tabletType,
Session: session, Session: session,
NotInTransaction: notInTransaction, NotInTransaction: notInTransaction,
@ -370,7 +372,7 @@ func (f *fakeVTGateService) ExecuteBatchKeyspaceIds(ctx context.Context, queries
} }
// StreamExecute is part of the VTGateService interface // StreamExecute is part of the VTGateService interface
func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error { func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error {
if f.panics { if f.panics {
panic(fmt.Errorf("test forced panic")) panic(fmt.Errorf("test forced panic"))
} }
@ -382,6 +384,7 @@ func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindV
query := &queryExecute{ query := &queryExecute{
SQL: sql, SQL: sql,
BindVariables: bindVariables, BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType, TabletType: tabletType,
} }
if !reflect.DeepEqual(query, execCase.execQuery) { if !reflect.DeepEqual(query, execCase.execQuery) {

Просмотреть файл

@ -20,7 +20,7 @@ import (
type VTGateService interface { type VTGateService interface {
// Regular query execution. // Regular query execution.
// All these methods can change the provided session. // All these methods can change the provided session.
Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
ExecuteKeyspaceIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyspaceIds [][]byte, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) ExecuteKeyspaceIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyspaceIds [][]byte, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
ExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*topodatapb.KeyRange, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error) ExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*topodatapb.KeyRange, tabletType topodatapb.TabletType, session *vtgatepb.Session, notInTransaction bool) (*sqltypes.Result, error)
@ -29,7 +29,7 @@ type VTGateService interface {
ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtgatepb.BoundKeyspaceIdQuery, tabletType topodatapb.TabletType, asTransaction bool, session *vtgatepb.Session) ([]sqltypes.Result, error) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtgatepb.BoundKeyspaceIdQuery, tabletType topodatapb.TabletType, asTransaction bool, session *vtgatepb.Session) ([]sqltypes.Result, error)
// Streaming queries // Streaming queries
StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error
StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error
StreamExecuteKeyspaceIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyspaceIds [][]byte, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error StreamExecuteKeyspaceIds(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyspaceIds [][]byte, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error
StreamExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*topodatapb.KeyRange, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error StreamExecuteKeyRanges(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, keyRanges []*topodatapb.KeyRange, tabletType topodatapb.TabletType, sendReply func(*sqltypes.Result) error) error

Просмотреть файл

@ -33,15 +33,15 @@ func (_m *MockVTGateService) EXPECT() *_MockVTGateServiceRecorder {
return _m.recorder return _m.recorder
} }
func (_m *MockVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) { func (_m *MockVTGateService) Execute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) {
ret := _m.ctrl.Call(_m, "Execute", ctx, sql, bindVariables, tabletType, session, notInTransaction) ret := _m.ctrl.Call(_m, "Execute", ctx, sql, bindVariables, keyspace, tabletType, session, notInTransaction)
ret0, _ := ret[0].(*sqltypes.Result) ret0, _ := ret[0].(*sqltypes.Result)
ret1, _ := ret[1].(error) ret1, _ := ret[1].(error)
return ret0, ret1 return ret0, ret1
} }
func (_mr *_MockVTGateServiceRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call { func (_mr *_MockVTGateServiceRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5, arg6 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Execute", arg0, arg1, arg2, arg3, arg4, arg5) return _mr.mock.ctrl.RecordCall(_mr.mock, "Execute", arg0, arg1, arg2, arg3, arg4, arg5, arg6)
} }
func (_m *MockVTGateService) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) { func (_m *MockVTGateService) ExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodata.TabletType, session *vtgate.Session, notInTransaction bool) (*sqltypes.Result, error) {
@ -110,14 +110,14 @@ func (_mr *_MockVTGateServiceRecorder) ExecuteBatchKeyspaceIds(arg0, arg1, arg2,
return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteBatchKeyspaceIds", arg0, arg1, arg2, arg3, arg4) return _mr.mock.ctrl.RecordCall(_mr.mock, "ExecuteBatchKeyspaceIds", arg0, arg1, arg2, arg3, arg4)
} }
func (_m *MockVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, tabletType topodata.TabletType, sendReply func(*sqltypes.Result) error) error { func (_m *MockVTGateService) StreamExecute(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, tabletType topodata.TabletType, sendReply func(*sqltypes.Result) error) error {
ret := _m.ctrl.Call(_m, "StreamExecute", ctx, sql, bindVariables, tabletType, sendReply) ret := _m.ctrl.Call(_m, "StreamExecute", ctx, sql, bindVariables, keyspace, tabletType, sendReply)
ret0, _ := ret[0].(error) ret0, _ := ret[0].(error)
return ret0 return ret0
} }
func (_mr *_MockVTGateServiceRecorder) StreamExecute(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call { func (_mr *_MockVTGateServiceRecorder) StreamExecute(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamExecute", arg0, arg1, arg2, arg3, arg4) return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamExecute", arg0, arg1, arg2, arg3, arg4, arg5)
} }
func (_m *MockVTGateService) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodata.TabletType, sendReply func(*sqltypes.Result) error) error { func (_m *MockVTGateService) StreamExecuteShards(ctx context.Context, sql string, bindVariables map[string]interface{}, keyspace string, shards []string, tabletType topodata.TabletType, sendReply func(*sqltypes.Result) error) error {

Просмотреть файл

@ -41,6 +41,9 @@ message ExecuteRequest {
// not_in_transaction is deprecated and should not be used. // not_in_transaction is deprecated and should not be used.
bool not_in_transaction = 5; bool not_in_transaction = 5;
// keyspace to target the query to.
string keyspace = 6;
} }
// ExecuteResponse is the returned value from Execute. // ExecuteResponse is the returned value from Execute.
@ -345,6 +348,9 @@ message StreamExecuteRequest {
// tablet_type is the type of tablets that this query is targeted to. // tablet_type is the type of tablets that this query is targeted to.
topodata.TabletType tablet_type = 3; topodata.TabletType tablet_type = 3;
// keyspace to target the query to.
string keyspace = 4;
} }
// StreamExecuteResponse is the returned value from StreamExecute. // StreamExecuteResponse is the returned value from StreamExecute.

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

Просмотреть файл

@ -126,7 +126,7 @@ vschema = '''{
"Owner": "vt_music" "Owner": "vt_music"
} }
}, },
"Classes": { "Tables": {
"vt_user": { "vt_user": {
"ColVindexes": [ "ColVindexes": [
{ {
@ -203,29 +203,19 @@ vschema = '''{
} }
] ]
} }
},
"Tables": {
"vt_user": "vt_user",
"vt_user2": "vt_user2",
"vt_user_extra": "vt_user_extra",
"vt_music": "vt_music",
"vt_music_extra": "vt_music_extra",
"join_user": "join_user",
"join_user_extra": "join_user_extra"
} }
}, },
"lookup": { "lookup": {
"Sharded": false, "Sharded": false,
"Classes" : {
"seq": {
"Type": "Sequence"
}
},
"Tables": { "Tables": {
"vt_user_seq": "seq", "vt_user_seq": {
"vt_music_seq": "seq", "Type": "Sequence"
"music_user_map": "", },
"name_user2_map": "" "vt_music_seq": {
"Type": "Sequence"
},
"music_user_map": {},
"name_user2_map": {}
} }
} }
} }