From b05d3a4a52343180bc9e736c33cb93667cf1aa2c Mon Sep 17 00:00:00 2001 From: "vitess-bot[bot]" <108069721+vitess-bot[bot]@users.noreply.github.com> Date: Wed, 26 Apr 2023 11:11:33 +0000 Subject: [PATCH] fix: union distinct between unsharded route and sharded join (#12974) Signed-off-by: Harshit Gangal Co-authored-by: Harshit Gangal --- .gitignore | 3 + .../planbuilder/operator_transformers.go | 29 ++-- .../planbuilder/testdata/union_cases.json | 125 ++++++++++++++++++ 3 files changed, 141 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index 3595b9673d8..881e89890cc 100644 --- a/.gitignore +++ b/.gitignore @@ -83,3 +83,6 @@ venv .scannerwork report + +# plan test output +/go/vt/vtgate/planbuilder/testdata/plan_test* diff --git a/go/vt/vtgate/planbuilder/operator_transformers.go b/go/vt/vtgate/planbuilder/operator_transformers.go index 9dc2dcd6e0f..ddceddc9ea0 100644 --- a/go/vt/vtgate/planbuilder/operator_transformers.go +++ b/go/vt/vtgate/planbuilder/operator_transformers.go @@ -464,25 +464,22 @@ func pushWeightStringForDistinct(ctx *plancontext.PlanningContext, plan logicalP } node.noNeedToTypeCheck = append(node.noNeedToTypeCheck, newOffset) case *joinGen4: - lhsSolves := node.Left.ContainsTables() - rhsSolves := node.Right.ContainsTables() - expr := node.OutputColumns()[offset] - aliasedExpr, isAliased := expr.(*sqlparser.AliasedExpr) - if !isAliased { - return 0, vterrors.VT13001("cannot convert JOIN output columns to an aliased-expression") - } - deps := ctx.SemTable.RecursiveDeps(aliasedExpr.Expr) + joinOffset := node.Cols[offset] switch { - case deps.IsSolvedBy(lhsSolves): - offset, err = pushWeightStringForDistinct(ctx, node.Left, offset) - node.Cols = append(node.Cols, -(offset + 1)) - case deps.IsSolvedBy(rhsSolves): - offset, err = pushWeightStringForDistinct(ctx, node.Right, offset) - node.Cols = append(node.Cols, offset+1) + case joinOffset < 0: + offset, err = pushWeightStringForDistinct(ctx, node.Left, -(joinOffset + 1)) + offset = -(offset + 1) + case joinOffset > 0: + offset, err = pushWeightStringForDistinct(ctx, node.Right, joinOffset-1) + offset = offset + 1 default: - return 0, vterrors.VT12001("push DISTINCT WEIGHT_STRING to both sides of the join") + return 0, vterrors.VT13001("wrong column offset in join plan to push DISTINCT WEIGHT_STRING") } - newOffset = len(node.Cols) - 1 + if err != nil { + return 0, err + } + newOffset = len(node.Cols) + node.Cols = append(node.Cols, offset) default: return 0, vterrors.VT13001(fmt.Sprintf("pushWeightStringForDistinct on %T", plan)) } diff --git a/go/vt/vtgate/planbuilder/testdata/union_cases.json b/go/vt/vtgate/planbuilder/testdata/union_cases.json index cd78c889706..1acfa7b82dd 100644 --- a/go/vt/vtgate/planbuilder/testdata/union_cases.json +++ b/go/vt/vtgate/planbuilder/testdata/union_cases.json @@ -2453,5 +2453,130 @@ "main.unsharded" ] } + }, + { + "comment": "union of unsharded route with sharded join with involvement of weight string", + "query": "select id, foo, bar from unsharded union select user.intcol, user.textcol2, authoritative.col2 from user join authoritative", + "v3-plan": { + "QueryType": "SELECT", + "Original": "select id, foo, bar from unsharded union select user.intcol, user.textcol2, authoritative.col2 from user join authoritative", + "Instructions": { + "OperatorType": "Distinct", + "Inputs": [ + { + "OperatorType": "Concatenate", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Unsharded", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select id, foo, bar from unsharded where 1 != 1", + "Query": "select id, foo, bar from unsharded", + "Table": "unsharded" + }, + { + "OperatorType": "Join", + "Variant": "Join", + "JoinColumnIndexes": "L:0,L:1,R:0", + "TableName": "`user`_authoritative", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select `user`.intcol, `user`.textcol2 from `user` where 1 != 1", + "Query": "select `user`.intcol, `user`.textcol2 from `user`", + "Table": "`user`" + }, + { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select authoritative.col2 from authoritative where 1 != 1", + "Query": "select authoritative.col2 from authoritative", + "Table": "authoritative" + } + ] + } + ] + } + ] + } + }, + "gen4-plan": { + "QueryType": "SELECT", + "Original": "select id, foo, bar from unsharded union select user.intcol, user.textcol2, authoritative.col2 from user join authoritative", + "Instructions": { + "OperatorType": "Distinct", + "Collations": [ + "(0:3)", + "(1:4)", + "(2:5)" + ], + "ResultColumns": 3, + "Inputs": [ + { + "OperatorType": "Concatenate", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Unsharded", + "Keyspace": { + "Name": "main", + "Sharded": false + }, + "FieldQuery": "select id, foo, bar, weight_string(id), weight_string(foo), weight_string(bar) from unsharded where 1 != 1", + "Query": "select distinct id, foo, bar, weight_string(id), weight_string(foo), weight_string(bar) from unsharded", + "Table": "unsharded" + }, + { + "OperatorType": "Join", + "Variant": "Join", + "JoinColumnIndexes": "L:0,L:1,R:0,L:2,L:3,R:1", + "TableName": "`user`_authoritative", + "Inputs": [ + { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select `user`.intcol, `user`.textcol2, weight_string(`user`.intcol), weight_string(`user`.textcol2) from `user` where 1 != 1", + "Query": "select `user`.intcol, `user`.textcol2, weight_string(`user`.intcol), weight_string(`user`.textcol2) from `user`", + "Table": "`user`" + }, + { + "OperatorType": "Route", + "Variant": "Scatter", + "Keyspace": { + "Name": "user", + "Sharded": true + }, + "FieldQuery": "select authoritative.col2, weight_string(authoritative.col2) from authoritative where 1 != 1", + "Query": "select authoritative.col2, weight_string(authoritative.col2) from authoritative", + "Table": "authoritative" + } + ] + } + ] + } + ] + }, + "TablesUsed": [ + "main.unsharded", + "user.authoritative", + "user.user" + ] + } } ]