vitess.io/vitess@v0.16.2/go/vt/sqlparser/parse_test.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package sqlparser
    18  
    19  import (
    20  	"bufio"
    21  	"bytes"
    22  	"compress/gzip"
    23  	"fmt"
    24  	"io"
    25  	"math/rand"
    26  	"os"
    27  	"path"
    28  	"strings"
    29  	"sync"
    30  	"testing"
    31  
    32  	"vitess.io/vitess/go/test/utils"
    33  
    34  	"github.com/google/go-cmp/cmp"
    35  
    36  	"github.com/stretchr/testify/assert"
    37  	"github.com/stretchr/testify/require"
    38  )
    39  
    40  var (
    41  	validSQL = []struct {
    42  		input                string
    43  		output               string
    44  		partialDDL           bool
    45  		ignoreNormalizerTest bool
    46  	}{{
    47  		input:      "create table x(location GEOMETRYCOLLECTION DEFAULT POINT(7.0, 3.0))",
    48  		output:     "create table x",
    49  		partialDDL: true,
    50  	}, {
    51  		input:  "create table t (id int primary key, dt datetime DEFAULT (CURRENT_TIMESTAMP))",
    52  		output: "create table t (\n\tid int primary key,\n\tdt datetime default current_timestamp()\n)",
    53  	}, {
    54  		input:  "create table t (id int primary key, dt datetime DEFAULT now())",
    55  		output: "create table t (\n\tid int primary key,\n\tdt datetime default now()\n)",
    56  	}, {
    57  		input:  "create table t (id int primary key, dt datetime DEFAULT (now()))",
    58  		output: "create table t (\n\tid int primary key,\n\tdt datetime default now()\n)",
    59  	}, {
    60  		input:  "create table x (e enum('red','yellow') null collate 'utf8_bin')",
    61  		output: "create table x (\n\te enum('red', 'yellow') collate 'utf8_bin' null\n)",
    62  	}, {
    63  		input:  "create table 3t2 (c1 bigint not null, c2 text, primary key(c1))",
    64  		output: "create table `3t2` (\n\tc1 bigint not null,\n\tc2 text,\n\tprimary key (c1)\n)",
    65  	}, {
    66  		input:  "select 1 from t1 where exists (select 1) = TRUE",
    67  		output: "select 1 from t1 where exists (select 1 from dual) = true",
    68  	}, {
    69  		input:  "select 1 from t1 where exists (select 1) = FALSE",
    70  		output: "select 1 from t1 where exists (select 1 from dual) = false",
    71  	}, {
    72  		input:  "select 1 from t1 where exists (select 1) = 1",
    73  		output: "select 1 from t1 where exists (select 1 from dual) = 1",
    74  	}, {
    75  		input:  "create table x(location GEOMETRY DEFAULT (POINT(7.0, 3.0)))",
    76  		output: "create table x (\n\tlocation GEOMETRY default (POINT(7.0, 3.0))\n)",
    77  	}, {
    78  		input:  "select 1",
    79  		output: "select 1 from dual",
    80  	}, {
    81  		input:  "SELECT EXTRACT(YEAR FROM '2019-07-02')",
    82  		output: "select extract(year from '2019-07-02') from dual",
    83  	}, {
    84  		input:  "SELECT EXTRACT(YEAR_MONTH FROM '2019-07-02 01:02:03')",
    85  		output: "select extract(year_month from '2019-07-02 01:02:03') from dual",
    86  	}, {
    87  		input:  "select extract(year from \"21-10-22 12:00:00\")",
    88  		output: "select extract(year from '21-10-22 12:00:00') from dual",
    89  	}, {
    90  		input:  "SELECT EXTRACT(DAY_MINUTE FROM '2019-07-02 01:02:03')",
    91  		output: "select extract(day_minute from '2019-07-02 01:02:03') from dual",
    92  	}, {
    93  		input:  "SELECT EXTRACT(MICROSECOND FROM '2003-01-02 10:30:00.000123')",
    94  		output: "select extract(microsecond from '2003-01-02 10:30:00.000123') from dual",
    95  	}, {
    96  		input:  "CREATE TABLE t2 (b BLOB DEFAULT 'abc')",
    97  		output: "create table t2 (\n\tb BLOB default ('abc')\n)",
    98  	}, {
    99  		input:  "CREATE TABLE t2 (b blob DEFAULT 'abc')",
   100  		output: "create table t2 (\n\tb blob default ('abc')\n)",
   101  	}, {
   102  		input:  "CREATE TABLE t2 (b BLOB DEFAULT ('abc'))",
   103  		output: "create table t2 (\n\tb BLOB default ('abc')\n)",
   104  	}, {
   105  		input:  "CREATE TABLE t2 (b TINYBLOB DEFAULT 'abc')",
   106  		output: "create table t2 (\n\tb TINYBLOB default ('abc')\n)",
   107  	}, {
   108  		input:  "CREATE TABLE t2 (b TINYBLOB DEFAULT ('abc'))",
   109  		output: "create table t2 (\n\tb TINYBLOB default ('abc')\n)",
   110  	}, {
   111  		input:  "CREATE TABLE t2 (b MEDIUMBLOB DEFAULT 'abc')",
   112  		output: "create table t2 (\n\tb MEDIUMBLOB default ('abc')\n)",
   113  	}, {
   114  		input:  "CREATE TABLE t2 (b MEDIUMBLOB DEFAULT ('abc'))",
   115  		output: "create table t2 (\n\tb MEDIUMBLOB default ('abc')\n)",
   116  	}, {
   117  		input:  "CREATE TABLE t2 (b LONGBLOB DEFAULT 'abc')",
   118  		output: "create table t2 (\n\tb LONGBLOB default ('abc')\n)",
   119  	}, {
   120  		input:  "CREATE TABLE t2 (b LONGBLOB DEFAULT ('abc'))",
   121  		output: "create table t2 (\n\tb LONGBLOB default ('abc')\n)",
   122  	}, {
   123  		input:  "CREATE TABLE t2 (b TEXT DEFAULT 'abc')",
   124  		output: "create table t2 (\n\tb TEXT default ('abc')\n)",
   125  	}, {
   126  		input:  "CREATE TABLE t2 (b TEXT DEFAULT ('abc'))",
   127  		output: "create table t2 (\n\tb TEXT default ('abc')\n)",
   128  	}, {
   129  		input:  "CREATE TABLE t2 (b TINYTEXT DEFAULT 'abc')",
   130  		output: "create table t2 (\n\tb TINYTEXT default ('abc')\n)",
   131  	}, {
   132  		input:  "CREATE TABLE t2 (b TINYTEXT DEFAULT ('abc'))",
   133  		output: "create table t2 (\n\tb TINYTEXT default ('abc')\n)",
   134  	}, {
   135  		input:  "CREATE TABLE t2 (b MEDIUMTEXT DEFAULT 'abc')",
   136  		output: "create table t2 (\n\tb MEDIUMTEXT default ('abc')\n)",
   137  	}, {
   138  		input:  "CREATE TABLE t2 (b MEDIUMTEXT DEFAULT ('abc'))",
   139  		output: "create table t2 (\n\tb MEDIUMTEXT default ('abc')\n)",
   140  	}, {
   141  		input:  "CREATE TABLE t2 (b LONGTEXT DEFAULT 'abc')",
   142  		output: "create table t2 (\n\tb LONGTEXT default ('abc')\n)",
   143  	}, {
   144  		input:  "CREATE TABLE t2 (b LONGTEXT DEFAULT ('abc'))",
   145  		output: "create table t2 (\n\tb LONGTEXT default ('abc')\n)",
   146  	}, {
   147  		input:  "CREATE TABLE t2 (b JSON DEFAULT null)",
   148  		output: "create table t2 (\n\tb JSON default null\n)",
   149  	}, {
   150  		input:  "CREATE TABLE t2 (b JSON DEFAULT (null))",
   151  		output: "create table t2 (\n\tb JSON default null\n)",
   152  	}, {
   153  		input:  "CREATE TABLE t2 (b JSON DEFAULT '{name:abc}')",
   154  		output: "create table t2 (\n\tb JSON default ('{name:abc}')\n)",
   155  	}, {
   156  		input:  "CREATE TABLE t2 (b JSON DEFAULT ('{name:abc}'))",
   157  		output: "create table t2 (\n\tb JSON default ('{name:abc}')\n)",
   158  	}, {
   159  		input:  "create table x(location POINT DEFAULT 7.0)",
   160  		output: "create table x (\n\tlocation POINT default (7.0)\n)",
   161  	}, {
   162  		input:  "create table x(location POINT DEFAULT (7.0))",
   163  		output: "create table x (\n\tlocation POINT default (7.0)\n)",
   164  	}, {
   165  		input:  "create table x(location LINESTRING DEFAULT (POINT(7.0, 3.0)))",
   166  		output: "create table x (\n\tlocation LINESTRING default (POINT(7.0, 3.0))\n)",
   167  	}, {
   168  		input:  "create table x(location POLYGON DEFAULT (POINT(7.0, 3.0)))",
   169  		output: "create table x (\n\tlocation POLYGON default (POINT(7.0, 3.0))\n)",
   170  	}, {
   171  		input:  "create table x(location MULTIPOINT DEFAULT (POINT(7.0, 3.0)))",
   172  		output: "create table x (\n\tlocation MULTIPOINT default (POINT(7.0, 3.0))\n)",
   173  	}, {
   174  		input:  "create table x(location MULTILINESTRING DEFAULT (POINT(7.0, 3.0)))",
   175  		output: "create table x (\n\tlocation MULTILINESTRING default (POINT(7.0, 3.0))\n)",
   176  	}, {
   177  		input:  "create table x(location MULTIPOLYGON DEFAULT (POINT(7.0, 3.0)))",
   178  		output: "create table x (\n\tlocation MULTIPOLYGON default (POINT(7.0, 3.0))\n)",
   179  	}, {
   180  		input:  "create table x(location GEOMETRYCOLLECTION DEFAULT (POINT(7.0, 3.0)))",
   181  		output: "create table x (\n\tlocation GEOMETRYCOLLECTION default (POINT(7.0, 3.0))\n)",
   182  	}, {
   183  		input:  "WITH RECURSIVE  odd_num_cte (id, n) AS (SELECT 1, 1 union all SELECT id+1, n+2 from odd_num_cte where id < 5) SELECT * FROM odd_num_cte",
   184  		output: "with recursive odd_num_cte(id, n) as (select 1, 1 from dual union all select id + 1, n + 2 from odd_num_cte where id < 5) select * from odd_num_cte",
   185  	}, {
   186  		input:  "WITH topsales2003 AS (SELECT salesRepEmployeeNumber employeeNumber, SUM(quantityOrdered * priceEach) sales FROM orders INNER JOIN orderdetails USING (orderNumber) INNER JOIN customers USING (customerNumber) WHERE YEAR(shippedDate) = 2003 AND status = 'Shipped' GROUP BY salesRepEmployeeNumber ORDER BY sales DESC LIMIT 5)SELECT employeeNumber, firstName, lastName, sales FROM employees JOIN topsales2003 USING (employeeNumber)",
   187  		output: "with topsales2003 as (select salesRepEmployeeNumber as employeeNumber, sum(quantityOrdered * priceEach) as sales from orders join orderdetails using (orderNumber) join customers using (customerNumber) where YEAR(shippedDate) = 2003 and `status` = 'Shipped' group by salesRepEmployeeNumber order by sales desc limit 5) select employeeNumber, firstName, lastName, sales from employees join topsales2003 using (employeeNumber)",
   188  	}, {
   189  		input: "select 1 from t",
   190  	}, {
   191  		input:  "select * from (select 1) as x(user)",
   192  		output: "select * from (select 1 from dual) as x(`user`)",
   193  	}, {
   194  		input:  "select user from (select id from users ) as x(user)",
   195  		output: "select `user` from (select id from users) as x(`user`)",
   196  	}, {
   197  		input: "select n, d from something",
   198  	}, {
   199  		input: "insert into sys_message_assign(message_id, assign_user_id, read_state, id, is_delete, create_time, update_time, remark) values (N'3477028275831808', N'4104487936', N'1', N'0', N'0', '2021-09-22 14:24:17.922', '2021-09-22 14:24:17.922', null), (N'3477028275831808', N'3454139190608923', N'1', N'0', N'0', '2021-09-22 14:24:17.922', '2021-09-22 14:24:17.922', null)",
   200  		/*We need to ignore this test because, after the normalizer, we change the produced NChar
   201  		string into an introducer expression, so the vttablet will never see a NChar string */
   202  		ignoreNormalizerTest: true,
   203  	}, {
   204  		input:  "select name, numbers from (select * from users) as x(name, numbers)",
   205  		output: "select `name`, numbers from (select * from users) as x(`name`, numbers)",
   206  	}, {
   207  		input:  "select 0b010, 0b0111, b'0111', b'011'",
   208  		output: "select B'010', B'0111', B'0111', B'011' from dual",
   209  	}, {
   210  		input:  "select 0x010, 0x0111, x'0111'",
   211  		output: "select 0x010, 0x0111, X'0111' from dual",
   212  	}, {
   213  		input:  "select date'2022-10-03'",
   214  		output: "select date'2022-10-03' from dual",
   215  	}, {
   216  		input:  "select date, time, timestamp from t",
   217  		output: "select `date`, `time`, `timestamp` from t",
   218  	}, {
   219  		input:  "select time'12:34:56'",
   220  		output: "select time'12:34:56' from dual",
   221  	}, {
   222  		input:  "select timestamp'2012-12-31 11:30:45'",
   223  		output: "select timestamp'2012-12-31 11:30:45' from dual",
   224  	}, {
   225  		input:  "select * from information_schema.columns",
   226  		output: "select * from information_schema.`columns`",
   227  	}, {
   228  		input:  "select * from information_schema.processlist",
   229  		output: "select * from information_schema.`processlist`",
   230  	}, {
   231  		input: "select .1 from t",
   232  	}, {
   233  		input: "select 1.2e1 from t",
   234  	}, {
   235  		input: "select 1.2e+1 from t",
   236  	}, {
   237  		input: "select 1.2e-1 from t",
   238  	}, {
   239  		input: "select 08.3 from t",
   240  	}, {
   241  		input: "select -1 from t where b = -2",
   242  	}, {
   243  		input:  "select - -1 from t",
   244  		output: "select - -1 from t",
   245  	}, {
   246  		input: "select a from t",
   247  	}, {
   248  		input: "select $ from t",
   249  	}, {
   250  		// shift/reduce conflict on CHARSET, should throw an error on shifting which will be ignored as it is a DDL
   251  		input:      "alter database charset = 'utf16';",
   252  		output:     "alter database",
   253  		partialDDL: true,
   254  	}, {
   255  		input:  "alter database charset charset = 'utf16'",
   256  		output: "alter database `charset` character set 'utf16'",
   257  	}, {
   258  		input:  "create table t(id int unique)",
   259  		output: "create table t (\n\tid int unique\n)",
   260  	}, {
   261  		input:  "create table t(id int key)",
   262  		output: "create table t (\n\tid int key\n)",
   263  	}, {
   264  		input:  "create table t(id int unique key)",
   265  		output: "create table t (\n\tid int unique key\n)",
   266  	}, {
   267  		input: "select a.b as a$b from $test$",
   268  	}, {
   269  		input:  "select 1 from t // aa\n",
   270  		output: "select 1 from t",
   271  	}, {
   272  		input:  "select 1 from t -- aa\n",
   273  		output: "select 1 from t",
   274  	}, {
   275  		input:  "select 1 from t # aa\n",
   276  		output: "select 1 from t",
   277  	}, {
   278  		input:  "select 1 -- aa\nfrom t",
   279  		output: "select 1 from t",
   280  	}, {
   281  		input:  "select 1 #aa\nfrom t",
   282  		output: "select 1 from t",
   283  	}, {
   284  		input: "select /* simplest */ 1 from t",
   285  	}, {
   286  		input: "select /* double star **/ 1 from t",
   287  	}, {
   288  		input: "select /* double */ /* comment */ 1 from t",
   289  	}, {
   290  		input: "select /* back-quote keyword */ `By` from t",
   291  	}, {
   292  		input: "select /* back-quote num */ `2a` from t",
   293  	}, {
   294  		input: "select /* back-quote . */ `a.b` from t",
   295  	}, {
   296  		input: "select /* back-quote back-quote */ `a``b` from t",
   297  	}, {
   298  		input:  "select /* back-quote unnecessary */ 1 from `t`",
   299  		output: "select /* back-quote unnecessary */ 1 from t",
   300  	}, {
   301  		input:  "select /* back-quote idnum */ 1 from `a1`",
   302  		output: "select /* back-quote idnum */ 1 from a1",
   303  	}, {
   304  		input: "select /* @ */ @@a from b",
   305  	}, {
   306  		input: "select /* \\0 */ '\\0' from a",
   307  	}, {
   308  		input:  "select 1 /* drop this comment */ from t",
   309  		output: "select 1 from t",
   310  	}, {
   311  		input: "select /* union */ 1 from t union select 1 from t",
   312  	}, {
   313  		input: "select /* double union */ 1 from t union select 1 from t union select 1 from t",
   314  	}, {
   315  		input: "select /* union all */ 1 from t union all select 1 from t",
   316  	}, {
   317  		input:  "select /* union distinct */ 1 from t union distinct select 1 from t",
   318  		output: "select /* union distinct */ 1 from t union select 1 from t",
   319  	}, {
   320  		input:  "(select /* union parenthesized select */ 1 from t order by a) union select 1 from t",
   321  		output: "(select /* union parenthesized select */ 1 from t order by a asc) union select 1 from t",
   322  	}, {
   323  		input:  "select /* union parenthesized select 2 */ 1 from t union (select 1 from t)",
   324  		output: "select /* union parenthesized select 2 */ 1 from t union select 1 from t",
   325  	}, {
   326  		input:  "select /* union order by */ 1 from t union select 1 from t order by a",
   327  		output: "select /* union order by */ 1 from t union select 1 from t order by a asc",
   328  	}, {
   329  		input:  "select /* union order by limit lock */ 1 from t union select 1 from t order by a limit 1 for update",
   330  		output: "select /* union order by limit lock */ 1 from t union select 1 from t order by a asc limit 1 for update",
   331  	}, {
   332  		input:  "(select id, a from t order by id limit 1) union (select id, b as a from s order by id limit 1) order by a limit 1",
   333  		output: "(select id, a from t order by id asc limit 1) union (select id, b as a from s order by id asc limit 1) order by a asc limit 1",
   334  	}, {
   335  		input:  "select a from (select 1 as a from tbl1 union select 2 from tbl2) as t",
   336  		output: "select a from (select 1 as a from tbl1 union select 2 from tbl2) as t",
   337  	}, {
   338  		input: "select * from t1 join (select * from t2 union select * from t3) as t",
   339  	}, {
   340  		// Ensure this doesn't generate: ""select * from t1 join t2 on a = b join t3 on a = b".
   341  		input: "select * from t1 join t2 on a = b join t3",
   342  	}, {
   343  		input:  "select * from t1 where col in (select 1 from dual union select 2 from dual)",
   344  		output: "select * from t1 where col in (select 1 from dual union select 2 from dual)",
   345  	}, {
   346  		input: "select * from t1 where exists (select a from t2 union select b from t3)",
   347  	}, {
   348  		input:  "select 1 from dual union select 2 from dual union all select 3 from dual union select 4 from dual union all select 5 from dual",
   349  		output: "select 1 from dual union select 2 from dual union all select 3 from dual union select 4 from dual union all select 5 from dual",
   350  	}, {
   351  		input:  "(select 1 from dual) order by 1 asc limit 2",
   352  		output: "select 1 from dual order by 1 asc limit 2",
   353  	}, {
   354  		input:  "(select 1 from dual order by 1 desc) order by 1 asc limit 2",
   355  		output: "select 1 from dual order by 1 asc limit 2",
   356  	}, {
   357  		input:  "(select 1 from dual)",
   358  		output: "select 1 from dual",
   359  	}, {
   360  		input:  "((select 1 from dual))",
   361  		output: "select 1 from dual",
   362  	}, {
   363  		input: "select 1 from (select 1 from dual) as t",
   364  	}, {
   365  		input:  "select 1 from (select 1 from dual union select 2 from dual) as t",
   366  		output: "select 1 from (select 1 from dual union select 2 from dual) as t",
   367  	}, {
   368  		input:  "select 1 from ((select 1 from dual) union select 2 from dual) as t",
   369  		output: "select 1 from (select 1 from dual union select 2 from dual) as t",
   370  	}, {
   371  		input: "select /* distinct */ distinct 1 from t",
   372  	}, {
   373  		input: "select /* straight_join */ straight_join 1 from t",
   374  	}, {
   375  		input: "select /* for update */ 1 from t for update",
   376  	}, {
   377  		input: "select /* lock in share mode */ 1 from t lock in share mode",
   378  	}, {
   379  		input: "select /* select list */ 1, 2 from t",
   380  	}, {
   381  		input: "select /* * */ * from t",
   382  	}, {
   383  		input: "select /* a.* */ a.* from t",
   384  	}, {
   385  		input: "select /* a.b.* */ a.b.* from t",
   386  	}, {
   387  		input:  "select /* column alias */ a b from t",
   388  		output: "select /* column alias */ a as b from t",
   389  	}, {
   390  		input: "select /* column alias with as */ a as b from t",
   391  	}, {
   392  		input: "select /* keyword column alias */ a as `By` from t",
   393  	}, {
   394  		input:  "select /* column alias as string */ a as \"b\" from t",
   395  		output: "select /* column alias as string */ a as b from t",
   396  	}, {
   397  		input:  "select /* column alias as string without as */ a \"b\" from t",
   398  		output: "select /* column alias as string without as */ a as b from t",
   399  	}, {
   400  		input:  "select /* column alias with non_reserved keyword */ a as auto_increment from t",
   401  		output: "select /* column alias with non_reserved keyword */ a as `auto_increment` from t",
   402  	}, {
   403  		input: "select /* a.* */ a.* from t",
   404  	}, {
   405  		input:  "select next value for t",
   406  		output: "select next 1 values from t",
   407  	}, {
   408  		input:  "select next value from t",
   409  		output: "select next 1 values from t",
   410  	}, {
   411  		input: "select next 10 values from t",
   412  	}, {
   413  		input: "select next :a values from t",
   414  	}, {
   415  		input: "select /* `By`.* */ `By`.* from t",
   416  	}, {
   417  		input: "select /* select with bool expr */ a = b from t",
   418  	}, {
   419  		input: "select /* case_when */ case when a = b then c end from t",
   420  	}, {
   421  		input: "select /* case_when_else */ case when a = b then c else d end from t",
   422  	}, {
   423  		input: "select /* case_when_when_else */ case when a = b then c when b = d then d else d end from t",
   424  	}, {
   425  		input: "select /* case */ case aa when a = b then c end from t",
   426  	}, {
   427  		input: "select /* parenthesis */ 1 from (t)",
   428  	}, {
   429  		input: "select /* parenthesis multi-table */ 1 from (t1, t2)",
   430  	}, {
   431  		input: "select /* table list */ 1 from t1, t2",
   432  	}, {
   433  		input: "select /* parenthessis in table list 1 */ 1 from (t1), t2",
   434  	}, {
   435  		input:  "SELECT * FROM t1 USE INDEX (i1) IGNORE INDEX FOR ORDER BY (i2) ORDER BY a",
   436  		output: "select * from t1 use index (i1) ignore index for order by (i2) order by a asc",
   437  	}, {
   438  		input:  "SELECT * FROM t1 USE INDEX FOR JOIN (i1) FORCE INDEX FOR JOIN (i2)",
   439  		output: "select * from t1 use index for join (i1) force index for join (i2)",
   440  	}, {
   441  		input:  "SELECT * FROM t1 USE INDEX FOR JOIN (i1) FORCE INDEX FOR JOIN (i2) IGNORE KEY FOR GROUP BY (i1, i2)",
   442  		output: "select * from t1 use index for join (i1) force index for join (i2) ignore index for group by (i1, i2)",
   443  	}, {
   444  		input:  "SELECT * FROM t1 USE KEY (), t2 FORCE KEY (i2), t3 IGNORE INDEX FOR GROUP BY (i1, i2)",
   445  		output: "select * from t1 use index (), t2 force index (i2), t3 ignore index for group by (i1, i2)",
   446  	}, {
   447  		input: "select /* parenthessis in table list 2 */ 1 from t1, (t2)",
   448  	}, {
   449  		input: "select /* use */ 1 from t1 use index (a) where b = 1",
   450  	}, {
   451  		input: "select /* use */ 1 from t1 use index () where b = 1",
   452  	}, {
   453  		input: "select /* keyword index */ 1 from t1 use index (`By`) where b = 1",
   454  	}, {
   455  		input: "select /* ignore */ 1 from t1 as t2 ignore index (a), t3 use index (b) where b = 1",
   456  	}, {
   457  		input: "select /* use */ 1 from t1 as t2 use index (a), t3 use index (b) where b = 1",
   458  	}, {
   459  		input: "select /* force */ 1 from t1 as t2 force index (a), t3 force index (b) where b = 1",
   460  	}, {
   461  		input:  "select /* table alias */ 1 from t t1",
   462  		output: "select /* table alias */ 1 from t as t1",
   463  	}, {
   464  		input: "select /* table alias with as */ 1 from t as t1",
   465  	}, {
   466  		input:  "select /* string table alias */ 1 from t as 't1'",
   467  		output: "select /* string table alias */ 1 from t as t1",
   468  	}, {
   469  		input:  "select /* string table alias without as */ 1 from t 't1'",
   470  		output: "select /* string table alias without as */ 1 from t as t1",
   471  	}, {
   472  		input: "select /* keyword table alias */ 1 from t as `By`",
   473  	}, {
   474  		input: "select /* join */ 1 from t1 join t2",
   475  	}, {
   476  		input: "select /* join on */ 1 from t1 join t2 on a = b",
   477  	}, {
   478  		input: "select /* join on */ 1 from t1 join t2 using (a)",
   479  	}, {
   480  		input:  "select /* inner join */ 1 from t1 inner join t2",
   481  		output: "select /* inner join */ 1 from t1 join t2",
   482  	}, {
   483  		input:  "select /* cross join */ 1 from t1 cross join t2",
   484  		output: "select /* cross join */ 1 from t1 join t2",
   485  	}, {
   486  		input: "select /* straight_join */ 1 from t1 straight_join t2",
   487  	}, {
   488  		input: "select /* straight_join on */ 1 from t1 straight_join t2 on a = b",
   489  	}, {
   490  		input: "select /* left join */ 1 from t1 left join t2 on a = b",
   491  	}, {
   492  		input: "select /* left join */ 1 from t1 left join t2 using (a)",
   493  	}, {
   494  		input:  "select /* left outer join */ 1 from t1 left outer join t2 on a = b",
   495  		output: "select /* left outer join */ 1 from t1 left join t2 on a = b",
   496  	}, {
   497  		input:  "select /* left outer join */ 1 from t1 left outer join t2 using (a)",
   498  		output: "select /* left outer join */ 1 from t1 left join t2 using (a)",
   499  	}, {
   500  		input: "select /* right join */ 1 from t1 right join t2 on a = b",
   501  	}, {
   502  		input: "select /* right join */ 1 from t1 right join t2 using (a)",
   503  	}, {
   504  		input:  "select /* right outer join */ 1 from t1 right outer join t2 on a = b",
   505  		output: "select /* right outer join */ 1 from t1 right join t2 on a = b",
   506  	}, {
   507  		input:  "select /* right outer join */ 1 from t1 right outer join t2 using (a)",
   508  		output: "select /* right outer join */ 1 from t1 right join t2 using (a)",
   509  	}, {
   510  		input: "select /* natural join */ 1 from t1 natural join t2",
   511  	}, {
   512  		input: "select /* natural left join */ 1 from t1 natural left join t2",
   513  	}, {
   514  		input:  "select /* natural left outer join */ 1 from t1 natural left join t2",
   515  		output: "select /* natural left outer join */ 1 from t1 natural left join t2",
   516  	}, {
   517  		input: "select /* natural right join */ 1 from t1 natural right join t2",
   518  	}, {
   519  		input:  "select /* natural right outer join */ 1 from t1 natural right join t2",
   520  		output: "select /* natural right outer join */ 1 from t1 natural right join t2",
   521  	}, {
   522  		input: "select /* join on */ 1 from t1 join t2 on a = b",
   523  	}, {
   524  		input: "select /* join using */ 1 from t1 join t2 using (a)",
   525  	}, {
   526  		input: "select /* join using (a, b, c) */ 1 from t1 join t2 using (a, b, c)",
   527  	}, {
   528  		input: "select /* s.t */ 1 from s.t",
   529  	}, {
   530  		input: "select /* keyword schema & table name */ 1 from `By`.`bY`",
   531  	}, {
   532  		input: "select /* select in from */ 1 from (select 1 from t) as a",
   533  	}, {
   534  		input:  "select /* select in from with no as */ 1 from (select 1 from t) a",
   535  		output: "select /* select in from with no as */ 1 from (select 1 from t) as a",
   536  	}, {
   537  		input: "select /* where */ 1 from t where a = b",
   538  	}, {
   539  		input: "select /* and */ 1 from t where a = b and a = c",
   540  	}, {
   541  		input:  "select /* && */ 1 from t where a = b && a = c",
   542  		output: "select /* && */ 1 from t where a = b and a = c",
   543  	}, {
   544  		input: "select /* or */ 1 from t where a = b or a = c",
   545  	}, {
   546  		input:  "select /* || */ 1 from t where a = b || a = c",
   547  		output: "select /* || */ 1 from t where a = b or a = c",
   548  	}, {
   549  		input: "select /* not */ 1 from t where not a = b",
   550  	}, {
   551  		input: "select /* ! */ 1 from t where a = !1",
   552  	}, {
   553  		input: "select /* bool is */ 1 from t where a = b is null",
   554  	}, {
   555  		input: "select /* bool is not */ 1 from t where a = b is not false",
   556  	}, {
   557  		input: "select /* true */ 1 from t where true",
   558  	}, {
   559  		input: "select /* false */ 1 from t where false",
   560  	}, {
   561  		input: "select /* false on left */ 1 from t where false = 0",
   562  	}, {
   563  		input: "select /* exists */ 1 from t where exists (select 1 from t)",
   564  	}, {
   565  		input:  "select /* (boolean) */ 1 from t where not (a = b)",
   566  		output: "select /* (boolean) */ 1 from t where not a = b",
   567  	}, {
   568  		input: "select /* in value list */ 1 from t where a in (b, c)",
   569  	}, {
   570  		input: "select /* in select */ 1 from t where a in (select 1 from t)",
   571  	}, {
   572  		input: "select /* not in */ 1 from t where a not in (b, c)",
   573  	}, {
   574  		input: "select /* like */ 1 from t where a like b",
   575  	}, {
   576  		input: "select /* like escape */ 1 from t where a like b escape '!'",
   577  	}, {
   578  		input: "select /* not like */ 1 from t where a not like b",
   579  	}, {
   580  		input: "select /* not like escape */ 1 from t where a not like b escape '$'",
   581  	}, {
   582  		input: "select /* regexp */ 1 from t where a regexp b",
   583  	}, {
   584  		input: "select /* not regexp */ 1 from t where a not regexp b",
   585  	}, {
   586  		input:  "select /* rlike */ 1 from t where a rlike b",
   587  		output: "select /* rlike */ 1 from t where a regexp b",
   588  	}, {
   589  		input:  "select /* not rlike */ 1 from t where a not rlike b",
   590  		output: "select /* not rlike */ 1 from t where a not regexp b",
   591  	}, {
   592  		input: "select /* between */ 1 from t where a between b and c",
   593  	}, {
   594  		input: "select /* not between */ 1 from t where a not between b and c",
   595  	}, {
   596  		input: "select /* is null */ 1 from t where a is null",
   597  	}, {
   598  		input: "select /* is not null */ 1 from t where a is not null",
   599  	}, {
   600  		input: "select /* is true */ 1 from t where a is true",
   601  	}, {
   602  		input: "select /* is not true */ 1 from t where a is not true",
   603  	}, {
   604  		input: "select /* is false */ 1 from t where a is false",
   605  	}, {
   606  		input: "select /* is not false */ 1 from t where a is not false",
   607  	}, {
   608  		input: "select /* < */ 1 from t where a < b",
   609  	}, {
   610  		input: "select /* <= */ 1 from t where a <= b",
   611  	}, {
   612  		input: "select /* >= */ 1 from t where a >= b",
   613  	}, {
   614  		input: "select /* > */ 1 from t where a > b",
   615  	}, {
   616  		input: "select /* != */ 1 from t where a != b",
   617  	}, {
   618  		input:  "select /* <> */ 1 from t where a <> b",
   619  		output: "select /* <> */ 1 from t where a != b",
   620  	}, {
   621  		input: "select /* <=> */ 1 from t where a <=> b",
   622  	}, {
   623  		input: "select /* != */ 1 from t where a != b",
   624  	}, {
   625  		input: "select /* single value expre list */ 1 from t where a in (b)",
   626  	}, {
   627  		input: "select /* select as a value expression */ 1 from t where a = (select a from t)",
   628  	}, {
   629  		input:  "select /* parenthesised value */ 1 from t where a = (b)",
   630  		output: "select /* parenthesised value */ 1 from t where a = b",
   631  	}, {
   632  		input:  "select /* over-parenthesize */ ((1)) from t where ((a)) in (((1))) and ((a, b)) in ((((1, 1))), ((2, 2)))",
   633  		output: "select /* over-parenthesize */ 1 from t where a in (1) and (a, b) in ((1, 1), (2, 2))",
   634  	}, {
   635  		input:  "select /* dot-parenthesize */ (a.b) from t where (b.c) = 2",
   636  		output: "select /* dot-parenthesize */ a.b from t where b.c = 2",
   637  	}, {
   638  		input: "select /* & */ 1 from t where a = b & c",
   639  	}, {
   640  		input: "select /* & */ 1 from t where a = b & c",
   641  	}, {
   642  		input: "select /* | */ 1 from t where a = b | c",
   643  	}, {
   644  		input: "select /* ^ */ 1 from t where a = b ^ c",
   645  	}, {
   646  		input: "select /* + */ 1 from t where a = b + c",
   647  	}, {
   648  		input: "select /* - */ 1 from t where a = b - c",
   649  	}, {
   650  		input: "select /* * */ 1 from t where a = b * c",
   651  	}, {
   652  		input: "select /* / */ 1 from t where a = b / c",
   653  	}, {
   654  		input: "select /* % */ 1 from t where a = b % c",
   655  	}, {
   656  		input: "select /* div */ 1 from t where a = b div c",
   657  	}, {
   658  		input:  "select /* MOD */ 1 from t where a = b MOD c",
   659  		output: "select /* MOD */ 1 from t where a = b % c",
   660  	}, {
   661  		input: "select /* << */ 1 from t where a = b << c",
   662  	}, {
   663  		input: "select /* >> */ 1 from t where a = b >> c",
   664  	}, {
   665  		input:  "select /* % no space */ 1 from t where a = b%c",
   666  		output: "select /* % no space */ 1 from t where a = b % c",
   667  	}, {
   668  		input:  "select /* u+ */ 1 from t where a = +b",
   669  		output: "select /* u+ */ 1 from t where a = b",
   670  	}, {
   671  		input: "select /* u- */ 1 from t where a = -b",
   672  	}, {
   673  		input: "select /* u~ */ 1 from t where a = ~b",
   674  	}, {
   675  		input: "select /* -> */ a.b -> 'ab' from t",
   676  	}, {
   677  		input: "select /* -> */ a.b ->> 'ab' from t",
   678  	}, {
   679  		input: "select /* empty function */ 1 from t where a = b()",
   680  	}, {
   681  		input: "select /* function with 1 param */ 1 from t where a = b(c)",
   682  	}, {
   683  		input: "select /* function with many params */ 1 from t where a = b(c, d)",
   684  	}, {
   685  		input: "select /* function with distinct */ count(distinct a) from t",
   686  	}, {
   687  		input:  "select count(distinctrow(1)) from (select (1) from dual union all select 1 from dual) a",
   688  		output: "select count(distinct 1) from (select 1 from dual union all select 1 from dual) as a",
   689  	}, {
   690  		input: "select /* if as func */ 1 from t where a = if(b)",
   691  	}, {
   692  		input: "select /* current_timestamp */ current_timestamp() from t",
   693  	}, {
   694  		input: "select /* current_timestamp as func */ current_timestamp() from t",
   695  	}, {
   696  		input: "select /* current_timestamp with fsp */ current_timestamp(3) from t",
   697  	}, {
   698  		input: "select /* current_date */ current_date() from t",
   699  	}, {
   700  		input: "select /* current_date as func */ current_date() from t",
   701  	}, {
   702  		input: "select /* current_time */ current_time() from t",
   703  	}, {
   704  		input: "select /* current_time as func */ current_time() from t",
   705  	}, {
   706  		input: "select /* current_time with fsp */ current_time(1) from t",
   707  	}, {
   708  		input: "select /* utc_timestamp */ utc_timestamp() from t",
   709  	}, {
   710  		input: "select /* utc_timestamp as func */ utc_timestamp() from t",
   711  	}, {
   712  		input: "select /* utc_timestamp with fsp */ utc_timestamp(0) from t",
   713  	}, {
   714  		input: "select /* utc_time */ utc_time() from t",
   715  	}, {
   716  		input: "select /* utc_time as func */ utc_time() from t",
   717  	}, {
   718  		input: "select /* utc_time with fsp */ utc_time(4) from t",
   719  	}, {
   720  		input: "select /* utc_date */ utc_date() from t",
   721  	}, {
   722  		input: "select /* utc_date as func */ utc_date() from t",
   723  	}, {
   724  		input: "select /* localtime */ localtime() from t",
   725  	}, {
   726  		input: "select /* localtime as func */ localtime() from t",
   727  	}, {
   728  		input: "select /* localtime with fsp */ localtime(5) from t",
   729  	}, {
   730  		input: "select /* localtimestamp */ localtimestamp() from t",
   731  	}, {
   732  		input: "select /* localtimestamp as func */ localtimestamp() from t",
   733  	}, {
   734  		input: "select /* localtimestamp with fsp */ localtimestamp(7) from t",
   735  	}, {
   736  		input: "select /* mod as func */ a from tab where mod(b, 2) = 0",
   737  	}, {
   738  		input: "select /* database as func no param */ database() from t",
   739  	}, {
   740  		input: "select /* database as func 1 param */ database(1) from t",
   741  	}, {
   742  		input: "select /* a */ a from t",
   743  	}, {
   744  		input: "select /* a.b */ a.b from t",
   745  	}, {
   746  		input: "select /* a.b.c */ a.b.c from t",
   747  	}, {
   748  		input: "select /* keyword a.b */ `By`.`bY` from t",
   749  	}, {
   750  		input: "select /* string */ 'a' from t",
   751  	}, {
   752  		input:  "select /* double quoted string */ \"a\" from t",
   753  		output: "select /* double quoted string */ 'a' from t",
   754  	}, {
   755  		input:  "select /* quote quote in string */ 'a''a' from t",
   756  		output: "select /* quote quote in string */ 'a\\'a' from t",
   757  	}, {
   758  		input:  "select /* double quote quote in string */ \"a\"\"a\" from t",
   759  		output: "select /* double quote quote in string */ 'a\\\"a' from t",
   760  	}, {
   761  		input:  "select /* quote in double quoted string */ \"a'a\" from t",
   762  		output: "select /* quote in double quoted string */ 'a\\'a' from t",
   763  	}, {
   764  		input: "select /* backslash quote in string */ 'a\\'a' from t",
   765  	}, {
   766  		input: "select /* literal backslash in string */ 'a\\\\na' from t",
   767  	}, {
   768  		input: "select /* all escapes */ '\\0\\'\\\"\\b\\n\\r\\t\\Z\\\\' from t",
   769  	}, {
   770  		input:  "select /* non-escape */ '\\x' from t",
   771  		output: "select /* non-escape */ 'x' from t",
   772  	}, {
   773  		input: "select /* unescaped backslash */ '\\n' from t",
   774  	}, {
   775  		input: "select /* value argument */ :a from t",
   776  	}, {
   777  		input: "select /* value argument with digit */ :a1 from t",
   778  	}, {
   779  		input: "select /* value argument with dot */ :a.b from t",
   780  	}, {
   781  		input:  "select /* positional argument */ ? from t",
   782  		output: "select /* positional argument */ :v1 from t",
   783  	}, {
   784  		input:  "select /* multiple positional arguments */ ?, ? from t",
   785  		output: "select /* multiple positional arguments */ :v1, :v2 from t",
   786  	}, {
   787  		input: "select /* list arg */ * from t where a in ::list",
   788  	}, {
   789  		input: "select /* list arg not in */ * from t where a not in ::list",
   790  	}, {
   791  		input: "select /* null */ null from t",
   792  	}, {
   793  		input: "select /* octal */ 010 from t",
   794  	}, {
   795  		input:  "select /* hex */ x'f0A1' from t",
   796  		output: "select /* hex */ X'f0A1' from t",
   797  	}, {
   798  		input: "select /* hex caps */ X'F0a1' from t",
   799  	}, {
   800  		input:  "select /* bit literal */ b'0101' from t",
   801  		output: "select /* bit literal */ B'0101' from t",
   802  	}, {
   803  		input: "select /* bit literal caps */ B'010011011010' from t",
   804  	}, {
   805  		input: "select /* 0x */ 0xf0 from t",
   806  	}, {
   807  		input: "select /* float */ 0.1 from t",
   808  	}, {
   809  		input: "select /* group by */ 1 from t group by a",
   810  	}, {
   811  		input: "select /* having */ 1 from t having a = b",
   812  	}, {
   813  		input:  "select /* simple order by */ 1 from t order by a",
   814  		output: "select /* simple order by */ 1 from t order by a asc",
   815  	}, {
   816  		input:  "select * from t where id = ((select a from t1 union select b from t2) order by a limit 1)",
   817  		output: "select * from t where id = (select a from t1 union select b from t2 order by a asc limit 1)",
   818  	}, {
   819  		input: "select /* order by asc */ 1 from t order by a asc",
   820  	}, {
   821  		input: "select /* order by desc */ 1 from t order by a desc",
   822  	}, {
   823  		input: "select /* order by null */ 1 from t order by null",
   824  	}, {
   825  		input: "select /* limit a */ 1 from t limit a",
   826  	}, {
   827  		input: "select /* limit a,b */ 1 from t limit a, b",
   828  	}, {
   829  		input:  "select /* binary unary */ a- -b from t",
   830  		output: "select /* binary unary */ a - -b from t",
   831  	}, {
   832  		input:  "select /* - - */ - -b from t",
   833  		output: "select /* - - */ - -b from t",
   834  	}, {
   835  		input:  "select /* binary binary */ binary  binary b from t",
   836  		output: "select /* binary binary */ convert(convert(b, binary), binary) from t",
   837  	}, {
   838  		input:  "select /* binary ~ */ binary  ~b from t",
   839  		output: "select /* binary ~ */ convert(~b, binary) from t",
   840  	}, {
   841  		input:  "select /* ~ binary */ ~ binary b from t",
   842  		output: "select /* ~ binary */ ~convert(b, binary) from t",
   843  	}, {
   844  		input: "select /* interval */ adddate('2008-01-02', interval 31 day) from t",
   845  	}, {
   846  		input: "select /* interval keyword */ adddate('2008-01-02', interval 1 year) from t",
   847  	}, {
   848  		input:  "select /* TIMESTAMPADD */ TIMESTAMPADD(MINUTE, 1, '2008-01-04') from t",
   849  		output: "select /* TIMESTAMPADD */ timestampadd(MINUTE, 1, '2008-01-04') from t",
   850  	}, {
   851  		input:  "select /* TIMESTAMPDIFF */ TIMESTAMPDIFF(MINUTE, '2008-01-02', '2008-01-04') from t",
   852  		output: "select /* TIMESTAMPDIFF */ timestampdiff(MINUTE, '2008-01-02', '2008-01-04') from t",
   853  	}, {
   854  		input:  "select DATE_ADD(MIN(FROM_UNIXTIME(1673444922)),interval -DAYOFWEEK(MIN(FROM_UNIXTIME(1673444922)))+1 DAY)",
   855  		output: "select DATE_ADD(min(FROM_UNIXTIME(1673444922)), interval (-DAYOFWEEK(min(FROM_UNIXTIME(1673444922))) + 1) DAY) from dual",
   856  	}, {
   857  		input:  "select '2020-01-01' + interval month(DATE_SUB(FROM_UNIXTIME(1234), interval 1 month))-1 month",
   858  		output: "select '2020-01-01' + interval (month(DATE_SUB(FROM_UNIXTIME(1234), interval 1 month)) - 1) month from dual",
   859  	}, {
   860  		input: "select /* dual */ 1 from dual",
   861  	}, {
   862  		input:  "select /* Dual */ 1 from Dual",
   863  		output: "select /* Dual */ 1 from dual",
   864  	}, {
   865  		input:  "select /* DUAL */ 1 from Dual",
   866  		output: "select /* DUAL */ 1 from dual",
   867  	}, {
   868  		input: "select /* column as bool in where */ a from t where b",
   869  	}, {
   870  		input: "select /* OR of columns in where */ * from t where a or b",
   871  	}, {
   872  		input: "select /* OR of mixed columns in where */ * from t where a = 5 or b and c is not null",
   873  	}, {
   874  		input:  "select /* OR in select columns */ (a or b) from t where c = 5",
   875  		output: "select /* OR in select columns */ a or b from t where c = 5",
   876  	}, {
   877  		input: "select /* XOR of columns in where */ * from t where a xor b",
   878  	}, {
   879  		input: "select /* XOR of mixed columns in where */ * from t where a = 5 xor b and c is not null",
   880  	}, {
   881  		input:  "select /* XOR in select columns */ (a xor b) from t where c = 5",
   882  		output: "select /* XOR in select columns */ a xor b from t where c = 5",
   883  	}, {
   884  		input:  "select /* XOR in select columns */ * from t where (1 xor c1 > 0)",
   885  		output: "select /* XOR in select columns */ * from t where 1 xor c1 > 0",
   886  	}, {
   887  		input: "select /* bool as select value */ a, true from t",
   888  	}, {
   889  		input: "select /* bool column in ON clause */ * from t join s on t.id = s.id and s.foo where t.bar",
   890  	}, {
   891  		input: "select /* bool in order by */ * from t order by a is null or b asc",
   892  	}, {
   893  		input: "select /* string in case statement */ if(max(case a when 'foo' then 1 else 0 end) = 1, 'foo', 'bar') as foobar from t",
   894  	}, {
   895  		input:  "/*!show databases*/",
   896  		output: "show databases",
   897  	}, {
   898  		input:  "select /*!40101 * from*/ t",
   899  		output: "select * from t",
   900  	}, {
   901  		input:  "select /*! * from*/ t",
   902  		output: "select * from t",
   903  	}, {
   904  		input:  "select /*!* from*/ t",
   905  		output: "select * from t",
   906  	}, {
   907  		input:  "select /*!401011 from*/ t",
   908  		output: "select 1 from t",
   909  	}, {
   910  		input: "select /* dual */ 1 from dual",
   911  	}, {
   912  		input:  "select * from (select 'tables') tables",
   913  		output: "select * from (select 'tables' from dual) as `tables`",
   914  	}, {
   915  		input: "insert /* simple */ into a values (1)",
   916  	}, {
   917  		input: "insert /* a.b */ into a.b values (1)",
   918  	}, {
   919  		input: "insert /* multi-value */ into a values (1, 2)",
   920  	}, {
   921  		input: "insert /* multi-value list */ into a values (1, 2), (3, 4)",
   922  	}, {
   923  		input: "insert /* no values */ into a values ()",
   924  	}, {
   925  		input:  "insert /* set */ into a set a = 1, b = 2",
   926  		output: "insert /* set */ into a(a, b) values (1, 2)",
   927  	}, {
   928  		input:  "insert /* set default */ into a set a = default, b = 2",
   929  		output: "insert /* set default */ into a(a, b) values (default, 2)",
   930  	}, {
   931  		input: "insert /* value expression list */ into a values (a + 1, 2 * 3)",
   932  	}, {
   933  		input: "insert /* default */ into a values (default, 2 * 3)",
   934  	}, {
   935  		input: "insert /* column list */ into a(a, b) values (1, 2)",
   936  	}, {
   937  		input: "insert into a(a, b) values (1, ifnull(null, default(b)))",
   938  	}, {
   939  		input: "insert /* qualified column list */ into a(a, b) values (1, 2)",
   940  	}, {
   941  		input:  "insert /* qualified columns */ into t (t.a, t.b) values (1, 2)",
   942  		output: "insert /* qualified columns */ into t(a, b) values (1, 2)",
   943  	}, {
   944  		input: "insert /* select */ into a select b, c from d",
   945  	}, {
   946  		input:  "insert /* it accepts columns with keyword action */ into a(action, b) values (1, 2)",
   947  		output: "insert /* it accepts columns with keyword action */ into a(`action`, b) values (1, 2)",
   948  	}, {
   949  		input:  "insert /* no cols & paren select */ into a (select * from t)",
   950  		output: "insert /* no cols & paren select */ into a select * from t",
   951  	}, {
   952  		input:  "insert /* cols & paren select */ into a(a, b, c) (select * from t)",
   953  		output: "insert /* cols & paren select */ into a(a, b, c) select * from t",
   954  	}, {
   955  		input:  "insert /* cols & union with paren select */ into a(b, c) (select d, e from f) union (select g from h)",
   956  		output: "insert /* cols & union with paren select */ into a(b, c) select d, e from f union select g from h",
   957  	}, {
   958  		input: "insert /* on duplicate */ into a values (1, 2) on duplicate key update b = func(a), c = d",
   959  	}, {
   960  		input: "insert /* bool in insert value */ into a values (1, true, false)",
   961  	}, {
   962  		input: "insert /* bool in on duplicate */ into a values (1, 2) on duplicate key update b = false, c = d",
   963  	}, {
   964  		input: "insert /* bool in on duplicate */ into a values (1, 2, 3) on duplicate key update b = values(b), c = d",
   965  	}, {
   966  		input: "insert /* bool in on duplicate */ into a values (1, 2, 3) on duplicate key update b = values(a.b), c = d",
   967  	}, {
   968  		input: "insert /* bool expression on duplicate */ into a values (1, 2) on duplicate key update b = func(a), c = a > d",
   969  	}, {
   970  		input: "insert into `user`(username, `status`) values ('Chuck', default(`status`))",
   971  	}, {
   972  		input:  "insert into user(format, tree, vitess) values ('Chuck', 42, 'Barry')",
   973  		output: "insert into `user`(`format`, `tree`, `vitess`) values ('Chuck', 42, 'Barry')",
   974  	}, {
   975  		input: "insert into customer() values ()",
   976  	}, {
   977  		input: "update /* simple */ a set b = 3",
   978  	}, {
   979  		input: "update /* a.b */ a.b set b = 3",
   980  	}, {
   981  		input: "update /* list */ a set b = 3, c = 4",
   982  	}, {
   983  		input: "update /* expression */ a set b = 3 + 4",
   984  	}, {
   985  		input: "update /* where */ a set b = 3 where a = b",
   986  	}, {
   987  		input: "update /* order */ a set b = 3 order by c desc",
   988  	}, {
   989  		input: "update /* limit */ a set b = 3 limit c",
   990  	}, {
   991  		input: "update /* bool in update */ a set b = true",
   992  	}, {
   993  		input: "update /* bool expr in update */ a set b = 5 > 2",
   994  	}, {
   995  		input: "update /* bool in update where */ a set b = 5 where c",
   996  	}, {
   997  		input: "update /* table qualifier */ a set a.b = 3",
   998  	}, {
   999  		input: "update /* table qualifier */ a set t.a.b = 3",
  1000  	}, {
  1001  		input:  "update /* table alias */ tt aa set aa.cc = 3",
  1002  		output: "update /* table alias */ tt as aa set aa.cc = 3",
  1003  	}, {
  1004  		input:  "update (select id from foo) subqalias set id = 4",
  1005  		output: "update (select id from foo) as subqalias set id = 4",
  1006  	}, {
  1007  		input:  "update foo f, bar b set f.id = b.id where b.name = 'test'",
  1008  		output: "update foo as f, bar as b set f.id = b.id where b.`name` = 'test'",
  1009  	}, {
  1010  		input:  "update foo f join bar b on f.name = b.name set f.id = b.id where b.name = 'test'",
  1011  		output: "update foo as f join bar as b on f.`name` = b.`name` set f.id = b.id where b.`name` = 'test'",
  1012  	}, {
  1013  		input: "update /* ignore */ ignore a set b = 3",
  1014  	}, {
  1015  		input: "delete /* simple */ from a",
  1016  	}, {
  1017  		input: "delete /* a.b */ from a.b",
  1018  	}, {
  1019  		input: "delete /* where */ from a where a = b",
  1020  	}, {
  1021  		input: "delete /* order */ from a order by b desc",
  1022  	}, {
  1023  		input: "delete /* limit */ from a limit b",
  1024  	}, {
  1025  		input:  "delete /* alias where */ t.* from a as t where t.id = 2",
  1026  		output: "delete /* alias where */ t from a as t where t.id = 2",
  1027  	}, {
  1028  		input:  "delete t.* from t, t1",
  1029  		output: "delete t from t, t1",
  1030  	}, {
  1031  		input:  "delete a from a join b on a.id = b.id where b.name = 'test'",
  1032  		output: "delete a from a join b on a.id = b.id where b.`name` = 'test'",
  1033  	}, {
  1034  		input:  "delete a, b from a, b where a.id = b.id and b.name = 'test'",
  1035  		output: "delete a, b from a, b where a.id = b.id and b.`name` = 'test'",
  1036  	}, {
  1037  		input: "delete /* simple */ ignore from a",
  1038  	}, {
  1039  		input: "delete ignore from a",
  1040  	}, {
  1041  		input: "delete /* limit */ ignore from a",
  1042  	}, {
  1043  		input:  "delete from a1, a2 using t1 as a1 inner join t2 as a2 where a1.id=a2.id",
  1044  		output: "delete a1, a2 from t1 as a1 join t2 as a2 where a1.id = a2.id",
  1045  	}, {
  1046  		input:  "set /* simple */ a = 3",
  1047  		output: "set /* simple */ @@a = 3",
  1048  	}, {
  1049  		input:  "set #simple\n b = 4",
  1050  		output: "set #simple\n @@b = 4",
  1051  	}, {
  1052  		input:  "set character_set_results = utf8",
  1053  		output: "set @@character_set_results = utf8",
  1054  	}, {
  1055  		input:  "set @@session.autocommit = true",
  1056  		output: "set @@autocommit = true",
  1057  	}, {
  1058  		input:  "set @@session.`autocommit` = true",
  1059  		output: "set @@autocommit = true",
  1060  	}, {
  1061  		input:  "set @@session.autocommit = ON",
  1062  		output: "set @@autocommit = 'on'",
  1063  	}, {
  1064  		input:  "set @@session.autocommit= OFF",
  1065  		output: "set @@autocommit = 'off'",
  1066  	}, {
  1067  		input:  "set autocommit = on",
  1068  		output: "set @@autocommit = 'on'",
  1069  	}, {
  1070  		input:  "set autocommit = off",
  1071  		output: "set @@autocommit = 'off'",
  1072  	}, {
  1073  		input:  "set names utf8 collate foo",
  1074  		output: "set names 'utf8'",
  1075  	}, {
  1076  		input:  "set names utf8 collate 'foo'",
  1077  		output: "set names 'utf8'",
  1078  	}, {
  1079  		input:  "set character set utf8",
  1080  		output: "set charset 'utf8'",
  1081  	}, {
  1082  		input:  "set character set 'utf8'",
  1083  		output: "set charset 'utf8'",
  1084  	}, {
  1085  		input:  "set s = 1--4",
  1086  		output: "set @@s = 1 - -4",
  1087  	}, {
  1088  		input:  "set character set \"utf8\"",
  1089  		output: "set charset 'utf8'",
  1090  	}, {
  1091  		input:  "set charset default",
  1092  		output: "set charset default",
  1093  	}, {
  1094  		input:  "set session wait_timeout = 3600",
  1095  		output: "set @@wait_timeout = 3600",
  1096  	}, {
  1097  		input:  "set session wait_timeout = 3600, session autocommit = off",
  1098  		output: "set @@wait_timeout = 3600, @@autocommit = 'off'",
  1099  	}, {
  1100  		input:  "set session wait_timeout = 3600, @@global.autocommit = off",
  1101  		output: "set @@wait_timeout = 3600, @@global.autocommit = 'off'",
  1102  	}, {
  1103  		input:  "set local wait_timeout = 3600",
  1104  		output: "set @@wait_timeout = 3600",
  1105  	}, {
  1106  		input:  "set @@local.wait_timeout = 3600",
  1107  		output: "set @@wait_timeout = 3600",
  1108  	}, {
  1109  		input:  "set /* list */ a = 3, b = 4",
  1110  		output: "set /* list */ @@a = 3, @@b = 4",
  1111  	}, {
  1112  		input:  "set /* mixed list */ a = 3, names 'utf8', charset 'ascii', b = 4",
  1113  		output: "set /* mixed list */ @@a = 3, names 'utf8', charset 'ascii', @@b = 4",
  1114  	}, {
  1115  		input:  "set session transaction isolation level repeatable read",
  1116  		output: "set @@session.transaction_isolation = 'repeatable-read'",
  1117  	}, {
  1118  		input:  "set transaction isolation level repeatable read",
  1119  		output: "set @@transaction_isolation = 'repeatable-read'",
  1120  	}, {
  1121  		input:  "set global transaction isolation level repeatable read",
  1122  		output: "set @@global.transaction_isolation = 'repeatable-read'",
  1123  	}, {
  1124  		input:  "set transaction isolation level repeatable read",
  1125  		output: "set @@transaction_isolation = 'repeatable-read'",
  1126  	}, {
  1127  		input:  "set transaction isolation level read committed",
  1128  		output: "set @@transaction_isolation = 'read-committed'",
  1129  	}, {
  1130  		input:  "set transaction isolation level read uncommitted",
  1131  		output: "set @@transaction_isolation = 'read-uncommitted'",
  1132  	}, {
  1133  		input:  "set transaction isolation level serializable",
  1134  		output: "set @@transaction_isolation = 'serializable'",
  1135  	}, {
  1136  		input:  "set transaction read write",
  1137  		output: "set @@transaction_read_only = 'off'",
  1138  	}, {
  1139  		input:  "set transaction read only",
  1140  		output: "set @@transaction_read_only = 'on'",
  1141  	}, {
  1142  		input:  "set session transaction read only, isolation level serializable",
  1143  		output: "set @@session.transaction_read_only = 'on', @@session.transaction_isolation = 'serializable'",
  1144  	}, {
  1145  		input:  "set tx_read_only = 1",
  1146  		output: "set @@tx_read_only = 1",
  1147  	}, {
  1148  		input:  "set tx_read_only = 0",
  1149  		output: "set @@tx_read_only = 0",
  1150  	}, {
  1151  		input:  "set transaction_read_only = 1",
  1152  		output: "set @@session.transaction_read_only = 1",
  1153  	}, {
  1154  		input:  "set transaction_read_only = 0",
  1155  		output: "set @@session.transaction_read_only = 0",
  1156  	}, {
  1157  		input: "set @@transaction_read_only = 1",
  1158  	}, {
  1159  		input: "set @@transaction_isolation = 'read-committed'",
  1160  	}, {
  1161  		input:  "set tx_isolation = 'repeatable read'",
  1162  		output: "set @@tx_isolation = 'repeatable read'",
  1163  	}, {
  1164  		input:  "set tx_isolation = 'read committed'",
  1165  		output: "set @@tx_isolation = 'read committed'",
  1166  	}, {
  1167  		input:  "set tx_isolation = 'read uncommitted'",
  1168  		output: "set @@tx_isolation = 'read uncommitted'",
  1169  	}, {
  1170  		input:  "set tx_isolation = 'serializable'",
  1171  		output: "set @@tx_isolation = 'serializable'",
  1172  	}, {
  1173  		input:  "set sql_safe_updates = 0",
  1174  		output: "set @@sql_safe_updates = 0",
  1175  	}, {
  1176  		input:  "set sql_safe_updates = 1",
  1177  		output: "set @@sql_safe_updates = 1",
  1178  	}, {
  1179  		input: "set @variable = 42",
  1180  	}, {
  1181  		input:  "set @period.variable = 42",
  1182  		output: "set @`period.variable` = 42",
  1183  	}, {
  1184  		input:  "set S= +++-++-+(4+1)",
  1185  		output: "set @@S = - -(4 + 1)",
  1186  	}, {
  1187  		input:  "set S= +- - - - -(4+1)",
  1188  		output: "set @@S = - - - - -(4 + 1)",
  1189  	}, {
  1190  		input:  "alter table a add foo int references b (a) on delete restrict first",
  1191  		output: "alter table a add column foo int references b (a) on delete restrict first",
  1192  	}, {
  1193  		input:  "alter table a lock default, lock = none, lock shared, lock exclusive",
  1194  		output: "alter table a lock default, lock none, lock shared, lock exclusive",
  1195  	}, {
  1196  		input:  "alter table a alter x set default NULL, alter column x2 set default 's', alter x3 drop default",
  1197  		output: "alter table a alter column x set default null, alter column x2 set default 's', alter column x3 drop default",
  1198  	}, {
  1199  		input: "alter table a alter column x set visible, alter column x2 set invisible",
  1200  	}, {
  1201  		input: "alter table a alter index x visible, alter index x2 invisible",
  1202  	}, {
  1203  		input: "alter table a add spatial key foo (column1)",
  1204  	}, {
  1205  		input: "alter table a add fulltext key foo (column1), order by a, b, c",
  1206  	}, {
  1207  		input: "alter table a add unique key foo (column1)",
  1208  	}, {
  1209  		input: "alter /*vt+ strategy=online */ table a add unique key foo (column1)",
  1210  	}, {
  1211  		input: "alter table a change column s foo int default 1 after x",
  1212  	}, {
  1213  		input: "alter table a modify column foo int default 1 first",
  1214  	}, {
  1215  		input: "alter table a rename column foo to bar",
  1216  	}, {
  1217  		input:  "alter table a add foo varchar(255) generated always as (concat(bar, ' ', baz)) stored",
  1218  		output: "alter table a add column foo varchar(255) as (concat(bar, ' ', baz)) stored",
  1219  	}, {
  1220  		input:  "alter table a add foo varchar(255) generated always as (concat(bar, ' ', baz))",
  1221  		output: "alter table a add column foo varchar(255) as (concat(bar, ' ', baz)) virtual",
  1222  	}, {
  1223  		input:  "alter table a add foo varchar(255) generated always as (concat(bar, ' ', baz)) null",
  1224  		output: "alter table a add column foo varchar(255) as (concat(bar, ' ', baz)) virtual null",
  1225  	}, {
  1226  		input:  "alter table a add foo varchar(255) generated always as (concat(bar, ' ', baz)) not null",
  1227  		output: "alter table a add column foo varchar(255) as (concat(bar, ' ', baz)) virtual not null",
  1228  	}, {
  1229  		input:  "alter table a change column s foo varchar(255) generated always as (concat(bar, ' ', baz)) stored",
  1230  		output: "alter table a change column s foo varchar(255) as (concat(bar, ' ', baz)) stored",
  1231  	}, {
  1232  		input:  "alter table a modify column foo varchar(255) generated always as (concat(bar, ' ', baz))",
  1233  		output: "alter table a modify column foo varchar(255) as (concat(bar, ' ', baz)) virtual",
  1234  	}, {
  1235  		input:  "alter table a character set utf32 collate = 'utf'",
  1236  		output: "alter table a charset utf32 collate utf",
  1237  	}, {
  1238  		input: "alter table a convert to character set utf32",
  1239  	}, {
  1240  		input: "alter table `By` add column foo int, algorithm = default",
  1241  	}, {
  1242  		input: "alter table `By` add column foo int, algorithm = copy",
  1243  	}, {
  1244  		input: "alter table `By` add column foo int, algorithm = inplace",
  1245  	}, {
  1246  		input: "alter table `By` add column foo int, algorithm = INPLACE",
  1247  	}, {
  1248  		input: "alter table `By` add column foo int, algorithm = instant",
  1249  	}, {
  1250  		input: "alter table a rename b",
  1251  	}, {
  1252  		input: "alter table `By` rename `bY`",
  1253  	}, {
  1254  		input:  "alter table a rename to b",
  1255  		output: "alter table a rename b",
  1256  	}, {
  1257  		input:  "alter table a rename as b",
  1258  		output: "alter table a rename b",
  1259  	}, {
  1260  		input: "alter table a rename index foo to bar, with validation",
  1261  	}, {
  1262  		input:  "alter table a rename key foo to bar",
  1263  		output: "alter table a rename index foo to bar",
  1264  	}, {
  1265  		input: "alter table e auto_increment 20",
  1266  	}, {
  1267  		input:  "alter table e character set = 'ascii'",
  1268  		output: "alter table e charset ascii",
  1269  	}, {
  1270  		input: "alter table e enable keys, discard tablespace, force",
  1271  	}, {
  1272  		input:  "alter table e default character set = 'ascii'",
  1273  		output: "alter table e charset ascii",
  1274  	}, {
  1275  		input: "alter table e comment 'hello' remove partitioning",
  1276  	}, {
  1277  		input:  "alter table a reorganize partition b into (partition c values less than (?), partition d values less than (maxvalue))",
  1278  		output: "alter table a reorganize partition b into (partition c values less than (:v1), partition d values less than maxvalue)",
  1279  	}, {
  1280  		input: "alter table a algorithm = default, lock none, add partition (partition d values less than maxvalue)",
  1281  	}, {
  1282  		input: "alter table a discard partition all tablespace",
  1283  	}, {
  1284  		input: "alter table a import partition a, b, v tablespace",
  1285  	}, {
  1286  		input: "alter table a truncate partition a, b, v",
  1287  	}, {
  1288  		input: "alter table a coalesce partition 7",
  1289  	}, {
  1290  		input: "alter table a exchange partition a with table t without validation",
  1291  	}, {
  1292  		input: "alter table a analyze partition all",
  1293  	}, {
  1294  		input: "alter table a analyze partition a, v",
  1295  	}, {
  1296  		input: "alter table a check partition all",
  1297  	}, {
  1298  		input: "alter table a check partition a, v",
  1299  	}, {
  1300  		input: "alter table a optimize partition all",
  1301  	}, {
  1302  		input: "alter table a optimize partition a, v",
  1303  	}, {
  1304  		input: "alter table a rebuild partition all",
  1305  	}, {
  1306  		input: "alter table a rebuild partition a, v",
  1307  	}, {
  1308  		input: "alter table a repair partition all",
  1309  	}, {
  1310  		input: "alter table a repair partition a, v",
  1311  	}, {
  1312  		input: "alter table a remove partitioning",
  1313  	}, {
  1314  		input: "alter table a upgrade partitioning",
  1315  	}, {
  1316  		input:  "alter table t2 add primary key `zzz` (id)",
  1317  		output: "alter table t2 add primary key (id)",
  1318  	}, {
  1319  		input: "alter table a \npartition by hash (id) partitions 4",
  1320  	}, {
  1321  		input: "alter table a \npartition by range (id)\n(partition p0 values less than (10),\n partition p1 values less than maxvalue)",
  1322  	}, {
  1323  		input:      "create database a garbage values",
  1324  		output:     "create database a",
  1325  		partialDDL: true,
  1326  	}, {
  1327  		input: "alter table `Post With Space` drop foreign key `Post With Space_ibfk_1`",
  1328  	}, {
  1329  		input: "alter table a add column (id int, id2 char(23))",
  1330  	}, {
  1331  		input: "alter table a add index idx (id)",
  1332  	}, {
  1333  		input: "alter table a add fulltext index idx (id)",
  1334  	}, {
  1335  		input: "alter table a add spatial index idx (id)",
  1336  	}, {
  1337  		input: "alter table a add fulltext index idx (id)",
  1338  	}, {
  1339  		input: "alter table a add foreign key (id) references f (id)",
  1340  	}, {
  1341  		input: "alter table a add foreign key the_idx(id) references f (id)",
  1342  	}, {
  1343  		input: "alter table a add primary key (id)",
  1344  	}, {
  1345  		input: "alter table a add constraint b primary key (id)",
  1346  	}, {
  1347  		input: "alter table a add constraint b primary key (id)",
  1348  	}, {
  1349  		input: "alter table a add constraint b unique key (id)",
  1350  	}, {
  1351  		input:  "alter table t add column iii int signed not null",
  1352  		output: "alter table t add column iii int not null",
  1353  	}, {
  1354  		input: "alter table t add column iii int unsigned not null",
  1355  	}, {
  1356  		input:  "alter table a add constraint b unique c (id)",
  1357  		output: "alter table a add constraint b unique key c (id)",
  1358  	}, {
  1359  		input:  "alter table a add constraint check (id)",
  1360  		output: "alter table a add check (id)",
  1361  	}, {
  1362  		input: "alter table a add constraint c check (id)",
  1363  	}, {
  1364  		input:  "alter table a add id int",
  1365  		output: "alter table a add column id int",
  1366  	}, {
  1367  		input: "alter table a add column id int first",
  1368  	}, {
  1369  		input: "alter table a add column id int after id2",
  1370  	}, {
  1371  		input: "alter table a drop column id",
  1372  	}, {
  1373  		input: "alter table a drop partition p2712, p123",
  1374  	}, {
  1375  		input:  "alter table a drop index idx",
  1376  		output: "alter table a drop key idx",
  1377  	}, {
  1378  		input: "alter table a add check (ch_1) not enforced",
  1379  	}, {
  1380  		input: "alter table a alter check ch_1 enforced",
  1381  	}, {
  1382  		input: "alter table a alter check ch_1 not enforced",
  1383  	}, {
  1384  		input: "alter table a drop check ch_1",
  1385  	}, {
  1386  		input:  "alter table a drop constraint ch_1",
  1387  		output: "alter table a drop check ch_1",
  1388  	}, {
  1389  		input: "alter table a drop foreign key kx",
  1390  	}, {
  1391  		input: "alter table a drop primary key",
  1392  	}, {
  1393  		input:  "alter table a drop id",
  1394  		output: "alter table a drop column id",
  1395  	}, {
  1396  		input:  "ALTER TABLE `product115s` CHANGE `part_number` `part_number` varchar(255) DEFAULT '0' NOT NULL",
  1397  		output: "alter table product115s change column part_number part_number varchar(255) not null default '0'",
  1398  	}, {
  1399  		input:  "ALTER TABLE distributors ADD CONSTRAINT zipchk CHECK (char_length(zipcode) = 5)",
  1400  		output: "alter table distributors add constraint zipchk check (char_length(zipcode) = 5)",
  1401  	}, {
  1402  		input: "alter database character set geostd8",
  1403  	}, {
  1404  		input: "alter database d character set geostd8",
  1405  	}, {
  1406  		input: "alter database d default collate 'utf8_bin'",
  1407  	}, {
  1408  		input: "alter database default collate 'utf8_bin'",
  1409  	}, {
  1410  		input: "alter database d upgrade data directory name",
  1411  	}, {
  1412  		input:  "alter database d collate = 'utf8_bin'",
  1413  		output: "alter database d collate 'utf8_bin'",
  1414  	}, {
  1415  		input:  "alter schema d default character set = geostd8",
  1416  		output: "alter database d default character set geostd8",
  1417  	}, {
  1418  		input:  "alter schema d character set = geostd8",
  1419  		output: "alter database d character set geostd8",
  1420  	}, {
  1421  		input:  "alter schema d default collate = 'utf8_bin'",
  1422  		output: "alter database d default collate 'utf8_bin'",
  1423  	}, {
  1424  		input:  "alter schema d collate = 'utf8_bin' character set = geostd8 character set = geostd8",
  1425  		output: "alter database d collate 'utf8_bin' character set geostd8 character set geostd8",
  1426  	}, {
  1427  		input:      "create table a",
  1428  		partialDDL: true,
  1429  	}, {
  1430  		input:      "CREATE TABLE a",
  1431  		output:     "create table a",
  1432  		partialDDL: true,
  1433  	}, {
  1434  		input:      "create table `a`",
  1435  		output:     "create table a",
  1436  		partialDDL: true,
  1437  	}, {
  1438  		input:  "create table function_default (x varchar(25) default (trim(' check ')))",
  1439  		output: "create table function_default (\n\tx varchar(25) default (trim(' check '))\n)",
  1440  	}, {
  1441  		input:  "create table function_default (x varchar(25) default (((trim(' check ')))))",
  1442  		output: "create table function_default (\n\tx varchar(25) default (trim(' check '))\n)",
  1443  	}, {
  1444  		input:  "create table function_default3 (x bool DEFAULT (true AND false));",
  1445  		output: "create table function_default3 (\n\tx bool default (true and false)\n)",
  1446  	}, {
  1447  		input:  "create table function_default (x bool DEFAULT true);",
  1448  		output: "create table function_default (\n\tx bool default true\n)",
  1449  	}, {
  1450  		input:  "create table a (\n\t`a` int\n)",
  1451  		output: "create table a (\n\ta int\n)",
  1452  	}, {
  1453  		input: "create table `by` (\n\t`by` char\n)",
  1454  	}, {
  1455  		input: "create table test (\n\t__year year(4)\n)",
  1456  	}, {
  1457  		input: "create table a (\n\ta int not null\n)",
  1458  	}, {
  1459  		input: "create /*vt+ strategy=online */ table a (\n\ta int not null\n)",
  1460  	}, {
  1461  		input: "create table a (\n\ta int not null default 0\n)",
  1462  	}, {
  1463  		input:  "create table a (\n\ta float not null default -1\n)",
  1464  		output: "create table a (\n\ta float not null default -1\n)",
  1465  	}, {
  1466  		input:  "create table a (\n\ta float not null default -2.1\n)",
  1467  		output: "create table a (\n\ta float not null default -2.1\n)",
  1468  	}, {
  1469  		input:  "create table a (\n\ta float(24) not null default -1\n)",
  1470  		output: "create table a (\n\ta float(24) not null default -1\n)",
  1471  	}, {
  1472  		input:  "create table a (\n\ta float(24,10) not null default -1\n)",
  1473  		output: "create table a (\n\ta float(24,10) not null default -1\n)",
  1474  	}, {
  1475  		input:  "create table a (\n\ta float4 not null default -1\n)",
  1476  		output: "create table a (\n\ta float4 not null default -1\n)",
  1477  	}, {
  1478  		input:  "create table a (\n\ta float8 not null default -1\n)",
  1479  		output: "create table a (\n\ta float8 not null default -1\n)",
  1480  	}, {
  1481  		input:  "create table a (a int not null default 0, primary key(a))",
  1482  		output: "create table a (\n\ta int not null default 0,\n\tprimary key (a)\n)",
  1483  	}, {
  1484  		input:  "create table a (`a column` int)",
  1485  		output: "create table a (\n\t`a column` int\n)",
  1486  	}, {
  1487  		input: "create table a (\n\ta varchar(32) not null default ''\n)",
  1488  	}, {
  1489  		input:  "create table if not exists a (\n\t`a` int\n)",
  1490  		output: "create table if not exists a (\n\ta int\n)",
  1491  	}, {
  1492  		input:      "create table a ignore me this is garbage",
  1493  		output:     "create table a",
  1494  		partialDDL: true,
  1495  	}, {
  1496  		input:      "create table a (a int, b char, c garbage)",
  1497  		output:     "create table a",
  1498  		partialDDL: true,
  1499  	}, {
  1500  		input:  "create table a (b1 bool not null primary key, b2 boolean not null)",
  1501  		output: "create table a (\n\tb1 bool not null primary key,\n\tb2 boolean not null\n)",
  1502  	}, {
  1503  		input:  "create table a (b1 bool NOT NULL PRIMARY KEY, b2 boolean not null references b (a) on delete restrict, KEY b2_idx(b))",
  1504  		output: "create table a (\n\tb1 bool not null primary key,\n\tb2 boolean not null references b (a) on delete restrict,\n\tKEY b2_idx (b)\n)",
  1505  	}, {
  1506  		input: "create temporary table a (\n\tid bigint\n)",
  1507  	}, {
  1508  		input:  "CREATE TABLE pkai (id INT PRIMARY KEY AUTO_INCREMENT);",
  1509  		output: "create table pkai (\n\tid INT auto_increment primary key\n)",
  1510  	}, {
  1511  		input:  "CREATE TABLE aipk (id INT AUTO_INCREMENT PRIMARY KEY)",
  1512  		output: "create table aipk (\n\tid INT auto_increment primary key\n)",
  1513  	}, {
  1514  		// This test case is added because MySQL supports this behaviour.
  1515  		// It allows the user to specify null and not null multiple times.
  1516  		// The last value specified is used.
  1517  		input:  "create table foo (f timestamp null not null , g timestamp not null null)",
  1518  		output: "create table foo (\n\tf timestamp not null,\n\tg timestamp null\n)",
  1519  	}, {
  1520  		// Tests unicode character §
  1521  		input: "create table invalid_enum_value_name (\n\there_be_enum enum('$§!') default null\n)",
  1522  	}, {
  1523  		input:  "create table t (id int) partition by hash (id) partitions 3",
  1524  		output: "create table t (\n\tid int\n)\npartition by hash (id) partitions 3",
  1525  	}, {
  1526  		input:  "create table t (hired date) partition by linear hash (year(hired)) partitions 4",
  1527  		output: "create table t (\n\thired date\n)\npartition by linear hash (year(hired)) partitions 4",
  1528  	}, {
  1529  		input:  "create table t (id int) partition by key (id) partitions 2",
  1530  		output: "create table t (\n\tid int\n)\npartition by key (id) partitions 2",
  1531  	}, {
  1532  		input:  "create table t (id int, primary key(id)) partition by key () partitions 2",
  1533  		output: "create table t (\n\tid int,\n\tprimary key (id)\n)\npartition by key () partitions 2",
  1534  	}, {
  1535  		input:  "create table t (id int) partition by key algorithm = 1 (id)",
  1536  		output: "create table t (\n\tid int\n)\npartition by key algorithm = 1 (id)",
  1537  	}, {
  1538  		input:  "create table t (id int not null) partition by linear key (id) partitions 5",
  1539  		output: "create table t (\n\tid int not null\n)\npartition by linear key (id) partitions 5",
  1540  	}, {
  1541  		input:  "create table t (id int) partition by list (id) (partition p0 values in (1, 4, 7))",
  1542  		output: "create table t (\n\tid int\n)\npartition by list (id)\n(partition p0 values in (1, 4, 7))",
  1543  	}, {
  1544  		input:  "create table t (renewal date) partition by range columns (renewal) (partition p0 values less than ('2021-08-27'))",
  1545  		output: "create table t (\n\trenewal date\n)\npartition by range columns (renewal)\n(partition p0 values less than ('2021-08-27'))",
  1546  	}, {
  1547  		input:  "create table t (pur date) partition by range (year(pur)) subpartition by hash (to_days(pur)) subpartitions 2 (partition p0 values less than (2015), partition p2 values less than (2018))",
  1548  		output: "create table t (\n\tpur date\n)\npartition by range (year(pur)) subpartition by hash (to_days(pur)) subpartitions 2\n(partition p0 values less than (2015),\n partition p2 values less than (2018))",
  1549  	}, {
  1550  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1551  		input:                "alter vschema create vindex hash_vdx using `hash`",
  1552  		ignoreNormalizerTest: true,
  1553  	}, {
  1554  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1555  		input:                "alter vschema create vindex keyspace.hash_vdx using `hash`",
  1556  		ignoreNormalizerTest: true,
  1557  	}, {
  1558  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1559  		input:                "alter vschema create vindex lookup_vdx using lookup with owner=user, table=name_user_idx, from=name, to=user_id",
  1560  		ignoreNormalizerTest: true,
  1561  	}, {
  1562  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1563  		input:                "alter vschema create vindex xyz_vdx using xyz with param1=hello, param2='world', param3=123",
  1564  		ignoreNormalizerTest: true,
  1565  	}, {
  1566  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1567  		input:                "alter vschema drop vindex hash_vdx",
  1568  		ignoreNormalizerTest: true,
  1569  	}, {
  1570  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1571  		input:                "alter vschema drop vindex ks.hash_vdx",
  1572  		ignoreNormalizerTest: true,
  1573  	}, {
  1574  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1575  		input:                "alter vschema add table a",
  1576  		ignoreNormalizerTest: true,
  1577  	}, {
  1578  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1579  		input:                "alter vschema add table ks.a",
  1580  		ignoreNormalizerTest: true,
  1581  	}, {
  1582  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1583  		input:                "alter vschema add sequence a_seq",
  1584  		ignoreNormalizerTest: true,
  1585  	}, {
  1586  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1587  		input:                "alter vschema add sequence ks.a_seq",
  1588  		ignoreNormalizerTest: true,
  1589  	}, {
  1590  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1591  		input:                "alter vschema on a add auto_increment id using a_seq",
  1592  		ignoreNormalizerTest: true,
  1593  	}, {
  1594  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1595  		input:                "alter vschema on ks.a add auto_increment id using a_seq",
  1596  		ignoreNormalizerTest: true,
  1597  	}, {
  1598  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1599  		input:                "alter vschema drop table a",
  1600  		ignoreNormalizerTest: true,
  1601  	}, {
  1602  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1603  		input:                "alter vschema drop table ks.a",
  1604  		ignoreNormalizerTest: true,
  1605  	}, {
  1606  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1607  		input:                "alter vschema on a add vindex `hash` (id)",
  1608  		ignoreNormalizerTest: true,
  1609  	}, {
  1610  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1611  		input:                "alter vschema on ks.a add vindex `hash` (id)",
  1612  		ignoreNormalizerTest: true,
  1613  	}, {
  1614  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1615  		input:                "alter vschema on a add vindex `hash` (`id`)",
  1616  		output:               "alter vschema on a add vindex `hash` (id)",
  1617  		ignoreNormalizerTest: true,
  1618  	}, {
  1619  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1620  		input:                "alter vschema on `ks`.a add vindex `hash` (`id`)",
  1621  		output:               "alter vschema on ks.a add vindex `hash` (id)",
  1622  		ignoreNormalizerTest: true,
  1623  	}, {
  1624  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1625  		input:                "alter vschema on a add vindex hash (id) using `hash`",
  1626  		output:               "alter vschema on a add vindex `hash` (id) using `hash`",
  1627  		ignoreNormalizerTest: true,
  1628  	}, {
  1629  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1630  		input:                "alter vschema on a add vindex `add` (`add`)",
  1631  		ignoreNormalizerTest: true,
  1632  	}, {
  1633  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1634  		input:                "alter vschema on a add vindex `hash` (id) using `hash`",
  1635  		ignoreNormalizerTest: true,
  1636  	}, {
  1637  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1638  		input:                "alter vschema on a add vindex hash (id) using `hash`",
  1639  		output:               "alter vschema on a add vindex `hash` (id) using `hash`",
  1640  		ignoreNormalizerTest: true,
  1641  	}, {
  1642  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1643  		input:                "alter vschema on user add vindex name_lookup_vdx (name) using lookup_hash with owner=user, table=name_user_idx, from=name, to=user_id",
  1644  		output:               "alter vschema on `user` add vindex name_lookup_vdx (`name`) using lookup_hash with owner=user, table=name_user_idx, from=name, to=user_id",
  1645  		ignoreNormalizerTest: true,
  1646  	}, {
  1647  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1648  		input:                "alter vschema on user2 add vindex name_lastname_lookup_vdx (name,lastname) using lookup with owner=`user`, table=`name_lastname_keyspace_id_map`, from=`name,lastname`, to=`keyspace_id`",
  1649  		output:               "alter vschema on user2 add vindex name_lastname_lookup_vdx (`name`, lastname) using lookup with owner=user, table=name_lastname_keyspace_id_map, from=name,lastname, to=keyspace_id",
  1650  		ignoreNormalizerTest: true,
  1651  	}, {
  1652  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1653  		input:                "alter vschema on a drop vindex `hash`",
  1654  		ignoreNormalizerTest: true,
  1655  	}, {
  1656  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1657  		input:                "alter vschema on ks.a drop vindex `hash`",
  1658  		ignoreNormalizerTest: true,
  1659  	}, {
  1660  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1661  		input:                "alter vschema on a drop vindex `hash`",
  1662  		output:               "alter vschema on a drop vindex `hash`",
  1663  		ignoreNormalizerTest: true,
  1664  	}, {
  1665  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1666  		input:                "alter vschema on a drop vindex hash",
  1667  		output:               "alter vschema on a drop vindex `hash`",
  1668  		ignoreNormalizerTest: true,
  1669  	}, {
  1670  		// Alter Vschema does not reach the vttablets, so we don't need to run the normalizer test
  1671  		input:                "alter vschema on a drop vindex `add`",
  1672  		output:               "alter vschema on a drop vindex `add`",
  1673  		ignoreNormalizerTest: true,
  1674  	}, {
  1675  		input:  "create index a on b (col1)",
  1676  		output: "alter table b add index a (col1)",
  1677  	}, {
  1678  		input:  "create unique index a on b (col1)",
  1679  		output: "alter table b add unique index a (col1)",
  1680  	}, {
  1681  		input:  "create unique index a using foo on b (col1 desc)",
  1682  		output: "alter table b add unique index a (col1 desc) using foo",
  1683  	}, {
  1684  		input:  "create fulltext index a on b (col1) with parser a",
  1685  		output: "alter table b add fulltext index a (col1) with parser a",
  1686  	}, {
  1687  		input:  "create spatial index a on b (col1)",
  1688  		output: "alter table b add spatial index a (col1)",
  1689  	}, {
  1690  		input:  "create fulltext index a on b (col1) key_block_size=12 with parser a comment 'string' algorithm inplace lock none",
  1691  		output: "alter table b add fulltext index a (col1) key_block_size 12 with parser a comment 'string', algorithm = inplace, lock none",
  1692  	}, {
  1693  		input:  "create index a on b ((col1 + col2), (col1*col2))",
  1694  		output: "alter table b add index a ((col1 + col2), (col1 * col2))",
  1695  	}, {
  1696  		input:  "create fulltext index b using btree on A (col1 desc, col2) algorithm = inplace lock = none",
  1697  		output: "alter table A add fulltext index b (col1 desc, col2) using btree, algorithm = inplace, lock none",
  1698  	}, {
  1699  		input: "create algorithm = merge sql security definer view a as select * from e",
  1700  	}, {
  1701  		input: "create view ks.a as select * from e",
  1702  	}, {
  1703  		input:  "create algorithm = merge sql security definer view a (b,c,d) as select * from e",
  1704  		output: "create algorithm = merge sql security definer view a(b, c, d) as select * from e",
  1705  	}, {
  1706  		input:  "create algorithm = merge sql security definer view a (b,c,d) as select * from e with cascaded check option",
  1707  		output: "create algorithm = merge sql security definer view a(b, c, d) as select * from e with cascaded check option",
  1708  	}, {
  1709  		input:  "create algorithm = temptable definer = a@b.c.d view a(b,c,d) as select * from e with local check option",
  1710  		output: "create algorithm = temptable definer = a@`b.c.d` view a(b, c, d) as select * from e with local check option",
  1711  	}, {
  1712  		input:  "create algorithm = temptable definer = a@b view a(b,c,d) as select * from e with local check option",
  1713  		output: "create algorithm = temptable definer = a@b view a(b, c, d) as select * from e with local check option",
  1714  	}, {
  1715  		input:  "create algorithm = temptable definer = 'create'@b view a(b,c,d) as select * from e with local check option",
  1716  		output: "create algorithm = temptable definer = 'create'@b view a(b, c, d) as select * from e with local check option",
  1717  	}, {
  1718  		input:  "create algorithm = temptable definer = a@'create' view a(b,c,d) as select * from e with local check option",
  1719  		output: "create algorithm = temptable definer = a@'create' view a(b, c, d) as select * from e with local check option",
  1720  	}, {
  1721  		input:  "create algorithm = temptable definer = 'a' view a(b,c,d) as select * from e with local check option",
  1722  		output: "create algorithm = temptable definer = 'a' view a(b, c, d) as select * from e with local check option",
  1723  	}, {
  1724  		input:  "create algorithm = temptable definer = 'select'@'create' view a(b,c,d) as select * from e with local check option",
  1725  		output: "create algorithm = temptable definer = 'select'@'create' view a(b, c, d) as select * from e with local check option",
  1726  	}, {
  1727  		input:  "create algorithm = temptable definer = `create`@b view a(b,c,d) as select * from e with local check option",
  1728  		output: "create algorithm = temptable definer = `create`@b view a(b, c, d) as select * from e with local check option",
  1729  	}, {
  1730  		input:  "create algorithm = temptable definer = a@`create` view a(b,c,d) as select * from e with local check option",
  1731  		output: "create algorithm = temptable definer = a@`create` view a(b, c, d) as select * from e with local check option",
  1732  	}, {
  1733  		input:  "create algorithm = temptable definer = `select`@`create` view a(b,c,d) as select * from e with local check option",
  1734  		output: "create algorithm = temptable definer = `select`@`create` view a(b, c, d) as select * from e with local check option",
  1735  	}, {
  1736  		input:  "create or replace algorithm = temptable definer = a@b.c.d sql security definer view a(b,c,d) as select * from e with local check option",
  1737  		output: "create or replace algorithm = temptable definer = a@`b.c.d` sql security definer view a(b, c, d) as select * from e with local check option",
  1738  	}, {
  1739  		input:  "create algorithm = undefined definer = `msandbox`@`localhost` sql security definer view `v3` as select `t`.`id` as `id` from `t`",
  1740  		output: "create algorithm = undefined definer = msandbox@localhost sql security definer view v3 as select t.id as id from t",
  1741  	}, {
  1742  		input:  "create definer = 'sa'@b.c.d view a(b,c,d) as select * from e",
  1743  		output: "create definer = 'sa'@`b.c.d` view a(b, c, d) as select * from e",
  1744  	}, {
  1745  		input: "create /*vt+ strategy=online */ or replace view v as select a, b, c from t",
  1746  	}, {
  1747  		input: "alter view a as select * from t",
  1748  	}, {
  1749  		input: "alter /*vt+ strategy=online */ view a as select * from t",
  1750  	}, {
  1751  		input: "alter algorithm = merge definer = m@`172.0.1.01` sql security definer view a as select * from t with local check option",
  1752  	}, {
  1753  		input:  "rename table a to b",
  1754  		output: "rename table a to b",
  1755  	}, {
  1756  		input:  "rename table x.a to b, b to c",
  1757  		output: "rename table x.a to b, b to c",
  1758  	}, {
  1759  		input:  "drop view a,B,c",
  1760  		output: "drop view a, b, c",
  1761  	}, {
  1762  		input: "drop /*vt+ strategy=online */ view if exists v",
  1763  	}, {
  1764  		input: "drop table a",
  1765  	}, {
  1766  		input: "drop /*vt+ strategy=online */ table if exists a",
  1767  	}, {
  1768  		input: "drop /*vt+ strategy=online */ table a",
  1769  	}, {
  1770  		input:  "drop table a, b",
  1771  		output: "drop table a, b",
  1772  	}, {
  1773  		input:  "drop table if exists a,b restrict",
  1774  		output: "drop table if exists a, b",
  1775  	}, {
  1776  		input: "drop temporary table if exists a, b",
  1777  	}, {
  1778  		input:  "drop view if exists a cascade",
  1779  		output: "drop view if exists a",
  1780  	}, {
  1781  		input:  "drop index b on a lock = none algorithm default",
  1782  		output: "alter table a drop key b, lock none, algorithm = default",
  1783  	}, {
  1784  		input:  "drop index `PRIMARY` on a lock none",
  1785  		output: "alter table a drop primary key, lock none",
  1786  	}, {
  1787  		input:  "analyze table a",
  1788  		output: "otherread",
  1789  	}, {
  1790  		input: "flush tables",
  1791  	}, {
  1792  		input: "flush tables with read lock",
  1793  	}, {
  1794  		input: "flush tables a, c.v, b",
  1795  	}, {
  1796  		input: "flush local tables a, c.v, b with read lock",
  1797  	}, {
  1798  		input: "flush tables a, c.v, b for export",
  1799  	}, {
  1800  		input: "flush local binary logs, engine logs, error logs, general logs, hosts, logs, privileges, optimizer_costs",
  1801  	}, {
  1802  		input:  "flush no_write_to_binlog slow logs, status, user_resources, relay logs, relay logs for channel s",
  1803  		output: "flush local slow logs, status, user_resources, relay logs, relay logs for channel s",
  1804  	}, {
  1805  		input:  "show binary logs",
  1806  		output: "show binary logs",
  1807  	}, {
  1808  		input:  "show binlog events",
  1809  		output: "show binlog",
  1810  	}, {
  1811  		input:  "show character set",
  1812  		output: "show charset",
  1813  	}, {
  1814  		input:  "show character set like '%foo'",
  1815  		output: "show charset like '%foo'",
  1816  	}, {
  1817  		input:  "show charset",
  1818  		output: "show charset",
  1819  	}, {
  1820  		input:  "show charset like '%foo'",
  1821  		output: "show charset like '%foo'",
  1822  	}, {
  1823  		input:  "show charset where 'charset' = 'utf8'",
  1824  		output: "show charset where 'charset' = 'utf8'",
  1825  	}, {
  1826  		input:  "show charset where 'charset' = '%foo'",
  1827  		output: "show charset where 'charset' = '%foo'",
  1828  	}, {
  1829  		input:  "show collation",
  1830  		output: "show collation",
  1831  	}, {
  1832  		input:  "show collation where `Charset` = 'utf8' and `Collation` = 'utf8_bin'",
  1833  		output: "show collation where `Charset` = 'utf8' and `Collation` = 'utf8_bin'",
  1834  	}, {
  1835  		input: "show create database d",
  1836  	}, {
  1837  		input: "show create event e",
  1838  	}, {
  1839  		input: "show create function f",
  1840  	}, {
  1841  		input: "show create procedure p",
  1842  	}, {
  1843  		input: "show create table t",
  1844  	}, {
  1845  		input: "show create trigger t",
  1846  	}, {
  1847  		input:  "show create user u",
  1848  		output: "show create user",
  1849  	}, {
  1850  		input: "show create view v",
  1851  	}, {
  1852  		input:  "show databases",
  1853  		output: "show databases",
  1854  	}, {
  1855  		input:  "show databases like '%'",
  1856  		output: "show databases like '%'",
  1857  	}, {
  1858  		input:  "show schemas",
  1859  		output: "show databases",
  1860  	}, {
  1861  		input:  "show schemas like '%'",
  1862  		output: "show databases like '%'",
  1863  	}, {
  1864  		input:  "show engine INNODB",
  1865  		output: "show engine",
  1866  	}, {
  1867  		input: "show engines",
  1868  	}, {
  1869  		input:  "show storage engines",
  1870  		output: "show storage",
  1871  	}, {
  1872  		input: "show errors",
  1873  	}, {
  1874  		input: "show events",
  1875  	}, {
  1876  		input: "show function code func",
  1877  	}, {
  1878  		input: "show function status",
  1879  	}, {
  1880  		input:  "show grants for 'root@localhost'",
  1881  		output: "show grants",
  1882  	}, {
  1883  		input:  "show index from t",
  1884  		output: "show indexes from t",
  1885  	}, {
  1886  		input: "show indexes from t",
  1887  	}, {
  1888  		input:  "show keys from t",
  1889  		output: "show indexes from t",
  1890  	}, {
  1891  		input:  "show master status",
  1892  		output: "show master",
  1893  	}, {
  1894  		input: "show open tables",
  1895  	}, {
  1896  		input:  "show plugins",
  1897  		output: "show plugins",
  1898  	}, {
  1899  		input:  "show privileges",
  1900  		output: "show privileges",
  1901  	}, {
  1902  		input: "show procedure code p",
  1903  	}, {
  1904  		input: "show procedure status",
  1905  	}, {
  1906  		input:  "show processlist",
  1907  		output: "show processlist",
  1908  	}, {
  1909  		input:  "show full processlist",
  1910  		output: "show processlist",
  1911  	}, {
  1912  		input:  "show profile cpu for query 1",
  1913  		output: "show profile",
  1914  	}, {
  1915  		input:  "show profiles",
  1916  		output: "show profiles",
  1917  	}, {
  1918  		input:  "show relaylog events",
  1919  		output: "show relaylog",
  1920  	}, {
  1921  		input:  "show slave hosts",
  1922  		output: "show slave",
  1923  	}, {
  1924  		input:  "show slave status",
  1925  		output: "show slave",
  1926  	}, {
  1927  		input:  "show status",
  1928  		output: "show status",
  1929  	}, {
  1930  		input:  "show global status",
  1931  		output: "show global status",
  1932  	}, {
  1933  		input:  "show session status",
  1934  		output: "show status",
  1935  	}, {
  1936  		input: "show table status",
  1937  	}, {
  1938  		input: "show table status from dbname",
  1939  	}, {
  1940  		input:  "show table status in dbname",
  1941  		output: "show table status from dbname",
  1942  	}, {
  1943  		input:  "show table status in dbname LIKE '%' ",
  1944  		output: "show table status from dbname like '%'",
  1945  	}, {
  1946  		input:  "show table status from dbname Where col=42 ",
  1947  		output: "show table status from dbname where col = 42",
  1948  	}, {
  1949  		input: "show tables",
  1950  	}, {
  1951  		input: "show tables like '%keyspace%'",
  1952  	}, {
  1953  		input: "show tables where 1 = 0",
  1954  	}, {
  1955  		input: "show tables from a",
  1956  	}, {
  1957  		input: "show tables from a where 1 = 0",
  1958  	}, {
  1959  		input: "show tables from a like '%keyspace%'",
  1960  	}, {
  1961  		input: "show full tables",
  1962  	}, {
  1963  		input: "show full tables from a",
  1964  	}, {
  1965  		input:  "show full tables in a",
  1966  		output: "show full tables from a",
  1967  	}, {
  1968  		input: "show full tables from a like '%keyspace%'",
  1969  	}, {
  1970  		input: "show full tables from a where 1 = 0",
  1971  	}, {
  1972  		input: "show full tables like '%keyspace%'",
  1973  	}, {
  1974  		input: "show full tables where 1 = 0",
  1975  	}, {
  1976  		input:  "show full columns in a in b like '%'",
  1977  		output: "show full columns from a from b like '%'",
  1978  	}, {
  1979  		input: "show full columns from messages from test_keyspace like '%'",
  1980  	}, {
  1981  		input:  "show full fields from a like '%'",
  1982  		output: "show full columns from a like '%'",
  1983  	}, {
  1984  		input:  "show fields from a where 1 = 1",
  1985  		output: "show columns from a where 1 = 1",
  1986  	}, {
  1987  		input:  "show triggers",
  1988  		output: "show triggers",
  1989  	}, {
  1990  		input:  "show variables",
  1991  		output: "show variables",
  1992  	}, {
  1993  		input:  "show global variables",
  1994  		output: "show global variables",
  1995  	}, {
  1996  		input:  "show session variables",
  1997  		output: "show variables",
  1998  	}, {
  1999  		input: "show global vgtid_executed",
  2000  	}, {
  2001  		input: "show global vgtid_executed from ks",
  2002  	}, {
  2003  		input: "show global gtid_executed",
  2004  	}, {
  2005  		input: "show global gtid_executed from ks",
  2006  	}, {
  2007  		input:  "show vitess_keyspaces",
  2008  		output: "show keyspaces",
  2009  	}, {
  2010  		input:  "show vitess_keyspaces like '%'",
  2011  		output: "show keyspaces like '%'",
  2012  	}, {
  2013  		input: "show vitess_metadata variables",
  2014  	}, {
  2015  		input: "show vitess_replication_status",
  2016  	}, {
  2017  		input: "show vitess_replication_status like '%'",
  2018  	}, {
  2019  		input: "show vitess_shards",
  2020  	}, {
  2021  		input: "show vitess_shards like '%'",
  2022  	}, {
  2023  		input: "show vitess_tablets",
  2024  	}, {
  2025  		input: "show vitess_tablets like '%'",
  2026  	}, {
  2027  		input: "show vitess_tablets where hostname = 'some-tablet'",
  2028  	}, {
  2029  		input: "show vitess_targets",
  2030  	}, {
  2031  		input: "show vschema tables",
  2032  	}, {
  2033  		input: "show vschema vindexes",
  2034  	}, {
  2035  		input: "show vschema vindexes from t",
  2036  	}, {
  2037  		input:  "show vschema vindexes on t",
  2038  		output: "show vschema vindexes from t",
  2039  	}, {
  2040  		input: "show vitess_migrations",
  2041  	}, {
  2042  		input: "show vitess_migrations from ks",
  2043  	}, {
  2044  		input: "show vitess_migrations from ks where col = 42",
  2045  	}, {
  2046  		input: `show vitess_migrations from ks like '%pattern'`,
  2047  	}, {
  2048  		input: "show vitess_migrations like '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90'",
  2049  	}, {
  2050  		input: "show vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' logs",
  2051  	}, {
  2052  		input: "revert vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90'",
  2053  	}, {
  2054  		input: "revert /*vt+ uuid=123 */ vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90'",
  2055  	}, {
  2056  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' retry",
  2057  	}, {
  2058  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' cleanup",
  2059  	}, {
  2060  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' launch",
  2061  	}, {
  2062  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' launch vitess_shards '-40'",
  2063  	}, {
  2064  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' launch vitess_shards '-40,40-80'",
  2065  	}, {
  2066  		input: "alter vitess_migration launch all",
  2067  	}, {
  2068  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' complete",
  2069  	}, {
  2070  		input: "alter vitess_migration complete all",
  2071  	}, {
  2072  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' cancel",
  2073  	}, {
  2074  		input: "alter vitess_migration cancel all",
  2075  	}, {
  2076  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' throttle",
  2077  	}, {
  2078  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' throttle expire '1h'",
  2079  	}, {
  2080  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' throttle ratio 0.7",
  2081  	}, {
  2082  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' throttle expire '1h' ratio 0.7",
  2083  	}, {
  2084  		input: "alter vitess_migration '9748c3b7_7fdb_11eb_ac2c_f875a4d24e90' unthrottle",
  2085  	}, {
  2086  		input: "alter vitess_migration throttle all",
  2087  	}, {
  2088  		input: "alter vitess_migration unthrottle all",
  2089  	}, {
  2090  		input: "alter vitess_migration throttle all expire '1h'",
  2091  	}, {
  2092  		input: "alter vitess_migration throttle all ratio 0.7",
  2093  	}, {
  2094  		input: "alter vitess_migration throttle all expire '1h' ratio 0.7",
  2095  	}, {
  2096  		input: "show vitess_throttled_apps",
  2097  	}, {
  2098  		input: "show vitess_throttler status",
  2099  	}, {
  2100  		input: "show warnings",
  2101  	}, {
  2102  		input:  "select warnings from t",
  2103  		output: "select `warnings` from t",
  2104  	}, {
  2105  		input:  "show foobar",
  2106  		output: "show foobar",
  2107  	}, {
  2108  		input:  "show foobar like select * from table where syntax is 'ignored'",
  2109  		output: "show foobar",
  2110  	}, {
  2111  		input:  "use db",
  2112  		output: "use db",
  2113  	}, {
  2114  		input:  "use duplicate",
  2115  		output: "use `duplicate`",
  2116  	}, {
  2117  		input:  "use `ks:-80@master`",
  2118  		output: "use `ks:-80@master`",
  2119  	}, {
  2120  		input:  "use `ks:-80@primary`",
  2121  		output: "use `ks:-80@primary`",
  2122  	}, {
  2123  		input:  "use @replica",
  2124  		output: "use `@replica`",
  2125  	}, {
  2126  		input:  "use ks@replica",
  2127  		output: "use `ks@replica`",
  2128  	}, {
  2129  		input:  "describe select * from t",
  2130  		output: "explain select * from t",
  2131  	}, {
  2132  		input:  "describe /*vt+ execute_dml_queries */ select * from t",
  2133  		output: "explain /*vt+ execute_dml_queries */ select * from t",
  2134  	}, {
  2135  		input:  "desc select * from t",
  2136  		output: "explain select * from t",
  2137  	}, {
  2138  		input:  "desc foobar",
  2139  		output: "explain foobar",
  2140  	}, {
  2141  		input: "explain t1",
  2142  	}, {
  2143  		input: "explain t1 col",
  2144  	}, {
  2145  		input: "explain t1 '%col%'",
  2146  	}, {
  2147  		input: "explain select * from t",
  2148  	}, {
  2149  		input: "explain format = traditional select * from t",
  2150  	}, {
  2151  		input: "vexplain queries select * from t",
  2152  	}, {
  2153  		input: "vexplain all select * from t",
  2154  	}, {
  2155  		input: "vexplain plan select * from t",
  2156  	}, {
  2157  		input:  "vexplain select * from t",
  2158  		output: "vexplain plan select * from t",
  2159  	}, {
  2160  		input: "explain analyze select * from t",
  2161  	}, {
  2162  		input: "explain format = tree select * from t",
  2163  	}, {
  2164  		input: "explain format = json select * from t",
  2165  	}, {
  2166  		input: "explain format = vtexplain select * from t",
  2167  	}, {
  2168  		input: "explain format = vitess select * from t",
  2169  	}, {
  2170  		input:  "describe format = vitess select * from t",
  2171  		output: "explain format = vitess select * from t",
  2172  	}, {
  2173  		input:  "describe format = vtexplain select * from t",
  2174  		output: "explain format = vtexplain select * from t",
  2175  	}, {
  2176  		input: "explain delete from t",
  2177  	}, {
  2178  		input: "explain insert into t(col1, col2) values (1, 2)",
  2179  	}, {
  2180  		input: "explain update t set col = 2",
  2181  	}, {
  2182  		input:  "truncate table foo",
  2183  		output: "truncate table foo",
  2184  	}, {
  2185  		input:  "truncate foo",
  2186  		output: "truncate table foo",
  2187  	}, {
  2188  		input:  "repair foo",
  2189  		output: "otheradmin",
  2190  	}, {
  2191  		input:  "optimize foo",
  2192  		output: "otheradmin",
  2193  	}, {
  2194  		input:  "lock tables foo read",
  2195  		output: "lock tables foo read",
  2196  	}, {
  2197  		input:  "lock tables foo write",
  2198  		output: "lock tables foo write",
  2199  	}, {
  2200  		input:  "lock tables foo read local",
  2201  		output: "lock tables foo read local",
  2202  	}, {
  2203  		input:  "lock tables foo low_priority write",
  2204  		output: "lock tables foo low_priority write",
  2205  	}, {
  2206  		input:  "unlock tables",
  2207  		output: "unlock tables",
  2208  	}, {
  2209  		input: "select /* EQ true */ 1 from t where a = true",
  2210  	}, {
  2211  		input: "select /* EQ false */ 1 from t where a = false",
  2212  	}, {
  2213  		input: "select /* NE true */ 1 from t where a != true",
  2214  	}, {
  2215  		input: "select /* NE false */ 1 from t where a != false",
  2216  	}, {
  2217  		input: "select /* LT true */ 1 from t where a < true",
  2218  	}, {
  2219  		input: "select /* LT false */ 1 from t where a < false",
  2220  	}, {
  2221  		input: "select /* GT true */ 1 from t where a > true",
  2222  	}, {
  2223  		input: "select /* GT false */ 1 from t where a > false",
  2224  	}, {
  2225  		input: "select /* LE true */ 1 from t where a <= true",
  2226  	}, {
  2227  		input: "select /* LE false */ 1 from t where a <= false",
  2228  	}, {
  2229  		input: "select /* GE true */ 1 from t where a >= true",
  2230  	}, {
  2231  		input: "select /* GE false */ 1 from t where a >= false",
  2232  	}, {
  2233  		input:  "select * from t order by a collate utf8_general_ci",
  2234  		output: "select * from t order by a collate utf8_general_ci asc",
  2235  	}, {
  2236  		input: "select k collate latin1_german2_ci as k1 from t1 order by k1 asc",
  2237  	}, {
  2238  		input: "select * from t group by a collate utf8_general_ci",
  2239  	}, {
  2240  		input:  "select MAX(k collate latin1_german2_ci) from t1",
  2241  		output: "select max(k collate latin1_german2_ci) from t1",
  2242  	}, {
  2243  		input: "select distinct k collate latin1_german2_ci from t1",
  2244  	}, {
  2245  		input: "select * from t1 where 'Müller' collate latin1_german2_ci = k",
  2246  	}, {
  2247  		input: "select * from t1 where k like 'Müller' collate latin1_german2_ci",
  2248  	}, {
  2249  		input: "select k from t1 group by k having k = 'Müller' collate latin1_german2_ci",
  2250  	}, {
  2251  		input: "select k from t1 join t2 order by a collate latin1_german2_ci asc, b collate latin1_german2_ci asc",
  2252  	}, {
  2253  		input:  "select k collate 'latin1_german2_ci' as k1 from t1 order by k1 asc",
  2254  		output: "select k collate latin1_german2_ci as k1 from t1 order by k1 asc",
  2255  	}, {
  2256  		input:  "select /* drop trailing semicolon */ 1 from dual;",
  2257  		output: "select /* drop trailing semicolon */ 1 from dual",
  2258  	}, {
  2259  		input: "select /* cache directive */ sql_no_cache 'foo' from t",
  2260  	}, {
  2261  		input: "select distinct sql_no_cache 'foo' from t",
  2262  	}, {
  2263  		input:  "select sql_no_cache distinct 'foo' from t",
  2264  		output: "select distinct sql_no_cache 'foo' from t",
  2265  	}, {
  2266  		input:  "select sql_no_cache straight_join distinct 'foo' from t",
  2267  		output: "select distinct sql_no_cache straight_join 'foo' from t",
  2268  	}, {
  2269  		input:  "select straight_join distinct sql_no_cache 'foo' from t",
  2270  		output: "select distinct sql_no_cache straight_join 'foo' from t",
  2271  	}, {
  2272  		input:  "select sql_calc_found_rows 'foo' from t",
  2273  		output: "select sql_calc_found_rows 'foo' from t",
  2274  	}, {
  2275  		input:  "select binary 'a' = 'A' from t",
  2276  		output: "select convert('a', binary) = 'A' from t",
  2277  	}, {
  2278  		input: "select 1 from t where foo = _binary 'bar'",
  2279  	}, {
  2280  		input: "select 1 from t where foo = _utf8 'bar' and bar = _latin1 'sjösjuk'",
  2281  	}, {
  2282  		input:  "select 1 from t where foo = _binary'bar'",
  2283  		output: "select 1 from t where foo = _binary 'bar'",
  2284  	}, {
  2285  		input: "select 1 from t where foo = _utf8mb4 'bar'",
  2286  	}, {
  2287  		input:  "select 1 from t where foo = _utf8mb4'bar'",
  2288  		output: "select 1 from t where foo = _utf8mb4 'bar'",
  2289  	}, {
  2290  		input:  "select 1 from t where foo = _utf8mb3 'bar'",
  2291  		output: "select 1 from t where foo = _utf8 'bar'",
  2292  	}, {
  2293  		input:  "select 1 from t where foo = _utf8mb3'bar'",
  2294  		output: "select 1 from t where foo = _utf8 'bar'",
  2295  	}, {
  2296  		input: "select match(a) against ('foo') from t",
  2297  	}, {
  2298  		input: "select match(a1, a2) against ('foo' in natural language mode with query expansion) from t",
  2299  	}, {
  2300  		input:  "select database()",
  2301  		output: "select database() from dual",
  2302  	}, {
  2303  		input:  "select schema()",
  2304  		output: "select schema() from dual",
  2305  	}, {
  2306  		input: "select title from video as v where match(v.title, v.tag) against ('DEMO' in boolean mode)",
  2307  	}, {
  2308  		input:  "SELECT id FROM blog_posts USE INDEX (PRIMARY) WHERE id = 10",
  2309  		output: "select id from blog_posts use index (`PRIMARY`) where id = 10",
  2310  	}, {
  2311  		input:  "select name, group_concat(score) from t group by name",
  2312  		output: "select `name`, group_concat(score) from t group by `name`",
  2313  	}, {
  2314  		input:  "select name, group_concat(distinct id, score order by id desc separator ':') from t group by name",
  2315  		output: "select `name`, group_concat(distinct id, score order by id desc separator ':') from t group by `name`",
  2316  	}, {
  2317  		input:  "select name, group_concat(distinct id, score order by id desc separator ':' limit 1) from t group by name",
  2318  		output: "select `name`, group_concat(distinct id, score order by id desc separator ':' limit 1) from t group by `name`",
  2319  	}, {
  2320  		input:  "select name, group_concat(distinct id, score order by id desc separator ':' limit 10, 2) from t group by name",
  2321  		output: "select `name`, group_concat(distinct id, score order by id desc separator ':' limit 10, 2) from t group by `name`",
  2322  	}, {
  2323  		input: "select * from t partition (p0)",
  2324  	}, {
  2325  		input: "select * from t partition (p0, p1)",
  2326  	}, {
  2327  		input: "select e.id, s.city from employees as e join stores partition (p1) as s on e.store_id = s.id",
  2328  	}, {
  2329  		input: "select truncate(120.3333, 2) from dual",
  2330  	}, {
  2331  		input: "update t partition (p0) set a = 1",
  2332  	}, {
  2333  		input: "insert into t partition (p0) values (1, 'asdf')",
  2334  	}, {
  2335  		input: "insert into t1 select * from t2 partition (p0)",
  2336  	}, {
  2337  		input: "replace into t partition (p0) values (1, 'asdf')",
  2338  	}, {
  2339  		input: "delete from t partition (p0) where a = 1",
  2340  	}, {
  2341  		input: "stream * from t",
  2342  	}, {
  2343  		input: "stream /* comment */ * from t",
  2344  	}, {
  2345  		input: "vstream * from t",
  2346  	}, {
  2347  		input: "begin",
  2348  	}, {
  2349  		input:  "begin;",
  2350  		output: "begin",
  2351  	}, {
  2352  		input:  "start transaction",
  2353  		output: "begin",
  2354  	}, {
  2355  		input: "start transaction with consistent snapshot",
  2356  	}, {
  2357  		input: "start transaction read write",
  2358  	}, {
  2359  		input: "start transaction read only",
  2360  	}, {
  2361  		input: "start transaction read only, with consistent snapshot",
  2362  	}, {
  2363  		input: "commit",
  2364  	}, {
  2365  		input: "rollback",
  2366  	}, {
  2367  		input: "create database /* simple */ test_db",
  2368  	}, {
  2369  		input:  "create schema test_db",
  2370  		output: "create database test_db",
  2371  	}, {
  2372  		input: "create database /* simple */ if not exists test_db",
  2373  	}, {
  2374  		input:  "create schema if not exists test_db",
  2375  		output: "create database if not exists test_db",
  2376  	}, {
  2377  		input: "create database test_db default collate 'utf8mb4_general_ci' collate utf8mb4_general_ci",
  2378  	}, {
  2379  		input: "create database test_db character set geostd8",
  2380  	}, {
  2381  		input:      "alter table corder zzzz zzzz zzzz",
  2382  		output:     "alter table corder",
  2383  		partialDDL: true,
  2384  	}, {
  2385  		input:      "create database test_db character set * unparsable",
  2386  		output:     "create database test_db",
  2387  		partialDDL: true,
  2388  	}, {
  2389  		input:  "CREATE DATABASE IF NOT EXISTS `mysql` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci ENCRYPTION='N';",
  2390  		output: "create database if not exists mysql default character set utf8mb4 collate utf8mb4_0900_ai_ci encryption 'N'",
  2391  	}, {
  2392  		input: "drop /* simple */ database test_db",
  2393  	}, {
  2394  		input:  "drop schema test_db",
  2395  		output: "drop database test_db",
  2396  	}, {
  2397  		input: "drop /* simple */ database if exists test_db",
  2398  	}, {
  2399  		input:  "delete a.*, b.* from tbl_a a, tbl_b b where a.id = b.id and b.name = 'test'",
  2400  		output: "delete a, b from tbl_a as a, tbl_b as b where a.id = b.id and b.`name` = 'test'",
  2401  	}, {
  2402  		input:  "select distinctrow a.* from (select (1) from dual union all select 1 from dual) a",
  2403  		output: "select distinct a.* from (select 1 from dual union all select 1 from dual) as a",
  2404  	}, {
  2405  		input: "select `weird function name`() from t",
  2406  	}, {
  2407  		input:  "select all* from t",
  2408  		output: "select * from t",
  2409  	}, {
  2410  		input:  "select distinct* from t",
  2411  		output: "select distinct * from t",
  2412  	}, {
  2413  		input: "select status() from t", // should not escape function names that are keywords
  2414  	}, {
  2415  		input: "select * from `weird table name`",
  2416  	}, {
  2417  		input:  "SHOW FULL TABLES FROM `jiradb` LIKE 'AO_E8B6CC_ISSUE_MAPPING'",
  2418  		output: "show full tables from jiradb like 'AO_E8B6CC_ISSUE_MAPPING'",
  2419  	}, {
  2420  		input:  "SHOW FULL COLUMNS FROM AO_E8B6CC_ISSUE_MAPPING FROM jiradb LIKE '%'",
  2421  		output: "show full columns from AO_E8B6CC_ISSUE_MAPPING from jiradb like '%'",
  2422  	}, {
  2423  		input:  "SHOW KEYS FROM `AO_E8B6CC_ISSUE_MAPPING` FROM `jiradb`",
  2424  		output: "show indexes from AO_E8B6CC_ISSUE_MAPPING from jiradb",
  2425  	}, {
  2426  		input:  "SHOW CREATE TABLE `jiradb`.`AO_E8B6CC_ISSUE_MAPPING`",
  2427  		output: "show create table jiradb.AO_E8B6CC_ISSUE_MAPPING",
  2428  	}, {
  2429  		input:  "SHOW INDEX FROM `AO_E8B6CC_ISSUE_MAPPING` FROM `jiradb`",
  2430  		output: "show indexes from AO_E8B6CC_ISSUE_MAPPING from jiradb",
  2431  	}, {
  2432  		input:  "SHOW FULL TABLES FROM `jiradb` LIKE '%'",
  2433  		output: "show full tables from jiradb like '%'",
  2434  	}, {
  2435  		input:  "SHOW EXTENDED INDEX FROM `AO_E8B6CC_PROJECT_MAPPING` FROM `jiradb`",
  2436  		output: "show indexes from AO_E8B6CC_PROJECT_MAPPING from jiradb",
  2437  	}, {
  2438  		input:  "SHOW EXTENDED KEYS FROM `AO_E8B6CC_ISSUE_MAPPING` FROM `jiradb`",
  2439  		output: "show indexes from AO_E8B6CC_ISSUE_MAPPING from jiradb",
  2440  	}, {
  2441  		input:  "SHOW CREATE TABLE `jiradb`.`AO_E8B6CC_ISSUE_MAPPING`",
  2442  		output: "show create table jiradb.AO_E8B6CC_ISSUE_MAPPING",
  2443  	}, {
  2444  		input: "create table t1 ( check (c1 <> c2), c1 int check (c1 > 10), c2 int constraint c2_positive check (c2 > 0), c3 int check (c3 < 100), constraint c1_nonzero check (c1 <> 0), check (c1 > c3))",
  2445  		output: "create table t1 (\n" +
  2446  			"\tc1 int,\n" +
  2447  			"\tc2 int,\n" +
  2448  			"\tc3 int,\n" +
  2449  			"\tcheck (c1 != c2),\n" +
  2450  			"\tcheck (c1 > 10),\n" +
  2451  			"\tconstraint c2_positive check (c2 > 0),\n" +
  2452  			"\tcheck (c3 < 100),\n" +
  2453  			"\tconstraint c1_nonzero check (c1 != 0),\n" +
  2454  			"\tcheck (c1 > c3)\n)",
  2455  	}, {
  2456  		input:  "SHOW INDEXES FROM `AO_E8B6CC_ISSUE_MAPPING` FROM `jiradb`",
  2457  		output: "show indexes from AO_E8B6CC_ISSUE_MAPPING from jiradb",
  2458  	}, {
  2459  		input:  "SHOW FULL TABLES FROM `jiradb` LIKE '%'",
  2460  		output: "show full tables from jiradb like '%'",
  2461  	}, {
  2462  		input:  "SHOW EXTENDED INDEXES FROM `AO_E8B6CC_PROJECT_MAPPING` FROM `jiradb`",
  2463  		output: "show indexes from AO_E8B6CC_PROJECT_MAPPING from jiradb",
  2464  	}, {
  2465  		input:  "SHOW EXTENDED INDEXES IN `AO_E8B6CC_PROJECT_MAPPING` IN `jiradb`",
  2466  		output: "show indexes from AO_E8B6CC_PROJECT_MAPPING from jiradb",
  2467  	}, {
  2468  		input:  "do 1",
  2469  		output: "otheradmin",
  2470  	}, {
  2471  		input:  "do funcCall(), 2 = 1, 3 + 1",
  2472  		output: "otheradmin",
  2473  	}, {
  2474  		input: "savepoint a",
  2475  	}, {
  2476  		input: "savepoint `@@@;a`",
  2477  	}, {
  2478  		input: "rollback to a",
  2479  	}, {
  2480  		input: "rollback to `@@@;a`",
  2481  	}, {
  2482  		input:  "rollback work to a",
  2483  		output: "rollback to a",
  2484  	}, {
  2485  		input:  "rollback to savepoint a",
  2486  		output: "rollback to a",
  2487  	}, {
  2488  		input:  "rollback work to savepoint a",
  2489  		output: "rollback to a",
  2490  	}, {
  2491  		input: "release savepoint a",
  2492  	}, {
  2493  		input: "release savepoint `@@@;a`",
  2494  	}, {
  2495  		input: "call proc()",
  2496  	}, {
  2497  		input: "call qualified.proc()",
  2498  	}, {
  2499  		input: "call proc(1, 'foo')",
  2500  	}, {
  2501  		input: "call proc(@param)",
  2502  	}, {
  2503  		input:  "PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse'",
  2504  		output: "prepare stmt1 from 'SELECT SQRT(POW(?,2) + POW(?,2)) AS hypotenuse'",
  2505  	}, {
  2506  		input:  "PREPARE stmt2 FROM @s",
  2507  		output: "prepare stmt2 from @s",
  2508  	}, {
  2509  		input:  "PREPARE /* comment */ stmt2 FROM @s",
  2510  		output: "prepare /* comment */ stmt2 from @s",
  2511  	}, {
  2512  		input:  "EXECUTE stmt1",
  2513  		output: "execute stmt1",
  2514  	}, {
  2515  		input:  "EXECUTE /* comment */ stmt1",
  2516  		output: "execute /* comment */ stmt1",
  2517  	}, {
  2518  		input:  "EXECUTE stmt1 USING @a",
  2519  		output: "execute stmt1 using @a",
  2520  	}, {
  2521  		input:  "EXECUTE stmt1 USING @a, @b",
  2522  		output: "execute stmt1 using @a, @b",
  2523  	}, {
  2524  		input:  "DEALLOCATE PREPARE stmt1",
  2525  		output: "deallocate prepare stmt1",
  2526  	}, {
  2527  		input:  "DROP PREPARE stmt1",
  2528  		output: "drop prepare stmt1",
  2529  	}, {
  2530  		input:  "DROP /* comment */ PREPARE stmt1",
  2531  		output: "drop /* comment */ prepare stmt1",
  2532  	}, {
  2533  		input:  `SELECT JSON_PRETTY('{"a":"10","b":"15","x":"25"}')`,
  2534  		output: `select json_pretty('{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') from dual`,
  2535  	}, {
  2536  		input:  `SELECT JSON_PRETTY(N'{"a":"10","b":"15","x":"25"}')`,
  2537  		output: `select json_pretty(N'{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') from dual`,
  2538  		/*We need to ignore this test because, after the normalizer, we change the produced NChar
  2539  		string into an introducer expression, so the vttablet will never see a NChar string */
  2540  		ignoreNormalizerTest: true,
  2541  	}, {
  2542  		input:  "SELECT jcol, JSON_PRETTY(jcol) from jtable",
  2543  		output: "select jcol, json_pretty(jcol) from jtable",
  2544  	}, {
  2545  		input:  "SELECT JSON_PRETTY(@j)",
  2546  		output: "select json_pretty(@j) from dual",
  2547  	}, {
  2548  		input:  "SELECT jcol, JSON_STORAGE_SIZE(jcol) AS Size FROM jtable",
  2549  		output: "select jcol, json_storage_size(jcol) as Size from jtable",
  2550  	}, {
  2551  		input:  `SELECT jcol, JSON_STORAGE_SIZE(N'{"a":"10","b":"15","x":"25"}') AS Size FROM jtable`,
  2552  		output: `select jcol, json_storage_size(N'{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') as Size from jtable`,
  2553  		/*We need to ignore this test because, after the normalizer, we change the produced NChar
  2554  		string into an introducer expression, so the vttablet will never see a NChar string */
  2555  		ignoreNormalizerTest: true,
  2556  	}, {
  2557  		input:  `SELECT JSON_STORAGE_SIZE('[100, "sakila", [1, 3, 5], 425.05]') AS A, JSON_STORAGE_SIZE('{"a": 1000, "b": "a", "c": "[1, 3, 5, 7]"}') AS B, JSON_STORAGE_SIZE('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}') AS C,JSON_STORAGE_SIZE('[100, "json", [[10, 20, 30], 3, 5], 425.05]') AS D`,
  2558  		output: `select json_storage_size('[100, \"sakila\", [1, 3, 5], 425.05]') as A, json_storage_size('{\"a\": 1000, \"b\": \"a\", \"c\": \"[1, 3, 5, 7]\"}') as B, json_storage_size('{\"a\": 1000, \"b\": \"wxyz\", \"c\": \"[1, 3, 5, 7]\"}') as C, json_storage_size('[100, \"json\", [[10, 20, 30], 3, 5], 425.05]') as D from dual`,
  2559  	}, {
  2560  		input:  "SELECT JSON_STORAGE_SIZE(@j)",
  2561  		output: "select json_storage_size(@j) from dual",
  2562  	}, {
  2563  		input:  "SELECT JSON_STORAGE_FREE(jcol) FROM jtable",
  2564  		output: "select json_storage_free(jcol) from jtable",
  2565  	}, {
  2566  		input:  `SELECT JSON_STORAGE_FREE('{"a":"10","b":"15","x":"25"}')`,
  2567  		output: `select json_storage_free('{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') from dual`,
  2568  	}, {
  2569  		input:  `SELECT JSON_STORAGE_FREE(N'{"a":"10","b":"15","x":"25"}')`,
  2570  		output: `select json_storage_free(N'{\"a\":\"10\",\"b\":\"15\",\"x\":\"25\"}') from dual`,
  2571  		/*We need to ignore this test because, after the normalizer, we change the produced NChar
  2572  		string into an introducer expression, so the vttablet will never see a NChar string */
  2573  		ignoreNormalizerTest: true,
  2574  	}, {
  2575  		input:  "SELECT JSON_STORAGE_FREE(@j)",
  2576  		output: "select json_storage_free(@j) from dual",
  2577  	}, {
  2578  		input:  "SELECT LTRIM('abc')",
  2579  		output: "select ltrim('abc') from dual",
  2580  	}, {
  2581  		input:  "SELECT RTRIM('abc')",
  2582  		output: "select rtrim('abc') from dual",
  2583  	}, {
  2584  		input:  "SELECT TRIM('  abc  ')",
  2585  		output: "select trim('  abc  ') from dual",
  2586  	}, {
  2587  		input:  "SELECT TRIM('aa' FROM 'aabccaaa')",
  2588  		output: "select trim('aa' from 'aabccaaa') from dual",
  2589  	}, {
  2590  		input:  "SELECT TRIM(LEADING FROM 'aabccaaa')",
  2591  		output: "select trim(leading from 'aabccaaa') from dual",
  2592  	}, {
  2593  		input:  "SELECT TRIM(TRAILING FROM 'abca')",
  2594  		output: "select trim(trailing from 'abca') from dual",
  2595  	}, {
  2596  		input:  "SELECT TRIM(BOTH FROM 'abc')",
  2597  		output: "select trim(both from 'abc') from dual",
  2598  	}, {
  2599  		input:  "SELECT TRIM(LEADING 'a' FROM 'abc')",
  2600  		output: "select trim(leading 'a' from 'abc') from dual",
  2601  	}, {
  2602  		input:  "SELECT TRIM(TRAILING 'a' FROM 'abc')",
  2603  		output: "select trim(trailing 'a' from 'abc') from dual",
  2604  	}, {
  2605  		input:  "SELECT TRIM(BOTH 'a' FROM 'abc')",
  2606  		output: "select trim(both 'a' from 'abc') from dual",
  2607  	}, {
  2608  		input: `SELECT * FROM JSON_TABLE('[ {"c1": null} ]','$[*]' COLUMNS( c1 INT PATH '$.c1' ERROR ON ERROR )) as jt`,
  2609  		output: `select * from json_table('[ {\"c1\": null} ]', '$[*]' columns(
  2610  	c1 INT path '$.c1' error on error 
  2611  	)
  2612  ) as jt`,
  2613  	}, {
  2614  		input: `SELECT * FROM  JSON_TABLE(    '[{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}]', '$[*]' COLUMNS(a INT PATH '$.a', NESTED PATH '$.b[*]' COLUMNS (b1 INT PATH '$'), NESTED PATH '$.b[*]' COLUMNS (b2 INT PATH '$'))) AS jt`,
  2615  		output: `select * from json_table('[{\"a\": 1, \"b\": [11,111]}, {\"a\": 2, \"b\": [22,222]}]', '$[*]' columns(
  2616  	a INT path '$.a' ,
  2617  	nested path '$.b[*]' columns(
  2618  	b1 INT path '$' 
  2619  ),
  2620  	nested path '$.b[*]' columns(
  2621  	b2 INT path '$' 
  2622  )
  2623  	)
  2624  ) as jt`,
  2625  	}, {
  2626  		input: `SELECT * FROM JSON_TABLE('[ {"c1": null} ]','$[*]' COLUMNS( c1 INT PATH '$.c1' ERROR ON ERROR )) as jt`,
  2627  		output: `select * from json_table('[ {\"c1\": null} ]', '$[*]' columns(
  2628  	c1 INT path '$.c1' error on error 
  2629  	)
  2630  ) as jt`,
  2631  	}, {
  2632  		input: `SELECT * FROM JSON_TABLE('[{"a":"3"},{"a":2},{"b":1},{"a":0},{"a":[1,2]}]', "$[*]" COLUMNS(rowid FOR ORDINALITY, ac VARCHAR(100) PATH "$.a" DEFAULT '111' ON EMPTY DEFAULT '999' ON ERROR,  aj JSON PATH "$.a" DEFAULT '{"x": 333}' ON EMPTY, bx INT EXISTS PATH "$.b" ) ) AS tt`,
  2633  		output: `select * from json_table('[{\"a\":\"3\"},{\"a\":2},{\"b\":1},{\"a\":0},{\"a\":[1,2]}]', '$[*]' columns(
  2634  	rowid for ordinality,
  2635  	ac VARCHAR(100) path '$.a' default '111' on empty default '999' on error ,
  2636  	aj JSON path '$.a' default '{\"x\": 333}' on empty ,
  2637  	bx INT exists path '$.b' 
  2638  	)
  2639  ) as tt`,
  2640  	}, {
  2641  		input: `SELECT * FROM  JSON_TABLE(    '[ {"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]',    '$[*]' COLUMNS(            a INT PATH '$.a',            NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$')           )   ) AS jt WHERE b IS NOT NULL`,
  2642  		output: `select * from json_table('[ {\"a\": 1, \"b\": [11,111]}, {\"a\": 2, \"b\": [22,222]}, {\"a\":3}]', '$[*]' columns(
  2643  	a INT path '$.a' ,
  2644  	nested path '$.b[*]' columns(
  2645  	b INT path '$' 
  2646  )
  2647  	)
  2648  ) as jt where b is not null`,
  2649  	}, {
  2650  		input: `SELECT * FROM  JSON_TABLE(    '[{"x":2,"y":"8"},{"x":"3","y":"7"},{"x":"4","y":6}]',    "$[1]" COLUMNS(      xval VARCHAR(100) PATH "$.x",      yval VARCHAR(100) PATH "$.y"    )  ) AS  jt1`,
  2651  		output: `select * from json_table('[{\"x\":2,\"y\":\"8\"},{\"x\":\"3\",\"y\":\"7\"},{\"x\":\"4\",\"y\":6}]', '$[1]' columns(
  2652  	xval VARCHAR(100) path '$.x' ,
  2653  	yval VARCHAR(100) path '$.y' 
  2654  	)
  2655  ) as jt1`,
  2656  	}, {
  2657  		input: `SELECT * FROM  JSON_TABLE(    '[{"a": "a_val","b": [{"c": "c_val", "l": [1,2]}]},{"a": "a_val", "b": [{"c": "c_val","l": [11]}, {"c": "c_val", "l": [22]}]}]',    '$[*]' COLUMNS(      top_ord FOR ORDINALITY,      apath VARCHAR(10) PATH '$.a',      NESTED PATH '$.b[*]' COLUMNS (        bpath VARCHAR(10) PATH '$.c',        ord FOR ORDINALITY,        NESTED PATH '$.l[*]' COLUMNS (lpath varchar(10) PATH '$')        )    )) as jt`,
  2658  		output: `select * from json_table('[{\"a\": \"a_val\",\"b\": [{\"c\": \"c_val\", \"l\": [1,2]}]},{\"a\": \"a_val\", \"b\": [{\"c\": \"c_val\",\"l\": [11]}, {\"c\": \"c_val\", \"l\": [22]}]}]', '$[*]' columns(
  2659  	top_ord for ordinality,
  2660  	apath VARCHAR(10) path '$.a' ,
  2661  	nested path '$.b[*]' columns(
  2662  	bpath VARCHAR(10) path '$.c' ,
  2663  	ord for ordinality,
  2664  	nested path '$.l[*]' columns(
  2665  	lpath varchar(10) path '$' 
  2666  )
  2667  )
  2668  	)
  2669  ) as jt`,
  2670  	}, {
  2671  		input: `SELECT * FROM JSON_TABLE('[{"x":2,"y":"8"},{"x":"3","y":"7"},{"x":"4","y":6}]', "$[1]" COLUMNS( xval VARCHAR(100) PATH "$.x", yval VARCHAR(100) PATH "$.y")) AS  jt1;`,
  2672  		output: `select * from json_table('[{\"x\":2,\"y\":\"8\"},{\"x\":\"3\",\"y\":\"7\"},{\"x\":\"4\",\"y\":6}]', '$[1]' columns(
  2673  	xval VARCHAR(100) path '$.x' ,
  2674  	yval VARCHAR(100) path '$.y' 
  2675  	)
  2676  ) as jt1`,
  2677  	}, {
  2678  		input:  "SELECT JSON_ARRAY()",
  2679  		output: "select json_array() from dual",
  2680  	}, {
  2681  		input:  "SELECT JSON_ARRAY(1)",
  2682  		output: "select json_array(1) from dual",
  2683  	}, {
  2684  		input:  "SELECT JSON_ARRAY('abc')",
  2685  		output: "select json_array('abc') from dual",
  2686  	}, {
  2687  		input:  "SELECT JSON_ARRAY(BIN(11))",
  2688  		output: "select json_array(BIN(11)) from dual",
  2689  	}, {
  2690  		input:  `SELECT JSON_ARRAY(1, "abc", NULL, TRUE, CURTIME());`,
  2691  		output: `select json_array(1, 'abc', null, true, CURTIME()) from dual`,
  2692  	}, {
  2693  		input:  "SELECT JSON_OBJECT(1,2)",
  2694  		output: "select json_object(1, 2) from dual",
  2695  	}, {
  2696  		input:  "SELECT JSON_OBJECT(1,'abc')",
  2697  		output: "select json_object(1, 'abc') from dual",
  2698  	}, {
  2699  		input:  "SELECT JSON_OBJECT('abc',1)",
  2700  		output: "select json_object('abc', 1) from dual",
  2701  	}, {
  2702  		input:  "SELECT JSON_OBJECT(BIN(1),2)",
  2703  		output: "select json_object(BIN(1), 2) from dual",
  2704  	}, {
  2705  		input:  "SELECT JSON_OBJECT(BIN(1),2,'abc',ASCII(4))",
  2706  		output: "select json_object(BIN(1), 2, 'abc', ASCII(4)) from dual",
  2707  	}, {
  2708  		input:  "SELECT JSON_QUOTE(BIN(11))",
  2709  		output: "select json_quote(BIN(11)) from dual",
  2710  	}, {
  2711  		input:  `SELECT JSON_QUOTE('null'), JSON_QUOTE('"null"')`,
  2712  		output: `select json_quote('null'), json_quote('\"null\"') from dual`,
  2713  	}, {
  2714  		input:  "select t1.a, dt.a from t1, lateral (select t1.a+t2.a as a from t2) dt",
  2715  		output: "select t1.a, dt.a from t1, lateral (select t1.a + t2.a as a from t2) as dt",
  2716  	}, {
  2717  		input:  "select b from v1 vq1, lateral (select count(*) from v1 vq2 having vq1.b = 3) dt",
  2718  		output: "select b from v1 as vq1, lateral (select count(*) from v1 as vq2 having vq1.b = 3) as dt",
  2719  	}, {
  2720  		input:  `SELECT JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"')`,
  2721  		output: `select json_schema_valid('{\"type\":\"string\",\"pattern\":\"(\"}', '\"abc\"') from dual`,
  2722  	}, {
  2723  		input:  `SELECT JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', @a)`,
  2724  		output: `select json_schema_valid('{\"type\":\"string\",\"pattern\":\"(\"}', @a) from dual`,
  2725  	}, {
  2726  		input:  `SELECT JSON_SCHEMA_VALID(@b, BIN(1))`,
  2727  		output: `select json_schema_valid(@b, BIN(1)) from dual`,
  2728  	}, {
  2729  		input:  `SELECT JSON_SCHEMA_VALID(N'{"type":"string","pattern":"("}', '"abc"')`,
  2730  		output: `select json_schema_valid(N'{\"type\":\"string\",\"pattern\":\"(\"}', '\"abc\"') from dual`,
  2731  		/*We need to ignore this test because, after the normalizer, we change the produced NChar
  2732  		string into an introducer expression, so the vttablet will never see a NChar string */
  2733  		ignoreNormalizerTest: true,
  2734  	}, {
  2735  		input:  `SELECT JSON_SCHEMA_VALIDATION_REPORT('{"type":"string","pattern":"("}', '"abc"')`,
  2736  		output: `select json_schema_validation_report('{\"type\":\"string\",\"pattern\":\"(\"}', '\"abc\"') from dual`,
  2737  	}, {
  2738  		input:  `SELECT JSON_SCHEMA_VALIDATION_REPORT('{"type":"string","pattern":"("}', @a)`,
  2739  		output: `select json_schema_validation_report('{\"type\":\"string\",\"pattern\":\"(\"}', @a) from dual`,
  2740  	}, {
  2741  		input:  `SELECT JSON_SCHEMA_VALIDATION_REPORT(@b, BIN(1))`,
  2742  		output: `select json_schema_validation_report(@b, BIN(1)) from dual`,
  2743  	}, {
  2744  		input:  `SELECT JSON_SCHEMA_VALIDATION_REPORT(N'{"type":"string","pattern":"("}', '"abc"')`,
  2745  		output: `select json_schema_validation_report(N'{\"type\":\"string\",\"pattern\":\"(\"}', '\"abc\"') from dual`,
  2746  		/*We need to ignore this test because, after the normalizer, we change the produced NChar
  2747  		string into an introducer expression, so the vttablet will never see a NChar string */
  2748  		ignoreNormalizerTest: true,
  2749  	}, {
  2750  		input:  `SELECT JSON_CONTAINS('{"a": 1, "b": 2, "c": {"d": 4}}', '1')`,
  2751  		output: `select json_contains('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', '1') from dual`,
  2752  	}, {
  2753  		input:  "SELECT JSON_CONTAINS(@j, @j2)",
  2754  		output: "select json_contains(@j, @j2) from dual",
  2755  	}, {
  2756  		input:  "SELECT JSON_CONTAINS(@j, @j2,'$.a', @j)",
  2757  		output: "select json_contains(@j, @j2, '$.a', @j) from dual",
  2758  	}, {
  2759  		input:  "SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e')",
  2760  		output: "select json_contains_path(@j, 'one', '$.a', '$.e') from dual",
  2761  	}, {
  2762  		input:  `SELECT JSON_CONTAINS_PATH('{"a": 1, "b": 2, "c": {"d": 4}}', 'one', '$.a', '$.e')`,
  2763  		output: `select json_contains_path('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', 'one', '$.a', '$.e') from dual`,
  2764  	}, {
  2765  		input:  "SELECT JSON_CONTAINS_PATH(@j, TRIM('one'), '$.a', '$.e')",
  2766  		output: "select json_contains_path(@j, trim('one'), '$.a', '$.e') from dual",
  2767  	}, {
  2768  		input:  "SELECT JSON_CONTAINS_PATH(@j, @k, '$.a', @i)",
  2769  		output: "select json_contains_path(@j, @k, '$.a', @i) from dual",
  2770  	}, {
  2771  		input:  "SELECT JSON_EXTRACT(@j, '$.a')",
  2772  		output: "select json_extract(@j, '$.a') from dual",
  2773  	}, {
  2774  		input:  `SELECT c, JSON_EXTRACT(c, "$.id"), g FROM jemp WHERE JSON_EXTRACT(c, "$.id") > 1 ORDER BY JSON_EXTRACT(c, "$.name")`,
  2775  		output: "select c, json_extract(c, '$.id'), g from jemp where json_extract(c, '$.id') > 1 order by json_extract(c, '$.name') asc",
  2776  	}, {
  2777  		input:  `SELECT JSON_EXTRACT('{"a": 1, "b": 2, "c": {"d": 4}}', '$.a', @j)`,
  2778  		output: `select json_extract('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', '$.a', @j) from dual`,
  2779  	}, {
  2780  		input:  "SELECT JSON_EXTRACT(@k, TRIM('abc'))",
  2781  		output: `select json_extract(@k, trim('abc')) from dual`,
  2782  	}, {
  2783  		input:  `SELECT JSON_KEYS('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', '$.a')`,
  2784  		output: `select json_keys('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', '$.a') from dual`,
  2785  	}, {
  2786  		input:  `SELECT JSON_KEYS('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}')`,
  2787  		output: `select json_keys('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}') from dual`,
  2788  	}, {
  2789  		input:  `SELECT JSON_OVERLAPS('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', '$.a')`,
  2790  		output: `select json_overlaps('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', '$.a') from dual`,
  2791  	}, {
  2792  		input:  "SELECT JSON_OVERLAPS(@j, @k)",
  2793  		output: "select json_overlaps(@j, @k) from dual",
  2794  	}, {
  2795  		input:  "SELECT JSON_OVERLAPS(@j, BIN(1))",
  2796  		output: "select json_overlaps(@j, BIN(1)) from dual",
  2797  	}, {
  2798  		input:  "SELECT JSON_SEARCH(@j, 'one', 'abc')",
  2799  		output: "select json_search(@j, 'one', 'abc') from dual",
  2800  	}, {
  2801  		input:  `SELECT JSON_SEARCH('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', @j, BIN(2))`,
  2802  		output: `select json_search('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', @j, BIN(2)) from dual`,
  2803  	}, {
  2804  		input:  `SELECT JSON_SEARCH('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', 'all', '10', NULL)`,
  2805  		output: `select json_search('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', 'all', '10', null) from dual`,
  2806  	}, {
  2807  		input:  "SELECT JSON_SEARCH(@j, 'all', '%b%', '', '$[3]')",
  2808  		output: "select json_search(@j, 'all', '%b%', '', '$[3]') from dual",
  2809  	}, {
  2810  		input:  "SELECT JSON_SEARCH(@j, 'all', '%b%', 'a', '$[3]')",
  2811  		output: "select json_search(@j, 'all', '%b%', 'a', '$[3]') from dual",
  2812  	}, {
  2813  		input:  `SELECT JSON_VALUE('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', '$.a')`,
  2814  		output: `select json_value('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}', '$.a') from dual`,
  2815  	}, {
  2816  		input:  `SELECT JSON_VALUE(@j, @k)`,
  2817  		output: `select json_value(@j, @k) from dual`,
  2818  	}, {
  2819  		input:  `select json_value(@j, @k RETURNING FLOAT) from dual`,
  2820  		output: `select json_value(@j, @k returning FLOAT) from dual`,
  2821  	}, {
  2822  		input:  `select json_value(@j, @k RETURNING DECIMAL(4,2)) from dual`,
  2823  		output: `select json_value(@j, @k returning DECIMAL(4, 2)) from dual`,
  2824  	}, {
  2825  		input:  `SELECT JSON_VALUE('{"fname": "Joe", "lname": "Palmer"}', '$.fname' returning char(49) Charset utf8mb4 error on error)`,
  2826  		output: `select json_value('{\"fname\": \"Joe\", \"lname\": \"Palmer\"}', '$.fname' returning char(49) character set utf8mb4 error on error) from dual`,
  2827  	}, {
  2828  		input:  `SELECT JSON_VALUE('{"item": "shoes", "price": "49.95"}', '$.price' NULL ON EMPTY) `,
  2829  		output: `select json_value('{\"item\": \"shoes\", \"price\": \"49.95\"}', '$.price' null on empty) from dual`,
  2830  	}, {
  2831  		input:  `SELECT JSON_VALUE('{"item": "shoes", "price": "49.95"}', '$.price' NULL ON ERROR) `,
  2832  		output: `select json_value('{\"item\": \"shoes\", \"price\": \"49.95\"}', '$.price' null on error) from dual`,
  2833  	}, {
  2834  		input:  `SELECT JSON_VALUE('{"item": "shoes", "price": "49.95"}', '$.price' NULL ON EMPTY ERROR ON ERROR) `,
  2835  		output: `select json_value('{\"item\": \"shoes\", \"price\": \"49.95\"}', '$.price' null on empty error on error) from dual`,
  2836  	}, {
  2837  		input:  `select json_value(@j, @k RETURNING FLOAT NULL ON EMPTY ERROR ON ERROR) from dual`,
  2838  		output: `select json_value(@j, @k returning FLOAT null on empty error on error) from dual`,
  2839  	}, {
  2840  		input:  `SELECT 17 MEMBER OF ('[23, "abc", 17, "ab", 10]')`,
  2841  		output: `select 17 member of ('[23, \"abc\", 17, \"ab\", 10]') from dual`,
  2842  	}, {
  2843  		input:  "SELECT @j MEMBER OF (@k)",
  2844  		output: "select @j member of (@k) from dual",
  2845  	}, {
  2846  		input:  `SELECT 17 MEMBER OF('[23, "abc", "17", "ab", 10]'), "17" MEMBER OF('[23, "abc", 17, "ab", 10]')`,
  2847  		output: `select 17 member of ('[23, \"abc\", \"17\", \"ab\", 10]'), '17' member of ('[23, \"abc\", 17, \"ab\", 10]') from dual`,
  2848  	}, {
  2849  		input:  `SELECT JSON_DEPTH('{}'), JSON_DEPTH('[]'), JSON_DEPTH('true')`,
  2850  		output: `select json_depth('{}'), json_depth('[]'), json_depth('true') from dual`,
  2851  	}, {
  2852  		input:  `SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}')`,
  2853  		output: `select json_length('{\"a\": 1, \"b\": {\"c\": 30}}') from dual`,
  2854  	}, {
  2855  		input:  `SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}', '$.b');`,
  2856  		output: `select json_length('{\"a\": 1, \"b\": {\"c\": 30}}', '$.b') from dual`,
  2857  	}, {
  2858  		input:  `SELECT JSON_LENGTH('{\"a\": 1, \"b\": {\"c\": 30}}', @j);`,
  2859  		output: `select json_length('{\"a\": 1, \"b\": {\"c\": 30}}', @j) from dual`,
  2860  	}, {
  2861  		input:  `SELECT jcol, JSON_LENGTH(jcol)`,
  2862  		output: `select jcol, json_length(jcol) from dual`,
  2863  	}, {
  2864  		input:  "SELECT JSON_TYPE(@j)",
  2865  		output: "select json_type(@j) from dual",
  2866  	}, {
  2867  		input:  `SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]'))`,
  2868  		output: `select json_type(json_extract(@j, '$.a[0]')) from dual`,
  2869  	}, {
  2870  		input:  `SELECT JSON_VALID('{\"a\": 1}')`,
  2871  		output: `select json_valid('{\"a\": 1}') from dual`,
  2872  	}, {
  2873  		input:  "SELECT JSON_VALID(@j)",
  2874  		output: "select json_valid(@j) from dual",
  2875  	}, {
  2876  		input:  `SELECT JSON_ARRAY_APPEND('{ "a": 1, "b": [2, 3]}','$[1]', 'x')`,
  2877  		output: `select json_array_append('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x') from dual`,
  2878  	}, {
  2879  		input:  `SELECT JSON_ARRAY_APPEND('{ "a": 1, "b": [2, 3]}','$[1]', 'x', '$[2]', 1)`,
  2880  		output: `select json_array_append('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', '$[2]', 1) from dual`,
  2881  	}, {
  2882  		input:  `SELECT JSON_ARRAY_APPEND('{ "a": 1, "b": [2, 3]}','$[1]', 'x', @i, @j)`,
  2883  		output: `select json_array_append('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', @i, @j) from dual`,
  2884  	}, {
  2885  		input:  `SELECT JSON_ARRAY_APPEND('{ "a": 1, "b": [2, 3]}', @j, 1)`,
  2886  		output: `select json_array_append('{ \"a\": 1, \"b\": [2, 3]}', @j, 1) from dual`,
  2887  	}, {
  2888  		input:  `SELECT JSON_ARRAY_APPEND('{ "a": 1, "b": [2, 3]}', '$[1]', @j)`,
  2889  		output: `select json_array_append('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', @j) from dual`,
  2890  	}, {
  2891  		input:  `SELECT JSON_ARRAY_APPEND('{ "a": 1, "b": [2, 3]}', @j, @k)`,
  2892  		output: `select json_array_append('{ \"a\": 1, \"b\": [2, 3]}', @j, @k) from dual`,
  2893  	}, {
  2894  		input:  "SELECT JSON_ARRAY_APPEND(@i,@j,@k)",
  2895  		output: `select json_array_append(@i, @j, @k) from dual`,
  2896  	}, {
  2897  		input:  `SELECT JSON_ARRAY_INSERT('{ "a": 1, "b": [2, 3]}','$[1]', 'x')`,
  2898  		output: `select json_array_insert('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x') from dual`,
  2899  	}, {
  2900  		input:  `SELECT JSON_ARRAY_INSERT('{ "a": 1, "b": [2, 3]}','$[1]', 'x', '$[2]', 1)`,
  2901  		output: `select json_array_insert('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', '$[2]', 1) from dual`,
  2902  	}, {
  2903  		input:  `SELECT JSON_ARRAY_INSERT('{ "a": 1, "b": [2, 3]}','$[1]', 'x', @i, @j)`,
  2904  		output: `select json_array_insert('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', @i, @j) from dual`,
  2905  	}, {
  2906  		input:  `SELECT JSON_ARRAY_INSERT('{ "a": 1, "b": [2, 3]}', @j, 1)`,
  2907  		output: `select json_array_insert('{ \"a\": 1, \"b\": [2, 3]}', @j, 1) from dual`,
  2908  	}, {
  2909  		input:  `SELECT JSON_ARRAY_INSERT('{ "a": 1, "b": [2, 3]}', '$[1]', @j)`,
  2910  		output: `select json_array_insert('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', @j) from dual`,
  2911  	}, {
  2912  		input:  `SELECT JSON_ARRAY_INSERT('{ "a": 1, "b": [2, 3]}', @j, @k)`,
  2913  		output: `select json_array_insert('{ \"a\": 1, \"b\": [2, 3]}', @j, @k) from dual`,
  2914  	}, {
  2915  		input:  "SELECT JSON_ARRAY_INSERT(@i,@j,@k)",
  2916  		output: "select json_array_insert(@i, @j, @k) from dual",
  2917  	}, {
  2918  		input:  "SELECT JSON_ARRAY_INSERT(@j, '$[0]', 'x', '$[2][1]', 'y')",
  2919  		output: "select json_array_insert(@j, '$[0]', 'x', '$[2][1]', 'y') from dual",
  2920  	}, {
  2921  		input:  `SELECT JSON_INSERT('{ "a": 1, "b": [2, 3]}','$[1]', 'x')`,
  2922  		output: `select json_insert('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x') from dual`,
  2923  	}, {
  2924  		input:  `SELECT JSON_INSERT('{ "a": 1, "b": [2, 3]}','$[1]', 'x', '$[2]', 1)`,
  2925  		output: `select json_insert('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', '$[2]', 1) from dual`,
  2926  	}, {
  2927  		input:  `SELECT JSON_INSERT('{ "a": 1, "b": [2, 3]}','$[1]', 'x', @i, @j)`,
  2928  		output: `select json_insert('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', @i, @j) from dual`,
  2929  	}, {
  2930  		input:  `SELECT JSON_INSERT('{ "a": 1, "b": [2, 3]}', @j, 1)`,
  2931  		output: `select json_insert('{ \"a\": 1, \"b\": [2, 3]}', @j, 1) from dual`,
  2932  	}, {
  2933  		input:  `SELECT JSON_INSERT('{ "a": 1, "b": [2, 3]}', '$[1]', @j)`,
  2934  		output: `select json_insert('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', @j) from dual`,
  2935  	}, {
  2936  		input:  `SELECT JSON_INSERT('{ "a": 1, "b": [2, 3]}', @j, @k)`,
  2937  		output: `select json_insert('{ \"a\": 1, \"b\": [2, 3]}', @j, @k) from dual`,
  2938  	}, {
  2939  		input:  "SELECT JSON_INSERT(@i,@j,@k)",
  2940  		output: "select json_insert(@i, @j, @k) from dual",
  2941  	}, {
  2942  		input:  "SELECT JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]')",
  2943  		output: "select json_insert(@j, '$.a', 10, '$.c', '[true, false]') from dual",
  2944  	}, {
  2945  		input:  `SELECT JSON_REPLACE('{ "a": 1, "b": [2, 3]}','$[1]', 'x')`,
  2946  		output: `select json_replace('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x') from dual`,
  2947  	}, {
  2948  		input:  `SELECT JSON_REPLACE('{ "a": 1, "b": [2, 3]}','$[1]', 'x', '$[2]', 1)`,
  2949  		output: `select json_replace('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', '$[2]', 1) from dual`,
  2950  	}, {
  2951  		input:  `SELECT JSON_REPLACE('{ "a": 1, "b": [2, 3]}','$[1]', 'x', @i, @j)`,
  2952  		output: `select json_replace('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', @i, @j) from dual`,
  2953  	}, {
  2954  		input:  `SELECT JSON_REPLACE('{ "a": 1, "b": [2, 3]}', @j, 1)`,
  2955  		output: `select json_replace('{ \"a\": 1, \"b\": [2, 3]}', @j, 1) from dual`,
  2956  	}, {
  2957  		input:  `SELECT JSON_REPLACE('{ "a": 1, "b": [2, 3]}', '$[1]', @j)`,
  2958  		output: `select json_replace('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', @j) from dual`,
  2959  	}, {
  2960  		input:  `SELECT JSON_REPLACE('{ "a": 1, "b": [2, 3]}', @j, @k)`,
  2961  		output: `select json_replace('{ \"a\": 1, \"b\": [2, 3]}', @j, @k) from dual`,
  2962  	}, {
  2963  		input:  "SELECT JSON_REPLACE(@i,@j,@k)",
  2964  		output: "select json_replace(@i, @j, @k) from dual",
  2965  	}, {
  2966  		input:  "SELECT JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]')",
  2967  		output: "select json_replace(@j, '$.a', 10, '$.c', '[true, false]') from dual",
  2968  	}, {
  2969  		input:  `SELECT JSON_SET('{ "a": 1, "b": [2, 3]}','$[1]', 'x')`,
  2970  		output: `select json_set('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x') from dual`,
  2971  	}, {
  2972  		input:  `SELECT JSON_SET('{ "a": 1, "b": [2, 3]}','$[1]', 'x', '$[2]', 1)`,
  2973  		output: `select json_set('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', '$[2]', 1) from dual`,
  2974  	}, {
  2975  		input:  `SELECT JSON_SET('{ "a": 1, "b": [2, 3]}','$[1]', 'x', @i, @j)`,
  2976  		output: `select json_set('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', 'x', @i, @j) from dual`,
  2977  	}, {
  2978  		input:  `SELECT JSON_SET('{ "a": 1, "b": [2, 3]}', @j, 1)`,
  2979  		output: `select json_set('{ \"a\": 1, \"b\": [2, 3]}', @j, 1) from dual`,
  2980  	}, {
  2981  		input:  `SELECT JSON_SET('{ "a": 1, "b": [2, 3]}', '$[1]', @j)`,
  2982  		output: `select json_set('{ \"a\": 1, \"b\": [2, 3]}', '$[1]', @j) from dual`,
  2983  	}, {
  2984  		input:  `SELECT JSON_SET('{ "a": 1, "b": [2, 3]}', @j, @k)`,
  2985  		output: `select json_set('{ \"a\": 1, \"b\": [2, 3]}', @j, @k) from dual`,
  2986  	}, {
  2987  		input:  "SELECT JSON_SET(@i,@j,@k)",
  2988  		output: "select json_set(@i, @j, @k) from dual",
  2989  	}, {
  2990  		input:  "SELECT JSON_SET(@j, '$.a', 10, '$.c', '[true, false]')",
  2991  		output: "select json_set(@j, '$.a', 10, '$.c', '[true, false]') from dual",
  2992  	}, {
  2993  		input:  "SELECT JSON_MERGE('[1, 2]', '[true, false]')",
  2994  		output: "select json_merge('[1, 2]', '[true, false]') from dual",
  2995  	}, {
  2996  		input:  "SELECT JSON_MERGE('[1, 2]', '[true, false]', 'hello')",
  2997  		output: "select json_merge('[1, 2]', '[true, false]', 'hello') from dual",
  2998  	}, {
  2999  		input:  "SELECT JSON_MERGE('[1, 2]', @i)",
  3000  		output: "select json_merge('[1, 2]', @i) from dual",
  3001  	}, {
  3002  		input:  "SELECT JSON_MERGE(@i, @j)",
  3003  		output: "select json_merge(@i, @j) from dual",
  3004  	}, {
  3005  		input:  "SELECT JSON_MERGE(@i, @j, @k)",
  3006  		output: "select json_merge(@i, @j, @k) from dual",
  3007  	}, {
  3008  		input:  "SELECT JSON_MERGE(@i, '[true, false]')",
  3009  		output: "select json_merge(@i, '[true, false]') from dual",
  3010  	}, {
  3011  		input:  `SELECT JSON_MERGE_PATCH('{"name": "x"}', '{"id": 47}')`,
  3012  		output: `select json_merge_patch('{\"name\": \"x\"}', '{\"id\": 47}') from dual`,
  3013  	}, {
  3014  		input:  `SELECT JSON_MERGE_PATCH('{ "a": 1, "b":2 }','{ "a": 3, "c":4 }','{ "a": 5, "d":6 }');`,
  3015  		output: `select json_merge_patch('{ \"a\": 1, \"b\":2 }', '{ \"a\": 3, \"c\":4 }', '{ \"a\": 5, \"d\":6 }') from dual`,
  3016  	}, {
  3017  		input:  "SELECT JSON_MERGE_PATCH('[1, 2]', '[true, false]', 'hello')",
  3018  		output: "select json_merge_patch('[1, 2]', '[true, false]', 'hello') from dual",
  3019  	}, {
  3020  		input:  "SELECT JSON_MERGE_PATCH('[1, 2]', @i)",
  3021  		output: "select json_merge_patch('[1, 2]', @i) from dual",
  3022  	}, {
  3023  		input:  "SELECT JSON_MERGE_PATCH(@i, @j)",
  3024  		output: "select json_merge_patch(@i, @j) from dual",
  3025  	}, {
  3026  		input:  "SELECT JSON_MERGE_PATCH(@i, '[true, false]')",
  3027  		output: "select json_merge_patch(@i, '[true, false]') from dual",
  3028  	}, {
  3029  		input:  `SELECT JSON_MERGE_PRESERVE('{"name": "x"}', '{"id": 47}')`,
  3030  		output: `select json_merge_preserve('{\"name\": \"x\"}', '{\"id\": 47}') from dual`,
  3031  	}, {
  3032  		input:  `SELECT JSON_MERGE_PRESERVE('{ "a": 1, "b":2 }','{ "a": 3, "c":4 }','{ "a": 5, "d":6 }');`,
  3033  		output: `select json_merge_preserve('{ \"a\": 1, \"b\":2 }', '{ \"a\": 3, \"c\":4 }', '{ \"a\": 5, \"d\":6 }') from dual`,
  3034  	}, {
  3035  		input:  "SELECT JSON_MERGE_PRESERVE('[1, 2]', '[true, false]', 'hello')",
  3036  		output: "select json_merge_preserve('[1, 2]', '[true, false]', 'hello') from dual",
  3037  	}, {
  3038  		input:  "SELECT JSON_MERGE_PRESERVE('[1, 2]', @i)",
  3039  		output: "select json_merge_preserve('[1, 2]', @i) from dual",
  3040  	}, {
  3041  		input:  "SELECT JSON_MERGE_PRESERVE(@i, @j)",
  3042  		output: "select json_merge_preserve(@i, @j) from dual",
  3043  	}, {
  3044  		input:  "SELECT JSON_MERGE_PRESERVE(@i, '[true, false]')",
  3045  		output: "select json_merge_preserve(@i, '[true, false]') from dual",
  3046  	}, {
  3047  		input:  "SELECT JSON_REMOVE(@i, '$[1]')",
  3048  		output: "select json_remove(@i, '$[1]') from dual",
  3049  	}, {
  3050  		input:  `SELECT JSON_REMOVE('["a", ["b", "c"], "d"]', '$[1]')`,
  3051  		output: `select json_remove('[\"a\", [\"b\", \"c\"], \"d\"]', '$[1]') from dual`,
  3052  	}, {
  3053  		input:  `SELECT JSON_REMOVE('["a", ["b", "c"], "d"]', @i)`,
  3054  		output: `select json_remove('[\"a\", [\"b\", \"c\"], \"d\"]', @i) from dual`,
  3055  	}, {
  3056  		input:  `SELECT JSON_REMOVE('["a", ["b", "c"], "d"]', @i, @j, '$[0]', '$[1]','$[2]')`,
  3057  		output: `select json_remove('[\"a\", [\"b\", \"c\"], \"d\"]', @i, @j, '$[0]', '$[1]', '$[2]') from dual`,
  3058  	}, {
  3059  		input:  "SELECT JSON_UNQUOTE('abc')",
  3060  		output: "select json_unquote('abc') from dual",
  3061  	}, {
  3062  		input:  `SELECT JSON_UNQUOTE('\"\\\\t\\\\u0032\"')`,
  3063  		output: `select json_unquote('\"\\\\t\\\\u0032\"') from dual`,
  3064  	}, {
  3065  		input:  "SELECT JSON_UNQUOTE(@j)",
  3066  		output: "select json_unquote(@j) from dual",
  3067  	}, {
  3068  		input:  "CREATE TABLE ts (id INT, purchased DATE) PARTITION BY RANGE( YEAR(purchased) ) SUBPARTITION BY HASH( TO_DAYS(purchased) ) ( PARTITION p0 VALUES LESS THAN (1990) (SUBPARTITION s0,SUBPARTITION s1),PARTITION p1 VALUES LESS THAN (2000),PARTITION p2 VALUES LESS THAN MAXVALUE (SUBPARTITION s2,SUBPARTITION s3));",
  3069  		output: "create table ts (\n\tid INT,\n\tpurchased DATE\n)\npartition by range (YEAR(purchased)) subpartition by hash (TO_DAYS(purchased))\n(partition p0 values less than (1990) (subpartition s0, subpartition s1),\n partition p1 values less than (2000),\n partition p2 values less than maxvalue (subpartition s2, subpartition `s3`))",
  3070  	}, {
  3071  		input:  "SELECT REGEXP_INSTR('dog cat dog', 'dog')",
  3072  		output: "select regexp_instr('dog cat dog', 'dog') from dual",
  3073  	}, {
  3074  		input:  "SELECT REGEXP_INSTR('aa aaa aaaa aaaa aaaa aaaa', 'a{4}',1)",
  3075  		output: "select regexp_instr('aa aaa aaaa aaaa aaaa aaaa', 'a{4}', 1) from dual",
  3076  	}, {
  3077  		input:  "SELECT REGEXP_INSTR('aa aaa aaaa aaaa aaaa aaaa', 'a{4}',1,TRIM('2'))",
  3078  		output: "select regexp_instr('aa aaa aaaa aaaa aaaa aaaa', 'a{4}', 1, trim('2')) from dual",
  3079  	}, {
  3080  		input:  "SELECT REGEXP_INSTR('aa aaa aaaa aaaa aaaa aaaa', 'a{4}',1,TRIM('2'),0)",
  3081  		output: "select regexp_instr('aa aaa aaaa aaaa aaaa aaaa', 'a{4}', 1, trim('2'), 0) from dual",
  3082  	}, {
  3083  		input:  "SELECT REGEXP_INSTR('aa aaa aaaa aaaa aaaa aaaa', 'a{4}',1,TRIM('2'),0, 'c')",
  3084  		output: "select regexp_instr('aa aaa aaaa aaaa aaaa aaaa', 'a{4}', 1, trim('2'), 0, 'c') from dual",
  3085  	}, {
  3086  		input:  "SELECT REGEXP_LIKE('dog cat dog', 'dog')",
  3087  		output: "select regexp_like('dog cat dog', 'dog') from dual",
  3088  	}, {
  3089  		input:  "SELECT NOT REGEXP_LIKE('dog cat dog', 'dog')",
  3090  		output: "select not regexp_like('dog cat dog', 'dog') from dual",
  3091  	}, {
  3092  		input:  "SELECT REGEXP_LIKE('aa aaa aaaa aaaa aaaa aaaa', 'a{4}',1)",
  3093  		output: "select regexp_like('aa aaa aaaa aaaa aaaa aaaa', 'a{4}', 1) from dual",
  3094  	}, {
  3095  		input:  "SELECT REGEXP_REPLACE('a b c', 'b', 'X');",
  3096  		output: "select regexp_replace('a b c', 'b', 'X') from dual",
  3097  	}, {
  3098  		input:  "SELECT REGEXP_REPLACE('abc def ghi', '[a-z]+', 'X', 1);",
  3099  		output: "select regexp_replace('abc def ghi', '[a-z]+', 'X', 1) from dual",
  3100  	}, {
  3101  		input:  "SELECT REGEXP_REPLACE('abc def ghi', '[a-z]+', 'X', 1, 3);",
  3102  		output: "select regexp_replace('abc def ghi', '[a-z]+', 'X', 1, 3) from dual",
  3103  	}, {
  3104  		input:  "SELECT REGEXP_REPLACE('abc def ghi', '[a-z]+', 'X', 1, 3, 'c');",
  3105  		output: "select regexp_replace('abc def ghi', '[a-z]+', 'X', 1, 3, 'c') from dual",
  3106  	}, {
  3107  		input:  "SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+');",
  3108  		output: "select regexp_substr('abc def ghi', '[a-z]+') from dual",
  3109  	}, {
  3110  		input:  "SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1);",
  3111  		output: "select regexp_substr('abc def ghi', '[a-z]+', 1) from dual",
  3112  	}, {
  3113  		input:  "SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1, 3);",
  3114  		output: "select regexp_substr('abc def ghi', '[a-z]+', 1, 3) from dual",
  3115  	}, {
  3116  		input:  "SELECT REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1, 3, TRIM(' n '));",
  3117  		output: "select regexp_substr('abc def ghi', '[a-z]+', 1, 3, trim(' n ')) from dual",
  3118  	}, {
  3119  		input:  "SELECT 'Michael!' RLIKE '.*';",
  3120  		output: "select 'Michael!' regexp '.*' from dual",
  3121  	}, {
  3122  		input:  "SELECT TRIM('Michael!') RLIKE @j",
  3123  		output: "select trim('Michael!') regexp @j from dual",
  3124  	}, {
  3125  		input:  "SELECT INSERT('Quadratic', 3, 4, 'What')",
  3126  		output: "select insert('Quadratic', 3, 4, 'What') from dual",
  3127  	}, {
  3128  		input:  "SELECT INTERVAL(1, 3, 4)",
  3129  		output: "select interval(1, 3, 4) from dual",
  3130  	}, {
  3131  		input:  "SELECT POSITION('bar' IN 'foobarbar')",
  3132  		output: "select locate('bar', 'foobarbar') from dual",
  3133  	}, {
  3134  		input:  "SELECT CHAR(77,121,83,81,'76' USING utf8mb4)",
  3135  		output: "select char(77, 121, 83, 81, '76' using utf8mb4) from dual",
  3136  	}, {
  3137  		input:  "SELECT val, CUME_DIST() OVER w, ROW_NUMBER() OVER w, DENSE_RANK() OVER w, PERCENT_RANK() OVER w, RANK() OVER w AS 'cd' FROM numbers",
  3138  		output: "select val, cume_dist() over w, row_number() over w, dense_rank() over w, percent_rank() over w, rank() over w as cd from numbers",
  3139  	}, {
  3140  		input:  "SELECT year, country, product, profit, CUME_DIST() OVER() AS total_profit FROM sales",
  3141  		output: "select `year`, country, product, profit, cume_dist() over () as total_profit from sales",
  3142  	}, {
  3143  		input:  "SELECT val, CUME_DIST() OVER (ORDER BY val) AS 'cd' FROM numbers",
  3144  		output: "select val, cume_dist() over ( order by val asc) as cd from numbers",
  3145  	}, {
  3146  		input:  "SELECT val, CUME_DIST() OVER (PARTITION BY z ORDER BY val, subject DESC ROWS CURRENT ROW) AS 'cd' FROM numbers",
  3147  		output: "select val, cume_dist() over ( partition by z order by val asc, subject desc rows current row) as cd from numbers",
  3148  	}, {
  3149  		input:  "SELECT val, CUME_DIST() OVER (val PARTITION BY z, subject ORDER BY val, subject DESC ROWS CURRENT ROW) AS 'cd' FROM numbers",
  3150  		output: "select val, cume_dist() over ( val partition by z, subject order by val asc, subject desc rows current row) as cd from numbers",
  3151  	}, {
  3152  		input:  "SELECT val, FIRST_VALUE(val) OVER w FROM numbers",
  3153  		output: "select val, first_value(val) over w from numbers",
  3154  	}, {
  3155  		input:  "SELECT val, LAST_VALUE(val) IGNORE NULLS OVER w FROM numbers",
  3156  		output: "select val, last_value(val) ignore nulls over w from numbers",
  3157  	}, {
  3158  		input:  "SELECT NTILE(1) OVER w, NTILE(0) OVER w  FROM numbers",
  3159  		output: "select ntile(1) over w, ntile(0) over w from numbers",
  3160  	}, {
  3161  		input:  "SELECT NTILE(NULL) OVER w FROM numbers",
  3162  		output: "select ntile(null) over w from numbers",
  3163  	}, {
  3164  		input:  "SELECT NTILE(@val) OVER w FROM numbers",
  3165  		output: "select ntile(@val) over w from numbers",
  3166  	}, {
  3167  		input:  "SELECT NTH_VALUE(@z,1) OVER w, NTH_VALUE('val',0) OVER w FROM numbers",
  3168  		output: "select nth_value(@z, 1) over w, nth_value('val', 0) over w from numbers",
  3169  	}, {
  3170  		input:  "SELECT NTH_VALUE(val,NULL) FROM FIRST OVER w FROM numbers",
  3171  		output: "select nth_value(val, null) respect nulls over w from numbers",
  3172  	}, {
  3173  		input:  "SELECT NTH_VALUE(val,NULL) RESPECT NULLS OVER w FROM numbers",
  3174  		output: "select nth_value(val, null) respect nulls over w from numbers",
  3175  	}, {
  3176  		input:  "SELECT LAG(val) OVER w, LEAD(TRIM('abc')) OVER w FROM numbers",
  3177  		output: "select lag(val) over w, lead(trim('abc')) over w from numbers",
  3178  	}, {
  3179  		input:  "SELECT LAG(val, 10) OVER w, LEAD('val', null) OVER w, LEAD(val, 1, ASCII(1)) OVER w FROM numbers",
  3180  		output: "select lag(val, 10) over w, lead('val', null) over w, lead(val, 1, ASCII(1)) over w from numbers",
  3181  	}, {
  3182  		input:  "SELECT val, ROW_NUMBER() OVER (ORDER BY val) AS 'row_number' FROM numbers WINDOW w AS (ORDER BY val);",
  3183  		output: "select val, row_number() over ( order by val asc) as `row_number` from numbers window w AS ( order by val asc)",
  3184  	}, {
  3185  		input:  "SELECT time, subject, val, FIRST_VALUE(val)  OVER w AS 'first', LAST_VALUE(val) OVER w AS 'last', NTH_VALUE(val, 2) OVER w AS 'second', NTH_VALUE(val, 4) OVER w AS 'fourth' FROM observations WINDOW w AS (PARTITION BY subject ORDER BY time ROWS UNBOUNDED PRECEDING);",
  3186  		output: "select `time`, subject, val, first_value(val) over w as `first`, last_value(val) over w as `last`, nth_value(val, 2) over w as `second`, nth_value(val, 4) over w as fourth from observations window w AS ( partition by subject order by `time` asc rows unbounded preceding)",
  3187  	}, {
  3188  		input:  "SELECT time, subject, val, FIRST_VALUE(val)  OVER w AS 'first', LAST_VALUE(val) OVER w AS 'last', NTH_VALUE(val, 2) OVER w AS 'second', NTH_VALUE(val, 4) OVER w AS 'fourth' FROM observations WINDOW w AS (PARTITION BY subject ORDER BY time RANGE 10 PRECEDING);",
  3189  		output: "select `time`, subject, val, first_value(val) over w as `first`, last_value(val) over w as `last`, nth_value(val, 2) over w as `second`, nth_value(val, 4) over w as fourth from observations window w AS ( partition by subject order by `time` asc range 10 preceding)",
  3190  	}, {
  3191  		input:  "SELECT time, subject, val, FIRST_VALUE(val)  OVER w AS 'first', LAST_VALUE(val) OVER w AS 'last', NTH_VALUE(val, 2) OVER w AS 'second', NTH_VALUE(val, 4) OVER w AS 'fourth' FROM observations WINDOW w AS (PARTITION BY subject ORDER BY time ROWS INTERVAL 5 DAY PRECEDING);",
  3192  		output: "select `time`, subject, val, first_value(val) over w as `first`, last_value(val) over w as `last`, nth_value(val, 2) over w as `second`, nth_value(val, 4) over w as fourth from observations window w AS ( partition by subject order by `time` asc rows interval 5 DAY preceding)",
  3193  	}, {
  3194  		input:  "SELECT time, subject, val, FIRST_VALUE(val)  OVER w AS 'first', LAST_VALUE(val) OVER w AS 'last', NTH_VALUE(val, 2) OVER w AS 'second', NTH_VALUE(val, 4) OVER w AS 'fourth' FROM observations WINDOW w AS (PARTITION BY subject ORDER BY time RANGE 5 FOLLOWING);",
  3195  		output: "select `time`, subject, val, first_value(val) over w as `first`, last_value(val) over w as `last`, nth_value(val, 2) over w as `second`, nth_value(val, 4) over w as fourth from observations window w AS ( partition by subject order by `time` asc range 5 following)",
  3196  	}, {
  3197  		input:  "SELECT time, subject, val, FIRST_VALUE(val)  OVER w AS 'first', LAST_VALUE(val) OVER w AS 'last', NTH_VALUE(val, 2) OVER w AS 'second', NTH_VALUE(val, 4) OVER w AS 'fourth' FROM observations WINDOW w AS (PARTITION BY subject ORDER BY time ROWS INTERVAL '2:30' MINUTE_SECOND FOLLOWING);",
  3198  		output: "select `time`, subject, val, first_value(val) over w as `first`, last_value(val) over w as `last`, nth_value(val, 2) over w as `second`, nth_value(val, 4) over w as fourth from observations window w AS ( partition by subject order by `time` asc rows interval '2:30' MINUTE_SECOND following)",
  3199  	}, {
  3200  		input:  "SELECT time, subject, val, FIRST_VALUE(val)  OVER w AS 'first', LAST_VALUE(val) OVER w AS 'last', NTH_VALUE(val, 2) OVER w AS 'second', NTH_VALUE(val, 4) OVER w AS 'fourth' FROM observations WINDOW w AS (PARTITION BY subject ORDER BY time ASC RANGE BETWEEN 10 PRECEDING AND 10 FOLLOWING);",
  3201  		output: "select `time`, subject, val, first_value(val) over w as `first`, last_value(val) over w as `last`, nth_value(val, 2) over w as `second`, nth_value(val, 4) over w as fourth from observations window w AS ( partition by subject order by `time` asc range between 10 preceding and 10 following)",
  3202  	}, {
  3203  		input:  "SELECT ExtractValue('<a><b/></a>', '/a/b')",
  3204  		output: "select extractvalue('<a><b/></a>', '/a/b') from dual",
  3205  	}, {
  3206  		input:  "SELECT @i, ExtractValue(@xml, '//b[$@i]')",
  3207  		output: "select @i, extractvalue(@xml, '//b[$@i]') from dual",
  3208  	}, {
  3209  		input:  "SELECT ExtractValue(TRIM('<a><c/></a>'), 'count(/a/b)')",
  3210  		output: "select extractvalue(trim('<a><c/></a>'), 'count(/a/b)') from dual",
  3211  	}, {
  3212  		input:  "SELECT UpdateXML(@xml, '//b:c', '<g:h>555</g:h>')",
  3213  		output: "select updatexml(@xml, '//b:c', '<g:h>555</g:h>') from dual",
  3214  	}, {
  3215  		input:  "SELECT UpdateXML('<a><d></d><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') AS val5",
  3216  		output: "select updatexml('<a><d></d><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') as val5 from dual",
  3217  	}, {
  3218  		input: "select get_lock('a', 10), is_free_lock('b'), is_used_lock('c'), release_all_locks(), release_lock('d') from dual",
  3219  	}, {
  3220  		input: "select /* function with distinct */ count(a) from t",
  3221  	}, {
  3222  		input:  "select /* function with distinct */ count(a) 'total col' from t",
  3223  		output: "select /* function with distinct */ count(a) as `total col` from t",
  3224  	}, {
  3225  		input: "select /* function with distinct */ count(distinct a) from t",
  3226  	}, {
  3227  		input:  "select /* function with distinct */ count(distinct(a)) from t",
  3228  		output: "select /* function with distinct */ count(distinct a) from t",
  3229  	}, {
  3230  		input: "select /* function with distinct */ count(*) from t",
  3231  	}, {
  3232  		input: "select avg(a) from products",
  3233  	}, {
  3234  		input:  "select avg(distinct(a)) from products",
  3235  		output: "select avg(distinct a) from products",
  3236  	}, {
  3237  		input:  "select avg(a) 'Avg Price' from products",
  3238  		output: "select avg(a) as `Avg Price` from products",
  3239  	}, {
  3240  		input: "select format(avg(distinct a), 2) from products",
  3241  	}, {
  3242  		input: "select max(a) from products",
  3243  	}, {
  3244  		input: "select min(a) from products",
  3245  	}, {
  3246  		input: "select sum(a) from products",
  3247  	}, {
  3248  		input:  "select sum(distinct(a)) from products",
  3249  		output: "select sum(distinct a) from products",
  3250  	}, {
  3251  		input: "select sum(distinct a) from products",
  3252  	}, {
  3253  		input:  "select sum(a) 'sum Price' from products",
  3254  		output: "select sum(a) as `sum Price` from products",
  3255  	}, {
  3256  		input: "select sum(a * b) from products",
  3257  	}, {
  3258  		input: "select bit_and(a) from products",
  3259  	}, {
  3260  		input: "select bit_or(a) from products",
  3261  	}, {
  3262  		input: "select bit_xor(a) from products",
  3263  	}, {
  3264  		input: "select std(a) from products",
  3265  	}, {
  3266  		input: "select stddev(a) from products",
  3267  	}, {
  3268  		input: "select stddev_pop(a) from products",
  3269  	}, {
  3270  		input: "select stddev_samp(a) from products",
  3271  	}, {
  3272  		input: "select var_pop(a) from products",
  3273  	}, {
  3274  		input: "select var_samp(a) from products",
  3275  	}, {
  3276  		input: "select variance(a) from products",
  3277  	}, {
  3278  		input:  "SELECT FORMAT_BYTES(512), FORMAT_BYTES(18446644073709551615), FORMAT_BYTES(@j), FORMAT_BYTES('asd'), FORMAT_BYTES(TRIM('str'))",
  3279  		output: "select format_bytes(512), format_bytes(18446644073709551615), format_bytes(@j), format_bytes('asd'), format_bytes(trim('str')) from dual",
  3280  	}, {
  3281  		input:  "SELECT FORMAT_PICO_TIME(512), FORMAT_PICO_TIME(18446644073709551615), FORMAT_PICO_TIME(@j), FORMAT_PICO_TIME('asd'), FORMAT_PICO_TIME(TRIM('str'))",
  3282  		output: "select format_pico_time(512), format_pico_time(18446644073709551615), format_pico_time(@j), format_pico_time('asd'), format_pico_time(trim('str')) from dual",
  3283  	}, {
  3284  		input:  "SELECT PS_CURRENT_THREAD_ID()",
  3285  		output: "select ps_current_thread_id() from dual",
  3286  	}, {
  3287  		input:  "SELECT PS_THREAD_ID(512), PS_THREAD_ID(18446644073709551615), PS_THREAD_ID(@j), PS_THREAD_ID('asd'), PS_THREAD_ID(TRIM('str'))",
  3288  		output: "select ps_thread_id(512), ps_thread_id(18446644073709551615), ps_thread_id(@j), ps_thread_id('asd'), ps_thread_id(trim('str')) from dual",
  3289  	}, {
  3290  		input:  "SELECT GTID_SUBSET('3E11FA47-71CA-11E1-9E33-C80AA9429562:23','3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57')",
  3291  		output: "select gtid_subset('3E11FA47-71CA-11E1-9E33-C80AA9429562:23', '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57') from dual",
  3292  	}, {
  3293  		input:  "SELECT GTID_SUBSET(@j,TRIM('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'))",
  3294  		output: "select gtid_subset(@j, trim('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57')) from dual",
  3295  	}, {
  3296  		input:  "SELECT GTID_SUBTRACT('3E11FA47-71CA-11E1-9E33-C80AA9429562:23','3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57')",
  3297  		output: "select gtid_subtract('3E11FA47-71CA-11E1-9E33-C80AA9429562:23', '3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57') from dual",
  3298  	}, {
  3299  		input:  "SELECT GTID_SUBTRACT(@j,TRIM('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'))",
  3300  		output: "select gtid_subtract(@j, trim('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57')) from dual",
  3301  	}, {
  3302  		input:  "SELECT WAIT_FOR_EXECUTED_GTID_SET('3E11FA47-71CA-11E1-9E33-C80AA9429562:23')",
  3303  		output: "select wait_for_executed_gtid_set('3E11FA47-71CA-11E1-9E33-C80AA9429562:23') from dual",
  3304  	}, {
  3305  		input:  "SELECT WAIT_FOR_EXECUTED_GTID_SET(TRIM('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'), @j)",
  3306  		output: "select wait_for_executed_gtid_set(trim('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'), @j) from dual",
  3307  	}, {
  3308  		input:  "SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS('3E11FA47-71CA-11E1-9E33-C80AA9429562:23')",
  3309  		output: "select wait_until_sql_thread_after_gtids('3E11FA47-71CA-11E1-9E33-C80AA9429562:23') from dual",
  3310  	}, {
  3311  		input:  "SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(TRIM('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'), @j)",
  3312  		output: "select wait_until_sql_thread_after_gtids(trim('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'), @j) from dual",
  3313  	}, {
  3314  		input:  "SELECT WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(TRIM('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'), 10, @i)",
  3315  		output: "select wait_until_sql_thread_after_gtids(trim('3E11FA47-71CA-11E1-9E33-C80AA9429562:21-57'), 10, @i) from dual",
  3316  	}, {
  3317  		// Offset as part of expressions
  3318  		input: "select a, b from c where :1 + :2 = :302 and sum(:34) < :24",
  3319  	}, {
  3320  		input:  "select * from (((select 1))) as tbl",
  3321  		output: "select * from (select 1 from dual) as tbl",
  3322  	}, {
  3323  		input:  `select * from t1 where col1 like 'ks\%' and col2 = 'ks\%' and col1 like 'ks%' and col2 = 'ks%'`,
  3324  		output: `select * from t1 where col1 like 'ks\%' and col2 = 'ks\%' and col1 like 'ks%' and col2 = 'ks%'`,
  3325  	}, {
  3326  		input:  `select * from t1 where col1 like 'ks\_' and col2 = 'ks\_' and col1 like 'ks_' and col2 = 'ks_'`,
  3327  		output: `select * from t1 where col1 like 'ks\_' and col2 = 'ks\_' and col1 like 'ks_' and col2 = 'ks_'`,
  3328  	}}
  3329  )
  3330  
  3331  func TestValid(t *testing.T) {
  3332  	for _, tcase := range validSQL {
  3333  		t.Run(tcase.input, func(t *testing.T) {
  3334  			if tcase.output == "" {
  3335  				tcase.output = tcase.input
  3336  			}
  3337  			tree, err := Parse(tcase.input)
  3338  			require.NoError(t, err, tcase.input)
  3339  			out := String(tree)
  3340  			assert.Equal(t, tcase.output, out)
  3341  
  3342  			// Some statements currently only have 5.7 specifications.
  3343  			// For mysql 8.0 syntax, the query is not entirely parsed.
  3344  			// Add more structs as we go on adding full parsing support for DDL constructs for 5.7 syntax.
  3345  			switch x := tree.(type) {
  3346  			case DBDDLStatement:
  3347  				assert.Equal(t, !tcase.partialDDL, x.IsFullyParsed())
  3348  			case DDLStatement:
  3349  				assert.Equal(t, !tcase.partialDDL, x.IsFullyParsed())
  3350  			}
  3351  			// This test just exercises the tree walking functionality.
  3352  			// There's no way automated way to verify that a node calls
  3353  			// all its children. But we can examine code coverage and
  3354  			// ensure that all walkSubtree functions were called.
  3355  			_ = Walk(func(node SQLNode) (bool, error) {
  3356  				return true, nil
  3357  			}, tree)
  3358  		})
  3359  	}
  3360  }
  3361  
  3362  // Ensure there is no corruption from using a pooled yyParserImpl in Parse.
  3363  func TestParallelValid(t *testing.T) {
  3364  	parallelism := 100
  3365  	numIters := 1000
  3366  
  3367  	wg := sync.WaitGroup{}
  3368  	wg.Add(parallelism)
  3369  	for i := 0; i < parallelism; i++ {
  3370  		go func() {
  3371  			defer wg.Done()
  3372  			for j := 0; j < numIters; j++ {
  3373  				tcase := validSQL[rand.Intn(len(validSQL))]
  3374  				if tcase.output == "" {
  3375  					tcase.output = tcase.input
  3376  				}
  3377  				tree, err := Parse(tcase.input)
  3378  				if err != nil {
  3379  					t.Errorf("Parse(%q) err: %v, want nil", tcase.input, err)
  3380  					continue
  3381  				}
  3382  				out := String(tree)
  3383  				if out != tcase.output {
  3384  					t.Errorf("Parse(%q) = %q, want: %q", tcase.input, out, tcase.output)
  3385  				}
  3386  			}
  3387  		}()
  3388  	}
  3389  	wg.Wait()
  3390  }
  3391  
  3392  func TestInvalid(t *testing.T) {
  3393  	invalidSQL := []struct {
  3394  		input string
  3395  		err   string
  3396  	}{{
  3397  		input: "select a, b from (select * from tbl) sort by a",
  3398  		err:   "syntax error",
  3399  	}, {
  3400  		input: "/*!*/",
  3401  		err:   "Query was empty",
  3402  	}, {
  3403  		input: "select /* union with limit on lhs */ 1 from t limit 1 union select 1 from t",
  3404  		err:   "syntax error at position 60 near 'union'",
  3405  	}, {
  3406  		input: "(select * from t limit 100 into outfile s3 'out_file_name') union (select * from t2)",
  3407  		err:   "syntax error",
  3408  	}, {
  3409  		input: "select * from (select * from t into outfile s3 'inner_outfile') as t2 into outfile s3 'out_file_name'",
  3410  		err:   "syntax error at position 36 near 'into'",
  3411  	}, {
  3412  		input: "select a from x order by y union select a from c",
  3413  		err:   "syntax error",
  3414  	}, {
  3415  		input: "select `name`, numbers from (select * from users) as x()",
  3416  		err:   "syntax error at position 57",
  3417  	}, {
  3418  		input: "select next 2 values from seq union select next value from seq",
  3419  		err:   "syntax error at position 36 near 'union'",
  3420  	}, {
  3421  		input: "select next 2 values from user where id = 1",
  3422  		err:   "syntax error at position 37 near 'where'",
  3423  	}, {
  3424  		input: "select next 2 values from seq, seq",
  3425  		err:   "syntax error at position 31",
  3426  	}, {
  3427  		input: "select 1, next value from seq",
  3428  		err:   "syntax error",
  3429  	}, {
  3430  		input: "SELECT jcol, JSON_PRETTY(jcol, jcol) from jtable",
  3431  		err:   "syntax error at position 31",
  3432  	}, {
  3433  		input: "SELECT JSON_ARRAY(1,)",
  3434  		err:   "syntax error at position 22",
  3435  	}, {
  3436  		input: "SELECT JSON_OBJECT(1)",
  3437  		err:   "syntax error at position 22",
  3438  	}, {
  3439  		input: "SELECT JSON_OBJECT(1,2,)",
  3440  		err:   "syntax error at position 25",
  3441  	}, {
  3442  		input: "SELECT JSON_OBJECT(1,)",
  3443  		err:   "syntax error at position 23",
  3444  	}, {
  3445  		input: "SELECT JSON_QUOTE()",
  3446  		err:   "syntax error at position 20",
  3447  	}, {
  3448  		input: "select from t1, lateral (with qn as (select t1.a) select (select max(a) from qn)) as dt",
  3449  		err:   "syntax error at position 12 near 'from'",
  3450  	}, {
  3451  		input: `SELECT JSON_SCHEMA_VALID('{"type":"string","pattern":"("}')`,
  3452  		err:   `syntax error at position 60`,
  3453  	}, {
  3454  		input: `SELECT JSON_SCHEMA_VALIDATION_REPORT('{"type":"string","pattern":"("}')`,
  3455  		err:   `syntax error at position 72`,
  3456  	}, {
  3457  		input: "SELECT JSON_CONTAINS(@j, @j2, )",
  3458  		err:   "syntax error at position 32",
  3459  	}, {
  3460  		input: "SELECT JSON_CONTAINS_PATH(@j, @j2)",
  3461  		err:   "syntax error at position 35",
  3462  	}, {
  3463  		input: "SELECT JSON_EXTRACT(@k)",
  3464  		err:   "syntax error at position 24",
  3465  	}, {
  3466  		input: `SELECT JSON_KEYS('{\"a\": 1, \"b\": 2, \"c\": {\"d\": 4}}',)`,
  3467  		err:   `syntax error at position 61`,
  3468  	}, {
  3469  		input: "SELECT JSON_ARRAY_APPEND('{ \"a\": 1, \"b\": [2, 3]}')",
  3470  		err:   "syntax error at position 51",
  3471  	}, {
  3472  		input: "SELECT JSON_ARRAY_APPEND('{ \"a\": 1, \"b\": [2, 3]}','$[1]',)",
  3473  		err:   "syntax error at position 59",
  3474  	}, {
  3475  		input: "SELECT JSON_ARRAY_INSERT('{ \"a\": 1, \"b\": [2, 3]}')",
  3476  		err:   "syntax error at position 51",
  3477  	}, {
  3478  		input: "SELECT JSON_ARRAY_INSERT('{ \"a\": 1, \"b\": [2, 3]}','$[1]',)",
  3479  		err:   "syntax error at position 59",
  3480  	}, {
  3481  		input: "SELECT JSON_INSERT('{ \"a\": 1, \"b\": [2, 3]}')",
  3482  		err:   "syntax error at position 45",
  3483  	}, {
  3484  		input: "SELECT JSON_INSERT('{ \"a\": 1, \"b\": [2, 3]}','$[1]',)",
  3485  		err:   "syntax error at position 53",
  3486  	}, {
  3487  		input: "SELECT JSON_REPLACE('{ \"a\": 1, \"b\": [2, 3]}')",
  3488  		err:   "syntax error at position 46",
  3489  	}, {
  3490  		input: "SELECT JSON_REPLACE('{ \"a\": 1, \"b\": [2, 3]}','$[1]',)",
  3491  		err:   "syntax error at position 54",
  3492  	}, {
  3493  		input: "SELECT JSON_SET('{ \"a\": 1, \"b\": [2, 3]}')",
  3494  		err:   "syntax error at position 42",
  3495  	}, {
  3496  		input: "SELECT JSON_SET('{ \"a\": 1, \"b\": [2, 3]}','$[1]',)",
  3497  		err:   "syntax error at position 50",
  3498  	}, {
  3499  		input: "SELECT JSON_MERGE('[1, 2]')",
  3500  		err:   "syntax error at position 28",
  3501  	}, {
  3502  		input: "SELECT JSON_MERGE_PATCH('[1, 2]')",
  3503  		err:   "syntax error at position 34",
  3504  	}, {
  3505  		input: "SELECT JSON_MERGE_PRESERVE('[1, 2]')",
  3506  		err:   "syntax error at position 37",
  3507  	}, {
  3508  		input: "SELECT JSON_REMOVE('[\"a\", [\"b\", \"c\"], \"d\"]')",
  3509  		err:   "syntax error at position 45",
  3510  	}, {
  3511  		input: "SELECT NTILE('val') OVER w FROM numbers",
  3512  		err:   "syntax error at position 19 near 'val'",
  3513  	}, {
  3514  		input: "SELECT NTILE(-10) OVER w FROM numbers",
  3515  		err:   "syntax error at position 15",
  3516  	}, {
  3517  		input: "SELECT NTH_VALUE(val,) OVER w FROM numbers",
  3518  		err:   "syntax error at position 23",
  3519  	}, {
  3520  		input: "SELECT NTH_VALUE(TRIM('abc'),-10) OVER w FROM numbers",
  3521  		err:   "syntax error at position 31",
  3522  	}, {
  3523  		input: "SELECT LAG(val, ) OVER w",
  3524  		err:   "syntax error at position 18",
  3525  	}, {
  3526  		input: "SELECT LAG(val, 10,  ) OVER w",
  3527  		err:   "syntax error at position 23",
  3528  	}, {
  3529  		input: "SELECT time, subject, val, FIRST_VALUE(val)  OVER w AS 'first', LAST_VALUE(val) OVER w AS 'last', NTH_VALUE(val, 2) OVER w AS 'second', NTH_VALUE(val, 4) OVER w AS 'fourth' FROM observations WINDOW w AS (PARTITION BY subject ORDER BY time ROWS -10 FOLLOWING);",
  3530  		err:   "syntax error at position 246",
  3531  	}, {
  3532  		input: "SELECT BIT_AND(DISTINCT a) FROM products",
  3533  		err:   "syntax error at position 24 near 'DISTINCT'",
  3534  	}, {
  3535  		input: "SELECT BIT_OR(DISTINCT a) FROM products",
  3536  		err:   "syntax error at position 23 near 'DISTINCT'",
  3537  	}, {
  3538  		input: "SELECT BIT_XOR(DISTINCT a) FROM products",
  3539  		err:   "syntax error at position 24 near 'DISTINCT'",
  3540  	}, {
  3541  		input: "SELECT STD(DISTINCT a) FROM products",
  3542  		err:   "syntax error at position 20 near 'DISTINCT'",
  3543  	}, {
  3544  		input: "SELECT STDDEV(DISTINCT a) FROM products",
  3545  		err:   "syntax error at position 23 near 'DISTINCT'",
  3546  	}, {
  3547  		input: "SELECT STDDEV_POP(DISTINCT a) FROM products",
  3548  		err:   "syntax error at position 27 near 'DISTINCT'",
  3549  	}, {
  3550  		input: "SELECT STDDEV_SAMP(DISTINCT a) FROM products",
  3551  		err:   "syntax error at position 28 near 'DISTINCT'",
  3552  	}, {
  3553  		input: "SELECT VAR_POP(DISTINCT a) FROM products",
  3554  		err:   "syntax error at position 24 near 'DISTINCT'",
  3555  	}, {
  3556  		input: "SELECT VAR_SAMP(DISTINCT a) FROM products",
  3557  		err:   "syntax error at position 25 near 'DISTINCT'",
  3558  	}, {
  3559  		input: "SELECT VARIANCE(DISTINCT a) FROM products",
  3560  		err:   "syntax error at position 25 near 'DISTINCT'",
  3561  	}, {
  3562  		input: "SELECT COUNT(DISTINCT *) FROM user",
  3563  		err:   "syntax error at position 24",
  3564  	}, {
  3565  		input: "SELECT x'018' FROM user",
  3566  		err:   "syntax error at position 14",
  3567  	}, {
  3568  		input: "SELECT b'012' FROM user",
  3569  		err:   "syntax error at position 12",
  3570  	}, {
  3571  		input: "SELECT 0b2 FROM user",
  3572  		err:   "syntax error at position 11",
  3573  	},
  3574  	}
  3575  
  3576  	for _, tcase := range invalidSQL {
  3577  		t.Run(tcase.input, func(t *testing.T) {
  3578  			_, err := Parse(tcase.input)
  3579  			require.Error(t, err)
  3580  			require.Contains(t, err.Error(), tcase.err)
  3581  		})
  3582  	}
  3583  }
  3584  
  3585  func TestIntroducers(t *testing.T) {
  3586  	validSQL := []struct {
  3587  		input  string
  3588  		output string
  3589  	}{{
  3590  		input:  "select _armscii8 'x'",
  3591  		output: "select _armscii8 'x' from dual",
  3592  	}, {
  3593  		input:  "select _ascii 'x'",
  3594  		output: "select _ascii 'x' from dual",
  3595  	}, {
  3596  		input:  "select _big5 'x'",
  3597  		output: "select _big5 'x' from dual",
  3598  	}, {
  3599  		input:  "select _binary 'x'",
  3600  		output: "select _binary 'x' from dual",
  3601  	}, {
  3602  		input:  "select _cp1250 'x'",
  3603  		output: "select _cp1250 'x' from dual",
  3604  	}, {
  3605  		input:  "select _cp1251 'x'",
  3606  		output: "select _cp1251 'x' from dual",
  3607  	}, {
  3608  		input:  "select _cp1256 'x'",
  3609  		output: "select _cp1256 'x' from dual",
  3610  	}, {
  3611  		input:  "select _cp1257 'x'",
  3612  		output: "select _cp1257 'x' from dual",
  3613  	}, {
  3614  		input:  "select _cp850 'x'",
  3615  		output: "select _cp850 'x' from dual",
  3616  	}, {
  3617  		input:  "select _cp852 'x'",
  3618  		output: "select _cp852 'x' from dual",
  3619  	}, {
  3620  		input:  "select _cp866 'x'",
  3621  		output: "select _cp866 'x' from dual",
  3622  	}, {
  3623  		input:  "select _cp932 'x'",
  3624  		output: "select _cp932 'x' from dual",
  3625  	}, {
  3626  		input:  "select _dec8 'x'",
  3627  		output: "select _dec8 'x' from dual",
  3628  	}, {
  3629  		input:  "select _eucjpms 'x'",
  3630  		output: "select _eucjpms 'x' from dual",
  3631  	}, {
  3632  		input:  "select _euckr 'x'",
  3633  		output: "select _euckr 'x' from dual",
  3634  	}, {
  3635  		input:  "select _gb18030 'x'",
  3636  		output: "select _gb18030 'x' from dual",
  3637  	}, {
  3638  		input:  "select _gb2312 'x'",
  3639  		output: "select _gb2312 'x' from dual",
  3640  	}, {
  3641  		input:  "select _gbk 'x'",
  3642  		output: "select _gbk 'x' from dual",
  3643  	}, {
  3644  		input:  "select _geostd8 'x'",
  3645  		output: "select _geostd8 'x' from dual",
  3646  	}, {
  3647  		input:  "select _greek 'x'",
  3648  		output: "select _greek 'x' from dual",
  3649  	}, {
  3650  		input:  "select _hebrew 'x'",
  3651  		output: "select _hebrew 'x' from dual",
  3652  	}, {
  3653  		input:  "select _hp8 'x'",
  3654  		output: "select _hp8 'x' from dual",
  3655  	}, {
  3656  		input:  "select _keybcs2 'x'",
  3657  		output: "select _keybcs2 'x' from dual",
  3658  	}, {
  3659  		input:  "select _koi8r 'x'",
  3660  		output: "select _koi8r 'x' from dual",
  3661  	}, {
  3662  		input:  "select _koi8u 'x'",
  3663  		output: "select _koi8u 'x' from dual",
  3664  	}, {
  3665  		input:  "select _latin1 'x'",
  3666  		output: "select _latin1 'x' from dual",
  3667  	}, {
  3668  		input:  "select _latin2 'x'",
  3669  		output: "select _latin2 'x' from dual",
  3670  	}, {
  3671  		input:  "select _latin5 'x'",
  3672  		output: "select _latin5 'x' from dual",
  3673  	}, {
  3674  		input:  "select _latin7 'x'",
  3675  		output: "select _latin7 'x' from dual",
  3676  	}, {
  3677  		input:  "select _macce 'x'",
  3678  		output: "select _macce 'x' from dual",
  3679  	}, {
  3680  		input:  "select _macroman 'x'",
  3681  		output: "select _macroman 'x' from dual",
  3682  	}, {
  3683  		input:  "select _sjis 'x'",
  3684  		output: "select _sjis 'x' from dual",
  3685  	}, {
  3686  		input:  "select _swe7 'x'",
  3687  		output: "select _swe7 'x' from dual",
  3688  	}, {
  3689  		input:  "select _tis620 'x'",
  3690  		output: "select _tis620 'x' from dual",
  3691  	}, {
  3692  		input:  "select _ucs2 'x'",
  3693  		output: "select _ucs2 'x' from dual",
  3694  	}, {
  3695  		input:  "select _ujis 'x'",
  3696  		output: "select _ujis 'x' from dual",
  3697  	}, {
  3698  		input:  "select _utf16 'x'",
  3699  		output: "select _utf16 'x' from dual",
  3700  	}, {
  3701  		input:  "select _utf16le 'x'",
  3702  		output: "select _utf16le 'x' from dual",
  3703  	}, {
  3704  		input:  "select _utf32 'x'",
  3705  		output: "select _utf32 'x' from dual",
  3706  	}, {
  3707  		input:  "select _utf8 'x'",
  3708  		output: "select _utf8 'x' from dual",
  3709  	}, {
  3710  		input:  "select _utf8mb4 'x'",
  3711  		output: "select _utf8mb4 'x' from dual",
  3712  	}, {
  3713  		input:  "select _utf8mb3 'x'",
  3714  		output: "select _utf8 'x' from dual",
  3715  	}}
  3716  	for _, tcase := range validSQL {
  3717  		t.Run(tcase.input, func(t *testing.T) {
  3718  			if tcase.output == "" {
  3719  				tcase.output = tcase.input
  3720  			}
  3721  			tree, err := Parse(tcase.input)
  3722  			assert.NoError(t, err)
  3723  			out := String(tree)
  3724  			assert.Equal(t, tcase.output, out)
  3725  		})
  3726  	}
  3727  }
  3728  
  3729  func TestCaseSensitivity(t *testing.T) {
  3730  	validSQL := []struct {
  3731  		input  string
  3732  		output string
  3733  	}{{
  3734  		input:  "create table A (\n\t`B` int\n)",
  3735  		output: "create table A (\n\tB int\n)",
  3736  	}, {
  3737  		input:  "create index b on A (col1 desc)",
  3738  		output: "alter table A add index b (col1 desc)",
  3739  	}, {
  3740  		input:  "alter table A foo",
  3741  		output: "alter table A",
  3742  	}, {
  3743  		input:  "alter table A convert unparsable",
  3744  		output: "alter table A",
  3745  	}, {
  3746  		// View names get lower-cased.
  3747  		input:  "alter view A as select * from t",
  3748  		output: "alter view a as select * from t",
  3749  	}, {
  3750  		input:  "alter table A rename to B",
  3751  		output: "alter table A rename B",
  3752  	}, {
  3753  		input:  "alter table `A r` rename to `B r`",
  3754  		output: "alter table `A r` rename `B r`",
  3755  	}, {
  3756  		input: "rename table A to B",
  3757  	}, {
  3758  		input:  "drop table B",
  3759  		output: "drop table B",
  3760  	}, {
  3761  		input:  "drop table if exists B",
  3762  		output: "drop table if exists B",
  3763  	}, {
  3764  		input:  "drop index b on A",
  3765  		output: "alter table A drop key b",
  3766  	}, {
  3767  		input: "select a from B",
  3768  	}, {
  3769  		input: "select A as B from C",
  3770  	}, {
  3771  		input: "select B.* from c",
  3772  	}, {
  3773  		input: "select B.A from c",
  3774  	}, {
  3775  		input: "select * from B as C",
  3776  	}, {
  3777  		input: "select * from A.B",
  3778  	}, {
  3779  		input: "update A set b = 1",
  3780  	}, {
  3781  		input: "update A.B set b = 1",
  3782  	}, {
  3783  		input: "select A() from b",
  3784  	}, {
  3785  		input: "select A(B, C) from b",
  3786  	}, {
  3787  		// IF is an exception. It's always lower-cased.
  3788  		input:  "select IF(B, C) from b",
  3789  		output: "select if(B, C) from b",
  3790  	}, {
  3791  		input: "select * from b use index (A)",
  3792  	}, {
  3793  		input: "insert into A(A, B) values (1, 2)",
  3794  	}, {
  3795  		input:  "CREATE TABLE A (\n\t`A` int\n)",
  3796  		output: "create table A (\n\tA int\n)",
  3797  	}, {
  3798  		input:  "create view A as select * from b",
  3799  		output: "create view a as select * from b",
  3800  	}, {
  3801  		input:  "drop view A",
  3802  		output: "drop view a",
  3803  	}, {
  3804  		input:  "drop view if exists A",
  3805  		output: "drop view if exists a",
  3806  	}, {
  3807  		input:  "select /* lock in SHARE MODE */ 1 from t lock in SHARE MODE",
  3808  		output: "select /* lock in SHARE MODE */ 1 from t lock in share mode",
  3809  	}, {
  3810  		input:  "select next VALUE from t",
  3811  		output: "select next 1 values from t",
  3812  	}, {
  3813  		input: "select /* use */ 1 from t1 use index (A) where b = 1",
  3814  	}}
  3815  	for _, tcase := range validSQL {
  3816  		if tcase.output == "" {
  3817  			tcase.output = tcase.input
  3818  		}
  3819  		tree, err := Parse(tcase.input)
  3820  		if err != nil {
  3821  			t.Errorf("input: %s, err: %v", tcase.input, err)
  3822  			continue
  3823  		}
  3824  		out := String(tree)
  3825  		if out != tcase.output {
  3826  			t.Errorf("out: %s, want %s", out, tcase.output)
  3827  		}
  3828  	}
  3829  }
  3830  
  3831  func TestKeywords(t *testing.T) {
  3832  	validSQL := []struct {
  3833  		input  string
  3834  		output string
  3835  	}{{
  3836  		input:  "select current_timestamp",
  3837  		output: "select current_timestamp() from dual",
  3838  	}, {
  3839  		input: "update t set a = current_timestamp()",
  3840  	}, {
  3841  		input: "update t set a = current_timestamp(5)",
  3842  	}, {
  3843  		input:  "select a, current_date from t",
  3844  		output: "select a, current_date() from t",
  3845  	}, {
  3846  		input:  "insert into t(a, b) values (current_date, current_date())",
  3847  		output: "insert into t(a, b) values (current_date(), current_date())",
  3848  	}, {
  3849  		input: "select * from t where a > utc_timestmp()",
  3850  	}, {
  3851  		input: "select * from t where a > utc_timestamp(4)",
  3852  	}, {
  3853  		input:  "update t set b = utc_timestamp + 5",
  3854  		output: "update t set b = utc_timestamp() + 5",
  3855  	}, {
  3856  		input:  "select utc_time, utc_date, utc_time(6)",
  3857  		output: "select utc_time(), utc_date(), utc_time(6) from dual",
  3858  	}, {
  3859  		input:  "select 1 from dual where localtime > utc_time",
  3860  		output: "select 1 from dual where localtime() > utc_time()",
  3861  	}, {
  3862  		input:  "select 1 from dual where localtime(2) > utc_time(1)",
  3863  		output: "select 1 from dual where localtime(2) > utc_time(1)",
  3864  	}, {
  3865  		input:  "update t set a = localtimestamp(), b = utc_timestamp",
  3866  		output: "update t set a = localtimestamp(), b = utc_timestamp()",
  3867  	}, {
  3868  		input:  "update t set a = localtimestamp(10), b = utc_timestamp(13)",
  3869  		output: "update t set a = localtimestamp(10), b = utc_timestamp(13)",
  3870  	}, {
  3871  		input: "insert into t(a) values (unix_timestamp)",
  3872  	}, {
  3873  		input: "select replace(a, 'foo', 'bar') from t",
  3874  	}, {
  3875  		input: "update t set a = replace('1234', '2', '1')",
  3876  	}, {
  3877  		input: "insert into t(a, b) values ('foo', 'bar') on duplicate key update a = replace(hex('foo'), 'f', 'b')",
  3878  	}, {
  3879  		input: "update t set a = left('1234', 3)",
  3880  	}, {
  3881  		input: "select left(a, 5) from t",
  3882  	}, {
  3883  		input: "update t set d = adddate(date('2003-12-31 01:02:03'), interval 5 days)",
  3884  	}, {
  3885  		input: "insert into t(a, b) values (left('foo', 1), 'b')",
  3886  	}, {
  3887  		input: "insert /* qualified function */ into t(a, b) values (test.PI(), 'b')",
  3888  	}, {
  3889  		input:  "select /* keyword in qualified id */ * from t join z on t.key = z.key",
  3890  		output: "select /* keyword in qualified id */ * from t join z on t.`key` = z.`key`",
  3891  	}, {
  3892  		input:  "select /* non-reserved keywords as unqualified cols */ date, view, offset from t",
  3893  		output: "select /* non-reserved keywords as unqualified cols */ `date`, `view`, `offset` from t",
  3894  	}, {
  3895  		input:  "select /* share and mode as cols */ share, mode from t where share = 'foo'",
  3896  		output: "select /* share and mode as cols */ `share`, `mode` from t where `share` = 'foo'",
  3897  	}, {
  3898  		input:  "select status from t",
  3899  		output: "select `status` from t",
  3900  	}, {
  3901  		input:  "select Status from t",
  3902  		output: "select `Status` from t",
  3903  	}, {
  3904  		input:  "select variables from t",
  3905  		output: "select `variables` from t",
  3906  	}, {
  3907  		input:  "select Variables from t",
  3908  		output: "select `Variables` from t",
  3909  	}, {
  3910  		input:  "select current_user, current_user() from dual",
  3911  		output: "select current_user(), current_user() from dual",
  3912  	}}
  3913  
  3914  	for _, tcase := range validSQL {
  3915  		if tcase.output == "" {
  3916  			tcase.output = tcase.input
  3917  		}
  3918  		tree, err := Parse(tcase.input)
  3919  		if err != nil {
  3920  			t.Errorf("input: %s, err: %v", tcase.input, err)
  3921  			continue
  3922  		}
  3923  		out := String(tree)
  3924  		if out != tcase.output {
  3925  			t.Errorf("out: %s, want %s", out, tcase.output)
  3926  		}
  3927  	}
  3928  }
  3929  
  3930  func TestConvert(t *testing.T) {
  3931  	validSQL := []struct {
  3932  		input  string
  3933  		output string
  3934  	}{{
  3935  		input: "select cast('abc' as date) from t",
  3936  	}, {
  3937  		input: "select convert('abc', binary(4)) from t",
  3938  	}, {
  3939  		input: "select convert('abc', binary) from t",
  3940  	}, {
  3941  		input: "select convert('abc', char character set binary) from t",
  3942  	}, {
  3943  		input:  "select convert('abc', char(4) ascii) from t",
  3944  		output: "select convert('abc', char(4) character set latin1) from t",
  3945  	}, {
  3946  		input:  "select convert('abc', char(4) ascii binary) from t",
  3947  		output: "select convert('abc', char(4) character set latin1 binary) from t",
  3948  	}, {
  3949  		input:  "select convert('abc', char unicode) from t",
  3950  		output: "select convert('abc', char character set ucs2) from t",
  3951  	}, {
  3952  		input: "select convert('abc', char(4)) from t",
  3953  	}, {
  3954  		input: "select convert('abc', char) from t",
  3955  	}, {
  3956  		input: "select convert('abc', nchar(4)) from t",
  3957  	}, {
  3958  		input: "select convert('abc', nchar) from t",
  3959  	}, {
  3960  		input: "select convert('abc', signed) from t",
  3961  	}, {
  3962  		input:  "select convert('abc', signed integer) from t",
  3963  		output: "select convert('abc', signed) from t",
  3964  	}, {
  3965  		input: "select convert('abc', unsigned) from t",
  3966  	}, {
  3967  		input:  "select convert('abc', unsigned integer) from t",
  3968  		output: "select convert('abc', unsigned) from t",
  3969  	}, {
  3970  		input: "select convert('abc', decimal(3, 4)) from t",
  3971  	}, {
  3972  		input: "select convert('abc', decimal(4)) from t",
  3973  	}, {
  3974  		input: "select convert('abc', decimal) from t",
  3975  	}, {
  3976  		input: "select convert('abc', date) from t",
  3977  	}, {
  3978  		input: "select convert('abc', time(4)) from t",
  3979  	}, {
  3980  		input: "select convert('abc', time) from t",
  3981  	}, {
  3982  		input: "select convert('abc', datetime(9)) from t",
  3983  	}, {
  3984  		input: "select convert('abc', datetime) from t",
  3985  	}, {
  3986  		input: "select convert('abc', json) from t",
  3987  	}, {
  3988  		input: "select cast(json_keys(c) as char(64) array) from t",
  3989  	}}
  3990  
  3991  	for _, tcase := range validSQL {
  3992  		if tcase.output == "" {
  3993  			tcase.output = tcase.input
  3994  		}
  3995  		tree, err := Parse(tcase.input)
  3996  		if err != nil {
  3997  			t.Errorf("input: %s, err: %v", tcase.input, err)
  3998  			continue
  3999  		}
  4000  		out := String(tree)
  4001  		if out != tcase.output {
  4002  			t.Errorf("out: %s, want %s", out, tcase.output)
  4003  		}
  4004  	}
  4005  
  4006  	invalidSQL := []struct {
  4007  		input  string
  4008  		output string
  4009  	}{{
  4010  		input:  "select convert('abc' as date) from t",
  4011  		output: "syntax error at position 24 near 'as'",
  4012  	}, {
  4013  		input:  "select convert from t",
  4014  		output: "syntax error at position 20 near 'from'",
  4015  	}, {
  4016  		input:  "select cast('foo', decimal) from t",
  4017  		output: "syntax error at position 19",
  4018  	}, {
  4019  		input:  "select convert('abc', datetime(4+9)) from t",
  4020  		output: "syntax error at position 34",
  4021  	}, {
  4022  		input:  "select convert('abc', decimal(4+9)) from t",
  4023  		output: "syntax error at position 33",
  4024  	}, {
  4025  		input:  "set transaction isolation level 12345",
  4026  		output: "syntax error at position 38 near '12345'",
  4027  	}, {
  4028  		input:  "@",
  4029  		output: "syntax error at position 2",
  4030  	}, {
  4031  		input:  "@@",
  4032  		output: "syntax error at position 3",
  4033  	}, {
  4034  		input:  "select A(distinct B, C) from b",
  4035  		output: "syntax error at position 18 near 'distinct'",
  4036  	}}
  4037  
  4038  	for _, tcase := range invalidSQL {
  4039  		_, err := Parse(tcase.input)
  4040  		if err == nil || err.Error() != tcase.output {
  4041  			t.Errorf("%s: %v, want %s", tcase.input, err, tcase.output)
  4042  		}
  4043  	}
  4044  }
  4045  
  4046  func TestSelectInto(t *testing.T) {
  4047  	validSQL := []struct {
  4048  		input  string
  4049  		output string
  4050  	}{{
  4051  		input:  "select * from t order by name limit 100 into outfile s3 'out_file_name'",
  4052  		output: "select * from t order by `name` asc limit 100 into outfile s3 'out_file_name'",
  4053  	}, {
  4054  		input: `select * from TestPerson into outfile s3 's3://test-bucket/export_import/export/users.csv' fields terminated by ',' enclosed by '\"' escaped by '\\' overwrite on`,
  4055  	}, {
  4056  		input: "select * from t into dumpfile 'out_file_name'",
  4057  	}, {
  4058  		input: "select * from t into outfile 'out_file_name' character set binary fields terminated by 'term' optionally enclosed by 'c' escaped by 'e' lines starting by 'a' terminated by '\\n'",
  4059  	}, {
  4060  		input: "select * from t into outfile s3 'out_file_name' character set binary format csv header fields terminated by 'term' optionally enclosed by 'c' escaped by 'e' lines starting by 'a' terminated by '\\n' manifest on overwrite off",
  4061  	}, {
  4062  		input: "select * from t into outfile s3 'out_file_name' character set binary lines terminated by '\\n' starting by 'a' manifest on overwrite off",
  4063  	}, {
  4064  		input:  "select * from (select * from t union select * from t2) as t3 where t3.name in (select col from t4) into outfile s3 'out_file_name'",
  4065  		output: "select * from (select * from t union select * from t2) as t3 where t3.`name` in (select col from t4) into outfile s3 'out_file_name'",
  4066  	}, {
  4067  		input: `select * from TestPerson into outfile s3 's3://test-bucket/export_import/export/users.csv' character set 'utf8' overwrite on`,
  4068  	}, {
  4069  		input: `select * from t1 into outfile '/tmp/foo.csv' fields escaped by '\\' terminated by '\n'`,
  4070  	}, {
  4071  		input: `select * from t1 into outfile '/tmp/foo.csv' fields escaped by 'c' terminated by '\n' enclosed by '\t'`,
  4072  	}, {
  4073  		input:  `alter vschema create vindex my_vdx using hash`,
  4074  		output: "alter vschema create vindex my_vdx using `hash`",
  4075  	}}
  4076  
  4077  	for _, tcase := range validSQL {
  4078  		t.Run(tcase.input, func(t *testing.T) {
  4079  			if tcase.output == "" {
  4080  				tcase.output = tcase.input
  4081  			}
  4082  			tree, err := Parse(tcase.input)
  4083  			require.NoError(t, err)
  4084  			out := String(tree)
  4085  			assert.Equal(t, tcase.output, out)
  4086  		})
  4087  	}
  4088  
  4089  	invalidSQL := []struct {
  4090  		input  string
  4091  		output string
  4092  	}{{
  4093  		input:  "select convert('abc' as date) from t",
  4094  		output: "syntax error at position 24 near 'as'",
  4095  	}, {
  4096  		input:  "set transaction isolation level 12345",
  4097  		output: "syntax error at position 38 near '12345'",
  4098  	}}
  4099  
  4100  	for _, tcase := range invalidSQL {
  4101  		_, err := Parse(tcase.input)
  4102  		if err == nil || err.Error() != tcase.output {
  4103  			t.Errorf("%s: %v, want %s", tcase.input, err, tcase.output)
  4104  		}
  4105  	}
  4106  }
  4107  
  4108  func TestPositionedErr(t *testing.T) {
  4109  	invalidSQL := []struct {
  4110  		input  string
  4111  		output PositionedErr
  4112  	}{{
  4113  		input:  "select convert('abc' as date) from t",
  4114  		output: PositionedErr{"syntax error", 24, "as"},
  4115  	}, {
  4116  		input:  "select convert from t",
  4117  		output: PositionedErr{"syntax error", 20, "from"},
  4118  	}, {
  4119  		input:  "select cast('foo', decimal) from t",
  4120  		output: PositionedErr{"syntax error", 19, ""},
  4121  	}, {
  4122  		input:  "select convert('abc', datetime(4+9)) from t",
  4123  		output: PositionedErr{"syntax error", 34, ""},
  4124  	}, {
  4125  		input:  "select convert('abc', decimal(4+9)) from t",
  4126  		output: PositionedErr{"syntax error", 33, ""},
  4127  	}, {
  4128  		input:  "set transaction isolation level 12345",
  4129  		output: PositionedErr{"syntax error", 38, "12345"},
  4130  	}, {
  4131  		input:  "select * from a left join b",
  4132  		output: PositionedErr{"syntax error", 28, ""},
  4133  	}, {
  4134  		input:  "select a from (select * from tbl)",
  4135  		output: PositionedErr{"syntax error", 34, ""},
  4136  	}}
  4137  
  4138  	for _, tcase := range invalidSQL {
  4139  		tkn := NewStringTokenizer(tcase.input)
  4140  		_, err := ParseNext(tkn)
  4141  
  4142  		if posErr, ok := err.(PositionedErr); !ok {
  4143  			t.Errorf("%s: %v expected PositionedErr, got (%T) %v", tcase.input, err, err, tcase.output)
  4144  		} else if posErr.Pos != tcase.output.Pos || posErr.Near != tcase.output.Near || err.Error() != tcase.output.Error() {
  4145  			t.Errorf("%s: %v, want: %v", tcase.input, err, tcase.output)
  4146  		}
  4147  	}
  4148  }
  4149  
  4150  func TestSubStr(t *testing.T) {
  4151  
  4152  	validSQL := []struct {
  4153  		input  string
  4154  		output string
  4155  	}{{
  4156  		input: `select substr('foobar', 1) from t`,
  4157  	}, {
  4158  		input: "select substr(a, 1, 6) from t",
  4159  	}, {
  4160  		input:  "select substring(a, 1) from t",
  4161  		output: "select substr(a, 1) from t",
  4162  	}, {
  4163  		input:  "select substring(a, 1, 6) from t",
  4164  		output: "select substr(a, 1, 6) from t",
  4165  	}, {
  4166  		input:  "select substr(a from 1 for 6) from t",
  4167  		output: "select substr(a, 1, 6) from t",
  4168  	}, {
  4169  		input:  "select substring(a from 1 for 6) from t",
  4170  		output: "select substr(a, 1, 6) from t",
  4171  	}, {
  4172  		input:  `select substr("foo" from 1 for 2) from t`,
  4173  		output: `select substr('foo', 1, 2) from t`,
  4174  	}, {
  4175  		input:  `select substring("foo", 1, 2) from t`,
  4176  		output: `select substr('foo', 1, 2) from t`,
  4177  	}, {
  4178  		input:  `select substr(substr("foo" from 1 for 2), 1, 2) from t`,
  4179  		output: `select substr(substr('foo', 1, 2), 1, 2) from t`,
  4180  	}, {
  4181  		input:  `select substr(substring("foo", 1, 2), 3, 4) from t`,
  4182  		output: `select substr(substr('foo', 1, 2), 3, 4) from t`,
  4183  	}, {
  4184  		input:  `select substring(substr("foo", 1), 2) from t`,
  4185  		output: `select substr(substr('foo', 1), 2) from t`,
  4186  	}}
  4187  
  4188  	for _, tcase := range validSQL {
  4189  		if tcase.output == "" {
  4190  			tcase.output = tcase.input
  4191  		}
  4192  		tree, err := Parse(tcase.input)
  4193  		if err != nil {
  4194  			t.Errorf("input: %s, err: %v", tcase.input, err)
  4195  			continue
  4196  		}
  4197  		out := String(tree)
  4198  		if out != tcase.output {
  4199  			t.Errorf("out: %s, want %s", out, tcase.output)
  4200  		}
  4201  	}
  4202  }
  4203  
  4204  func TestLoadData(t *testing.T) {
  4205  	validSQL := []string{
  4206  		"load data from s3 'x.txt'",
  4207  		"load data from s3 manifest 'x.txt'",
  4208  		"load data from s3 file 'x.txt'",
  4209  		"load data infile 'x.txt' into table 'c'",
  4210  		"load data from s3 'x.txt' into table x"}
  4211  
  4212  	for _, tcase := range validSQL {
  4213  		_, err := Parse(tcase)
  4214  		require.NoError(t, err)
  4215  	}
  4216  }
  4217  
  4218  func TestCreateTable(t *testing.T) {
  4219  	createTableQueries := []struct {
  4220  		input, output string
  4221  	}{{
  4222  		// test all the data types and options
  4223  		input: `create table t (
  4224  	col_bit bit,
  4225  	col_tinyint tinyint auto_increment,
  4226  	col_tinyint3 tinyint(3) unsigned,
  4227  	col_smallint smallint,
  4228  	col_smallint4 smallint(4) zerofill,
  4229  	col_mediumint mediumint,
  4230  	col_mediumint5 mediumint(5) unsigned not null,
  4231  	col_int int,
  4232  	col_int10 int(10) not null,
  4233  	col_integer integer comment 'this is an integer',
  4234  	col_bigint bigint,
  4235  	col_bigint10 bigint(10) zerofill not null default 10,
  4236  	col_real real,
  4237  	col_real2 real(1,2) not null default 1.23,
  4238  	col_double double,
  4239  	col_double2 double(3,4) not null default 1.23,
  4240  	col_float float,
  4241  	col_float2 float(3,4) not null default 1.23,
  4242  	col_decimal decimal,
  4243  	col_decimal2 decimal(2),
  4244  	col_decimal3 decimal(2,3),
  4245  	col_numeric numeric,
  4246  	col_numeric2 numeric(2),
  4247  	col_numeric3 numeric(2,3),
  4248  	col_date date,
  4249  	col_time time,
  4250  	col_timestamp timestamp,
  4251  	col_datetime datetime,
  4252  	col_year year,
  4253  	col_char char,
  4254  	col_char2 char(2),
  4255  	col_char3 char(3) character set ascii,
  4256  	col_char4 char(4) character set ascii collate ascii_bin,
  4257  	col_varchar varchar,
  4258  	col_varchar2 varchar(2),
  4259  	col_varchar3 varchar(3) character set ascii,
  4260  	col_varchar4 varchar(4) character set ascii collate ascii_bin,
  4261  	col_binary binary,
  4262  	col_varbinary varbinary(10),
  4263  	col_tinyblob tinyblob,
  4264  	col_blob blob,
  4265  	col_mediumblob mediumblob,
  4266  	col_longblob longblob,
  4267  	col_tinytext tinytext,
  4268  	col_text text,
  4269  	col_mediumtext mediumtext,
  4270  	col_longtext longtext,
  4271  	col_text text character set ascii collate ascii_bin,
  4272  	col_json json,
  4273  	col_enum enum('a', 'b', 'c', 'd'),
  4274  	col_enum2 enum('a', 'b', 'c', 'd') character set ascii,
  4275  	col_enum3 enum('a', 'b', 'c', 'd') collate ascii_bin,
  4276  	col_enum4 enum('a', 'b', 'c', 'd') character set ascii collate ascii_bin,
  4277  	col_set set('a', 'b', 'c', 'd'),
  4278  	col_set2 set('a', 'b', 'c', 'd') character set ascii,
  4279  	col_set3 set('a', 'b', 'c', 'd') collate ascii_bin,
  4280  	col_set4 set('a', 'b', 'c', 'd') character set ascii collate ascii_bin,
  4281  	col_geometry1 geometry,
  4282  	col_geometry2 geometry not null,
  4283  	col_point1 point,
  4284  	col_point2 point not null,
  4285  	col_linestring1 linestring,
  4286  	col_linestring2 linestring not null,
  4287  	col_polygon1 polygon,
  4288  	col_polygon2 polygon not null,
  4289  	col_geometrycollection1 geometrycollection,
  4290  	col_geometrycollection2 geometrycollection not null,
  4291  	col_multipoint1 multipoint,
  4292  	col_multipoint2 multipoint not null,
  4293  	col_multilinestring1 multilinestring,
  4294  	col_multilinestring2 multilinestring not null,
  4295  	col_multipolygon1 multipolygon,
  4296  	col_multipolygon2 multipolygon not null
  4297  )`,
  4298  	},
  4299  		// test null columns
  4300  		{
  4301  			input: `create table foo (
  4302  	id int primary key,
  4303  	a varchar(255) null,
  4304  	b varchar(255) null default 'foo',
  4305  	c timestamp null default current_timestamp()
  4306  )`,
  4307  		},
  4308  		// test defining indexes separately
  4309  		{
  4310  			input: `create table t (
  4311  	id int auto_increment,
  4312  	username varchar,
  4313  	email varchar,
  4314  	full_name varchar,
  4315  	geom point not null,
  4316  	status_nonkeyword varchar,
  4317  	primary key (id),
  4318  	spatial key geom (geom),
  4319  	fulltext key fts (full_name),
  4320  	unique key by_username (username),
  4321  	unique key by_username2 (username),
  4322  	unique index by_username3 (username),
  4323  	index by_status (status_nonkeyword),
  4324  	key by_full_name (full_name)
  4325  )`,
  4326  		},
  4327  		// test defining index visibility
  4328  		{
  4329  			input: `create table t (
  4330  	id int auto_increment,
  4331  	username varchar,
  4332  	unique key by_username (username) visible,
  4333  	unique key by_username2 (username) invisible,
  4334  	unique index by_username3 (username)
  4335  )`,
  4336  		},
  4337  		// test adding engine attributes
  4338  		{
  4339  			input: `create table t (
  4340  	id int auto_increment,
  4341  	username varchar,
  4342  	unique key by_username (username) engine_attribute '{}' secondary_engine_attribute '{}',
  4343  	unique index by_username3 (username)
  4344  )`,
  4345  		},
  4346  		// test defining SRID
  4347  		{
  4348  			input: `create table t (
  4349  	p point srid 0,
  4350  	g geometry not null srid 4326
  4351  )`,
  4352  		},
  4353  		// test defining column visibility
  4354  		{
  4355  			input: `create table t (
  4356  	id int auto_increment,
  4357  	username varchar invisible,
  4358  	login varchar visible
  4359  )`,
  4360  		},
  4361  		// test adding column engine attributes
  4362  		{
  4363  			input: `create table t (
  4364  	id int auto_increment,
  4365  	username varchar engine_attribute '{}' secondary_engine_attribute '{}'
  4366  )`,
  4367  		},
  4368  		// test adding column format
  4369  		{
  4370  			input: `create table t (
  4371  	id int auto_increment,
  4372  	username varchar column_format dynamic
  4373  )`,
  4374  		},
  4375  		// test that indexes support USING <id>
  4376  		{
  4377  			input: `create table t (
  4378  	id int auto_increment,
  4379  	username varchar,
  4380  	email varchar,
  4381  	full_name varchar,
  4382  	status_nonkeyword varchar,
  4383  	primary key (id) using BTREE,
  4384  	unique key by_username (username) using HASH,
  4385  	unique key by_username2 (username) using OTHER,
  4386  	unique index by_username3 (username) using XYZ,
  4387  	index by_status (status_nonkeyword) using PDQ,
  4388  	key by_full_name (full_name) using OTHER
  4389  )`,
  4390  		},
  4391  		// test other index options
  4392  		{
  4393  			input: `create table t (
  4394  	id int auto_increment,
  4395  	username varchar,
  4396  	email varchar,
  4397  	primary key (id) comment 'hi',
  4398  	unique key by_username (username) key_block_size 8,
  4399  	unique index by_username4 (username) comment 'hi' using BTREE,
  4400  	unique index by_username4 (username) using BTREE key_block_size 4 comment 'hi'
  4401  )`,
  4402  		},
  4403  		{
  4404  			input: `create table t1 (
  4405  	first_name varchar(10),
  4406  	last_name varchar(10),
  4407  	full_name varchar(255) character set utf8mb4 collate utf8mb4_0900_ai_ci as (concat(first_name, ' ', last_name)) virtual,
  4408  	middle_name varchar(255) character set utf8mb4 collate utf8mb4_0900_ai_ci default '' collate utf8mb4_bin
  4409  )`,
  4410  			output: `create table t1 (
  4411  	first_name varchar(10),
  4412  	last_name varchar(10),
  4413  	full_name varchar(255) character set utf8mb4 collate utf8mb4_0900_ai_ci as (concat(first_name, ' ', last_name)) virtual,
  4414  	middle_name varchar(255) character set utf8mb4 collate utf8mb4_bin default ''
  4415  )`,
  4416  		},
  4417  		{
  4418  			input: "create table t1 (`idb` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci GENERATED ALWAYS AS (json_unquote(json_extract(`jsonobj`,_utf8mb4'$._id'))) STORED NOT NULL)",
  4419  			output: `create table t1 (
  4420  	idb varchar(36) character set utf8mb4 collate utf8mb4_0900_ai_ci as (json_unquote(json_extract(jsonobj, _utf8mb4 '$._id'))) stored not null
  4421  )`,
  4422  		},
  4423  		{
  4424  			input: "create table t2 (\n\tid int not null,\n\textra tinyint(1) as (id = 1) stored,\n\tPRIMARY KEY (id)\n)",
  4425  		},
  4426  		// multi-column indexes
  4427  		{
  4428  			input: `create table t (
  4429  	id int auto_increment,
  4430  	username varchar,
  4431  	email varchar,
  4432  	full_name varchar,
  4433  	a int,
  4434  	b int,
  4435  	c int,
  4436  	primary key (id, username),
  4437  	unique key by_abc (a, b, c),
  4438  	unique key (a, b, c),
  4439  	key by_email (email(10), username)
  4440  )`,
  4441  		},
  4442  		// geometrycollection & geomcollection alias
  4443  		{
  4444  			input: `create table t (
  4445  	id int auto_increment,
  4446  	col_geometrycollection1 geometrycollection,
  4447  	col_geometrycollection2 geometrycollection not null,
  4448  	col_geometrycollection3 geomcollection,
  4449  	col_geometrycollection4 geomcollection not null,
  4450  	primary key (id)
  4451  )`,
  4452  		},
  4453  		// foreign keys
  4454  		{
  4455  			input: `create table t (
  4456  	id int auto_increment,
  4457  	username varchar,
  4458  	k int,
  4459  	Z int,
  4460  	newCol int references t2 (a),
  4461  	newCol int references t2 (a) on delete restrict,
  4462  	newCol int references t2 (a) on delete no action,
  4463  	newCol int references t2 (a) on delete cascade on update set default,
  4464  	newCol int references t2 (a) on delete set default on update set null,
  4465  	newCol int references t2 (a) on delete set null on update restrict,
  4466  	newCol int references t2 (a) on update set default on delete cascade,
  4467  	newCol int references t2 (a) on update set null on delete set default,
  4468  	newCol int references t2 (a) on update restrict on delete set null,
  4469  	newCol int references t2 (a) match full on delete cascade on update set default,
  4470  	newCol int references t2 (a) match partial on delete set default on update set null,
  4471  	newCol int references t2 (a) match simple on delete set null on update restrict,
  4472  	newCol int references t2 (a) on update no action,
  4473  	newCol int references t2 (a) on update cascade,
  4474  	primary key (id, username),
  4475  	key by_email (email(10), username),
  4476  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b),
  4477  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete restrict,
  4478  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete no action,
  4479  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete cascade on update set default,
  4480  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete set default on update set null,
  4481  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete set null on update restrict,
  4482  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on update set default on delete cascade ,
  4483  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on update set null on delete set default,
  4484  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on update restrict on delete set null,
  4485  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) match full on delete cascade on update set default,
  4486  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) match partial on delete set default on update set null,
  4487  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) match simple on delete set null on update restrict,
  4488  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on update no action,
  4489  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on update cascade
  4490  )`,
  4491  			output: `create table t (
  4492  	id int auto_increment,
  4493  	username varchar,
  4494  	k int,
  4495  	Z int,
  4496  	newCol int references t2 (a),
  4497  	newCol int references t2 (a) on delete restrict,
  4498  	newCol int references t2 (a) on delete no action,
  4499  	newCol int references t2 (a) on delete cascade on update set default,
  4500  	newCol int references t2 (a) on delete set default on update set null,
  4501  	newCol int references t2 (a) on delete set null on update restrict,
  4502  	newCol int references t2 (a) on delete cascade on update set default,
  4503  	newCol int references t2 (a) on delete set default on update set null,
  4504  	newCol int references t2 (a) on delete set null on update restrict,
  4505  	newCol int references t2 (a) match full on delete cascade on update set default,
  4506  	newCol int references t2 (a) match partial on delete set default on update set null,
  4507  	newCol int references t2 (a) match simple on delete set null on update restrict,
  4508  	newCol int references t2 (a) on update no action,
  4509  	newCol int references t2 (a) on update cascade,
  4510  	primary key (id, username),
  4511  	key by_email (email(10), username),
  4512  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b),
  4513  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete restrict,
  4514  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete no action,
  4515  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete cascade on update set default,
  4516  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete set default on update set null,
  4517  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete set null on update restrict,
  4518  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete cascade on update set default,
  4519  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete set default on update set null,
  4520  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on delete set null on update restrict,
  4521  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) match full on delete cascade on update set default,
  4522  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) match partial on delete set default on update set null,
  4523  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) match simple on delete set null on update restrict,
  4524  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on update no action,
  4525  	constraint second_ibfk_1 foreign key (k, j) references t2 (a, b) on update cascade
  4526  )`,
  4527  		},
  4528  		// constraint name with spaces
  4529  		{
  4530  			input: `create table ` + "`" + `Post With Space` + "`" + ` (
  4531  	id int(11) not null auto_increment,
  4532  	user_id int(11) not null,
  4533  	primary key (id),
  4534  	unique key post_user_unique (user_id),
  4535  	constraint ` + "`" + `Post With Space_ibfk_1` + "`" + ` foreign key (user_id) references ` + "`" + `User` + "`" + ` (id)
  4536  ) ENGINE Innodb`,
  4537  		},
  4538  		// table options
  4539  		{
  4540  			input: `create table t (
  4541  	id int auto_increment
  4542  ) engine InnoDB,
  4543    auto_increment 123,
  4544    autoextend_size 16,
  4545    avg_row_length 1,
  4546    charset utf8mb4,
  4547    charset latin1,
  4548    checksum 0,
  4549    collate binary,
  4550    collate ascii_bin,
  4551    comment 'this is a comment',
  4552    compression 'zlib',
  4553    connection 'connect_string',
  4554    data directory 'absolute path to directory',
  4555    delay_key_write 1,
  4556    encryption 'n',
  4557    engine_attribute '{}',
  4558    index directory 'absolute path to directory',
  4559    insert_method no,
  4560    key_block_size 1024,
  4561    max_rows 100,
  4562    min_rows 10,
  4563    pack_keys 0,
  4564    password 'sekret',
  4565    row_format default,
  4566    secondary_engine_attribute '{}',
  4567    stats_auto_recalc default,
  4568    stats_persistent 0,
  4569    stats_sample_pages 1,
  4570    tablespace tablespace_name storage disk,
  4571    union (a, b, c),
  4572    tablespace tablespace_name`,
  4573  		},
  4574  		// boolean columns
  4575  		{
  4576  			input: `create table t (
  4577  	bi bigint not null primary key,
  4578  	b1 bool not null,
  4579  	b2 boolean
  4580  )`,
  4581  		},
  4582  		{
  4583  			// test key_block_size
  4584  			input: `create table t (
  4585  	id int auto_increment,
  4586  	username varchar,
  4587  	unique key by_username (username) key_block_size 8,
  4588  	unique key by_username2 (username) key_block_size=8,
  4589  	unique by_username3 (username) key_block_size = 4
  4590  )`,
  4591  			output: `create table t (
  4592  	id int auto_increment,
  4593  	username varchar,
  4594  	unique key by_username (username) key_block_size 8,
  4595  	unique key by_username2 (username) key_block_size 8,
  4596  	unique key by_username3 (username) key_block_size 4
  4597  )`,
  4598  		}, {
  4599  			// test defaults
  4600  			input: `create table t (
  4601  	i1 int default 1,
  4602  	i2 int default null,
  4603  	f1 float default 1.23,
  4604  	s1 varchar default 'c',
  4605  	s2 varchar default 'this is a string',
  4606  	s3 varchar default null,
  4607  	s4 timestamp default current_timestamp,
  4608  	s41 timestamp default now,
  4609  	s5 bit(1) default B'0'
  4610  )`,
  4611  			output: `create table t (
  4612  	i1 int default 1,
  4613  	i2 int default null,
  4614  	f1 float default 1.23,
  4615  	s1 varchar default 'c',
  4616  	s2 varchar default 'this is a string',
  4617  	` + "`" + `s3` + "`" + ` varchar default null,
  4618  	s4 timestamp default current_timestamp(),
  4619  	s41 timestamp default now(),
  4620  	s5 bit(1) default B'0'
  4621  )`,
  4622  		}, {
  4623  			// test non_reserved word in column name
  4624  			input: `create table t (
  4625  	repair int
  4626  )`,
  4627  			output: `create table t (
  4628  	` + "`" + `repair` + "`" + ` int
  4629  )`,
  4630  		}, {
  4631  			// test key field options
  4632  			input: `create table t (
  4633  	id int auto_increment primary key,
  4634  	username varchar unique key,
  4635  	email varchar unique,
  4636  	full_name varchar key,
  4637  	time1 timestamp on update current_timestamp,
  4638  	time2 timestamp default current_timestamp on update current_timestamp
  4639  )`,
  4640  			output: `create table t (
  4641  	id int auto_increment primary key,
  4642  	username varchar unique key,
  4643  	email varchar unique,
  4644  	full_name varchar key,
  4645  	time1 timestamp on update current_timestamp(),
  4646  	time2 timestamp default current_timestamp() on update current_timestamp()
  4647  )`,
  4648  		}, {
  4649  			// test current_timestamp with and without ()
  4650  			input: `create table t (
  4651  	time1 timestamp default current_timestamp,
  4652  	time2 timestamp default current_timestamp(),
  4653  	time3 timestamp default current_timestamp on update current_timestamp,
  4654  	time4 timestamp default current_timestamp() on update current_timestamp(),
  4655  	time5 timestamp(3) default current_timestamp(3) on update current_timestamp(3)
  4656  )`,
  4657  			output: `create table t (
  4658  	time1 timestamp default current_timestamp(),
  4659  	time2 timestamp default current_timestamp(),
  4660  	time3 timestamp default current_timestamp() on update current_timestamp(),
  4661  	time4 timestamp default current_timestamp() on update current_timestamp(),
  4662  	time5 timestamp(3) default current_timestamp(3) on update current_timestamp(3)
  4663  )`,
  4664  		}, {
  4665  			// test now with and without ()
  4666  			input: `create table t (
  4667  	time1 timestamp default now,
  4668  	time2 timestamp default now(),
  4669  	time3 timestamp default (now()),
  4670  	time4 timestamp default now on update now,
  4671  	time5 timestamp default now() on update now(),
  4672  	time6 timestamp(3) default now(3) on update now(3)
  4673  )`,
  4674  			output: `create table t (
  4675  	time1 timestamp default now(),
  4676  	time2 timestamp default now(),
  4677  	time3 timestamp default now(),
  4678  	time4 timestamp default now() on update now(),
  4679  	time5 timestamp default now() on update now(),
  4680  	time6 timestamp(3) default now(3) on update now(3)
  4681  )`,
  4682  		}, {
  4683  			// test localtime with and without ()
  4684  			input: `create table t (
  4685  	time1 timestamp default localtime,
  4686  	time2 timestamp default localtime(),
  4687  	time3 timestamp default localtime on update localtime,
  4688  	time4 timestamp default localtime() on update localtime(),
  4689  	time5 timestamp(6) default localtime(6) on update localtime(6)
  4690  )`,
  4691  			output: `create table t (
  4692  	time1 timestamp default localtime(),
  4693  	time2 timestamp default localtime(),
  4694  	time3 timestamp default localtime() on update localtime(),
  4695  	time4 timestamp default localtime() on update localtime(),
  4696  	time5 timestamp(6) default localtime(6) on update localtime(6)
  4697  )`,
  4698  		}, {
  4699  			// test localtimestamp with and without ()
  4700  			input: `create table t (
  4701  	time1 timestamp default localtimestamp,
  4702  	time2 timestamp default localtimestamp(),
  4703  	time3 timestamp default localtimestamp on update localtimestamp,
  4704  	time4 timestamp default localtimestamp() on update localtimestamp(),
  4705  	time5 timestamp(1) default localtimestamp(1) on update localtimestamp(1)
  4706  )`,
  4707  			output: `create table t (
  4708  	time1 timestamp default localtimestamp(),
  4709  	time2 timestamp default localtimestamp(),
  4710  	time3 timestamp default localtimestamp() on update localtimestamp(),
  4711  	time4 timestamp default localtimestamp() on update localtimestamp(),
  4712  	time5 timestamp(1) default localtimestamp(1) on update localtimestamp(1)
  4713  )`,
  4714  		}, {
  4715  			input: `create table t1 (
  4716  	first_name varchar(10),
  4717  	last_name varchar(10),
  4718  	full_name varchar(255) as (concat(first_name, ' ', last_name))
  4719  )`, output: `create table t1 (
  4720  	first_name varchar(10),
  4721  	last_name varchar(10),
  4722  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual
  4723  )`,
  4724  		}, {
  4725  			input: `create table t1 (id int, gnrtd int as (id+2) virtual)`,
  4726  			output: `create table t1 (
  4727  	id int,
  4728  	gnrtd int as (id + 2) virtual
  4729  )`,
  4730  		}, {
  4731  			input: `create table t1 (first_name varchar(10), last_name varchar(10),
  4732  	full_name varchar(255) generated always as (concat(first_name, ' ', last_name)))`,
  4733  			output: `create table t1 (
  4734  	first_name varchar(10),
  4735  	last_name varchar(10),
  4736  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual
  4737  )`,
  4738  		}, {
  4739  			input: `create table t1 (first_name varchar(10), last_name varchar(10),
  4740  	full_name varchar(255) generated always as (concat(first_name, ' ', last_name)) not null )`,
  4741  			output: `create table t1 (
  4742  	first_name varchar(10),
  4743  	last_name varchar(10),
  4744  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual not null
  4745  )`,
  4746  		}, {
  4747  			input: `create table t1 (first_name varchar(10), full_name varchar(255) as (concat(first_name, ' ', last_name)) null)`,
  4748  			output: `create table t1 (
  4749  	first_name varchar(10),
  4750  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual null
  4751  )`,
  4752  		}, {
  4753  			input: `create table t1 (first_name varchar(10), full_name varchar(255) as (concat(first_name, ' ', last_name)) unique)`,
  4754  			output: `create table t1 (
  4755  	first_name varchar(10),
  4756  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual unique
  4757  )`,
  4758  		}, {
  4759  			input: `create table t1 (first_name varchar(10), full_name varchar(255) as (concat(first_name, ' ', last_name)) unique key)`,
  4760  			output: `create table t1 (
  4761  	first_name varchar(10),
  4762  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual unique key
  4763  )`,
  4764  		}, {
  4765  			input: `create table t1 (first_name varchar(10), full_name varchar(255) as (concat(first_name, ' ', last_name)) key)`,
  4766  			output: `create table t1 (
  4767  	first_name varchar(10),
  4768  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual key
  4769  )`,
  4770  		}, {
  4771  			input: `create table t1 (first_name varchar(10), full_name varchar(255) as (concat(first_name, ' ', last_name)) primary key)`,
  4772  			output: `create table t1 (
  4773  	first_name varchar(10),
  4774  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual primary key
  4775  )`,
  4776  		}, {
  4777  			input: `create table t1 (first_name varchar(10), full_name varchar(255) as (concat(first_name, ' ', last_name)) comment 'hello world')`,
  4778  			output: `create table t1 (
  4779  	first_name varchar(10),
  4780  	full_name varchar(255) as (concat(first_name, ' ', last_name)) virtual comment 'hello world'
  4781  )`,
  4782  		}, {
  4783  			input: `create table non_reserved_keyword (id int(11)) ENGINE = MEMORY`,
  4784  			output: `create table non_reserved_keyword (
  4785  	id int(11)
  4786  ) ENGINE MEMORY`,
  4787  		}, {
  4788  			input: `create table non_reserved_keyword (id int(11)) ENGINE = MEDIUMTEXT`,
  4789  			output: `create table non_reserved_keyword (
  4790  	id int(11)
  4791  ) ENGINE MEDIUMTEXT`,
  4792  		}, {
  4793  			input: `create table t1 (id int(11)) ENGINE = FOOBAR`,
  4794  			output: `create table t1 (
  4795  	id int(11)
  4796  ) ENGINE FOOBAR`,
  4797  		},
  4798  		// partitions
  4799  		{
  4800  			input: `
  4801  CREATE TABLE employees (
  4802      id INT NOT NULL,
  4803      fname VARCHAR(30),
  4804      lname VARCHAR(30),
  4805      hired DATE NOT NULL DEFAULT '1970-01-01',
  4806      separated DATE NOT NULL DEFAULT '9999-12-31',
  4807      job_code INT NOT NULL,
  4808      store_id INT NOT NULL
  4809  )
  4810  PARTITION BY RANGE (store_id) (
  4811      PARTITION p0 VALUES LESS THAN (6),
  4812      PARTITION p1 VALUES LESS THAN (11),
  4813      PARTITION p2 VALUES LESS THAN (16),
  4814      PARTITION p3 VALUES LESS THAN (21)
  4815  )`,
  4816  			output: `create table employees (
  4817  	id INT not null,
  4818  	fname VARCHAR(30),
  4819  	lname VARCHAR(30),
  4820  	hired DATE not null default '1970-01-01',
  4821  	separated DATE not null default '9999-12-31',
  4822  	job_code INT not null,
  4823  	store_id INT not null
  4824  )
  4825  partition by range (store_id)
  4826  (partition p0 values less than (6),
  4827   partition p1 values less than (11),
  4828   partition p2 values less than (16),
  4829   partition p3 values less than (21))`,
  4830  		},
  4831  		{
  4832  			input: `CREATE TABLE employees (
  4833      id INT NOT NULL,
  4834      fname VARCHAR(30),
  4835      lname VARCHAR(30),
  4836      hired DATE NOT NULL DEFAULT '1970-01-01',
  4837      separated DATE NOT NULL DEFAULT '9999-12-31',
  4838      job_code INT NOT NULL,
  4839      store_id INT NOT NULL
  4840  )
  4841  PARTITION BY RANGE (store_id) (
  4842      PARTITION p0 VALUES LESS THAN (6),
  4843      PARTITION p1 VALUES LESS THAN (11),
  4844      PARTITION p2 VALUES LESS THAN (16),
  4845      PARTITION p3 VALUES LESS THAN MAXVALUE
  4846  )`,
  4847  			output: `create table employees (
  4848  	id INT not null,
  4849  	fname VARCHAR(30),
  4850  	lname VARCHAR(30),
  4851  	hired DATE not null default '1970-01-01',
  4852  	separated DATE not null default '9999-12-31',
  4853  	job_code INT not null,
  4854  	store_id INT not null
  4855  )
  4856  partition by range (store_id)
  4857  (partition p0 values less than (6),
  4858   partition p1 values less than (11),
  4859   partition p2 values less than (16),
  4860   partition p3 values less than maxvalue)`,
  4861  		},
  4862  		{
  4863  			input: `CREATE TABLE employees (
  4864      id INT NOT NULL,
  4865      fname VARCHAR(30),
  4866      lname VARCHAR(30),
  4867      hired DATE NOT NULL DEFAULT '1970-01-01',
  4868      separated DATE NOT NULL DEFAULT '9999-12-31',
  4869      job_code INT NOT NULL,
  4870      store_id INT NOT NULL
  4871  )
  4872  PARTITION BY RANGE (job_code) (
  4873      PARTITION p0 VALUES LESS THAN (100),
  4874      PARTITION p1 VALUES LESS THAN (1000),
  4875      PARTITION p2 VALUES LESS THAN (10000)
  4876  )`,
  4877  			output: `create table employees (
  4878  	id INT not null,
  4879  	fname VARCHAR(30),
  4880  	lname VARCHAR(30),
  4881  	hired DATE not null default '1970-01-01',
  4882  	separated DATE not null default '9999-12-31',
  4883  	job_code INT not null,
  4884  	store_id INT not null
  4885  )
  4886  partition by range (job_code)
  4887  (partition p0 values less than (100),
  4888   partition p1 values less than (1000),
  4889   partition p2 values less than (10000))`,
  4890  		},
  4891  		{
  4892  			input: `CREATE TABLE employees (
  4893      id INT NOT NULL,
  4894      fname VARCHAR(30),
  4895      lname VARCHAR(30),
  4896      hired DATE NOT NULL DEFAULT '1970-01-01',
  4897      separated DATE NOT NULL DEFAULT '9999-12-31',
  4898      job_code INT,
  4899      store_id INT
  4900  )
  4901  PARTITION BY RANGE ( YEAR(separated) ) (
  4902      PARTITION p0 VALUES LESS THAN (1991),
  4903      PARTITION p1 VALUES LESS THAN (1996),
  4904      PARTITION p2 VALUES LESS THAN (2001),
  4905      PARTITION p3 VALUES LESS THAN MAXVALUE
  4906  )`,
  4907  			output: `create table employees (
  4908  	id INT not null,
  4909  	fname VARCHAR(30),
  4910  	lname VARCHAR(30),
  4911  	hired DATE not null default '1970-01-01',
  4912  	separated DATE not null default '9999-12-31',
  4913  	job_code INT,
  4914  	store_id INT
  4915  )
  4916  partition by range (YEAR(separated))
  4917  (partition p0 values less than (1991),
  4918   partition p1 values less than (1996),
  4919   partition p2 values less than (2001),
  4920   partition p3 values less than maxvalue)`,
  4921  		},
  4922  		{
  4923  			input: `CREATE TABLE quarterly_report_status (
  4924      report_id INT NOT NULL,
  4925      report_status VARCHAR(20) NOT NULL,
  4926      report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  4927  )
  4928  PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
  4929      PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
  4930      PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
  4931      PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
  4932      PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
  4933      PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
  4934      PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
  4935      PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
  4936      PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
  4937      PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
  4938      PARTITION p9 VALUES LESS THAN (MAXVALUE)
  4939  )`,
  4940  			output: `create table quarterly_report_status (
  4941  	report_id INT not null,
  4942  	report_status VARCHAR(20) not null,
  4943  	report_updated TIMESTAMP not null default current_timestamp() on update current_timestamp()
  4944  )
  4945  partition by range (UNIX_TIMESTAMP(report_updated))
  4946  (partition p0 values less than (UNIX_TIMESTAMP('2008-01-01 00:00:00')),
  4947   partition p1 values less than (UNIX_TIMESTAMP('2008-04-01 00:00:00')),
  4948   partition p2 values less than (UNIX_TIMESTAMP('2008-07-01 00:00:00')),
  4949   partition p3 values less than (UNIX_TIMESTAMP('2008-10-01 00:00:00')),
  4950   partition p4 values less than (UNIX_TIMESTAMP('2009-01-01 00:00:00')),
  4951   partition p5 values less than (UNIX_TIMESTAMP('2009-04-01 00:00:00')),
  4952   partition p6 values less than (UNIX_TIMESTAMP('2009-07-01 00:00:00')),
  4953   partition p7 values less than (UNIX_TIMESTAMP('2009-10-01 00:00:00')),
  4954   partition p8 values less than (UNIX_TIMESTAMP('2010-01-01 00:00:00')),
  4955   partition p9 values less than maxvalue)`,
  4956  		},
  4957  		{
  4958  			input: `CREATE TABLE quarterly_report_status (
  4959      report_id INT NOT NULL,
  4960      report_status VARCHAR(20) NOT NULL,
  4961      report_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
  4962  )
  4963  PARTITION BY RANGE ( UNIX_TIMESTAMP(report_updated) ) (
  4964      PARTITION p0 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-01-01 00:00:00') ),
  4965      PARTITION p1 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-04-01 00:00:00') ),
  4966      PARTITION p2 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-07-01 00:00:00') ),
  4967      PARTITION p3 VALUES LESS THAN ( UNIX_TIMESTAMP('2008-10-01 00:00:00') ),
  4968      PARTITION p4 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-01-01 00:00:00') ),
  4969      PARTITION p5 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-04-01 00:00:00') ),
  4970      PARTITION p6 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-07-01 00:00:00') ),
  4971      PARTITION p7 VALUES LESS THAN ( UNIX_TIMESTAMP('2009-10-01 00:00:00') ),
  4972      PARTITION p8 VALUES LESS THAN ( UNIX_TIMESTAMP('2010-01-01 00:00:00') ),
  4973      PARTITION p9 VALUES LESS THAN (MAXVALUE)
  4974  )`,
  4975  			output: `create table quarterly_report_status (
  4976  	report_id INT not null,
  4977  	report_status VARCHAR(20) not null,
  4978  	report_updated TIMESTAMP not null default current_timestamp() on update current_timestamp()
  4979  )
  4980  partition by range (UNIX_TIMESTAMP(report_updated))
  4981  (partition p0 values less than (UNIX_TIMESTAMP('2008-01-01 00:00:00')),
  4982   partition p1 values less than (UNIX_TIMESTAMP('2008-04-01 00:00:00')),
  4983   partition p2 values less than (UNIX_TIMESTAMP('2008-07-01 00:00:00')),
  4984   partition p3 values less than (UNIX_TIMESTAMP('2008-10-01 00:00:00')),
  4985   partition p4 values less than (UNIX_TIMESTAMP('2009-01-01 00:00:00')),
  4986   partition p5 values less than (UNIX_TIMESTAMP('2009-04-01 00:00:00')),
  4987   partition p6 values less than (UNIX_TIMESTAMP('2009-07-01 00:00:00')),
  4988   partition p7 values less than (UNIX_TIMESTAMP('2009-10-01 00:00:00')),
  4989   partition p8 values less than (UNIX_TIMESTAMP('2010-01-01 00:00:00')),
  4990   partition p9 values less than maxvalue)`,
  4991  		},
  4992  		{
  4993  			input: `CREATE TABLE members (
  4994      firstname VARCHAR(25) NOT NULL,
  4995      lastname VARCHAR(25) NOT NULL,
  4996      username VARCHAR(16) NOT NULL,
  4997      email VARCHAR(35),
  4998      joined DATE NOT NULL
  4999  )
  5000  PARTITION BY RANGE COLUMNS(joined) (
  5001      PARTITION p0 VALUES LESS THAN ('1960-01-01'),
  5002      PARTITION p1 VALUES LESS THAN ('1970-01-01'),
  5003      PARTITION p2 VALUES LESS THAN ('1980-01-01'),
  5004      PARTITION p3 VALUES LESS THAN ('1990-01-01'),
  5005      PARTITION p4 VALUES LESS THAN MAXVALUE
  5006  )`,
  5007  			output: `create table members (
  5008  	firstname VARCHAR(25) not null,
  5009  	lastname VARCHAR(25) not null,
  5010  	username VARCHAR(16) not null,
  5011  	email VARCHAR(35),
  5012  	joined DATE not null
  5013  )
  5014  partition by range columns (joined)
  5015  (partition p0 values less than ('1960-01-01'),
  5016   partition p1 values less than ('1970-01-01'),
  5017   partition p2 values less than ('1980-01-01'),
  5018   partition p3 values less than ('1990-01-01'),
  5019   partition p4 values less than maxvalue)`,
  5020  		},
  5021  		{
  5022  			input: `CREATE TABLE ti (id INT, amount DECIMAL(7,2), tr_date DATE)
  5023      ENGINE=INNODB
  5024      PARTITION BY HASH( MONTH(tr_date) )
  5025      PARTITIONS 6`,
  5026  			output: `create table ti (
  5027  	id INT,
  5028  	amount DECIMAL(7,2),
  5029  	tr_date DATE
  5030  ) ENGINE INNODB
  5031  partition by hash (MONTH(tr_date)) partitions 6`,
  5032  		},
  5033  		{
  5034  			input: `CREATE TABLE members (
  5035      firstname VARCHAR(25) NOT NULL,
  5036      lastname VARCHAR(25) NOT NULL,
  5037      username VARCHAR(16) NOT NULL,
  5038      email VARCHAR(35),
  5039      joined DATE NOT NULL
  5040  )
  5041  PARTITION BY KEY(joined)
  5042  PARTITIONS 6`,
  5043  			output: `create table members (
  5044  	firstname VARCHAR(25) not null,
  5045  	lastname VARCHAR(25) not null,
  5046  	username VARCHAR(16) not null,
  5047  	email VARCHAR(35),
  5048  	joined DATE not null
  5049  )
  5050  partition by key (joined) partitions 6`,
  5051  		},
  5052  		{
  5053  			input: `CREATE TABLE t2 (val INT)
  5054  	PARTITION BY LIST(val)(
  5055  	PARTITION mypart VALUES IN (1,3,5),
  5056  	PARTITION MyPart VALUES IN (2,4,6)
  5057  )`,
  5058  			output: `create table t2 (
  5059  	val INT
  5060  )
  5061  partition by list (val)
  5062  (partition mypart values in (1, 3, 5),
  5063   partition MyPart values in (2, 4, 6))`,
  5064  		},
  5065  		{
  5066  			input: `CREATE TABLE t2 (val INT)
  5067  	PARTITION BY LIST(val)(
  5068  	PARTITION mypart VALUES IN (1,3,5) STORAGE ENGINE = FOOBAR,
  5069  	PARTITION MyPart VALUES IN (2,4,6)
  5070  )`,
  5071  			output: `create table t2 (
  5072  	val INT
  5073  )
  5074  partition by list (val)
  5075  (partition mypart values in (1, 3, 5) storage engine FOOBAR,
  5076   partition MyPart values in (2, 4, 6))`,
  5077  		},
  5078  		{
  5079  			input: `CREATE TABLE t2 (val INT)
  5080  	PARTITION BY LIST(val)(
  5081  	PARTITION mypart VALUES IN (1,3,5) ENGINE = FOOBAR,
  5082  	PARTITION MyPart VALUES IN (2,4,6)
  5083  )`,
  5084  			output: `create table t2 (
  5085  	val INT
  5086  )
  5087  partition by list (val)
  5088  (partition mypart values in (1, 3, 5) engine FOOBAR,
  5089   partition MyPart values in (2, 4, 6))`,
  5090  		},
  5091  		{
  5092  			input: `CREATE TABLE t2 (val INT)
  5093  	PARTITION BY LIST(val)(
  5094  	PARTITION mypart VALUES IN (1,3,5) STORAGE ENGINE FOOBAR,
  5095  	PARTITION MyPart VALUES IN (2,4,6)
  5096  )`,
  5097  			output: `create table t2 (
  5098  	val INT
  5099  )
  5100  partition by list (val)
  5101  (partition mypart values in (1, 3, 5) storage engine FOOBAR,
  5102   partition MyPart values in (2, 4, 6))`,
  5103  		},
  5104  		{
  5105  			input: `CREATE TABLE t2 (val INT)
  5106  	PARTITION BY LIST(val)(
  5107  	PARTITION mypart VALUES IN (1,3,5) STORAGE ENGINE FOOBAR COMMENT = 'test',
  5108  	PARTITION MyPart VALUES IN (2,4,6) comment 'test2'
  5109  )`,
  5110  			output: `create table t2 (
  5111  	val INT
  5112  )
  5113  partition by list (val)
  5114  (partition mypart values in (1, 3, 5) storage engine FOOBAR comment 'test',
  5115   partition MyPart values in (2, 4, 6) comment 'test2')`,
  5116  		},
  5117  		{
  5118  			input: `CREATE TABLE t2 (val INT)
  5119  	PARTITION BY LIST(val)(
  5120  	PARTITION mypart VALUES IN (1,3,5) STORAGE ENGINE FOOBAR DATA DIRECTORY = 'test',
  5121  	PARTITION MyPart VALUES IN (2,4,6) DATA DIRECTORY 'test2'
  5122  )`,
  5123  			output: `create table t2 (
  5124  	val INT
  5125  )
  5126  partition by list (val)
  5127  (partition mypart values in (1, 3, 5) storage engine FOOBAR data directory 'test',
  5128   partition MyPart values in (2, 4, 6) data directory 'test2')`,
  5129  		},
  5130  		{
  5131  			input: `CREATE TABLE t2 (val INT)
  5132  	PARTITION BY LIST(val)(
  5133  	PARTITION mypart VALUES IN (1,3,5) INDEX DIRECTORY = 'test',
  5134  	PARTITION MyPart VALUES IN (2,4,6) INDEX DIRECTORY 'test2'
  5135  )`,
  5136  			output: `create table t2 (
  5137  	val INT
  5138  )
  5139  partition by list (val)
  5140  (partition mypart values in (1, 3, 5) index directory 'test',
  5141   partition MyPart values in (2, 4, 6) index directory 'test2')`,
  5142  		},
  5143  		{
  5144  			input: `create table t1 (id int primary key) partition by list (id) (partition p1 values in(11,21), partition p2 values in (12,22))`,
  5145  			output: `create table t1 (
  5146  	id int primary key
  5147  )
  5148  partition by list (id)
  5149  (partition p1 values in (11, 21),
  5150   partition p2 values in (12, 22))`,
  5151  		},
  5152  		{
  5153  			input: `CREATE TABLE t2 (val INT)
  5154  	PARTITION BY LIST(val)(
  5155  	PARTITION mypart VALUES IN (1,3,5) COMMENT = 'before' STORAGE ENGINE FOOBAR DATA DIRECTORY = 'test',
  5156  	PARTITION MyPart VALUES IN (2,4,6) DATA DIRECTORY 'test2'
  5157  )`,
  5158  			output: `create table t2 (
  5159  	val INT
  5160  )
  5161  partition by list (val)
  5162  (partition mypart values in (1, 3, 5) storage engine FOOBAR comment 'before' data directory 'test',
  5163   partition MyPart values in (2, 4, 6) data directory 'test2')`,
  5164  		},
  5165  		{
  5166  			input: `CREATE TABLE t2 (val INT)
  5167  	PARTITION BY LIST(val)(
  5168  	PARTITION mypart VALUES IN (1,3,5) MAX_ROWS = 4,
  5169  	PARTITION MyPart VALUES IN (2,4,6) MAX_ROWS 10
  5170  )`,
  5171  			output: `create table t2 (
  5172  	val INT
  5173  )
  5174  partition by list (val)
  5175  (partition mypart values in (1, 3, 5) max_rows 4,
  5176   partition MyPart values in (2, 4, 6) max_rows 10)`,
  5177  		},
  5178  		{
  5179  			input: `CREATE TABLE t2 (val INT)
  5180  	PARTITION BY LIST(val)(
  5181  	PARTITION mypart VALUES IN (1,3,5) MIN_ROWS = 4,
  5182  	PARTITION MyPart VALUES IN (2,4,6) MIN_ROWS 10
  5183  )`,
  5184  			output: `create table t2 (
  5185  	val INT
  5186  )
  5187  partition by list (val)
  5188  (partition mypart values in (1, 3, 5) min_rows 4,
  5189   partition MyPart values in (2, 4, 6) min_rows 10)`,
  5190  		},
  5191  		{
  5192  			input: `CREATE TABLE t2 (val INT)
  5193  	PARTITION BY LIST(val)(
  5194  	PARTITION mypart VALUES IN (1,3,5) TABLESPACE = innodb_system,
  5195  	PARTITION MyPart VALUES IN (2,4,6) TABLESPACE innodb_system
  5196  )`,
  5197  			output: `create table t2 (
  5198  	val INT
  5199  )
  5200  partition by list (val)
  5201  (partition mypart values in (1, 3, 5) tablespace innodb_system,
  5202   partition MyPart values in (2, 4, 6) tablespace innodb_system)`,
  5203  		},
  5204  		{
  5205  			// index with an expression
  5206  			input: `create table t (
  5207  	id int auto_increment,
  5208  	username varchar(64),
  5209  	nickname varchar(64),
  5210  	email varchar(64),
  5211  	primary key (id),
  5212  	key email_idx (email, (if(username = '', nickname, username)))
  5213  )`,
  5214  		},
  5215  		{
  5216  			input: `create table entries (
  5217  	uid varchar(53) character set utf8mb4 collate utf8mb4_bin not null,
  5218  	namespace varchar(254) character set utf8mb4 collate utf8mb4_bin not null,
  5219  	place varchar(254) character set utf8mb4 collate utf8mb4_bin not null,
  5220  	creationTimestamp timestamp null default current_timestamp(),
  5221  	updatedTimestamp timestamp null default current_timestamp() on update current_timestamp(),
  5222  	labels json default null,
  5223  	spec json default null,
  5224  	salaryInfo json default null,
  5225  	PRIMARY KEY (namespace, uid),
  5226  	UNIQUE KEY namespaced_name (namespace, place),
  5227  	UNIQUE KEY unique_uid (uid),
  5228  	KEY entries_spec_updatedAt ((json_value(spec, _utf8mb4 '$.updatedAt')))
  5229  ) ENGINE InnoDB,
  5230    CHARSET utf8mb4,
  5231    COLLATE utf8mb4_bin`,
  5232  		},
  5233  		{
  5234  			input: `CREATE TABLE t1(
  5235      j JSON,
  5236      INDEX i1 ( (JSON_VALUE(j, '$.id' RETURNING UNSIGNED)) )
  5237  )`,
  5238  			output: `create table t1 (
  5239  	j JSON,
  5240  	INDEX i1 ((json_value(j, '$.id' returning UNSIGNED)))
  5241  )`,
  5242  		}, {
  5243  			input: `CREATE TABLE entries (
  5244  	uid varchar(53) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  5245  	namespace varchar(254) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  5246  	employee varchar(254) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL,
  5247  	creationTimestamp timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  5248  	updatedTimestamp timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  5249  	labels json DEFAULT NULL,
  5250  	spec json DEFAULT NULL,
  5251  	salaryInfo json DEFAULT NULL,
  5252  	PRIMARY KEY (namespace,uid),
  5253  	UNIQUE KEY namespaced_employee (namespace,employee),
  5254  	UNIQUE KEY unique_uid (uid),
  5255  	KEY entries_spec_updatedAt ((json_value(spec, _utf8mb4'$.updatedAt' returning datetime)))
  5256  ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin`,
  5257  			output: `create table entries (
  5258  	uid varchar(53) character set utf8mb4 collate utf8mb4_bin not null,
  5259  	namespace varchar(254) character set utf8mb4 collate utf8mb4_bin not null,
  5260  	employee varchar(254) character set utf8mb4 collate utf8mb4_bin not null,
  5261  	creationTimestamp timestamp null default current_timestamp(),
  5262  	updatedTimestamp timestamp null default current_timestamp() on update current_timestamp(),
  5263  	labels json default null,
  5264  	spec json default null,
  5265  	salaryInfo json default null,
  5266  	PRIMARY KEY (namespace, uid),
  5267  	UNIQUE KEY namespaced_employee (namespace, employee),
  5268  	UNIQUE KEY unique_uid (uid),
  5269  	KEY entries_spec_updatedAt ((json_value(spec, _utf8mb4 '$.updatedAt' returning datetime)))
  5270  ) ENGINE InnoDB,
  5271    CHARSET utf8mb4,
  5272    COLLATE utf8mb4_bin`,
  5273  		}, {
  5274  			// Subpartitions
  5275  			input: `CREATE TABLE ts (id INT, purchased DATE)
  5276      PARTITION BY RANGE( YEAR(purchased) )
  5277      SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
  5278          PARTITION p0 VALUES LESS THAN (1990) (
  5279              SUBPARTITION s0,
  5280              SUBPARTITION s1
  5281          ),
  5282          PARTITION p1 VALUES LESS THAN (2000) (
  5283              SUBPARTITION s2,
  5284              SUBPARTITION s31
  5285          ),
  5286          PARTITION p2 VALUES LESS THAN MAXVALUE (
  5287              SUBPARTITION s4,
  5288              SUBPARTITION s5
  5289          )
  5290      )`,
  5291  			output: `create table ts (
  5292  	id INT,
  5293  	purchased DATE
  5294  )
  5295  partition by range (YEAR(purchased)) subpartition by hash (TO_DAYS(purchased))
  5296  (partition p0 values less than (1990) (subpartition s0, subpartition s1),
  5297   partition p1 values less than (2000) (subpartition s2, subpartition s31),
  5298   partition p2 values less than maxvalue (subpartition s4, subpartition s5))`,
  5299  		},
  5300  		{
  5301  			input: `CREATE TABLE ts (id INT, purchased DATE)
  5302      PARTITION BY RANGE( YEAR(purchased) )
  5303      SUBPARTITION BY HASH( TO_DAYS(purchased) ) (
  5304          PARTITION p0 VALUES LESS THAN (1990) (
  5305              SUBPARTITION s0 STORAGE Engine = 'innodb' data directory = '/data',
  5306              SUBPARTITION s1 COMMENT = 'this is s1' index directory = '/index'
  5307          ),
  5308          PARTITION p1 VALUES LESS THAN (2000) (
  5309              SUBPARTITION s2 MAx_rows = 4,
  5310              SUBPARTITION s31 min_rows = 5 tablespace = t2
  5311          ),
  5312          PARTITION p2 VALUES LESS THAN MAXVALUE (
  5313              SUBPARTITION s4,
  5314              SUBPARTITION s5
  5315          )
  5316      )`,
  5317  			output: `create table ts (
  5318  	id INT,
  5319  	purchased DATE
  5320  )
  5321  partition by range (YEAR(purchased)) subpartition by hash (TO_DAYS(purchased))
  5322  (partition p0 values less than (1990) (subpartition s0 storage engine innodb data directory '/data', subpartition s1 comment 'this is s1' index directory '/index'),
  5323   partition p1 values less than (2000) (subpartition s2 max_rows 4, subpartition s31 min_rows 5 tablespace t2),
  5324   partition p2 values less than maxvalue (subpartition s4, subpartition s5))`,
  5325  		},
  5326  		{
  5327  			input:  "create table t (i bigint) charset ascii",
  5328  			output: "create table t (\n\ti bigint\n) charset ascii",
  5329  		},
  5330  		{
  5331  			input:  "create table t (i1 char ascii, i2 char character set ascii, i3 char binary, i4 char unicode binary, i5 char binary unicode, i6 char ascii binary, i7 char binary ascii, i8 char byte, i9 char character set latin1 binary)",
  5332  			output: "create table t (\n\ti1 char character set latin1,\n\ti2 char character set ascii,\n\ti3 char binary,\n\ti4 char character set ucs2 binary,\n\ti5 char character set ucs2 binary,\n\ti6 char character set latin1 binary,\n\ti7 char character set latin1 binary,\n\ti8 binary,\n\ti9 char character set latin1 binary\n)",
  5333  		},
  5334  		{
  5335  			input:  "create table t (id int, info JSON, INDEX zips((CAST(info->'$.field' AS unsigned ARRAY))))",
  5336  			output: "create table t (\n\tid int,\n\tinfo JSON,\n\tINDEX zips ((cast(info -> '$.field' as unsigned array)))\n)",
  5337  		},
  5338  	}
  5339  	for _, test := range createTableQueries {
  5340  		sql := strings.TrimSpace(test.input)
  5341  		t.Run(sql, func(t *testing.T) {
  5342  			tree, err := ParseStrictDDL(sql)
  5343  			require.NoError(t, err)
  5344  			got := String(tree)
  5345  			expected := test.output
  5346  			if expected == "" {
  5347  				expected = sql
  5348  			}
  5349  			require.Equal(t, expected, got)
  5350  		})
  5351  	}
  5352  }
  5353  
  5354  func TestOne(t *testing.T) {
  5355  	testOne := struct {
  5356  		input, output string
  5357  	}{
  5358  		input:  "",
  5359  		output: "",
  5360  	}
  5361  	if testOne.input == "" {
  5362  		return
  5363  	}
  5364  	sql := strings.TrimSpace(testOne.input)
  5365  	tree, err := Parse(sql)
  5366  	require.NoError(t, err)
  5367  	got := String(tree)
  5368  	expected := testOne.output
  5369  	if expected == "" {
  5370  		expected = sql
  5371  	}
  5372  	require.Equal(t, expected, got)
  5373  }
  5374  
  5375  func TestCreateTableLike(t *testing.T) {
  5376  	normal := "create table a like b"
  5377  	testCases := []struct {
  5378  		input  string
  5379  		output string
  5380  	}{
  5381  		{
  5382  			"create table a like b",
  5383  			normal,
  5384  		},
  5385  		{
  5386  			"create table a (like b)",
  5387  			normal,
  5388  		},
  5389  		{
  5390  			"create table ks.a like unsharded_ks.b",
  5391  			"create table ks.a like unsharded_ks.b",
  5392  		},
  5393  	}
  5394  	for _, tcase := range testCases {
  5395  		tree, err := ParseStrictDDL(tcase.input)
  5396  		if err != nil {
  5397  			t.Errorf("input: %s, err: %v", tcase.input, err)
  5398  			continue
  5399  		}
  5400  		assert.True(t, tree.(*CreateTable).FullyParsed)
  5401  		if got, want := String(tree.(*CreateTable)), tcase.output; got != want {
  5402  			t.Errorf("Parse(%s):\n%s, want\n%s", tcase.input, got, want)
  5403  		}
  5404  	}
  5405  }
  5406  
  5407  func TestCreateTableEscaped(t *testing.T) {
  5408  	testCases := []struct {
  5409  		input  string
  5410  		output string
  5411  	}{{
  5412  		input: "create table `a`(`id` int, primary key(`id`))",
  5413  		output: "create table a (\n" +
  5414  			"\tid int,\n" +
  5415  			"\tprimary key (id)\n" +
  5416  			")",
  5417  	}, {
  5418  		input: "create table `insert`(`update` int, primary key(`delete`))",
  5419  		output: "create table `insert` (\n" +
  5420  			"\t`update` int,\n" +
  5421  			"\tprimary key (`delete`)\n" +
  5422  			")",
  5423  	}}
  5424  	for _, tcase := range testCases {
  5425  		tree, err := ParseStrictDDL(tcase.input)
  5426  		if err != nil {
  5427  			t.Errorf("input: %s, err: %v", tcase.input, err)
  5428  			continue
  5429  		}
  5430  		if got, want := String(tree.(*CreateTable)), tcase.output; got != want {
  5431  			t.Errorf("Parse(%s):\n%s, want\n%s", tcase.input, got, want)
  5432  		}
  5433  	}
  5434  }
  5435  
  5436  var (
  5437  	invalidSQL = []struct {
  5438  		input        string
  5439  		output       string
  5440  		excludeMulti bool // Don't use in the ParseNext multi-statement parsing tests.
  5441  	}{{
  5442  		input:  "select : from t",
  5443  		output: "syntax error at position 9 near ':'",
  5444  	}, {
  5445  		input:  "execute stmt using 1;",
  5446  		output: "syntax error at position 21 near '1'",
  5447  	}, {
  5448  		input:  "PREPARE stmt FROM a;",
  5449  		output: "syntax error at position 20 near 'a'",
  5450  	}, {
  5451  		input:  "PREPARE stmt FROM @@a;",
  5452  		output: "syntax error at position 22 near 'a'",
  5453  	}, {
  5454  		input:  "select x'78 from t",
  5455  		output: "syntax error at position 12 near '78'",
  5456  	}, {
  5457  		input:  "select x'777' from t",
  5458  		output: "syntax error at position 14 near '777'",
  5459  	}, {
  5460  		input:  "select * from t where :1f = 2",
  5461  		output: "syntax error at position 26 near 'f'",
  5462  	}, {
  5463  		input:  "select * from t where :. = 2",
  5464  		output: "syntax error at position 24 near ':'",
  5465  	}, {
  5466  		input:  "select * from t where ::1 = 2",
  5467  		output: "syntax error at position 25 near '::'",
  5468  	}, {
  5469  		input:  "select * from t where ::. = 2",
  5470  		output: "syntax error at position 25 near '::'",
  5471  	}, {
  5472  		input:  "update a set c = values(1)",
  5473  		output: "syntax error at position 26 near '1'",
  5474  	}, {
  5475  		input: "select(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F" +
  5476  			"(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(" +
  5477  			"F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F" +
  5478  			"(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(" +
  5479  			"F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F" +
  5480  			"(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(" +
  5481  			"F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F" +
  5482  			"(F(F(F(F(F(F(F(F(F(F(F(F(",
  5483  		output: "max nesting level reached at position 406",
  5484  	}, {
  5485  		input: "select(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F" +
  5486  			"(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(" +
  5487  			"F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F" +
  5488  			"(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(" +
  5489  			"F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F" +
  5490  			"(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(" +
  5491  			"F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F(F" +
  5492  			"(F(F(F(F(F(F(F(F(F(F(F(",
  5493  		output: "syntax error at position 404",
  5494  	}, {
  5495  		// This construct is considered invalid due to a grammar conflict.
  5496  		input:  "insert into a select * from b join c on duplicate key update d=e",
  5497  		output: "syntax error at position 54 near 'key'",
  5498  	}, {
  5499  		input:  "select * from a left join b",
  5500  		output: "syntax error at position 28",
  5501  	}, {
  5502  		input:  "select * from a natural join b on c = d",
  5503  		output: "syntax error at position 34 near 'on'",
  5504  	}, {
  5505  		input:  "select * from a natural join b using (c)",
  5506  		output: "syntax error at position 37 near 'using'",
  5507  	}, {
  5508  		input:  "select next id from a",
  5509  		output: "expecting value after next at position 15 near 'id'",
  5510  	}, {
  5511  		input:  "select next 1+1 values from a",
  5512  		output: "syntax error at position 15",
  5513  	}, {
  5514  		input:  "insert into a values (select * from b)",
  5515  		output: "syntax error at position 29 near 'select'",
  5516  	}, {
  5517  		input:  "select database",
  5518  		output: "syntax error at position 16",
  5519  	}, {
  5520  		input:  "select mod from t",
  5521  		output: "syntax error at position 16 near 'from'",
  5522  	}, {
  5523  		input:  "select 1 from t where div 5",
  5524  		output: "syntax error at position 26 near 'div'",
  5525  	}, {
  5526  		input:  "select 1 from t where binary",
  5527  		output: "syntax error at position 29",
  5528  	}, {
  5529  		input:  "select match(a1, a2) against ('foo' in boolean mode with query expansion) from t",
  5530  		output: "syntax error at position 57 near 'with'",
  5531  	}, {
  5532  		input:  "select /* reserved keyword as unqualified column */ * from t where key = 'test'",
  5533  		output: "syntax error at position 71 near 'key'",
  5534  	}, {
  5535  		input:  "select /* vitess-reserved keyword as unqualified column */ * from t where escape = 'test'",
  5536  		output: "syntax error at position 81 near 'escape'",
  5537  	}, {
  5538  		input:  "select /* straight_join using */ 1 from t1 straight_join t2 using (a)",
  5539  		output: "syntax error at position 66 near 'using'",
  5540  	}, {
  5541  		input:        "select 'aa",
  5542  		output:       "syntax error at position 11 near 'aa'",
  5543  		excludeMulti: true,
  5544  	}, {
  5545  		input:        "select 'aa\\",
  5546  		output:       "syntax error at position 12 near 'aa'",
  5547  		excludeMulti: true,
  5548  	}, {
  5549  		input:        "select /* aa",
  5550  		output:       "syntax error at position 13 near '/* aa'",
  5551  		excludeMulti: true,
  5552  	}, {
  5553  		// This is a valid MySQL query but does not yet work with Vitess.
  5554  		// The problem is that the tokenizer takes .3 as a single token which causes parsing error
  5555  		// We should instead be using . as a separate token and then 3t2 as an identifier.
  5556  		// This highlights another problem, the tokenization has to be aware of the context of parsing!
  5557  		// Since in an alternate query like `select .3e3t`, we should use .3e3 as a single token FLOAT and then t as ID.
  5558  		input:        "create table 2t.3t2 (c1 bigint not null, c2 text, primary key(c1))",
  5559  		output:       "syntax error at position 18 near '.3'",
  5560  		excludeMulti: true,
  5561  	}, {
  5562  		input:  "execute stmt1 using a, @b",
  5563  		output: "syntax error at position 22 near 'a'",
  5564  	}, {
  5565  		input:  "create index @a on b (col1)",
  5566  		output: "syntax error at position 16 near 'a'",
  5567  	}, {
  5568  		input:  "create database test_db default collate @a",
  5569  		output: "syntax error at position 43 near 'a'",
  5570  	}, {
  5571  		input:  "create database test_db default charset @a",
  5572  		output: "syntax error at position 43 near 'a'",
  5573  	}, {
  5574  		input:  "create database test_db default encryption @a",
  5575  		output: "syntax error at position 46 near 'a'",
  5576  	}}
  5577  )
  5578  
  5579  func TestErrors(t *testing.T) {
  5580  	for _, tcase := range invalidSQL {
  5581  		t.Run(tcase.input, func(t *testing.T) {
  5582  			_, err := ParseStrictDDL(tcase.input)
  5583  			require.Error(t, err, tcase.output)
  5584  			require.Equal(t, tcase.output, err.Error())
  5585  		})
  5586  	}
  5587  }
  5588  
  5589  // TestSkipToEnd tests that the skip to end functionality
  5590  // does not skip past a ';'. If any tokens exist after that, Parse
  5591  // should return an error.
  5592  func TestSkipToEnd(t *testing.T) {
  5593  	testcases := []struct {
  5594  		input  string
  5595  		output string
  5596  	}{{
  5597  		// This is the case where the partial ddl will be reset
  5598  		// because of a premature ';'.
  5599  		input:  "create table a(id; select * from t",
  5600  		output: "syntax error at position 19",
  5601  	}, {
  5602  		// Partial DDL should get reset for valid DDLs also.
  5603  		input:  "create table a(id int); select * from t",
  5604  		output: "syntax error at position 31 near 'select'",
  5605  	}, {
  5606  		// Partial DDL does not get reset here. But we allow the
  5607  		// DDL only if there are no new tokens after skipping to end.
  5608  		input:  "create table a bb cc; select * from t",
  5609  		output: "extra characters encountered after end of DDL: 'select'",
  5610  	}, {
  5611  		// Test that we don't step at ';' inside strings.
  5612  		input:  "create table a bb 'a;'; select * from t",
  5613  		output: "extra characters encountered after end of DDL: 'select'",
  5614  	}}
  5615  	for _, tcase := range testcases {
  5616  		_, err := Parse(tcase.input)
  5617  		if err == nil || err.Error() != tcase.output {
  5618  			t.Errorf("%s: %v, want %s", tcase.input, err, tcase.output)
  5619  		}
  5620  	}
  5621  }
  5622  
  5623  func loadQueries(t testing.TB, filename string) (queries []string) {
  5624  	file, err := os.Open(path.Join("testdata", filename))
  5625  	require.NoError(t, err)
  5626  	defer file.Close()
  5627  
  5628  	var read io.Reader
  5629  	if strings.HasSuffix(filename, ".gz") {
  5630  		gzread, err := gzip.NewReader(file)
  5631  		if err != nil {
  5632  			t.Fatal(err)
  5633  		}
  5634  		defer gzread.Close()
  5635  		read = gzread
  5636  	} else {
  5637  		read = file
  5638  	}
  5639  
  5640  	scanner := bufio.NewScanner(read)
  5641  	for scanner.Scan() {
  5642  		queries = append(queries, scanner.Text())
  5643  	}
  5644  	return queries
  5645  }
  5646  
  5647  func TestParseDjangoQueries(t *testing.T) {
  5648  	for _, query := range loadQueries(t, "django_queries.txt") {
  5649  		_, err := Parse(query)
  5650  		if err != nil {
  5651  			t.Errorf("failed to parse %q: %v", query, err)
  5652  		}
  5653  	}
  5654  }
  5655  
  5656  func TestParseLobstersQueries(t *testing.T) {
  5657  	for _, query := range loadQueries(t, "lobsters.sql.gz") {
  5658  		_, err := Parse(query)
  5659  		if err != nil {
  5660  			t.Errorf("failed to parse %q: %v", query, err)
  5661  		}
  5662  	}
  5663  }
  5664  
  5665  func TestParseVersionedComments(t *testing.T) {
  5666  	testcases := []struct {
  5667  		input        string
  5668  		mysqlVersion string
  5669  		output       string
  5670  	}{
  5671  		{
  5672  			input:        `CREATE TABLE table1 (id int) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 /*!50900 PARTITION BY RANGE (id) (PARTITION x VALUES LESS THAN (5) ENGINE = InnoDB, PARTITION t VALUES LESS THAN (20) ENGINE = InnoDB) */`,
  5673  			mysqlVersion: "50401",
  5674  			output: `create table table1 (
  5675  	id int
  5676  ) ENGINE InnoDB,
  5677    CHARSET utf8mb4`,
  5678  		}, {
  5679  			input:        `CREATE TABLE table1 (id int) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 /*!50900 PARTITION BY RANGE (id) (PARTITION x VALUES LESS THAN (5) ENGINE = InnoDB, PARTITION t VALUES LESS THAN (20) ENGINE = InnoDB) */`,
  5680  			mysqlVersion: "80001",
  5681  			output: `create table table1 (
  5682  	id int
  5683  ) ENGINE InnoDB,
  5684    CHARSET utf8mb4
  5685  partition by range (id)
  5686  (partition x values less than (5) engine InnoDB,
  5687   partition t values less than (20) engine InnoDB)`,
  5688  		},
  5689  	}
  5690  
  5691  	for _, testcase := range testcases {
  5692  		t.Run(testcase.input+":"+testcase.mysqlVersion, func(t *testing.T) {
  5693  			oldMySQLVersion := mySQLParserVersion
  5694  			defer func() { mySQLParserVersion = oldMySQLVersion }()
  5695  			mySQLParserVersion = testcase.mysqlVersion
  5696  			tree, err := Parse(testcase.input)
  5697  			require.NoError(t, err, testcase.input)
  5698  			out := String(tree)
  5699  			require.Equal(t, testcase.output, out)
  5700  		})
  5701  	}
  5702  }
  5703  
  5704  func BenchmarkParseTraces(b *testing.B) {
  5705  	for _, trace := range []string{"django_queries.txt", "lobsters.sql.gz"} {
  5706  		b.Run(trace, func(b *testing.B) {
  5707  			queries := loadQueries(b, trace)
  5708  			if len(queries) > 10000 {
  5709  				queries = queries[:10000]
  5710  			}
  5711  			b.ResetTimer()
  5712  			b.ReportAllocs()
  5713  
  5714  			for i := 0; i < b.N; i++ {
  5715  				for _, query := range queries {
  5716  					_, err := Parse(query)
  5717  					if err != nil {
  5718  						b.Fatal(err)
  5719  					}
  5720  				}
  5721  			}
  5722  		})
  5723  	}
  5724  
  5725  }
  5726  
  5727  func BenchmarkParseStress(b *testing.B) {
  5728  	const (
  5729  		sql1 = "select 'abcd', 20, 30.0, eid from a where 1=eid and name='3'"
  5730  		sql2 = "select aaaa, bbb, ccc, ddd, eeee, ffff, gggg, hhhh, iiii from tttt, ttt1, ttt3 where aaaa = bbbb and bbbb = cccc and dddd+1 = eeee group by fff, gggg having hhhh = iiii and iiii = jjjj order by kkkk, llll limit 3, 4"
  5731  	)
  5732  
  5733  	for i, sql := range []string{sql1, sql2} {
  5734  		b.Run(fmt.Sprintf("sql%d", i), func(b *testing.B) {
  5735  			var buf bytes.Buffer
  5736  			buf.WriteString(sql)
  5737  			querySQL := buf.String()
  5738  			b.ReportAllocs()
  5739  			b.ResetTimer()
  5740  
  5741  			for i := 0; i < b.N; i++ {
  5742  				_, err := Parse(querySQL)
  5743  				if err != nil {
  5744  					b.Fatal(err)
  5745  				}
  5746  			}
  5747  		})
  5748  	}
  5749  }
  5750  
  5751  func BenchmarkParse3(b *testing.B) {
  5752  	largeQueryBenchmark := func(b *testing.B, escape bool) {
  5753  		b.Helper()
  5754  
  5755  		// benchQuerySize is the approximate size of the query.
  5756  		benchQuerySize := 1000000
  5757  
  5758  		// Size of value is 1/10 size of query. Then we add
  5759  		// 10 such values to the where clause.
  5760  		var baseval bytes.Buffer
  5761  		for i := 0; i < benchQuerySize/100; i++ {
  5762  			// Add an escape character: This will force the upcoming
  5763  			// tokenizer improvement to still create a copy of the string.
  5764  			// Then we can see if avoiding the copy will be worth it.
  5765  			if escape {
  5766  				baseval.WriteString("\\'123456789")
  5767  			} else {
  5768  				baseval.WriteString("123456789")
  5769  			}
  5770  		}
  5771  
  5772  		var buf bytes.Buffer
  5773  		buf.WriteString("select a from t1 where v = 1")
  5774  		for i := 0; i < 10; i++ {
  5775  			fmt.Fprintf(&buf, " and v%d = \"%d%s\"", i, i, baseval.String())
  5776  		}
  5777  		benchQuery := buf.String()
  5778  		b.ResetTimer()
  5779  		b.ReportAllocs()
  5780  
  5781  		for i := 0; i < b.N; i++ {
  5782  			if _, err := Parse(benchQuery); err != nil {
  5783  				b.Fatal(err)
  5784  			}
  5785  		}
  5786  	}
  5787  
  5788  	b.Run("normal", func(b *testing.B) {
  5789  		largeQueryBenchmark(b, false)
  5790  	})
  5791  
  5792  	b.Run("escaped", func(b *testing.B) {
  5793  		largeQueryBenchmark(b, true)
  5794  	})
  5795  }
  5796  
  5797  func TestValidUnionCases(t *testing.T) {
  5798  	testFile(t, "union_cases.txt", makeTestOutput(t))
  5799  }
  5800  
  5801  func TestValidSelectCases(t *testing.T) {
  5802  	testFile(t, "select_cases.txt", makeTestOutput(t))
  5803  }
  5804  
  5805  func makeTestOutput(t *testing.T) string {
  5806  	testOutputTempDir := utils.MakeTestOutput(t, "testdata", "parse_test")
  5807  
  5808  	t.Cleanup(func() {
  5809  		if !t.Failed() {
  5810  			_ = os.RemoveAll(testOutputTempDir)
  5811  		} else {
  5812  			t.Logf("Errors found. If the output is correct, run `cp %s/* testdata/` to update test expectations", testOutputTempDir)
  5813  		}
  5814  	})
  5815  
  5816  	return testOutputTempDir
  5817  }
  5818  
  5819  type testCase struct {
  5820  	file     string
  5821  	lineno   int
  5822  	input    string
  5823  	output   string
  5824  	errStr   string
  5825  	comments string
  5826  }
  5827  
  5828  func escapeNewLines(in string) string {
  5829  	return strings.ReplaceAll(in, "\n", "\\n")
  5830  }
  5831  
  5832  func testFile(t *testing.T, filename, tempDir string) {
  5833  	t.Run(filename, func(t *testing.T) {
  5834  		fail := false
  5835  		expected := strings.Builder{}
  5836  		for tcase := range iterateExecFile(filename) {
  5837  			t.Run(fmt.Sprintf("%d : %s", tcase.lineno, tcase.input), func(t *testing.T) {
  5838  				if tcase.output == "" && tcase.errStr == "" {
  5839  					tcase.output = tcase.input
  5840  				}
  5841  				expected.WriteString(fmt.Sprintf("%sINPUT\n%s\nEND\n", tcase.comments, escapeNewLines(tcase.input)))
  5842  				tree, err := Parse(tcase.input)
  5843  				if tcase.errStr != "" {
  5844  					errPresent := ""
  5845  					if err != nil {
  5846  						errPresent = err.Error()
  5847  					}
  5848  					expected.WriteString(fmt.Sprintf("ERROR\n%s\nEND\n", escapeNewLines(errPresent)))
  5849  					if err == nil || tcase.errStr != err.Error() {
  5850  						fail = true
  5851  						t.Errorf("File: %s, Line: %d\nDiff:\n%s\n[%s] \n[%s]", filename, tcase.lineno, cmp.Diff(tcase.errStr, errPresent), tcase.errStr, errPresent)
  5852  					}
  5853  				} else {
  5854  					if err != nil {
  5855  						expected.WriteString(fmt.Sprintf("ERROR\n%s\nEND\n", escapeNewLines(err.Error())))
  5856  						fail = true
  5857  						t.Errorf("File: %s:%d\nDiff:\n%s\n[%s] \n[%s]", filename, tcase.lineno, cmp.Diff(tcase.errStr, err.Error()), tcase.errStr, err.Error())
  5858  					} else {
  5859  						out := String(tree)
  5860  						expected.WriteString(fmt.Sprintf("OUTPUT\n%s\nEND\n", escapeNewLines(out)))
  5861  						if tcase.output != out {
  5862  							fail = true
  5863  							t.Errorf("Parsing failed. \nExpected/Got:\n%s\n%s", tcase.output, out)
  5864  						}
  5865  					}
  5866  				}
  5867  			})
  5868  		}
  5869  
  5870  		if fail && tempDir != "" {
  5871  			gotFile := fmt.Sprintf("%s/%s", tempDir, filename)
  5872  			_ = os.WriteFile(gotFile, []byte(strings.TrimSpace(expected.String())+"\n"), 0644)
  5873  			fmt.Println(fmt.Sprintf("Errors found in parse tests. If the output is correct, run `cp %s/* testdata/` to update test expectations", tempDir)) // nolint
  5874  		}
  5875  	})
  5876  }
  5877  
  5878  func iterateExecFile(name string) (testCaseIterator chan testCase) {
  5879  	name = locateFile(name)
  5880  	fd, err := os.OpenFile(name, os.O_RDONLY, 0)
  5881  	if err != nil {
  5882  		panic(fmt.Sprintf("Could not open file %s", name))
  5883  	}
  5884  
  5885  	testCaseIterator = make(chan testCase)
  5886  	var comments string
  5887  	go func() {
  5888  		defer close(testCaseIterator)
  5889  
  5890  		r := bufio.NewReader(fd)
  5891  		lineno := 0
  5892  		var output string
  5893  		var returnTypeNumber int
  5894  		var input string
  5895  		for {
  5896  			input, lineno, _ = parsePartial(r, []string{"INPUT"}, lineno, name)
  5897  			if input == "" && lineno == 0 {
  5898  				break
  5899  			}
  5900  			output, lineno, returnTypeNumber = parsePartial(r, []string{"OUTPUT", "ERROR"}, lineno, name)
  5901  			var errStr string
  5902  			if returnTypeNumber == 1 {
  5903  				errStr = output
  5904  				output = ""
  5905  			}
  5906  			testCaseIterator <- testCase{
  5907  				file:     name,
  5908  				lineno:   lineno,
  5909  				input:    input,
  5910  				comments: comments,
  5911  				output:   output,
  5912  				errStr:   errStr,
  5913  			}
  5914  			comments = ""
  5915  		}
  5916  	}()
  5917  	return testCaseIterator
  5918  }
  5919  
  5920  func parsePartial(r *bufio.Reader, readType []string, lineno int, fileName string) (string, int, int) {
  5921  	returnTypeNumber := -1
  5922  	for {
  5923  		binput, err := r.ReadBytes('\n')
  5924  		if err != nil {
  5925  			if err != io.EOF {
  5926  				panic(fmt.Errorf("error reading file %s: line %d: %s", fileName, lineno, err.Error()))
  5927  			}
  5928  			return "", 0, 0
  5929  		}
  5930  		lineno++
  5931  		input := string(binput)
  5932  		input = strings.TrimSpace(input)
  5933  		if input == "" || input == "\n" {
  5934  			continue
  5935  		}
  5936  		for i, str := range readType {
  5937  			if input == str {
  5938  				returnTypeNumber = i
  5939  				break
  5940  			}
  5941  		}
  5942  		if returnTypeNumber != -1 {
  5943  			break
  5944  		}
  5945  		panic(fmt.Errorf("error reading file %s: line %d: %s - Expected keyword", fileName, lineno, err.Error()))
  5946  	}
  5947  	input := ""
  5948  	for {
  5949  		l, err := r.ReadBytes('\n')
  5950  		lineno++
  5951  		if err != nil {
  5952  			panic(fmt.Sprintf("error reading file %s line# %d: %s", fileName, lineno, err.Error()))
  5953  		}
  5954  		str := strings.TrimSpace(string(l))
  5955  		if str == "END" {
  5956  			break
  5957  		}
  5958  		if input == "" {
  5959  			input += str
  5960  		} else {
  5961  			input += str + "\n"
  5962  		}
  5963  	}
  5964  	return input, lineno, returnTypeNumber
  5965  }
  5966  
  5967  func locateFile(name string) string {
  5968  	return "testdata/" + name
  5969  }