diff --git a/go/vt/vtgate/planbuilder/operators/ast_to_op.go b/go/vt/vtgate/planbuilder/operators/ast_to_op.go index e7628edacc5..ba366c1292d 100644 --- a/go/vt/vtgate/planbuilder/operators/ast_to_op.go +++ b/go/vt/vtgate/planbuilder/operators/ast_to_op.go @@ -125,6 +125,7 @@ func findTablesContained(ctx *plancontext.PlanningContext, node sqlparser.SQLNod return } +<<<<<<< HEAD func rewriteRemainingColumns( ctx *plancontext.PlanningContext, stmt sqlparser.SelectStatement, @@ -144,6 +145,8 @@ func rewriteRemainingColumns( }, nil).(sqlparser.SelectStatement) } +======= +>>>>>>> fd99639e40 (Fix subquery cloning and dependencies (#15039)) // joinPredicateCollector is used to inspect the predicates inside the subquery, looking for any // comparisons between the inner and the outer side. // They can be used for merging the two parts of the query together diff --git a/go/vt/vtgate/planbuilder/operators/horizon_expanding.go b/go/vt/vtgate/planbuilder/operators/horizon_expanding.go index 84dd7aa3519..5c2c923ab02 100644 --- a/go/vt/vtgate/planbuilder/operators/horizon_expanding.go +++ b/go/vt/vtgate/planbuilder/operators/horizon_expanding.go @@ -114,10 +114,7 @@ func expandSelectHorizon(ctx *plancontext.PlanningContext, horizon *Horizon, sel } if len(qp.OrderExprs) > 0 { - op = &Ordering{ - Source: op, - Order: qp.OrderExprs, - } + op = expandOrderBy(ctx, op, qp) extracted = append(extracted, "Ordering") } @@ -132,11 +129,50 @@ func expandSelectHorizon(ctx *plancontext.PlanningContext, horizon *Horizon, sel return op, rewrite.NewTree(fmt.Sprintf("expand SELECT horizon into (%s)", strings.Join(extracted, ", ")), op), nil } +<<<<<<< HEAD func createProjectionFromSelect(ctx *plancontext.PlanningContext, horizon *Horizon) (out ops.Operator, err error) { qp, err := horizon.getQP(ctx) if err != nil { return nil, err } +======= +func expandOrderBy(ctx *plancontext.PlanningContext, op Operator, qp *QueryProjection) Operator { + proj := newAliasedProjection(op) + var newOrder []OrderBy + sqc := &SubQueryBuilder{} + for _, expr := range qp.OrderExprs { + newExpr, subqs := sqc.pullOutValueSubqueries(ctx, expr.SimplifiedExpr, TableID(op), false) + if newExpr == nil { + // no subqueries found, let's move on + newOrder = append(newOrder, expr) + continue + } + proj.addSubqueryExpr(aeWrap(newExpr), newExpr, subqs...) + newOrder = append(newOrder, OrderBy{ + Inner: &sqlparser.Order{ + Expr: newExpr, + Direction: expr.Inner.Direction, + }, + SimplifiedExpr: newExpr, + }) + + } + + if len(proj.Columns.GetColumns()) > 0 { + // if we had to project columns for the ordering, + // we need the projection as source + op = proj + } + + return &Ordering{ + Source: op, + Order: newOrder, + } +} + +func createProjectionFromSelect(ctx *plancontext.PlanningContext, horizon *Horizon) Operator { + qp := horizon.getQP(ctx) +>>>>>>> fd99639e40 (Fix subquery cloning and dependencies (#15039)) var dt *DerivedTable if horizon.TableId != nil { @@ -271,7 +307,7 @@ func createProjectionWithoutAggr(ctx *plancontext.PlanningContext, qp *QueryProj sqc := &SubQueryBuilder{} outerID := TableID(src) for _, ae := range aes { - org := sqlparser.CloneRefOfAliasedExpr(ae) + org := ctx.SemTable.Clone(ae).(*sqlparser.AliasedExpr) expr := ae.Expr newExpr, subqs, err := sqc.pullOutValueSubqueries(ctx, expr, outerID, false) if err != nil { diff --git a/go/vt/vtgate/planbuilder/operators/queryprojection.go b/go/vt/vtgate/planbuilder/operators/queryprojection.go index 0630b09d459..0e91f6aaf27 100644 --- a/go/vt/vtgate/planbuilder/operators/queryprojection.go +++ b/go/vt/vtgate/planbuilder/operators/queryprojection.go @@ -370,8 +370,13 @@ func (qp *QueryProjection) addOrderBy(ctx *plancontext.PlanningContext, orderBy if !es.add(ctx, order.Expr) { continue } +<<<<<<< HEAD qp.OrderExprs = append(qp.OrderExprs, ops.OrderBy{ Inner: sqlparser.CloneRefOfOrder(order), +======= + qp.OrderExprs = append(qp.OrderExprs, OrderBy{ + Inner: ctx.SemTable.Clone(order).(*sqlparser.Order), +>>>>>>> fd99639e40 (Fix subquery cloning and dependencies (#15039)) SimplifiedExpr: order.Expr, }) canPushSorting = canPushSorting && !containsAggr(order.Expr) diff --git a/go/vt/vtgate/planbuilder/operators/subquery.go b/go/vt/vtgate/planbuilder/operators/subquery.go index a8564052ffa..acedbfe617c 100644 --- a/go/vt/vtgate/planbuilder/operators/subquery.go +++ b/go/vt/vtgate/planbuilder/operators/subquery.go @@ -206,7 +206,14 @@ func (sq *SubQuery) GetMergePredicates() []sqlparser.Expr { func (sq *SubQuery) settle(ctx *plancontext.PlanningContext, outer ops.Operator) (ops.Operator, error) { if !sq.TopLevel { +<<<<<<< HEAD return nil, subqueryNotAtTopErr +======= + panic(subqueryNotAtTopErr) + } + if sq.correlated && sq.FilterType != opcode.PulloutExists { + panic(correlatedSubqueryErr) +>>>>>>> fd99639e40 (Fix subquery cloning and dependencies (#15039)) } if sq.IsProjection { if len(sq.GetMergePredicates()) > 0 { diff --git a/go/vt/vtgate/planbuilder/operators/subquery_builder.go b/go/vt/vtgate/planbuilder/operators/subquery_builder.go index a0897b5ad4b..67ef904f234 100644 --- a/go/vt/vtgate/planbuilder/operators/subquery_builder.go +++ b/go/vt/vtgate/planbuilder/operators/subquery_builder.go @@ -183,10 +183,15 @@ func createSubquery( totalID := subqID.Merge(outerID) sqc := &SubQueryBuilder{totalID: totalID, subqID: subqID, outerID: outerID} +<<<<<<< HEAD predicates, joinCols, err := sqc.inspectStatement(ctx, subq.Select) if err != nil { return nil, err } +======= + predicates, joinCols := sqc.inspectStatement(ctx, subq.Select) + correlated := !ctx.SemTable.RecursiveDeps(subq).IsEmpty() +>>>>>>> fd99639e40 (Fix subquery cloning and dependencies (#15039)) stmt := rewriteRemainingColumns(ctx, subq.Select, subqID) diff --git a/go/vt/vtgate/planbuilder/testdata/aggr_cases.json b/go/vt/vtgate/planbuilder/testdata/aggr_cases.json index a59e289a7e9..2de73685155 100644 --- a/go/vt/vtgate/planbuilder/testdata/aggr_cases.json +++ b/go/vt/vtgate/planbuilder/testdata/aggr_cases.json @@ -6386,7 +6386,7 @@ "Sharded": true }, "FieldQuery": "select id, from_unixtime(min(col)) as col, min(col) from `user` where 1 != 1 group by id", - "OrderBy": "2 ASC", + "OrderBy": "2 ASC COLLATE utf8mb4_0900_ai_ci", "Query": "select id, from_unixtime(min(col)) as col, min(col) from `user` group by id order by min(col) asc", "ResultColumns": 2, "Table": "`user`" diff --git a/go/vt/vtgate/planbuilder/testdata/select_cases.json b/go/vt/vtgate/planbuilder/testdata/select_cases.json index 8d7c902ded3..3bcdda935c4 100644 --- a/go/vt/vtgate/planbuilder/testdata/select_cases.json +++ b/go/vt/vtgate/planbuilder/testdata/select_cases.json @@ -2021,6 +2021,80 @@ } }, { +<<<<<<< HEAD +======= + "comment": "select (select col from user limit 1) as a from user join user_extra order by a", + "query": "select (select col from user limit 1) as a from user join user_extra order by a", + "plan": { + "QueryType": "SELECT", + "Original": "select (select col from user limit 1) as a from user join user_extra order by a", + "Instructions": { + "OperatorType": "Join", + "Variant": "Join", + "JoinColumnIndexes": "L:0", + "TableName": "`user`_user_extra", + "Inputs": [ + { + "OperatorType": "UncorrelatedSubquery", + "Variant": "PulloutValue", + "PulloutVars": [ + "__sq1" + ], + "Inputs": [ + { + "InputName": "SubQuery", + "OperatorType": "Limit", + "Count": "1", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select col from `user` where 1 != 1", + "Query": "select col from `user` limit :__upper_limit", + "Table": "`user`" + } + ] + }, + { + "InputName": "Outer", + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select :__sq1 as __sq1, weight_string(:__sq1) from `user` where 1 != 1", + "OrderBy": "(0|1) ASC", + "Query": "select :__sq1 as __sq1, weight_string(:__sq1) from `user` order by __sq1 asc", + "Table": "`user`" + } + ] + }, + { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select 1 from user_extra where 1 != 1", + "Query": "select 1 from user_extra", + "Table": "user_extra" + } + ] + }, + "TablesUsed": [ + "user.user", + "user.user_extra" + ] + } + }, + { +>>>>>>> fd99639e40 (Fix subquery cloning and dependencies (#15039)) "comment": "select t.a from (select (select col from user limit 1) as a from user join user_extra) t", "query": "select t.a from (select (select col from user limit 1) as a from user join user_extra) t", "plan": { diff --git a/go/vt/vtgate/semantics/semantic_state.go b/go/vt/vtgate/semantics/semantic_state.go index 0af935918f9..c13a41ab8f0 100644 --- a/go/vt/vtgate/semantics/semantic_state.go +++ b/go/vt/vtgate/semantics/semantic_state.go @@ -592,3 +592,13 @@ func (st *SemTable) ASTEquals() *sqlparser.Comparator { } return st.comparator } + +func (st *SemTable) Clone(n sqlparser.SQLNode) sqlparser.SQLNode { + return sqlparser.CopyOnRewrite(n, nil, func(cursor *sqlparser.CopyOnWriteCursor) { + expr, isExpr := cursor.Node().(sqlparser.Expr) + if !isExpr { + return + } + cursor.Replace(sqlparser.CloneExpr(expr)) + }, st.CopySemanticInfo) +}