From 9ef1d0268335737ea588feedce7f0781c05bb681 Mon Sep 17 00:00:00 2001 From: Ashudeep Sharma Date: Fri, 30 Dec 2016 19:07:42 +0530 Subject: [PATCH 1/5] MultiRow Insert Optimization --- go/vt/vtgate/planbuilder/plan_test.go | 20 +-- go/vt/vtgate/router.go | 98 +++++++++----- go/vt/vtgate/router_dml_test.go | 120 ++++++++---------- go/vt/vtgate/vindexes/binary.go | 34 +++-- go/vt/vtgate/vindexes/binary_test.go | 8 +- go/vt/vtgate/vindexes/binarymd5.go | 20 ++- go/vt/vtgate/vindexes/binarymd5_test.go | 2 +- go/vt/vtgate/vindexes/hash.go | 34 +++-- go/vt/vtgate/vindexes/hash_test.go | 6 +- go/vt/vtgate/vindexes/lookup.go | 20 +-- go/vt/vtgate/vindexes/lookup_hash.go | 20 +-- go/vt/vtgate/vindexes/lookup_hash_test.go | 10 +- .../vindexes/lookup_hash_unique_test.go | 10 +- go/vt/vtgate/vindexes/lookup_internal.go | 116 +++++++++++------ go/vt/vtgate/vindexes/lookup_test.go | 18 +-- go/vt/vtgate/vindexes/numeric.go | 40 ++++-- go/vt/vtgate/vindexes/numeric_static_map.go | 32 +++-- .../vindexes/numeric_static_map_test.go | 4 +- go/vt/vtgate/vindexes/numeric_test.go | 12 +- go/vt/vtgate/vindexes/unicodeloosemd5.go | 20 ++- go/vt/vtgate/vindexes/unicodeloosemd5_test.go | 2 +- go/vt/vtgate/vindexes/vindex.go | 8 +- go/vt/vtgate/vindexes/vschema_test.go | 38 +++--- 23 files changed, 403 insertions(+), 289 deletions(-) diff --git a/go/vt/vtgate/planbuilder/plan_test.go b/go/vt/vtgate/planbuilder/plan_test.go index d00638b8795..773f4336fa7 100644 --- a/go/vt/vtgate/planbuilder/plan_test.go +++ b/go/vt/vtgate/planbuilder/plan_test.go @@ -25,11 +25,11 @@ type hashIndex struct{ name string } func (v *hashIndex) String() string { return v.name } func (*hashIndex) Cost() int { return 1 } -func (*hashIndex) Verify(vindexes.VCursor, interface{}, []byte) (bool, error) { +func (*hashIndex) Verify(vindexes.VCursor, []interface{}, [][]byte) (bool, error) { return false, nil } func (*hashIndex) Map(vindexes.VCursor, []interface{}) ([][]byte, error) { return nil, nil } -func (*hashIndex) Create(vindexes.VCursor, interface{}) error { return nil } +func (*hashIndex) Create(vindexes.VCursor, []interface{}) error { return nil } func (*hashIndex) Delete(vindexes.VCursor, []interface{}, []byte) error { return nil } func newHashIndex(name string, _ map[string]string) (vindexes.Vindex, error) { @@ -41,12 +41,12 @@ type lookupIndex struct{ name string } func (v *lookupIndex) String() string { return v.name } func (*lookupIndex) Cost() int { return 2 } -func (*lookupIndex) Verify(vindexes.VCursor, interface{}, []byte) (bool, error) { +func (*lookupIndex) Verify(vindexes.VCursor, []interface{}, [][]byte) (bool, error) { return false, nil } -func (*lookupIndex) Map(vindexes.VCursor, []interface{}) ([][]byte, error) { return nil, nil } -func (*lookupIndex) Create(vindexes.VCursor, interface{}, []byte) error { return nil } -func (*lookupIndex) Delete(vindexes.VCursor, []interface{}, []byte) error { return nil } +func (*lookupIndex) Map(vindexes.VCursor, []interface{}) ([][]byte, error) { return nil, nil } +func (*lookupIndex) Create(vindexes.VCursor, []interface{}, [][]byte) error { return nil } +func (*lookupIndex) Delete(vindexes.VCursor, []interface{}, []byte) error { return nil } func newLookupIndex(name string, _ map[string]string) (vindexes.Vindex, error) { return &lookupIndex{name: name}, nil @@ -57,11 +57,11 @@ type multiIndex struct{ name string } func (v *multiIndex) String() string { return v.name } func (*multiIndex) Cost() int { return 3 } -func (*multiIndex) Verify(vindexes.VCursor, interface{}, []byte) (bool, error) { +func (*multiIndex) Verify(vindexes.VCursor, []interface{}, [][]byte) (bool, error) { return false, nil } func (*multiIndex) Map(vindexes.VCursor, []interface{}) ([][][]byte, error) { return nil, nil } -func (*multiIndex) Create(vindexes.VCursor, interface{}, []byte) error { return nil } +func (*multiIndex) Create(vindexes.VCursor, []interface{}, [][]byte) error { return nil } func (*multiIndex) Delete(vindexes.VCursor, []interface{}, []byte) error { return nil } func newMultiIndex(name string, _ map[string]string) (vindexes.Vindex, error) { @@ -73,11 +73,11 @@ type costlyIndex struct{ name string } func (v *costlyIndex) String() string { return v.name } func (*costlyIndex) Cost() int { return 10 } -func (*costlyIndex) Verify(vindexes.VCursor, interface{}, []byte) (bool, error) { +func (*costlyIndex) Verify(vindexes.VCursor, []interface{}, [][]byte) (bool, error) { return false, nil } func (*costlyIndex) Map(vindexes.VCursor, []interface{}) ([][][]byte, error) { return nil, nil } -func (*costlyIndex) Create(vindexes.VCursor, interface{}, []byte) error { return nil } +func (*costlyIndex) Create(vindexes.VCursor, []interface{}, [][]byte) error { return nil } func (*costlyIndex) Delete(vindexes.VCursor, []interface{}, []byte) error { return nil } func newCostlyIndex(name string, _ map[string]string) (vindexes.Vindex, error) { diff --git a/go/vt/vtgate/router.go b/go/vt/vtgate/router.go index 8b95b52f572..d4965d9a24d 100644 --- a/go/vt/vtgate/router.go +++ b/go/vt/vtgate/router.go @@ -5,7 +5,6 @@ package vtgate import ( - "encoding/hex" "fmt" "strconv" @@ -432,25 +431,29 @@ func (rtr *Router) getInsertShardedRoute(vcursor *queryExecutor, route *engine.R } inputs := route.Values.([]interface{}) - for rowNum, input := range inputs { + allKeys := make([][]interface{}, len(inputs[0].([]interface{}))) + for _, input := range inputs { keys, err := rtr.resolveKeys(input.([]interface{}), vcursor.bindVars) if err != nil { return "", nil, fmt.Errorf("getInsertShardedRoute: %v", err) } for colNum := 0; colNum < len(keys); colNum++ { - if colNum == 0 { - ksid, err := rtr.handlePrimary(vcursor, keys[colNum], route.Table.ColumnVindexes[colNum], vcursor.bindVars, rowNum) - if err != nil { - return "", nil, fmt.Errorf("getInsertShardedRoute: %v", err) - } - keyspaceIDs = append(keyspaceIDs, ksid) - } else { - err := rtr.handleNonPrimary(vcursor, keys[colNum], route.Table.ColumnVindexes[colNum], vcursor.bindVars, keyspaceIDs[rowNum], rowNum) - if err != nil { - return "", nil, fmt.Errorf("getInsertShardedRoute: %v", err) - } - } + allKeys[colNum] = append(allKeys[colNum], keys[colNum]) + } + } + + keyspaceIDs, err = rtr.handlePrimary(vcursor, allKeys[0], route.Table.ColumnVindexes[0], vcursor.bindVars, allShards) + if err != nil { + return "", nil, fmt.Errorf("getInsertShardedRoute: %v", err) + } + + for colNum := 1; colNum < len(allKeys); colNum++ { + err := rtr.handleNonPrimary(vcursor, allKeys[colNum], route.Table.ColumnVindexes[colNum], vcursor.bindVars, keyspaceIDs) + if err != nil { + return "", nil, fmt.Errorf("getInsertShardedRoute: %v", err) } + } + for rowNum := range keyspaceIDs { shard, err := getShardForKeyspaceID(allShards, keyspaceIDs[rowNum]) routing[shard] = append(routing[shard], route.Mid[rowNum]) if err != nil { @@ -701,57 +704,86 @@ func (rtr *Router) handleGenerate(vcursor *queryExecutor, gen *engine.Generate) return insertid, nil } -func (rtr *Router) handlePrimary(vcursor *queryExecutor, vindexKey interface{}, colVindex *vindexes.ColumnVindex, bv map[string]interface{}, rowNum int) (ksid []byte, err error) { - if vindexKey == nil { +func (rtr *Router) handlePrimary(vcursor *queryExecutor, vindexKeys []interface{}, colVindex *vindexes.ColumnVindex, bv map[string]interface{}, allShards []*topodatapb.ShardReference) (keyspaceIDs [][]byte, err error) { + if vindexKeys == nil { return nil, fmt.Errorf("value must be supplied for column %v", colVindex.Column) } + for _, vindexkey := range vindexKeys { + if vindexkey == nil { + return nil, fmt.Errorf("value must be supplied for column %v", colVindex.Column) + } + } mapper := colVindex.Vindex.(vindexes.Unique) - ksids, err := mapper.Map(vcursor, []interface{}{vindexKey}) + keyspaceIDs, err = mapper.Map(vcursor, vindexKeys) if err != nil { return nil, err } - ksid = ksids[0] - if len(ksid) == 0 { - return nil, fmt.Errorf("could not map %v to a keyspace id", vindexKey) + if len(keyspaceIDs) != len(vindexKeys) { + return nil, fmt.Errorf("could not map %v to a keyspaceids", vindexKeys) + } + for rowNum, vindexKey := range vindexKeys { + if len(keyspaceIDs[rowNum]) == 0 { + return nil, fmt.Errorf("could not map %v to a keyspace id", vindexKey) + } + bv["_"+colVindex.Column.CompliantName()+strconv.Itoa(rowNum)] = vindexKey } - bv["_"+colVindex.Column.CompliantName()+strconv.Itoa(rowNum)] = vindexKey - return ksid, nil + return keyspaceIDs, nil } -func (rtr *Router) handleNonPrimary(vcursor *queryExecutor, vindexKey interface{}, colVindex *vindexes.ColumnVindex, bv map[string]interface{}, ksid []byte, rowNum int) error { +func (rtr *Router) handleNonPrimary(vcursor *queryExecutor, vindexKeys []interface{}, colVindex *vindexes.ColumnVindex, bv map[string]interface{}, ksids [][]byte) error { if colVindex.Owned { - if vindexKey == nil { + if vindexKeys == nil { return fmt.Errorf("value must be supplied for column %v", colVindex.Column) } - err := colVindex.Vindex.(vindexes.Lookup).Create(vcursor, vindexKey, ksid) + for rowNum, vindexKey := range vindexKeys { + if vindexKey == nil { + return fmt.Errorf("value must be supplied for column %v", colVindex.Column) + } + bv["_"+colVindex.Column.CompliantName()+strconv.Itoa(rowNum)] = vindexKey + } + err := colVindex.Vindex.(vindexes.Lookup).Create(vcursor, vindexKeys, ksids) if err != nil { return err } } else { - if vindexKey == nil { + var reverseKsids [][]byte + var verifyKsids [][]byte + for rowNum, vindexKey := range vindexKeys { + if vindexKey == nil { + reverseKsids = append(reverseKsids, ksids[rowNum]) + } else { + verifyKsids = append(verifyKsids, ksids[rowNum]) + } + bv["_"+colVindex.Column.CompliantName()+strconv.Itoa(rowNum)] = vindexKey + } + var err error + if reverseKsids != nil { reversible, ok := colVindex.Vindex.(vindexes.Reversible) if !ok { return fmt.Errorf("value must be supplied for column %v", colVindex.Column) } - var err error - vindexKey, err = reversible.ReverseMap(vcursor, ksid) + vindexKeys, err = reversible.ReverseMap(vcursor, reverseKsids) if err != nil { return err } - if vindexKey == nil { + if vindexKeys == nil { return fmt.Errorf("could not compute value for column %v", colVindex.Column) } - } else { - ok, err := colVindex.Vindex.Verify(vcursor, vindexKey, ksid) + for rowNum, vindexKey := range vindexKeys { + bv["_"+colVindex.Column.CompliantName()+strconv.Itoa(rowNum)] = vindexKey + } + } + + if verifyKsids != nil { + ok, err := colVindex.Vindex.Verify(vcursor, vindexKeys, verifyKsids) if err != nil { return err } if !ok { - return fmt.Errorf("value %v for column %v does not map to keyspace id %v", vindexKey, colVindex.Column, hex.EncodeToString(ksid)) + return fmt.Errorf("values %v for column %v does not map to keyspaceids", vindexKeys, colVindex.Column) } } } - bv["_"+colVindex.Column.CompliantName()+strconv.Itoa(rowNum)] = vindexKey return nil } diff --git a/go/vt/vtgate/router_dml_test.go b/go/vt/vtgate/router_dml_test.go index e455aea6e71..2137c3eea83 100644 --- a/go/vt/vtgate/router_dml_test.go +++ b/go/vt/vtgate/router_dml_test.go @@ -313,10 +313,10 @@ func TestInsertSharded(t *testing.T) { t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries) } wantQueries = []querytypes.BoundQuery{{ - Sql: "insert into name_user_map(name, user_id) values (:name, :user_id)", + Sql: "insert into name_user_map(name, user_id) values (:name0, :user_id0)", BindVariables: map[string]interface{}{ - "name": []byte("myname"), - "user_id": int64(1), + "name0": []byte("myname"), + "user_id0": int64(1), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -344,10 +344,10 @@ func TestInsertSharded(t *testing.T) { t.Errorf("sbc1.Queries: %+v, want nil\n", sbc1.Queries) } wantQueries = []querytypes.BoundQuery{{ - Sql: "insert into name_user_map(name, user_id) values (:name, :user_id)", + Sql: "insert into name_user_map(name, user_id) values (:name0, :user_id0)", BindVariables: map[string]interface{}{ - "name": []byte("myname2"), - "user_id": int64(3), + "name0": []byte("myname2"), + "user_id0": int64(3), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -377,10 +377,10 @@ func TestInsertComments(t *testing.T) { t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries) } wantQueries = []querytypes.BoundQuery{{ - Sql: "insert into name_user_map(name, user_id) values (:name, :user_id)", + Sql: "insert into name_user_map(name, user_id) values (:name0, :user_id0)", BindVariables: map[string]interface{}{ - "name": []byte("myname"), - "user_id": int64(1), + "name0": []byte("myname"), + "user_id0": int64(1), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -417,10 +417,10 @@ func TestInsertGeneratorSharded(t *testing.T) { Sql: "select next :n values from user_seq", BindVariables: map[string]interface{}{"n": int64(1)}, }, { - Sql: "insert into name_user_map(name, user_id) values (:name, :user_id)", + Sql: "insert into name_user_map(name, user_id) values (:name0, :user_id0)", BindVariables: map[string]interface{}{ - "name": []byte("myname"), - "user_id": int64(1), + "name0": []byte("myname"), + "user_id0": int64(1), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -477,10 +477,10 @@ func TestInsertLookupOwned(t *testing.T) { t.Errorf("sbc.Queries:\n%+v, want\n%+v\n", sbc.Queries, wantQueries) } wantQueries = []querytypes.BoundQuery{{ - Sql: "insert into music_user_map(music_id, user_id) values (:music_id, :user_id)", + Sql: "insert into music_user_map(music_id, user_id) values (:music_id0, :user_id0)", BindVariables: map[string]interface{}{ - "music_id": int64(3), - "user_id": int64(2), + "music_id0": int64(3), + "user_id0": int64(2), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -517,10 +517,10 @@ func TestInsertLookupOwnedGenerator(t *testing.T) { Sql: "select next :n values from user_seq", BindVariables: map[string]interface{}{"n": int64(1)}, }, { - Sql: "insert into music_user_map(music_id, user_id) values (:music_id, :user_id)", + Sql: "insert into music_user_map(music_id, user_id) values (:music_id0, :user_id0)", BindVariables: map[string]interface{}{ - "music_id": int64(4), - "user_id": int64(2), + "music_id0": int64(4), + "user_id0": int64(2), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -551,10 +551,10 @@ func TestInsertLookupUnowned(t *testing.T) { t.Errorf("sbc.Queries: %+v, want %+v\n", sbc.Queries, wantQueries) } wantQueries = []querytypes.BoundQuery{{ - Sql: "select music_id from music_user_map where music_id = :music_id and user_id = :user_id", + Sql: "select music_id from music_user_map where music_id in (:music_id0) and user_id in (:user_id0)", BindVariables: map[string]interface{}{ - "music_id": int64(3), - "user_id": int64(2), + "music_id0": int64(3), + "user_id0": int64(2), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -668,11 +668,11 @@ func TestInsertFail(t *testing.T) { t.Errorf("routerExec: %v, want prefix %v", err, want) } - _, err = routerExec(router, "insert into music_extra(user_id, music_id) values (1, null)", nil) - want = "execInsertSharded: getInsertShardedRoute: value must be supplied for column music_id" - if err == nil || err.Error() != want { - t.Errorf("routerExec: %v, want %v", err, want) - } + //_, err = routerExec(router, "insert into music_extra(user_id, music_id) values (1, null)", nil) + //want = "execInsertSharded: getInsertShardedRoute: value must be supplied for column music_id" + //if err == nil || err.Error() != want { + // t.Errorf("routerExec: %v, want %v", err, want) + //} _, err = routerExec(router, "insert into music_extra_reversed(music_id, user_id) values (1, 'aa')", nil) want = `execInsertSharded: getInsertShardedRoute: hash.Verify: parseString: strconv.ParseUint: parsing "aa": invalid syntax` @@ -681,7 +681,7 @@ func TestInsertFail(t *testing.T) { } _, err = routerExec(router, "insert into music_extra_reversed(music_id, user_id) values (1, 3)", nil) - want = "execInsertSharded: getInsertShardedRoute: value 3 for column user_id does not map to keyspace id 166b40b44aba4bd6" + want = "execInsertSharded: getInsertShardedRoute: values [3] for column user_id does not map to keyspaceids" if err == nil || err.Error() != want { t.Errorf("routerExec: %v, want %v", err, want) } @@ -774,16 +774,12 @@ func TestMultiInsertSharded(t *testing.T) { } wantQueries1 = []querytypes.BoundQuery{{ - Sql: "insert into name_user_map(name, user_id) values (:name, :user_id)", + Sql: "insert into name_user_map(name, user_id) values (:name0, :user_id0), (:name1, :user_id1)", BindVariables: map[string]interface{}{ - "name": []byte("myname1"), - "user_id": int64(1), - }, - }, { - Sql: "insert into name_user_map(name, user_id) values (:name, :user_id)", - BindVariables: map[string]interface{}{ - "name": []byte("myname3"), - "user_id": int64(3), + "name0": []byte("myname1"), + "user_id0": int64(1), + "name1": []byte("myname3"), + "user_id1": int64(3), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries1) { @@ -816,16 +812,12 @@ func TestMultiInsertSharded(t *testing.T) { t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries) } wantQueries = []querytypes.BoundQuery{{ - Sql: "insert into name_user_map(name, user_id) values (:name, :user_id)", - BindVariables: map[string]interface{}{ - "name": []byte("myname1"), - "user_id": int64(1), - }, - }, { - Sql: "insert into name_user_map(name, user_id) values (:name, :user_id)", + Sql: "insert into name_user_map(name, user_id) values (:name0, :user_id0), (:name1, :user_id1)", BindVariables: map[string]interface{}{ - "name": []byte("myname2"), - "user_id": int64(2), + "name0": []byte("myname1"), + "user_id0": int64(1), + "name1": []byte("myname2"), + "user_id1": int64(2), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -866,16 +858,12 @@ func TestMultiInsertGenerator(t *testing.T) { Sql: "select next :n values from user_seq", BindVariables: map[string]interface{}{"n": int64(2)}, }, { - Sql: "insert into music_user_map(music_id, user_id) values (:music_id, :user_id)", + Sql: "insert into music_user_map(music_id, user_id) values (:music_id0, :user_id0), (:music_id1, :user_id1)", BindVariables: map[string]interface{}{ - "user_id": int64(2), - "music_id": int64(1), - }, - }, { - Sql: "insert into music_user_map(music_id, user_id) values (:music_id, :user_id)", - BindVariables: map[string]interface{}{ - "user_id": int64(2), - "music_id": int64(2), + "user_id0": int64(2), + "music_id0": int64(1), + "user_id1": int64(2), + "music_id1": int64(2), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { @@ -924,22 +912,14 @@ func TestMultiInsertGeneratorSparse(t *testing.T) { Sql: "select next :n values from user_seq", BindVariables: map[string]interface{}{"n": int64(2)}, }, { - Sql: "insert into music_user_map(music_id, user_id) values (:music_id, :user_id)", - BindVariables: map[string]interface{}{ - "user_id": int64(2), - "music_id": int64(1), - }, - }, { - Sql: "insert into music_user_map(music_id, user_id) values (:music_id, :user_id)", - BindVariables: map[string]interface{}{ - "user_id": int64(2), - "music_id": int64(2), - }, - }, { - Sql: "insert into music_user_map(music_id, user_id) values (:music_id, :user_id)", - BindVariables: map[string]interface{}{ - "user_id": int64(2), - "music_id": int64(2), + Sql: "insert into music_user_map(music_id, user_id) values (:music_id0, :user_id0), (:music_id1, :user_id1), (:music_id2, :user_id2)", + BindVariables: map[string]interface{}{ + "user_id0": int64(2), + "music_id0": int64(1), + "user_id1": int64(2), + "music_id1": int64(2), + "user_id2": int64(2), + "music_id2": int64(2), }, }} if !reflect.DeepEqual(sbclookup.Queries, wantQueries) { diff --git a/go/vt/vtgate/vindexes/binary.go b/go/vt/vtgate/vindexes/binary.go index 4f0f3278ea0..1030faa75ed 100644 --- a/go/vt/vtgate/vindexes/binary.go +++ b/go/vt/vtgate/vindexes/binary.go @@ -25,13 +25,21 @@ func (vind *Binary) Cost() int { return 0 } -// Verify returns true if id maps to ksid. -func (vind *Binary) Verify(_ VCursor, id interface{}, ksid []byte) (bool, error) { - data, err := getBytes(id) - if err != nil { - return false, fmt.Errorf("Binary.Verify: %v", err) +// Verify returns true if ids maps to ksids. +func (vind *Binary) Verify(_ VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + if len(ids) != len(ksids) { + return false, fmt.Errorf("Binary.Verify: length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) } - return bytes.Compare(data, ksid) == 0, nil + for rowNum := range ids { + data, err := getBytes(ids[rowNum]) + if err != nil { + return false, fmt.Errorf("Binary.Verify: %v", err) + } + if bytes.Compare(data, ksids[rowNum]) != 0 { + return false, nil + } + } + return true, nil } // Map returns the corresponding keyspace id values for the given ids. @@ -47,12 +55,16 @@ func (vind *Binary) Map(_ VCursor, ids []interface{}) ([][]byte, error) { return out, nil } -// ReverseMap returns the associated id for the ksid. -func (*Binary) ReverseMap(_ VCursor, ksid []byte) (interface{}, error) { - if ksid == nil { - return nil, fmt.Errorf("Binary.ReverseMap: is nil") +// ReverseMap returns the associated ids for the ksids. +func (*Binary) ReverseMap(_ VCursor, ksids [][]byte) ([]interface{}, error) { + var reverseIds = make([]interface{}, len(ksids)) + for rownum, keyspaceID := range ksids { + if keyspaceID == nil { + return nil, fmt.Errorf("Binary.ReverseMap: is nil") + } + reverseIds[rownum] = []byte(keyspaceID) } - return []byte(ksid), nil + return reverseIds, nil } func init() { diff --git a/go/vt/vtgate/vindexes/binary_test.go b/go/vt/vtgate/vindexes/binary_test.go index 391f9acac71..6004e5e77cd 100644 --- a/go/vt/vtgate/vindexes/binary_test.go +++ b/go/vt/vtgate/vindexes/binary_test.go @@ -1,8 +1,8 @@ package vindexes import ( - "testing" "bytes" + "testing" ) var binOnlyVindex Vindex @@ -39,7 +39,7 @@ func TestBinary(t *testing.T) { if bytes.Compare(tcase.in, out) != 0 { t.Errorf("Map(%#v): %#v, want %#v", tcase.in, out, tcase.out) } - ok, err := binOnlyVindex.Verify(nil, tcase.in, tcase.out) + ok, err := binOnlyVindex.Verify(nil, []interface{}{tcase.in}, [][]byte{tcase.out}) if err != nil { t.Error(err) } @@ -50,11 +50,11 @@ func TestBinary(t *testing.T) { } func TestBinaryReverseMap(t *testing.T) { - got, err := binOnlyVindex.(Reversible).ReverseMap(nil, []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) + got, err := binOnlyVindex.(Reversible).ReverseMap(nil, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) if err != nil { t.Error(err) } - if bytes.Compare(got.([]byte), []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) != 0 { + if bytes.Compare(got[0].([]byte), []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) != 0 { t.Errorf("ReverseMap(): %+v, want %+v", got, []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) } } diff --git a/go/vt/vtgate/vindexes/binarymd5.go b/go/vt/vtgate/vindexes/binarymd5.go index 741e771882b..cd4bda74aa1 100644 --- a/go/vt/vtgate/vindexes/binarymd5.go +++ b/go/vt/vtgate/vindexes/binarymd5.go @@ -26,13 +26,21 @@ func (vind *BinaryMD5) Cost() int { return 1 } -// Verify returns true if id maps to ksid. -func (vind *BinaryMD5) Verify(_ VCursor, id interface{}, ksid []byte) (bool, error) { - data, err := binHashKey(id) - if err != nil { - return false, fmt.Errorf("BinaryMD5_hash.Verify: %v", err) +// Verify returns true if ids maps to ksids. +func (vind *BinaryMD5) Verify(_ VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + if len(ids) != len(ksids) { + return false, fmt.Errorf("BinaryMD5_hash.Verify: length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) + } + for rowNum := range ids { + data, err := binHashKey(ids[rowNum]) + if err != nil { + return false, fmt.Errorf("BinaryMD5_hash.Verify: %v", err) + } + if bytes.Compare(data, ksids[rowNum]) != 0 { + return false, nil + } } - return bytes.Compare(data, ksid) == 0, nil + return true, nil } // Map returns the corresponding keyspace id values for the given ids. diff --git a/go/vt/vtgate/vindexes/binarymd5_test.go b/go/vt/vtgate/vindexes/binarymd5_test.go index 73a799d2baf..5784595bf56 100644 --- a/go/vt/vtgate/vindexes/binarymd5_test.go +++ b/go/vt/vtgate/vindexes/binarymd5_test.go @@ -40,7 +40,7 @@ func TestBinaryMD5(t *testing.T) { if out != tcase.out { t.Errorf("Map(%#v): %#v, want %#v", tcase.in, out, tcase.out) } - ok, err := binVindex.Verify(nil, []byte(tcase.in), []byte(tcase.out)) + ok, err := binVindex.Verify(nil, []interface{}{[]byte(tcase.in)}, [][]byte{[]byte(tcase.out)}) if err != nil { t.Error(err) } diff --git a/go/vt/vtgate/vindexes/hash.go b/go/vt/vtgate/vindexes/hash.go index 4911f2d3031..94f1d1b928b 100644 --- a/go/vt/vtgate/vindexes/hash.go +++ b/go/vt/vtgate/vindexes/hash.go @@ -48,18 +48,34 @@ func (vind *Hash) Map(_ VCursor, ids []interface{}) ([][]byte, error) { return out, nil } -// Verify returns true if id maps to ksid. -func (vind *Hash) Verify(_ VCursor, id interface{}, ksid []byte) (bool, error) { - num, err := getNumber(id) - if err != nil { - return false, fmt.Errorf("hash.Verify: %v", err) +// Verify returns true if ids maps to ksids. +func (vind *Hash) Verify(_ VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + if len(ids) != len(ksids) { + return false, fmt.Errorf("hash.Verify: length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) + } + for rowNum := range ids { + num, err := getNumber(ids[rowNum]) + if err != nil { + return false, fmt.Errorf("hash.Verify: %v", err) + } + if bytes.Compare(vhash(num), ksids[rowNum]) != 0 { + return false, nil + } } - return bytes.Compare(vhash(num), ksid) == 0, nil + return true, nil } -// ReverseMap returns the id from ksid. -func (vind *Hash) ReverseMap(_ VCursor, ksid []byte) (interface{}, error) { - return vunhash(ksid) +// ReverseMap returns the ids from ksids. +func (vind *Hash) ReverseMap(_ VCursor, ksids [][]byte) ([]interface{}, error) { + reverseIds := make([]interface{}, len(ksids)) + var err error + for rownum, keyspaceID := range ksids { + reverseIds[rownum], err = vunhash(keyspaceID) + if err != nil { + return reverseIds, err + } + } + return reverseIds, nil } var block3DES cipher.Block diff --git a/go/vt/vtgate/vindexes/hash_test.go b/go/vt/vtgate/vindexes/hash_test.go index f63f3b1ef6d..7a030dcf1c9 100644 --- a/go/vt/vtgate/vindexes/hash_test.go +++ b/go/vt/vtgate/vindexes/hash_test.go @@ -44,7 +44,7 @@ func TestHashMap(t *testing.T) { } func TestHashVerify(t *testing.T) { - success, err := hash.Verify(nil, 1, []byte("\x16k@\xb4J\xbaK\xd6")) + success, err := hash.Verify(nil, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { t.Error(err) } @@ -54,11 +54,11 @@ func TestHashVerify(t *testing.T) { } func TestHashReverseMap(t *testing.T) { - got, err := hash.(Reversible).ReverseMap(nil, []byte("\x16k@\xb4J\xbaK\xd6")) + got, err := hash.(Reversible).ReverseMap(nil, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { t.Error(err) } - if got.(int64) != 1 { + if got[0].(int64) != 1 { t.Errorf("ReverseMap(): %+v, want 1", got) } } diff --git a/go/vt/vtgate/vindexes/lookup.go b/go/vt/vtgate/vindexes/lookup.go index 6a3dcdbef8a..b5acdcfbff2 100644 --- a/go/vt/vtgate/vindexes/lookup.go +++ b/go/vt/vtgate/vindexes/lookup.go @@ -38,14 +38,14 @@ func (vindex *LookupNonUnique) Map(vcursor VCursor, ids []interface{}) ([][][]by return vindex.lkp.MapNonUniqueLookup(vcursor, ids) } -// Verify returns true if id maps to ksid. -func (vindex *LookupNonUnique) Verify(vcursor VCursor, id interface{}, ksid []byte) (bool, error) { - return vindex.lkp.Verify(vcursor, id, ksid) +// Verify returns true if ids maps to ksids. +func (vindex *LookupNonUnique) Verify(vcursor VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + return vindex.lkp.Verify(vcursor, ids, ksids) } // Create reserves the id by inserting it into the vindex table. -func (vindex *LookupNonUnique) Create(vcursor VCursor, id interface{}, ksid []byte) error { - return vindex.lkp.Create(vcursor, id, ksid) +func (vindex *LookupNonUnique) Create(vcursor VCursor, id []interface{}, ksids [][]byte) error { + return vindex.lkp.Create(vcursor, id, ksids) } // Delete deletes the entry from the vindex table. @@ -88,14 +88,14 @@ func (vindex *LookupUnique) Map(vcursor VCursor, ids []interface{}) ([][]byte, e return vindex.lkp.MapUniqueLookup(vcursor, ids) } -// Verify returns true if id maps to ksid. -func (vindex *LookupUnique) Verify(vcursor VCursor, id interface{}, ksid []byte) (bool, error) { - return vindex.lkp.Verify(vcursor, id, ksid) +// Verify returns true if ids maps to ksids. +func (vindex *LookupUnique) Verify(vcursor VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + return vindex.lkp.Verify(vcursor, ids, ksids) } // Create reserves the id by inserting it into the vindex table. -func (vindex *LookupUnique) Create(vcursor VCursor, id interface{}, ksid []byte) error { - return vindex.lkp.Create(vcursor, id, ksid) +func (vindex *LookupUnique) Create(vcursor VCursor, id []interface{}, ksids [][]byte) error { + return vindex.lkp.Create(vcursor, id, ksids) } // Delete deletes the entry from the vindex table. diff --git a/go/vt/vtgate/vindexes/lookup_hash.go b/go/vt/vtgate/vindexes/lookup_hash.go index c74d457d3b7..83c5779f259 100644 --- a/go/vt/vtgate/vindexes/lookup_hash.go +++ b/go/vt/vtgate/vindexes/lookup_hash.go @@ -45,14 +45,14 @@ func (vind *LookupHash) Map(vcursor VCursor, ids []interface{}) ([][][]byte, err return vind.lkp.MapNonUniqueLookup(vcursor, ids) } -// Verify returns true if id maps to ksid. -func (vind *LookupHash) Verify(vcursor VCursor, id interface{}, ksid []byte) (bool, error) { - return vind.lkp.Verify(vcursor, id, ksid) +// Verify returns true if ids maps to ksids. +func (vind *LookupHash) Verify(vcursor VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + return vind.lkp.Verify(vcursor, ids, ksids) } // Create reserves the id by inserting it into the vindex table. -func (vind *LookupHash) Create(vcursor VCursor, id interface{}, ksid []byte) error { - return vind.lkp.Create(vcursor, id, ksid) +func (vind *LookupHash) Create(vcursor VCursor, id []interface{}, ksids [][]byte) error { + return vind.lkp.Create(vcursor, id, ksids) } // Delete deletes the entry from the vindex table. @@ -97,14 +97,14 @@ func (vind *LookupHashUnique) Map(vcursor VCursor, ids []interface{}) ([][]byte, return vind.lkp.MapUniqueLookup(vcursor, ids) } -// Verify returns true if id maps to ksid. -func (vind *LookupHashUnique) Verify(vcursor VCursor, id interface{}, ksid []byte) (bool, error) { - return vind.lkp.Verify(vcursor, id, ksid) +// Verify returns true if ids maps to ksids. +func (vind *LookupHashUnique) Verify(vcursor VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + return vind.lkp.Verify(vcursor, ids, ksids) } // Create reserves the id by inserting it into the vindex table. -func (vind *LookupHashUnique) Create(vcursor VCursor, id interface{}, ksid []byte) error { - return vind.lkp.Create(vcursor, id, ksid) +func (vind *LookupHashUnique) Create(vcursor VCursor, id []interface{}, ksids [][]byte) error { + return vind.lkp.Create(vcursor, id, ksids) } // Delete deletes the entry from the vindex table. diff --git a/go/vt/vtgate/vindexes/lookup_hash_test.go b/go/vt/vtgate/vindexes/lookup_hash_test.go index 2b410f91498..9aeaa392f83 100644 --- a/go/vt/vtgate/vindexes/lookup_hash_test.go +++ b/go/vt/vtgate/vindexes/lookup_hash_test.go @@ -92,7 +92,7 @@ func TestLookupHashMap(t *testing.T) { func TestLookupHashVerify(t *testing.T) { vc := &vcursor{numRows: 1} - success, err := lhm.Verify(vc, 1, []byte("\x16k@\xb4J\xbaK\xd6")) + success, err := lhm.Verify(vc, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { t.Error(err) } @@ -103,15 +103,15 @@ func TestLookupHashVerify(t *testing.T) { func TestLookupHashCreate(t *testing.T) { vc := &vcursor{} - err := lhm.(Lookup).Create(vc, 1, []byte("\x16k@\xb4J\xbaK\xd6")) + err := lhm.(Lookup).Create(vc, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { t.Error(err) } wantQuery := &querytypes.BoundQuery{ - Sql: "insert into t(fromc, toc) values(:fromc, :toc)", + Sql: "insert into t(fromc,toc) values(:fromc0,:toc0)", BindVariables: map[string]interface{}{ - "fromc": 1, - "toc": int64(1), + "fromc0": 1, + "toc0": int64(1), }, } if !reflect.DeepEqual(vc.bq, wantQuery) { diff --git a/go/vt/vtgate/vindexes/lookup_hash_unique_test.go b/go/vt/vtgate/vindexes/lookup_hash_unique_test.go index 14f7ab607b7..2386c1e81d2 100644 --- a/go/vt/vtgate/vindexes/lookup_hash_unique_test.go +++ b/go/vt/vtgate/vindexes/lookup_hash_unique_test.go @@ -44,7 +44,7 @@ func TestLookupHashUniqueMap(t *testing.T) { func TestLookupHashUniqueVerify(t *testing.T) { vc := &vcursor{numRows: 1} - success, err := lhu.Verify(vc, 1, []byte("\x16k@\xb4J\xbaK\xd6")) + success, err := lhu.Verify(vc, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { t.Error(err) } @@ -55,15 +55,15 @@ func TestLookupHashUniqueVerify(t *testing.T) { func TestLookupHashUniqueCreate(t *testing.T) { vc := &vcursor{} - err := lhu.(Lookup).Create(vc, 1, []byte("\x16k@\xb4J\xbaK\xd6")) + err := lhu.(Lookup).Create(vc, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { t.Error(err) } wantQuery := &querytypes.BoundQuery{ - Sql: "insert into t(fromc, toc) values(:fromc, :toc)", + Sql: "insert into t(fromc,toc) values(:fromc0,:toc0)", BindVariables: map[string]interface{}{ - "fromc": 1, - "toc": int64(1), + "fromc0": 1, + "toc0": int64(1), }, } if !reflect.DeepEqual(vc.bq, wantQuery) { diff --git a/go/vt/vtgate/vindexes/lookup_internal.go b/go/vt/vtgate/vindexes/lookup_internal.go index 87f52e72398..2e41a16c2f3 100644 --- a/go/vt/vtgate/vindexes/lookup_internal.go +++ b/go/vt/vtgate/vindexes/lookup_internal.go @@ -1,7 +1,10 @@ package vindexes import ( + "bytes" "fmt" + "strconv" + "strings" ) // lookup implements the functions for the Lookup vindexes. @@ -13,18 +16,18 @@ type lookup struct { isHashedIndex bool } -func (lkp *lookup) Init(m map[string]string, isHashed bool) { - t := m["table"] - from := m["from"] - to := m["to"] +func (lkp *lookup) Init(lookupQueryParams map[string]string, isHashed bool) { + table := lookupQueryParams["table"] + fromCol := lookupQueryParams["from"] + toCol := lookupQueryParams["to"] - lkp.Table = t - lkp.From = from - lkp.To = to - lkp.sel = fmt.Sprintf("select %s from %s where %s = :%s", to, t, from, from) - lkp.ver = fmt.Sprintf("select %s from %s where %s = :%s and %s = :%s", from, t, from, from, to, to) - lkp.ins = fmt.Sprintf("insert into %s(%s, %s) values(:%s, :%s)", t, from, to, from, to) - lkp.del = fmt.Sprintf("delete from %s where %s = :%s and %s = :%s", t, from, from, to, to) + lkp.Table = table + lkp.From = fromCol + lkp.To = toCol + lkp.sel = fmt.Sprintf("select %s from %s where %s = :%s", toCol, table, fromCol, fromCol) + lkp.ver = fmt.Sprintf("select %s from %s where %s = :%s and %s = :%s", fromCol, table, fromCol, fromCol, toCol, toCol) + lkp.ins = fmt.Sprintf("insert into %s(%s, %s) values", table, fromCol, toCol) + lkp.del = fmt.Sprintf("delete from %s where %s = :%s and %s = :%s", table, fromCol, fromCol, toCol, toCol) lkp.isHashedIndex = isHashed } @@ -87,47 +90,84 @@ func (lkp *lookup) MapNonUniqueLookup(vcursor VCursor, ids []interface{}) ([][][ return out, nil } -// Verify returns true if id maps to ksid. -func (lkp *lookup) Verify(vcursor VCursor, id interface{}, ksid []byte) (bool, error) { - var val interface{} +// Verify returns true if ids maps to ksids. +func (lkp *lookup) Verify(vcursor VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + var fromColBuff bytes.Buffer + var toColBuff bytes.Buffer var err error - if lkp.isHashedIndex { - val, err = vunhash(ksid) - if err != nil { - return false, fmt.Errorf("lookup.Verify: %v", err) + if len(ids) != len(ksids) { + return false, fmt.Errorf("lookup.Verify:length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) + } + val := make([]interface{}, len(ksids)) + bindVars := make(map[string]interface{}, 2*len(ids)) + fromColBuff.WriteString("(") + toColBuff.WriteString("(") + for rowNum, keyspaceID := range ksids { + fromStr := lkp.From + strconv.Itoa(rowNum) + toStr := lkp.To + strconv.Itoa(rowNum) + fromColBuff.WriteString(":") + fromColBuff.WriteString(fromStr) + fromColBuff.WriteString(",") + toColBuff.WriteString(":") + toColBuff.WriteString(toStr) + toColBuff.WriteString(",") + if lkp.isHashedIndex { + val[rowNum], err = vunhash(keyspaceID) + if err != nil { + return false, fmt.Errorf("lookup.Verify: %v", err) + } + } else { + val[rowNum] = keyspaceID } - } else { - val = ksid + bindVars[fromStr] = ids[rowNum] + bindVars[toStr] = val[rowNum] } - result, err := vcursor.Execute(lkp.ver, map[string]interface{}{ - lkp.From: id, - lkp.To: val, - }) + lkp.ver = fmt.Sprintf("select %s from %s where %s in %s and %s in %s", lkp.From, lkp.Table, lkp.From, strings.Trim(fromColBuff.String(), ",")+")", lkp.To, strings.Trim(toColBuff.String(), ",")+")") + result, err := vcursor.Execute(lkp.ver, bindVars) if err != nil { return false, fmt.Errorf("lookup.Verify: %v", err) } - if len(result.Rows) == 0 { + if len(result.Rows) != len(ids) { return false, nil } return true, nil } -// Create creates an association between id and ksid by inserting a row in the vindex table. -func (lkp *lookup) Create(vcursor VCursor, id interface{}, ksid []byte) error { - var val interface{} +// Create creates an association between ids and ksids by inserting a row in the vindex table. +func (lkp *lookup) Create(vcursor VCursor, ids []interface{}, ksids [][]byte) error { + var insBuffer bytes.Buffer var err error - if lkp.isHashedIndex { - val, err = vunhash(ksid) - if err != nil { - return fmt.Errorf("lookup.Create: %v", err) + if len(ids) != len(ksids) { + return fmt.Errorf("lookup.Create:length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) + } + val := make([]interface{}, len(ksids)) + insBuffer.WriteString("insert into ") + insBuffer.WriteString(lkp.Table) + insBuffer.WriteString("(") + insBuffer.WriteString(lkp.From) + insBuffer.WriteString(",") + insBuffer.WriteString(lkp.To) + insBuffer.WriteString(") values") + bindVars := make(map[string]interface{}, 2*len(ids)) + for rowNum, keyspaceID := range ksids { + fromStr := lkp.From + strconv.Itoa(rowNum) + toStr := lkp.To + strconv.Itoa(rowNum) + insBuffer.WriteString("(:") + insBuffer.WriteString(fromStr + ",:" + toStr) + insBuffer.WriteString("),") + if lkp.isHashedIndex { + val[rowNum], err = vunhash(keyspaceID) + if err != nil { + return fmt.Errorf("lookup.Create: %v", err) + } + } else { + val[rowNum] = keyspaceID } - } else { - val = ksid + bindVars[fromStr] = ids[rowNum] + bindVars[toStr] = val[rowNum] } - if _, err := vcursor.Execute(lkp.ins, map[string]interface{}{ - lkp.From: id, - lkp.To: val, - }); err != nil { + lkp.ins = strings.Trim(insBuffer.String(), ",") + if _, err := vcursor.Execute(lkp.ins, bindVars); err != nil { return fmt.Errorf("lookup.Create: %v", err) } return nil diff --git a/go/vt/vtgate/vindexes/lookup_test.go b/go/vt/vtgate/vindexes/lookup_test.go index a954b1610fb..f3172d63778 100644 --- a/go/vt/vtgate/vindexes/lookup_test.go +++ b/go/vt/vtgate/vindexes/lookup_test.go @@ -11,13 +11,13 @@ var lookupUnique Vindex var lookupNonUnique Vindex func init() { - lunique, err := CreateVindex("lookup_unique", "lookupUnique", map[string]string{"table": "t", "from": "fromc", "to": "toc"}) + lkpunique, err := CreateVindex("lookup_unique", "lookupUnique", map[string]string{"table": "t", "from": "fromc", "to": "toc"}) if err != nil { panic(err) } - lnonunique, err := CreateVindex("lookup", "lookupNonUnique", map[string]string{"table": "t", "from": "fromc", "to": "toc"}) - lookupUnique = lunique - lookupNonUnique = lnonunique + lkpnonunique, err := CreateVindex("lookup", "lookupNonUnique", map[string]string{"table": "t", "from": "fromc", "to": "toc"}) + lookupUnique = lkpunique + lookupNonUnique = lkpnonunique } func TestLookupUniqueCost(t *testing.T) { @@ -34,7 +34,7 @@ func TestLookupNonUniqueCost(t *testing.T) { func TestLookupUniqueVerify(t *testing.T) { vc := &vcursor{numRows: 1} - success, err := lookupUnique.Verify(vc, 1, []byte("test")) + success, err := lookupUnique.Verify(vc, []interface{}{1}, [][]byte{[]byte("test")}) if err != nil { t.Error(err) } @@ -45,15 +45,15 @@ func TestLookupUniqueVerify(t *testing.T) { func TestLookupUniqueCreate(t *testing.T) { vc := &vcursor{} - err := lookupUnique.(Lookup).Create(vc, 1, []byte("test")) + err := lookupUnique.(Lookup).Create(vc, []interface{}{1}, [][]byte{[]byte("test")}) if err != nil { t.Error(err) } wantQuery := &querytypes.BoundQuery{ - Sql: "insert into t(fromc, toc) values(:fromc, :toc)", + Sql: "insert into t(fromc,toc) values(:fromc0,:toc0)", BindVariables: map[string]interface{}{ - "fromc": 1, - "toc": []byte("test"), + "fromc0": 1, + "toc0": []byte("test"), }, } if !reflect.DeepEqual(vc.bq, wantQuery) { diff --git a/go/vt/vtgate/vindexes/numeric.go b/go/vt/vtgate/vindexes/numeric.go index 39812b8267f..db96e307fb0 100644 --- a/go/vt/vtgate/vindexes/numeric.go +++ b/go/vt/vtgate/vindexes/numeric.go @@ -31,18 +31,26 @@ func (*Numeric) Cost() int { return 0 } -// Verify returns true if id and ksid match. -func (*Numeric) Verify(_ VCursor, id interface{}, ksid []byte) (bool, error) { - var keybytes [8]byte - num, err := getNumber(id) - if err != nil { - return false, fmt.Errorf("Numeric.Verify: %v", err) +// Verify returns true if ids and ksids match. +func (*Numeric) Verify(_ VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + if len(ids) != len(ksids) { + return false, fmt.Errorf("Numeric.Verify: length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) } - binary.BigEndian.PutUint64(keybytes[:], uint64(num)) - return bytes.Compare(keybytes[:], ksid) == 0, nil + for rowNum := range ids { + var keybytes [8]byte + num, err := getNumber(ids[rowNum]) + if err != nil { + return false, fmt.Errorf("Numeric.Verify: %v", err) + } + binary.BigEndian.PutUint64(keybytes[:], uint64(num)) + if bytes.Compare(keybytes[:], ksids[rowNum]) != 0 { + return false, nil + } + } + return true, nil } -// Map returns the associated keyspae ids for the given ids. +// Map returns the associated keyspace ids for the given ids. func (*Numeric) Map(_ VCursor, ids []interface{}) ([][]byte, error) { out := make([][]byte, 0, len(ids)) for _, id := range ids { @@ -57,12 +65,16 @@ func (*Numeric) Map(_ VCursor, ids []interface{}) ([][]byte, error) { return out, nil } -// ReverseMap returns the associated id for the ksid. -func (*Numeric) ReverseMap(_ VCursor, ksid []byte) (interface{}, error) { - if len(ksid) != 8 { - return nil, fmt.Errorf("Numeric.ReverseMap: length of keyspace is not 8: %d", len(ksid)) +// ReverseMap returns the associated ids for the ksids. +func (*Numeric) ReverseMap(_ VCursor, ksids [][]byte) ([]interface{}, error) { + var reverseIds = make([]interface{}, len(ksids)) + for rownum, keyspaceID := range ksids { + if len(keyspaceID) != 8 { + return nil, fmt.Errorf("Numeric.ReverseMap: length of keyspaceId is not 8: %d", len(keyspaceID)) + } + reverseIds[rownum] = binary.BigEndian.Uint64([]byte(keyspaceID)) } - return binary.BigEndian.Uint64([]byte(ksid)), nil + return reverseIds, nil } func init() { diff --git a/go/vt/vtgate/vindexes/numeric_static_map.go b/go/vt/vtgate/vindexes/numeric_static_map.go index 11613dd2874..3080440b728 100644 --- a/go/vt/vtgate/vindexes/numeric_static_map.go +++ b/go/vt/vtgate/vindexes/numeric_static_map.go @@ -56,21 +56,27 @@ func (*NumericStaticMap) Cost() int { return 1 } -// Verify returns true if id and ksid match. -func (vind *NumericStaticMap) Verify(_ VCursor, id interface{}, ksid []byte) (bool, error) { - var keybytes [8]byte - num, err := getNumber(id) - if err != nil { - return false, fmt.Errorf("NumericStaticMap.Verify: %v", err) +// Verify returns true if ids and ksids match. +func (vind *NumericStaticMap) Verify(_ VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + if len(ids) != len(ksids) { + return false, fmt.Errorf("NumericStaticMap.Verify: length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) } - - lookupNum, ok := vind.lookup[uint64(num)] - if ok { - num = int64(lookupNum) + for rowNum := range ids { + var keybytes [8]byte + num, err := getNumber(ids[rowNum]) + if err != nil { + return false, fmt.Errorf("NumericStaticMap.Verify: %v", err) + } + lookupNum, ok := vind.lookup[uint64(num)] + if ok { + num = int64(lookupNum) + } + binary.BigEndian.PutUint64(keybytes[:], uint64(num)) + if bytes.Compare(keybytes[:], ksids[rowNum]) != 0 { + return false, nil + } } - - binary.BigEndian.PutUint64(keybytes[:], uint64(num)) - return bytes.Compare(keybytes[:], ksid) == 0, nil + return true, nil } // Map returns the associated keyspace ids for the given ids. diff --git a/go/vt/vtgate/vindexes/numeric_static_map_test.go b/go/vt/vtgate/vindexes/numeric_static_map_test.go index f51f70c1ed6..77d4053ac24 100644 --- a/go/vt/vtgate/vindexes/numeric_static_map_test.go +++ b/go/vt/vtgate/vindexes/numeric_static_map_test.go @@ -86,7 +86,7 @@ func TestNumericStaticMapVerify(t *testing.T) { t.Fatalf("failed to create vindex: %v", err) } - success, err := numericStaticMap.Verify(nil, 1, []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) + success, err := numericStaticMap.Verify(nil, []interface{}{1}, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) if err != nil { t.Error(err) } @@ -101,7 +101,7 @@ func TestNumericStaticMapVerifyBadData(t *testing.T) { t.Fatalf("failed to create vindex: %v", err) } - _, err = numericStaticMap.Verify(nil, 1.1, []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) + _, err = numericStaticMap.Verify(nil, []interface{}{1.1}, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) want := `NumericStaticMap.Verify: getNumber: unexpected type for 1.1: float64` if err == nil || err.Error() != want { t.Errorf("numericStaticMap.Map: %v, want %v", err, want) diff --git a/go/vt/vtgate/vindexes/numeric_test.go b/go/vt/vtgate/vindexes/numeric_test.go index 937c6e3c976..1e36664ea6e 100644 --- a/go/vt/vtgate/vindexes/numeric_test.go +++ b/go/vt/vtgate/vindexes/numeric_test.go @@ -62,7 +62,7 @@ func TestNumericMapBadData(t *testing.T) { } func TestNumericVerify(t *testing.T) { - success, err := numeric.Verify(nil, 1, []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) + success, err := numeric.Verify(nil, []interface{}{1}, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) if err != nil { t.Error(err) } @@ -72,7 +72,7 @@ func TestNumericVerify(t *testing.T) { } func TestNumericVerifyBadData(t *testing.T) { - _, err := numeric.Verify(nil, 1.1, []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) + _, err := numeric.Verify(nil, []interface{}{1.1}, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) want := `Numeric.Verify: getNumber: unexpected type for 1.1: float64` if err == nil || err.Error() != want { t.Errorf("numeric.Map: %v, want %v", err, want) @@ -80,18 +80,18 @@ func TestNumericVerifyBadData(t *testing.T) { } func TestNumericReverseMap(t *testing.T) { - got, err := numeric.(Reversible).ReverseMap(nil, []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) + got, err := numeric.(Reversible).ReverseMap(nil, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) if err != nil { t.Error(err) } - if got.(uint64) != 1 { + if got[0].(uint64) != 1 { t.Errorf("ReverseMap(): %+v, want 1", got) } } func TestNumericReverseMapBadData(t *testing.T) { - _, err := numeric.(Reversible).ReverseMap(nil, []byte("aa")) - want := `Numeric.ReverseMap: length of keyspace is not 8: 2` + _, err := numeric.(Reversible).ReverseMap(nil, [][]byte{[]byte("aa")}) + want := `Numeric.ReverseMap: length of keyspaceId is not 8: 2` if err == nil || err.Error() != want { t.Errorf("numeric.Map: %v, want %v", err, want) } diff --git a/go/vt/vtgate/vindexes/unicodeloosemd5.go b/go/vt/vtgate/vindexes/unicodeloosemd5.go index 1df5237fe7c..f8924ccce23 100644 --- a/go/vt/vtgate/vindexes/unicodeloosemd5.go +++ b/go/vt/vtgate/vindexes/unicodeloosemd5.go @@ -34,13 +34,21 @@ func (vind *UnicodeLooseMD5) Cost() int { return 1 } -// Verify returns true if id maps to ksid. -func (vind *UnicodeLooseMD5) Verify(_ VCursor, id interface{}, ksid []byte) (bool, error) { - data, err := unicodeHash(id) - if err != nil { - return false, fmt.Errorf("UnicodeLooseMD5.Verify: %v", err) +// Verify returns true if ids maps to ksids. +func (vind *UnicodeLooseMD5) Verify(_ VCursor, ids []interface{}, ksids [][]byte) (bool, error) { + if len(ids) != len(ksids) { + return false, fmt.Errorf("BinaryMD5_hash.Verify: length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) + } + for rowNum := range ids { + data, err := unicodeHash(ids[rowNum]) + if err != nil { + return false, fmt.Errorf("BinaryMD5_hash.Verify: %v", err) + } + if bytes.Compare(data, ksids[rowNum]) != 0 { + return false, nil + } } - return bytes.Compare(data, ksid) == 0, nil + return true, nil } // Map returns the corresponding keyspace id values for the given ids. diff --git a/go/vt/vtgate/vindexes/unicodeloosemd5_test.go b/go/vt/vtgate/vindexes/unicodeloosemd5_test.go index 47fd45b7774..383704c4e33 100644 --- a/go/vt/vtgate/vindexes/unicodeloosemd5_test.go +++ b/go/vt/vtgate/vindexes/unicodeloosemd5_test.go @@ -61,7 +61,7 @@ func TestUnicodeLooseMD5(t *testing.T) { if out != tcase.out { t.Errorf("Map(%#v): %#v, want %#v", tcase.in, out, tcase.out) } - ok, err := charVindex.Verify(nil, []byte(tcase.in), []byte(tcase.out)) + ok, err := charVindex.Verify(nil, []interface{}{tcase.in}, [][]byte{[]byte(tcase.out)}) if err != nil { t.Error(err) } diff --git a/go/vt/vtgate/vindexes/vindex.go b/go/vt/vtgate/vindexes/vindex.go index 968776abe53..b1524adfc53 100644 --- a/go/vt/vtgate/vindexes/vindex.go +++ b/go/vt/vtgate/vindexes/vindex.go @@ -37,8 +37,8 @@ type Vindex interface { Cost() int // Verify must be implented by all vindexes. It should return - // true if the id can be mapped to the keyspace id. - Verify(cursor VCursor, id interface{}, ks []byte) (bool, error) + // true if the ids can be mapped to the keyspace ids. + Verify(cursor VCursor, ids []interface{}, ksids [][]byte) (bool, error) } // Unique defines the interface for a unique vindex. @@ -65,7 +65,7 @@ func IsUnique(v Vindex) bool { // is optional. If present, VTGate can use it to // fill column values based on the target keyspace id. type Reversible interface { - ReverseMap(cursor VCursor, ks []byte) (interface{}, error) + ReverseMap(cursor VCursor, ks [][]byte) ([]interface{}, error) } // A Functional vindex is an index that can compute @@ -86,7 +86,7 @@ type Functional interface { // keyspace_id, which must be supplied, can be used // to determine the target shard for an insert operation. type Lookup interface { - Create(VCursor, interface{}, []byte) error + Create(VCursor, []interface{}, [][]byte) error Delete(VCursor, []interface{}, []byte) error } diff --git a/go/vt/vtgate/vindexes/vschema_test.go b/go/vt/vtgate/vindexes/vschema_test.go index 61814c77e3b..31cd11ed1f7 100644 --- a/go/vt/vtgate/vindexes/vschema_test.go +++ b/go/vt/vtgate/vindexes/vschema_test.go @@ -20,10 +20,10 @@ type stFU struct { Params map[string]string } -func (v *stFU) String() string { return v.name } -func (*stFU) Cost() int { return 1 } -func (*stFU) Verify(VCursor, interface{}, []byte) (bool, error) { return false, nil } -func (*stFU) Map(VCursor, []interface{}) ([][]byte, error) { return nil, nil } +func (v *stFU) String() string { return v.name } +func (*stFU) Cost() int { return 1 } +func (*stFU) Verify(VCursor, []interface{}, [][]byte) (bool, error) { return false, nil } +func (*stFU) Map(VCursor, []interface{}) ([][]byte, error) { return nil, nil } func NewSTFU(name string, params map[string]string) (Vindex, error) { return &stFU{name: name, Params: params}, nil @@ -35,9 +35,9 @@ type stF struct { Params map[string]string } -func (v *stF) String() string { return v.name } -func (*stF) Cost() int { return 0 } -func (*stF) Verify(VCursor, interface{}, []byte) (bool, error) { return false, nil } +func (v *stF) String() string { return v.name } +func (*stF) Cost() int { return 0 } +func (*stF) Verify(VCursor, []interface{}, [][]byte) (bool, error) { return false, nil } func NewSTF(name string, params map[string]string) (Vindex, error) { return &stF{name: name, Params: params}, nil @@ -49,12 +49,12 @@ type stLN struct { Params map[string]string } -func (v *stLN) String() string { return v.name } -func (*stLN) Cost() int { return 0 } -func (*stLN) Verify(VCursor, interface{}, []byte) (bool, error) { return false, nil } -func (*stLN) Map(VCursor, []interface{}) ([][][]byte, error) { return nil, nil } -func (*stLN) Create(VCursor, interface{}, []byte) error { return nil } -func (*stLN) Delete(VCursor, []interface{}, []byte) error { return nil } +func (v *stLN) String() string { return v.name } +func (*stLN) Cost() int { return 0 } +func (*stLN) Verify(VCursor, []interface{}, [][]byte) (bool, error) { return false, nil } +func (*stLN) Map(VCursor, []interface{}) ([][][]byte, error) { return nil, nil } +func (*stLN) Create(VCursor, []interface{}, [][]byte) error { return nil } +func (*stLN) Delete(VCursor, []interface{}, []byte) error { return nil } func NewSTLN(name string, params map[string]string) (Vindex, error) { return &stLN{name: name, Params: params}, nil @@ -66,12 +66,12 @@ type stLU struct { Params map[string]string } -func (v *stLU) String() string { return v.name } -func (*stLU) Cost() int { return 2 } -func (*stLU) Verify(VCursor, interface{}, []byte) (bool, error) { return false, nil } -func (*stLU) Map(VCursor, []interface{}) ([][]byte, error) { return nil, nil } -func (*stLU) Create(VCursor, interface{}, []byte) error { return nil } -func (*stLU) Delete(VCursor, []interface{}, []byte) error { return nil } +func (v *stLU) String() string { return v.name } +func (*stLU) Cost() int { return 2 } +func (*stLU) Verify(VCursor, []interface{}, [][]byte) (bool, error) { return false, nil } +func (*stLU) Map(VCursor, []interface{}) ([][]byte, error) { return nil, nil } +func (*stLU) Create(VCursor, []interface{}, [][]byte) error { return nil } +func (*stLU) Delete(VCursor, []interface{}, []byte) error { return nil } func NewSTLU(name string, params map[string]string) (Vindex, error) { return &stLU{name: name, Params: params}, nil From 4fbff447be3d6c55712babbe82ebf0593771a904 Mon Sep 17 00:00:00 2001 From: Ashudeep Sharma Date: Sat, 31 Dec 2016 00:07:26 +0530 Subject: [PATCH 2/5] Rewriting lkp.ver query using and/or clauses --- go/vt/vtgate/router_dml_test.go | 12 ++++++------ go/vt/vtgate/vindexes/lookup_internal.go | 23 ++++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/go/vt/vtgate/router_dml_test.go b/go/vt/vtgate/router_dml_test.go index 2137c3eea83..b493d553605 100644 --- a/go/vt/vtgate/router_dml_test.go +++ b/go/vt/vtgate/router_dml_test.go @@ -551,7 +551,7 @@ func TestInsertLookupUnowned(t *testing.T) { t.Errorf("sbc.Queries: %+v, want %+v\n", sbc.Queries, wantQueries) } wantQueries = []querytypes.BoundQuery{{ - Sql: "select music_id from music_user_map where music_id in (:music_id0) and user_id in (:user_id0)", + Sql: "select music_id from music_user_map where ((music_id = :music_id0 and user_id = :user_id0))", BindVariables: map[string]interface{}{ "music_id0": int64(3), "user_id0": int64(2), @@ -668,11 +668,11 @@ func TestInsertFail(t *testing.T) { t.Errorf("routerExec: %v, want prefix %v", err, want) } - //_, err = routerExec(router, "insert into music_extra(user_id, music_id) values (1, null)", nil) - //want = "execInsertSharded: getInsertShardedRoute: value must be supplied for column music_id" - //if err == nil || err.Error() != want { - // t.Errorf("routerExec: %v, want %v", err, want) - //} + _, err = routerExec(router, "insert into music_extra(user_id, music_id) values (1, null)", nil) + want = "execInsertSharded: getInsertShardedRoute: value must be supplied for column music_id" + if err == nil || err.Error() != want { + t.Errorf("routerExec: %v, want %v", err, want) + } _, err = routerExec(router, "insert into music_extra_reversed(music_id, user_id) values (1, 'aa')", nil) want = `execInsertSharded: getInsertShardedRoute: hash.Verify: parseString: strconv.ParseUint: parsing "aa": invalid syntax` diff --git a/go/vt/vtgate/vindexes/lookup_internal.go b/go/vt/vtgate/vindexes/lookup_internal.go index 2e41a16c2f3..f059a93ed71 100644 --- a/go/vt/vtgate/vindexes/lookup_internal.go +++ b/go/vt/vtgate/vindexes/lookup_internal.go @@ -92,25 +92,26 @@ func (lkp *lookup) MapNonUniqueLookup(vcursor VCursor, ids []interface{}) ([][][ // Verify returns true if ids maps to ksids. func (lkp *lookup) Verify(vcursor VCursor, ids []interface{}, ksids [][]byte) (bool, error) { - var fromColBuff bytes.Buffer - var toColBuff bytes.Buffer + var colBuff bytes.Buffer var err error if len(ids) != len(ksids) { return false, fmt.Errorf("lookup.Verify:length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) } val := make([]interface{}, len(ksids)) bindVars := make(map[string]interface{}, 2*len(ids)) - fromColBuff.WriteString("(") - toColBuff.WriteString("(") + colBuff.WriteString("(") for rowNum, keyspaceID := range ksids { fromStr := lkp.From + strconv.Itoa(rowNum) toStr := lkp.To + strconv.Itoa(rowNum) - fromColBuff.WriteString(":") - fromColBuff.WriteString(fromStr) - fromColBuff.WriteString(",") - toColBuff.WriteString(":") - toColBuff.WriteString(toStr) - toColBuff.WriteString(",") + colBuff.WriteString("(") + colBuff.WriteString(lkp.From) + colBuff.WriteString("=:") + colBuff.WriteString(fromStr) + colBuff.WriteString(" and ") + colBuff.WriteString(lkp.To) + colBuff.WriteString("=:") + colBuff.WriteString(toStr) + colBuff.WriteString(")or") if lkp.isHashedIndex { val[rowNum], err = vunhash(keyspaceID) if err != nil { @@ -122,7 +123,7 @@ func (lkp *lookup) Verify(vcursor VCursor, ids []interface{}, ksids [][]byte) (b bindVars[fromStr] = ids[rowNum] bindVars[toStr] = val[rowNum] } - lkp.ver = fmt.Sprintf("select %s from %s where %s in %s and %s in %s", lkp.From, lkp.Table, lkp.From, strings.Trim(fromColBuff.String(), ",")+")", lkp.To, strings.Trim(toColBuff.String(), ",")+")") + lkp.ver = fmt.Sprintf("select %s from %s where %s", lkp.From, lkp.Table, strings.Trim(colBuff.String(),"or")+")") result, err := vcursor.Execute(lkp.ver, bindVars) if err != nil { return false, fmt.Errorf("lookup.Verify: %v", err) From 02a3b288a85e308fbcd59c87d942a3053e88b34b Mon Sep 17 00:00:00 2001 From: Ashudeep Sharma Date: Sat, 31 Dec 2016 00:07:53 +0530 Subject: [PATCH 3/5] Rewriting lkp.ver query using and/or clauses --- go/vt/vtgate/vindexes/lookup_internal.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/vt/vtgate/vindexes/lookup_internal.go b/go/vt/vtgate/vindexes/lookup_internal.go index f059a93ed71..1586d6bf26e 100644 --- a/go/vt/vtgate/vindexes/lookup_internal.go +++ b/go/vt/vtgate/vindexes/lookup_internal.go @@ -123,7 +123,7 @@ func (lkp *lookup) Verify(vcursor VCursor, ids []interface{}, ksids [][]byte) (b bindVars[fromStr] = ids[rowNum] bindVars[toStr] = val[rowNum] } - lkp.ver = fmt.Sprintf("select %s from %s where %s", lkp.From, lkp.Table, strings.Trim(colBuff.String(),"or")+")") + lkp.ver = fmt.Sprintf("select %s from %s where %s", lkp.From, lkp.Table, strings.Trim(colBuff.String(), "or")+")") result, err := vcursor.Execute(lkp.ver, bindVars) if err != nil { return false, fmt.Errorf("lookup.Verify: %v", err) From 16de87b053e674299de1e6dbf6cac5cb6d5d0265 Mon Sep 17 00:00:00 2001 From: Ashudeep Sharma Date: Thu, 5 Jan 2017 20:00:38 +0530 Subject: [PATCH 4/5] Incorporating comments and Adding tests to improve the code-coverage --- go/vt/vtgate/engine/route.go | 3 - go/vt/vtgate/vindexes/binary.go | 4 +- go/vt/vtgate/vindexes/binary_test.go | 49 +++++- go/vt/vtgate/vindexes/binarymd5_test.go | 39 ++++- go/vt/vtgate/vindexes/hash_test.go | 44 +++++ go/vt/vtgate/vindexes/lookup_hash_test.go | 38 +++-- go/vt/vtgate/vindexes/lookup_test.go | 159 +++++++++++++++++- .../vindexes/numeric_static_map_test.go | 54 +++--- go/vt/vtgate/vindexes/numeric_test.go | 34 +++- go/vt/vtgate/vindexes/unicodeloosemd5.go | 4 +- go/vt/vtgate/vindexes/unicodeloosemd5_test.go | 36 ++++ 11 files changed, 407 insertions(+), 57 deletions(-) diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go index cacd64eb36d..e141cadb9ae 100644 --- a/go/vt/vtgate/engine/route.go +++ b/go/vt/vtgate/engine/route.go @@ -803,9 +803,6 @@ func (route *Route) handleNonPrimary(vcursor VCursor, vindexKeys []interface{}, if err != nil { return err } - if vindexKeys == nil { - return fmt.Errorf("could not compute value for column %v", colVindex.Column) - } for rowNum, vindexKey := range vindexKeys { bv["_"+colVindex.Column.CompliantName()+strconv.Itoa(rowNum)] = vindexKey } diff --git a/go/vt/vtgate/vindexes/binary.go b/go/vt/vtgate/vindexes/binary.go index 1030faa75ed..d83a0b08704 100644 --- a/go/vt/vtgate/vindexes/binary.go +++ b/go/vt/vtgate/vindexes/binary.go @@ -22,7 +22,7 @@ func (vind *Binary) String() string { // Cost returns the cost as 1. func (vind *Binary) Cost() int { - return 0 + return 1 } // Verify returns true if ids maps to ksids. @@ -60,7 +60,7 @@ func (*Binary) ReverseMap(_ VCursor, ksids [][]byte) ([]interface{}, error) { var reverseIds = make([]interface{}, len(ksids)) for rownum, keyspaceID := range ksids { if keyspaceID == nil { - return nil, fmt.Errorf("Binary.ReverseMap: is nil") + return nil, fmt.Errorf("Binary.ReverseMap: keyspaceId is nil") } reverseIds[rownum] = []byte(keyspaceID) } diff --git a/go/vt/vtgate/vindexes/binary_test.go b/go/vt/vtgate/vindexes/binary_test.go index 6004e5e77cd..4c6672fa9c1 100644 --- a/go/vt/vtgate/vindexes/binary_test.go +++ b/go/vt/vtgate/vindexes/binary_test.go @@ -2,18 +2,25 @@ package vindexes import ( "bytes" + "strings" "testing" ) var binOnlyVindex Vindex func init() { - binOnlyVindex, _ = CreateVindex("binary", "vch", nil) + binOnlyVindex, _ = CreateVindex("binary", "binary_varchar", nil) } func TestBinaryCost(t *testing.T) { - if binOnlyVindex.Cost() != 0 { - t.Errorf("Cost(): %d, want 0", binOnlyVindex.Cost()) + if binOnlyVindex.Cost() != 1 { + t.Errorf("Cost(): %d, want 1", binOnlyVindex.Cost()) + } +} + +func TestBinaryString(t *testing.T) { + if strings.Compare("binary_varchar", binOnlyVindex.String()) != 0 { + t.Errorf("String(): %s, want binary_varchar", binOnlyVindex.String()) } } @@ -47,6 +54,35 @@ func TestBinary(t *testing.T) { t.Errorf("Verify(%#v): false, want true", tcase.in) } } + + //Negative Test Case + _, err := binOnlyVindex.(Unique).Map(nil, []interface{}{1}) + want := "Binary.Map :unexpected data type for getBytes: int" + if err.Error() != want { + t.Error(err) + } +} + +func TestBinaryVerifyNeg(t *testing.T) { + _, err := binOnlyVindex.Verify(nil, []interface{}{[]byte("test1"), []byte("test2")}, [][]byte{[]byte("test1")}) + want := "Binary.Verify: length of ids 2 doesn't match length of ksids 1" + if err.Error() != want { + t.Error(err.Error()) + } + + ok, err := binOnlyVindex.Verify(nil, []interface{}{[]byte("test2")}, [][]byte{[]byte("test1")}) + if err != nil { + t.Error(err) + } + if ok { + t.Errorf("Verify(%#v): true, want false", []byte("test2")) + } + + _, err = binOnlyVindex.Verify(nil, []interface{}{1}, [][]byte{[]byte("test1")}) + want = "Binary.Verify: unexpected data type for getBytes: int" + if err.Error() != want { + t.Error(err) + } } func TestBinaryReverseMap(t *testing.T) { @@ -57,4 +93,11 @@ func TestBinaryReverseMap(t *testing.T) { if bytes.Compare(got[0].([]byte), []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) != 0 { t.Errorf("ReverseMap(): %+v, want %+v", got, []byte("\x00\x00\x00\x00\x00\x00\x00\x01")) } + + //Negative Test + _, err = binOnlyVindex.(Reversible).ReverseMap(nil, [][]byte{[]byte(nil)}) + want := "Binary.ReverseMap: keyspaceId is nil" + if err.Error() != want { + t.Error(err) + } } diff --git a/go/vt/vtgate/vindexes/binarymd5_test.go b/go/vt/vtgate/vindexes/binarymd5_test.go index 5784595bf56..bfb3ae4f08a 100644 --- a/go/vt/vtgate/vindexes/binarymd5_test.go +++ b/go/vt/vtgate/vindexes/binarymd5_test.go @@ -3,13 +3,15 @@ package vindexes import ( "testing" + "strings" + "github.com/youtube/vitess/go/sqltypes" ) var binVindex Vindex func init() { - binVindex, _ = CreateVindex("binary_md5", "vch", nil) + binVindex, _ = CreateVindex("binary_md5", "binary_md5_varchar", nil) } func TestBinaryMD5Cost(t *testing.T) { @@ -18,6 +20,12 @@ func TestBinaryMD5Cost(t *testing.T) { } } +func TestBinaryMD5String(t *testing.T) { + if strings.Compare("binary_md5_varchar", binVindex.String()) != 0 { + t.Errorf("String(): %s, want binary_md5_varchar", binVindex.String()) + } +} + func TestBinaryMD5(t *testing.T) { tcases := []struct { in, out string @@ -48,6 +56,35 @@ func TestBinaryMD5(t *testing.T) { t.Errorf("Verify(%#v): false, want true", tcase.in) } } + + //Negative Test Case + _, err := binVindex.(Unique).Map(nil, []interface{}{1}) + want := "BinaryMd5.Map :unexpected data type for getBytes: int" + if err.Error() != want { + t.Error(err) + } +} + +func TestBinaryMD5VerifyNeg(t *testing.T) { + _, err := binVindex.Verify(nil, []interface{}{[]byte("test1"), []byte("test2")}, [][]byte{[]byte("test1")}) + want := "BinaryMD5_hash.Verify: length of ids 2 doesn't match length of ksids 1" + if err.Error() != want { + t.Error(err.Error()) + } + + ok, err := binVindex.Verify(nil, []interface{}{[]byte("test2")}, [][]byte{[]byte("test1")}) + if err != nil { + t.Error(err) + } + if ok { + t.Errorf("Verify(%#v): true, want false", []byte("test2")) + } + + _, err = binVindex.Verify(nil, []interface{}{1}, [][]byte{[]byte("test1")}) + want = "BinaryMD5_hash.Verify: unexpected data type for getBytes: int" + if err.Error() != want { + t.Error(err) + } } func TestSQLValue(t *testing.T) { diff --git a/go/vt/vtgate/vindexes/hash_test.go b/go/vt/vtgate/vindexes/hash_test.go index 7a030dcf1c9..907ddad42c5 100644 --- a/go/vt/vtgate/vindexes/hash_test.go +++ b/go/vt/vtgate/vindexes/hash_test.go @@ -6,6 +6,7 @@ package vindexes import ( "reflect" + "strings" "testing" ) @@ -25,6 +26,12 @@ func TestHashCost(t *testing.T) { } } +func TestHashString(t *testing.T) { + if strings.Compare("nn", hash.String()) != 0 { + t.Errorf("String(): %s, want hash", hash.String()) + } +} + func TestHashMap(t *testing.T) { got, err := hash.(Unique).Map(nil, []interface{}{1, int32(2), int64(3), uint(4), uint32(5), uint64(6)}) if err != nil { @@ -41,6 +48,13 @@ func TestHashMap(t *testing.T) { if !reflect.DeepEqual(got, want) { t.Errorf("Map(): %#v, want %+v", got, want) } + + //Negative Test Case + _, err = hash.(Unique).Map(nil, []interface{}{1.2}) + want = "hash.Map: getNumber: unexpected type for 1.2: float64" + if err.Error() != want { + t.Error(err) + } } func TestHashVerify(t *testing.T) { @@ -53,6 +67,28 @@ func TestHashVerify(t *testing.T) { } } +func TestHashVerifyNeg(t *testing.T) { + _, err := hash.Verify(nil, []interface{}{1, 2}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) + want := "hash.Verify: length of ids 2 doesn't match length of ksids 1" + if err.Error() != want { + t.Error(err.Error()) + } + + _, err = hash.Verify(nil, []interface{}{1.2}, [][]byte{[]byte("test1")}) + want = "hash.Verify: getNumber: unexpected type for 1.2: float64" + if err.Error() != want { + t.Error(err) + } + + success, err := hash.Verify(nil, []interface{}{uint(4)}, [][]byte{[]byte("\x06\xe7\xea\"Βp\x8f")}) + if err != nil { + t.Error(err) + } + if success { + t.Errorf("Verify(): %+v, want false", success) + } +} + func TestHashReverseMap(t *testing.T) { got, err := hash.(Reversible).ReverseMap(nil, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { @@ -62,3 +98,11 @@ func TestHashReverseMap(t *testing.T) { t.Errorf("ReverseMap(): %+v, want 1", got) } } + +func TestHashReverseMapNeg(t *testing.T) { + _, err := hash.(Reversible).ReverseMap(nil, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6\x16k@\xb4J\xbaK\xd6")}) + want := "invalid keyspace id: 166b40b44aba4bd6166b40b44aba4bd6" + if err.Error() != want { + t.Error(err) + } +} diff --git a/go/vt/vtgate/vindexes/lookup_hash_test.go b/go/vt/vtgate/vindexes/lookup_hash_test.go index 9aeaa392f83..8832607268c 100644 --- a/go/vt/vtgate/vindexes/lookup_hash_test.go +++ b/go/vt/vtgate/vindexes/lookup_hash_test.go @@ -56,25 +56,43 @@ func (vc *vcursor) Execute(query string, bindvars map[string]interface{}) (*sqlt panic("unexpected") } -var lhm Vindex +var lookuphash Vindex +var lookuphashunique Vindex func init() { - h, err := CreateVindex("lookup_hash", "nn", map[string]string{"table": "t", "from": "fromc", "to": "toc"}) + lh, err := CreateVindex("lookup_hash", "lookup_hash", map[string]string{"table": "t", "from": "fromc", "to": "toc"}) if err != nil { panic(err) } - lhm = h + lu, err := CreateVindex("lookup_hash_unique", "lookup_hash_unique", map[string]string{"table": "t", "from": "fromc", "to": "toc"}) + if err != nil { + panic(err) + } + lookuphash = lh + lookuphashunique = lu } func TestLookupHashCost(t *testing.T) { - if lhm.Cost() != 20 { - t.Errorf("Cost(): %d, want 20", lhm.Cost()) + if lookuphash.Cost() != 20 { + t.Errorf("Cost(): %d, want 20", lookuphash.Cost()) + } + if lookuphashunique.Cost() != 10 { + t.Errorf("Cost(): %d, want 10", lookuphashunique.Cost()) + } +} + +func TestLookupHashString(t *testing.T) { + if strings.Compare("lookup_hash", lookuphash.String()) != 0 { + t.Errorf("String(): %s, want lookup_hash", lookuphash.String()) + } + if strings.Compare("lookup_hash_unique", lookuphashunique.String()) != 0 { + t.Errorf("String(): %s, want lookup_hash_unique", lookuphashunique.String()) } } func TestLookupHashMap(t *testing.T) { vc := &vcursor{numRows: 2} - got, err := lhm.(NonUnique).Map(vc, []interface{}{1, int32(2)}) + got, err := lookuphash.(NonUnique).Map(vc, []interface{}{1, int32(2)}) if err != nil { t.Error(err) } @@ -92,7 +110,7 @@ func TestLookupHashMap(t *testing.T) { func TestLookupHashVerify(t *testing.T) { vc := &vcursor{numRows: 1} - success, err := lhm.Verify(vc, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) + success, err := lookuphash.Verify(vc, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { t.Error(err) } @@ -103,7 +121,7 @@ func TestLookupHashVerify(t *testing.T) { func TestLookupHashCreate(t *testing.T) { vc := &vcursor{} - err := lhm.(Lookup).Create(vc, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) + err := lookuphash.(Lookup).Create(vc, []interface{}{1}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) if err != nil { t.Error(err) } @@ -120,7 +138,7 @@ func TestLookupHashCreate(t *testing.T) { } func TestLookupHashReverse(t *testing.T) { - _, ok := lhm.(Reversible) + _, ok := lookuphash.(Reversible) if ok { t.Errorf("lhm.(Reversible): true, want false") } @@ -128,7 +146,7 @@ func TestLookupHashReverse(t *testing.T) { func TestLookupHashDelete(t *testing.T) { vc := &vcursor{} - err := lhm.(Lookup).Delete(vc, []interface{}{1}, []byte("\x16k@\xb4J\xbaK\xd6")) + err := lookuphash.(Lookup).Delete(vc, []interface{}{1}, []byte("\x16k@\xb4J\xbaK\xd6")) if err != nil { t.Error(err) } diff --git a/go/vt/vtgate/vindexes/lookup_test.go b/go/vt/vtgate/vindexes/lookup_test.go index f3172d63778..5054a48a53b 100644 --- a/go/vt/vtgate/vindexes/lookup_test.go +++ b/go/vt/vtgate/vindexes/lookup_test.go @@ -4,6 +4,8 @@ import ( "reflect" "testing" + "strings" + "github.com/youtube/vitess/go/vt/tabletserver/querytypes" ) @@ -16,6 +18,10 @@ func init() { panic(err) } lkpnonunique, err := CreateVindex("lookup", "lookupNonUnique", map[string]string{"table": "t", "from": "fromc", "to": "toc"}) + if err != nil { + panic(err) + } + lookupUnique = lkpunique lookupNonUnique = lkpnonunique } @@ -32,14 +38,63 @@ func TestLookupNonUniqueCost(t *testing.T) { } } +func TestLookupUniqueString(t *testing.T) { + if strings.Compare("lookupUnique", lookupUnique.String()) != 0 { + t.Errorf("String(): %s, want lookupUnique", lookupUnique.String()) + } +} + +func TestLookupNonUniqueString(t *testing.T) { + if strings.Compare("lookupNonUnique", lookupNonUnique.String()) != 0 { + t.Errorf("String(): %s, want lookupNonUnique", lookupNonUnique.String()) + } +} + func TestLookupUniqueVerify(t *testing.T) { vc := &vcursor{numRows: 1} - success, err := lookupUnique.Verify(vc, []interface{}{1}, [][]byte{[]byte("test")}) + _, err := lookupUnique.Verify(vc, []interface{}{1}, [][]byte{[]byte("test")}) + wantQuery := &querytypes.BoundQuery{ + Sql: "select fromc from t where ((fromc=:fromc0 and toc=:toc0))", + BindVariables: map[string]interface{}{ + "fromc0": 1, + "toc0": []byte("test"), + }, + } if err != nil { t.Error(err) } - if !success { - t.Errorf("Verify(): %+v, want true", success) + if !reflect.DeepEqual(vc.bq, wantQuery) { + t.Errorf("vc.query = %#v, want %#v", vc.bq, wantQuery) + } + + //Negative test + want := "lookup.Verify:length of ids 2 doesn't match length of ksids 1" + _, err = lookupUnique.Verify(vc, []interface{}{1, 2}, [][]byte{[]byte("test")}) + if err.Error() != want { + t.Error(err.Error()) + } + + _, err = lookuphashunique.Verify(nil, []interface{}{1}, [][]byte{[]byte("test1test23")}) + want = "lookup.Verify: invalid keyspace id: 7465737431746573743233" + if err.Error() != want { + t.Error(err) + } +} + +func TestLookupUniqueMap(t *testing.T) { + vc := &vcursor{} + _, err := lookupUnique.(Unique).Map(vc, []interface{}{2}) + if err != nil { + t.Error(err) + } + wantQuery := &querytypes.BoundQuery{ + Sql: "select toc from t where fromc = :fromc", + BindVariables: map[string]interface{}{ + "fromc": 2, + }, + } + if !reflect.DeepEqual(vc.bq, wantQuery) { + t.Errorf("vc.query = %#v, want %#v", vc.bq, wantQuery) } } @@ -59,6 +114,19 @@ func TestLookupUniqueCreate(t *testing.T) { if !reflect.DeepEqual(vc.bq, wantQuery) { t.Errorf("vc.query = %#v, want %#v", vc.bq, wantQuery) } + + //Negative test + want := "lookup.Create:length of ids 2 doesn't match length of ksids 1" + err = lookupUnique.(Lookup).Create(vc, []interface{}{1, 2}, [][]byte{[]byte("test")}) + if err.Error() != want { + t.Error(err.Error()) + } + + err = lookuphashunique.(Lookup).Create(nil, []interface{}{1}, [][]byte{[]byte("test1test23")}) + want = "lookup.Create: invalid keyspace id: 7465737431746573743233" + if err.Error() != want { + t.Error(err) + } } func TestLookupUniqueReverse(t *testing.T) { @@ -84,4 +152,89 @@ func TestLookupUniqueDelete(t *testing.T) { if !reflect.DeepEqual(vc.bq, wantQuery) { t.Errorf("vc.query = %#v, want %#v", vc.bq, wantQuery) } + + //Negative Test + err = lookuphashunique.(Lookup).Delete(vc, []interface{}{1}, []byte("test1test23")) + want := "lookup.Delete: invalid keyspace id: 7465737431746573743233" + if err.Error() != want { + t.Error(err) + } +} + +func TestLookupNonUniqueVerify(t *testing.T) { + vc := &vcursor{numRows: 1} + _, err := lookupNonUnique.Verify(vc, []interface{}{1}, [][]byte{[]byte("test")}) + wantQuery := &querytypes.BoundQuery{ + Sql: "select fromc from t where ((fromc=:fromc0 and toc=:toc0))", + BindVariables: map[string]interface{}{ + "fromc0": 1, + "toc0": []byte("test"), + }, + } + if err != nil { + t.Error(err) + } + if !reflect.DeepEqual(vc.bq, wantQuery) { + t.Errorf("vc.query = %#v, want %#v", vc.bq, wantQuery) + } +} + +func TestLookupNonUniqueMap(t *testing.T) { + vc := &vcursor{} + _, err := lookupNonUnique.(NonUnique).Map(vc, []interface{}{2}) + if err != nil { + t.Error(err) + } + wantQuery := &querytypes.BoundQuery{ + Sql: "select toc from t where fromc = :fromc", + BindVariables: map[string]interface{}{ + "fromc": 2, + }, + } + if !reflect.DeepEqual(vc.bq, wantQuery) { + t.Errorf("vc.query = %#v, want %#v", vc.bq, wantQuery) + } +} + +func TestLookupNonUniqueCreate(t *testing.T) { + vc := &vcursor{} + err := lookupNonUnique.(Lookup).Create(vc, []interface{}{1}, [][]byte{[]byte("test")}) + if err != nil { + t.Error(err) + } + wantQuery := &querytypes.BoundQuery{ + Sql: "insert into t(fromc,toc) values(:fromc0,:toc0)", + BindVariables: map[string]interface{}{ + "fromc0": 1, + "toc0": []byte("test"), + }, + } + if !reflect.DeepEqual(vc.bq, wantQuery) { + t.Errorf("vc.query = %#v, want %#v", vc.bq, wantQuery) + } +} + +func TestLookupNonUniqueReverse(t *testing.T) { + _, ok := lookupNonUnique.(Reversible) + if ok { + t.Errorf("lhu.(Reversible): true, want false") + } +} + +func TestLookupNonUniqueDelete(t *testing.T) { + vc := &vcursor{} + err := lookupNonUnique.(Lookup).Delete(vc, []interface{}{1}, []byte("test")) + if err != nil { + t.Error(err) + } + wantQuery := &querytypes.BoundQuery{ + Sql: "delete from t where fromc = :fromc and toc = :toc", + BindVariables: map[string]interface{}{ + "fromc": 1, + "toc": []byte("test"), + }, + } + if !reflect.DeepEqual(vc.bq, wantQuery) { + t.Errorf("vc.query = %#v, want %#v", vc.bq, wantQuery) + } } diff --git a/go/vt/vtgate/vindexes/numeric_static_map_test.go b/go/vt/vtgate/vindexes/numeric_static_map_test.go index 77d4053ac24..1c683ee6e5f 100644 --- a/go/vt/vtgate/vindexes/numeric_static_map_test.go +++ b/go/vt/vtgate/vindexes/numeric_static_map_test.go @@ -8,33 +8,33 @@ import ( "reflect" "testing" + "strings" + "github.com/youtube/vitess/go/sqltypes" "github.com/youtube/vitess/go/testfiles" ) -func createVindex() (Vindex, error) { +var numericStaticMap Vindex + +func init() { m := make(map[string]string) m["json_path"] = testfiles.Locate("vtgate/numeric_static_map_test.json") - return CreateVindex("numeric_static_map", "numericStaticMap", m) + numericStaticMap, _ = CreateVindex("numeric_static_map", "numericStaticMap", m) } func TestNumericStaticMapCost(t *testing.T) { - numericStaticMap, err := createVindex() - if err != nil { - t.Fatalf("failed to create vindex: %v", err) - } - if numericStaticMap.Cost() != 1 { t.Errorf("Cost(): %d, want 1", numericStaticMap.Cost()) } } -func TestNumericStaticMapMap(t *testing.T) { - numericStaticMap, err := createVindex() - if err != nil { - t.Fatalf("failed to create vindex: %v", err) +func TestNumericStaticMapString(t *testing.T) { + if strings.Compare("numericStaticMap", numericStaticMap.String()) != 0 { + t.Errorf("String(): %s, want num", numericStaticMap.String()) } +} +func TestNumericStaticMapMap(t *testing.T) { sqlVal, _ := sqltypes.BuildIntegral("8") got, err := numericStaticMap.(Unique).Map(nil, []interface{}{ 1, @@ -68,12 +68,7 @@ func TestNumericStaticMapMap(t *testing.T) { } func TestNumericStaticMapMapBadData(t *testing.T) { - numericStaticMap, err := createVindex() - if err != nil { - t.Fatalf("failed to create vindex: %v", err) - } - - _, err = numericStaticMap.(Unique).Map(nil, []interface{}{1.1}) + _, err := numericStaticMap.(Unique).Map(nil, []interface{}{1.1}) want := `NumericStaticMap.Map: getNumber: unexpected type for 1.1: float64` if err == nil || err.Error() != want { t.Errorf("NumericStaticMap.Map: %v, want %v", err, want) @@ -81,11 +76,6 @@ func TestNumericStaticMapMapBadData(t *testing.T) { } func TestNumericStaticMapVerify(t *testing.T) { - numericStaticMap, err := createVindex() - if err != nil { - t.Fatalf("failed to create vindex: %v", err) - } - success, err := numericStaticMap.Verify(nil, []interface{}{1}, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) if err != nil { t.Error(err) @@ -95,15 +85,25 @@ func TestNumericStaticMapVerify(t *testing.T) { } } -func TestNumericStaticMapVerifyBadData(t *testing.T) { - numericStaticMap, err := createVindex() - if err != nil { - t.Fatalf("failed to create vindex: %v", err) +func TestNumericStaticMapVerifyNeg(t *testing.T) { + _, err := numericStaticMap.Verify(nil, []interface{}{1, 2}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) + want := "NumericStaticMap.Verify: length of ids 2 doesn't match length of ksids 1" + if err.Error() != want { + t.Error(err.Error()) } _, err = numericStaticMap.Verify(nil, []interface{}{1.1}, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) - want := `NumericStaticMap.Verify: getNumber: unexpected type for 1.1: float64` + want = `NumericStaticMap.Verify: getNumber: unexpected type for 1.1: float64` if err == nil || err.Error() != want { t.Errorf("numericStaticMap.Map: %v, want %v", err, want) } + + success, err := numericStaticMap.Verify(nil, []interface{}{1}, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x02")}) + if err != nil { + t.Errorf(err.Error()) + } + if success { + t.Errorf("Numeric.Verify(): %+v, want false", success) + } + } diff --git a/go/vt/vtgate/vindexes/numeric_test.go b/go/vt/vtgate/vindexes/numeric_test.go index 1e36664ea6e..51524827920 100644 --- a/go/vt/vtgate/vindexes/numeric_test.go +++ b/go/vt/vtgate/vindexes/numeric_test.go @@ -8,13 +8,15 @@ import ( "reflect" "testing" + "strings" + "github.com/youtube/vitess/go/sqltypes" ) var numeric Vindex func init() { - numeric, _ = CreateVindex("numeric", "nn", nil) + numeric, _ = CreateVindex("numeric", "num", nil) } func TestNumericCost(t *testing.T) { @@ -23,6 +25,12 @@ func TestNumericCost(t *testing.T) { } } +func TestNumericString(t *testing.T) { + if strings.Compare("num", numeric.String()) != 0 { + t.Errorf("String(): %s, want num", numeric.String()) + } +} + func TestNumericMap(t *testing.T) { sqlVal, _ := sqltypes.BuildIntegral("8") got, err := numeric.(Unique).Map(nil, []interface{}{ @@ -71,11 +79,25 @@ func TestNumericVerify(t *testing.T) { } } -func TestNumericVerifyBadData(t *testing.T) { - _, err := numeric.Verify(nil, []interface{}{1.1}, [][]byte{[]byte("\x00\x00\x00\x00\x00\x00\x00\x01")}) - want := `Numeric.Verify: getNumber: unexpected type for 1.1: float64` - if err == nil || err.Error() != want { - t.Errorf("numeric.Map: %v, want %v", err, want) +func TestNumericVerifyNeg(t *testing.T) { + _, err := numeric.Verify(nil, []interface{}{1, 2}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) + want := "Numeric.Verify: length of ids 2 doesn't match length of ksids 1" + if err.Error() != want { + t.Error(err.Error()) + } + + _, err = numeric.Verify(nil, []interface{}{1.1}, [][]byte{[]byte("test1")}) + want = "Numeric.Verify: getNumber: unexpected type for 1.1: float64" + if err.Error() != want { + t.Error(err) + } + + success, err := numeric.Verify(nil, []interface{}{uint(4)}, [][]byte{[]byte("\x06\xe7\xea\"Βp\x8f")}) + if err != nil { + t.Error(err) + } + if success { + t.Errorf("Numeric.Verify(): %+v, want false", success) } } diff --git a/go/vt/vtgate/vindexes/unicodeloosemd5.go b/go/vt/vtgate/vindexes/unicodeloosemd5.go index f8924ccce23..e3e028e26e7 100644 --- a/go/vt/vtgate/vindexes/unicodeloosemd5.go +++ b/go/vt/vtgate/vindexes/unicodeloosemd5.go @@ -37,12 +37,12 @@ func (vind *UnicodeLooseMD5) Cost() int { // Verify returns true if ids maps to ksids. func (vind *UnicodeLooseMD5) Verify(_ VCursor, ids []interface{}, ksids [][]byte) (bool, error) { if len(ids) != len(ksids) { - return false, fmt.Errorf("BinaryMD5_hash.Verify: length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) + return false, fmt.Errorf("UnicodeLooseMD5.Verify: length of ids %v doesn't match length of ksids %v", len(ids), len(ksids)) } for rowNum := range ids { data, err := unicodeHash(ids[rowNum]) if err != nil { - return false, fmt.Errorf("BinaryMD5_hash.Verify: %v", err) + return false, fmt.Errorf("UnicodeLooseMD5.Verify: %v", err) } if bytes.Compare(data, ksids[rowNum]) != 0 { return false, nil diff --git a/go/vt/vtgate/vindexes/unicodeloosemd5_test.go b/go/vt/vtgate/vindexes/unicodeloosemd5_test.go index 383704c4e33..9403dff7b47 100644 --- a/go/vt/vtgate/vindexes/unicodeloosemd5_test.go +++ b/go/vt/vtgate/vindexes/unicodeloosemd5_test.go @@ -18,6 +18,12 @@ func TestUnicodeLooseMD5Cost(t *testing.T) { } } +func TestUnicodeLooseMD5String(t *testing.T) { + if strings.Compare("utf8ch", charVindex.String()) != 0 { + t.Errorf("String(): %s, want utf8ch", charVindex.String()) + } +} + func TestUnicodeLooseMD5(t *testing.T) { tcases := []struct { in, out string @@ -69,6 +75,36 @@ func TestUnicodeLooseMD5(t *testing.T) { t.Errorf("Verify(%#v): false, want true", tcase.in) } } + + //Negative test case + _, err := charVindex.(Unique).Map(nil, []interface{}{1}) + want := "UnicodeLooseMD5.Map: unexpected data type for getBytes: int" + if err.Error() != want { + t.Error(err) + } + +} + +func TestUnicodeLooseMD5Neg(t *testing.T) { + _, err := charVindex.Verify(nil, []interface{}{[]byte("test1"), []byte("test2")}, [][]byte{[]byte("test1")}) + want := "UnicodeLooseMD5.Verify: length of ids 2 doesn't match length of ksids 1" + if err.Error() != want { + t.Error(err.Error()) + } + + ok, err := charVindex.Verify(nil, []interface{}{[]byte("test2")}, [][]byte{[]byte("test1")}) + if err != nil { + t.Error(err) + } + if ok { + t.Errorf("Verify(%#v): true, want false", []byte("test2")) + } + + _, err = charVindex.Verify(nil, []interface{}{1}, [][]byte{[]byte("test1")}) + want = "UnicodeLooseMD5.Verify: unexpected data type for getBytes: int" + if err.Error() != want { + t.Error(err) + } } func TestNormalization(t *testing.T) { From b520cc0ad68befd047baff195041efb5dae8dfc3 Mon Sep 17 00:00:00 2001 From: Ashudeep Sharma Date: Thu, 5 Jan 2017 20:03:16 +0530 Subject: [PATCH 5/5] Fixing Lint Errors --- go/vt/vtgate/vindexes/hash_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/vt/vtgate/vindexes/hash_test.go b/go/vt/vtgate/vindexes/hash_test.go index 907ddad42c5..8efafc8e9ad 100644 --- a/go/vt/vtgate/vindexes/hash_test.go +++ b/go/vt/vtgate/vindexes/hash_test.go @@ -51,8 +51,8 @@ func TestHashMap(t *testing.T) { //Negative Test Case _, err = hash.(Unique).Map(nil, []interface{}{1.2}) - want = "hash.Map: getNumber: unexpected type for 1.2: float64" - if err.Error() != want { + wanterr := "hash.Map: getNumber: unexpected type for 1.2: float64" + if err.Error() != wanterr { t.Error(err) } }