diff --git a/go/vt/vtgate/planbuilder/abstract/operator.go b/go/vt/vtgate/planbuilder/abstract/operator.go index 8f2cfac35a8..001459ac039 100644 --- a/go/vt/vtgate/planbuilder/abstract/operator.go +++ b/go/vt/vtgate/planbuilder/abstract/operator.go @@ -109,8 +109,6 @@ func getOperatorFromTableExpr(tableExpr sqlparser.TableExpr, semTable *semantics lhs, rhs = rhs, lhs } return &Join{LHS: lhs, RHS: rhs, LeftJoin: true, Predicate: tableExpr.Condition.On}, nil - case sqlparser.StraightJoinType: - return nil, semantics.Gen4NotSupportedF(tableExpr.Join.ToString()) default: return nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: %s", tableExpr.Join.ToString()) } diff --git a/go/vt/vtgate/planbuilder/builder.go b/go/vt/vtgate/planbuilder/builder.go index b9f62bb7469..468face549c 100644 --- a/go/vt/vtgate/planbuilder/builder.go +++ b/go/vt/vtgate/planbuilder/builder.go @@ -63,6 +63,9 @@ type ContextVSchema interface { // that could become a problem if they move to a sharded keyspace WarnUnshardedOnly(format string, params ...interface{}) + // PlannerWarning records warning created during planning. + PlannerWarning(message string) + // ForeignKeyMode returns the foreign_key flag value ForeignKeyMode() string } diff --git a/go/vt/vtgate/planbuilder/gen4_planner.go b/go/vt/vtgate/planbuilder/gen4_planner.go index d990bf3bba2..cf8a026c91f 100644 --- a/go/vt/vtgate/planbuilder/gen4_planner.go +++ b/go/vt/vtgate/planbuilder/gen4_planner.go @@ -78,6 +78,10 @@ func gen4planSQLCalcFoundRows(vschema ContextVSchema, sel *sqlparser.Select, que if err != nil { return nil, err } + if semTable.Warning != "" { + // log it as planning warning. + vschema.PlannerWarning(semTable.Warning) + } plan, err := buildSQLCalcFoundRowsPlan(query, sel, reservedVars, vschema, planSelectGen4) if err != nil { return nil, err diff --git a/go/vt/vtgate/planbuilder/plan_test.go b/go/vt/vtgate/planbuilder/plan_test.go index f65fca732e2..1f3953573a6 100644 --- a/go/vt/vtgate/planbuilder/plan_test.go +++ b/go/vt/vtgate/planbuilder/plan_test.go @@ -437,6 +437,9 @@ type vschemaWrapper struct { version PlannerVersion } +func (vw *vschemaWrapper) PlannerWarning(_ string) { +} + func (vw *vschemaWrapper) ForeignKeyMode() string { return "allow" } diff --git a/go/vt/vtgate/planbuilder/testdata/from_cases.txt b/go/vt/vtgate/planbuilder/testdata/from_cases.txt index aab055e22e7..de0cb57ff30 100644 --- a/go/vt/vtgate/planbuilder/testdata/from_cases.txt +++ b/go/vt/vtgate/planbuilder/testdata/from_cases.txt @@ -784,7 +784,7 @@ Gen4 plan same as above } } -# Straight-join +# Straight-join (Gen4 ignores the straight_join hint) "select m1.col from unsharded as m1 straight_join unsharded as m2" { "QueryType": "SELECT", @@ -801,6 +801,21 @@ Gen4 plan same as above "Table": "unsharded" } } +{ + "QueryType": "SELECT", + "Original": "select m1.col from unsharded as m1 straight_join unsharded as m2", + "Instructions": { + "OperatorType": "Route", + "Variant": "SelectUnsharded", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select m1.col from unsharded as m1, unsharded as m2 where 1 != 1", + "Query": "select m1.col from unsharded as m1, unsharded as m2", + "Table": "unsharded" + } +} # Three-way join "select user.col from user join unsharded as m1 join unsharded as m2" diff --git a/go/vt/vtgate/semantics/analyzer.go b/go/vt/vtgate/semantics/analyzer.go index fd2ae5f8405..5708095439e 100644 --- a/go/vt/vtgate/semantics/analyzer.go +++ b/go/vt/vtgate/semantics/analyzer.go @@ -42,6 +42,7 @@ type analyzer struct { inProjection int projErr error + warning string } // newAnalyzer create the semantic analyzer @@ -75,6 +76,7 @@ func Analyze(statement sqlparser.SelectStatement, currentDb string, si SchemaInf semTable := analyzer.newSemTable(statement) semTable.ProjectionErr = analyzer.projErr + semTable.Warning = analyzer.warning return semTable, nil } @@ -126,6 +128,8 @@ func (a *analyzer) analyzeDown(cursor *sqlparser.Cursor) bool { a.setError(err) return true } + // log any warn in rewriting. + a.warning = a.rewriter.warning a.enterProjection(cursor) // this is the visitor going down the tree. Returning false here would just not visit the children diff --git a/go/vt/vtgate/semantics/early_rewriter.go b/go/vt/vtgate/semantics/early_rewriter.go index 613d39c39a5..fcab3a63559 100644 --- a/go/vt/vtgate/semantics/early_rewriter.go +++ b/go/vt/vtgate/semantics/early_rewriter.go @@ -25,8 +25,9 @@ import ( ) type earlyRewriter struct { - scoper *scoper - clause string + scoper *scoper + clause string + warning string } func (r *earlyRewriter) down(cursor *sqlparser.Cursor) error { @@ -59,6 +60,11 @@ func (r *earlyRewriter) down(cursor *sqlparser.Cursor) error { if changed { cursor.ReplaceAndRevisit(selExprs) } + case *sqlparser.JoinTableExpr: + if node.Join == sqlparser.StraightJoinType { + node.Join = sqlparser.NormalJoinType + r.warning = "straight join is converted to normal join" + } case *sqlparser.Order: r.clause = "order clause" case sqlparser.GroupBy: diff --git a/go/vt/vtgate/semantics/semantic_state.go b/go/vt/vtgate/semantics/semantic_state.go index 8c252c2b78a..c140c3b631f 100644 --- a/go/vt/vtgate/semantics/semantic_state.go +++ b/go/vt/vtgate/semantics/semantic_state.go @@ -90,6 +90,8 @@ type ( // ColumnEqualities is used to enable transitive closures // if a == b and b == c then a == c ColumnEqualities map[columnName][]sqlparser.Expr + + Warning string } columnName struct { diff --git a/go/vt/vtgate/vcursor_impl.go b/go/vt/vtgate/vcursor_impl.go index a63a7697948..5f9b6ae2c3a 100644 --- a/go/vt/vtgate/vcursor_impl.go +++ b/go/vt/vtgate/vcursor_impl.go @@ -371,6 +371,7 @@ func (vc *vcursorImpl) TargetString() string { return vc.safeSession.TargetString } +// MaxBufferingRetries is to represent max retries on buffering. const MaxBufferingRetries = 3 func (vc *vcursorImpl) ExecutePrimitive(primitive engine.Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { @@ -746,7 +747,18 @@ func (vc *vcursorImpl) WarnUnshardedOnly(format string, params ...interface{}) { } } -// ForeignKey implements the VCursor interface +// PlannerWarning implements the VCursor interface +func (vc *vcursorImpl) PlannerWarning(message string) { + if message == "" { + return + } + vc.warnings = append(vc.warnings, &querypb.QueryWarning{ + Code: mysql.ERNotSupportedYet, + Message: message, + }) +} + +// ForeignKeyMode implements the VCursor interface func (vc *vcursorImpl) ForeignKeyMode() string { if foreignKeyMode == nil { return ""