github.com/dolthub/go-mysql-server@v0.18.0/enginetest/queries/derived_table_outer_scope_visibility_queries.go (about) 1 // Copyright 2022 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package queries 16 17 import "github.com/dolthub/go-mysql-server/sql" 18 19 var DerivedTableOuterScopeVisibilityQueries = []ScriptTest{ 20 { 21 Name: "outer scope visibility for derived tables", 22 SetUpScript: []string{ 23 "create table t1 (a int primary key, b int, c int, d int, e int);", 24 "create table t2 (a int primary key, b int, c int, d int, e int);", 25 "insert into t1 values (1, 1, 1, 100, 100), (2, 2, 2, 200, 200);", 26 "insert into t2 values (2, 2, 2, 2, 2);", 27 "create table numbers (val int);", 28 "insert into numbers values (1), (1), (2), (3), (3), (3), (4), (5), (6), (6), (6);", 29 }, 30 Assertions: []ScriptTestAssertion{ 31 { 32 // A subquery containing a derived table, used in the WHERE clause of a top-level query, has visibility 33 // to tables and columns in the top-level query. 34 Query: "SELECT * FROM t1 WHERE t1.d > (SELECT dt.a FROM (SELECT t2.a AS a FROM t2 WHERE t2.b = t1.b) dt);", 35 Expected: []sql.Row{{2, 2, 2, 200, 200}}, 36 }, 37 { 38 // A subquery containing a derived table, used in the HAVING clause of a top-level query, has visibility 39 // to tables and columns in the top-level query. 40 Query: "SELECT * FROM t1 HAVING t1.d > (SELECT dt.a FROM (SELECT t2.a AS a FROM t2 WHERE t2.b = t1.b) dt);", 41 Expected: []sql.Row{{2, 2, 2, 200, 200}}, 42 }, 43 { 44 Query: "SELECT (SELECT dt.z FROM (SELECT t2.a AS z FROM t2 WHERE t2.b = t1.b) dt) FROM t1;", 45 Expected: []sql.Row{{nil}, {2}}, 46 }, 47 { 48 Query: "SELECT (SELECT max(dt.z) FROM (SELECT t2.a AS z FROM t2 WHERE t2.b = t1.b) dt) FROM t1;", 49 Expected: []sql.Row{{nil}, {2}}, 50 }, 51 { 52 // A subquery containing a derived table, projected in a SELECT query, has visibility to tables and columns 53 // in the top-level query. 54 Query: "SELECT t1.*, (SELECT max(dt.a) FROM (SELECT t2.a AS a FROM t2 WHERE t2.b = t1.b) dt) FROM t1;", 55 Expected: []sql.Row{{1, 1, 1, 100, 100, nil}, {2, 2, 2, 200, 200, 2}}, 56 }, 57 { 58 // A subquery containing a derived table, projected in a GROUPBY query, has visibility to tables and columns 59 // in the top-level query. 60 Query: "SELECT t1.a, t1.b, (SELECT max(dt.a) FROM (SELECT t2.a AS a FROM t2 WHERE t2.b = t1.b) dt) FROM t1 GROUP BY 1, 2, 3;", 61 Expected: []sql.Row{{1, 1, nil}, {2, 2, 2}}, 62 }, 63 { 64 // A subquery containing a derived table, projected in a WINDOW query, has visibility to tables and columns 65 // in the top-level query. 66 Query: "SELECT val, row_number() over (partition by val) as 'row_number', (SELECT two from (SELECT val*2, val*3) as dt(one, two)) as a1 from numbers having a1 > 10;", 67 Expected: []sql.Row{{4, 1, 12}, {5, 1, 15}, {6, 1, 18}, {6, 2, 18}, {6, 3, 18}}, 68 }, 69 { 70 // A subquery containing a derived table, used in the GROUP BY clause of a top-level query as a grouping 71 // expression, has visibility to tables and columns in the top-level query. 72 Query: "SELECT max(val), (select max(dt.a) from (SELECT val as a) as dt(a)) as a1 from numbers group by a1;", 73 Expected: []sql.Row{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {5, 5}, {6, 6}}, 74 }, 75 { 76 // CTEs are eligible for outer scope visibility, as long as they are contained in a subquery expression. 77 Query: "SELECT DISTINCT numbers.val, (WITH cte1 AS (SELECT val * 2 as val2 from numbers) SELECT count(*) from cte1 where numbers.val = cte1.val2) as count from numbers having count > 0;", 78 Expected: []sql.Row{{2, 2}, {4, 1}, {6, 3}}, 79 }, 80 { 81 // Recursive CTEs are eligible for outer scope visibility as well, as long as they are contained in a 82 // subquery expression. 83 Query: "select distinct n1.val, (with recursive cte1(n) as (select (n1.val) from dual union all select n + 1 from cte1 where n < 10) select sum(n) from cte1) from numbers n1 where n1.val > 4;", 84 Expected: []sql.Row{{5, 45.0}, {6, 40.0}}, 85 }, 86 }, 87 }, 88 { 89 Name: "outer scope visibility for derived tables – error cases", 90 SetUpScript: []string{ 91 "create table numbers (val int);", 92 "insert into numbers values (1), (1), (2), (3), (3), (3), (4), (5), (6), (6), (6);", 93 }, 94 Assertions: []ScriptTestAssertion{ 95 { 96 // expression aliases are NOT visible from outer scopes to derived tables 97 Query: "select 'foo' as foo, (select dt.b from (select 1 as a, foo as b) dt);", 98 ExpectedErr: sql.ErrColumnNotFound, 99 }, 100 { 101 // a derived table NOT inside a subquery expression does NOT have access to any lateral scope tables. 102 Query: "SELECT n1.val as a1 from numbers n1, (select n1.val, n2.val * -1 from numbers n2 where n1.val = n2.val) as dt;", 103 ExpectedErr: sql.ErrTableNotFound, 104 }, 105 { 106 // A derived table inside a derived table does NOT have visibility to any outer scopes. 107 Query: "SELECT 1 as a1, dt.* from (select * from (select a1 from numbers group by val having val = a1) as dt2(val)) as dt(val);", 108 ExpectedErr: sql.ErrColumnNotFound, 109 }, 110 { 111 // The analyzer rewrites this query so that the CTE is embedded in the projected subquery expression, 112 // which provides outer scope visibility for the opk table. It seems like MySQL is attaching the CTE 113 // to the top level of the query, and not directly inside the subquery expression, which would explain 114 // why MySQL does NOT give this query visibility to the 'opk' table alias. We should match MySQL's 115 // behavior, but this is a small edge case we can follow up on. 116 Skip: true, 117 118 // CTEs and Recursive CTEs may receive outer scope visibility, but only when they are contained in a 119 // subquery expression. The CTE in this query should NOT have visibility to the 'opk' table alias. 120 Query: "with cte1 as (SELECT c3 FROM one_pk WHERE c4 < opk.c2 ORDER BY 1 DESC LIMIT 1) SELECT pk, (select c3 from cte1) FROM one_pk opk ORDER BY 1", 121 ExpectedErr: sql.ErrTableNotFound, 122 }, 123 }, 124 }, 125 { 126 Name: "https://github.com/dolthub/go-mysql-server/issues/1282", 127 SetUpScript: []string{ 128 "CREATE TABLE `dcim_rackgroup` (`id` char(32) NOT NULL, `lft` int unsigned NOT NULL, `rght` int unsigned NOT NULL, `tree_id` int unsigned NOT NULL, `level` int unsigned NOT NULL, `parent_id` char(32), PRIMARY KEY (`id`), KEY `dcim_rackgroup_tree_id_9c2ad6f4` (`tree_id`), CONSTRAINT `dcim_rackgroup_parent_id_cc315105_fk_dcim_rackgroup_id` FOREIGN KEY (`parent_id`) REFERENCES `dcim_rackgroup` (`id`));", 129 "CREATE TABLE `dcim_rack` (`id` char(32) NOT NULL, `group_id` char(32), PRIMARY KEY (`id`), KEY `dcim_rack_group_id_44e90ea9` (`group_id`), CONSTRAINT `dcim_rack_group_id_44e90ea9_fk_dcim_rackgroup_id` FOREIGN KEY (`group_id`) REFERENCES `dcim_rackgroup` (`id`));", 130 "INSERT INTO dcim_rackgroup VALUES ('rackgroup-parent', 100, 200, 1000, 1, NULL), ('rackgroup1', 101, 201, 1000, 1, 'rackgroup-parent'), ('rackgroup2', 102, 202, 1000, 1, 'rackgroup-parent');", 131 "INSERT INTO dcim_rack VALUES ('rack1', 'rackgroup1'), ('rack2', 'rackgroup1'), ('rack3', 'rackgroup1'), ('rack4', 'rackgroup2');", 132 }, 133 Assertions: []ScriptTestAssertion{ 134 { 135 Query: ` 136 SELECT ( 137 SELECT count(*) FROM ( 138 SELECT U0.id 139 FROM dcim_rack U0 140 INNER JOIN dcim_rackgroup U1 ON (U0.group_id = U1.id) 141 WHERE 142 U1.lft >= dcim_rackgroup.lft AND 143 U1.lft <= dcim_rackgroup.rght AND 144 U1.tree_id = dcim_rackgroup.tree_id 145 ) _count 146 ) AS rack_count 147 FROM dcim_rackgroup 148 WHERE dcim_rackgroup.id IN ('rackgroup1', 'rackgroup2')`, 149 Expected: []sql.Row{{4}, {1}}, 150 }, 151 { 152 Query: "SELECT COUNT(*) FROM (SELECT (SELECT count(*) FROM (SELECT U0.`id` FROM `dcim_rack` U0 INNER JOIN `dcim_rackgroup` U1 ON (U0.`group_id` = U1.`id`) WHERE (U1.`lft` >= `dcim_rackgroup`.`lft` AND U1.`lft` <= `dcim_rackgroup`.`rght` AND U1.`tree_id` = `dcim_rackgroup`.`tree_id`)) _count) AS `rack_count` FROM `dcim_rackgroup` WHERE `dcim_rackgroup`.`id` IN ('rackgroup1', 'rackgroup2')) subquery;", 153 Expected: []sql.Row{{2}}, 154 }, 155 }, 156 }, 157 }