From 8f3c035226e5f9a52d6d8b8299ab0fdfd09b2274 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Taylor?= Date: Tue, 28 May 2024 09:58:14 +0200 Subject: [PATCH] refactor: remove logical plan interface (#16006) --- go/vt/sqlparser/constants.go | 13 +- go/vt/vtgate/engine/cached_size.go | 8 +- go/vt/vtgate/engine/memory_sort.go | 5 - go/vt/vtgate/engine/ordered_aggregate.go | 11 +- go/vt/vtgate/engine/route.go | 5 - go/vt/vtgate/engine/semi_join.go | 48 +- go/vt/vtgate/engine/semi_join_test.go | 2 - go/vt/vtgate/engine/sql_calc_found_rows.go | 18 +- go/vt/vtgate/engine/update_test.go | 28 -- go/vt/vtgate/planbuilder/builder.go | 4 - go/vt/vtgate/planbuilder/concatenate.go | 41 -- go/vt/vtgate/planbuilder/ddl.go | 3 - go/vt/vtgate/planbuilder/delete.go | 10 +- go/vt/vtgate/planbuilder/distinct.go | 62 --- go/vt/vtgate/planbuilder/dml_with_input.go | 46 -- go/vt/vtgate/planbuilder/filter.go | 37 -- go/vt/vtgate/planbuilder/fk_cascade.go | 48 -- go/vt/vtgate/planbuilder/fk_verify.go | 57 --- go/vt/vtgate/planbuilder/insert.go | 27 +- go/vt/vtgate/planbuilder/join.go | 70 --- go/vt/vtgate/planbuilder/limit.go | 47 -- go/vt/vtgate/planbuilder/logical_plan.go | 61 --- go/vt/vtgate/planbuilder/memory_sort.go | 47 -- go/vt/vtgate/planbuilder/merge_sort.go | 47 -- .../planbuilder/operator_transformers.go | 418 ++++++++++-------- go/vt/vtgate/planbuilder/ordered_aggregate.go | 91 ---- go/vt/vtgate/planbuilder/planner.go | 31 +- go/vt/vtgate/planbuilder/primitive_wrapper.go | 32 -- go/vt/vtgate/planbuilder/projection.go | 37 -- go/vt/vtgate/planbuilder/route.go | 86 +--- go/vt/vtgate/planbuilder/select.go | 56 +-- go/vt/vtgate/planbuilder/semi_join.go | 59 --- go/vt/vtgate/planbuilder/sequential.go | 36 -- go/vt/vtgate/planbuilder/show.go | 1 - go/vt/vtgate/planbuilder/simple_projection.go | 43 -- .../planbuilder/single_sharded_shortcut.go | 21 +- .../vtgate/planbuilder/sql_calc_found_rows.go | 41 -- .../planbuilder/uncorrelated_subquery.go | 53 --- go/vt/vtgate/planbuilder/update.go | 10 +- go/vt/vtgate/planbuilder/upsert.go | 37 -- go/vt/vtgate/planbuilder/vindex_func.go | 45 +- go/vt/vtgate/planbuilder/vindex_op.go | 63 --- go/vt/vtgate/semantics/early_rewriter.go | 2 +- .../tabletmanager/vdiff/table_differ.go | 7 +- go/vt/wrangler/vdiff.go | 7 +- go/vt/wrangler/vdiff_test.go | 5 +- 46 files changed, 360 insertions(+), 1566 deletions(-) delete mode 100644 go/vt/vtgate/planbuilder/concatenate.go delete mode 100644 go/vt/vtgate/planbuilder/distinct.go delete mode 100644 go/vt/vtgate/planbuilder/dml_with_input.go delete mode 100644 go/vt/vtgate/planbuilder/filter.go delete mode 100644 go/vt/vtgate/planbuilder/fk_cascade.go delete mode 100644 go/vt/vtgate/planbuilder/fk_verify.go delete mode 100644 go/vt/vtgate/planbuilder/join.go delete mode 100644 go/vt/vtgate/planbuilder/limit.go delete mode 100644 go/vt/vtgate/planbuilder/logical_plan.go delete mode 100644 go/vt/vtgate/planbuilder/memory_sort.go delete mode 100644 go/vt/vtgate/planbuilder/merge_sort.go delete mode 100644 go/vt/vtgate/planbuilder/ordered_aggregate.go delete mode 100644 go/vt/vtgate/planbuilder/primitive_wrapper.go delete mode 100644 go/vt/vtgate/planbuilder/projection.go delete mode 100644 go/vt/vtgate/planbuilder/semi_join.go delete mode 100644 go/vt/vtgate/planbuilder/sequential.go delete mode 100644 go/vt/vtgate/planbuilder/simple_projection.go delete mode 100644 go/vt/vtgate/planbuilder/sql_calc_found_rows.go delete mode 100644 go/vt/vtgate/planbuilder/uncorrelated_subquery.go delete mode 100644 go/vt/vtgate/planbuilder/upsert.go delete mode 100644 go/vt/vtgate/planbuilder/vindex_op.go diff --git a/go/vt/sqlparser/constants.go b/go/vt/sqlparser/constants.go index cba5f7823c1..b1f33184ec0 100644 --- a/go/vt/sqlparser/constants.go +++ b/go/vt/sqlparser/constants.go @@ -677,8 +677,8 @@ const ( NotRegexpOp ) -func Inverse(in ComparisonExprOperator) ComparisonExprOperator { - switch in { +func (op ComparisonExprOperator) Inverse() ComparisonExprOperator { + switch op { case EqualOp: return NotEqualOp case LessThanOp: @@ -709,6 +709,15 @@ func Inverse(in ComparisonExprOperator) ComparisonExprOperator { panic("unreachable") } +func (op ComparisonExprOperator) IsCommutative() bool { + switch op { + case EqualOp, NotEqualOp, NullSafeEqualOp: + return true + default: + return false + } +} + // Constant for Enum Type - IsExprOperator const ( IsNullOp IsExprOperator = iota diff --git a/go/vt/vtgate/engine/cached_size.go b/go/vt/vtgate/engine/cached_size.go index f0354e9e726..e65ff61a9f6 100644 --- a/go/vt/vtgate/engine/cached_size.go +++ b/go/vt/vtgate/engine/cached_size.go @@ -793,8 +793,6 @@ func (cached *OrderedAggregate) CachedSize(alloc bool) int64 { if cc, ok := cached.Input.(cachedObject); ok { size += cc.CachedSize(true) } - // field CollationEnv *vitess.io/vitess/go/mysql/collations.Environment - size += cached.CollationEnv.CachedSize(true) return size } func (cached *Plan) CachedSize(alloc bool) int64 { @@ -1076,7 +1074,7 @@ func (cached *SemiJoin) CachedSize(alloc bool) int64 { } size := int64(0) if alloc { - size += int64(64) + size += int64(48) } // field Left vitess.io/vitess/go/vt/vtgate/engine.Primitive if cc, ok := cached.Left.(cachedObject); ok { @@ -1086,10 +1084,6 @@ func (cached *SemiJoin) CachedSize(alloc bool) int64 { if cc, ok := cached.Right.(cachedObject); ok { size += cc.CachedSize(true) } - // field Cols []int - { - size += hack.RuntimeAllocSize(int64(cap(cached.Cols)) * int64(8)) - } // field Vars map[string]int if cached.Vars != nil { size += int64(48) diff --git a/go/vt/vtgate/engine/memory_sort.go b/go/vt/vtgate/engine/memory_sort.go index 4e222498f26..d9919045eaf 100644 --- a/go/vt/vtgate/engine/memory_sort.go +++ b/go/vt/vtgate/engine/memory_sort.go @@ -59,11 +59,6 @@ func (ms *MemorySort) GetTableName() string { return ms.Input.GetTableName() } -// SetTruncateColumnCount sets the truncate column count. -func (ms *MemorySort) SetTruncateColumnCount(count int) { - ms.TruncateColumnCount = count -} - // TryExecute satisfies the Primitive interface. func (ms *MemorySort) TryExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { count, err := ms.fetchCount(ctx, vcursor, bindVars) diff --git a/go/vt/vtgate/engine/ordered_aggregate.go b/go/vt/vtgate/engine/ordered_aggregate.go index 5a72bdf4501..b67483216cf 100644 --- a/go/vt/vtgate/engine/ordered_aggregate.go +++ b/go/vt/vtgate/engine/ordered_aggregate.go @@ -51,8 +51,6 @@ type OrderedAggregate struct { // Input is the primitive that will feed into this Primitive. Input Primitive - - CollationEnv *collations.Environment } // GroupByParams specify the grouping key to be used. @@ -96,11 +94,6 @@ func (oa *OrderedAggregate) GetTableName() string { return oa.Input.GetTableName() } -// SetTruncateColumnCount sets the truncate column count. -func (oa *OrderedAggregate) SetTruncateColumnCount(count int) { - oa.TruncateColumnCount = count -} - // TryExecute is a Primitive function. func (oa *OrderedAggregate) TryExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, _ bool) (*sqltypes.Result, error) { qr, err := oa.execute(ctx, vcursor, bindVars) @@ -344,14 +337,14 @@ func (oa *OrderedAggregate) nextGroupBy(currentKey, nextRow []sqltypes.Value) (n return nextRow, true, nil } - cmp, err := evalengine.NullsafeCompare(v1, v2, oa.CollationEnv, gb.Type.Collation(), gb.Type.Values()) + cmp, err := evalengine.NullsafeCompare(v1, v2, gb.CollationEnv, gb.Type.Collation(), gb.Type.Values()) if err != nil { _, isCollationErr := err.(evalengine.UnsupportedCollationError) if !isCollationErr || gb.WeightStringCol == -1 { return nil, false, err } gb.KeyCol = gb.WeightStringCol - cmp, err = evalengine.NullsafeCompare(currentKey[gb.WeightStringCol], nextRow[gb.WeightStringCol], oa.CollationEnv, gb.Type.Collation(), gb.Type.Values()) + cmp, err = evalengine.NullsafeCompare(currentKey[gb.WeightStringCol], nextRow[gb.WeightStringCol], gb.CollationEnv, gb.Type.Collation(), gb.Type.Values()) if err != nil { return nil, false, err } diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go index a45329c8e84..f28dda01a52 100644 --- a/go/vt/vtgate/engine/route.go +++ b/go/vt/vtgate/engine/route.go @@ -128,11 +128,6 @@ func (route *Route) GetTableName() string { return route.TableName } -// SetTruncateColumnCount sets the truncate column count. -func (route *Route) SetTruncateColumnCount(count int) { - route.TruncateColumnCount = count -} - // TryExecute performs a non-streaming exec. func (route *Route) TryExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { ctx, cancelFunc := addQueryTimeout(ctx, vcursor, route.QueryTimeout) diff --git a/go/vt/vtgate/engine/semi_join.go b/go/vt/vtgate/engine/semi_join.go index 8ab0465249c..de8eeef5a32 100644 --- a/go/vt/vtgate/engine/semi_join.go +++ b/go/vt/vtgate/engine/semi_join.go @@ -18,8 +18,6 @@ package engine import ( "context" - "fmt" - "strings" "vitess.io/vitess/go/sqltypes" querypb "vitess.io/vitess/go/vt/proto/query" @@ -33,14 +31,6 @@ type SemiJoin struct { // of the SemiJoin. They can be any primitive. Left, Right Primitive `json:",omitempty"` - // Cols defines which columns from the left - // results should be used to build the - // return result. For results coming from the - // left query, the index values go as -1, -2, etc. - // If Cols is {-1, -2}, it means that - // the returned result will be {Left0, Left1}. - Cols []int `json:",omitempty"` - // Vars defines the list of SemiJoinVars that need to // be built from the LHS result before invoking // the RHS subquery. @@ -54,7 +44,7 @@ func (jn *SemiJoin) TryExecute(ctx context.Context, vcursor VCursor, bindVars ma if err != nil { return nil, err } - result := &sqltypes.Result{Fields: projectFields(lresult.Fields, jn.Cols)} + result := &sqltypes.Result{Fields: lresult.Fields} for _, lrow := range lresult.Rows { for k, col := range jn.Vars { joinVars[k] = sqltypes.ValueBindVariable(lrow[col]) @@ -64,7 +54,7 @@ func (jn *SemiJoin) TryExecute(ctx context.Context, vcursor VCursor, bindVars ma return nil, err } if len(rresult.Rows) > 0 { - result.Rows = append(result.Rows, projectRows(lrow, jn.Cols)) + result.Rows = append(result.Rows, lrow) } } return result, nil @@ -74,7 +64,7 @@ func (jn *SemiJoin) TryExecute(ctx context.Context, vcursor VCursor, bindVars ma func (jn *SemiJoin) TryStreamExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error { joinVars := make(map[string]*querypb.BindVariable) err := vcursor.StreamExecutePrimitive(ctx, jn.Left, bindVars, wantfields, func(lresult *sqltypes.Result) error { - result := &sqltypes.Result{Fields: projectFields(lresult.Fields, jn.Cols)} + result := &sqltypes.Result{Fields: lresult.Fields} for _, lrow := range lresult.Rows { for k, col := range jn.Vars { joinVars[k] = sqltypes.ValueBindVariable(lrow[col]) @@ -82,7 +72,7 @@ func (jn *SemiJoin) TryStreamExecute(ctx context.Context, vcursor VCursor, bindV rowAdded := false err := vcursor.StreamExecutePrimitive(ctx, jn.Right, combineVars(bindVars, joinVars), false, func(rresult *sqltypes.Result) error { if len(rresult.Rows) > 0 && !rowAdded { - result.Rows = append(result.Rows, projectRows(lrow, jn.Cols)) + result.Rows = append(result.Rows, lrow) rowAdded = true } return nil @@ -135,8 +125,7 @@ func (jn *SemiJoin) NeedsTransaction() bool { func (jn *SemiJoin) description() PrimitiveDescription { other := map[string]any{ - "TableName": jn.GetTableName(), - "ProjectedIndexes": strings.Trim(strings.Join(strings.Fields(fmt.Sprint(jn.Cols)), ","), "[]"), + "TableName": jn.GetTableName(), } if len(jn.Vars) > 0 { other["JoinVars"] = orderedStringIntMap(jn.Vars) @@ -146,30 +135,3 @@ func (jn *SemiJoin) description() PrimitiveDescription { Other: other, } } - -func projectFields(lfields []*querypb.Field, cols []int) []*querypb.Field { - if lfields == nil { - return nil - } - if len(cols) == 0 { - return lfields - } - fields := make([]*querypb.Field, len(cols)) - for i, index := range cols { - fields[i] = lfields[-index-1] - } - return fields -} - -func projectRows(lrow []sqltypes.Value, cols []int) []sqltypes.Value { - if len(cols) == 0 { - return lrow - } - row := make([]sqltypes.Value, len(cols)) - for i, index := range cols { - if index < 0 { - row[i] = lrow[-index-1] - } - } - return row -} diff --git a/go/vt/vtgate/engine/semi_join_test.go b/go/vt/vtgate/engine/semi_join_test.go index 9cf55d4f78f..8fee0490415 100644 --- a/go/vt/vtgate/engine/semi_join_test.go +++ b/go/vt/vtgate/engine/semi_join_test.go @@ -74,7 +74,6 @@ func TestSemiJoinExecute(t *testing.T) { Vars: map[string]int{ "bv": 1, }, - Cols: []int{-1, -2, -3}, } r, err := jn.TryExecute(context.Background(), &noopVCursor{}, bv, true) require.NoError(t, err) @@ -139,7 +138,6 @@ func TestSemiJoinStreamExecute(t *testing.T) { Vars: map[string]int{ "bv": 1, }, - Cols: []int{-1, -2, -3}, } r, err := wrapStreamExecute(jn, &noopVCursor{}, map[string]*querypb.BindVariable{}, true) require.NoError(t, err) diff --git a/go/vt/vtgate/engine/sql_calc_found_rows.go b/go/vt/vtgate/engine/sql_calc_found_rows.go index 2472bfd1d14..64ec80f99c7 100644 --- a/go/vt/vtgate/engine/sql_calc_found_rows.go +++ b/go/vt/vtgate/engine/sql_calc_found_rows.go @@ -34,22 +34,22 @@ type SQLCalcFoundRows struct { } // RouteType implements the Primitive interface -func (s SQLCalcFoundRows) RouteType() string { +func (s *SQLCalcFoundRows) RouteType() string { return "SQLCalcFoundRows" } // GetKeyspaceName implements the Primitive interface -func (s SQLCalcFoundRows) GetKeyspaceName() string { +func (s *SQLCalcFoundRows) GetKeyspaceName() string { return s.LimitPrimitive.GetKeyspaceName() } // GetTableName implements the Primitive interface -func (s SQLCalcFoundRows) GetTableName() string { +func (s *SQLCalcFoundRows) GetTableName() string { return s.LimitPrimitive.GetTableName() } // TryExecute implements the Primitive interface -func (s SQLCalcFoundRows) TryExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { +func (s *SQLCalcFoundRows) TryExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { limitQr, err := vcursor.ExecutePrimitive(ctx, s.LimitPrimitive, bindVars, wantfields) if err != nil { return nil, err @@ -70,7 +70,7 @@ func (s SQLCalcFoundRows) TryExecute(ctx context.Context, vcursor VCursor, bindV } // TryStreamExecute implements the Primitive interface -func (s SQLCalcFoundRows) TryStreamExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error { +func (s *SQLCalcFoundRows) TryStreamExecute(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error { err := vcursor.StreamExecutePrimitive(ctx, s.LimitPrimitive, bindVars, wantfields, callback) if err != nil { return err @@ -104,21 +104,21 @@ func (s SQLCalcFoundRows) TryStreamExecute(ctx context.Context, vcursor VCursor, } // GetFields implements the Primitive interface -func (s SQLCalcFoundRows) GetFields(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { +func (s *SQLCalcFoundRows) GetFields(ctx context.Context, vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { return s.LimitPrimitive.GetFields(ctx, vcursor, bindVars) } // NeedsTransaction implements the Primitive interface -func (s SQLCalcFoundRows) NeedsTransaction() bool { +func (s *SQLCalcFoundRows) NeedsTransaction() bool { return s.LimitPrimitive.NeedsTransaction() } // Inputs implements the Primitive interface -func (s SQLCalcFoundRows) Inputs() ([]Primitive, []map[string]any) { +func (s *SQLCalcFoundRows) Inputs() ([]Primitive, []map[string]any) { return []Primitive{s.LimitPrimitive, s.CountPrimitive}, nil } -func (s SQLCalcFoundRows) description() PrimitiveDescription { +func (s *SQLCalcFoundRows) description() PrimitiveDescription { return PrimitiveDescription{ OperatorType: "SQL_CALC_FOUND_ROWS", } diff --git a/go/vt/vtgate/engine/update_test.go b/go/vt/vtgate/engine/update_test.go index eab2742fc15..eb6af5a5299 100644 --- a/go/vt/vtgate/engine/update_test.go +++ b/go/vt/vtgate/engine/update_test.go @@ -209,34 +209,6 @@ func TestUpdateEqualNoRoute(t *testing.T) { }) } -func TestUpdateEqualNoScatter(t *testing.T) { - t.Skip("planner does not produces this plan anymore") - vindex, _ := vindexes.CreateVindex("lookup_unique", "", map[string]string{ - "table": "lkp", - "from": "from", - "to": "toc", - "write_only": "true", - }) - upd := &Update{ - DML: &DML{ - RoutingParameters: &RoutingParameters{ - Opcode: Equal, - Keyspace: &vindexes.Keyspace{ - Name: "ks", - Sharded: true, - }, - Vindex: vindex, - Values: []evalengine.Expr{evalengine.NewLiteralInt(1)}, - }, - Query: "dummy_update", - }, - } - - vc := newDMLTestVCursor("0") - _, err := upd.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false) - require.EqualError(t, err, `cannot map vindex to unique keyspace id: DestinationKeyRange(-)`) -} - func TestUpdateEqualChangedVindex(t *testing.T) { ks := buildTestVSchema().Keyspaces["sharded"] upd := &Update{ diff --git a/go/vt/vtgate/planbuilder/builder.go b/go/vt/vtgate/planbuilder/builder.go index e79e19ee96b..5d1d4ecd622 100644 --- a/go/vt/vtgate/planbuilder/builder.go +++ b/go/vt/vtgate/planbuilder/builder.go @@ -47,10 +47,6 @@ var ( ) type ( - truncater interface { - SetTruncateColumnCount(int) - } - planResult struct { primitive engine.Primitive tables []string diff --git a/go/vt/vtgate/planbuilder/concatenate.go b/go/vt/vtgate/planbuilder/concatenate.go deleted file mode 100644 index 81cbe3d5b65..00000000000 --- a/go/vt/vtgate/planbuilder/concatenate.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright 2021 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -type concatenate struct { - sources []logicalPlan - - // These column offsets do not need to be typed checked - they usually contain weight_string() - // columns that are not going to be returned to the user - noNeedToTypeCheck []int -} - -var _ logicalPlan = (*concatenate)(nil) - -// Primitive implements the logicalPlan interface -func (c *concatenate) Primitive() engine.Primitive { - var sources []engine.Primitive - for _, source := range c.sources { - sources = append(sources, source.Primitive()) - } - - return engine.NewConcatenate(sources, c.noNeedToTypeCheck) -} diff --git a/go/vt/vtgate/planbuilder/ddl.go b/go/vt/vtgate/planbuilder/ddl.go index 41c868c7450..351bf42672c 100644 --- a/go/vt/vtgate/planbuilder/ddl.go +++ b/go/vt/vtgate/planbuilder/ddl.go @@ -230,9 +230,6 @@ func buildCreateViewCommon( sqlparser.RemoveKeyspace(ddl) if vschema.IsViewsEnabled() { - if keyspace == nil { - return nil, nil, vterrors.VT09005() - } return destination, keyspace, nil } isRoutePlan, opCode := tryToGetRoutePlan(selectPlan.primitive) diff --git a/go/vt/vtgate/planbuilder/delete.go b/go/vt/vtgate/planbuilder/delete.go index 980af21df61..239e7bae0ae 100644 --- a/go/vt/vtgate/planbuilder/delete.go +++ b/go/vt/vtgate/planbuilder/delete.go @@ -63,7 +63,7 @@ func gen4DeleteStmtPlanner( if ks, tables := ctx.SemTable.SingleUnshardedKeyspace(); ks != nil { if !ctx.SemTable.ForeignKeysPresent() { plan := deleteUnshardedShortcut(deleteStmt, ks, tables) - return newPlanResult(plan.Primitive(), operators.QualifiedTables(ks, tables)...), nil + return newPlanResult(plan, operators.QualifiedTables(ks, tables)...), nil } } @@ -78,12 +78,12 @@ func gen4DeleteStmtPlanner( return nil, err } - plan, err := transformToLogicalPlan(ctx, op) + plan, err := transformToPrimitive(ctx, op) if err != nil { return nil, err } - return newPlanResult(plan.Primitive(), operators.TablesUsed(op)...), nil + return newPlanResult(plan, operators.TablesUsed(op)...), nil } func rewriteSingleTbl(del *sqlparser.Delete) (*sqlparser.Delete, error) { @@ -123,7 +123,7 @@ func rewriteSingleTbl(del *sqlparser.Delete) (*sqlparser.Delete, error) { return del, nil } -func deleteUnshardedShortcut(stmt *sqlparser.Delete, ks *vindexes.Keyspace, tables []*vindexes.Table) logicalPlan { +func deleteUnshardedShortcut(stmt *sqlparser.Delete, ks *vindexes.Keyspace, tables []*vindexes.Table) engine.Primitive { edml := engine.NewDML() edml.Keyspace = ks edml.Opcode = engine.Unsharded @@ -131,5 +131,5 @@ func deleteUnshardedShortcut(stmt *sqlparser.Delete, ks *vindexes.Keyspace, tabl for _, tbl := range tables { edml.TableNames = append(edml.TableNames, tbl.Name.String()) } - return &primitiveWrapper{prim: &engine.Delete{DML: edml}} + return &engine.Delete{DML: edml} } diff --git a/go/vt/vtgate/planbuilder/distinct.go b/go/vt/vtgate/planbuilder/distinct.go deleted file mode 100644 index 2a9f58a9942..00000000000 --- a/go/vt/vtgate/planbuilder/distinct.go +++ /dev/null @@ -1,62 +0,0 @@ -/* -Copyright 2020 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*distinct)(nil) - -// distinct is the logicalPlan for engine.Distinct. -type distinct struct { - logicalPlanCommon - checkCols []engine.CheckCol - truncateColumn int - - // needToTruncate is the old way to check weight_string column and set truncation. - needToTruncate bool -} - -func newDistinct(source logicalPlan, checkCols []engine.CheckCol, truncateColumn int) logicalPlan { - return &distinct{ - logicalPlanCommon: newBuilderCommon(source), - checkCols: checkCols, - truncateColumn: truncateColumn, - } -} - -func (d *distinct) Primitive() engine.Primitive { - truncate := d.truncateColumn - if d.needToTruncate { - wsColFound := false - for _, col := range d.checkCols { - if col.WsCol != nil { - wsColFound = true - break - } - } - if wsColFound { - truncate = len(d.checkCols) - } - } - return &engine.Distinct{ - Source: d.input.Primitive(), - CheckCols: d.checkCols, - Truncate: truncate, - } -} diff --git a/go/vt/vtgate/planbuilder/dml_with_input.go b/go/vt/vtgate/planbuilder/dml_with_input.go deleted file mode 100644 index 1cf72e5ab17..00000000000 --- a/go/vt/vtgate/planbuilder/dml_with_input.go +++ /dev/null @@ -1,46 +0,0 @@ -/* -Copyright 2023 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -type dmlWithInput struct { - input logicalPlan - dmls []logicalPlan - - outputCols [][]int - bvList []map[string]int -} - -var _ logicalPlan = (*dmlWithInput)(nil) - -// Primitive implements the logicalPlan interface -func (d *dmlWithInput) Primitive() engine.Primitive { - inp := d.input.Primitive() - var dels []engine.Primitive - for _, dml := range d.dmls { - dels = append(dels, dml.Primitive()) - } - return &engine.DMLWithInput{ - DMLs: dels, - Input: inp, - OutputCols: d.outputCols, - BVList: d.bvList, - } -} diff --git a/go/vt/vtgate/planbuilder/filter.go b/go/vt/vtgate/planbuilder/filter.go deleted file mode 100644 index c3686380446..00000000000 --- a/go/vt/vtgate/planbuilder/filter.go +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright 2021 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -type ( - // filter is the logicalPlan for engine.Filter. - filter struct { - logicalPlanCommon - efilter *engine.Filter - } -) - -var _ logicalPlan = (*filter)(nil) - -// Primitive implements the logicalPlan interface -func (l *filter) Primitive() engine.Primitive { - l.efilter.Input = l.input.Primitive() - return l.efilter -} diff --git a/go/vt/vtgate/planbuilder/fk_cascade.go b/go/vt/vtgate/planbuilder/fk_cascade.go deleted file mode 100644 index f2ca67ef5d0..00000000000 --- a/go/vt/vtgate/planbuilder/fk_cascade.go +++ /dev/null @@ -1,48 +0,0 @@ -/* -Copyright 2023 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*fkCascade)(nil) - -// fkCascade is the logicalPlan for engine.FkCascade. -type fkCascade struct { - parent logicalPlan - selection logicalPlan - children []*engine.FkChild -} - -// newFkCascade builds a new fkCascade. -func newFkCascade(parent, selection logicalPlan, children []*engine.FkChild) *fkCascade { - return &fkCascade{ - parent: parent, - selection: selection, - children: children, - } -} - -// Primitive implements the logicalPlan interface -func (fkc *fkCascade) Primitive() engine.Primitive { - return &engine.FkCascade{ - Parent: fkc.parent.Primitive(), - Selection: fkc.selection.Primitive(), - Children: fkc.children, - } -} diff --git a/go/vt/vtgate/planbuilder/fk_verify.go b/go/vt/vtgate/planbuilder/fk_verify.go deleted file mode 100644 index 206bad90fea..00000000000 --- a/go/vt/vtgate/planbuilder/fk_verify.go +++ /dev/null @@ -1,57 +0,0 @@ -/* -Copyright 2023 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*fkVerify)(nil) - -type verifyLP struct { - verify logicalPlan - typ string -} - -// fkVerify is the logicalPlan for engine.FkVerify. -type fkVerify struct { - input logicalPlan - verify []*verifyLP -} - -// newFkVerify builds a new fkVerify. -func newFkVerify(input logicalPlan, verify []*verifyLP) *fkVerify { - return &fkVerify{ - input: input, - verify: verify, - } -} - -// Primitive implements the logicalPlan interface -func (fkc *fkVerify) Primitive() engine.Primitive { - var verify []*engine.Verify - for _, v := range fkc.verify { - verify = append(verify, &engine.Verify{ - Exec: v.verify.Primitive(), - Typ: v.typ, - }) - } - return &engine.FkVerify{ - Exec: fkc.input.Primitive(), - Verify: verify, - } -} diff --git a/go/vt/vtgate/planbuilder/insert.go b/go/vt/vtgate/planbuilder/insert.go index e674850c753..80516871623 100644 --- a/go/vt/vtgate/planbuilder/insert.go +++ b/go/vt/vtgate/planbuilder/insert.go @@ -53,7 +53,7 @@ func gen4InsertStmtPlanner(version querypb.ExecuteOptions_PlannerVersion, insStm if tables[0].AutoIncrement == nil && !ctx.SemTable.ForeignKeysPresent() { plan := insertUnshardedShortcut(insStmt, ks, tables) setCommentDirectivesOnPlan(plan, insStmt) - return newPlanResult(plan.Primitive(), operators.QualifiedTables(ks, tables)...), nil + return newPlanResult(plan, operators.QualifiedTables(ks, tables)...), nil } } @@ -75,12 +75,12 @@ func gen4InsertStmtPlanner(version querypb.ExecuteOptions_PlannerVersion, insStm return nil, err } - plan, err := transformToLogicalPlan(ctx, op) + plan, err := transformToPrimitive(ctx, op) if err != nil { return nil, err } - return newPlanResult(plan.Primitive(), operators.TablesUsed(op)...), nil + return newPlanResult(plan, operators.TablesUsed(op)...), nil } func errOutIfPlanCannotBeConstructed(ctx *plancontext.PlanningContext, vTbl *vindexes.Table) error { @@ -90,7 +90,7 @@ func errOutIfPlanCannotBeConstructed(ctx *plancontext.PlanningContext, vTbl *vin return ctx.SemTable.NotUnshardedErr } -func insertUnshardedShortcut(stmt *sqlparser.Insert, ks *vindexes.Keyspace, tables []*vindexes.Table) logicalPlan { +func insertUnshardedShortcut(stmt *sqlparser.Insert, ks *vindexes.Keyspace, tables []*vindexes.Table) engine.Primitive { eIns := &engine.Insert{ InsertCommon: engine.InsertCommon{ Opcode: engine.InsertUnsharded, @@ -99,22 +99,5 @@ func insertUnshardedShortcut(stmt *sqlparser.Insert, ks *vindexes.Keyspace, tabl }, } eIns.Query = generateQuery(stmt) - return &insert{eInsert: eIns} -} - -type insert struct { - eInsert *engine.Insert - eInsertSelect *engine.InsertSelect - source logicalPlan -} - -var _ logicalPlan = (*insert)(nil) - -func (i *insert) Primitive() engine.Primitive { - if i.source == nil { - return i.eInsert - } - input := i.source.Primitive() - i.eInsertSelect.Input = input - return i.eInsertSelect + return eIns } diff --git a/go/vt/vtgate/planbuilder/join.go b/go/vt/vtgate/planbuilder/join.go deleted file mode 100644 index 462b45fa00a..00000000000 --- a/go/vt/vtgate/planbuilder/join.go +++ /dev/null @@ -1,70 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*join)(nil) - -// join is used to build a Join primitive. -// It's used to build an inner join and only used by the Gen4 planner -type join struct { - // Left and Right are the nodes for the join. - Left, Right logicalPlan - - // The Opcode tells us if this is an inner or outer join - Opcode engine.JoinOpcode - - // These are the columns that will be produced by this plan. - // Negative offsets come from the LHS, and positive from the RHS - Cols []int - - // Vars are the columns that will be sent from the LHS to the RHS - // the number is the offset on the LHS result, and the string is the bind variable name used in the RHS - Vars map[string]int - - // LHSColumns are the columns from the LHS used for the join. - // These are the same columns pushed on the LHS that are now used in the Vars field - LHSColumns []*sqlparser.ColName -} - -// Primitive implements the logicalPlan interface -func (j *join) Primitive() engine.Primitive { - return &engine.Join{ - Left: j.Left.Primitive(), - Right: j.Right.Primitive(), - Cols: j.Cols, - Vars: j.Vars, - Opcode: j.Opcode, - } -} - -type hashJoin struct { - lhs, rhs logicalPlan - inner *engine.HashJoin -} - -func (hj *hashJoin) Primitive() engine.Primitive { - lhs := hj.lhs.Primitive() - rhs := hj.rhs.Primitive() - hj.inner.Left = lhs - hj.inner.Right = rhs - return hj.inner -} diff --git a/go/vt/vtgate/planbuilder/limit.go b/go/vt/vtgate/planbuilder/limit.go deleted file mode 100644 index 5cfd27dfe06..00000000000 --- a/go/vt/vtgate/planbuilder/limit.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*limit)(nil) - -// limit is the logicalPlan for engine.Limit. -// This gets built if a limit needs to be applied -// after rows are returned from an underlying -// operation. Since a limit is the final operation -// of a SELECT, most pushes are not applicable. -type limit struct { - logicalPlanCommon - elimit *engine.Limit -} - -// newLimit builds a new limit. -func newLimit(plan logicalPlan) *limit { - return &limit{ - logicalPlanCommon: newBuilderCommon(plan), - elimit: &engine.Limit{}, - } -} - -// Primitive implements the logicalPlan interface -func (l *limit) Primitive() engine.Primitive { - l.elimit.Input = l.input.Primitive() - return l.elimit -} diff --git a/go/vt/vtgate/planbuilder/logical_plan.go b/go/vt/vtgate/planbuilder/logical_plan.go deleted file mode 100644 index fac0bb59b5f..00000000000 --- a/go/vt/vtgate/planbuilder/logical_plan.go +++ /dev/null @@ -1,61 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -// logicalPlan defines the interface that a primitive must -// satisfy. -type logicalPlan interface { - // Primitive returns the underlying primitive. - Primitive() engine.Primitive -} - -// ------------------------------------------------------------------------- - -// logicalPlanCommon implements some common functionality of builders. -// Make sure to override in case behavior needs to be changed. -type logicalPlanCommon struct { - order int - input logicalPlan -} - -func newBuilderCommon(input logicalPlan) logicalPlanCommon { - return logicalPlanCommon{input: input} -} - -func (bc *logicalPlanCommon) Order() int { - return bc.order -} - -// ------------------------------------------------------------------------- - -// resultsBuilder is a superset of logicalPlanCommon. It also handles -// resultsColumn functionality. -type resultsBuilder struct { - logicalPlanCommon - truncater truncater -} - -func newResultsBuilder(input logicalPlan, truncater truncater) resultsBuilder { - return resultsBuilder{ - logicalPlanCommon: newBuilderCommon(input), - truncater: truncater, - } -} diff --git a/go/vt/vtgate/planbuilder/memory_sort.go b/go/vt/vtgate/planbuilder/memory_sort.go deleted file mode 100644 index e1d3cf311dc..00000000000 --- a/go/vt/vtgate/planbuilder/memory_sort.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vterrors" - - "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*memorySort)(nil) - -// memorySort is the logicalPlan for engine.Limit. -// This gets built if a limit needs to be applied -// after rows are returned from an underlying -// operation. Since a limit is the final operation -// of a SELECT, most pushes are not applicable. -type memorySort struct { - resultsBuilder - eMemorySort *engine.MemorySort -} - -// Primitive implements the logicalPlan interface -func (ms *memorySort) Primitive() engine.Primitive { - ms.eMemorySort.Input = ms.input.Primitive() - return ms.eMemorySort -} - -// SetLimit implements the logicalPlan interface -func (ms *memorySort) SetLimit(limit *sqlparser.Limit) error { - return vterrors.VT13001("memorySort.Limit: unreachable") -} diff --git a/go/vt/vtgate/planbuilder/merge_sort.go b/go/vt/vtgate/planbuilder/merge_sort.go deleted file mode 100644 index edca9194ccf..00000000000 --- a/go/vt/vtgate/planbuilder/merge_sort.go +++ /dev/null @@ -1,47 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*mergeSort)(nil) - -// mergeSort is a pseudo-primitive. It amends the -// the underlying Route to perform a merge sort. -// It's differentiated as a separate primitive -// because some operations cannot be pushed down, -// which would otherwise be possible with a simple route. -// Since ORDER BY happens near the end of the SQL processing, -// most functions of this primitive are unreachable. -type mergeSort struct { - resultsBuilder - truncateColumnCount int -} - -// SetTruncateColumnCount satisfies the truncater interface. -// This function records the truncate column count and sets -// it later on the eroute during wire-up phase. -func (ms *mergeSort) SetTruncateColumnCount(count int) { - ms.truncateColumnCount = count -} - -// Primitive implements the logicalPlan interface -func (ms *mergeSort) Primitive() engine.Primitive { - return ms.input.Primitive() -} diff --git a/go/vt/vtgate/planbuilder/operator_transformers.go b/go/vt/vtgate/planbuilder/operator_transformers.go index 31367d06b21..76c4ddd476c 100644 --- a/go/vt/vtgate/planbuilder/operator_transformers.go +++ b/go/vt/vtgate/planbuilder/operator_transformers.go @@ -37,7 +37,7 @@ import ( "vitess.io/vitess/go/vt/vtgate/vindexes" ) -func transformToLogicalPlan(ctx *plancontext.PlanningContext, op operators.Operator) (logicalPlan, error) { +func transformToPrimitive(ctx *plancontext.PlanningContext, op operators.Operator) (engine.Primitive, error) { switch op := op.(type) { case *operators.Route: return transformRoutePlan(ctx, op) @@ -79,74 +79,76 @@ func transformToLogicalPlan(ctx *plancontext.PlanningContext, op operators.Opera return transformDMLWithInput(ctx, op) } - return nil, vterrors.VT13001(fmt.Sprintf("unknown type encountered: %T (transformToLogicalPlan)", op)) + return nil, vterrors.VT13001(fmt.Sprintf("unknown type encountered: %T (transformToPrimitive)", op)) } -func transformDMLWithInput(ctx *plancontext.PlanningContext, op *operators.DMLWithInput) (logicalPlan, error) { - input, err := transformToLogicalPlan(ctx, op.Source) +func transformDMLWithInput(ctx *plancontext.PlanningContext, op *operators.DMLWithInput) (engine.Primitive, error) { + input, err := transformToPrimitive(ctx, op.Source) if err != nil { return nil, err } - var dmls []logicalPlan + var dmls []engine.Primitive for _, dml := range op.DML { - del, err := transformToLogicalPlan(ctx, dml) + del, err := transformToPrimitive(ctx, dml) if err != nil { return nil, err } dmls = append(dmls, del) } - return &dmlWithInput{ - input: input, - dmls: dmls, - outputCols: op.Offsets, - bvList: op.BvList, + + return &engine.DMLWithInput{ + DMLs: dmls, + Input: input, + OutputCols: op.Offsets, + BVList: op.BvList, }, nil } -func transformUpsert(ctx *plancontext.PlanningContext, op *operators.Upsert) (logicalPlan, error) { - u := &upsert{} +func transformUpsert(ctx *plancontext.PlanningContext, op *operators.Upsert) (engine.Primitive, error) { + upsert := &engine.Upsert{} for _, source := range op.Sources { iLp, uLp, err := transformOneUpsert(ctx, source) if err != nil { return nil, err } - u.insert = append(u.insert, iLp) - u.update = append(u.update, uLp) + upsert.AddUpsert(iLp, uLp) } - return u, nil + return upsert, nil } -func transformOneUpsert(ctx *plancontext.PlanningContext, source operators.UpsertSource) (iLp, uLp logicalPlan, err error) { - iLp, err = transformToLogicalPlan(ctx, source.Insert) +func transformOneUpsert(ctx *plancontext.PlanningContext, source operators.UpsertSource) (iLp, uLp engine.Primitive, err error) { + iLp, err = transformToPrimitive(ctx, source.Insert) if err != nil { return } - if ins, ok := iLp.(*insert); ok { - ins.eInsert.PreventAutoCommit = true + ins, ok := iLp.(*engine.Insert) + if ok { + ins.PreventAutoCommit = true } - uLp, err = transformToLogicalPlan(ctx, source.Update) + uLp, err = transformToPrimitive(ctx, source.Update) return } -func transformSequential(ctx *plancontext.PlanningContext, op *operators.Sequential) (logicalPlan, error) { - var lps []logicalPlan +func transformSequential(ctx *plancontext.PlanningContext, op *operators.Sequential) (engine.Primitive, error) { + var prims []engine.Primitive for _, source := range op.Sources { - lp, err := transformToLogicalPlan(ctx, source) + prim, err := transformToPrimitive(ctx, source) if err != nil { return nil, err } - if ins, ok := lp.(*insert); ok { - ins.eInsert.PreventAutoCommit = true + ins, ok := prim.(*engine.Insert) + if ok { + ins.PreventAutoCommit = true } - lps = append(lps, lp) + + prims = append(prims, prim) } - return &sequential{ - sources: lps, - }, nil + + return engine.NewSequential(prims), nil } -func transformInsertionSelection(ctx *plancontext.PlanningContext, op *operators.InsertSelection) (logicalPlan, error) { +func transformInsertionSelection(ctx *plancontext.PlanningContext, op *operators.InsertSelection) (engine.Primitive, error) { rb, isRoute := op.Insert.(*operators.Route) if !isRoute { return nil, vterrors.VT13001(fmt.Sprintf("Incorrect type encountered: %T (transformInsertionSelection)", op.Insert)) @@ -173,31 +175,30 @@ func transformInsertionSelection(ctx *plancontext.PlanningContext, op *operators }, VindexValueOffset: ins.VindexValueOffset, } - lp := &insert{eInsertSelect: eins} eins.Prefix, _, eins.Suffix = generateInsertShardedQuery(ins.AST) - selectionPlan, err := transformToLogicalPlan(ctx, op.Select) + selectionPlan, err := transformToPrimitive(ctx, op.Select) if err != nil { return nil, err } - lp.source = selectionPlan - return lp, nil + eins.Input = selectionPlan + return eins, nil } -// transformFkCascade transforms a FkCascade operator into a logical plan. -func transformFkCascade(ctx *plancontext.PlanningContext, fkc *operators.FkCascade) (logicalPlan, error) { - // We convert the parent operator to a logical plan. - parentLP, err := transformToLogicalPlan(ctx, fkc.Parent) +// transformFkCascade transforms a FkCascade operator into an engine primitive +func transformFkCascade(ctx *plancontext.PlanningContext, fkc *operators.FkCascade) (engine.Primitive, error) { + // We convert the parent operator to a primitive + parentLP, err := transformToPrimitive(ctx, fkc.Parent) if err != nil { return nil, nil } - // Once we have the parent logical plan, we can create the selection logical plan and the primitives for the children operators. + // Once we have the parent primitive, we can create the selection primitive and the primitives for the children operators. // For all of these, we don't need the semTable anymore. We set it to nil, to avoid using an incorrect one. ctx.SemTable = nil - selLP, err := transformToLogicalPlan(ctx, fkc.Selection) + selLP, err := transformToPrimitive(ctx, fkc.Selection) if err != nil { return nil, err } @@ -205,12 +206,12 @@ func transformFkCascade(ctx *plancontext.PlanningContext, fkc *operators.FkCasca // Go over the children and convert them to Primitives too. var children []*engine.FkChild for _, child := range fkc.Children { - childLP, err := transformToLogicalPlan(ctx, child.Op) + childLP, err := transformToPrimitive(ctx, child.Op) if err != nil { return nil, err } - childEngine := childLP.Primitive() + childEngine := childLP children = append(children, &engine.FkChild{ BVName: child.BVName, Cols: child.Cols, @@ -219,16 +220,20 @@ func transformFkCascade(ctx *plancontext.PlanningContext, fkc *operators.FkCasca }) } - return newFkCascade(parentLP, selLP, children), nil + return &engine.FkCascade{ + Selection: selLP, + Children: children, + Parent: parentLP, + }, nil } -func transformSubQuery(ctx *plancontext.PlanningContext, op *operators.SubQuery) (logicalPlan, error) { - outer, err := transformToLogicalPlan(ctx, op.Outer) +func transformSubQuery(ctx *plancontext.PlanningContext, op *operators.SubQuery) (engine.Primitive, error) { + outer, err := transformToPrimitive(ctx, op.Outer) if err != nil { return nil, err } - inner, err := transformToLogicalPlan(ctx, op.Subquery) + inner, err := transformToPrimitive(ctx, op.Subquery) if err != nil { return nil, err } @@ -239,53 +244,64 @@ func transformSubQuery(ctx *plancontext.PlanningContext, op *operators.SubQuery) } if len(cols) == 0 { // no correlation, so uncorrelated it is - return newUncorrelatedSubquery(op.FilterType, op.SubqueryValueName, op.HasValuesName, inner, outer), nil - } - - lhsCols := op.OuterExpressionsNeeded(ctx, op.Outer) - return newSemiJoin(outer, inner, op.Vars, lhsCols), nil + return &engine.UncorrelatedSubquery{ + Opcode: op.FilterType, + SubqueryResult: op.SubqueryValueName, + HasValues: op.HasValuesName, + Subquery: inner, + Outer: outer, + }, nil + } + + return &engine.SemiJoin{ + Left: outer, + Right: inner, + Vars: op.Vars, + }, nil } -// transformFkVerify transforms a FkVerify operator into a logical plan. -func transformFkVerify(ctx *plancontext.PlanningContext, fkv *operators.FkVerify) (logicalPlan, error) { - inputLP, err := transformToLogicalPlan(ctx, fkv.Input) +// transformFkVerify transforms a FkVerify operator into a engine primitive +func transformFkVerify(ctx *plancontext.PlanningContext, fkv *operators.FkVerify) (engine.Primitive, error) { + inputLP, err := transformToPrimitive(ctx, fkv.Input) if err != nil { return nil, err } - // Once we have the input logical plan, we can create the primitives for the verification operators. + // Once we have the input primitive, we can create the primitives for the verification operators. // For all of these, we don't need the semTable anymore. We set it to nil, to avoid using an incorrect one. ctx.SemTable = nil // Go over the children and convert them to Primitives too. - var verify []*verifyLP + var verify []*engine.Verify for _, v := range fkv.Verify { - lp, err := transformToLogicalPlan(ctx, v.Op) + lp, err := transformToPrimitive(ctx, v.Op) if err != nil { return nil, err } - verify = append(verify, &verifyLP{ - verify: lp, - typ: v.Typ, + verify = append(verify, &engine.Verify{ + Exec: lp, + Typ: v.Typ, }) } - return newFkVerify(inputLP, verify), nil + return &engine.FkVerify{ + Verify: verify, + Exec: inputLP, + }, nil + } -func transformAggregator(ctx *plancontext.PlanningContext, op *operators.Aggregator) (logicalPlan, error) { +func transformAggregator(ctx *plancontext.PlanningContext, op *operators.Aggregator) (engine.Primitive, error) { if op.WithRollup { return nil, vterrors.VT12001("GROUP BY WITH ROLLUP not supported for sharded queries") } - plan, err := transformToLogicalPlan(ctx, op.Source) + src, err := transformToPrimitive(ctx, op.Source) if err != nil { return nil, err } - oa := &orderedAggregate{ - resultsBuilder: newResultsBuilder(plan, nil), - collationEnv: ctx.VSchema.Environment().CollationEnv(), - } + var aggregates []*engine.AggregateParams + var groupByKeys []*engine.GroupByParams for _, aggr := range op.Aggregations { if aggr.OpCode == opcode.AggregateUnassigned { @@ -297,11 +313,12 @@ func transformAggregator(ctx *plancontext.PlanningContext, op *operators.Aggrega aggrParam.OrigOpcode = aggr.OriginalOpCode aggrParam.WCol = aggr.WSOffset aggrParam.Type = aggr.GetTypeCollation(ctx) - oa.aggregates = append(oa.aggregates, aggrParam) + aggregates = append(aggregates, aggrParam) } + for _, groupBy := range op.Grouping { typ, _ := ctx.SemTable.TypeForExpr(groupBy.Inner) - oa.groupByKeys = append(oa.groupByKeys, &engine.GroupByParams{ + groupByKeys = append(groupByKeys, &engine.GroupByParams{ KeyCol: groupBy.ColOffset, WeightStringCol: groupBy.WSOffset, Expr: groupBy.Inner, @@ -310,20 +327,37 @@ func transformAggregator(ctx *plancontext.PlanningContext, op *operators.Aggrega }) } - oa.truncateColumnCount = op.ResultColumns - return oa, nil + if len(groupByKeys) == 0 { + return &engine.ScalarAggregate{ + Aggregates: aggregates, + TruncateColumnCount: op.ResultColumns, + Input: src, + }, nil + } + + return &engine.OrderedAggregate{ + Aggregates: aggregates, + GroupByKeys: groupByKeys, + TruncateColumnCount: op.ResultColumns, + Input: src, + }, nil } -func transformDistinct(ctx *plancontext.PlanningContext, op *operators.Distinct) (logicalPlan, error) { - src, err := transformToLogicalPlan(ctx, op.Source) +func transformDistinct(ctx *plancontext.PlanningContext, op *operators.Distinct) (engine.Primitive, error) { + src, err := transformToPrimitive(ctx, op.Source) if err != nil { return nil, err } - return newDistinct(src, op.Columns, op.Truncate), nil + + return &engine.Distinct{ + Source: src, + CheckCols: op.Columns, + Truncate: op.Truncate, + }, nil } -func transformOrdering(ctx *plancontext.PlanningContext, op *operators.Ordering) (logicalPlan, error) { - plan, err := transformToLogicalPlan(ctx, op.Source) +func transformOrdering(ctx *plancontext.PlanningContext, op *operators.Ordering) (engine.Primitive, error) { + plan, err := transformToPrimitive(ctx, op.Source) if err != nil { return nil, err } @@ -331,18 +365,15 @@ func transformOrdering(ctx *plancontext.PlanningContext, op *operators.Ordering) return createMemorySort(ctx, plan, op) } -func createMemorySort(ctx *plancontext.PlanningContext, src logicalPlan, ordering *operators.Ordering) (logicalPlan, error) { - primitive := &engine.MemorySort{ +func createMemorySort(ctx *plancontext.PlanningContext, src engine.Primitive, ordering *operators.Ordering) (engine.Primitive, error) { + prim := &engine.MemorySort{ + Input: src, TruncateColumnCount: ordering.ResultColumns, } - ms := &memorySort{ - resultsBuilder: newResultsBuilder(src, primitive), - eMemorySort: primitive, - } for idx, order := range ordering.Order { typ, _ := ctx.SemTable.TypeForExpr(order.SimplifiedExpr) - ms.eMemorySort.OrderBy = append(ms.eMemorySort.OrderBy, evalengine.OrderByParams{ + prim.OrderBy = append(prim.OrderBy, evalengine.OrderByParams{ Col: ordering.Offset[idx], WeightStringCol: ordering.WOffset[idx], Desc: order.Inner.Direction == sqlparser.DescOrder, @@ -351,11 +382,11 @@ func createMemorySort(ctx *plancontext.PlanningContext, src logicalPlan, orderin }) } - return ms, nil + return prim, nil } -func transformProjection(ctx *plancontext.PlanningContext, op *operators.Projection) (logicalPlan, error) { - src, err := transformToLogicalPlan(ctx, op.Source) +func transformProjection(ctx *plancontext.PlanningContext, op *operators.Projection) (engine.Primitive, error) { + src, err := transformToPrimitive(ctx, op.Source) if err != nil { return nil, err } @@ -366,7 +397,7 @@ func transformProjection(ctx *plancontext.PlanningContext, op *operators.Project if len(op.Source.GetColumns(ctx)) == len(cols) && offsetInInputOrder(cols) { cols = nil } - return newSimpleProjection(cols, colNames, src) + return newSimpleProjection(cols, colNames, src), nil } ap, err := op.GetAliasedProjections() @@ -377,7 +408,7 @@ func transformProjection(ctx *plancontext.PlanningContext, op *operators.Project var evalengineExprs []evalengine.Expr var columnNames []string for _, pe := range ap { - ee, err := getEvalEngingeExpr(ctx, pe) + ee, err := getEvalEngineExpr(ctx, pe) if err != nil { return nil, err } @@ -385,14 +416,10 @@ func transformProjection(ctx *plancontext.PlanningContext, op *operators.Project columnNames = append(columnNames, pe.Original.ColumnName()) } - primitive := &engine.Projection{ + return &engine.Projection{ + Input: src, Cols: columnNames, Exprs: evalengineExprs, - } - - return &projection{ - source: src, - primitive: primitive, }, nil } @@ -406,7 +433,7 @@ func offsetInInputOrder(cols []int) bool { return true } -func getEvalEngingeExpr(ctx *plancontext.PlanningContext, pe *operators.ProjExpr) (evalengine.Expr, error) { +func getEvalEngineExpr(ctx *plancontext.PlanningContext, pe *operators.ProjExpr) (evalengine.Expr, error) { switch e := pe.Info.(type) { case *operators.EvalEngine: return e.EExpr, nil @@ -420,57 +447,39 @@ func getEvalEngingeExpr(ctx *plancontext.PlanningContext, pe *operators.ProjExpr } // newSimpleProjection creates a simple projections -func newSimpleProjection(cols []int, colNames []string, src logicalPlan) (logicalPlan, error) { - return &simpleProjection{ - logicalPlanCommon: newBuilderCommon(src), - eSimpleProj: &engine.SimpleProjection{ - Cols: cols, - ColNames: colNames, - }, - }, nil -} - -// elementsMatchIndices checks if the elements of the input slice match -// their corresponding index values. It returns true if all elements match -// their indices, and false otherwise. -func elementsMatchIndices(in []int) bool { - for idx, val := range in { - if val != idx { - return false - } +func newSimpleProjection(cols []int, colNames []string, src engine.Primitive) engine.Primitive { + return &engine.SimpleProjection{ + Input: src, + Cols: cols, + ColNames: colNames, } - return true } -func transformFilter(ctx *plancontext.PlanningContext, op *operators.Filter) (logicalPlan, error) { - plan, err := transformToLogicalPlan(ctx, op.Source) +func transformFilter(ctx *plancontext.PlanningContext, op *operators.Filter) (engine.Primitive, error) { + src, err := transformToPrimitive(ctx, op.Source) if err != nil { return nil, err } predicate := op.PredicateWithOffsets - ast := ctx.SemTable.AndExpressions(op.Predicates...) - if predicate == nil { panic("this should have already been done") } - return &filter{ - logicalPlanCommon: newBuilderCommon(plan), - efilter: &engine.Filter{ - Predicate: predicate, - ASTPredicate: ast, - Truncate: op.Truncate, - }, + return &engine.Filter{ + Input: src, + Predicate: predicate, + ASTPredicate: ctx.SemTable.AndExpressions(op.Predicates...), + Truncate: op.Truncate, }, nil } -func transformApplyJoinPlan(ctx *plancontext.PlanningContext, n *operators.ApplyJoin) (logicalPlan, error) { - lhs, err := transformToLogicalPlan(ctx, n.LHS) +func transformApplyJoinPlan(ctx *plancontext.PlanningContext, n *operators.ApplyJoin) (engine.Primitive, error) { + lhs, err := transformToPrimitive(ctx, n.LHS) if err != nil { return nil, err } - rhs, err := transformToLogicalPlan(ctx, n.RHS) + rhs, err := transformToPrimitive(ctx, n.RHS) if err != nil { return nil, err } @@ -479,12 +488,12 @@ func transformApplyJoinPlan(ctx *plancontext.PlanningContext, n *operators.Apply opCode = engine.LeftJoin } - return &join{ + return &engine.Join{ + Opcode: opCode, Left: lhs, Right: rhs, Cols: n.Columns, Vars: n.Vars, - Opcode: opCode, }, nil } @@ -543,7 +552,7 @@ func getHints(cmt *sqlparser.ParsedComments) *queryHints { } } -func transformRoutePlan(ctx *plancontext.PlanningContext, op *operators.Route) (logicalPlan, error) { +func transformRoutePlan(ctx *plancontext.PlanningContext, op *operators.Route) (engine.Primitive, error) { stmt, dmlOp, err := operators.ToSQL(ctx, op.Source) if err != nil { return nil, err @@ -560,22 +569,26 @@ func transformRoutePlan(ctx *plancontext.PlanningContext, op *operators.Route) ( if op.Lock != sqlparser.NoLock { stmt.SetLock(op.Lock) } - return buildRouteLogicalPlan(ctx, op, stmt, hints) + return buildRoutePrimitive(ctx, op, stmt, hints) case *sqlparser.Update: - return buildUpdateLogicalPlan(ctx, op, dmlOp, stmt, hints) + return buildUpdatePrimitive(ctx, op, dmlOp, stmt, hints) case *sqlparser.Delete: - return buildDeleteLogicalPlan(ctx, op, dmlOp, stmt, hints) + return buildDeletePrimitive(ctx, op, dmlOp, stmt, hints) case *sqlparser.Insert: - return buildInsertLogicalPlan(op, dmlOp, stmt, hints) + return buildInsertPrimitive(op, dmlOp, stmt, hints) default: return nil, vterrors.VT13001(fmt.Sprintf("dont know how to %T", stmt)) } } -func buildRouteLogicalPlan(ctx *plancontext.PlanningContext, op *operators.Route, stmt sqlparser.SelectStatement, hints *queryHints) (logicalPlan, error) { +func buildRoutePrimitive(ctx *plancontext.PlanningContext, op *operators.Route, stmt sqlparser.SelectStatement, hints *queryHints) (engine.Primitive, error) { _ = updateSelectedVindexPredicate(op.Routing) eroute, err := routeToEngineRoute(ctx, op, hints) + if err != nil { + return nil, err + } + for _, order := range op.Ordering { typ, _ := ctx.SemTable.TypeForExpr(order.AST) eroute.OrderBy = append(eroute.OrderBy, evalengine.OrderByParams{ @@ -586,25 +599,21 @@ func buildRouteLogicalPlan(ctx *plancontext.PlanningContext, op *operators.Route CollationEnv: ctx.VSchema.Environment().CollationEnv(), }) } + + prepareTheAST(stmt) + + res, err := WireupRoute(ctx, eroute, stmt) if err != nil { return nil, err } - r := &route{ - eroute: eroute, - Select: stmt, - tables: operators.TableID(op), - } - if err = r.Wireup(ctx); err != nil { - return nil, err - } - return r, nil + return res, nil } -func buildInsertLogicalPlan( +func buildInsertPrimitive( rb *operators.Route, op operators.Operator, stmt *sqlparser.Insert, hints *queryHints, -) (logicalPlan, error) { +) (engine.Primitive, error) { ins := op.(*operators.Insert) ic := engine.InsertCommon{ @@ -624,7 +633,6 @@ func buildInsertLogicalPlan( InsertCommon: ic, VindexValues: ins.VindexValues, } - lp := &insert{eInsert: eins} // we would need to generate the query on the fly. The only exception here is // when unsharded query with autoincrement for that there is no input operator. @@ -636,7 +644,7 @@ func buildInsertLogicalPlan( } eins.Query = generateQuery(stmt) - return lp, nil + return eins, nil } func mapToInsertOpCode(code engine.Opcode) engine.InsertOpcode { @@ -697,13 +705,13 @@ func dmlFormatter(buf *sqlparser.TrackedBuffer, node sqlparser.SQLNode) { node.Format(buf) } -func buildUpdateLogicalPlan( +func buildUpdatePrimitive( ctx *plancontext.PlanningContext, rb *operators.Route, dmlOp operators.Operator, stmt *sqlparser.Update, hints *queryHints, -) (logicalPlan, error) { +) (engine.Primitive, error) { upd := dmlOp.(*operators.Update) var vindexes []*vindexes.ColumnVindex vQuery := "" @@ -722,13 +730,13 @@ func buildUpdateLogicalPlan( _ = updateSelectedVindexPredicate(rb.Routing) edml := createDMLPrimitive(ctx, rb, hints, upd.Target.VTable, generateQuery(stmt), vindexes, vQuery) - return &primitiveWrapper{prim: &engine.Update{ + return &engine.Update{ DML: edml, ChangedVindexValues: upd.ChangedVindexValues, - }}, nil + }, nil } -func buildDeleteLogicalPlan(ctx *plancontext.PlanningContext, rb *operators.Route, dmlOp operators.Operator, stmt *sqlparser.Delete, hints *queryHints) (logicalPlan, error) { +func buildDeletePrimitive(ctx *plancontext.PlanningContext, rb *operators.Route, dmlOp operators.Operator, stmt *sqlparser.Delete, hints *queryHints) (engine.Primitive, error) { del := dmlOp.(*operators.Delete) var vindexes []*vindexes.ColumnVindex @@ -742,7 +750,7 @@ func buildDeleteLogicalPlan(ctx *plancontext.PlanningContext, rb *operators.Rout _ = updateSelectedVindexPredicate(rb.Routing) edml := createDMLPrimitive(ctx, rb, hints, del.Target.VTable, generateQuery(stmt), vindexes, vQuery) - return &primitiveWrapper{prim: &engine.Delete{DML: edml}}, nil + return &engine.Delete{DML: edml}, nil } func createDMLPrimitive(ctx *plancontext.PlanningContext, rb *operators.Route, hints *queryHints, vTbl *vindexes.Table, query string, colVindexes []*vindexes.ColumnVindex, vindexQuery string) *engine.DML { @@ -826,13 +834,13 @@ func getAllTableNames(op *operators.Route) ([]string, error) { return tableNames, nil } -func transformUnionPlan(ctx *plancontext.PlanningContext, op *operators.Union) (logicalPlan, error) { - sources, err := slice.MapWithError(op.Sources, func(src operators.Operator) (logicalPlan, error) { - plan, err := transformToLogicalPlan(ctx, src) +func transformUnionPlan(ctx *plancontext.PlanningContext, op *operators.Union) (engine.Primitive, error) { + sources, err := slice.MapWithError(op.Sources, func(src operators.Operator) (engine.Primitive, error) { + primitive, err := transformToPrimitive(ctx, src) if err != nil { return nil, err } - return plan, nil + return primitive, nil }) if err != nil { return nil, err @@ -841,15 +849,12 @@ func transformUnionPlan(ctx *plancontext.PlanningContext, op *operators.Union) ( if len(sources) == 1 { return sources[0], nil } - return &concatenate{ - sources: sources, - noNeedToTypeCheck: nil, - }, nil + return engine.NewConcatenate(sources, nil), nil } -func transformLimit(ctx *plancontext.PlanningContext, op *operators.Limit) (logicalPlan, error) { - plan, err := transformToLogicalPlan(ctx, op.Source) +func transformLimit(ctx *plancontext.PlanningContext, op *operators.Limit) (engine.Primitive, error) { + plan, err := transformToPrimitive(ctx, op.Source) if err != nil { return nil, err } @@ -857,35 +862,36 @@ func transformLimit(ctx *plancontext.PlanningContext, op *operators.Limit) (logi return createLimit(plan, op.AST, ctx.VSchema.Environment(), ctx.VSchema.ConnCollation()) } -func createLimit(input logicalPlan, limit *sqlparser.Limit, env *vtenv.Environment, coll collations.ID) (logicalPlan, error) { - plan := newLimit(input) +func createLimit(input engine.Primitive, limit *sqlparser.Limit, env *vtenv.Environment, coll collations.ID) (engine.Primitive, error) { cfg := &evalengine.Config{ Collation: coll, Environment: env, } - pv, err := evalengine.Translate(limit.Rowcount, cfg) + count, err := evalengine.Translate(limit.Rowcount, cfg) if err != nil { return nil, vterrors.Wrap(err, "unexpected expression in LIMIT") } - plan.elimit.Count = pv - + var offset evalengine.Expr if limit.Offset != nil { - pv, err = evalengine.Translate(limit.Offset, cfg) + offset, err = evalengine.Translate(limit.Offset, cfg) if err != nil { return nil, vterrors.Wrap(err, "unexpected expression in OFFSET") } - plan.elimit.Offset = pv } - return plan, nil + return &engine.Limit{ + Input: input, + Count: count, + Offset: offset, + }, nil } -func transformHashJoin(ctx *plancontext.PlanningContext, op *operators.HashJoin) (logicalPlan, error) { - lhs, err := transformToLogicalPlan(ctx, op.LHS) +func transformHashJoin(ctx *plancontext.PlanningContext, op *operators.HashJoin) (engine.Primitive, error) { + lhs, err := transformToPrimitive(ctx, op.LHS) if err != nil { return nil, err } - rhs, err := transformToLogicalPlan(ctx, op.RHS) + rhs, err := transformToPrimitive(ctx, op.RHS) if err != nil { return nil, err } @@ -920,23 +926,53 @@ func transformHashJoin(ctx *plancontext.PlanningContext, op *operators.HashJoin) return nil, err } - return &hashJoin{ - lhs: lhs, - rhs: rhs, - inner: &engine.HashJoin{ - Opcode: joinOp, - Cols: op.ColumnOffsets, - LHSKey: op.LHSKeys[0], - RHSKey: op.RHSKeys[0], - ASTPred: op.JoinPredicate(), - Collation: comparisonType.Collation(), - ComparisonType: comparisonType.Type(), - CollationEnv: ctx.VSchema.Environment().CollationEnv(), - Values: comparisonType.Values(), - }, + return &engine.HashJoin{ + Left: lhs, + Right: rhs, + Opcode: joinOp, + Cols: op.ColumnOffsets, + LHSKey: op.LHSKeys[0], + RHSKey: op.RHSKeys[0], + ASTPred: op.JoinPredicate(), + Collation: comparisonType.Collation(), + ComparisonType: comparisonType.Type(), + CollationEnv: ctx.VSchema.Environment().CollationEnv(), + Values: comparisonType.Values(), }, nil } +func transformVindexPlan(ctx *plancontext.PlanningContext, op *operators.Vindex) (engine.Primitive, error) { + single, ok := op.Vindex.(vindexes.SingleColumn) + if !ok { + return nil, vterrors.VT12001("multi-column vindexes not supported") + } + + expr, err := evalengine.Translate(op.Value, &evalengine.Config{ + Collation: ctx.SemTable.Collation, + ResolveType: ctx.SemTable.TypeForExpr, + Environment: ctx.VSchema.Environment(), + }) + if err != nil { + return nil, err + } + prim := &engine.VindexFunc{ + Opcode: op.OpCode, + Vindex: single, + Value: expr, + } + + for _, col := range op.Columns { + err := SupplyProjection(prim, &sqlparser.AliasedExpr{ + Expr: col, + As: sqlparser.IdentifierCI{}, + }, false) + if err != nil { + return nil, err + } + } + return prim, nil +} + func generateQuery(statement sqlparser.Statement) string { buf := sqlparser.NewTrackedBuffer(dmlFormatter) statement.Format(buf) diff --git a/go/vt/vtgate/planbuilder/ordered_aggregate.go b/go/vt/vtgate/planbuilder/ordered_aggregate.go deleted file mode 100644 index c6a37c8decb..00000000000 --- a/go/vt/vtgate/planbuilder/ordered_aggregate.go +++ /dev/null @@ -1,91 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/mysql/collations" - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*orderedAggregate)(nil) - -// orderedAggregate is the logicalPlan for engine.OrderedAggregate. -// This gets built if there are aggregations on a SelectScatter -// route. The primitive requests the underlying route to order -// the results by the grouping columns. This will allow the -// engine code to aggregate the results as they come. -// For example: 'select col1, col2, count(*) from t group by col1, col2' -// will be sent to the scatter route as: -// 'select col1, col2, count(*) from t group by col1, col2 order by col1, col2` -// The orderAggregate primitive built for this will be: -// -// &engine.OrderedAggregate { -// // Aggregates has one column. It computes the count -// // using column 2 of the underlying route. -// Aggregates: []AggregateParams{{ -// Opcode: AggregateCount, -// Col: 2, -// }}, -// -// // Keys has the two group by values for col1 and col2. -// // The column numbers are from the underlying route. -// // These values will be used to perform the grouping -// // of the ordered results as they come from the underlying -// // route. -// Keys: []int{0, 1}, -// Input: (Scatter Route with the order by request), -// } -type orderedAggregate struct { - resultsBuilder - - // aggregates specifies the aggregation parameters for each - // aggregation function: function opcode and input column number. - aggregates []*engine.AggregateParams - - // groupByKeys specifies the input values that must be used for - // the aggregation key. - groupByKeys []*engine.GroupByParams - - truncateColumnCount int - - collationEnv *collations.Environment -} - -// Primitive implements the logicalPlan interface -func (oa *orderedAggregate) Primitive() engine.Primitive { - input := oa.input.Primitive() - if len(oa.groupByKeys) == 0 { - return &engine.ScalarAggregate{ - Aggregates: oa.aggregates, - TruncateColumnCount: oa.truncateColumnCount, - Input: input, - } - } - - return &engine.OrderedAggregate{ - Aggregates: oa.aggregates, - GroupByKeys: oa.groupByKeys, - TruncateColumnCount: oa.truncateColumnCount, - Input: input, - CollationEnv: oa.collationEnv, - } -} - -// SetTruncateColumnCount sets the truncate column count. -func (oa *orderedAggregate) SetTruncateColumnCount(count int) { - oa.truncateColumnCount = count -} diff --git a/go/vt/vtgate/planbuilder/planner.go b/go/vt/vtgate/planbuilder/planner.go index b7a918260b7..cf4e110913d 100644 --- a/go/vt/vtgate/planbuilder/planner.go +++ b/go/vt/vtgate/planbuilder/planner.go @@ -45,7 +45,7 @@ func gen4Planner(query string, plannerVersion querypb.ExecuteOptions_PlannerVers } // setCommentDirectivesOnPlan adds comments to queries -func setCommentDirectivesOnPlan(plan logicalPlan, stmt sqlparser.Statement) { +func setCommentDirectivesOnPlan(plan engine.Primitive, stmt sqlparser.Statement) { var directives *sqlparser.CommentDirectives cmt, ok := stmt.(sqlparser.Commented) if !ok { @@ -57,28 +57,23 @@ func setCommentDirectivesOnPlan(plan logicalPlan, stmt sqlparser.Statement) { timeout := queryTimeout(directives) multiShardAutoCommit := directives.IsSet(sqlparser.DirectiveMultiShardAutocommit) - switch plan := plan.(type) { - case *route: - plan.eroute.ScatterErrorsAsWarnings = scatterAsWarns - plan.eroute.QueryTimeout = timeout - case *primitiveWrapper: - setDirective(plan.prim, multiShardAutoCommit, timeout) - case *insert: - setDirective(plan.eInsert, multiShardAutoCommit, timeout) - } + setDirective(plan, multiShardAutoCommit, timeout, scatterAsWarns) } -func setDirective(prim engine.Primitive, msac bool, timeout int) { - switch edml := prim.(type) { +func setDirective(prim engine.Primitive, msac bool, timeout int, scatterAsWarns bool) { + switch prim := prim.(type) { case *engine.Insert: - edml.MultiShardAutocommit = msac - edml.QueryTimeout = timeout + prim.MultiShardAutocommit = msac + prim.QueryTimeout = timeout case *engine.Update: - edml.MultiShardAutocommit = msac - edml.QueryTimeout = timeout + prim.MultiShardAutocommit = msac + prim.QueryTimeout = timeout case *engine.Delete: - edml.MultiShardAutocommit = msac - edml.QueryTimeout = timeout + prim.MultiShardAutocommit = msac + prim.QueryTimeout = timeout + case *engine.Route: + prim.ScatterErrorsAsWarnings = scatterAsWarns + prim.QueryTimeout = timeout } } diff --git a/go/vt/vtgate/planbuilder/primitive_wrapper.go b/go/vt/vtgate/planbuilder/primitive_wrapper.go deleted file mode 100644 index a03c94ce850..00000000000 --- a/go/vt/vtgate/planbuilder/primitive_wrapper.go +++ /dev/null @@ -1,32 +0,0 @@ -/* -Copyright 2022 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -// primitiveWrapper is used when only need a logical plan that supports plan.Primitive() and nothing else -type primitiveWrapper struct { - prim engine.Primitive -} - -func (p *primitiveWrapper) Primitive() engine.Primitive { - return p.prim -} - -var _ logicalPlan = (*primitiveWrapper)(nil) diff --git a/go/vt/vtgate/planbuilder/projection.go b/go/vt/vtgate/planbuilder/projection.go deleted file mode 100644 index cb60c079c37..00000000000 --- a/go/vt/vtgate/planbuilder/projection.go +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright 2022 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -type projection struct { - source logicalPlan - primitive *engine.Projection -} - -var _ logicalPlan = (*projection)(nil) - -// Primitive implements the logicalPlan interface -func (p *projection) Primitive() engine.Primitive { - if p.primitive == nil { - panic("WireUp not yet run") - } - p.primitive.Input = p.source.Primitive() - return p.primitive -} diff --git a/go/vt/vtgate/planbuilder/route.go b/go/vt/vtgate/planbuilder/route.go index d4f72f0ff3a..e320df14416 100644 --- a/go/vt/vtgate/planbuilder/route.go +++ b/go/vt/vtgate/planbuilder/route.go @@ -22,87 +22,54 @@ import ( "vitess.io/vitess/go/vt/vterrors" "vitess.io/vitess/go/vt/vtgate/engine" "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" - "vitess.io/vitess/go/vt/vtgate/semantics" "vitess.io/vitess/go/vt/vtgate/vindexes" ) -var _ logicalPlan = (*route)(nil) - -// route is used to build a Route primitive. -// It's used to build one of the Select routes like -// SelectScatter, etc. Portions of the original Select AST -// are moved into this node, which will be used to build -// the final SQL for this route. -type route struct { - - // Select is the AST for the query fragment that will be - // executed by this route. - Select sqlparser.SelectStatement - - // eroute is the primitive being built. - eroute *engine.Route - - // is the engine primitive we will return from the Primitive() method. Note that it could be different than eroute - enginePrimitive engine.Primitive - - // tables keeps track of which tables this route is covering - tables semantics.TableSet -} - -// Primitive implements the logicalPlan interface -func (rb *route) Primitive() engine.Primitive { - return rb.enginePrimitive -} - -// Wireup implements the logicalPlan interface -func (rb *route) Wireup(ctx *plancontext.PlanningContext) error { - rb.prepareTheAST() - +// WireupRoute returns an engine primitive for the given route. +func WireupRoute(ctx *plancontext.PlanningContext, eroute *engine.Route, sel sqlparser.SelectStatement) (engine.Primitive, error) { // prepare the queries we will pass down - rb.eroute.Query = sqlparser.String(rb.Select) + eroute.Query = sqlparser.String(sel) buffer := sqlparser.NewTrackedBuffer(sqlparser.FormatImpossibleQuery) - node := buffer.WriteNode(rb.Select) - parsedQuery := node.ParsedQuery() - rb.eroute.FieldQuery = parsedQuery.Query + node := buffer.WriteNode(sel) + eroute.FieldQuery = node.ParsedQuery().Query // if we have a planable vindex lookup, let's extract it into its own primitive - planableVindex, ok := rb.eroute.RoutingParameters.Vindex.(vindexes.LookupPlanable) + planableVindex, ok := eroute.RoutingParameters.Vindex.(vindexes.LookupPlanable) if !ok { - rb.enginePrimitive = rb.eroute - return nil + return eroute, nil } query, args := planableVindex.Query() stmt, reserved, err := ctx.VSchema.Environment().Parser().Parse2(query) if err != nil { - return err + return nil, err } reservedVars := sqlparser.NewReservedVars("vtg", reserved) lookupPrimitive, err := gen4SelectStmtPlanner(query, querypb.ExecuteOptions_Gen4, stmt.(sqlparser.SelectStatement), reservedVars, ctx.VSchema) if err != nil { - return vterrors.Wrapf(err, "failed to plan the lookup query: [%s]", query) + return nil, vterrors.Wrapf(err, "failed to plan the lookup query: [%s]", query) } - rb.enginePrimitive = &engine.VindexLookup{ - Opcode: rb.eroute.Opcode, + vdxLookup := &engine.VindexLookup{ + Opcode: eroute.Opcode, Vindex: planableVindex, - Keyspace: rb.eroute.Keyspace, - Values: rb.eroute.Values, - SendTo: rb.eroute, + Keyspace: eroute.Keyspace, + Values: eroute.Values, + SendTo: eroute, Arguments: args, Lookup: lookupPrimitive.primitive, } - rb.eroute.RoutingParameters.Opcode = engine.ByDestination - rb.eroute.RoutingParameters.Values = nil - rb.eroute.RoutingParameters.Vindex = nil + eroute.RoutingParameters.Opcode = engine.ByDestination + eroute.RoutingParameters.Values = nil + eroute.RoutingParameters.Vindex = nil - return nil + return vdxLookup, nil } // prepareTheAST does minor fixups of the SELECT struct before producing the query string -func (rb *route) prepareTheAST() { +func prepareTheAST(sel sqlparser.SelectStatement) { _ = sqlparser.Walk(func(node sqlparser.SQLNode) (bool, error) { switch node := node.(type) { case *sqlparser.Select: @@ -115,19 +82,12 @@ func (rb *route) prepareTheAST() { } case *sqlparser.ComparisonExpr: // 42 = colName -> colName = 42 - b := node.Operator == sqlparser.EqualOp - value := sqlparser.IsValue(node.Left) - name := sqlparser.IsColName(node.Right) - if b && - value && - name { + if node.Operator.IsCommutative() && + !sqlparser.IsColName(node.Left) && + sqlparser.IsColName(node.Right) { node.Left, node.Right = node.Right, node.Left } } return true, nil - }, rb.Select) -} - -func (rb *route) isSingleShard() bool { - return rb.eroute.Opcode.IsSingleShard() + }, sel) } diff --git a/go/vt/vtgate/planbuilder/select.go b/go/vt/vtgate/planbuilder/select.go index d1ae02f0b86..01dfd8aa387 100644 --- a/go/vt/vtgate/planbuilder/select.go +++ b/go/vt/vtgate/planbuilder/select.go @@ -62,7 +62,7 @@ func gen4SelectStmtPlanner( sel.SQLCalcFoundRows = false } - getPlan := func(selStatement sqlparser.SelectStatement) (logicalPlan, []string, error) { + getPlan := func(selStatement sqlparser.SelectStatement) (engine.Primitive, []string, error) { return newBuildSelectPlan(selStatement, reservedVars, vschema, plannerVersion) } @@ -74,15 +74,14 @@ func gen4SelectStmtPlanner( if shouldRetryAfterPredicateRewriting(plan) { // by transforming the predicates to CNF, the planner will sometimes find better plans // TODO: this should move to the operator side of planning - plan2, tablesUsed := gen4PredicateRewrite(stmt, getPlan) - if plan2 != nil { - return newPlanResult(plan2.Primitive(), tablesUsed...), nil + prim2, tablesUsed := gen4PredicateRewrite(stmt, getPlan) + if prim2 != nil { + return newPlanResult(prim2, tablesUsed...), nil } } - primitive := plan.Primitive() if !isSel { - return newPlanResult(primitive, tablesUsed...), nil + return newPlanResult(plan, tablesUsed...), nil } // this is done because engine.Route doesn't handle the empty result well @@ -90,14 +89,14 @@ func gen4SelectStmtPlanner( // All other engine primitives can handle this, so we only need it when // Route is the last (and only) instruction before the user sees a result if isOnlyDual(sel) || (sel.GroupBy == nil && sel.SelectExprs.AllAggregation()) { - switch prim := primitive.(type) { + switch prim := plan.(type) { case *engine.Route: prim.NoRoutesSpecialHandling = true case *engine.VindexLookup: prim.SendTo.NoRoutesSpecialHandling = true } } - return newPlanResult(primitive, tablesUsed...), nil + return newPlanResult(plan, tablesUsed...), nil } func gen4planSQLCalcFoundRows(vschema plancontext.VSchema, sel *sqlparser.Select, query string, reservedVars *sqlparser.ReservedVars) (*planResult, error) { @@ -116,7 +115,7 @@ func gen4planSQLCalcFoundRows(vschema plancontext.VSchema, sel *sqlparser.Select if err != nil { return nil, err } - return newPlanResult(plan.Primitive(), tablesUsed...), nil + return newPlanResult(plan, tablesUsed...), nil } func buildSQLCalcFoundRowsPlan( @@ -124,7 +123,7 @@ func buildSQLCalcFoundRowsPlan( sel *sqlparser.Select, reservedVars *sqlparser.ReservedVars, vschema plancontext.VSchema, -) (logicalPlan, []string, error) { +) (engine.Primitive, []string, error) { limitPlan, _, err := newBuildSelectPlan(sel, reservedVars, vschema, Gen4) if err != nil { return nil, nil, err @@ -169,10 +168,19 @@ func buildSQLCalcFoundRowsPlan( if err != nil { return nil, nil, err } - return &sqlCalcFoundRows{LimitQuery: limitPlan, CountQuery: countPlan}, tablesUsed, nil + + rb, ok := countPlan.(*engine.Route) + if ok { + // if our count query is an aggregation, we want the no-match result to still return a zero + rb.NoRoutesSpecialHandling = true + } + return &engine.SQLCalcFoundRows{ + LimitPrimitive: limitPlan, + CountPrimitive: countPlan, + }, tablesUsed, nil } -func gen4PredicateRewrite(stmt sqlparser.Statement, getPlan func(selStatement sqlparser.SelectStatement) (logicalPlan, []string, error)) (logicalPlan, []string) { +func gen4PredicateRewrite(stmt sqlparser.Statement, getPlan func(selStatement sqlparser.SelectStatement) (engine.Primitive, []string, error)) (engine.Primitive, []string) { rewritten, isSel := sqlparser.RewritePredicate(stmt).(sqlparser.SelectStatement) if !isSel { // Fail-safe code, should never happen @@ -191,7 +199,7 @@ func newBuildSelectPlan( reservedVars *sqlparser.ReservedVars, vschema plancontext.VSchema, version querypb.ExecuteOptions_PlannerVersion, -) (plan logicalPlan, tablesUsed []string, err error) { +) (plan engine.Primitive, tablesUsed []string, err error) { ctx, err := plancontext.CreatePlanningContext(selStmt, reservedVars, vschema, version) if err != nil { return nil, nil, err @@ -216,7 +224,7 @@ func newBuildSelectPlan( return nil, nil, err } - plan, err = transformToLogicalPlan(ctx, op) + plan, err = transformToPrimitive(ctx, op) if err != nil { return nil, nil, err } @@ -251,24 +259,16 @@ func isOnlyDual(sel *sqlparser.Select) bool { return ok && tableName.Name.String() == "dual" && tableName.Qualifier.IsEmpty() } -func shouldRetryAfterPredicateRewriting(plan logicalPlan) bool { +func shouldRetryAfterPredicateRewriting(plan engine.Primitive) bool { // if we have a I_S query, but have not found table_schema or table_name, let's try CNF - var opcode engine.Opcode - var sysTableTableName map[string]evalengine.Expr - var sysTableTableSchema []evalengine.Expr - - switch routePlan := plan.(type) { - case *route: - opcode = routePlan.eroute.Opcode - sysTableTableName = routePlan.eroute.SysTableTableName - sysTableTableSchema = routePlan.eroute.SysTableTableSchema + switch eroute := plan.(type) { + case *engine.Route: + return eroute.Opcode == engine.DBA && + len(eroute.SysTableTableName) == 0 && + len(eroute.SysTableTableSchema) == 0 default: return false } - - return opcode == engine.DBA && - len(sysTableTableName) == 0 && - len(sysTableTableSchema) == 0 } func handleDualSelects(sel *sqlparser.Select, vschema plancontext.VSchema) (engine.Primitive, error) { diff --git a/go/vt/vtgate/planbuilder/semi_join.go b/go/vt/vtgate/planbuilder/semi_join.go deleted file mode 100644 index b12b04a1ed5..00000000000 --- a/go/vt/vtgate/planbuilder/semi_join.go +++ /dev/null @@ -1,59 +0,0 @@ -/* -Copyright 2021 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*semiJoin)(nil) - -// semiJoin is the logicalPlan for engine.SemiJoin. -// This gets built if a rhs is correlated and can -// be pulled out but requires some variables to be supplied from outside. -type semiJoin struct { - rhs logicalPlan - lhs logicalPlan - cols []int - - vars map[string]int - - // LHSColumns are the columns from the LHS used for the join. - // These are the same columns pushed on the LHS that are now used in the vars field - LHSColumns []*sqlparser.ColName -} - -// newSemiJoin builds a new semiJoin. -func newSemiJoin(lhs, rhs logicalPlan, vars map[string]int, lhsCols []*sqlparser.ColName) *semiJoin { - return &semiJoin{ - rhs: rhs, - lhs: lhs, - vars: vars, - LHSColumns: lhsCols, - } -} - -// Primitive implements the logicalPlan interface -func (ps *semiJoin) Primitive() engine.Primitive { - return &engine.SemiJoin{ - Left: ps.lhs.Primitive(), - Right: ps.rhs.Primitive(), - Vars: ps.vars, - Cols: ps.cols, - } -} diff --git a/go/vt/vtgate/planbuilder/sequential.go b/go/vt/vtgate/planbuilder/sequential.go deleted file mode 100644 index ff6abacb437..00000000000 --- a/go/vt/vtgate/planbuilder/sequential.go +++ /dev/null @@ -1,36 +0,0 @@ -/* -Copyright 2023 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -type sequential struct { - sources []logicalPlan -} - -var _ logicalPlan = (*sequential)(nil) - -// Primitive implements the logicalPlan interface -func (s *sequential) Primitive() engine.Primitive { - var sources []engine.Primitive - for _, source := range s.sources { - sources = append(sources, source.Primitive()) - } - return engine.NewSequential(sources) -} diff --git a/go/vt/vtgate/planbuilder/show.go b/go/vt/vtgate/planbuilder/show.go index 1830f197fa8..734885c9dd9 100644 --- a/go/vt/vtgate/planbuilder/show.go +++ b/go/vt/vtgate/planbuilder/show.go @@ -565,7 +565,6 @@ func buildShowVGtidPlan(show *sqlparser.ShowBasic, vschema plancontext.VSchema) }, TruncateColumnCount: 2, Input: send, - CollationEnv: vschema.Environment().CollationEnv(), }, nil } diff --git a/go/vt/vtgate/planbuilder/simple_projection.go b/go/vt/vtgate/planbuilder/simple_projection.go deleted file mode 100644 index 4c29ef0ae9a..00000000000 --- a/go/vt/vtgate/planbuilder/simple_projection.go +++ /dev/null @@ -1,43 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*simpleProjection)(nil) - -// simpleProjection is used for wrapping a derived table. -// This primitive wraps any derived table that results -// in something that's not a route. It builds a -// 'table' for the derived table allowing higher level -// constructs to reference its columns. If a derived table -// results in a route primitive, we instead build -// a new route that keeps the subquery in the FROM -// clause, because a route is more versatile than -// a simpleProjection. -type simpleProjection struct { - logicalPlanCommon - eSimpleProj *engine.SimpleProjection -} - -// Primitive implements the logicalPlan interface -func (sq *simpleProjection) Primitive() engine.Primitive { - sq.eSimpleProj.Input = sq.input.Primitive() - return sq.eSimpleProj -} diff --git a/go/vt/vtgate/planbuilder/single_sharded_shortcut.go b/go/vt/vtgate/planbuilder/single_sharded_shortcut.go index dea4e7bb595..5d877cd341d 100644 --- a/go/vt/vtgate/planbuilder/single_sharded_shortcut.go +++ b/go/vt/vtgate/planbuilder/single_sharded_shortcut.go @@ -28,7 +28,7 @@ import ( "vitess.io/vitess/go/vt/vtgate/vindexes" ) -func selectUnshardedShortcut(ctx *plancontext.PlanningContext, stmt sqlparser.SelectStatement, ks *vindexes.Keyspace) (logicalPlan, []string, error) { +func selectUnshardedShortcut(ctx *plancontext.PlanningContext, stmt sqlparser.SelectStatement, ks *vindexes.Keyspace) (engine.Primitive, []string, error) { // this method is used when the query we are handling has all tables in the same unsharded keyspace sqlparser.SafeRewrite(stmt, nil, func(cursor *sqlparser.Cursor) bool { switch node := cursor.Node().(type) { @@ -46,21 +46,18 @@ func selectUnshardedShortcut(ctx *plancontext.PlanningContext, stmt sqlparser.Se if err != nil { return nil, nil, err } - plan := &route{ - eroute: &engine.Route{ - RoutingParameters: &engine.RoutingParameters{ - Opcode: engine.Unsharded, - Keyspace: ks, - }, - TableName: strings.Join(escapedTableNames(tableNames), ", "), + eroute := &engine.Route{ + RoutingParameters: &engine.RoutingParameters{ + Opcode: engine.Unsharded, + Keyspace: ks, }, - Select: stmt, + TableName: strings.Join(escapedTableNames(tableNames), ", "), } - - if err := plan.Wireup(ctx); err != nil { + prim, err := WireupRoute(ctx, eroute, stmt) + if err != nil { return nil, nil, err } - return plan, operators.QualifiedTableNames(ks, tableNames), nil + return prim, operators.QualifiedTableNames(ks, tableNames), nil } func escapedTableNames(tableNames []sqlparser.TableName) []string { diff --git a/go/vt/vtgate/planbuilder/sql_calc_found_rows.go b/go/vt/vtgate/planbuilder/sql_calc_found_rows.go deleted file mode 100644 index 62823a8c10e..00000000000 --- a/go/vt/vtgate/planbuilder/sql_calc_found_rows.go +++ /dev/null @@ -1,41 +0,0 @@ -/* -Copyright 2020 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -var _ logicalPlan = (*sqlCalcFoundRows)(nil) - -type sqlCalcFoundRows struct { - LimitQuery, CountQuery logicalPlan -} - -// Primitive implements the logicalPlan interface -func (s *sqlCalcFoundRows) Primitive() engine.Primitive { - countPrim := s.CountQuery.Primitive() - rb, ok := countPrim.(*engine.Route) - if ok { - // if our count query is an aggregation, we want the no-match result to still return a zero - rb.NoRoutesSpecialHandling = true - } - return engine.SQLCalcFoundRows{ - LimitPrimitive: s.LimitQuery.Primitive(), - CountPrimitive: countPrim, - } -} diff --git a/go/vt/vtgate/planbuilder/uncorrelated_subquery.go b/go/vt/vtgate/planbuilder/uncorrelated_subquery.go deleted file mode 100644 index edb46e5b4fe..00000000000 --- a/go/vt/vtgate/planbuilder/uncorrelated_subquery.go +++ /dev/null @@ -1,53 +0,0 @@ -/* -Copyright 2019 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" - popcode "vitess.io/vitess/go/vt/vtgate/engine/opcode" -) - -var _ logicalPlan = (*uncorrelatedSubquery)(nil) - -// uncorrelatedSubquery is the logicalPlan for engine.UncorrelatedSubquery. -// This gets built if a subquery is not correlated and can -// therefore can be pulled out and executed upfront. -type uncorrelatedSubquery struct { - subquery logicalPlan - outer logicalPlan - eSubquery *engine.UncorrelatedSubquery -} - -// newUncorrelatedSubquery builds a new uncorrelatedSubquery. -func newUncorrelatedSubquery(opcode popcode.PulloutOpcode, sqName, hasValues string, subquery, outer logicalPlan) *uncorrelatedSubquery { - return &uncorrelatedSubquery{ - subquery: subquery, - outer: outer, - eSubquery: &engine.UncorrelatedSubquery{ - Opcode: opcode, - SubqueryResult: sqName, - HasValues: hasValues, - }, - } -} - -// Primitive implements the logicalPlan interface -func (ps *uncorrelatedSubquery) Primitive() engine.Primitive { - ps.eSubquery.Subquery = ps.subquery.Primitive() - ps.eSubquery.Outer = ps.outer.Primitive() - return ps.eSubquery -} diff --git a/go/vt/vtgate/planbuilder/update.go b/go/vt/vtgate/planbuilder/update.go index 313f33b6bf1..d653df867fb 100644 --- a/go/vt/vtgate/planbuilder/update.go +++ b/go/vt/vtgate/planbuilder/update.go @@ -61,7 +61,7 @@ func gen4UpdateStmtPlanner( if !ctx.SemTable.ForeignKeysPresent() { plan := updateUnshardedShortcut(updStmt, ks, tables) setCommentDirectivesOnPlan(plan, updStmt) - return newPlanResult(plan.Primitive(), operators.QualifiedTables(ks, tables)...), nil + return newPlanResult(plan, operators.QualifiedTables(ks, tables)...), nil } } @@ -74,15 +74,15 @@ func gen4UpdateStmtPlanner( return nil, err } - plan, err := transformToLogicalPlan(ctx, op) + plan, err := transformToPrimitive(ctx, op) if err != nil { return nil, err } - return newPlanResult(plan.Primitive(), operators.TablesUsed(op)...), nil + return newPlanResult(plan, operators.TablesUsed(op)...), nil } -func updateUnshardedShortcut(stmt *sqlparser.Update, ks *vindexes.Keyspace, tables []*vindexes.Table) logicalPlan { +func updateUnshardedShortcut(stmt *sqlparser.Update, ks *vindexes.Keyspace, tables []*vindexes.Table) engine.Primitive { edml := engine.NewDML() edml.Keyspace = ks edml.Opcode = engine.Unsharded @@ -90,5 +90,5 @@ func updateUnshardedShortcut(stmt *sqlparser.Update, ks *vindexes.Keyspace, tabl for _, tbl := range tables { edml.TableNames = append(edml.TableNames, tbl.Name.String()) } - return &primitiveWrapper{prim: &engine.Update{DML: edml}} + return &engine.Update{DML: edml} } diff --git a/go/vt/vtgate/planbuilder/upsert.go b/go/vt/vtgate/planbuilder/upsert.go deleted file mode 100644 index cd9c127635c..00000000000 --- a/go/vt/vtgate/planbuilder/upsert.go +++ /dev/null @@ -1,37 +0,0 @@ -/* -Copyright 2023 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/vtgate/engine" -) - -type upsert struct { - insert []logicalPlan - update []logicalPlan -} - -var _ logicalPlan = (*upsert)(nil) - -// Primitive implements the logicalPlan interface -func (u *upsert) Primitive() engine.Primitive { - up := &engine.Upsert{} - for i := 0; i < len(u.insert); i++ { - up.AddUpsert(u.insert[i].Primitive(), u.update[i].Primitive()) - } - return up -} diff --git a/go/vt/vtgate/planbuilder/vindex_func.go b/go/vt/vtgate/planbuilder/vindex_func.go index abfd2d1d9b3..6db9adab051 100644 --- a/go/vt/vtgate/planbuilder/vindex_func.go +++ b/go/vt/vtgate/planbuilder/vindex_func.go @@ -20,8 +20,6 @@ import ( "fmt" "vitess.io/vitess/go/mysql/collations" - "vitess.io/vitess/go/vt/vtgate/semantics" - "vitess.io/vitess/go/vt/vterrors" querypb "vitess.io/vitess/go/vt/proto/query" @@ -29,63 +27,36 @@ import ( "vitess.io/vitess/go/vt/vtgate/engine" ) -var _ logicalPlan = (*vindexFunc)(nil) - -// vindexFunc is used to build a VindexFunc primitive. -type vindexFunc struct { - order int - - // the tableID field is only used by the gen4 planner - tableID semantics.TableSet - - // eVindexFunc is the primitive being built. - eVindexFunc *engine.VindexFunc -} - -var colnames = []string{ - "id", - "keyspace_id", - "range_start", - "range_end", - "hex_keyspace_id", - "shard", -} - -// Primitive implements the logicalPlan interface -func (vf *vindexFunc) Primitive() engine.Primitive { - return vf.eVindexFunc -} - // SupplyProjection pushes the given aliased expression into the fields and cols slices of the // vindexFunc engine primitive. The method returns the offset of the new expression in the columns // list. -func (vf *vindexFunc) SupplyProjection(expr *sqlparser.AliasedExpr, reuse bool) (int, error) { +func SupplyProjection(eVindexFunc *engine.VindexFunc, expr *sqlparser.AliasedExpr, reuse bool) error { colName, isColName := expr.Expr.(*sqlparser.ColName) if !isColName { - return 0, vterrors.VT12001("expression on results of a vindex function") + return vterrors.VT12001("expression on results of a vindex function") } enum := vindexColumnToIndex(colName) if enum == -1 { - return 0, vterrors.VT03016(colName.Name.String()) + return vterrors.VT03016(colName.Name.String()) } if reuse { - for i, col := range vf.eVindexFunc.Cols { + for _, col := range eVindexFunc.Cols { if col == enum { - return i, nil + return nil } } } - vf.eVindexFunc.Fields = append(vf.eVindexFunc.Fields, &querypb.Field{ + eVindexFunc.Fields = append(eVindexFunc.Fields, &querypb.Field{ Name: expr.ColumnName(), Type: querypb.Type_VARBINARY, Charset: collations.CollationBinaryID, Flags: uint32(querypb.MySqlFlag_BINARY_FLAG), }) - vf.eVindexFunc.Cols = append(vf.eVindexFunc.Cols, enum) - return len(vf.eVindexFunc.Cols) - 1, nil + eVindexFunc.Cols = append(eVindexFunc.Cols, enum) + return nil } // UnsupportedSupplyWeightString represents the error where the supplying a weight string is not supported diff --git a/go/vt/vtgate/planbuilder/vindex_op.go b/go/vt/vtgate/planbuilder/vindex_op.go deleted file mode 100644 index ffd304aa06d..00000000000 --- a/go/vt/vtgate/planbuilder/vindex_op.go +++ /dev/null @@ -1,63 +0,0 @@ -/* -Copyright 2022 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package planbuilder - -import ( - "vitess.io/vitess/go/vt/sqlparser" - "vitess.io/vitess/go/vt/vterrors" - "vitess.io/vitess/go/vt/vtgate/engine" - "vitess.io/vitess/go/vt/vtgate/evalengine" - "vitess.io/vitess/go/vt/vtgate/planbuilder/operators" - "vitess.io/vitess/go/vt/vtgate/planbuilder/plancontext" - "vitess.io/vitess/go/vt/vtgate/vindexes" -) - -func transformVindexPlan(ctx *plancontext.PlanningContext, op *operators.Vindex) (logicalPlan, error) { - single, ok := op.Vindex.(vindexes.SingleColumn) - if !ok { - return nil, vterrors.VT12001("multi-column vindexes not supported") - } - - expr, err := evalengine.Translate(op.Value, &evalengine.Config{ - Collation: ctx.SemTable.Collation, - ResolveType: ctx.SemTable.TypeForExpr, - Environment: ctx.VSchema.Environment(), - }) - if err != nil { - return nil, err - } - plan := &vindexFunc{ - order: 1, - tableID: op.Solved, - eVindexFunc: &engine.VindexFunc{ - Opcode: op.OpCode, - Vindex: single, - Value: expr, - }, - } - - for _, col := range op.Columns { - _, err := plan.SupplyProjection(&sqlparser.AliasedExpr{ - Expr: col, - As: sqlparser.IdentifierCI{}, - }, false) - if err != nil { - return nil, err - } - } - return plan, nil -} diff --git a/go/vt/vtgate/semantics/early_rewriter.go b/go/vt/vtgate/semantics/early_rewriter.go index cb2d009f8cc..51ed110adf9 100644 --- a/go/vt/vtgate/semantics/early_rewriter.go +++ b/go/vt/vtgate/semantics/early_rewriter.go @@ -161,7 +161,7 @@ func rewriteNotExpr(cursor *sqlparser.Cursor, node *sqlparser.NotExpr) { if cmp.Operator == sqlparser.NullSafeEqualOp { return } - cmp.Operator = sqlparser.Inverse(cmp.Operator) + cmp.Operator = cmp.Operator.Inverse() cursor.Replace(cmp) } diff --git a/go/vt/vttablet/tabletmanager/vdiff/table_differ.go b/go/vt/vttablet/tabletmanager/vdiff/table_differ.go index f6550cc01cd..a98a3ce90f9 100644 --- a/go/vt/vttablet/tabletmanager/vdiff/table_differ.go +++ b/go/vt/vttablet/tabletmanager/vdiff/table_differ.go @@ -478,10 +478,9 @@ func (td *tableDiffer) setupRowSorters() { // the results, which engine.OrderedAggregate can do. if len(td.tablePlan.aggregates) != 0 { td.sourcePrimitive = &engine.OrderedAggregate{ - Aggregates: td.tablePlan.aggregates, - GroupByKeys: pkColsToGroupByParams(td.tablePlan.pkCols, td.wd.collationEnv), - Input: td.sourcePrimitive, - CollationEnv: td.wd.collationEnv, + Aggregates: td.tablePlan.aggregates, + GroupByKeys: pkColsToGroupByParams(td.tablePlan.pkCols, td.wd.collationEnv), + Input: td.sourcePrimitive, } } } diff --git a/go/vt/wrangler/vdiff.go b/go/vt/wrangler/vdiff.go index 2e9529070f6..4caad42ce1f 100644 --- a/go/vt/wrangler/vdiff.go +++ b/go/vt/wrangler/vdiff.go @@ -773,10 +773,9 @@ func (df *vdiff) buildTablePlan(table *tabletmanagerdatapb.TableDefinition, quer // the results, which engine.OrderedAggregate can do. if len(aggregates) != 0 { td.sourcePrimitive = &engine.OrderedAggregate{ - Aggregates: aggregates, - GroupByKeys: pkColsToGroupByParams(td.pkCols, td.collationEnv), - Input: td.sourcePrimitive, - CollationEnv: df.env.CollationEnv(), + Aggregates: aggregates, + GroupByKeys: pkColsToGroupByParams(td.pkCols, td.collationEnv), + Input: td.sourcePrimitive, } } diff --git a/go/vt/wrangler/vdiff_test.go b/go/vt/wrangler/vdiff_test.go index 87988c5fd7e..3ac6edb373c 100644 --- a/go/vt/wrangler/vdiff_test.go +++ b/go/vt/wrangler/vdiff_test.go @@ -441,9 +441,8 @@ func TestVDiffPlanSuccess(t *testing.T) { engine.NewAggregateParam(opcode.AggregateSum, 2, "", collationEnv), engine.NewAggregateParam(opcode.AggregateSum, 3, "", collationEnv), }, - GroupByKeys: []*engine.GroupByParams{{KeyCol: 0, WeightStringCol: -1, CollationEnv: collations.MySQL8()}}, - Input: newMergeSorter(nil, []compareColInfo{{0, collations.Unknown, nil, true}}, collationEnv), - CollationEnv: collationEnv, + GroupByKeys: []*engine.GroupByParams{{KeyCol: 0, WeightStringCol: -1, CollationEnv: collations.MySQL8()}}, + Input: newMergeSorter(nil, []compareColInfo{{0, collations.Unknown, nil, true}}, collationEnv), }, targetPrimitive: newMergeSorter(nil, []compareColInfo{{0, collations.Unknown, nil, true}}, collationEnv), collationEnv: collationEnv,