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  }