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

[release-17.0] Fix aliasing in queries by keeping required projections (#15943) #15950

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions go/test/endtoend/vtgate/queries/misc/misc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,180 @@ func TestLeftJoinUsingUnsharded(t *testing.T) {
mcmp, closer := start(t)
defer closer()

<<<<<<< HEAD
utils.Exec(t, mcmp.VtConn, "insert /*vt+ QUERY_TIMEOUT_MS=2000 */ into uks.unsharded(id1) values (1),(2),(3),(4),(5)")
utils.Exec(t, mcmp.VtConn, "select /*vt+ QUERY_TIMEOUT_MS=2000 */ * from uks.unsharded as A left join uks.unsharded as B using(id1)")
=======
utils.Exec(t, mcmp.VtConn, "insert into uks.unsharded(id1) values (1),(2),(3),(4),(5)")
utils.Exec(t, mcmp.VtConn, "select * from uks.unsharded as A left join uks.unsharded as B using(id1)")
}

// TestAnalyze executes different analyze statement and validates that they run successfully.
func TestAnalyze(t *testing.T) {
mcmp, closer := start(t)
defer closer()

for _, workload := range []string{"olap", "oltp"} {
mcmp.Run(workload, func(mcmp *utils.MySQLCompare) {
utils.Exec(t, mcmp.VtConn, fmt.Sprintf("set workload = %s", workload))
utils.Exec(t, mcmp.VtConn, "analyze table t1")
utils.Exec(t, mcmp.VtConn, "analyze table uks.unsharded")
utils.Exec(t, mcmp.VtConn, "analyze table mysql.user")
})
}
}

// TestTransactionModeVar executes SELECT on `transaction_mode` variable
func TestTransactionModeVar(t *testing.T) {
utils.SkipIfBinaryIsBelowVersion(t, 19, "vtgate")

mcmp, closer := start(t)
defer closer()

tcases := []struct {
setStmt string
expRes string
}{{
expRes: `[[VARCHAR("MULTI")]]`,
}, {
setStmt: `set transaction_mode = single`,
expRes: `[[VARCHAR("SINGLE")]]`,
}, {
setStmt: `set transaction_mode = multi`,
expRes: `[[VARCHAR("MULTI")]]`,
}, {
setStmt: `set transaction_mode = twopc`,
expRes: `[[VARCHAR("TWOPC")]]`,
}}

for _, tcase := range tcases {
mcmp.Run(tcase.setStmt, func(mcmp *utils.MySQLCompare) {
if tcase.setStmt != "" {
utils.Exec(t, mcmp.VtConn, tcase.setStmt)
}
utils.AssertMatches(t, mcmp.VtConn, "select @@transaction_mode", tcase.expRes)
})
}
}

// TestAliasesInOuterJoinQueries tests that aliases work in queries that have outer join clauses.
func TestAliasesInOuterJoinQueries(t *testing.T) {
utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")

mcmp, closer := start(t)
defer closer()

// Insert data into the 2 tables
mcmp.Exec("insert into t1(id1, id2) values (1,2), (42,5), (5, 42)")
mcmp.Exec("insert into tbl(id, unq_col, nonunq_col) values (1,2,3), (2,5,3), (3, 42, 2)")

// Check that the select query works as intended and then run it again verifying the column names as well.
mcmp.AssertMatches("select t1.id1 as t0, t1.id1 as t1, tbl.unq_col as col from t1 left outer join tbl on t1.id2 = tbl.nonunq_col", `[[INT64(1) INT64(1) INT64(42)] [INT64(5) INT64(5) NULL] [INT64(42) INT64(42) NULL]]`)
mcmp.ExecWithColumnCompare("select t1.id1 as t0, t1.id1 as t1, tbl.unq_col as col from t1 left outer join tbl on t1.id2 = tbl.nonunq_col")

mcmp.AssertMatches("select t1.id1 as t0, t1.id1 as t1, tbl.unq_col as col from t1 left outer join tbl on t1.id2 = tbl.nonunq_col order by t1.id2 limit 2", `[[INT64(1) INT64(1) INT64(42)] [INT64(42) INT64(42) NULL]]`)
mcmp.ExecWithColumnCompare("select t1.id1 as t0, t1.id1 as t1, tbl.unq_col as col from t1 left outer join tbl on t1.id2 = tbl.nonunq_col order by t1.id2 limit 2")
}

func TestAlterTableWithView(t *testing.T) {
utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()

// Test that create/alter view works and the output is as expected
mcmp.Exec(`use ks_misc`)
mcmp.Exec(`create view v1 as select * from t1`)
var viewDef string
utils.WaitForVschemaCondition(t, clusterInstance.VtgateProcess, keyspaceName, func(t *testing.T, ksMap map[string]any) bool {
views, ok := ksMap["views"]
if !ok {
return false
}
viewsMap := views.(map[string]any)
view, ok := viewsMap["v1"]
if ok {
viewDef = view.(string)
}
return ok
}, "Waiting for view creation")
mcmp.Exec(`insert into t1(id1, id2) values (1, 1)`)
mcmp.AssertMatches("select * from v1", `[[INT64(1) INT64(1)]]`)

// alter table add column
mcmp.Exec(`alter table t1 add column test bigint`)
time.Sleep(10 * time.Second)
mcmp.Exec(`alter view v1 as select * from t1`)

waitForChange := func(t *testing.T, ksMap map[string]any) bool {
// wait for the view definition to change
views := ksMap["views"]
viewsMap := views.(map[string]any)
newView := viewsMap["v1"]
if newView.(string) == viewDef {
return false
}
viewDef = newView.(string)
return true
}
utils.WaitForVschemaCondition(t, clusterInstance.VtgateProcess, keyspaceName, waitForChange, "Waiting for alter view")

mcmp.AssertMatches("select * from v1", `[[INT64(1) INT64(1) NULL]]`)

// alter table remove column
mcmp.Exec(`alter table t1 drop column test`)
mcmp.Exec(`alter view v1 as select * from t1`)

utils.WaitForVschemaCondition(t, clusterInstance.VtgateProcess, keyspaceName, waitForChange, "Waiting for alter view")

mcmp.AssertMatches("select * from v1", `[[INT64(1) INT64(1)]]`)
}

// TestStraightJoin tests that Vitess respects the ordering of join in a STRAIGHT JOIN query.
func TestStraightJoin(t *testing.T) {
utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()

mcmp.Exec("insert into tbl(id, unq_col, nonunq_col) values (1,0,10), (2,10,10), (3,4,20), (4,30,20), (5,40,10)")
mcmp.Exec(`insert into t1(id1, id2) values (10, 11), (20, 13)`)

mcmp.AssertMatchesNoOrder("select tbl.unq_col, tbl.nonunq_col, t1.id2 from t1 join tbl where t1.id1 = tbl.nonunq_col",
`[[INT64(0) INT64(10) INT64(11)] [INT64(10) INT64(10) INT64(11)] [INT64(4) INT64(20) INT64(13)] [INT64(40) INT64(10) INT64(11)] [INT64(30) INT64(20) INT64(13)]]`,
)
// Verify that in a normal join query, vitess joins tbl with t1.
res, err := mcmp.VtConn.ExecuteFetch("vexplain plan select tbl.unq_col, tbl.nonunq_col, t1.id2 from t1 join tbl where t1.id1 = tbl.nonunq_col", 100, false)
require.NoError(t, err)
require.Contains(t, fmt.Sprintf("%v", res.Rows), "tbl_t1")

// Test the same query with a straight join
mcmp.AssertMatchesNoOrder("select tbl.unq_col, tbl.nonunq_col, t1.id2 from t1 straight_join tbl where t1.id1 = tbl.nonunq_col",
`[[INT64(0) INT64(10) INT64(11)] [INT64(10) INT64(10) INT64(11)] [INT64(4) INT64(20) INT64(13)] [INT64(40) INT64(10) INT64(11)] [INT64(30) INT64(20) INT64(13)]]`,
)
// Verify that in a straight join query, vitess joins t1 with tbl.
res, err = mcmp.VtConn.ExecuteFetch("vexplain plan select tbl.unq_col, tbl.nonunq_col, t1.id2 from t1 straight_join tbl where t1.id1 = tbl.nonunq_col", 100, false)
require.NoError(t, err)
require.Contains(t, fmt.Sprintf("%v", res.Rows), "t1_tbl")
}

func TestColumnAliases(t *testing.T) {
utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")
mcmp, closer := start(t)
defer closer()

mcmp.Exec("insert into t1(id1, id2) values (0,0), (1,1)")
mcmp.ExecWithColumnCompare(`select a as k from (select count(*) as a from t1) t`)
}

func TestEnumSetVals(t *testing.T) {
utils.SkipIfBinaryIsBelowVersion(t, 20, "vtgate")

mcmp, closer := start(t)
defer closer()
require.NoError(t, utils.WaitForAuthoritative(t, keyspaceName, "tbl_enum_set", clusterInstance.VtgateProcess.ReadVSchema))

mcmp.Exec("insert into tbl_enum_set(id, enum_col, set_col) values (1, 'medium', 'a,b,e'), (2, 'small', 'e,f,g'), (3, 'large', 'c'), (4, 'xsmall', 'a,b'), (5, 'medium', 'a,d')")

mcmp.AssertMatches("select id, enum_col, cast(enum_col as signed) from tbl_enum_set order by enum_col, id", `[[INT64(4) ENUM("xsmall") INT64(1)] [INT64(2) ENUM("small") INT64(2)] [INT64(1) ENUM("medium") INT64(3)] [INT64(5) ENUM("medium") INT64(3)] [INT64(3) ENUM("large") INT64(4)]]`)
mcmp.AssertMatches("select id, set_col, cast(set_col as unsigned) from tbl_enum_set order by set_col, id", `[[INT64(4) SET("a,b") UINT64(3)] [INT64(3) SET("c") UINT64(4)] [INT64(5) SET("a,d") UINT64(9)] [INT64(1) SET("a,b,e") UINT64(19)] [INT64(2) SET("e,f,g") UINT64(112)]]`)
>>>>>>> 951f2732f3 (Fix aliasing in queries by keeping required projections (#15943))
}
8 changes: 8 additions & 0 deletions go/vt/vtgate/planbuilder/operator_transformers.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,11 @@ func transformProjection(ctx *plancontext.PlanningContext, op *operators.Project
if cols := op.AllOffsets(); cols != nil {
// if all this op is doing is passing through columns from the input, we
// can use the faster SimpleProjection
<<<<<<< HEAD
return useSimpleProjection(op, cols, src)
=======
return useSimpleProjection(cols, colNames, src)
>>>>>>> 951f2732f3 (Fix aliasing in queries by keeping required projections (#15943))
}

expressions := slices2.Map(op.Projections, func(from operators.ProjExpr) sqlparser.Expr {
Expand Down Expand Up @@ -216,6 +220,7 @@ func transformProjection(ctx *plancontext.PlanningContext, op *operators.Project

// useSimpleProjection uses nothing at all if the output is already correct,
// or SimpleProjection when we have to reorder or truncate the columns
<<<<<<< HEAD
func useSimpleProjection(op *operators.Projection, cols []int, src logicalPlan) (logicalPlan, error) {
columns, err := op.Source.GetColumns()
if err != nil {
Expand All @@ -225,6 +230,9 @@ func useSimpleProjection(op *operators.Projection, cols []int, src logicalPlan)
// the columns are already in the right order. we don't need anything at all here
return src, nil
}
=======
func useSimpleProjection(cols []int, colNames []string, src logicalPlan) (logicalPlan, error) {
>>>>>>> 951f2732f3 (Fix aliasing in queries by keeping required projections (#15943))
return &simpleProjection{
logicalPlanCommon: newBuilderCommon(src),
eSimpleProj: &engine.SimpleProjection{
Expand Down
15 changes: 15 additions & 0 deletions go/vt/vtgate/planbuilder/testdata/aggr_cases.json
Original file line number Diff line number Diff line change
Expand Up @@ -4829,8 +4829,18 @@
],
"Inputs": [
{
<<<<<<< HEAD
"OperatorType": "Limit",
"Count": "INT64(10)",
=======
"OperatorType": "SimpleProjection",
"ColumnNames": [
"col"
],
"Columns": [
0
],
>>>>>>> 951f2732f3 (Fix aliasing in queries by keeping required projections (#15943))
"Inputs": [
{
"OperatorType": "Join",
Expand Down Expand Up @@ -4859,8 +4869,13 @@
"Name": "user",
"Sharded": true
},
<<<<<<< HEAD
"FieldQuery": "select user_extra.col as col from user_extra where 1 != 1",
"Query": "select user_extra.col as col from user_extra where user_extra.id = :user_id",
=======
"FieldQuery": "select user_extra.col from user_extra where 1 != 1",
"Query": "select user_extra.col from user_extra where user_extra.id = :user_id",
>>>>>>> 951f2732f3 (Fix aliasing in queries by keeping required projections (#15943))
"Table": "user_extra"
}
]
Expand Down
Loading
Loading