diff --git a/go/sqltypes/bind_variables.go b/go/sqltypes/bind_variables.go index d1f866cac05..1d79f033681 100644 --- a/go/sqltypes/bind_variables.go +++ b/go/sqltypes/bind_variables.go @@ -27,8 +27,16 @@ import ( querypb "vitess.io/vitess/go/vt/proto/query" ) -// NullBindVariable is a bindvar with NULL value. -var NullBindVariable = &querypb.BindVariable{Type: querypb.Type_NULL_TYPE} +var ( + // BvSchemaName is bind variable to be sent down to vttablet for schema name. + BvSchemaName = "__vtschemaname" + + // BvReplaceSchemaName is bind variable to be sent down to vttablet to replace schema name. + BvReplaceSchemaName = "__replacevtschemaname" + + // NullBindVariable is a bindvar with NULL value. + NullBindVariable = &querypb.BindVariable{Type: querypb.Type_NULL_TYPE} +) // ValueToProto converts Value to a *querypb.Value. func ValueToProto(v Value) *querypb.Value { diff --git a/go/test/endtoend/vtgate/misc_test.go b/go/test/endtoend/vtgate/misc_test.go index bf76b42092b..4e15153fc3b 100644 --- a/go/test/endtoend/vtgate/misc_test.go +++ b/go/test/endtoend/vtgate/misc_test.go @@ -317,6 +317,10 @@ func TestInformationSchemaQuery(t *testing.T) { require.Nil(t, err) assert.Equal(t, 1, len(qr.Rows), "did not get enough rows back") assert.Equal(t, "vt_ks", qr.Rows[0][0].ToString()) + + qr, err = conn.ExecuteFetch("SELECT distinct table_schema FROM information_schema.tables WHERE table_schema = 'NONE'", 1000, true) + require.Nil(t, err) + assert.Empty(t, qr.Rows) } func TestOffsetAndLimitWithOLAP(t *testing.T) { diff --git a/go/vt/vtexplain/vtexplain_flaky_test.go b/go/vt/vtexplain/vtexplain_flaky_test.go index 8162ff43f37..2df2d0ad445 100644 --- a/go/vt/vtexplain/vtexplain_flaky_test.go +++ b/go/vt/vtexplain/vtexplain_flaky_test.go @@ -216,7 +216,6 @@ func TestJSONOutput(t *testing.T) { { "BindVars": { "#maxLimit": "10001", - "__vtschemaname": "''", "vtg1": "1" }, "SQL": "select :vtg1 from user where id = :vtg1", diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go index a6843a28aa7..90936eaaac6 100644 --- a/go/vt/vtgate/engine/route.go +++ b/go/vt/vtgate/engine/route.go @@ -186,8 +186,6 @@ var routeName = map[RouteOpcode]string{ var ( partialSuccessScatterQueries = stats.NewCounter("PartialSuccessScatterQueries", "Count of partially successful scatter queries") - // BvSchemaName is bind variable to be sent down to vttablet for schema name. - BvSchemaName = "__vtschemaname" ) // MarshalJSON serializes the RouteOpcode as a JSON string. @@ -386,6 +384,7 @@ func (route *Route) paramsSystemQuery(vcursor VCursor, bindVars map[string]*quer } var keyspace string + schemaExists := false for _, expr := range route.SysTableKeyspaceExpr { result, err := expr.Evaluate(env) if err != nil { @@ -393,7 +392,8 @@ func (route *Route) paramsSystemQuery(vcursor VCursor, bindVars map[string]*quer } if keyspace == "" { keyspace = result.Value().ToString() - bindVars[BvSchemaName] = sqltypes.StringBindVariable(keyspace) + bindVars[sqltypes.BvSchemaName] = sqltypes.StringBindVariable(keyspace) + schemaExists = true } else if other := result.Value().ToString(); keyspace != other { return nil, nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "can't use more than one keyspace per system table query - found both '%s' and '%s'", keyspace, other) } @@ -404,7 +404,12 @@ func (route *Route) paramsSystemQuery(vcursor VCursor, bindVars map[string]*quer } destinations, _, err := vcursor.ResolveDestinations(keyspace, nil, []key.Destination{key.DestinationAnyShard{}}) - if err != nil { + if err == nil { + // This is to indicate vttablet to replace the schema name. + if schemaExists { + bindVars[sqltypes.BvReplaceSchemaName] = sqltypes.Int64BindVariable(1) + } + } else { // Check with assigned route keyspace. destinations, _, err = vcursor.ResolveDestinations(route.Keyspace.Name, nil, []key.Destination{key.DestinationAnyShard{}}) if err != nil { diff --git a/go/vt/vtgate/planbuilder/select.go b/go/vt/vtgate/planbuilder/select.go index 2a5f0c97933..b819fa2b038 100644 --- a/go/vt/vtgate/planbuilder/select.go +++ b/go/vt/vtgate/planbuilder/select.go @@ -20,6 +20,8 @@ import ( "errors" "fmt" + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/vt/key" vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" @@ -257,7 +259,7 @@ func (r *rewriter) rewriteTableSchema(cursor *sqlparser.Cursor) bool { return false } r.tableNameExpressions = append(r.tableNameExpressions, evalExpr) - parent.Right = sqlparser.NewArgument([]byte(":" + engine.BvSchemaName)) + parent.Right = sqlparser.NewArgument([]byte(":" + sqltypes.BvSchemaName)) } } } diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index a2c444b0cd7..70c363fe3b4 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -124,7 +124,9 @@ func (qre *QueryExecutor) Execute() (reply *sqltypes.Result, err error) { case planbuilder.PlanSelect, planbuilder.PlanSelectImpossible, planbuilder.PlanShowTables: maxrows := qre.getSelectLimit() qre.bindVars["#maxLimit"] = sqltypes.Int64BindVariable(maxrows + 1) - qre.bindVars["__vtschemaname"] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName) + if qre.bindVars[sqltypes.BvReplaceSchemaName] != nil { + qre.bindVars[sqltypes.BvSchemaName] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName) + } qr, err := qre.execSelect() if err != nil { return nil, err @@ -207,7 +209,9 @@ func (qre *QueryExecutor) txConnExec(conn *StatefulConnection) (*sqltypes.Result case planbuilder.PlanSelect, planbuilder.PlanSelectLock, planbuilder.PlanSelectImpossible, planbuilder.PlanShowTables: maxrows := qre.getSelectLimit() qre.bindVars["#maxLimit"] = sqltypes.Int64BindVariable(maxrows + 1) - qre.bindVars["__vtschemaname"] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName) + if qre.bindVars[sqltypes.BvReplaceSchemaName] != nil { + qre.bindVars[sqltypes.BvSchemaName] = sqltypes.StringBindVariable(qre.tsv.config.DB.DBName) + } qr, err := qre.txFetch(conn, false) if err != nil { return nil, err