github.com/dolthub/go-mysql-server@v0.18.0/enginetest/queries/ansi_quotes_queries.go (about) 1 // Copyright 2023 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 ( 18 "github.com/dolthub/go-mysql-server/sql" 19 "github.com/dolthub/go-mysql-server/sql/plan" 20 "github.com/dolthub/go-mysql-server/sql/types" 21 ) 22 23 var AnsiQuotesTests = []ScriptTest{ 24 { 25 Name: "ANSI_QUOTES: basic cases", 26 SetUpScript: []string{ 27 "SET @@sql_mode='ANSI_QUOTES,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';", 28 "create table auctions (ai int auto_increment, id varchar(32), data varchar(100), primary key (ai));", 29 "insert into auctions (id, data) values (42, 'forty-two');", 30 }, 31 Assertions: []ScriptTestAssertion{ 32 { 33 // When ANSI_QUOTES mode is enabled, double quotes become identifier quotes. 34 Query: `select "data" from auctions order by "ai" desc;`, 35 Expected: []sql.Row{{"forty-two"}}, 36 }, 37 { 38 // Backtick quotes are always valid as identifier characters, even if 39 // ANSI_QUOTES mode is enabled. 40 Query: "select `data` from auctions order by `ai` desc;", 41 Expected: []sql.Row{{"forty-two"}}, 42 }, 43 { 44 Query: `PREPARE prep1 FROM 'select "data" from auctions order by "ai" desc;'`, 45 Expected: []sql.Row{{types.OkResult{RowsAffected: 0x0, InsertID: 0x0, Info: plan.PrepareInfo{}}}}, 46 }, 47 { 48 Query: `PREPARE prep2 FROM 'INSERT INTO auctions (id, "data") VALUES (?, ?);';`, 49 Expected: []sql.Row{{types.OkResult{RowsAffected: 0x0, InsertID: 0x0, Info: plan.PrepareInfo{}}}}, 50 }, 51 { 52 Query: `select "data", '"' from auctions order by "ai";`, 53 Expected: []sql.Row{{"forty-two", "\""}}, 54 }, 55 { 56 Query: `select "data", '\"' from auctions order by "ai";`, 57 Expected: []sql.Row{{"forty-two", "\""}}, 58 }, 59 { 60 Query: `select '''foo''';`, 61 Expected: []sql.Row{{`'foo'`}}, 62 }, 63 { 64 Query: `select """""foo""""";`, 65 ExpectedErrStr: `column "\"\"foo\"\"" could not be found in any table in scope`, 66 }, 67 { 68 Query: "select ```foo```;", 69 ExpectedErrStr: "column \"`foo`\" could not be found in any table in scope", 70 }, 71 { 72 // Disable ANSI_QUOTES and make sure we can still run queries 73 Query: `SET @@sql_mode='NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 74 Expected: []sql.Row{{}}, 75 }, 76 { 77 Query: `select "data" from auctions order by "ai" desc;`, 78 Expected: []sql.Row{{"data"}}, 79 }, 80 { 81 Query: `show tables;`, 82 Expected: []sql.Row{{"auctions"}}, 83 }, 84 }, 85 }, 86 { 87 // ANSI mode is a special "combination" mode that includes ANSI_QUOTES and other modes 88 // https://dev.mysql.com/doc/refman/8.0/en/sql-mode.html#sql-mode-combo 89 Name: "ANSI_QUOTES: ANSI combination mode", 90 SetUpScript: []string{ 91 `SET @@sql_mode='ANSI';`, 92 }, 93 Assertions: []ScriptTestAssertion{ 94 { 95 // Assert that we can create a table using ANSI style quotes 96 Query: `create table "t" ("pk" int primary key, "data" varchar(100));`, 97 Expected: []sql.Row{{types.NewOkResult(0)}}, 98 }, 99 { 100 Query: `insert into t ("pk", "data") values (1, 'one');`, 101 Expected: []sql.Row{{types.NewOkResult(1)}}, 102 }, 103 { 104 Query: `select "pk", "data" from "t" order by "pk" asc;`, 105 Expected: []sql.Row{{1, "one"}}, 106 }, 107 }, 108 }, 109 { 110 Name: "ANSI_QUOTES: views", 111 SetUpScript: []string{ 112 `SET @@sql_mode='ANSI_QUOTES,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 113 }, 114 Assertions: []ScriptTestAssertion{ 115 { 116 // https://github.com/dolthub/dolt/issues/6305 117 Query: `CREATE TABLE public_keys (item INTEGER, type CHAR(4), hash INTEGER, "count" INTEGER, "public" VARCHAR(8000))`, 118 Expected: []sql.Row{{types.NewOkResult(0)}}, 119 }, 120 { 121 Query: `insert into public_keys("item", "type", "hash", "count", "public") values (42, 'type', 1010, 1, 'public');`, 122 Expected: []sql.Row{{types.NewOkResult(1)}}, 123 }, 124 { 125 Query: `create view view1 as select public_keys."public", public_keys."count" from public_keys;`, 126 Expected: []sql.Row{{types.NewOkResult(0)}}, 127 }, 128 { 129 Query: `show tables;`, 130 Expected: []sql.Row{{"public_keys"}, {"view1"}}, 131 }, 132 { 133 Query: `show create table view1;`, 134 Expected: []sql.Row{{"view1", "CREATE VIEW `view1` AS select public_keys.\"public\", public_keys.\"count\" from public_keys", "utf8mb4", "utf8mb4_0900_bin"}}, 135 }, 136 { 137 // TODO: MySQL returns view definitions according to the session's current 138 // SQL_MODE settings, but we currently don't normalize the view 139 // definition based on the current setting for ANSI_QUOTES. We should 140 // fix that, remove the test above, and unskip this test. 141 Skip: true, 142 Query: `show create table view1;`, 143 Expected: []sql.Row{{"view1", "CREATE VIEW `view1` AS select public_keys.`public`, public_keys.`count` from public_keys", "utf8mb4", "utf8mb4_0900_bin"}}, 144 }, 145 { 146 Query: `select "public", "count" from view1;`, 147 Expected: []sql.Row{{"public", 1}}, 148 }, 149 { 150 // Assert that we can load and parse views for information_schema when ANSI_QUOTES mode is enabled 151 Query: `select table_name, view_definition from information_schema.views where table_name='view1';`, 152 Expected: []sql.Row{{"view1", `select public_keys."public", public_keys."count" from public_keys`}}, 153 }, 154 { 155 // Disable ANSI_QUOTES mode 156 Query: `SET @@sql_mode='NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 157 Expected: []sql.Row{{}}, 158 }, 159 { 160 Query: `show create table view1;`, 161 Expected: []sql.Row{{"view1", "CREATE VIEW `view1` AS select public_keys.\"public\", public_keys.\"count\" from public_keys", "utf8mb4", "utf8mb4_0900_bin"}}, 162 }, 163 { 164 Query: `show create table public_keys;`, 165 Expected: []sql.Row{{"public_keys", "CREATE TABLE `public_keys` (\n `item` int,\n `type` char(4),\n `hash` int,\n `count` int,\n `public` varchar(8000)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin"}}, 166 }, 167 { 168 Query: "select public, `count` from view1;", 169 Expected: []sql.Row{{"public", 1}}, 170 }, 171 { 172 // Assert that we can still load and parse views for information_schema when ANSI_QUOTES mode is disabled 173 Query: `select table_name, view_definition from information_schema.views where table_name='view1';`, 174 Expected: []sql.Row{{"view1", `select public_keys."public", public_keys."count" from public_keys`}}, 175 }, 176 }, 177 }, 178 { 179 Name: "ANSI_QUOTES: triggers", 180 SetUpScript: []string{ 181 `SET @@sql_mode='ANSI_QUOTES,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 182 `create table t (pk int primary key, name varchar(32), data varchar(100));`, 183 `create trigger ansi_quotes_trigger BEFORE INSERT ON "t" FOR EACH ROW SET new."data" = 'triggered!';`, 184 `insert into t values (1, 'John', 'FooBar');`, 185 }, 186 Assertions: []ScriptTestAssertion{ 187 { 188 // Assert the trigger ran correctly with ANSI_QUOTES mode enabled 189 Query: `select "name", "data" from t order by "pk";`, 190 Expected: []sql.Row{{"John", "triggered!"}}, 191 }, 192 { 193 // Assert that we can read and parse the trigger definition from information_schema 194 Query: `select action_statement from information_schema.triggers where trigger_name='ansi_quotes_trigger';`, 195 Expected: []sql.Row{{`SET new."data" = 'triggered!'`}}, 196 }, 197 { 198 // Disable ANSI_QUOTES mode 199 Query: `SET @@sql_mode='NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 200 Expected: []sql.Row{{}}, 201 }, 202 { 203 Query: `insert into t values (2, 'George', 'SomethingElse');`, 204 Expected: []sql.Row{{types.NewOkResult(1)}}, 205 }, 206 { 207 // Assert the trigger still runs correctly after disabling ANSI_QUOTES mode 208 Query: `select name, data from t where pk=2;`, 209 Expected: []sql.Row{{"George", "triggered!"}}, 210 }, 211 { 212 // Assert that we can still read and parse the trigger definition from information_schema 213 Query: `select action_statement from information_schema.triggers where trigger_name='ansi_quotes_trigger';`, 214 Expected: []sql.Row{{`SET new."data" = 'triggered!'`}}, 215 }, 216 }, 217 }, 218 { 219 Name: "ANSI_QUOTES: stored procedures", 220 SetUpScript: []string{ 221 `SET @@sql_mode='ANSI_QUOTES,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 222 `create table t (pk int primary key, name varchar(32), data varchar(100));`, 223 `create procedure AnsiProcedure() BEGIN SELECT "name" from "t" where "pk" = 1; END`, 224 `insert into t values (1, 'John', 'FooBar');`, 225 }, 226 Assertions: []ScriptTestAssertion{ 227 { 228 // Assert the procedure runs correctly with ANSI_QUOTES mode enabled 229 Query: `call AnsiProcedure();`, 230 Expected: []sql.Row{{"John"}}, 231 }, 232 { 233 // Assert that we can read and parse the procedure definition from information_schema 234 Query: `select routine_definition from information_schema.routines where routine_name='AnsiProcedure';`, 235 Expected: []sql.Row{{`BEGIN SELECT "name" from "t" where "pk" = 1; END`}}, 236 }, 237 { 238 // Disable ANSI_QUOTES mode 239 Query: `SET @@sql_mode='NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 240 Expected: []sql.Row{{}}, 241 }, 242 { 243 // Assert the procedure runs correctly with ANSI_QUOTES mode disabled 244 Query: `call AnsiProcedure();`, 245 Expected: []sql.Row{{"John"}}, 246 }, 247 { 248 // Assert that we can read and parse the procedure definition from information_schema 249 // TODO: This one doesn't work yet, until we fix information_schema ROUTINES table support for parsing ANSI_QUOTES 250 Skip: true, 251 Query: `select routine_definition from information_schema.routines where routine_name='AnsiProcedure';`, 252 Expected: []sql.Row{{`BEGIN SELECT "name" from "t" where "pk" = 1; END`}}, 253 }, 254 }, 255 }, 256 { 257 Name: "ANSI_QUOTES: column defaults", 258 SetUpScript: []string{ 259 `SET @@sql_mode='ANSI_QUOTES,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 260 `create table t ("pk" int primary key, "name" varchar(20), data varchar(100) DEFAULT(CONCAT("name", '!')));`, 261 `insert into t (pk, name) values (1, 'John');`, 262 }, 263 Assertions: []ScriptTestAssertion{ 264 { 265 // Assert the column default is applied correctly when ANSI_QUOTES mode is enabled 266 Query: `select "name", "data" from t where "pk"=1;`, 267 Expected: []sql.Row{{"John", "John!"}}, 268 }, 269 { 270 // Disable ANSI_QUOTES mode 271 Query: `SET @@sql_mode='NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 272 Expected: []sql.Row{{}}, 273 }, 274 { 275 // Insert a row with ANSI_QUOTES mode disabled 276 Query: `insert into t (pk, name) values (2, 'Jill');`, 277 Expected: []sql.Row{{types.NewOkResult(1)}}, 278 }, 279 { 280 // Assert the column default was applied correctly when ANSI_QUOTES mode is disabled 281 Query: `select name, data from t where pk=2;`, 282 Expected: []sql.Row{{"Jill", "Jill!"}}, 283 }, 284 }, 285 }, 286 { 287 Name: "ANSI_QUOTES: check constraints", 288 SetUpScript: []string{ 289 `SET @@sql_mode='ANSI_QUOTES,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 290 `create table t (pk int primary key, data varchar(100), CONSTRAINT "ansi_check" CHECK ("data" != 'forbidden'));`, 291 }, 292 Assertions: []ScriptTestAssertion{ 293 { 294 // Assert the check constraint runs correctly in ANSI_QUOTES mode 295 Query: `insert into t values (1, 'forbidden');`, 296 ExpectedErrStr: `Check constraint "ansi_check" violated`, 297 }, 298 { 299 // Disable ANSI_QUOTES mode 300 Query: `SET @@sql_mode='NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 301 Expected: []sql.Row{{}}, 302 }, 303 { 304 // Assert the check constraint runs correctly when ANSI_QUOTES mode is disabled 305 Query: `insert into t values (1, 'forbidden');`, 306 ExpectedErrStr: `Check constraint "ansi_check" violated`, 307 }, 308 }, 309 }, 310 { 311 Name: "ANSI_QUOTES: events", 312 SetUpScript: []string{ 313 `SET @@sql_mode='ANSI_QUOTES,NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 314 `create table t (pk int primary key, "count" int);`, 315 `insert into t values (1, 0);`, 316 }, 317 Assertions: []ScriptTestAssertion{ 318 { 319 Query: `CREATE EVENT myevent 320 ON SCHEDULE EVERY 1 SECOND STARTS '2037-10-16 23:59:00' DO 321 UPDATE "t" SET "count"="count"+1;`, 322 Expected: []sql.Row{{types.NewOkResult(0)}}, 323 }, 324 { 325 Query: `SHOW EVENTS;`, 326 Expected: []sql.Row{{"mydb", "myevent", "`root`@`localhost`", "SYSTEM", "RECURRING", nil, "1", "SECOND", "2037-10-16 23:59:00", nil, "ENABLED", 0, "utf8mb4", "utf8mb4_0900_bin", "utf8mb4_0900_bin"}}, 327 }, 328 { 329 // Disable ANSI_QUOTES mode and make sure we can still list and run events 330 Query: `SET @@sql_mode='NO_ENGINE_SUBSTITUTION,ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES';`, 331 Expected: []sql.Row{{}}, 332 }, 333 { 334 Query: `SHOW EVENTS;`, 335 Expected: []sql.Row{{"mydb", "myevent", "`root`@`localhost`", "SYSTEM", "RECURRING", nil, "1", "SECOND", "2037-10-16 23:59:00", nil, "ENABLED", 0, "utf8mb4", "utf8mb4_0900_bin", "utf8mb4_0900_bin"}}, 336 }, 337 }, 338 }, 339 }