Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Gen4] Initial Horizon Planning #7775

Merged
merged 8 commits into from
Apr 10, 2021
1 change: 1 addition & 0 deletions go/mysql/sql_error.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ var stateToMysqlCode = map[vterrors.State]struct {
vterrors.NotSupportedYet: {num: ERNotSupportedYet, state: SSClientError},
vterrors.ForbidSchemaChange: {num: ERForbidSchemaChange, state: SSUnknownSQLState},
vterrors.NetPacketTooLarge: {num: ERNetPacketTooLarge, state: SSNetError},
vterrors.NonUniqError: {num: ERNonUniq, state: SSConstraintViolation},
vterrors.NonUniqTable: {num: ERNonUniqTable, state: SSClientError},
vterrors.QueryInterrupted: {num: ERQueryInterrupted, state: SSQueryInterrupted},
vterrors.SPDoesNotExist: {num: ERSPDoesNotExist, state: SSClientError},
Expand Down
1 change: 1 addition & 0 deletions go/vt/vterrors/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const (
EmptyQuery
ForbidSchemaChange
IncorrectGlobalLocalVar
NonUniqError
NonUniqTable
SyntaxError
WrongGroupField
Expand Down
3 changes: 3 additions & 0 deletions go/vt/vtgate/engine/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,9 @@ func (route *Route) description() PrimitiveDescription {
if orderBy != "" {
other["OrderBy"] = orderBy
}
if route.TruncateColumnCount > 0 {
other["ResultColumns"] = route.TruncateColumnCount
}

return PrimitiveDescription{
OperatorType: "Route",
Expand Down
18 changes: 16 additions & 2 deletions go/vt/vtgate/planbuilder/querygraph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ import (
"strings"
"testing"

"vitess.io/vitess/go/vt/key"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
"vitess.io/vitess/go/vt/vtgate/vindexes"

"github.com/stretchr/testify/assert"

"vitess.io/vitess/go/test/utils"
Expand Down Expand Up @@ -119,7 +123,7 @@ func TestQueryGraph(t *testing.T) {
t.Run(fmt.Sprintf("%d %s", i, sql), func(t *testing.T) {
tree, err := sqlparser.Parse(sql)
require.NoError(t, err)
semTable, err := semantics.Analyse(tree)
semTable, err := semantics.Analyse(tree, &fakeSI{})
require.NoError(t, err)
qgraph, err := createQGFromSelect(tree.(*sqlparser.Select), semTable)
require.NoError(t, err)
Expand All @@ -132,7 +136,7 @@ func TestQueryGraph(t *testing.T) {
func TestString(t *testing.T) {
tree, err := sqlparser.Parse("select * from a,b join c on b.id = c.id where a.id = b.id and b.col IN (select 42) and func() = 'foo'")
require.NoError(t, err)
semTable, err := semantics.Analyse(tree)
semTable, err := semantics.Analyse(tree, &fakeSI{})
require.NoError(t, err)
qgraph, err := createQGFromSelect(tree.(*sqlparser.Select), semTable)
require.NoError(t, err)
Expand Down Expand Up @@ -232,3 +236,13 @@ func (qg *queryGraph) noDepsString() string {
}
return fmt.Sprintf("\nForAll: %s", sqlparser.String(qg.noDeps))
}

var _ semantics.SchemaInformation = (*fakeSI)(nil)

type fakeSI struct {
tables map[string]*vindexes.Table
}

func (s *fakeSI) FindTableOrVindex(tablename sqlparser.TableName) (*vindexes.Table, vindexes.Vindex, string, topodatapb.TabletType, key.Destination, error) {
return s.tables[sqlparser.String(tablename)], nil, "", 0, nil, nil
}
84 changes: 84 additions & 0 deletions go/vt/vtgate/planbuilder/queryprojection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
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 (
vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
"vitess.io/vitess/go/vt/sqlparser"
"vitess.io/vitess/go/vt/vterrors"
"vitess.io/vitess/go/vt/vtgate/semantics"
)

type queryProjection struct {
selectExprs []*sqlparser.AliasedExpr
aggrExprs []*sqlparser.AliasedExpr
groupOrderingCommonExpr map[sqlparser.Expr]*sqlparser.Order

orderExprs sqlparser.OrderBy

// orderExprColMap keeps a map between the Order object and the offset into the select expressions list
orderExprColMap map[*sqlparser.Order]int
}

func newQueryProjection() *queryProjection {
return &queryProjection{
groupOrderingCommonExpr: map[sqlparser.Expr]*sqlparser.Order{},
orderExprColMap: map[*sqlparser.Order]int{},
}
}

func createQPFromSelect(sel *sqlparser.Select) (*queryProjection, error) {
qp := newQueryProjection()

for _, selExp := range sel.SelectExprs {
exp, ok := selExp.(*sqlparser.AliasedExpr)
if !ok {
return nil, semantics.Gen4NotSupportedF("%T in select list", selExp)
}
fExpr, ok := exp.Expr.(*sqlparser.FuncExpr)
if ok && fExpr.IsAggregate() {
if len(fExpr.Exprs) != 1 {
return nil, vterrors.NewErrorf(vtrpcpb.Code_INVALID_ARGUMENT, vterrors.SyntaxError, "multiple arguments inside the function '%s'", sqlparser.String(fExpr))
}
qp.aggrExprs = append(qp.aggrExprs, exp)
continue
}
if nodeHasAggregates(exp.Expr) {
return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "unsupported: in scatter query: complex aggregate expression")
}
qp.selectExprs = append(qp.selectExprs, exp)
}

qp.orderExprs = sel.OrderBy

allExpr := append(qp.selectExprs, qp.aggrExprs...)
for _, order := range sel.OrderBy {
for offset, expr := range allExpr {
if sqlparser.EqualsExpr(order.Expr, expr.Expr) {
qp.orderExprColMap[order] = offset
break
}
// TODO: handle alias and column offset
}
}

if sel.GroupBy == nil || sel.OrderBy == nil {
return qp, nil
}

return qp, nil
}
57 changes: 34 additions & 23 deletions go/vt/vtgate/planbuilder/route_planning.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func gen4Planner(_ string) func(sqlparser.Statement, sqlparser.BindVars, Context
}

func newBuildSelectPlan(sel *sqlparser.Select, vschema ContextVSchema) (engine.Primitive, error) {
semTable, err := semantics.Analyse(sel) // TODO no nil no
semTable, err := semantics.Analyse(sel, vschema)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -74,7 +74,8 @@ func newBuildSelectPlan(sel *sqlparser.Select, vschema ContextVSchema) (engine.P
return nil, err
}

if err := planProjections(sel, plan, semTable); err != nil {
plan, err = planHorizon(sel, plan, semTable)
if err != nil {
return nil, err
}

Expand Down Expand Up @@ -112,7 +113,7 @@ func planLimit(limit *sqlparser.Limit, plan logicalPlan) (logicalPlan, error) {
return lPlan, nil
}

func planProjections(sel *sqlparser.Select, plan logicalPlan, semTable *semantics.SemTable) error {
func planHorizon(sel *sqlparser.Select, plan logicalPlan, semTable *semantics.SemTable) (logicalPlan, error) {
rb, ok := plan.(*route)
if ok && rb.isSingleShard() {
ast := rb.Select.(*sqlparser.Select)
Expand All @@ -121,30 +122,40 @@ func planProjections(sel *sqlparser.Select, plan logicalPlan, semTable *semantic
ast.OrderBy = sel.OrderBy
ast.SelectExprs = sel.SelectExprs
ast.Comments = sel.Comments
} else {
// TODO real horizon planning to be done
if sel.Distinct {
return semantics.Gen4NotSupportedF("DISTINCT")
return plan, nil
}

// TODO real horizon planning to be done
if sel.Distinct {
return nil, semantics.Gen4NotSupportedF("DISTINCT")
}
if sel.GroupBy != nil {
return nil, semantics.Gen4NotSupportedF("GROUP BY")
}
qp, err := createQPFromSelect(sel)
if err != nil {
return nil, err
}
for _, e := range qp.selectExprs {
if _, err := pushProjection(e, plan, semTable); err != nil {
return nil, err
}
if sel.GroupBy != nil {
return semantics.Gen4NotSupportedF("GROUP BY")
}

if len(qp.aggrExprs) > 0 {
plan, err = planAggregations(qp, plan, semTable)
if err != nil {
return nil, err
}
for _, expr := range sel.SelectExprs {
switch e := expr.(type) {
case *sqlparser.AliasedExpr:
if nodeHasAggregates(e.Expr) {
return semantics.Gen4NotSupportedF("aggregation [%s]", sqlparser.String(e))
}
if _, err := pushProjection(e, plan, semTable); err != nil {
return err
}
default:
return semantics.Gen4NotSupportedF("%T", e)
}
}
if len(sel.OrderBy) > 0 {
plan, err = planOrderBy(qp, plan, semTable)
if err != nil {
return nil, err
}

}
return nil

return plan, nil
}

type (
Expand Down
Loading