diff --git a/go/test/endtoend/vtgate/queries/random/random_test.go b/go/test/endtoend/vtgate/queries/random/random_test.go index 7b0ab93c165..31b48b4ee52 100644 --- a/go/test/endtoend/vtgate/queries/random/random_test.go +++ b/go/test/endtoend/vtgate/queries/random/random_test.go @@ -85,72 +85,72 @@ func TestMustFix(t *testing.T) { require.NoError(t, utils.WaitForAuthoritative(t, keyspaceName, "dept", clusterInstance.VtgateProcess.ReadVSchema)) // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct case count(*) when 0 then -0 end from emp as tbl0, emp as tbl1 where 0") + helperTest(t, "select distinct case count(*) when 0 then -0 end from emp as tbl0, emp as tbl1 where 0") // results mismatched (maybe derived tables) - helperTest(t, "select /*vt+ PLANNER=Gen4 */ 0 as crandom0 from dept as tbl0, (select /*vt+ PLANNER=Gen4 */ distinct count(*) from emp as tbl1 where 0) as tbl1") + helperTest(t, "select 0 as crandom0 from dept as tbl0, (select distinct count(*) from emp as tbl1 where 0) as tbl1") // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct case count(distinct true) when 'b' then 't' end from emp as tbl1 where 's'") + helperTest(t, "select distinct case count(distinct true) when 'b' then 't' end from emp as tbl1 where 's'") // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct sum(distinct tbl1.deptno) from dept as tbl0, emp as tbl1") + helperTest(t, "select distinct sum(distinct tbl1.deptno) from dept as tbl0, emp as tbl1") // mismatched number of columns - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(*) + 0 from emp as tbl0 order by count(*) desc") + helperTest(t, "select count(*) + 0 from emp as tbl0 order by count(*) desc") // results mismatched (mismatched types) - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(0 >> 0), sum(distinct tbl2.empno) from emp as tbl0 left join emp as tbl2 on -32") + helperTest(t, "select count(0 >> 0), sum(distinct tbl2.empno) from emp as tbl0 left join emp as tbl2 on -32") // results mismatched (decimals off by a little; evalengine problem) - helperTest(t, "select /*vt+ PLANNER=Gen4 */ sum(case false when true then tbl1.deptno else -154 / 132 end) as caggr1 from emp as tbl0, dept as tbl1") + helperTest(t, "select sum(case false when true then tbl1.deptno else -154 / 132 end) as caggr1 from emp as tbl0, dept as tbl1") // EOF - helperTest(t, "select /*vt+ PLANNER=Gen4 */ tbl1.dname as cgroup0, tbl1.dname as cgroup1, tbl1.deptno as crandom0 from dept as tbl0, dept as tbl1 group by tbl1.dname, tbl1.deptno order by tbl1.deptno desc") + helperTest(t, "select tbl1.dname as cgroup0, tbl1.dname as cgroup1, tbl1.deptno as crandom0 from dept as tbl0, dept as tbl1 group by tbl1.dname, tbl1.deptno order by tbl1.deptno desc") // results mismatched // limit >= 9 works - helperTest(t, "select /*vt+ PLANNER=Gen4 */ tbl0.ename as cgroup1 from emp as tbl0 group by tbl0.job, tbl0.ename having sum(tbl0.mgr) order by tbl0.job desc, tbl0.ename asc limit 8") + helperTest(t, "select tbl0.ename as cgroup1 from emp as tbl0 group by tbl0.job, tbl0.ename having sum(tbl0.mgr) order by tbl0.job desc, tbl0.ename asc limit 8") // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct count(*) as caggr1 from emp as tbl1 group by tbl1.sal having max(0) != true") + helperTest(t, "select distinct count(*) as caggr1 from emp as tbl1 group by tbl1.sal having max(0) != true") // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct 0 as caggr0 from dept as tbl0, dept as tbl1 group by tbl1.deptno having max(0) <= 0") + helperTest(t, "select distinct 0 as caggr0 from dept as tbl0, dept as tbl1 group by tbl1.deptno having max(0) <= 0") // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ min(0) as caggr0 from dept as tbl0, emp as tbl1 where case when false then tbl0.dname end group by tbl1.comm") + helperTest(t, "select min(0) as caggr0 from dept as tbl0, emp as tbl1 where case when false then tbl0.dname end group by tbl1.comm") // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(*) as caggr0, 0 as crandom0 from dept as tbl0, emp as tbl1 where 0") + helperTest(t, "select count(*) as caggr0, 0 as crandom0 from dept as tbl0, emp as tbl1 where 0") // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(*) as caggr0, 0 as crandom0 from dept as tbl0, emp as tbl1 where 'o'") + helperTest(t, "select count(*) as caggr0, 0 as crandom0 from dept as tbl0, emp as tbl1 where 'o'") // similar to previous two // results mismatched - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct 'o' as crandom0 from dept as tbl0, emp as tbl1 where 0 having count(*) = count(*)") + helperTest(t, "select distinct 'o' as crandom0 from dept as tbl0, emp as tbl1 where 0 having count(*) = count(*)") // results mismatched (group by + right join) // left instead of right works // swapping tables and predicates and changing to left fails - helperTest(t, "select /*vt+ PLANNER=Gen4 */ 0 from dept as tbl0 right join emp as tbl1 on tbl0.deptno = tbl1.empno and tbl0.deptno = tbl1.deptno group by tbl0.deptno") + helperTest(t, "select 0 from dept as tbl0 right join emp as tbl1 on tbl0.deptno = tbl1.empno and tbl0.deptno = tbl1.deptno group by tbl0.deptno") // results mismatched (count + right join) // left instead of right works // swapping tables and predicates and changing to left fails - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(tbl1.comm) from emp as tbl1 right join emp as tbl2 on tbl1.mgr = tbl2.sal") + helperTest(t, "select count(tbl1.comm) from emp as tbl1 right join emp as tbl2 on tbl1.mgr = tbl2.sal") // Passes with different errors // vitess error: EOF // mysql error: Operand should contain 1 column(s) - helperTest(t, "select /*vt+ PLANNER=Gen4 */ 8 < -31 xor (-29, sum((tbl0.deptno, 'wren', 'ostrich')), max(distinct (tbl0.dname, -15, -8))) in ((sum(distinct (tbl0.dname, 'bengal', -10)), 'ant', true)) as caggr0 from dept as tbl0 where tbl0.deptno * (77 - 61)") + helperTest(t, "select 8 < -31 xor (-29, sum((tbl0.deptno, 'wren', 'ostrich')), max(distinct (tbl0.dname, -15, -8))) in ((sum(distinct (tbl0.dname, 'bengal', -10)), 'ant', true)) as caggr0 from dept as tbl0 where tbl0.deptno * (77 - 61)") // EOF - helperTest(t, "select /*vt+ PLANNER=Gen4 */ tbl1.deptno as cgroup0, tbl1.loc as cgroup1, count(distinct tbl1.loc) as caggr1, tbl1.loc as crandom0 from dept as tbl0, dept as tbl1 group by tbl1.deptno, tbl1.loc") + helperTest(t, "select tbl1.deptno as cgroup0, tbl1.loc as cgroup1, count(distinct tbl1.loc) as caggr1, tbl1.loc as crandom0 from dept as tbl0, dept as tbl1 group by tbl1.deptno, tbl1.loc") // EOF - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(*) from dept as tbl0, (select count(*) from emp as tbl0, emp as tbl1 limit 18) as tbl1") + helperTest(t, "select count(*) from dept as tbl0, (select count(*) from emp as tbl0, emp as tbl1 limit 18) as tbl1") } func TestKnownFailures(t *testing.T) { @@ -160,105 +160,67 @@ func TestKnownFailures(t *testing.T) { require.NoError(t, utils.WaitForAuthoritative(t, keyspaceName, "dept", clusterInstance.VtgateProcess.ReadVSchema)) // logs more stuff - //clusterInstance.EnableGeneralLog() - - // column 'tbl1.`not exists (select 1 from dual)`' not found - helperTest(t, "select /*vt+ PLANNER=Gen4 */ tbl1.`not exists (select 1 from dual)`, count(*) from dept as tbl0, (select /*vt+ PLANNER=Gen4 */ not exists (select 1 from dual) from dept as tbl0 where tbl0.dname) as tbl1 group by tbl0.deptno, tbl1.`not exists (select 1 from dual)`") + // clusterInstance.EnableGeneralLog() // VT13001: [BUG] failed to find the corresponding column - helperTest(t, "select /*vt+ PLANNER=Gen4 */ tbl1.dname as cgroup0, tbl1.dname as cgroup1 from dept as tbl0, dept as tbl1 group by tbl1.dname, tbl1.deptno order by tbl1.deptno desc") + helperTest(t, "select tbl1.dname as cgroup0, tbl1.dname as cgroup1 from dept as tbl0, dept as tbl1 group by tbl1.dname, tbl1.deptno order by tbl1.deptno desc") // vitess error: // mysql error: Operand should contain 1 column(s) helperTest(t, "select (count('sheepdog') ^ (-71 % sum(emp.mgr) ^ count('koi')) and count(*), 'fly') from emp, dept") // rhs of an In operation should be a tuple - helperTest(t, "select /*vt+ PLANNER=Gen4 */ (case when true then min(distinct tbl1.job) else 'bee' end, 'molly') not in (('dane', 0)) as caggr1 from emp as tbl0, emp as tbl1") + helperTest(t, "select (case when true then min(distinct tbl1.job) else 'bee' end, 'molly') not in (('dane', 0)) as caggr1 from emp as tbl0, emp as tbl1") // VT13001: [BUG] in scatter query: complex ORDER BY expression: :vtg1 /* VARCHAR */ - helperTest(t, "select /*vt+ PLANNER=Gen4 */ tbl1.job as cgroup0, sum(distinct 'mudfish'), tbl1.job as crandom0 from emp as tbl0, emp as tbl1 group by tbl1.job order by tbl1.job asc limit 8, 1") - - // VT13001: [BUG] column should not be pushed to projection while doing a column lookup - helperTest(t, "select /*vt+ PLANNER=Gen4 */ -26 in (tbl2.mgr, -8, tbl0.deptno) as crandom0 from dept as tbl0, emp as tbl1 left join emp as tbl2 on tbl2.ename") + helperTest(t, "select tbl1.job as cgroup0, sum(distinct 'mudfish'), tbl1.job as crandom0 from emp as tbl0, emp as tbl1 group by tbl1.job order by tbl1.job asc limit 8, 1") // unsupported: min/max on types that are not comparable is not supported - helperTest(t, "select /*vt+ PLANNER=Gen4 */ max(case true when false then 'gnu' when true then 'meerkat' end) as caggr0 from dept as tbl0") + helperTest(t, "select max(case true when false then 'gnu' when true then 'meerkat' end) as caggr0 from dept as tbl0") // vttablet: rpc error: code = InvalidArgument desc = BIGINT UNSIGNED value is out of range in '(-(273) + (-(15) & 124))' - helperTest(t, "select /*vt+ PLANNER=Gen4 */ -273 + (-15 & 124) as crandom0 from emp as tbl0, emp as tbl1 where tbl1.sal >= tbl1.mgr") - - // vitess error: cannot compare strings, collation is unknown or unsupported (collation ID: 0) - helperTest(t, "select /*vt+ PLANNER=Gen4 */ max(tbl1.dname) as caggr1 from dept as tbl0, dept as tbl1 group by tbl1.dname order by tbl1.dname asc") + helperTest(t, "select -273 + (-15 & 124) as crandom0 from emp as tbl0, emp as tbl1 where tbl1.sal >= tbl1.mgr") // vitess error: // mysql error: Incorrect DATE value: 'tuna' - helperTest(t, "select /*vt+ PLANNER=Gen4 */ min(tbl0.empno) as caggr0 from emp as tbl0 where case 'gator' when false then 314 else 'weevil' end > tbl0.job having min(tbl0.hiredate) <=> 'tuna'") + helperTest(t, "select min(tbl0.empno) as caggr0 from emp as tbl0 where case 'gator' when false then 314 else 'weevil' end > tbl0.job having min(tbl0.hiredate) <=> 'tuna'") // vitess error: // mysql error: Unknown column 'tbl0.deptno' in 'having clause' - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(*) as caggr0 from dept as tbl0 having tbl0.deptno") - - // coercion should not try to coerce this value: DATE("1980-12-17") - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct tbl1.hiredate as cgroup0, count(tbl1.mgr) as caggr0 from emp as tbl1 group by tbl1.hiredate, tbl1.ename") + helperTest(t, "select count(*) as caggr0 from dept as tbl0 having tbl0.deptno") // only_full_group_by enabled // vitess error: In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'ks_random.tbl0.EMPNO'; this is incompatible with sql_mode=only_full_group_by - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct tbl0.empno as cgroup0, count(distinct 56) as caggr0, min('flounder' = 'penguin') as caggr1 from emp as tbl0, (select /*vt+ PLANNER=Gen4 */ 'manatee' as crandom0 from dept as tbl0 where -26 limit 2) as tbl2 where 'anteater' like 'catfish' is null and -11 group by tbl0.empno order by tbl0.empno asc, count(distinct 56) asc, min('flounder' = 'penguin') desc") + helperTest(t, "select distinct tbl0.empno as cgroup0, count(distinct 56) as caggr0, min('flounder' = 'penguin') as caggr1 from emp as tbl0, (select 'manatee' as crandom0 from dept as tbl0 where -26 limit 2) as tbl2 where 'anteater' like 'catfish' is null and -11 group by tbl0.empno order by tbl0.empno asc, count(distinct 56) asc, min('flounder' = 'penguin') desc") // only_full_group_by enabled // vitess error: // mysql error: In aggregated query without GROUP BY, expression #1 of SELECT list contains nonaggregated column 'ks_random.tbl0.ENAME'; this is incompatible with sql_mode=only_full_group_by - helperTest(t, "select /*vt+ PLANNER=Gen4 */ tbl0.ename, min(tbl0.comm) from emp as tbl0 left join emp as tbl1 on tbl0.empno = tbl1.comm and tbl0.empno = tbl1.empno") + helperTest(t, "select tbl0.ename, min(tbl0.comm) from emp as tbl0 left join emp as tbl1 on tbl0.empno = tbl1.comm and tbl0.empno = tbl1.empno") // only_full_group_by enabled // vitess error: // mysql error: Expression #1 of ORDER BY clause is not in SELECT list, references column 'ks_random.tbl2.DNAME' which is not in SELECT list; this is incompatible with DISTINCT - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct count(*) as caggr0 from dept as tbl2 group by tbl2.dname order by tbl2.dname asc") + helperTest(t, "select distinct count(*) as caggr0 from dept as tbl2 group by tbl2.dname order by tbl2.dname asc") // vttablet: rpc error: code = NotFound desc = Unknown column 'cgroup0' in 'field list' (errno 1054) (sqlstate 42S22) (CallerID: userData1) - helperTest(t, "select /*vt+ PLANNER=Gen4 */ tbl1.ename as cgroup0, max(tbl0.comm) as caggr0 from emp as tbl0, emp as tbl1 group by cgroup0") - - // vttablet: rpc error: code = NotFound desc = Unknown column '347' in 'group statement' - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct 347 as crandom0 from emp as tbl0") - - // vttablet: rpc error: code = InvalidArgument desc = Can't group on 'count(*)' (errno 1056) (sqlstate 42000) (CallerID: userData1) - helperTest(t, "select /*vt+ PLANNER=Gen4 */ distinct count(*) from dept as tbl0 group by tbl0.deptno") + helperTest(t, "select tbl1.ename as cgroup0, max(tbl0.comm) as caggr0 from emp as tbl0, emp as tbl1 group by cgroup0") // unsupported // VT12001: unsupported: only one DISTINCT aggregation is allowed in a SELECT: sum(distinct 1) as caggr1 - helperTest(t, "select /*vt+ PLANNER=Gen4 */ sum(distinct tbl0.comm) as caggr0, sum(distinct 1) as caggr1 from emp as tbl0 having 'redfish' < 'blowfish'") - - // unsupported - // VT12001: unsupported: aggregation on top of aggregation not supported - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(*) from dept as tbl1 join (select count(*) from emp as tbl0, dept as tbl1 group by tbl1.loc) as tbl2") - - // unsupported - // VT12001: unsupported: in scatter query: complex aggregate expression - helperTest(t, "select /*vt+ PLANNER=Gen4 */ (select count(*) from emp as tbl0) from emp as tbl0") - - // unsupported - // VT12001: unsupported: using aggregation on top of a *planbuilder.filter plan - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(tbl1.dname) as caggr1 from dept as tbl0 left join dept as tbl1 on tbl1.dname > tbl1.loc where tbl1.loc <=> tbl1.dname group by tbl1.dname order by tbl1.dname asc") - - // unsupported - // VT12001: unsupported: aggregation on top of aggregation not supported - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(*) from (select count(*) from dept as tbl0) as tbl0") - - // unsupported - // VT12001: unsupported: aggregation on top of aggregation not supported - helperTest(t, "select /*vt+ PLANNER=Gen4 */ count(*), count(*) from (select count(*) from dept as tbl0) as tbl0, dept as tbl1") + helperTest(t, "select sum(distinct tbl0.comm) as caggr0, sum(distinct 1) as caggr1 from emp as tbl0 having 'redfish' < 'blowfish'") // unsupported // VT12001: unsupported: in scatter query: aggregation function 'avg(tbl0.deptno)' - helperTest(t, "select /*vt+ PLANNER=Gen4 */ avg(tbl0.deptno) from dept as tbl0") + helperTest(t, "select avg(tbl0.deptno) from dept as tbl0") // unsupported // VT12001: unsupported: LEFT JOIN with derived tables - helperTest(t, "select /*vt+ PLANNER=Gen4 */ -1 as crandom0 from emp as tbl2 left join (select count(*) from dept as tbl1) as tbl3 on 6 != tbl2.deptno") + helperTest(t, "select -1 as crandom0 from emp as tbl2 left join (select count(*) from dept as tbl1) as tbl3 on 6 != tbl2.deptno") // unsupported // VT12001: unsupported: subqueries in GROUP BY - helperTest(t, "select /*vt+ PLANNER=Gen4 */ exists (select 1) as crandom0 from dept as tbl0 group by exists (select 1)") + helperTest(t, "select exists (select 1) as crandom0 from dept as tbl0 group by exists (select 1)") } func TestRandom(t *testing.T) { @@ -343,29 +305,38 @@ func TestBuggyQueries(t *testing.T) { require.NoError(t, utils.WaitForAuthoritative(t, keyspaceName, "emp", clusterInstance.VtgateProcess.ReadVSchema)) require.NoError(t, utils.WaitForAuthoritative(t, keyspaceName, "dept", clusterInstance.VtgateProcess.ReadVSchema)) - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ sum(tbl1.sal) as caggr1 from emp as tbl0, emp as tbl1 group by tbl1.ename order by tbl1.ename asc") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ count(*), count(*), count(*) from dept as tbl0, emp as tbl1 where tbl0.deptno = tbl1.deptno group by tbl1.empno order by tbl1.empno") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ count(tbl0.deptno) from dept as tbl0, emp as tbl1 group by tbl1.job order by tbl1.job limit 3") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ count(*), count(*) from emp as tbl0 group by tbl0.empno order by tbl0.empno") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ distinct count(*), tbl0.loc from dept as tbl0 group by tbl0.loc") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ distinct count(*) from dept as tbl0 group by tbl0.loc") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ sum(tbl1.comm) from emp as tbl0, emp as tbl1") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ tbl1.mgr, tbl1.mgr, count(*) from emp as tbl1 group by tbl1.mgr") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ tbl1.mgr, tbl1.mgr, count(*) from emp as tbl0, emp as tbl1 group by tbl1.mgr") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ count(*), count(*), count(tbl0.comm) from emp as tbl0, emp as tbl1 join dept as tbl2") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ count(*), count(*) from (select count(*) from dept as tbl0 group by tbl0.deptno) as tbl0, dept as tbl1") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ count(*) from (select count(*) from dept as tbl0 group by tbl0.deptno) as tbl0") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ min(tbl0.loc) from dept as tbl0") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ tbl1.empno, max(tbl1.job) from dept as tbl0, emp as tbl1 group by tbl1.empno") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ tbl1.ename, max(tbl0.comm) from emp as tbl0, emp as tbl1 group by tbl1.ename") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ tbl0.dname, tbl0.dname, min(tbl0.deptno) from dept as tbl0, dept as tbl1 group by tbl0.dname, tbl0.dname") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ tbl0.dname, min(tbl1.deptno) from dept as tbl0, dept as tbl1 group by tbl0.dname, tbl1.dname") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ max(tbl0.hiredate) from emp as tbl0") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ min(tbl0.deptno) as caggr0, count(*) as caggr1 from dept as tbl0 left join dept as tbl1 on tbl1.loc = tbl1.dname") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ count(tbl1.loc) as caggr0 from dept as tbl1 left join dept as tbl2 on tbl1.loc = tbl2.loc where (tbl2.deptno)") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ sum(tbl1.ename), min(tbl0.empno) from emp as tbl0, emp as tbl1 left join dept as tbl2 on tbl1.job = tbl2.loc and tbl1.comm = tbl2.deptno where ('trout') and tbl0.deptno = tbl1.comm") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ distinct max(tbl0.deptno), count(tbl0.job) from emp as tbl0, dept as tbl1 left join dept as tbl2 on tbl1.dname = tbl2.loc and tbl1.dname = tbl2.loc where (tbl2.loc) and tbl0.deptno = tbl1.deptno") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ count(*), count(*) from (select count(*) from dept as tbl0 group by tbl0.deptno) as tbl0") - mcmp.Exec("select /*vt+ PLANNER=Gen4 */ distinct max(tbl0.dname) as caggr0, 'cattle' as crandom0 from dept as tbl0, emp as tbl1 where tbl0.deptno != tbl1.sal group by tbl1.comm") - + mcmp.Exec("select sum(tbl1.sal) as caggr1 from emp as tbl0, emp as tbl1 group by tbl1.ename order by tbl1.ename asc") + mcmp.Exec("select count(*), count(*), count(*) from dept as tbl0, emp as tbl1 where tbl0.deptno = tbl1.deptno group by tbl1.empno order by tbl1.empno") + mcmp.Exec("select count(tbl0.deptno) from dept as tbl0, emp as tbl1 group by tbl1.job order by tbl1.job limit 3") + mcmp.Exec("select count(*), count(*) from emp as tbl0 group by tbl0.empno order by tbl0.empno") + mcmp.Exec("select distinct count(*), tbl0.loc from dept as tbl0 group by tbl0.loc") + mcmp.Exec("select distinct count(*) from dept as tbl0 group by tbl0.loc") + mcmp.Exec("select sum(tbl1.comm) from emp as tbl0, emp as tbl1") + mcmp.Exec("select tbl1.mgr, tbl1.mgr, count(*) from emp as tbl1 group by tbl1.mgr") + mcmp.Exec("select tbl1.mgr, tbl1.mgr, count(*) from emp as tbl0, emp as tbl1 group by tbl1.mgr") + mcmp.Exec("select count(*), count(*), count(tbl0.comm) from emp as tbl0, emp as tbl1 join dept as tbl2") + mcmp.Exec("select count(*), count(*) from (select count(*) from dept as tbl0 group by tbl0.deptno) as tbl0, dept as tbl1") + mcmp.Exec("select count(*) from (select count(*) from dept as tbl0 group by tbl0.deptno) as tbl0") + mcmp.Exec("select min(tbl0.loc) from dept as tbl0") + mcmp.Exec("select tbl1.empno, max(tbl1.job) from dept as tbl0, emp as tbl1 group by tbl1.empno") + mcmp.Exec("select tbl1.ename, max(tbl0.comm) from emp as tbl0, emp as tbl1 group by tbl1.ename") + mcmp.Exec("select tbl0.dname, tbl0.dname, min(tbl0.deptno) from dept as tbl0, dept as tbl1 group by tbl0.dname, tbl0.dname") + mcmp.Exec("select tbl0.dname, min(tbl1.deptno) from dept as tbl0, dept as tbl1 group by tbl0.dname, tbl1.dname") + mcmp.Exec("select max(tbl0.hiredate) from emp as tbl0") + mcmp.Exec("select min(tbl0.deptno) as caggr0, count(*) as caggr1 from dept as tbl0 left join dept as tbl1 on tbl1.loc = tbl1.dname") + mcmp.Exec("select count(tbl1.loc) as caggr0 from dept as tbl1 left join dept as tbl2 on tbl1.loc = tbl2.loc where (tbl2.deptno)") + mcmp.Exec("select sum(tbl1.ename), min(tbl0.empno) from emp as tbl0, emp as tbl1 left join dept as tbl2 on tbl1.job = tbl2.loc and tbl1.comm = tbl2.deptno where ('trout') and tbl0.deptno = tbl1.comm") + mcmp.Exec("select distinct max(tbl0.deptno), count(tbl0.job) from emp as tbl0, dept as tbl1 left join dept as tbl2 on tbl1.dname = tbl2.loc and tbl1.dname = tbl2.loc where (tbl2.loc) and tbl0.deptno = tbl1.deptno") + mcmp.Exec("select count(*), count(*) from (select count(*) from dept as tbl0 group by tbl0.deptno) as tbl0") + mcmp.Exec("select distinct max(tbl0.dname) as caggr0, 'cattle' as crandom0 from dept as tbl0, emp as tbl1 where tbl0.deptno != tbl1.sal group by tbl1.comm") + mcmp.Exec("select -26 in (tbl2.mgr, -8, tbl0.deptno) as crandom0 from dept as tbl0, emp as tbl1 left join emp as tbl2 on tbl2.ename") + mcmp.Exec("select max(tbl1.dname) as caggr1 from dept as tbl0, dept as tbl1 group by tbl1.dname order by tbl1.dname asc") + mcmp.Exec("select distinct tbl1.hiredate as cgroup0, count(tbl1.mgr) as caggr0 from emp as tbl1 group by tbl1.hiredate, tbl1.ename") + mcmp.Exec("select distinct 347 as crandom0 from emp as tbl0") + mcmp.Exec("select distinct count(*) from dept as tbl0 group by tbl0.deptno") + mcmp.Exec("select count(*) from dept as tbl1 join (select count(*) from emp as tbl0, dept as tbl1 group by tbl1.loc) as tbl2") + mcmp.Exec("select (select count(*) from emp as tbl0) from emp as tbl0") + mcmp.Exec("select count(tbl1.dname) as caggr1 from dept as tbl0 left join dept as tbl1 on tbl1.dname > tbl1.loc where tbl1.loc <=> tbl1.dname group by tbl1.dname order by tbl1.dname asc") + mcmp.Exec("select count(*) from (select count(*) from dept as tbl0) as tbl0") + mcmp.Exec("select count(*), count(*) from (select count(*) from dept as tbl0) as tbl0, dept as tbl1") } diff --git a/go/tools/release-notes/release_notes.go b/go/tools/release-notes/release_notes.go index 5bb03339245..1673d6a5160 100644 --- a/go/tools/release-notes/release_notes.go +++ b/go/tools/release-notes/release_notes.go @@ -201,6 +201,10 @@ func loadMergedPRsAndAuthors(name string) (pris []pullRequestInformation, author authorMap := map[string]bool{} for _, pri := range pris { login := pri.Author.Login + if strings.HasPrefix(login, "@app") { + // skip the bots + continue + } if ok := authorMap[login]; !ok { authors = append(authors, login) authorMap[login] = true diff --git a/go/vt/schema/ddl_strategy.go b/go/vt/schema/ddl_strategy.go index 88400d423fd..bc33c8cb3cf 100644 --- a/go/vt/schema/ddl_strategy.go +++ b/go/vt/schema/ddl_strategy.go @@ -20,6 +20,7 @@ import ( "fmt" "regexp" "strconv" + "strings" "time" "github.com/google/shlex" @@ -115,6 +116,14 @@ func ParseDDLStrategy(strategyVariable string) (*DDLStrategySetting, error) { if _, err := setting.RetainArtifactsDuration(); err != nil { return nil, err } + + switch setting.Strategy { + case DDLStrategyVitess, DDLStrategyOnline, DDLStrategyMySQL, DDLStrategyDirect: + if opts := setting.RuntimeOptions(); len(opts) > 0 { + return nil, fmt.Errorf("invalid flags for %v strategy: %s", setting.Strategy, strings.Join(opts, " ")) + } + } + return setting, nil } diff --git a/go/vt/schema/ddl_strategy_test.go b/go/vt/schema/ddl_strategy_test.go index 8ad6ff592dc..ba7d029b8b7 100644 --- a/go/vt/schema/ddl_strategy_test.go +++ b/go/vt/schema/ddl_strategy_test.go @@ -41,19 +41,23 @@ func TestIsDirect(t *testing.T) { func TestIsCutOverThresholdFlag(t *testing.T) { tt := []struct { - s string - expect bool - val string - d time.Duration + s string + expect bool + expectError string + val string + d time.Duration }{ { - s: "something", + s: "something", + expectError: "invalid flags", }, { - s: "-cut-over-threshold", + s: "-cut-over-threshold", + expectError: "invalid flags", }, { - s: "--cut-over-threshold", + s: "--cut-over-threshold", + expectError: "invalid flags", }, { s: "--cut-over-threshold=", @@ -87,6 +91,11 @@ func TestIsCutOverThresholdFlag(t *testing.T) { for _, ts := range tt { t.Run(ts.s, func(t *testing.T) { setting, err := ParseDDLStrategy("online " + ts.s) + if ts.expectError != "" { + assert.ErrorContains(t, err, ts.expectError) + return + } + assert.NoError(t, err) val, isCutOver := isCutOverThresholdFlag(ts.s) @@ -104,19 +113,23 @@ func TestIsCutOverThresholdFlag(t *testing.T) { func TestIsExpireArtifactsFlag(t *testing.T) { tt := []struct { - s string - expect bool - val string - d time.Duration + s string + expect bool + expectError string + val string + d time.Duration }{ { - s: "something", + s: "something", + expectError: "invalid flags", }, { - s: "-retain-artifacts", + s: "-retain-artifacts", + expectError: "invalid flags", }, { - s: "--retain-artifacts", + s: "--retain-artifacts", + expectError: "invalid flags", }, { s: "--retain-artifacts=", @@ -150,6 +163,10 @@ func TestIsExpireArtifactsFlag(t *testing.T) { for _, ts := range tt { t.Run(ts.s, func(t *testing.T) { setting, err := ParseDDLStrategy("online " + ts.s) + if ts.expectError != "" { + assert.ErrorContains(t, err, ts.expectError) + return + } assert.NoError(t, err) val, isRetainArtifacts := isRetainArtifactsFlag(ts.s) @@ -183,7 +200,7 @@ func TestParseDDLStrategy(t *testing.T) { cutOverThreshold time.Duration expireArtifacts time.Duration runtimeOptions string - err error + expectError string }{ { strategyVariable: "direct", @@ -317,10 +334,29 @@ func TestParseDDLStrategy(t *testing.T) { runtimeOptions: "", analyzeTable: true, }, + + { + strategyVariable: "vitess --alow-concrrnt", // intentional typo + strategy: DDLStrategyVitess, + options: "", + runtimeOptions: "", + expectError: "invalid flags", + }, + { + strategyVariable: "vitess --declarative --max-load=Threads_running=100", + strategy: DDLStrategyVitess, + options: "--declarative --max-load=Threads_running=100", + runtimeOptions: "--max-load=Threads_running=100", + expectError: "invalid flags", + }, } for _, ts := range tt { t.Run(ts.strategyVariable, func(t *testing.T) { setting, err := ParseDDLStrategy(ts.strategyVariable) + if ts.expectError != "" { + assert.ErrorContains(t, err, ts.expectError) + return + } assert.NoError(t, err) assert.Equal(t, ts.strategy, setting.Strategy) assert.Equal(t, ts.options, setting.Options) diff --git a/go/vt/schemadiff/schema.go b/go/vt/schemadiff/schema.go index a9ef60fbb27..9180012676f 100644 --- a/go/vt/schemadiff/schema.go +++ b/go/vt/schemadiff/schema.go @@ -795,6 +795,69 @@ func (s *Schema) SchemaDiff(other *Schema, hints *DiffHints) (*SchemaDiff, error return dependentDiffs, relationsMade } + checkChildForeignKeyDefinition := func(fk *sqlparser.ForeignKeyDefinition, diff EntityDiff) (bool, error) { + // We add a foreign key. Normally that's fine, expect for a couple specific scenarios + parentTableName := fk.ReferenceDefinition.ReferencedTable.Name.String() + dependentDiffs, ok := checkDependencies(diff, []string{parentTableName}) + if !ok { + // No dependency. Not interesting + return true, nil + } + for _, parentDiff := range dependentDiffs { + switch parentDiff := parentDiff.(type) { + case *CreateTableEntityDiff: + // We add a foreign key constraint onto a new table... That table must therefore be first created, + // and only then can we proceed to add the FK + schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) + case *AlterTableEntityDiff: + // The current diff is ALTER TABLE ... ADD FOREIGN KEY, or it is a CREATE TABLE with a FOREIGN KEY + // and the parent table also has an ALTER TABLE. + // so if the parent's ALTER in any way modifies the referenced FK columns, that's + // a sequential execution dependency. + // Also, if there is no index on the parent's referenced columns, and a migration adds an index + // on those columns, that's a sequential execution dependency. + referencedColumnNames := map[string]bool{} + for _, referencedColumn := range fk.ReferenceDefinition.ReferencedColumns { + referencedColumnNames[referencedColumn.Lowered()] = true + } + // Walk parentDiff.Statement() + _ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { + switch node := node.(type) { + case *sqlparser.ModifyColumn: + if referencedColumnNames[node.NewColDefinition.Name.Lowered()] { + schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) + } + case *sqlparser.AddColumns: + for _, col := range node.Columns { + if referencedColumnNames[col.Name.Lowered()] { + schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) + } + } + case *sqlparser.DropColumn: + if referencedColumnNames[node.Name.Name.Lowered()] { + schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) + } + case *sqlparser.AddIndexDefinition: + referencedTableEntity, _ := parentDiff.Entities() + // We _know_ the type is *CreateTableEntity + referencedTable, _ := referencedTableEntity.(*CreateTableEntity) + if indexCoversColumnsInOrder(node.IndexDefinition, fk.ReferenceDefinition.ReferencedColumns) { + // This diff adds an index covering referenced columns + if !referencedTable.columnsCoveredByInOrderIndex(fk.ReferenceDefinition.ReferencedColumns) { + // And there was no earlier index on referenced columns. So this is a new index. + // In MySQL, you can't add a foreign key constraint on a child, before the parent + // has an index of referenced columns. This is a sequential dependency. + schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) + } + } + } + return true, nil + }, parentDiff.Statement()) + } + } + return true, nil + } + for _, diff := range schemaDiff.UnorderedDiffs() { switch diff := diff.(type) { case *CreateViewEntityDiff: @@ -806,6 +869,19 @@ func (s *Schema) SchemaDiff(other *Schema, hints *DiffHints) (*SchemaDiff, error checkDependencies(diff, getViewDependentTableNames(diff.from.CreateView)) case *CreateTableEntityDiff: checkDependencies(diff, getForeignKeyParentTableNames(diff.CreateTable())) + _ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { + switch node := node.(type) { + case *sqlparser.ConstraintDefinition: + // Only interested in a foreign key + fk, ok := node.Details.(*sqlparser.ForeignKeyDefinition) + if !ok { + return true, nil + } + return checkChildForeignKeyDefinition(fk, diff) + } + return true, nil + }, diff.Statement()) + case *AlterTableEntityDiff: _ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { switch node := node.(type) { @@ -815,51 +891,7 @@ func (s *Schema) SchemaDiff(other *Schema, hints *DiffHints) (*SchemaDiff, error if !ok { return true, nil } - // We add a foreign key. Normally that's fine, expect for a couple specific scenarios - parentTableName := fk.ReferenceDefinition.ReferencedTable.Name.String() - dependentDiffs, ok := checkDependencies(diff, []string{parentTableName}) - if !ok { - // No dependency. Not interesting - return true, nil - } - for _, parentDiff := range dependentDiffs { - switch parentDiff := parentDiff.(type) { - case *CreateTableEntityDiff: - // We add a foreign key constraint onto a new table... That table must therefore be first created, - // and only then can we proceed to add the FK - schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) - case *AlterTableEntityDiff: - // The current diff is ALTER TABLE ... ADD FOREIGN KEY - // and the parent table also has an ALTER TABLE. - // so if the parent's ALTER in any way modifies the referenced FK columns, that's - // a sequential execution dependency - referencedColumnNames := map[string]bool{} - for _, referencedColumn := range fk.ReferenceDefinition.ReferencedColumns { - referencedColumnNames[referencedColumn.Lowered()] = true - } - // Walk parentDiff.Statement() - _ = sqlparser.Walk(func(node sqlparser.SQLNode) (kontinue bool, err error) { - switch node := node.(type) { - case *sqlparser.ModifyColumn: - if referencedColumnNames[node.NewColDefinition.Name.Lowered()] { - schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) - } - case *sqlparser.AddColumns: - for _, col := range node.Columns { - if referencedColumnNames[col.Name.Lowered()] { - schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) - } - } - case *sqlparser.DropColumn: - if referencedColumnNames[node.Name.Name.Lowered()] { - schemaDiff.addDep(diff, parentDiff, DiffDependencySequentialExecution) - } - } - return true, nil - }, parentDiff.Statement()) - } - } - + return checkChildForeignKeyDefinition(fk, diff) case *sqlparser.DropKey: if node.Type != sqlparser.ForeignKeyType { // Not interesting diff --git a/go/vt/schemadiff/schema_diff_test.go b/go/vt/schemadiff/schema_diff_test.go index d835177c795..df7d893356f 100644 --- a/go/vt/schemadiff/schema_diff_test.go +++ b/go/vt/schemadiff/schema_diff_test.go @@ -558,7 +558,7 @@ func TestSchemaDiff(t *testing.T) { entityOrder: []string{"t3"}, }, { - name: "create two table with fk", + name: "create two tables with fk", toQueries: append( createQueries, "create table tp (id int primary key, info int not null);", @@ -567,6 +567,7 @@ func TestSchemaDiff(t *testing.T) { expectDiffs: 2, expectDeps: 1, entityOrder: []string{"tp", "t3"}, + sequential: true, }, { name: "add FK", @@ -648,6 +649,7 @@ func TestSchemaDiff(t *testing.T) { expectDiffs: 2, expectDeps: 1, entityOrder: []string{"t1", "t3"}, + sequential: true, }, { name: "add column. add FK referencing new column", @@ -672,6 +674,70 @@ func TestSchemaDiff(t *testing.T) { expectDeps: 1, sequential: true, entityOrder: []string{"t2", "t1"}, + }, { + name: "add index on parent. add FK to index column", + toQueries: []string{ + "create table t1 (id int primary key, info int not null, key info_idx(info));", + "create table t2 (id int primary key, ts timestamp, t1_info int not null, constraint parent_info_fk foreign key (t1_info) references t1 (info));", + "create view v1 as select id from t1", + }, + expectDiffs: 2, + expectDeps: 1, + sequential: true, + entityOrder: []string{"t1", "t2"}, + }, + { + name: "add index on parent with existing index. add FK to index column", + fromQueries: []string{ + "create table t1 (id int primary key, info int not null, key existing_info_idx(info));", + "create table t2 (id int primary key, ts timestamp);", + "create view v1 as select id from t1", + }, + toQueries: []string{ + "create table t1 (id int primary key, info int not null, key existing_info_idx(info), key info_idx(info));", + "create table t2 (id int primary key, ts timestamp, t1_info int not null, constraint parent_info_fk foreign key (t1_info) references t1 (info));", + "create view v1 as select id from t1", + }, + expectDiffs: 2, + expectDeps: 1, + sequential: false, + entityOrder: []string{"t1", "t2"}, + }, + { + name: "modify fk column types, fail", + fromQueries: []string{ + "create table t1 (id int primary key);", + "create table t2 (id int primary key, ts timestamp, t1_id int, foreign key (t1_id) references t1 (id) on delete no action);", + }, + toQueries: []string{ + "create table t1 (id bigint primary key);", + "create table t2 (id int primary key, ts timestamp, t1_id bigint, foreign key (t1_id) references t1 (id) on delete no action);", + }, + expectDiffs: 2, + expectDeps: 0, + sequential: false, + conflictingDiffs: 1, + }, + { + name: "add hierarchical constraints", + fromQueries: []string{ + "create table t1 (id int primary key, ref int, key ref_idx (ref));", + "create table t2 (id int primary key, ref int, key ref_idx (ref));", + "create table t3 (id int primary key, ref int, key ref_idx (ref));", + "create table t4 (id int primary key, ref int, key ref_idx (ref));", + "create table t5 (id int primary key, ref int, key ref_idx (ref));", + }, + toQueries: []string{ + "create table t1 (id int primary key, ref int, key ref_idx (ref));", + "create table t2 (id int primary key, ref int, key ref_idx (ref), foreign key (ref) references t1 (id) on delete no action);", + "create table t3 (id int primary key, ref int, key ref_idx (ref), foreign key (ref) references t2 (id) on delete no action);", + "create table t4 (id int primary key, ref int, key ref_idx (ref), foreign key (ref) references t3 (id) on delete no action);", + "create table t5 (id int primary key, ref int, key ref_idx (ref), foreign key (ref) references t1 (id) on delete no action);", + }, + expectDiffs: 4, + expectDeps: 2, // t2<->t3, t3<->t4 + sequential: false, + entityOrder: []string{"t2", "t3", "t4", "t5"}, }, { name: "drop fk", @@ -755,6 +821,20 @@ func TestSchemaDiff(t *testing.T) { expectDeps: 0, entityOrder: []string{"t1"}, }, + { + name: "test", + fromQueries: []string{ + "CREATE TABLE t1 (id bigint NOT NULL, name varchar(255), PRIMARY KEY (id))", + }, + toQueries: []string{ + "CREATE TABLE t1 (id bigint NOT NULL, name varchar(255), PRIMARY KEY (id), KEY idx_name (name))", + "CREATE TABLE t3 (id bigint NOT NULL, name varchar(255), t1_id bigint, PRIMARY KEY (id), KEY t1_id (t1_id), KEY nameidx (name), CONSTRAINT t3_ibfk_1 FOREIGN KEY (t1_id) REFERENCES t1 (id) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT t3_ibfk_2 FOREIGN KEY (name) REFERENCES t1 (name) ON DELETE CASCADE ON UPDATE CASCADE)", + }, + expectDiffs: 2, + expectDeps: 1, + sequential: true, + entityOrder: []string{"t1", "t3"}, + }, } hints := &DiffHints{RangeRotationStrategy: RangeRotationDistinctStatements} for _, tc := range tt { @@ -790,11 +870,14 @@ func TestSchemaDiff(t *testing.T) { orderedDiffs, err := schemaDiff.OrderedDiffs(ctx) if tc.conflictingDiffs > 0 { - require.Greater(t, tc.conflictingDiffs, 1) // self integrity. If there's a conflict, then obviously there's at least two conflicting diffs (a single diff has nothing to conflict with) assert.Error(t, err) impossibleOrderErr, ok := err.(*ImpossibleApplyDiffOrderError) assert.True(t, ok) - assert.Equal(t, tc.conflictingDiffs, len(impossibleOrderErr.ConflictingDiffs)) + conflictingDiffsStatements := []string{} + for _, diff := range impossibleOrderErr.ConflictingDiffs { + conflictingDiffsStatements = append(conflictingDiffsStatements, diff.CanonicalStatementString()) + } + assert.Equalf(t, tc.conflictingDiffs, len(impossibleOrderErr.ConflictingDiffs), "found conflicting diffs: %+v\n diff statements=%+v", conflictingDiffsStatements, allDiffsStatements) } else { require.NoErrorf(t, err, "Unordered diffs: %v", allDiffsStatements) } diff --git a/go/vt/vtgate/evalengine/translate_card.go b/go/vt/vtgate/evalengine/translate_card.go index 962fc129850..593cdf2b805 100644 --- a/go/vt/vtgate/evalengine/translate_card.go +++ b/go/vt/vtgate/evalengine/translate_card.go @@ -174,7 +174,7 @@ func (ast *astCompiler) cardExpr(expr IR) error { return errCardinality(1) } default: - return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "rhs of an In operation should be a tuple") + return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "rhs of an In operation should be a tuple, was %T", expr.Right) } case TupleExpr: diff --git a/go/vt/vtgate/planbuilder/operators/projection.go b/go/vt/vtgate/planbuilder/operators/projection.go index f87ef03be07..31be577913d 100644 --- a/go/vt/vtgate/planbuilder/operators/projection.go +++ b/go/vt/vtgate/planbuilder/operators/projection.go @@ -169,7 +169,7 @@ func (pe *ProjExpr) String() string { if !pe.Original.As.IsEmpty() { alias = " AS " + pe.Original.As.String() } - if pe.EvalExpr == pe.ColExpr { + if sqlparser.Equals.Expr(pe.EvalExpr, pe.ColExpr) { expr = sqlparser.String(pe.EvalExpr) } else { expr = fmt.Sprintf("%s|%s", sqlparser.String(pe.EvalExpr), sqlparser.String(pe.ColExpr)) diff --git a/go/vt/vtgate/semantics/analyzer_test.go b/go/vt/vtgate/semantics/analyzer_test.go index 61dd1ee4a9d..f1227bfe7b0 100644 --- a/go/vt/vtgate/semantics/analyzer_test.go +++ b/go/vt/vtgate/semantics/analyzer_test.go @@ -604,6 +604,9 @@ func TestOrderByBindingTable(t *testing.T) { }, { "select a.id from t1 as a union (select uid from t2, t union (select name from t) order by 1) order by id", MergeTableSets(TS0, TS1, TS3), + }, { + "select * from (SELECT c1, c2 FROM a UNION SELECT c1, c2 FROM b) AS u ORDER BY u.c1", + MergeTableSets(TS0, TS1), }} for _, tc := range tcases { t.Run(tc.sql, func(t *testing.T) { diff --git a/go/vt/vtgate/semantics/scoper.go b/go/vt/vtgate/semantics/scoper.go index c3685913376..458e08b1f15 100644 --- a/go/vt/vtgate/semantics/scoper.go +++ b/go/vt/vtgate/semantics/scoper.go @@ -197,7 +197,7 @@ func (s *scoper) up(cursor *sqlparser.Cursor) error { if isParentSelectStatement(cursor) { s.popScope() } - case *sqlparser.Select, sqlparser.GroupBy, *sqlparser.Update, *sqlparser.Delete, *sqlparser.Insert: + case *sqlparser.Select, sqlparser.GroupBy, *sqlparser.Update, *sqlparser.Delete, *sqlparser.Insert, *sqlparser.Union: id := EmptyTableSet() for _, tableInfo := range s.currentScope().tables { set := tableInfo.getTableSet(s.org) diff --git a/go/vt/vtgate/semantics/semantic_state.go b/go/vt/vtgate/semantics/semantic_state.go index 0c4fe130bab..fdbf2f0e04d 100644 --- a/go/vt/vtgate/semantics/semantic_state.go +++ b/go/vt/vtgate/semantics/semantic_state.go @@ -171,7 +171,9 @@ func (st *SemTable) CopyDependencies(from, to sqlparser.Expr) { if ValidAsMapKey(to) { st.Recursive[to] = st.RecursiveDeps(from) st.Direct[to] = st.DirectDeps(from) - st.ExprTypes[to] = st.ExprTypes[from] + if ValidAsMapKey(from) { + st.ExprTypes[to] = st.ExprTypes[from] + } } }