vitess.io/vitess@v0.16.2/go/vt/sqlparser/tracked_buffer_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  	"testing"
    21  
    22  	"github.com/stretchr/testify/assert"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestBuildParsedQuery(t *testing.T) {
    27  	testcases := []struct {
    28  		in   string
    29  		args []any
    30  		out  string
    31  	}{{
    32  		in:  "select * from tbl",
    33  		out: "select * from tbl",
    34  	}, {
    35  		in:  "select * from tbl where b=4 or a=3",
    36  		out: "select * from tbl where b=4 or a=3",
    37  	}, {
    38  		in:  "select * from tbl where b = 4 or a = 3",
    39  		out: "select * from tbl where b = 4 or a = 3",
    40  	}, {
    41  		in:   "select * from tbl where name='%s'",
    42  		args: []any{"xyz"},
    43  		out:  "select * from tbl where name='xyz'",
    44  	}}
    45  
    46  	for _, tc := range testcases {
    47  		t.Run(tc.in, func(t *testing.T) {
    48  			parsed := BuildParsedQuery(tc.in, tc.args...)
    49  			assert.Equal(t, tc.out, parsed.Query)
    50  		})
    51  	}
    52  }
    53  
    54  func TestCanonicalOutput(t *testing.T) {
    55  	testcases := []struct {
    56  		input     string
    57  		canonical string
    58  	}{
    59  		{
    60  			"create table t(id int)",
    61  			"CREATE TABLE `t` (\n\t`id` int\n)",
    62  		},
    63  		{
    64  			"create algorithm = merge sql security definer view a (b,c,d) as select * from e with cascaded check option",
    65  			"CREATE ALGORITHM = merge SQL SECURITY DEFINER VIEW `a`(`b`, `c`, `d`) AS SELECT * FROM `e` WITH CASCADED CHECK OPTION",
    66  		},
    67  		{
    68  			"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",
    69  			"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",
    70  		},
    71  		{
    72  			"create table `a`(`id` int, primary key(`id`))",
    73  			"CREATE TABLE `a` (\n\t`id` int,\n\tPRIMARY KEY (`id`)\n)",
    74  		},
    75  		{
    76  			"create table `a`(`id` int unsigned, primary key(`id`))",
    77  			"CREATE TABLE `a` (\n\t`id` int unsigned,\n\tPRIMARY KEY (`id`)\n)",
    78  		},
    79  		{
    80  			"create table `a`(`id` int zerofill, primary key(`id`))",
    81  			"CREATE TABLE `a` (\n\t`id` int zerofill,\n\tPRIMARY KEY (`id`)\n)",
    82  		},
    83  		{
    84  			"create table `a`(`id` int primary key)",
    85  			"CREATE TABLE `a` (\n\t`id` int PRIMARY KEY\n)",
    86  		},
    87  		{
    88  			"create table a (id int not null auto_increment, v varchar(32) default null, v2 varchar(62) charset utf8mb4 collate utf8mb4_0900_ai_ci, key v_idx(v(16)))",
    89  			"CREATE TABLE `a` (\n\t`id` int NOT NULL AUTO_INCREMENT,\n\t`v` varchar(32) DEFAULT NULL,\n\t`v2` varchar(62) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci,\n\tKEY `v_idx` (`v`(16))\n)",
    90  		},
    91  		{
    92  			"create table a (id int not null primary key, dt datetime default current_timestamp)",
    93  			"CREATE TABLE `a` (\n\t`id` int NOT NULL PRIMARY KEY,\n\t`dt` datetime DEFAULT CURRENT_TIMESTAMP()\n)",
    94  		},
    95  		{
    96  			"create table `insert`(`update` int, primary key(`delete`))",
    97  			"CREATE TABLE `insert` (\n\t`update` int,\n\tPRIMARY KEY (`delete`)\n)",
    98  		},
    99  		{
   100  			"alter table a engine=InnoDB",
   101  			"ALTER TABLE `a` ENGINE InnoDB",
   102  		},
   103  		{
   104  			"create table a (v varchar(32)) engine=InnoDB",
   105  			"CREATE TABLE `a` (\n\t`v` varchar(32)\n) ENGINE InnoDB",
   106  		},
   107  		{
   108  			"create table a (id int not null primary key) engine InnoDB, charset utf8mb4, collate utf8mb4_0900_ai_ci partition by range (`id`) (partition `p10` values less than(10) engine InnoDB)",
   109  			"CREATE TABLE `a` (\n\t`id` int NOT NULL PRIMARY KEY\n) ENGINE InnoDB,\n  CHARSET utf8mb4,\n  COLLATE utf8mb4_0900_ai_ci\nPARTITION BY RANGE (`id`)\n(PARTITION `p10` VALUES LESS THAN (10) ENGINE InnoDB)",
   110  		},
   111  		{
   112  			"alter table a comment='a b c'",
   113  			"ALTER TABLE `a` COMMENT 'a b c'",
   114  		},
   115  		{
   116  			"alter table a add column c char not null default 'x'",
   117  			"ALTER TABLE `a` ADD COLUMN `c` char NOT NULL DEFAULT 'x'",
   118  		},
   119  		{
   120  			"alter table t2 modify column id bigint unsigned primary key",
   121  			"ALTER TABLE `t2` MODIFY COLUMN `id` bigint unsigned PRIMARY KEY",
   122  		},
   123  		{
   124  			"alter table t1 modify column a int first, modify column b int after a",
   125  			"ALTER TABLE `t1` MODIFY COLUMN `a` int FIRST, MODIFY COLUMN `b` int AFTER `a`",
   126  		},
   127  		{
   128  			"alter table t2 rename column foo to bar",
   129  			"ALTER TABLE `t2` RENAME COLUMN `foo` TO `bar`",
   130  		},
   131  		{
   132  			"alter table t1 drop key `PRIMARY`, add primary key (id,n)",
   133  			"ALTER TABLE `t1` DROP KEY `PRIMARY`, ADD PRIMARY KEY (`id`, `n`)",
   134  		},
   135  		{
   136  			"alter table t1 drop foreign key f",
   137  			"ALTER TABLE `t1` DROP FOREIGN KEY `f`",
   138  		},
   139  		{
   140  			"alter table t1 add constraint f foreign key (i) references parent (id) match simple on delete cascade on update set null",
   141  			"ALTER TABLE `t1` ADD CONSTRAINT `f` FOREIGN KEY (`i`) REFERENCES `parent` (`id`) MATCH SIMPLE ON DELETE CASCADE ON UPDATE SET NULL",
   142  		},
   143  		{
   144  			"alter table t1 remove partitioning",
   145  			"ALTER TABLE `t1` REMOVE PARTITIONING",
   146  		},
   147  		{
   148  			"alter table t1 partition by hash (id) partitions 5",
   149  			"ALTER TABLE `t1` \nPARTITION BY HASH (`id`) PARTITIONS 5",
   150  		},
   151  		{
   152  			"alter table t1 partition by list (id) (partition p1 values in (11, 21), partition p2 values in (12, 22))",
   153  			"ALTER TABLE `t1` \nPARTITION BY LIST (`id`)\n(PARTITION `p1` VALUES IN (11, 21),\n PARTITION `p2` VALUES IN (12, 22))",
   154  		},
   155  		{
   156  			"alter table t1 row_format=compressed, character set=utf8",
   157  			"ALTER TABLE `t1` ROW_FORMAT COMPRESSED, CHARSET utf8",
   158  		},
   159  		{
   160  			"create table a (id int primary key) row_format=compressed, character set=utf8mb4 collate=utf8mb4_0900_ai_ci",
   161  			"CREATE TABLE `a` (\n\t`id` int PRIMARY KEY\n) ROW_FORMAT COMPRESSED,\n  CHARSET utf8mb4,\n  COLLATE utf8mb4_0900_ai_ci",
   162  		},
   163  		{
   164  			"create table a (e enum('red','green','blue','orange','yellow'))",
   165  			"CREATE TABLE `a` (\n\t`e` enum('red', 'green', 'blue', 'orange', 'yellow')\n)",
   166  		},
   167  		{
   168  			"create table a (e set('red','green','blue','orange','yellow'))",
   169  			"CREATE TABLE `a` (\n\t`e` set('red', 'green', 'blue', 'orange', 'yellow')\n)",
   170  		},
   171  		{
   172  			"create table entries (uid varchar(53) not null, namespace varchar(254) not null, spec json default null, primary key (namespace, uid), key entries_spec_updatedAt ((json_value(spec, _utf8mb4 '$.updatedAt'))))",
   173  			"CREATE TABLE `entries` (\n\t`uid` varchar(53) NOT NULL,\n\t`namespace` varchar(254) NOT NULL,\n\t`spec` json DEFAULT NULL,\n\tPRIMARY KEY (`namespace`, `uid`),\n\tKEY `entries_spec_updatedAt` ((JSON_VALUE(`spec`, _utf8mb4 '$.updatedAt')))\n)",
   174  		},
   175  		{
   176  			"create table identifiers (id binary(16) not null default (uuid_to_bin(uuid(),true)))",
   177  			"CREATE TABLE `identifiers` (\n\t`id` binary(16) NOT NULL DEFAULT (uuid_to_bin(uuid(), true))\n)",
   178  		},
   179  		{
   180  			"create table t (\n\tid int auto_increment,\n\tusername varchar column_format dynamic\n)",
   181  			"CREATE TABLE `t` (\n\t`id` int AUTO_INCREMENT,\n\t`username` varchar COLUMN_FORMAT DYNAMIC\n)",
   182  		},
   183  		{
   184  			"create table t (\n\tid int auto_increment,\n\tusername varchar visible\n)",
   185  			"CREATE TABLE `t` (\n\t`id` int AUTO_INCREMENT,\n\t`username` varchar VISIBLE\n)",
   186  		},
   187  		{
   188  			"create table t (\n\tid int auto_increment,\n\tusername varchar engine_attribute '{}' secondary_engine_attribute '{}'\n)",
   189  			"CREATE TABLE `t` (\n\t`id` int AUTO_INCREMENT,\n\t`username` varchar ENGINE_ATTRIBUTE '{}' SECONDARY_ENGINE_ATTRIBUTE '{}'\n)",
   190  		},
   191  		{
   192  			"create table t (p point srid 0, g geometry not null srid 4326)",
   193  			"CREATE TABLE `t` (\n\t`p` point SRID 0,\n\t`g` geometry NOT NULL SRID 4326\n)",
   194  		},
   195  		{
   196  			"select regexp_replace('abc def ghi', '[a-z]+', 'X', 1, 3, 'c'), REGEXP_LIKE('dog cat dog', 'dog'), REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1), REGEXP_INSTR('aa aaa aaaa aaaa aaaa aaaa', 'a{4}',1), 'Michael!' RLIKE '.*' from dual",
   197  			"SELECT REGEXP_REPLACE('abc def ghi', '[a-z]+', 'X', 1, 3, 'c'), REGEXP_LIKE('dog cat dog', 'dog'), REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1), REGEXP_INSTR('aa aaa aaaa aaaa aaaa aaaa', 'a{4}', 1), 'Michael!' REGEXP '.*' FROM `dual`",
   198  		},
   199  		{
   200  			"select not regexp_replace('abc def ghi', '[a-z]+', 'X', 1, 3, 'c'), not regexp_like('dog cat dog', 'dog'), not regexp_substr('abc def ghi', '[a-z]+', 1), not regexp_instr('aa aaa aaaa aaaa aaaa aaaa', 'a{4}',1), 'Michael!' not rlike '.*' from dual",
   201  			"SELECT NOT REGEXP_REPLACE('abc def ghi', '[a-z]+', 'X', 1, 3, 'c'), NOT REGEXP_LIKE('dog cat dog', 'dog'), NOT REGEXP_SUBSTR('abc def ghi', '[a-z]+', 1), NOT REGEXP_INSTR('aa aaa aaaa aaaa aaaa aaaa', 'a{4}', 1), 'Michael!' NOT REGEXP '.*' FROM `dual`",
   202  		},
   203  		{
   204  			"revert /* vt+ foo */ vitess_migration '9aecb3b4_b8a9_11ec_929a_0a43f95f28a3'",
   205  			"REVERT /* vt+ foo */ VITESS_MIGRATION '9aecb3b4_b8a9_11ec_929a_0a43f95f28a3'",
   206  		},
   207  		{
   208  			"select count(a) from t",
   209  			"SELECT COUNT(`a`) FROM `t`",
   210  		},
   211  		{
   212  			"select var_pop(a) from products",
   213  			"SELECT VAR_POP(`a`) FROM `products`",
   214  		},
   215  		{
   216  			"select /* function with distinct */ count(distinct a) from t",
   217  			"SELECT /* function with distinct */ COUNT(DISTINCT `a`) FROM `t`",
   218  		},
   219  		{
   220  			"select char(77, 121, 83, 81, '76' using utf8mb4) from dual",
   221  			"SELECT CHAR(77, 121, 83, 81, '76' USING utf8mb4) FROM `dual`",
   222  		},
   223  		{
   224  			"create table t1 (id int primary key, name tinytext not null, fulltext key name_ft(name) with parser ngram)",
   225  			"CREATE TABLE `t1` (\n\t`id` int PRIMARY KEY,\n\t`name` tinytext NOT NULL,\n\tFULLTEXT KEY `name_ft` (`name`) WITH PARSER ngram\n)",
   226  		},
   227  		{
   228  			"select convert('abc' using utf8mb4)",
   229  			"SELECT CONVERT('abc' USING utf8mb4) FROM `dual`",
   230  		},
   231  	}
   232  
   233  	for _, tc := range testcases {
   234  		t.Run(tc.input, func(t *testing.T) {
   235  			tree, err := Parse(tc.input)
   236  			require.NoError(t, err, tc.input)
   237  
   238  			out := CanonicalString(tree)
   239  			require.Equal(t, tc.canonical, out, "bad serialization")
   240  
   241  			// Make sure we've generated a valid query!
   242  			rereadStmt, err := Parse(out)
   243  			require.NoError(t, err, out)
   244  			out = CanonicalString(rereadStmt)
   245  			require.Equal(t, tc.canonical, out, "bad serialization")
   246  		})
   247  	}
   248  }