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"
"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 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
"select user.id from user join user"
"duplicate symbol: user"

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

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

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

@ -146,10 +146,6 @@
"delete from user where col = (select id from main1)"
"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 user set val = 1"
"unsupported: multi-shard where clause in DML"

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

@ -28,7 +28,7 @@
"Type": "numeric"
}
},
"Classes": {
"Tables": {
"user": {
"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": {
"Sharded": false,
"Classes": {
"seq": {
"Type": "Sequence"
}
},
"Tables": {
"user_seq": "seq",
"music_seq": "seq",
"name_user_idx": ""
"user_seq": {
"Type": "Sequence"
},
"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")
}
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 {
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) {
@ -118,11 +118,11 @@ func (c *callerIDClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []
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 {
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 {

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

@ -86,18 +86,19 @@ func echoQueryResult(vals map[string]interface{}) *sqltypes.Result {
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) {
return echoQueryResult(map[string]interface{}{
"callerId": callerid.EffectiveCallerIDFromContext(ctx),
"query": sql,
"bindVars": bindVariables,
"keyspace": keyspace,
"tabletType": tabletType,
"session": session,
"notInTransaction": notInTransaction,
}), 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) {
@ -205,17 +206,18 @@ func (c *echoClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vtg
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) {
sendReply(echoQueryResult(map[string]interface{}{
"callerId": callerid.EffectiveCallerIDFromContext(ctx),
"query": sql,
"bindVars": bindVariables,
"keyspace": keyspace,
"tabletType": tabletType,
}))
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 {

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

@ -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 {
return nil, err
}
if err := requestToError(sql); err != nil {
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) {
@ -192,11 +192,11 @@ func (c *errorClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*vt
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 {
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 {

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

@ -27,8 +27,8 @@ func newFallbackClient(fallback vtgateservice.VTGateService) fallbackClient {
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) {
return c.fallback.Execute(ctx, sql, bindVariables, tabletType, session, notInTransaction)
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, 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) {
@ -55,8 +55,8 @@ func (c fallbackClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []*
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 {
return c.fallback.StreamExecute(ctx, sql, bindVariables, tabletType, sendReply)
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, 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 {

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

@ -29,7 +29,7 @@ func newTerminalClient() *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://" {
log.Fatal("Received quit:// query. Going down.")
}
@ -60,7 +60,7 @@ func (c *terminalClient) ExecuteBatchKeyspaceIds(ctx context.Context, queries []
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
}

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

@ -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"`
// 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"`
// keyspace to target the query to.
Keyspace string `protobuf:"bytes,6,opt,name=keyspace" json:"keyspace,omitempty"`
}
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"`
// 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"`
// keyspace to target the query to.
Keyspace string `protobuf:"bytes,4,opt,name=keyspace" json:"keyspace,omitempty"`
}
func (m *StreamExecuteRequest) Reset() { *m = StreamExecuteRequest{} }
@ -1376,87 +1380,88 @@ func init() {
}
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,
0x14, 0x97, 0xe3, 0x34, 0x69, 0x9e, 0x93, 0xb4, 0xf5, 0xb6, 0xdb, 0x10, 0x96, 0x6d, 0xb1, 0x40,
0x5b, 0x60, 0x65, 0x69, 0xb3, 0xfc, 0x13, 0x42, 0x02, 0x1a, 0x2a, 0x14, 0x2d, 0xac, 0xca, 0xb4,
0x42, 0x1c, 0x40, 0x96, 0x9b, 0x8c, 0x5a, 0xd3, 0xc4, 0x0e, 0x9e, 0x71, 0xa0, 0x1c, 0xb8, 0x21,
0x71, 0xdb, 0x13, 0x12, 0x42, 0x5c, 0x90, 0xf8, 0x02, 0x7c, 0x04, 0x4e, 0x1c, 0x39, 0x70, 0xe0,
0xc6, 0x47, 0x80, 0x23, 0x17, 0x0e, 0x8c, 0x67, 0xc6, 0x7f, 0xe2, 0x36, 0x69, 0x9a, 0xb4, 0x55,
0x7a, 0xaa, 0x67, 0xde, 0x9b, 0x79, 0xef, 0xfd, 0x7e, 0x6f, 0xde, 0xcc, 0x6b, 0xa0, 0x3c, 0xa0,
0x87, 0x36, 0xc5, 0x66, 0xdf, 0xf7, 0xa8, 0xa7, 0x17, 0xc4, 0xa8, 0xae, 0x7d, 0x1e, 0x60, 0xff,
0x44, 0x4c, 0xd6, 0xab, 0xd4, 0xeb, 0x7b, 0x1d, 0x9b, 0xda, 0x72, 0xac, 0x0d, 0xa8, 0xdf, 0x6f,
0x8b, 0x81, 0xf1, 0x87, 0x02, 0xc5, 0x3d, 0x4c, 0x88, 0xe3, 0xb9, 0xfa, 0xf3, 0x50, 0x75, 0x5c,
0x8b, 0xfa, 0xb6, 0x4b, 0xec, 0x36, 0x65, 0x33, 0x35, 0x65, 0x53, 0xd9, 0x5a, 0x44, 0x15, 0xc7,
0xdd, 0x4f, 0x26, 0xf5, 0x26, 0x54, 0xc9, 0x91, 0xed, 0x77, 0x2c, 0x22, 0xd6, 0x91, 0x5a, 0x6e,
0x53, 0xdd, 0xd2, 0x1a, 0x77, 0x4c, 0xe9, 0x8b, 0xdc, 0xcf, 0xdc, 0x0b, 0xb5, 0xe4, 0x00, 0x55,
0x48, 0x6a, 0x44, 0xea, 0x9f, 0x40, 0x39, 0x2d, 0x66, 0xb6, 0x0b, 0xd4, 0xf6, 0x0f, 0x31, 0xe5,
0x36, 0xb5, 0x46, 0xc5, 0x14, 0x21, 0xec, 0xf3, 0x49, 0x24, 0x85, 0xa1, 0x8b, 0x29, 0xff, 0x2c,
0xa7, 0xc3, 0x6c, 0x2b, 0x5b, 0x2a, 0xaa, 0xa4, 0x66, 0x5b, 0x1d, 0xe3, 0x5f, 0x05, 0xaa, 0x3b,
0x5f, 0xe2, 0x76, 0x40, 0x31, 0xc2, 0x6c, 0x23, 0x42, 0xf5, 0xfb, 0x50, 0x6a, 0xdb, 0xdd, 0x2e,
0xf6, 0xc3, 0x45, 0xc2, 0xc6, 0x92, 0x29, 0x90, 0x68, 0xf2, 0xf9, 0xd6, 0xbb, 0x68, 0x51, 0x68,
0xb4, 0x3a, 0xfa, 0x0b, 0x50, 0x94, 0xd1, 0x71, 0x03, 0x42, 0x37, 0x1d, 0x1c, 0x8a, 0xe4, 0xfa,
0x3d, 0x58, 0xe0, 0xae, 0xd6, 0x54, 0xae, 0xb8, 0x22, 0x1d, 0xdf, 0xf6, 0x02, 0xb7, 0xf3, 0x61,
0x14, 0x97, 0xe3, 0x34, 0x69, 0x9e, 0x93, 0xb4, 0xeb, 0x6d, 0x77, 0x43, 0x58, 0xb6, 0xc5, 0x02,
0x6d, 0x81, 0x95, 0xa5, 0xcd, 0xf2, 0x4f, 0x08, 0x09, 0x68, 0xa8, 0x50, 0xb4, 0xb0, 0x2a, 0xd3,
0x0a, 0x71, 0x00, 0x59, 0x6e, 0x32, 0x6a, 0x4d, 0x13, 0x3b, 0x78, 0xc6, 0x81, 0x72, 0xe0, 0x86,
0xc4, 0x6d, 0x0f, 0x08, 0x09, 0x21, 0x2e, 0x7c, 0x04, 0xbe, 0x01, 0x9c, 0x38, 0x72, 0xe0, 0xc0,
0x8d, 0x8f, 0x00, 0x5f, 0x80, 0x03, 0xe3, 0x99, 0xf1, 0x9f, 0xb8, 0x49, 0x9a, 0x26, 0x6d, 0x95,
0x9e, 0xea, 0x99, 0xf7, 0x66, 0xde, 0x7b, 0xbf, 0xdf, 0x9b, 0x37, 0xf3, 0x1a, 0x28, 0x0f, 0xe8,
0xa1, 0x4d, 0xb1, 0xd9, 0xf7, 0x3d, 0xea, 0xe9, 0x05, 0x31, 0xaa, 0x6b, 0x9f, 0x07, 0xd8, 0x3f,
0x11, 0x93, 0xf5, 0x2a, 0xf5, 0xfa, 0x5e, 0xc7, 0xa6, 0xb6, 0x1c, 0x6b, 0x03, 0xea, 0xf7, 0xdb,
0x62, 0x60, 0xfc, 0xa9, 0x40, 0x71, 0x0f, 0x13, 0xe2, 0x78, 0xae, 0xfe, 0x3c, 0x54, 0x1d, 0xd7,
0xa2, 0xbe, 0xed, 0x12, 0xbb, 0x4d, 0xd9, 0x4c, 0x4d, 0xd9, 0x54, 0xb6, 0x96, 0x51, 0xc5, 0x71,
0xf7, 0x93, 0x49, 0xbd, 0x09, 0x55, 0x72, 0x64, 0xfb, 0x1d, 0x8b, 0x88, 0x75, 0xa4, 0x96, 0xdb,
0x54, 0xb7, 0xb4, 0xc6, 0x1d, 0x53, 0xfa, 0x22, 0xf7, 0x33, 0xf7, 0x42, 0x2d, 0x39, 0x40, 0x15,
0x92, 0x1a, 0x91, 0xfa, 0x27, 0x50, 0x4e, 0x8b, 0x99, 0xed, 0x02, 0xb5, 0xfd, 0x43, 0x4c, 0xb9,
0x4d, 0xad, 0x51, 0x31, 0x45, 0x08, 0xfb, 0x7c, 0x12, 0x49, 0x61, 0xe8, 0x62, 0xca, 0x3f, 0xcb,
0xe9, 0x30, 0xdb, 0xca, 0x96, 0x8a, 0x2a, 0xa9, 0xd9, 0x56, 0xc7, 0xf8, 0x2e, 0x07, 0xd5, 0x9d,
0x2f, 0x71, 0x3b, 0xa0, 0x18, 0x61, 0xb6, 0x11, 0xa1, 0xfa, 0x7d, 0x28, 0xb5, 0xed, 0x6e, 0x17,
0xfb, 0xe1, 0x22, 0x61, 0x63, 0xc5, 0x14, 0x48, 0x34, 0xf9, 0x7c, 0xeb, 0x5d, 0xb4, 0x2c, 0x34,
0x5a, 0x1d, 0xfd, 0x05, 0x28, 0xca, 0xe8, 0xb8, 0x01, 0xa1, 0x9b, 0x0e, 0x0e, 0x45, 0x72, 0xfd,
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,
0xf2, 0x4c, 0xbd, 0xda, 0x58, 0x35, 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,
0xc7, 0x78, 0xa2, 0xc0, 0x52, 0x1c, 0x39, 0xe9, 0x33, 0xa8, 0x31, 0x03, 0x6d, 0x01, 0xfb, 0xbe,
0xe7, 0x67, 0xc2, 0x46, 0xbb, 0xcd, 0x9d, 0x70, 0x1a, 0x09, 0xe9, 0x45, 0x62, 0x7e, 0x11, 0x0a,
0x3e, 0x26, 0x41, 0x97, 0xca, 0xa0, 0x75, 0x19, 0xb4, 0x88, 0x97, 0x4b, 0x90, 0xd4, 0x30, 0x7e,
0xc9, 0xc1, 0xaa, 0xf4, 0x88, 0x33, 0x4e, 0xe6, 0x87, 0x91, 0x3a, 0x2c, 0x1e, 0xe3, 0x13, 0xd2,
0xb7, 0xdb, 0x82, 0x8e, 0x12, 0x8a, 0xc7, 0xfa, 0x6d, 0x28, 0xf0, 0x8c, 0x25, 0x0c, 0x6a, 0x95,
0x49, 0xe4, 0x28, 0xcb, 0x62, 0x61, 0x26, 0x16, 0x8b, 0x23, 0x58, 0xfc, 0x4e, 0x81, 0xb5, 0x0c,
0x66, 0x73, 0xc1, 0xe5, 0xaf, 0x39, 0x78, 0x4a, 0xfa, 0xf5, 0x48, 0x02, 0xd5, 0xba, 0x29, 0x84,
0x3e, 0x0b, 0xe5, 0xe8, 0x9b, 0xf9, 0x27, 0x68, 0x2d, 0x23, 0xed, 0x38, 0x89, 0xe3, 0x7a, 0xb8,
0xfd, 0x41, 0x81, 0xfa, 0x59, 0x18, 0xce, 0x05, 0xc1, 0xbf, 0xe7, 0x60, 0x3d, 0x71, 0x0e, 0xd9,
0xee, 0x21, 0xbe, 0x21, 0xf4, 0x3e, 0x00, 0x60, 0xdf, 0x96, 0xcf, 0x5d, 0xe6, 0xe4, 0x86, 0x91,
0xc6, 0xd4, 0x45, 0xd1, 0xa0, 0xd2, 0x71, 0x14, 0xd7, 0xf5, 0xd0, 0xfd, 0xbd, 0x02, 0xb5, 0xd3,
0x88, 0xce, 0x05, 0xd9, 0xdf, 0xe6, 0x63, 0xb2, 0x77, 0x5c, 0xea, 0xd0, 0x93, 0x1b, 0x73, 0x96,
0x19, 0x05, 0x98, 0x7b, 0x6c, 0xb5, 0xbd, 0x6e, 0xd0, 0x73, 0x2d, 0xd7, 0xee, 0x61, 0x7e, 0x27,
0x96, 0xd0, 0xb2, 0x90, 0x34, 0xb9, 0xe0, 0x31, 0x9b, 0xd7, 0x3f, 0x86, 0x5b, 0x52, 0x7b, 0xa8,
0x00, 0x14, 0x78, 0x8e, 0x6c, 0x45, 0x9e, 0x8e, 0x40, 0xc2, 0x8c, 0x26, 0xd0, 0x8a, 0xd8, 0xe4,
0xd1, 0xe8, 0x82, 0x51, 0x9c, 0x29, 0x83, 0x16, 0xcf, 0xce, 0xa0, 0xfa, 0x01, 0x2c, 0x46, 0x3e,
0xe8, 0x1b, 0x90, 0xe7, 0x96, 0x14, 0x6e, 0x49, 0x8b, 0x1e, 0x49, 0xa1, 0x01, 0x2e, 0xd0, 0x57,
0x61, 0x61, 0x60, 0x77, 0x03, 0xcc, 0x79, 0x28, 0x23, 0x31, 0x60, 0xcb, 0xb4, 0x54, 0xe8, 0x1c,
0xfa, 0x32, 0x82, 0xa4, 0xf4, 0xa5, 0xb3, 0x34, 0x05, 0xc0, 0x5c, 0x64, 0xa9, 0x0b, 0x4b, 0x3c,
0x39, 0xf8, 0x45, 0xc8, 0x15, 0x92, 0x1c, 0x52, 0x2e, 0x90, 0x43, 0xb9, 0x91, 0x17, 0xbc, 0x9a,
0xbe, 0xe0, 0x8d, 0x6f, 0x92, 0x3b, 0x6e, 0xdb, 0xa6, 0xed, 0xa3, 0x6b, 0x7a, 0xb4, 0x3c, 0x80,
0x62, 0xe8, 0xb3, 0x83, 0x85, 0x3f, 0x5a, 0x63, 0x3d, 0x52, 0xcd, 0x44, 0x8f, 0x22, 0xbd, 0x69,
0x1f, 0x94, 0xec, 0x0d, 0x6d, 0x93, 0x33, 0x1e, 0x93, 0x15, 0x9b, 0xa4, 0x0b, 0xd7, 0x8f, 0xc9,
0x3d, 0x35, 0x84, 0xc3, 0x95, 0x25, 0xc5, 0x7d, 0x28, 0x0a, 0xca, 0x23, 0x04, 0xce, 0xca, 0x8a,
0x48, 0xc5, 0xf8, 0x1a, 0x56, 0x39, 0x30, 0xc9, 0x71, 0xbc, 0xc4, 0xdc, 0xc8, 0xbe, 0x15, 0xd4,
0x53, 0x6f, 0x05, 0xe3, 0x49, 0x0e, 0xee, 0xa6, 0xe1, 0xb9, 0xce, 0xf7, 0xd0, 0xab, 0xd9, 0x5c,
0xb9, 0x33, 0x94, 0x2b, 0x19, 0x48, 0xae, 0x2b, 0x61, 0x7e, 0x52, 0x60, 0x63, 0x24, 0x22, 0x73,
0x92, 0x35, 0x3f, 0x2b, 0xb0, 0xba, 0x47, 0x7d, 0x6c, 0xf7, 0x66, 0x6a, 0x0f, 0xe3, 0x24, 0xcb,
0x5d, 0xac, 0xe7, 0x53, 0x27, 0x43, 0xdc, 0x68, 0xc2, 0x5a, 0xc6, 0x4b, 0x89, 0x5f, 0x52, 0x38,
0x95, 0x73, 0x0b, 0xe7, 0x5f, 0xec, 0x00, 0x0f, 0xed, 0x32, 0x4b, 0x25, 0x9b, 0x38, 0xe2, 0xf4,
0xb1, 0x52, 0x47, 0x96, 0xdc, 0xfc, 0xb8, 0x9e, 0x6a, 0x61, 0x42, 0x94, 0x5a, 0xf0, 0xf4, 0x99,
0xf1, 0x4d, 0x81, 0xd5, 0xdf, 0x2c, 0x77, 0x87, 0xf6, 0x9a, 0xf9, 0x38, 0x5f, 0x0a, 0x60, 0xd9,
0x3a, 0x94, 0x3f, 0xb7, 0x67, 0x99, 0x14, 0xbb, 0xc7, 0xb0, 0x39, 0x3a, 0xde, 0x29, 0x00, 0xfc,
0x4f, 0x81, 0x67, 0xb2, 0x1b, 0xce, 0xd2, 0x3e, 0x5c, 0x0a, 0x7c, 0xc3, 0x3d, 0x41, 0x7e, 0x8a,
0x9e, 0x60, 0x52, 0x38, 0xdf, 0x87, 0xbb, 0xa3, 0xa2, 0x9f, 0x02, 0xcc, 0x37, 0xa1, 0xbc, 0x8d,
0x0f, 0x1d, 0x77, 0x2a, 0xe8, 0x8c, 0x37, 0xa0, 0x22, 0x57, 0x4b, 0xd3, 0xa9, 0x6a, 0xaa, 0x8c,
0xaf, 0xa6, 0xc6, 0x11, 0x54, 0x9a, 0x5e, 0xaf, 0xe7, 0xd0, 0xab, 0xbe, 0xc3, 0x8c, 0x65, 0xa8,
0x46, 0x96, 0x84, 0x9b, 0xc6, 0x67, 0xb0, 0x84, 0xbc, 0x6e, 0xf7, 0xc0, 0x6e, 0x1f, 0x5f, 0xb9,
0x75, 0x1d, 0x96, 0x13, 0x5b, 0xd2, 0xfe, 0x3f, 0x39, 0x58, 0xd9, 0xeb, 0x77, 0x1d, 0x2a, 0x29,
0x99, 0xc6, 0x85, 0x71, 0x8f, 0x8a, 0x89, 0x3b, 0x1f, 0x76, 0xea, 0x49, 0xe8, 0x87, 0x6c, 0x6e,
0x64, 0xb1, 0xd4, 0xf8, 0x9c, 0x68, 0x6b, 0xc2, 0x07, 0x7d, 0xa4, 0x12, 0xb8, 0x94, 0xa7, 0xa9,
0x8a, 0x40, 0x6a, 0xb0, 0x19, 0xfd, 0x65, 0x58, 0x77, 0x83, 0x9e, 0xe5, 0x7b, 0x5f, 0x10, 0xab,
0xcf, 0x9c, 0xe7, 0x3b, 0x5b, 0x7d, 0xdb, 0xa7, 0xbc, 0xcf, 0x55, 0xd1, 0x2d, 0x26, 0x46, 0x4c,
0xba, 0x8b, 0x7d, 0x6e, 0x7c, 0x97, 0x89, 0xf4, 0xb7, 0xa1, 0x64, 0x77, 0x0f, 0x3d, 0xdf, 0xa1,
0x47, 0x3d, 0xd9, 0xcd, 0x18, 0xd2, 0xcd, 0x53, 0xc8, 0x98, 0xef, 0x44, 0x9a, 0x28, 0x59, 0xa4,
0xbf, 0x04, 0x7a, 0x40, 0xb0, 0x25, 0x9c, 0x13, 0x46, 0x07, 0x0d, 0xd9, 0xda, 0x2c, 0x31, 0x49,
0xb2, 0xcd, 0x47, 0x0d, 0xe3, 0x37, 0x15, 0xf4, 0xf4, 0xbe, 0x32, 0x5f, 0x5f, 0x63, 0xd7, 0x44,
0x38, 0x4b, 0x18, 0xde, 0xe1, 0x91, 0xdd, 0x88, 0x69, 0x3c, 0xa5, 0x6b, 0x86, 0x6e, 0x23, 0xa9,
0x5e, 0xff, 0x14, 0xca, 0xd1, 0xc1, 0xe3, 0xe1, 0xa4, 0xd9, 0x50, 0xc6, 0xd6, 0x86, 0xdc, 0x04,
0xb5, 0xa1, 0xfe, 0x16, 0x94, 0xf8, 0x15, 0x73, 0xee, 0xde, 0xc9, 0x3d, 0x97, 0x4b, 0xdf, 0x73,
0xf5, 0x3f, 0x15, 0xc8, 0xf3, 0xc5, 0x13, 0x3f, 0x52, 0x3f, 0x80, 0x6a, 0xec, 0xa5, 0x60, 0x4f,
0x64, 0xf6, 0xbd, 0x31, 0x90, 0xa4, 0x21, 0x40, 0xe5, 0xe3, 0x34, 0x20, 0x4d, 0x00, 0xf1, 0xaf,
0x7b, 0xbe, 0x95, 0xc8, 0xc3, 0xe7, 0xc6, 0x6c, 0x15, 0x87, 0x8b, 0x4a, 0x24, 0x8e, 0x5c, 0x87,
0x3c, 0x71, 0xbe, 0x12, 0xcf, 0x47, 0x15, 0xf1, 0x6f, 0xe3, 0x21, 0xac, 0xbd, 0x87, 0xe9, 0x9e,
0x3f, 0x88, 0xee, 0x91, 0xe8, 0xf8, 0x8c, 0x81, 0xc9, 0x40, 0x70, 0x3b, 0xbb, 0x48, 0x66, 0xc0,
0xeb, 0xec, 0x04, 0xf8, 0x03, 0x6b, 0x68, 0xa5, 0xd6, 0x58, 0x4b, 0xe8, 0x49, 0x2f, 0xd2, 0x48,
0x32, 0xd8, 0xae, 0x43, 0xad, 0xed, 0xf5, 0xcc, 0x13, 0x2f, 0xa0, 0xc1, 0x01, 0x36, 0x07, 0x0e,
0x65, 0x27, 0x5e, 0xfc, 0xd6, 0x71, 0x50, 0xe0, 0x7f, 0x1e, 0xfe, 0x1f, 0x00, 0x00, 0xff, 0xff,
0xad, 0x6e, 0xed, 0xad, 0x34, 0x19, 0x00, 0x00,
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, 0x71, 0x66, 0x56, 0x99, 0xa4, 0x35, 0x44,
0x4e, 0x1d, 0x96, 0x8f, 0xf1, 0x09, 0xe9, 0xdb, 0x6d, 0x5c, 0x2b, 0x30, 0x9d, 0x12, 0x8a, 0xc7,
0xc6, 0x13, 0x05, 0x56, 0x62, 0x54, 0x48, 0x9f, 0xd1, 0x80, 0x19, 0xa0, 0x4b, 0xd8, 0xf7, 0x3d,
0x3f, 0x03, 0x09, 0xda, 0x6d, 0xee, 0x84, 0xd3, 0x48, 0x48, 0xcf, 0x83, 0xc7, 0x8b, 0x50, 0xf0,
0x31, 0x09, 0xba, 0x54, 0x02, 0xa2, 0x4b, 0x40, 0x04, 0x16, 0x5c, 0x82, 0xa4, 0x86, 0xf1, 0x4b,
0x0e, 0xd6, 0xa4, 0x47, 0x3c, 0x1b, 0xc8, 0xe2, 0xb0, 0x95, 0x06, 0x32, 0x3f, 0x0c, 0xa4, 0x7e,
0x0b, 0x0a, 0x3c, 0x9b, 0x09, 0xa3, 0x41, 0x65, 0x12, 0x39, 0xca, 0x32, 0x5c, 0x98, 0x8b, 0xe1,
0xe2, 0x68, 0x86, 0x8d, 0xef, 0x15, 0x58, 0xcf, 0x60, 0xb6, 0x10, 0x5c, 0xfe, 0x96, 0x83, 0xa7,
0xa4, 0x5f, 0x8f, 0x24, 0x50, 0xad, 0xeb, 0x42, 0xe8, 0xb3, 0x50, 0x8e, 0xbe, 0x99, 0x7f, 0x82,
0xd6, 0x32, 0xd2, 0x8e, 0x93, 0x38, 0xae, 0x86, 0xdb, 0x1f, 0x15, 0xa8, 0x8f, 0xc2, 0x70, 0x21,
0x08, 0xfe, 0x23, 0x07, 0xb7, 0x13, 0xe7, 0x90, 0xed, 0x1e, 0xe2, 0x6b, 0x42, 0xef, 0x03, 0x00,
0xf6, 0x6d, 0xf9, 0xdc, 0x65, 0x4e, 0x6e, 0x18, 0x69, 0x4c, 0x5d, 0x14, 0x0d, 0x2a, 0x1d, 0x47,
0x71, 0x5d, 0x0d, 0xdd, 0x3f, 0x28, 0x50, 0x3b, 0x8d, 0xe8, 0x42, 0x90, 0xfd, 0x6d, 0x3e, 0x26,
0x7b, 0xc7, 0xa5, 0x0e, 0x3d, 0xb9, 0x36, 0x67, 0x99, 0x51, 0x80, 0xb9, 0xc7, 0x56, 0xdb, 0xeb,
0x06, 0x3d, 0xd7, 0x72, 0xed, 0x1e, 0xe6, 0xf7, 0x65, 0x09, 0xad, 0x0a, 0x49, 0x93, 0x0b, 0x1e,
0xb3, 0x79, 0xfd, 0x63, 0xb8, 0x29, 0xb5, 0x87, 0x0a, 0x40, 0x81, 0xe7, 0xc8, 0x56, 0xe4, 0xe9,
0x18, 0x24, 0xcc, 0x68, 0x02, 0xdd, 0x10, 0x9b, 0x3c, 0x1a, 0x5f, 0x30, 0x8a, 0x73, 0x65, 0xd0,
0xf2, 0xe8, 0x0c, 0xaa, 0x1f, 0xc0, 0x72, 0xe4, 0x83, 0xbe, 0x01, 0x79, 0x6e, 0x49, 0xe1, 0x96,
0xb4, 0xe8, 0x01, 0x15, 0x1a, 0xe0, 0x02, 0x7d, 0x0d, 0x96, 0x06, 0x76, 0x37, 0xc0, 0x9c, 0x87,
0x32, 0x12, 0x03, 0xb6, 0x4c, 0x4b, 0x85, 0xce, 0xa1, 0x2f, 0x23, 0x48, 0x4a, 0x5f, 0x3a, 0x4b,
0x53, 0x00, 0x2c, 0x44, 0x96, 0xba, 0xb0, 0xc2, 0x93, 0x83, 0x5f, 0x84, 0x5c, 0x21, 0xc9, 0x21,
0xe5, 0x1c, 0x39, 0x94, 0x1b, 0x7b, 0xc1, 0xab, 0xe9, 0x0b, 0xde, 0xf8, 0x26, 0xb9, 0xe3, 0xb6,
0x6d, 0xda, 0x3e, 0xba, 0xa2, 0x47, 0xcb, 0x03, 0x28, 0x86, 0x3e, 0x3b, 0x58, 0xf8, 0xa3, 0x35,
0x6e, 0x47, 0xaa, 0x99, 0xe8, 0x51, 0xa4, 0x37, 0xeb, 0x63, 0x93, 0xbd, 0xaf, 0x6d, 0x32, 0xe2,
0xa1, 0x59, 0xb1, 0x49, 0xba, 0x70, 0xfd, 0x94, 0xdc, 0x53, 0x43, 0x38, 0x5c, 0x5a, 0x52, 0xdc,
0x87, 0xa2, 0xa0, 0x3c, 0x42, 0x60, 0x54, 0x56, 0x44, 0x2a, 0xc6, 0xd7, 0xb0, 0xc6, 0x81, 0x49,
0x8e, 0xe3, 0x05, 0xe6, 0x46, 0xf6, 0xad, 0xa0, 0x9e, 0x7a, 0x2b, 0x18, 0x4f, 0x72, 0x70, 0x37,
0x0d, 0xcf, 0x55, 0xbe, 0x87, 0x5e, 0xcd, 0xe6, 0xca, 0x9d, 0xa1, 0x5c, 0xc9, 0x40, 0x72, 0x55,
0x09, 0xf3, 0xb3, 0x02, 0x1b, 0x63, 0x11, 0x59, 0x90, 0xac, 0xf9, 0x55, 0x81, 0xb5, 0x3d, 0xea,
0x63, 0xbb, 0x37, 0x57, 0xeb, 0x18, 0x27, 0x59, 0xee, 0x7c, 0xfd, 0xa0, 0x3a, 0x25, 0xe2, 0x13,
0xee, 0x3e, 0xa3, 0x09, 0xeb, 0x99, 0x08, 0x24, 0xb6, 0x49, 0x51, 0x55, 0xce, 0x2c, 0xaa, 0x7f,
0xb3, 0xc3, 0x3d, 0xb4, 0xcb, 0x3c, 0x55, 0x6e, 0x6a, 0x34, 0xd2, 0x61, 0xa9, 0x63, 0xcb, 0x71,
0x7e, 0x52, 0xbf, 0xb5, 0x34, 0x1d, 0x82, 0x46, 0x0b, 0x9e, 0x1e, 0x19, 0xdf, 0x0c, 0x58, 0xfd,
0xc3, 0xf2, 0x7a, 0x68, 0xaf, 0xb9, 0x8f, 0xfa, 0x85, 0x00, 0x96, 0xad, 0x51, 0xf9, 0x33, 0xfb,
0x99, 0x69, 0xb1, 0x7b, 0x0c, 0x9b, 0xe3, 0xe3, 0x9d, 0x01, 0xc0, 0xff, 0x14, 0x78, 0x26, 0xbb,
0xe1, 0x3c, 0xad, 0xc5, 0x85, 0xc0, 0x37, 0xdc, 0x2f, 0xe4, 0x67, 0xe8, 0x17, 0xa6, 0x85, 0xf3,
0x7d, 0xb8, 0x3b, 0x2e, 0xfa, 0x19, 0xc0, 0x7c, 0x13, 0xca, 0xdb, 0xf8, 0xd0, 0x71, 0x67, 0x82,
0xce, 0x78, 0x03, 0x2a, 0x72, 0xb5, 0x34, 0x9d, 0xaa, 0xb4, 0xca, 0xe4, 0x4a, 0x6b, 0x1c, 0x41,
0xa5, 0xe9, 0xf5, 0x7a, 0x0e, 0xbd, 0xec, 0xfb, 0xcd, 0x58, 0x85, 0x6a, 0x64, 0x49, 0xb8, 0x69,
0x7c, 0x06, 0x2b, 0xc8, 0xeb, 0x76, 0x0f, 0xec, 0xf6, 0xf1, 0xa5, 0x5b, 0xd7, 0x61, 0x35, 0xb1,
0x25, 0xed, 0xff, 0x9b, 0x83, 0x1b, 0x7b, 0xfd, 0xae, 0x43, 0x25, 0x25, 0xb3, 0xb8, 0x30, 0xe9,
0xc1, 0x31, 0x75, 0x57, 0xc4, 0x4e, 0x3d, 0x09, 0xfd, 0x90, 0x8d, 0x8f, 0x2c, 0x96, 0x1a, 0x9f,
0x13, 0x2d, 0x4f, 0xf8, 0xd8, 0x8f, 0x54, 0x02, 0x97, 0xf2, 0x34, 0x55, 0x11, 0x48, 0x0d, 0x36,
0xa3, 0xbf, 0x0c, 0xb7, 0xdd, 0xa0, 0x67, 0xf9, 0xde, 0x17, 0xc4, 0xea, 0x33, 0xe7, 0xf9, 0xce,
0x56, 0xdf, 0xf6, 0x29, 0xef, 0x81, 0x55, 0x74, 0x93, 0x89, 0x11, 0x93, 0xee, 0x62, 0x9f, 0x1b,
0xdf, 0x65, 0x22, 0xfd, 0x6d, 0x28, 0xd9, 0xdd, 0x43, 0xcf, 0x77, 0xe8, 0x51, 0x4f, 0x76, 0x3a,
0x86, 0x74, 0xf3, 0x14, 0x32, 0xe6, 0x3b, 0x91, 0x26, 0x4a, 0x16, 0xe9, 0x2f, 0x81, 0x1e, 0x10,
0x6c, 0x09, 0xe7, 0x84, 0xd1, 0x41, 0x43, 0xb6, 0x3d, 0x2b, 0x4c, 0x92, 0x6c, 0xf3, 0x51, 0xc3,
0xf8, 0x5d, 0x05, 0x3d, 0xbd, 0xaf, 0xcc, 0xd7, 0xd7, 0xd8, 0x35, 0x11, 0xce, 0x12, 0x86, 0x77,
0x78, 0x64, 0x37, 0x62, 0x1a, 0x4f, 0xe9, 0x9a, 0xa1, 0xdb, 0x48, 0xaa, 0xd7, 0x3f, 0x85, 0x72,
0x74, 0xf0, 0x78, 0x38, 0x69, 0x36, 0x94, 0x89, 0xb5, 0x21, 0x37, 0x45, 0x6d, 0xa8, 0xbf, 0x05,
0x25, 0x7e, 0xc5, 0x9c, 0xb9, 0x77, 0x72, 0xcf, 0xe5, 0xd2, 0xf7, 0x5c, 0xfd, 0x2f, 0x05, 0xf2,
0x7c, 0xf1, 0xd4, 0x0f, 0xd8, 0x0f, 0xa0, 0x1a, 0x7b, 0x29, 0xd8, 0x13, 0x99, 0x7d, 0x6f, 0x02,
0x24, 0x69, 0x08, 0x50, 0xf9, 0x38, 0x0d, 0x48, 0x13, 0x40, 0xfc, 0xcb, 0x9f, 0x6f, 0x25, 0xf2,
0xf0, 0xb9, 0x09, 0x5b, 0xc5, 0xe1, 0xa2, 0x12, 0x89, 0x23, 0xd7, 0x21, 0x4f, 0x9c, 0xaf, 0xc4,
0xa3, 0x45, 0x45, 0xfc, 0xdb, 0x78, 0x08, 0xeb, 0xef, 0x61, 0xba, 0xe7, 0x0f, 0xa2, 0x7b, 0x24,
0x3a, 0x3e, 0x13, 0x60, 0x32, 0x10, 0xdc, 0xca, 0x2e, 0x92, 0x19, 0xf0, 0x3a, 0x3b, 0x01, 0xfe,
0xc0, 0x1a, 0x5a, 0xa9, 0x35, 0xd6, 0x13, 0x7a, 0xd2, 0x8b, 0x34, 0x92, 0x0c, 0xb6, 0xeb, 0x50,
0x6b, 0x7b, 0x3d, 0xf3, 0xc4, 0x0b, 0x68, 0x70, 0x80, 0xcd, 0x81, 0x43, 0xd9, 0x89, 0x17, 0xbf,
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 {
SQL string
BindVariables map[string]interface{}
Keyspace string
TabletType topodatapb.TabletType
Session *vtgatepb.Session
NotInTransaction bool
@ -36,7 +37,7 @@ type queryExecuteSpecificShard struct {
}
// 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]
if !ok {
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{
SQL: sql,
BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType,
Session: session,
NotInTransaction: notInTransaction,
@ -109,7 +111,7 @@ func (f *fakeVTGateService) ExecuteBatchKeyspaceIds(ctx context.Context, queries
}
// 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]
if !ok {
return fmt.Errorf("no match for: %s", sql)
@ -117,6 +119,7 @@ func (f *fakeVTGateService) StreamExecute(ctx context.Context, sql string, bindV
query := &queryExecute{
SQL: sql,
BindVariables: bindVariables,
Keyspace: keyspace,
TabletType: tabletType,
}
if !reflect.DeepEqual(query, execCase.execQuery) {

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

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

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

@ -68,9 +68,15 @@ type builder interface {
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.
// 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)
if err != nil {
return nil, err

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

@ -14,15 +14,23 @@ import (
"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.
func buildUpdatePlan(upd *sqlparser.Update, vschema *vindexes.VSchema) (*engine.Route, error) {
func buildUpdatePlan(upd *sqlparser.Update, vschema VSchema) (*engine.Route, error) {
route := &engine.Route{
Query: generateQuery(upd),
}
// We allow only one table in an update.
tablename := sqlparser.GetTableName(upd.Table)
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 {
return nil, err
}
@ -47,7 +55,7 @@ func buildUpdatePlan(upd *sqlparser.Update, vschema *vindexes.VSchema) (*engine.
}
func generateQuery(statement sqlparser.Statement) string {
buf := sqlparser.NewTrackedBuffer(nil)
buf := sqlparser.NewTrackedBuffer(dmlFormatter)
statement.Format(buf)
return buf.String()
}
@ -68,14 +76,12 @@ func isIndexChanging(setClauses sqlparser.UpdateExprs, colVindexes []*vindexes.C
}
// 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{
Query: generateQuery(del),
}
// We allow only one table in a delete.
tablename := sqlparser.GetTableName(del.Table)
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 {
return nil, err
}

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

@ -13,12 +13,11 @@ import (
"github.com/youtube/vitess/go/vt/vtgate/vindexes"
)
// This file has functions to analyze the FROM clause
// for select statements.
// This file has functions to analyze the FROM clause.
// processTableExprs analyzes the FROM clause. It produces a builder
// 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 {
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.
func processTableExpr(tableExpr sqlparser.TableExpr, vschema *vindexes.VSchema) (builder, error) {
func processTableExpr(tableExpr sqlparser.TableExpr, vschema VSchema) (builder, error) {
switch tableExpr := tableExpr.(type) {
case *sqlparser.AliasedTableExpr:
return processAliasedTable(tableExpr, vschema)
@ -55,7 +54,7 @@ func processTableExpr(tableExpr sqlparser.TableExpr, vschema *vindexes.VSchema)
// vindex columns will be added to the tabsym.
// A symtab symbol can only point to a route. This means that we canoot
// 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) {
case *sqlparser.TableName:
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.
// It also returns the associated vschema info (*Table) so that
// it can be used to create the symbol table entry.
func getTablePlan(tableName *sqlparser.TableName, vschema *vindexes.VSchema) (*engine.Route, *vindexes.Table, error) {
table, err := vschema.FindTable(string(tableName.Name))
func getTablePlan(tableName *sqlparser.TableName, vschema VSchema) (*engine.Route, *vindexes.Table, error) {
table, err := vschema.Find(string(tableName.Qualifier), string(tableName.Name))
if err != nil {
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.
// If the left and right nodes can be part of the same route,
// 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 {
case sqlparser.JoinStr, sqlparser.StraightJoinStr, sqlparser.LeftJoinStr:
case sqlparser.RightJoinStr:

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

@ -14,13 +14,12 @@ import (
)
// 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{
Query: generateQuery(ins),
}
tablename := sqlparser.GetTableName(ins.Table)
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 {
return nil, err
}

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

@ -36,7 +36,7 @@ type route struct {
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:
// The route points to the symtab idicating
// the symtab that should be used to resolve symbols

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

@ -13,7 +13,7 @@ import (
)
// 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)
builder, err := processSelect(sel, vschema, 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.
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)
if err != nil {
return nil, err

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

@ -50,12 +50,12 @@ type symtab struct {
Colsyms []*colsym
Externs []*sqlparser.ColName
Outer *symtab
VSchema *vindexes.VSchema
VSchema VSchema
}
// newSymtab creates a new symtab initialized
// to contain the provided table alias.
func newSymtab(vschema *vindexes.VSchema) *symtab {
func newSymtab(vschema VSchema) *symtab {
return &symtab{
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
// 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 {
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
}
plan, err := planbuilder.Build(sql, plr.vschema)
plan, err := planbuilder.Build(sql, &wrappedVSchema{
vschema: plr.vschema,
keyspace: keyspace,
})
if err != nil {
return nil, err
}
@ -95,3 +102,15 @@ func (plr *Planner) ServeHTTP(response http.ResponseWriter, request *http.Reques
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
sql string
bindVars map[string]interface{}
keyspace string
tabletType topodatapb.TabletType
session *vtgatepb.Session
notInTransaction bool
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{
ctx: ctx,
sql: sql,
bindVars: bindVars,
keyspace: keyspace,
tabletType: tabletType,
session: session,
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) {
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) {

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

@ -59,12 +59,12 @@ func NewRouter(serv topo.SrvTopoServer, cell string, vschema *vindexes.VSchema,
}
// 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 {
bindVars = make(map[string]interface{})
}
vcursor := newRequestContext(ctx, sql, bindVars, tabletType, session, notInTransaction, rtr)
plan, err := rtr.planner.GetPlan(sql)
vcursor := newRequestContext(ctx, sql, bindVars, keyspace, tabletType, session, notInTransaction, rtr)
plan, err := rtr.planner.GetPlan(sql, keyspace)
if err != nil {
return nil, err
}
@ -72,12 +72,12 @@ func (rtr *Router) Execute(ctx context.Context, sql string, bindVars map[string]
}
// 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 {
bindVars = make(map[string]interface{})
}
vcursor := newRequestContext(ctx, sql, bindVars, tabletType, nil, false, rtr)
plan, err := rtr.planner.GetPlan(sql)
vcursor := newRequestContext(ctx, sql, bindVars, keyspace, tabletType, nil, false, rtr)
plan, err := rtr.planner.GetPlan(sql, keyspace)
if err != nil {
return err
}

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

@ -55,7 +55,7 @@ var routerVSchema = createTestVSchema(`
"Type": "numeric"
}
},
"Classes": {
"Tables": {
"user": {
"ColVindexes": [
{
@ -67,10 +67,10 @@ var routerVSchema = createTestVSchema(`
"Name": "name_user_map"
}
],
"Autoinc" : {
"Col": "id",
"Sequence": "user_seq"
}
"Autoinc" : {
"Col": "id",
"Sequence": "user_seq"
}
},
"user_extra": {
"ColVindexes": [
@ -91,10 +91,10 @@ var routerVSchema = createTestVSchema(`
"Name": "music_user_map"
}
],
"Autoinc" : {
"Col": "id",
"Sequence": "user_seq"
}
"Autoinc" : {
"Col": "id",
"Sequence": "user_seq"
}
},
"music_extra": {
"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": {
"Sharded": false,
"Tables": {
"sharded_table": ""
"sharded_table": {}
}
},
"TestUnsharded": {
"Sharded": false,
"Classes": {
"seq": {
"Type": "Sequence"
}
},
"Tables": {
"user_seq": "seq",
"music_user_map": "",
"name_user_map": ""
"user_seq": {
"Type": "Sequence"
},
"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(),
sql,
bv,
"",
topodatapb.TabletType_MASTER,
nil,
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) {
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
return nil
})

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

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

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

@ -85,8 +85,8 @@ func TestUnshardedVSchema(t *testing.T) {
good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"unsharded": {
Tables: map[string]string{
"t1": "",
Tables: map[string]TableFormal{
"t1": {},
},
},
},
@ -95,11 +95,12 @@ func TestUnshardedVSchema(t *testing.T) {
if err != nil {
t.Error(err)
}
ks := &Keyspace{
Name: "unsharded",
}
t1 := &Table{
Name: "t1",
Keyspace: &Keyspace{
Name: "unsharded",
},
Name: "t1",
Keyspace: ks,
}
want := &VSchema{
tables: map[string]*Table{
@ -107,6 +108,7 @@ func TestUnshardedVSchema(t *testing.T) {
},
Keyspaces: map[string]*KeyspaceSchema{
"unsharded": {
Keyspace: ks,
Tables: map[string]*Table{
"t1": t1,
},
@ -136,7 +138,7 @@ func TestShardedVSchemaOwned(t *testing.T) {
Owner: "t1",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
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 {
t.Error(err)
}
ks := &Keyspace{
Name: "sharded",
Sharded: true,
}
t1 := &Table{
Name: "t1",
Keyspace: &Keyspace{
Name: "sharded",
Sharded: true,
},
Name: "t1",
Keyspace: ks,
ColVindexes: []*ColVindex{
{
Col: "c1",
@ -197,7 +197,7 @@ func TestShardedVSchemaOwned(t *testing.T) {
},
Keyspaces: map[string]*KeyspaceSchema{
"sharded": {
Sharded: true,
Keyspace: ks,
Tables: map[string]*Table{
"t1": t1,
},
@ -226,7 +226,7 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
Owner: "",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
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 {
t.Error(err)
}
ks := &Keyspace{
Name: "sharded",
Sharded: true,
}
t1 := &Table{
Name: "t1",
Keyspace: &Keyspace{
Name: "sharded",
Sharded: true,
},
Name: "t1",
Keyspace: ks,
ColVindexes: []*ColVindex{
{
Col: "c1",
@ -282,7 +280,7 @@ func TestShardedVSchemaNotOwned(t *testing.T) {
},
Keyspaces: map[string]*KeyspaceSchema{
"sharded": {
Sharded: true,
Keyspace: ks,
Tables: map[string]*Table{
"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) {
bad := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
@ -351,7 +316,7 @@ func TestBuildVSchemaVindexNotFoundFail(t *testing.T) {
Type: "noexist",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
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",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
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{
Keyspaces: map[string]KeyspaceFormal{
"ksa": {
Classes: map[string]ClassFormal{
"seq": {
Tables: map[string]TableFormal{
"t1": {
Type: "Sequence",
},
},
Tables: map[string]string{
"t1": "seq",
},
},
"ksb": {
Classes: map[string]ClassFormal{
"seq": {
Tables: map[string]TableFormal{
"t1": {
Type: "Sequence",
},
},
Tables: map[string]string{
"t1": "seq",
},
},
},
}
ksa := &Keyspace{
Name: "ksa",
}
ksb := &Keyspace{
Name: "ksb",
}
got, _ := BuildVSchema(&good)
t1a := &Table{
Name: "t1",
Keyspace: &Keyspace{
Name: "ksa",
},
Name: "t1",
Keyspace: ksa,
IsSequence: true,
}
t1b := &Table{
Name: "t1",
Keyspace: &Keyspace{
Name: "ksb",
},
Name: "t1",
Keyspace: ksb,
IsSequence: true,
}
want := &VSchema{
@ -453,11 +408,13 @@ func TestBuildVSchemaDupSeq(t *testing.T) {
},
Keyspaces: map[string]*KeyspaceSchema{
"ksa": {
Keyspace: ksa,
Tables: map[string]*Table{
"t1": t1a,
},
},
"ksb": {
Keyspace: ksb,
Tables: map[string]*Table{
"t1": t1b,
},
@ -475,29 +432,31 @@ func TestBuildVSchemaDupTable(t *testing.T) {
good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"ksa": {
Tables: map[string]string{
"t1": "",
Tables: map[string]TableFormal{
"t1": {},
},
},
"ksb": {
Tables: map[string]string{
"t1": "",
Tables: map[string]TableFormal{
"t1": {},
},
},
},
}
got, _ := BuildVSchema(&good)
ksa := &Keyspace{
Name: "ksa",
}
t1a := &Table{
Name: "t1",
Keyspace: &Keyspace{
Name: "ksa",
},
Name: "t1",
Keyspace: ksa,
}
ksb := &Keyspace{
Name: "ksb",
}
t1b := &Table{
Name: "t1",
Keyspace: &Keyspace{
Name: "ksb",
},
Name: "t1",
Keyspace: ksb,
}
want := &VSchema{
tables: map[string]*Table{
@ -505,11 +464,13 @@ func TestBuildVSchemaDupTable(t *testing.T) {
},
Keyspaces: map[string]*KeyspaceSchema{
"ksa": {
Keyspace: ksa,
Tables: map[string]*Table{
"t1": t1a,
},
},
"ksb": {
Keyspace: ksb,
Tables: map[string]*Table{
"t1": t1b,
},
@ -533,7 +494,7 @@ func TestBuildVSchemaNoindexFail(t *testing.T) {
Type: "stfu",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -543,14 +504,11 @@ func TestBuildVSchemaNoindexFail(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, 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 {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
@ -566,7 +524,7 @@ func TestBuildVSchemaNotUniqueFail(t *testing.T) {
Type: "stln",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -576,14 +534,11 @@ func TestBuildVSchemaNotUniqueFail(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, 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 {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
@ -600,7 +555,7 @@ func TestBuildVSchemaPrimaryNonFunctionalFail(t *testing.T) {
Owner: "t1",
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
ColVindexes: []ColVindexFormal{
{
@ -610,14 +565,11 @@ func TestBuildVSchemaPrimaryNonFunctionalFail(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, 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 {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
@ -627,14 +579,11 @@ func TestSequence(t *testing.T) {
good := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"unsharded": {
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"seq": {
Type: "Sequence",
},
},
Tables: map[string]string{
"seq": "seq",
},
},
"sharded": {
Sharded: true,
@ -646,7 +595,7 @@ func TestSequence(t *testing.T) {
},
},
},
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
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 {
t.Error(err)
}
ksu := &Keyspace{
Name: "unsharded",
}
kss := &Keyspace{
Name: "sharded",
Sharded: true,
}
seq := &Table{
Name: "seq",
Keyspace: &Keyspace{
Name: "unsharded",
},
Name: "seq",
Keyspace: ksu,
IsSequence: true,
}
t1 := &Table{
Name: "t1",
Keyspace: &Keyspace{
Name: "sharded",
Sharded: true,
},
Name: "t1",
Keyspace: kss,
ColVindexes: []*ColVindex{
{
Col: "c1",
@ -711,12 +659,13 @@ func TestSequence(t *testing.T) {
},
Keyspaces: map[string]*KeyspaceSchema{
"unsharded": {
Keyspace: ksu,
Tables: map[string]*Table{
"seq": seq,
},
},
"sharded": {
Sharded: true,
Keyspace: kss,
Tables: map[string]*Table{
"t1": t1,
},
@ -735,7 +684,7 @@ func TestBadSequence(t *testing.T) {
Keyspaces: map[string]KeyspaceFormal{
"sharded": {
Sharded: true,
Classes: map[string]ClassFormal{
Tables: map[string]TableFormal{
"t1": {
Autoinc: &AutoincFormal{
Col: "c1",
@ -743,14 +692,11 @@ func TestBadSequence(t *testing.T) {
},
},
},
Tables: map[string]string{
"t1": "t1",
},
},
},
}
_, 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 {
t.Errorf("BuildVSchema: %v, want %v", err, want)
}
@ -760,47 +706,108 @@ func TestFind(t *testing.T) {
input := VSchemaFormal{
Keyspaces: map[string]KeyspaceFormal{
"ksa": {
Tables: map[string]string{
"ta": "",
"t1": "",
Tables: map[string]TableFormal{
"ta": {},
"t1": {},
},
},
"ksb": {
Tables: map[string]string{
"tb": "",
"t1": "",
Sharded: true,
Tables: map[string]TableFormal{
"tb": {},
"t1": {},
},
},
},
}
vschema, _ := BuildVSchema(&input)
_, err := vschema.FindTable("")
wantErr := "unsupported: compex table expression in DML"
_, err := vschema.Find("", "t1")
wantErr := "ambiguous table reference: t1"
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")
wantErr = "ambiguous table reference: t1"
if err == nil || err.Error() != wantErr {
t.Errorf("FindTable(\"\"): %v, want %s", err, wantErr)
}
_, err = vschema.FindTable("none")
_, err = vschema.Find("", "none")
wantErr = "table none not found"
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 {
t.Error(err)
return
}
want := &Table{
ta := &Table{
Name: "ta",
Keyspace: &Keyspace{
Name: "ksa",
},
}
if !reflect.DeepEqual(got, want) {
t.Errorf("FindTable(\"t1a\"): %+v, want %+v", got, want)
if !reflect.DeepEqual(got, ta) {
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.
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()
statsKey := []string{"Execute", "Any", strings.ToLower(tabletType.String())}
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
}
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 {
vtg.rowsReturned.Add(statsKey, int64(len(qr.Rows)))
return qr, nil
@ -177,6 +177,7 @@ func (vtg *VTGate) Execute(ctx context.Context, sql string, bindVariables map[st
query := map[string]interface{}{
"Sql": sql,
"BindVariables": bindVariables,
"Keyspace": keyspace,
"TabletType": strings.ToLower(tabletType.String()),
"Session": session,
"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.
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()
statsKey := []string{"StreamExecute", "Any", strings.ToLower(tabletType.String())}
defer vtg.timings.Record(statsKey, startTime)
@ -426,6 +427,7 @@ func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables
ctx,
sql,
bindVariables,
keyspace,
tabletType,
func(reply *sqltypes.Result) error {
rowCount += int64(len(reply.Rows))
@ -438,6 +440,7 @@ func (vtg *VTGate) StreamExecute(ctx context.Context, sql string, bindVariables
query := map[string]interface{}{
"Sql": sql,
"BindVariables": bindVariables,
"Keyspace": keyspace,
"TabletType": strings.ToLower(tabletType.String()),
}
logError(err, query, vtg.logStreamExecute)

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

@ -35,7 +35,7 @@ func init() {
"TestUnsharded": {
"Sharded": false,
"Tables": {
"t1": ""
"t1": {}
}
}
}
@ -51,6 +51,7 @@ func TestVTGateExecute(t *testing.T) {
qr, err := rpcVTGate.Execute(context.Background(),
"select id from t1",
nil,
"",
topodatapb.TabletType_MASTER,
nil,
false)
@ -68,6 +69,7 @@ func TestVTGateExecute(t *testing.T) {
rpcVTGate.Execute(context.Background(),
"select id from t1",
nil,
"",
topodatapb.TabletType_MASTER,
session,
false)
@ -95,12 +97,43 @@ func TestVTGateExecute(t *testing.T) {
rpcVTGate.Execute(context.Background(),
"select id from t1",
nil,
"",
topodatapb.TabletType_MASTER,
session,
false)
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) {
sandbox := createSandbox("TestVTGateExecuteShards")
sbc := &sandboxConn{}
@ -532,6 +565,7 @@ func TestVTGateStreamExecute(t *testing.T) {
err := rpcVTGate.StreamExecute(context.Background(),
"select id from t1",
nil,
"",
topodatapb.TabletType_MASTER,
func(r *sqltypes.Result) error {
qrs = append(qrs, r)

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

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

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

@ -20,7 +20,7 @@ import (
type VTGateService interface {
// Regular query execution.
// 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)
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)
@ -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)
// 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
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

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

@ -33,15 +33,15 @@ func (_m *MockVTGateService) EXPECT() *_MockVTGateServiceRecorder {
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) {
ret := _m.ctrl.Call(_m, "Execute", ctx, sql, bindVariables, tabletType, session, notInTransaction)
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, keyspace, tabletType, session, notInTransaction)
ret0, _ := ret[0].(*sqltypes.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
func (_mr *_MockVTGateServiceRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "Execute", arg0, arg1, arg2, arg3, arg4, arg5)
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, 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) {
@ -110,14 +110,14 @@ func (_mr *_MockVTGateServiceRecorder) ExecuteBatchKeyspaceIds(arg0, arg1, arg2,
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 {
ret := _m.ctrl.Call(_m, "StreamExecute", ctx, sql, bindVariables, tabletType, sendReply)
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, keyspace, tabletType, sendReply)
ret0, _ := ret[0].(error)
return ret0
}
func (_mr *_MockVTGateServiceRecorder) StreamExecute(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
return _mr.mock.ctrl.RecordCall(_mr.mock, "StreamExecute", arg0, arg1, arg2, arg3, arg4)
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, 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 {

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

@ -41,6 +41,9 @@ message ExecuteRequest {
// not_in_transaction is deprecated and should not be used.
bool not_in_transaction = 5;
// keyspace to target the query to.
string keyspace = 6;
}
// 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.
topodata.TabletType tablet_type = 3;
// keyspace to target the query to.
string keyspace = 4;
}
// StreamExecuteResponse is the returned value from StreamExecute.

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

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

@ -126,7 +126,7 @@ vschema = '''{
"Owner": "vt_music"
}
},
"Classes": {
"Tables": {
"vt_user": {
"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": {
"Sharded": false,
"Classes" : {
"seq": {
"Type": "Sequence"
}
},
"Tables": {
"vt_user_seq": "seq",
"vt_music_seq": "seq",
"music_user_map": "",
"name_user2_map": ""
"vt_user_seq": {
"Type": "Sequence"
},
"vt_music_seq": {
"Type": "Sequence"
},
"music_user_map": {},
"name_user2_map": {}
}
}
}