From 27b5aae3f9219bd2bfcad6ff80f8410904996c54 Mon Sep 17 00:00:00 2001 From: wh Date: Mon, 7 Oct 2019 02:06:31 +0800 Subject: [PATCH 1/2] treat the route of sql with pseudo table as SelectReference Signed-off-by: wh --- go/vt/vtgate/planbuilder/expr.go | 2 ++ go/vt/vtgate/planbuilder/from.go | 20 +++++++++++++------ go/vt/vtgate/planbuilder/route.go | 9 +++++++++ .../planbuilder/testdata/select_cases.txt | 10 +++++----- .../testdata/unsupported_cases.txt | 4 ++++ 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/go/vt/vtgate/planbuilder/expr.go b/go/vt/vtgate/planbuilder/expr.go index 0447fa9dde8..47ecf4077e7 100644 --- a/go/vt/vtgate/planbuilder/expr.go +++ b/go/vt/vtgate/planbuilder/expr.go @@ -156,6 +156,8 @@ func (pb *primitiveBuilder) findOrigin(expr sqlparser.Expr) (pullouts []*pullout case node.Name.EqualString("last_insert_id"): if rb, isRoute := pb.bldr.(*route); !isRoute || !rb.removeShardedOptions() { return false, errors.New("unsupported: LAST_INSERT_ID is only allowed for unsharded keyspaces") + } else if rb.containsDualTable() { + return false, errors.New("unsupported: LAST_INSERT_ID is not allowed for dual table") } } return true, nil diff --git a/go/vt/vtgate/planbuilder/from.go b/go/vt/vtgate/planbuilder/from.go index 203146683ca..3908f3faa9c 100644 --- a/go/vt/vtgate/planbuilder/from.go +++ b/go/vt/vtgate/planbuilder/from.go @@ -19,6 +19,7 @@ package planbuilder import ( "errors" "fmt" + "strings" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/sqlparser" @@ -240,12 +241,19 @@ func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTabl eroute.TargetDestination = destTarget eroute.TargetTabletType = destTableType default: - // Pinned tables have their keyspace ids already assigned. - // Use the Binary vindex, which is the identity function - // for keyspace id. Currently only dual tables are pinned. - eroute = engine.NewSimpleRoute(engine.SelectEqualUnique, vst.Keyspace) - eroute.Vindex, _ = vindexes.NewBinary("binary", nil) - eroute.Values = []sqltypes.PlanValue{{Value: sqltypes.MakeTrusted(sqltypes.VarBinary, vst.Pinned)}} + // In some cases, JDBC Driver may produce tons of pointless queries like 'select 1 from dual', + // 'select @@session.tx_read_only from dual',etc. To avoid causing significant burden on one + // specific vttablet, we treat those 'dual' table queries as SelectReference. + if strings.EqualFold(tableName.Name.String(), "dual") && tableName.Qualifier.String() == "" { + eroute = engine.NewSimpleRoute(engine.SelectReference, vst.Keyspace) + } else { + // Pinned tables have their keyspace ids already assigned. + // Use the Binary vindex, which is the identity function + // for keyspace id. Currently only dual tables are pinned. + eroute = engine.NewSimpleRoute(engine.SelectEqualUnique, vst.Keyspace) + eroute.Vindex, _ = vindexes.NewBinary("binary", nil) + eroute.Values = []sqltypes.PlanValue{{Value: sqltypes.MakeTrusted(sqltypes.VarBinary, vst.Pinned)}} + } } // set table name into route eroute.TableName = vst.Name.String() diff --git a/go/vt/vtgate/planbuilder/route.go b/go/vt/vtgate/planbuilder/route.go index c8e58cf6bdd..b0a2cd155ee 100644 --- a/go/vt/vtgate/planbuilder/route.go +++ b/go/vt/vtgate/planbuilder/route.go @@ -503,6 +503,15 @@ func (rb *route) removeShardedOptions() bool { }) } +func (rb *route) containsDualTable() bool { + for _, ro := range rb.routeOptions { + if ro.vschemaTable.Name.String() == "dual" { + return true + } + } + return false +} + // removeOptionsWithUnmatchedKeyspace removes all options that don't match // the specified keyspace. It returns false if no such options exist. func (rb *route) removeOptionsWithUnmatchedKeyspace(keyspace string) bool { diff --git a/go/vt/vtgate/planbuilder/testdata/select_cases.txt b/go/vt/vtgate/planbuilder/testdata/select_cases.txt index e8885a33a28..f89e3c49410 100644 --- a/go/vt/vtgate/planbuilder/testdata/select_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/select_cases.txt @@ -392,18 +392,18 @@ "NEXT used on a non-sequence table" # last_insert_id for unsharded route -"select last_insert_id() from main.dual" +"select last_insert_id() from unsharded" { - "Original": "select last_insert_id() from main.dual", + "Original": "select last_insert_id() from unsharded", "Instructions": { "Opcode": "SelectUnsharded", "Keyspace": { "Name": "main", "Sharded": false }, - "Query": "select last_insert_id() from dual", - "FieldQuery": "select last_insert_id() from dual where 1 != 1", - "Table": "dual" + "Query": "select last_insert_id() from unsharded", + "FieldQuery": "select last_insert_id() from unsharded where 1 != 1", + "Table": "unsharded" } } diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt index c10604dfa72..8792eeb37af 100644 --- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt @@ -71,6 +71,10 @@ "select last_insert_id() from user" "unsupported: LAST_INSERT_ID is only allowed for unsharded keyspaces" +# last_insert_id for dual table +"select last_insert_id() from dual" +"unsupported: LAST_INSERT_ID is not allowed for dual table" + # natural join "select * from user natural join user_extra" "unsupported: natural join" From 001ec0777a75795526e071bf2570700c950ea632 Mon Sep 17 00:00:00 2001 From: wh Date: Sun, 20 Oct 2019 12:17:28 +0800 Subject: [PATCH 2/2] set the type of 'dual' table as 'TypeReference' Signed-off-by: wh --- go/vt/vtgate/planbuilder/expr.go | 2 -- go/vt/vtgate/planbuilder/from.go | 20 +++++---------- go/vt/vtgate/planbuilder/route.go | 9 ------- .../planbuilder/testdata/select_cases.txt | 12 ++++----- .../testdata/unsupported_cases.txt | 6 ++--- go/vt/vtgate/vindexes/vschema.go | 4 +-- go/vt/vtgate/vindexes/vschema_test.go | 25 +++++++++++++------ 7 files changed, 32 insertions(+), 46 deletions(-) diff --git a/go/vt/vtgate/planbuilder/expr.go b/go/vt/vtgate/planbuilder/expr.go index 47ecf4077e7..0447fa9dde8 100644 --- a/go/vt/vtgate/planbuilder/expr.go +++ b/go/vt/vtgate/planbuilder/expr.go @@ -156,8 +156,6 @@ func (pb *primitiveBuilder) findOrigin(expr sqlparser.Expr) (pullouts []*pullout case node.Name.EqualString("last_insert_id"): if rb, isRoute := pb.bldr.(*route); !isRoute || !rb.removeShardedOptions() { return false, errors.New("unsupported: LAST_INSERT_ID is only allowed for unsharded keyspaces") - } else if rb.containsDualTable() { - return false, errors.New("unsupported: LAST_INSERT_ID is not allowed for dual table") } } return true, nil diff --git a/go/vt/vtgate/planbuilder/from.go b/go/vt/vtgate/planbuilder/from.go index 3908f3faa9c..fa1cfc6af54 100644 --- a/go/vt/vtgate/planbuilder/from.go +++ b/go/vt/vtgate/planbuilder/from.go @@ -19,7 +19,6 @@ package planbuilder import ( "errors" "fmt" - "strings" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/sqlparser" @@ -241,19 +240,12 @@ func (pb *primitiveBuilder) buildTablePrimitive(tableExpr *sqlparser.AliasedTabl eroute.TargetDestination = destTarget eroute.TargetTabletType = destTableType default: - // In some cases, JDBC Driver may produce tons of pointless queries like 'select 1 from dual', - // 'select @@session.tx_read_only from dual',etc. To avoid causing significant burden on one - // specific vttablet, we treat those 'dual' table queries as SelectReference. - if strings.EqualFold(tableName.Name.String(), "dual") && tableName.Qualifier.String() == "" { - eroute = engine.NewSimpleRoute(engine.SelectReference, vst.Keyspace) - } else { - // Pinned tables have their keyspace ids already assigned. - // Use the Binary vindex, which is the identity function - // for keyspace id. Currently only dual tables are pinned. - eroute = engine.NewSimpleRoute(engine.SelectEqualUnique, vst.Keyspace) - eroute.Vindex, _ = vindexes.NewBinary("binary", nil) - eroute.Values = []sqltypes.PlanValue{{Value: sqltypes.MakeTrusted(sqltypes.VarBinary, vst.Pinned)}} - } + // Pinned tables have their keyspace ids already assigned. + // Use the Binary vindex, which is the identity function + // for keyspace id. + eroute = engine.NewSimpleRoute(engine.SelectEqualUnique, vst.Keyspace) + eroute.Vindex, _ = vindexes.NewBinary("binary", nil) + eroute.Values = []sqltypes.PlanValue{{Value: sqltypes.MakeTrusted(sqltypes.VarBinary, vst.Pinned)}} } // set table name into route eroute.TableName = vst.Name.String() diff --git a/go/vt/vtgate/planbuilder/route.go b/go/vt/vtgate/planbuilder/route.go index b0a2cd155ee..c8e58cf6bdd 100644 --- a/go/vt/vtgate/planbuilder/route.go +++ b/go/vt/vtgate/planbuilder/route.go @@ -503,15 +503,6 @@ func (rb *route) removeShardedOptions() bool { }) } -func (rb *route) containsDualTable() bool { - for _, ro := range rb.routeOptions { - if ro.vschemaTable.Name.String() == "dual" { - return true - } - } - return false -} - // removeOptionsWithUnmatchedKeyspace removes all options that don't match // the specified keyspace. It returns false if no such options exist. func (rb *route) removeOptionsWithUnmatchedKeyspace(keyspace string) bool { diff --git a/go/vt/vtgate/planbuilder/testdata/select_cases.txt b/go/vt/vtgate/planbuilder/testdata/select_cases.txt index f89e3c49410..bf0ce701b1c 100644 --- a/go/vt/vtgate/planbuilder/testdata/select_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/select_cases.txt @@ -376,7 +376,7 @@ { "Original": "select database() from dual", "Instructions": { - "Opcode": "SelectUnsharded", + "Opcode": "SelectReference", "Keyspace": { "Name": "main", "Sharded": false @@ -392,9 +392,9 @@ "NEXT used on a non-sequence table" # last_insert_id for unsharded route -"select last_insert_id() from unsharded" +"select last_insert_id() from main.unsharded" { - "Original": "select last_insert_id() from unsharded", + "Original": "select last_insert_id() from main.unsharded", "Instructions": { "Opcode": "SelectUnsharded", "Keyspace": { @@ -412,7 +412,7 @@ { "Original": "select @@session.auto_increment_increment from dual", "Instructions": { - "Opcode": "SelectUnsharded", + "Opcode": "SelectReference", "Keyspace": { "Name": "main", "Sharded": false @@ -449,15 +449,13 @@ { "Original": "select @@session.auto_increment_increment from user.dual", "Instructions": { - "Opcode": "SelectEqualUnique", + "Opcode": "SelectReference", "Keyspace": { "Name": "user", "Sharded": true }, "Query": "select @@session.auto_increment_increment from dual", "FieldQuery": "select @@session.auto_increment_increment from dual where 1 != 1", - "Vindex": "binary", - "Values": ["\u0000"], "Table": "dual" } } diff --git a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt index 8792eeb37af..77cee7da742 100644 --- a/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/unsupported_cases.txt @@ -71,9 +71,9 @@ "select last_insert_id() from user" "unsupported: LAST_INSERT_ID is only allowed for unsharded keyspaces" -# last_insert_id for dual table -"select last_insert_id() from dual" -"unsupported: LAST_INSERT_ID is not allowed for dual table" +# last_insert_id for dual +"select last_insert_id()" +"unsupported: LAST_INSERT_ID is only allowed for unsharded keyspaces" # natural join "select * from user natural join user_extra" diff --git a/go/vt/vtgate/vindexes/vschema.go b/go/vt/vtgate/vindexes/vschema.go index 3cf5c9a2bb4..efd93f1da65 100644 --- a/go/vt/vtgate/vindexes/vschema.go +++ b/go/vt/vtgate/vindexes/vschema.go @@ -363,9 +363,7 @@ func addDual(vschema *VSchema) { t := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks.Keyspace, - } - if ks.Keyspace.Sharded { - t.Pinned = []byte{0} + Type: TypeReference, } ks.Tables["dual"] = t if first == "" || first > ksname { diff --git a/go/vt/vtgate/vindexes/vschema_test.go b/go/vt/vtgate/vindexes/vschema_test.go index 38045cd05ad..a3aa7f5f4a8 100644 --- a/go/vt/vtgate/vindexes/vschema_test.go +++ b/go/vt/vtgate/vindexes/vschema_test.go @@ -176,6 +176,7 @@ func TestUnshardedVSchema(t *testing.T) { dual := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -239,6 +240,7 @@ func TestVSchemaColumns(t *testing.T) { dual := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -305,6 +307,7 @@ func TestVSchemaColumnListAuthoritative(t *testing.T) { dual := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -385,7 +388,7 @@ func TestVSchemaPinned(t *testing.T) { dual := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks, - Pinned: []byte{0}, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -489,7 +492,7 @@ func TestShardedVSchemaOwned(t *testing.T) { dual := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks, - Pinned: []byte{0}, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -706,11 +709,12 @@ func TestVSchemaRoutingRules(t *testing.T) { dual1 := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks1, - Pinned: []byte{0}, + Type: TypeReference, } dual2 := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks2, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{ @@ -948,7 +952,7 @@ func TestShardedVSchemaMultiColumnVindex(t *testing.T) { dual := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks, - Pinned: []byte{0}, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -1048,7 +1052,7 @@ func TestShardedVSchemaNotOwned(t *testing.T) { dual := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ks, - Pinned: []byte{0}, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -1175,10 +1179,12 @@ func TestBuildVSchemaDupSeq(t *testing.T) { duala := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ksa, + Type: TypeReference, } dualb := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ksb, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -1246,10 +1252,12 @@ func TestBuildVSchemaDupTable(t *testing.T) { duala := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ksa, + Type: TypeReference, } dualb := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ksb, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -1380,12 +1388,12 @@ func TestBuildVSchemaDupVindex(t *testing.T) { duala := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ksa, - Pinned: []byte{0}, + Type: TypeReference, } dualb := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ksb, - Pinned: []byte{0}, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{}, @@ -1699,11 +1707,12 @@ func TestSequence(t *testing.T) { duala := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: ksu, + Type: TypeReference, } dualb := &Table{ Name: sqlparser.NewTableIdent("dual"), Keyspace: kss, - Pinned: []byte{0}, + Type: TypeReference, } want := &VSchema{ RoutingRules: map[string]*RoutingRule{},