vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/mysql80/misc_test.go (about) 1 /* 2 Copyright 2021 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 vtgate 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 24 "vitess.io/vitess/go/test/endtoend/utils" 25 26 "vitess.io/vitess/go/test/endtoend/cluster" 27 28 "github.com/stretchr/testify/require" 29 30 "vitess.io/vitess/go/mysql" 31 ) 32 33 func TestFunctionInDefault(t *testing.T) { 34 defer cluster.PanicHandler(t) 35 ctx := context.Background() 36 conn, err := mysql.Connect(ctx, &vtParams) 37 require.NoError(t, err) 38 defer conn.Close() 39 40 // set the sql mode ALLOW_INVALID_DATES 41 utils.Exec(t, conn, `SET sql_mode = 'ALLOW_INVALID_DATES'`) 42 43 utils.Exec(t, conn, `create table function_default (x varchar(25) DEFAULT (TRIM(" check ")))`) 44 utils.Exec(t, conn, "drop table function_default") 45 46 utils.Exec(t, conn, `create table function_default ( 47 ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 48 dt DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 49 ts2 TIMESTAMP DEFAULT CURRENT_TIMESTAMP, 50 dt2 DATETIME DEFAULT CURRENT_TIMESTAMP, 51 ts3 TIMESTAMP DEFAULT 0, 52 dt3 DATETIME DEFAULT 0, 53 ts4 TIMESTAMP DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP, 54 dt4 DATETIME DEFAULT 0 ON UPDATE CURRENT_TIMESTAMP, 55 ts5 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 56 ts6 TIMESTAMP NULL ON UPDATE CURRENT_TIMESTAMP, 57 dt5 DATETIME ON UPDATE CURRENT_TIMESTAMP, 58 dt6 DATETIME NOT NULL ON UPDATE CURRENT_TIMESTAMP, 59 ts7 TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6), 60 ts8 TIMESTAMP DEFAULT NOW(), 61 ts9 TIMESTAMP DEFAULT LOCALTIMESTAMP, 62 ts10 TIMESTAMP DEFAULT LOCALTIME, 63 ts11 TIMESTAMP DEFAULT LOCALTIMESTAMP(), 64 ts12 TIMESTAMP DEFAULT LOCALTIME() 65 )`) 66 utils.Exec(t, conn, "drop table function_default") 67 68 // this query works because utc_timestamp will get parenthesised before reaching MySQL. However, this syntax is not supported in MySQL 8.0 69 utils.Exec(t, conn, `create table function_default (ts TIMESTAMP DEFAULT UTC_TIMESTAMP)`) 70 utils.Exec(t, conn, "drop table function_default") 71 72 utils.Exec(t, conn, `create table function_default (x varchar(25) DEFAULT "check")`) 73 utils.Exec(t, conn, "drop table function_default") 74 } 75 76 // TestCheckConstraint test check constraints on CREATE TABLE 77 // This feature is supported from MySQL 8.0.16 and MariaDB 10.2.1. 78 func TestCheckConstraint(t *testing.T) { 79 conn, err := mysql.Connect(context.Background(), &vtParams) 80 require.NoError(t, err) 81 defer conn.Close() 82 83 query := `CREATE TABLE t7 (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));` 84 utils.Exec(t, conn, query) 85 86 checkQuery := `SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_NAME = 't7' order by CONSTRAINT_NAME;` 87 expected := `[[VARCHAR("c1_nonzero")] [VARCHAR("c2_positive")] [VARCHAR("t7_chk_1")] [VARCHAR("t7_chk_2")] [VARCHAR("t7_chk_3")] [VARCHAR("t7_chk_4")]]` 88 89 utils.AssertMatches(t, conn, checkQuery, expected) 90 91 cleanup := `DROP TABLE t7` 92 utils.Exec(t, conn, cleanup) 93 } 94 95 func TestValueDefault(t *testing.T) { 96 vtParams := mysql.ConnParams{ 97 Host: "localhost", 98 Port: clusterInstance.VtgateMySQLPort, 99 } 100 conn, err := mysql.Connect(context.Background(), &vtParams) 101 require.NoError(t, err) 102 defer conn.Close() 103 104 utils.Exec(t, conn, `create table test_float_default (pos_f float default 2.1, neg_f float default -2.1,b blob default ('abc'));`) 105 defer utils.Exec(t, conn, `drop table test_float_default`) 106 utils.AssertMatches(t, conn, "select table_name, column_name, column_default from information_schema.columns where table_name = 'test_float_default' order by column_name", `[[VARBINARY("test_float_default") VARCHAR("b") BLOB("_utf8mb4\\'abc\\'")] [VARBINARY("test_float_default") VARCHAR("neg_f") BLOB("-2.1")] [VARBINARY("test_float_default") VARCHAR("pos_f") BLOB("2.1")]]`) 107 } 108 109 func TestVersionCommentWorks(t *testing.T) { 110 conn, err := mysql.Connect(context.Background(), &vtParams) 111 require.NoError(t, err) 112 defer conn.Close() 113 utils.Exec(t, conn, "/*!80000 SET SESSION information_schema_stats_expiry=0 */") 114 utils.Exec(t, conn, "/*!80000 SET SESSION information_schema_stats_expiry=0 */") 115 } 116 117 func TestSystemVariables(t *testing.T) { 118 conn, err := mysql.Connect(context.Background(), &vtParams) 119 require.NoError(t, err) 120 defer conn.Close() 121 122 tcs := []struct { 123 name string 124 value string 125 expectation string 126 comment string 127 }{ 128 {name: "sql_mode", value: "'only_full_group_by'", expectation: `[[VARCHAR("only_full_group_by")]]`}, 129 {name: "sql_mode", value: "' '", expectation: `[[VARCHAR(" ")]]`}, 130 {name: "sql_mode", value: "'only_full_group_by'", expectation: `[[VARCHAR("only_full_group_by")]]`, comment: "/* comment */"}, 131 {name: "sql_mode", value: "' '", expectation: `[[VARCHAR(" ")]]`, comment: "/* comment */"}, 132 } 133 134 for _, tc := range tcs { 135 t.Run(tc.name+tc.value, func(t *testing.T) { 136 utils.Exec(t, conn, fmt.Sprintf("set %s=%s", tc.name, tc.value)) 137 utils.AssertMatches(t, conn, fmt.Sprintf("select %s @@%s", tc.comment, tc.name), tc.expectation) 138 }) 139 } 140 } 141 142 func TestUseSystemAndUserVariables(t *testing.T) { 143 conn, err := mysql.Connect(context.Background(), &vtParams) 144 require.NoError(t, err) 145 defer conn.Close() 146 147 utils.Exec(t, conn, "set @@sql_mode = 'only_full_group_by,strict_trans_tables'") 148 utils.Exec(t, conn, "select 1 from information_schema.table_constraints") 149 150 utils.Exec(t, conn, "set @var = @@sql_mode") 151 utils.AssertMatches(t, conn, "select @var", `[[VARCHAR("only_full_group_by,strict_trans_tables")]]`) 152 153 utils.Exec(t, conn, "create table t(name varchar(100))") 154 utils.Exec(t, conn, "insert into t(name) values (@var)") 155 156 utils.AssertMatches(t, conn, "select name from t", `[[VARCHAR("only_full_group_by,strict_trans_tables")]]`) 157 158 utils.Exec(t, conn, "delete from t where name = @var") 159 utils.AssertMatches(t, conn, "select name from t", `[]`) 160 161 utils.Exec(t, conn, "drop table t") 162 } 163 164 func BenchmarkReservedConnWhenSettingSysVar(b *testing.B) { 165 conn, err := mysql.Connect(context.Background(), &vtParams) 166 require.NoError(b, err) 167 defer conn.Close() 168 169 _, err = conn.ExecuteFetch("create table t(id int)", 1000, true) 170 if err != nil { 171 b.Fatal(err) 172 } 173 174 defer func() { 175 _, err = conn.ExecuteFetch("drop table t", 1000, true) 176 if err != nil { 177 b.Fatal(err) 178 } 179 }() 180 181 _, err = conn.ExecuteFetch("set @@sql_mode = 'only_full_group_by,strict_trans_tables', @@sql_big_selects = 0, @@sql_safe_updates = 1, @@foreign_key_checks = 0", 1000, true) 182 if err != nil { 183 b.Fatal(err) 184 } 185 186 f := func(i int) { 187 _, err = conn.ExecuteFetch(fmt.Sprintf("insert into t(id) values (%d)", i), 1, true) 188 if err != nil { 189 b.Fatal(err) 190 } 191 _, err = conn.ExecuteFetch(fmt.Sprintf("select id from t where id = %d limit 1", i), 1, true) 192 if err != nil { 193 b.Fatal(err) 194 } 195 _, err = conn.ExecuteFetch(fmt.Sprintf("update t set id = 1 where id = %d", i), 1, true) 196 if err != nil { 197 b.Fatal(err) 198 } 199 _, err = conn.ExecuteFetch(fmt.Sprintf("delete from t where id = %d", i), 1, true) 200 if err != nil { 201 b.Fatal(err) 202 } 203 } 204 205 // warmup, plan and cache the plans 206 f(0) 207 208 benchmarkName := "Use SET_VAR" 209 for i := 0; i < 2; i++ { 210 b.Run(benchmarkName, func(b *testing.B) { 211 for i := 0; i < b.N; i++ { 212 f(i) 213 } 214 }) 215 216 // setting another sysvar that does not support SET_VAR, the next iteration of benchmark will use reserved connection 217 _, err = conn.ExecuteFetch("set @@sql_warnings = 1", 1, true) 218 if err != nil { 219 b.Fatal(err) 220 } 221 benchmarkName = "Use reserved connections" 222 } 223 } 224 225 func TestJsonFunctions(t *testing.T) { 226 defer cluster.PanicHandler(t) 227 ctx := context.Background() 228 conn, err := mysql.Connect(ctx, &vtParams) 229 require.NoError(t, err) 230 defer conn.Close() 231 232 utils.AssertMatches(t, conn, 233 `SELECT 234 JSON_QUOTE('null'), 235 JSON_QUOTE('"null"'), 236 JSON_OBJECT(BIN(1),2,'abc',ASCII(4)), 237 JSON_ARRAY(1, "abc", NULL, TRUE)`, 238 `[[VARBINARY("\"null\"") VARBINARY("\"\\\"null\\\"\"") JSON("{\"1\": 2, \"abc\": 52}") JSON("[1, \"abc\", null, true]")]]`) 239 240 utils.AssertMatches(t, conn, 241 `SELECT 242 JSON_CONTAINS('{"a": 1, "b": 2, "c": {"d": 4}}', '1'), 243 JSON_CONTAINS_PATH('{"a": 1, "b": 2, "c": {"d": 4}}', 'one', '$.a', '$.e'), 244 JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]'), 245 JSON_UNQUOTE(JSON_EXTRACT('["a","b"]', '$[1]')), 246 JSON_KEYS('{"a": 1, "b": {"c": 30}}'), 247 JSON_OVERLAPS("[1,3,5,7]", "[2,5,7]"), 248 JSON_SEARCH('["abc"]', 'one', 'abc'), 249 JSON_VALUE('{"fname": "Joe", "lname": "Palmer"}', '$.fname'), 250 JSON_ARRAY(4,5) MEMBER OF('[[3,4],[4,5]]')`, 251 `[[INT64(0) INT64(1) JSON("20") BLOB("b") JSON("[\"a\", \"b\"]") INT64(1) JSON("\"$[0]\"") VARBINARY("Joe") INT64(1)]]`) 252 253 utils.AssertMatches(t, conn, 254 `SELECT 255 JSON_SCHEMA_VALIDATION_REPORT('{"type":"string","pattern":"("}', '"abc"'), 256 JSON_SCHEMA_VALID('{"type":"string","pattern":"("}', '"abc"');`, 257 `[[JSON("{\"valid\": true}") INT64(1)]]`) 258 259 utils.Exec(t, conn, "create table jt(a JSON, b INT)") 260 utils.Exec(t, conn, `INSERT INTO jt (a, b) VALUES ("[3,10,5,\"x\",44]", 33), ("[3,10,5,17,[22,44,66]]", 0)`) 261 defer func() { 262 utils.Exec(t, conn, "drop table jt") 263 }() 264 265 utils.AssertMatches(t, conn, 266 `SELECT a->"$[4]", a->>"$[3]" FROM jt`, 267 `[[JSON("44") BLOB("x")] [JSON("[22, 44, 66]") BLOB("17")]]`) 268 269 utils.AssertMatches(t, conn, 270 `select JSON_DEPTH('{}'), JSON_LENGTH('{"a": 1, "b": {"c": 30}}', '$.b'), JSON_TYPE(JSON_EXTRACT('{"a": [10, true]}', '$.a')), JSON_VALID('{"a": 1}');`, 271 `[[INT64(1) INT64(1) VARBINARY("ARRAY") INT64(1)]]`) 272 273 utils.AssertMatches(t, conn, 274 `select 275 JSON_ARRAY_APPEND('{"a": 1}', '$', 'z'), 276 JSON_ARRAY_INSERT('["a", {"b": [1, 2]}, [3, 4]]', '$[0]', 'x', '$[2][1]', 'y'), 277 JSON_INSERT('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', CAST('[true, false]' AS JSON))`, 278 `[[JSON("[{\"a\": 1}, \"z\"]") JSON("[\"x\", \"a\", {\"b\": [1, 2]}, [3, 4]]") JSON("{\"a\": 1, \"b\": [2, 3], \"c\": [true, false]}")]]`) 279 280 utils.AssertMatches(t, conn, 281 `select 282 JSON_MERGE('[1, 2]', '[true, false]'), 283 JSON_MERGE_PATCH('{"name": "x"}', '{"id": 47}'), 284 JSON_MERGE_PRESERVE('[1, 2]', '{"id": 47}')`, 285 `[[JSON("[1, 2, true, false]") JSON("{\"id\": 47, \"name\": \"x\"}") JSON("[1, 2, {\"id\": 47}]")]]`) 286 287 utils.AssertMatches(t, conn, 288 `select 289 JSON_REMOVE('[1, [2, 3], 4]', '$[1]'), 290 JSON_REPLACE('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]'), 291 JSON_SET('{ "a": 1, "b": [2, 3]}', '$.a', 10, '$.c', '[true, false]'), 292 JSON_UNQUOTE('"abc"')`, 293 `[[JSON("[1, 4]") JSON("{\"a\": 10, \"b\": [2, 3]}") JSON("{\"a\": 10, \"b\": [2, 3], \"c\": \"[true, false]\"}") VARBINARY("abc")]]`) 294 }