// Copyright 2015 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // See the License for the specific language governing permissions and // limitations under the License. package expression_test import ( "github.com/juju/errors" . "github.com/pingcap/check" "github.com/pingcap/tidb" "github.com/pingcap/tidb/ast" "github.com/pingcap/tidb/context" "github.com/pingcap/tidb/expression" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/model" "github.com/pingcap/tidb/mysql" "github.com/pingcap/tidb/plan" "github.com/pingcap/tidb/sessionctx" "github.com/pingcap/tidb/store/tikv" "github.com/pingcap/tidb/table" "github.com/pingcap/tidb/util/charset" "github.com/pingcap/tidb/util/testkit" "github.com/pingcap/tidb/util/testleak" ) var _ = Suite(&testTypeInferrerSuite{}) type testTypeInferrerSuite struct { } func (ts *testTypeInferrerSuite) TestInferType(c *C) { c.Skip("we re-implement this test in plan/typeinfer_test.go") store, err := newStoreWithBootstrap() c.Assert(err, IsNil) defer store.Close() testKit := testkit.NewTestKit(c, store) testKit.MustExec("use test") sql := `create table t ( c_int int, c_bigint bigint, c_float float, c_double double, c_decimal decimal, c_datetime datetime, c_time time, c_timestamp timestamp, c_char char, c_varchar varchar(20), c_text text, c_binary binary, c_varbinary varbinary(20), c_blob blob, c_set set('a', 'b', 'c'), c_enum enum('a', 'b', 'c'))` testKit.MustExec(sql) tests := []struct { expr string tp byte chs string flag uint }{ {"c_int", mysql.TypeLong, charset.CharsetBin, mysql.BinaryFlag}, {"+1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"-1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"-'1'", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"-curtime()", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"-now()", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"~1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag | mysql.UnsignedFlag}, {"1e0", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"1.0", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"!true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"c_int is true", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"c_double is null", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"isnull(1/0)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"cast(1 as decimal)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"1 and 1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"1 or 1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"1 xor 1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"'1' & 2", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag}, {"'1' | 2", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag}, {"'1' ^ 2", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag}, {"'1' << 1", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag}, {"'1' >> 1", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag}, {"1 + '1'", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"1 + 1.1", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"now() + 0", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"curtime() + 0", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"now(0) + 0", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"now(2) + 0", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"now() + 1.1", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"now() + '1'", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"now(2) + '1'", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"now() + curtime()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"now() + now()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"now() + now(2)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"c_timestamp + 1", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"c_timestamp + 1.1", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"c_timestamp + '1.1'", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"c_set + 1", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"c_enum + 1", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"1.1 + now()", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"1 + now()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"1 div 2", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"1 / 2", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"1 > any (select 1)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"exists (select 1)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"1 in (2, 3)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"'abc' rlike 'abc'", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"(1+1)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, // Functions {"version()", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"abs()", mysql.TypeNull, charset.CharsetBin, mysql.BinaryFlag}, {"abs(1)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"abs(1.1)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"abs(cast(\"20150817015609\" as DATETIME))", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"IF(1>2,2,3)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"IFNULL(1,0)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"POW(2,2)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"POWER(2,2)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"LN(3)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"LOG(3)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"LOG(3, 10)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"LOG2(3)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"LOG10(3)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"SQRT(3)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"PI()", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"PI() + 0.000000000000000000", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"SIN(0)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"COS(0)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"TAN(0)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"COT(1)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"ACOS(1)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"ASIN(1)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"ATAN(1)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"ATAN(0, 1)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"rand()", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"curdate()", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag}, {"current_date()", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag}, {"DATE('2003-12-31 01:02:03')", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag}, {"curtime()", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"current_time()", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"curtime()", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"curtime(2)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"makedate(2017,31)", mysql.TypeDate, charset.CharsetBin, mysql.BinaryFlag}, {"maketime(12, 15, 30)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"sec_to_time(2378)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"current_timestamp()", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"utc_time()", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"utc_time(3)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"utc_timestamp()", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"microsecond('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"second('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"minute('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"hour('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"day('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"week('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"month('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"quarter('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"year('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"dayofweek('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"dayofmonth('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"dayofyear('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"weekday('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"weekofyear('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"yearweek('2009-12-31 23:59:59.000010')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"addtime(c_datetime, c_time)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"addtime(c_time, c_time)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"subtime(c_datetime, c_time)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"subtime(c_time, c_time)", mysql.TypeDuration, charset.CharsetBin, mysql.BinaryFlag}, {"found_rows()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"length('tidb')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"is_ipv4('192.168.1.1')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"period_add(199206, 2)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"period_diff(199206, 199006)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"now()", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"from_unixtime(1447430881)", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"from_unixtime(1447430881, '%Y %D %M %h:%i:%s %x')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {`from_unixtime(12.1) + 1`, mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"sysdate()", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"dayname('2007-02-03')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"version()", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"database()", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"schema()", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"user()", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"current_user()", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"CONCAT('T', 'i', 'DB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"CONCAT_WS('-', 'T', 'i', 'DB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"left('TiDB', 2)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"right('TiDB', 2)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"lower('TiDB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"lcase('TiDB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"locate('foo', 'foobar')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"position('foo' in 'foobar')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"repeat('TiDB', 3)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"replace('TiDB', 'D', 'd')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"upper('TiDB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"ucase('TiDB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"trim(' TiDB ')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"ltrim(' TiDB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"rtrim('TiDB ')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"connection_id()", mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag}, {"if(1>2, 2, 3)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"case c_int when null then 2 when 2 then 1.1 else 1 END", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"case c_int when null then 2 when 2 then 'tidb' else 1.1 END", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"case c_int when null then c_char when 2 then c_float else 1.1 END", mysql.TypeString, charset.CharsetUTF8, 0}, {"case c_int when null then c_binary when 2 then c_float else 1.1 END", mysql.TypeString, charset.CharsetBin, mysql.BinaryFlag}, // least() is the same as greatest() {"greatest('TiDB', 'D', 'd')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"greatest(1.1, 2.2)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"greatest('TiDB', 3)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_decimal, c_double)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_int, c_int)", mysql.TypeLong, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_int, c_double)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_bigint, c_int, c_int)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_varchar, c_text)", mysql.TypeBlob, charset.CharsetUTF8, 0}, {"greatest(c_binary, c_text)", mysql.TypeBlob, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_varchar, c_varbinary)", mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_enum, c_int)", mysql.TypeString, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_set, c_int)", mysql.TypeString, charset.CharsetBin, mysql.BinaryFlag}, {"greatest(c_enum, c_set)", mysql.TypeString, charset.CharsetUTF8, 0}, {"interval(1, 2, 3)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"interval(1.0, 2.0, 3.0)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"interval('1', '2', '3')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"round()", mysql.TypeNull, charset.CharsetBin, mysql.BinaryFlag}, {"round(null, 2)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"round('1.2', 2)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"round(1e2, 2)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"round(1.2, 2)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"round(true, 2)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"round(1000, 2)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"truncate(null, 2)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"truncate('1.2', 2)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"truncate(1e2, 2)", mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {"truncate(1.2, 2)", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"truncate(true, 2)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"truncate(1000, 2)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"hex('TiDB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"hex(12)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"unhex('TiDB')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"unhex(12)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"rpad('TiDB', 12, 'go')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"lpad('TiDB', 12, 'go')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"elt(1, 'TiDB', 17, 'go')", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"export_set(5, 'Y', 'N', ',', 4)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"bit_length('TiDB')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"char(66)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"char_length('TiDB')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"crc32('TiDB')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"instr('foobarbar', 'bar')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"timestampdiff(MINUTE,'2003-02-01','2003-05-01 12:05:55')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"sign(0)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"sign(null)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"unix_timestamp()", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"unix_timestamp('2015-11-13 10:20:19')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"to_days('2015-11-13')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"to_days(950501)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"ceiling()", mysql.TypeNull, charset.CharsetBin, mysql.BinaryFlag}, {"ceiling(1.23)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"ceil()", mysql.TypeNull, charset.CharsetBin, mysql.BinaryFlag}, {"ceil(1.23)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"floor()", mysql.TypeNull, charset.CharsetBin, mysql.BinaryFlag}, {"floor(1.23)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"field('foo', null)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"find_in_set('foo', 'foo,bar')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"find_in_set('foo', null)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"find_in_set(null, 'bar')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"conv('TiDB',36,10)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {"timestamp('2003-12-31 12:00:00')", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"timestamp('2003-12-31 12:00:00','12:00:00')", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"convert_tz('2003-12-31 12:00:00','GMT', 'MET')", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {"timestampadd(WEEK,40,'2003-01-01 01:01:01.000011')", mysql.TypeDatetime, charset.CharsetBin, mysql.BinaryFlag}, {`aes_encrypt("pingcap", "fit2cloud@2014")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`aes_decrypt("pingcap", "fit2cloud@2014")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`md5(123)`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`compress('love')`, mysql.TypeBlob, charset.CharsetBin, mysql.BinaryFlag}, {`uncompress('love')`, mysql.TypeLongBlob, charset.CharsetBin, mysql.BinaryFlag}, {`uncompressed_length('love')`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`sha1(123)`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`sha(123)`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`sha2(123, 256)`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`uuid()`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`from_base64('YWJj')`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`to_base64('abc')`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`random_bytes(32)`, mysql.TypeVarString, charset.CharsetBin, mysql.BinaryFlag}, {`coalesce(null, 0)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`coalesce(null, 0.1)`, mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {`coalesce(1, "1" + 1)`, mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {`coalesce(1, "abc")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`coalesce(c_int, c_char)`, mysql.TypeString, charset.CharsetUTF8, 0}, {`coalesce(c_int, c_binary)`, mysql.TypeString, charset.CharsetBin, mysql.BinaryFlag}, {`coalesce(c_int, c_int)`, mysql.TypeLong, charset.CharsetBin, mysql.BinaryFlag}, {`any_value("abc")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`any_value(1)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`any_value(1.234)`, mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {`degrees(1)`, mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {`radians(90)`, mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {`make_set(1 | 3, "hello", "nice", null, "world")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`oct(12)`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`exp(1)`, mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {`exp(1.23)`, mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {`exp('1.23')`, mysql.TypeDouble, charset.CharsetBin, mysql.BinaryFlag}, {`inet_aton('255.255.255.255')`, mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag}, {`inet_aton('')`, mysql.TypeLonglong, charset.CharsetBin, mysql.UnsignedFlag | mysql.BinaryFlag}, {`quote("Don\\'t!")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`insert("Titanium", 3, 6, "DB")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`is_ipv6('FE80::AAAA:0000:00C2:0002')`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`format(12332.123456, 4)`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {"inet_ntoa(1)", mysql.TypeVarString, charset.CharsetUTF8, 0}, {`ord('2')`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`ord(2)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`ord(true)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`ord(null)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`bin(1)`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {"to_seconds('2003-05-01 12:05:55')", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"to_seconds(950501)", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`bit_count(1)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`time_to_sec("23:59:59")`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`inet6_aton('FE80::AAAA:0000:00C2:0002')`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`inet6_ntoa(inet6_aton('FE80::AAAA:0000:00C2:0002'))`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`is_ipv4_mapped(c_varbinary)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`is_ipv4_compat(c_varbinary)`, mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {`password("abc")`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`json_type('3')`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`json_extract('{"a": 1}', '$.a')`, mysql.TypeJSON, charset.CharsetUTF8, 0}, {`json_unquote('{"a": 1}')`, mysql.TypeVarString, charset.CharsetUTF8, 0}, {`json_set('{"a": 1}', '$.a', 3)`, mysql.TypeJSON, charset.CharsetUTF8, 0}, {`json_insert('{"a": 1}', '$.a', 3)`, mysql.TypeJSON, charset.CharsetUTF8, 0}, {`json_replace('{"a": 1}', '$.a', 3)`, mysql.TypeJSON, charset.CharsetUTF8, 0}, {`json_merge('{"a": 1}', '3')`, mysql.TypeJSON, charset.CharsetUTF8, 0}, {"-9223372036854775809", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"-9223372036854775808", mysql.TypeLonglong, charset.CharsetBin, mysql.BinaryFlag}, {"--9223372036854775809", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, {"--9223372036854775808", mysql.TypeNewDecimal, charset.CharsetBin, mysql.BinaryFlag}, } for _, tt := range tests { ctx := testKit.Se.(context.Context) stmts, err := tidb.Parse(ctx, "select "+tt.expr+" from t") c.Assert(err, IsNil) c.Assert(stmts, HasLen, 1) stmt := stmts[0].(*ast.SelectStmt) is := sessionctx.GetDomain(ctx).InfoSchema() err = plan.ResolveName(stmt, is, ctx) c.Assert(err, IsNil) expression.InferType(ctx.GetSessionVars().StmtCtx, stmt) tp := stmt.GetResultFields()[0].Column.Tp chs := stmt.GetResultFields()[0].Column.Charset flag := stmt.GetResultFields()[0].Column.Flag c.Assert(tp, Equals, tt.tp, Commentf("Tp for %s", tt.expr)) c.Assert(chs, Equals, tt.chs, Commentf("Charset for %s", tt.expr)) c.Assert(flag^uint(tt.flag), Equals, uint(0x0), Commentf("Charset for %s", tt.flag)) } } func (s *testTypeInferrerSuite) TestColumnInfoModified(c *C) { defer testleak.AfterTest(c)() store, err := newStoreWithBootstrap() c.Assert(err, IsNil) defer store.Close() testKit := testkit.NewTestKit(c, store) testKit.MustExec("use test") testKit.MustExec("drop table if exists tab0") testKit.MustExec("CREATE TABLE tab0(col0 INTEGER, col1 INTEGER, col2 INTEGER)") testKit.MustExec("SELECT + - (- CASE + col0 WHEN + CAST( col0 AS SIGNED ) THEN col1 WHEN 79 THEN NULL WHEN + - col1 THEN col0 / + col0 END ) * - 16 FROM tab0") ctx := testKit.Se.(context.Context) is := sessionctx.GetDomain(ctx).InfoSchema() tbl, _ := is.TableByName(model.NewCIStr("test"), model.NewCIStr("tab0")) col := table.FindCol(tbl.Cols(), "col1") c.Assert(col.Tp, Equals, mysql.TypeLong) } func (s *testTypeInferrerSuite) TestIsHybridType(c *C) { defer testleak.AfterTest(c)() store, err := newStoreWithBootstrap() c.Assert(err, IsNil) defer store.Close() testKit := testkit.NewTestKit(c, store) testKit.MustExec("use test") testKit.MustExec("drop table if exists t") sql := `create table t ( c_enum enum('a', 'b', 'c', 'd'), c_set set('a', 'b', 'c', 'd'), c_bit bit(10), c_dt datetime, c_date date, c_time time, c_int int)` testKit.MustExec(sql) tests := []struct { expr string tp byte isHybridType bool }{ {"c_enum", mysql.TypeEnum, true}, {"c_set", mysql.TypeSet, true}, {"c_bit", mysql.TypeBit, true}, {"0b1001", mysql.TypeVarString, true}, {"0xFFFF", mysql.TypeVarString, true}, {"c_dt", mysql.TypeDatetime, false}, {"c_date", mysql.TypeDate, false}, {"c_time", mysql.TypeDuration, false}, {"c_int", mysql.TypeLong, false}, } for _, tt := range tests { ctx := testKit.Se.(context.Context) stmts, err := tidb.Parse(ctx, "select "+tt.expr+" from t") c.Assert(err, IsNil) c.Assert(stmts, HasLen, 1) stmt := stmts[0].(*ast.SelectStmt) is := sessionctx.GetDomain(ctx).InfoSchema() err = plan.ResolveName(stmt, is, ctx) c.Assert(err, IsNil) expression.InferType(ctx.GetSessionVars().StmtCtx, stmt) tp := stmt.GetResultFields()[0].Column.Tp c.Assert(tp, Equals, tt.tp, Commentf("Tp for %s", tt.expr)) p, err := plan.BuildLogicalPlan(ctx, stmt, is) c.Assert(err, IsNil) proj := p.(*plan.Projection) c.Assert(expression.IsHybridType(proj.Exprs[0]), Equals, tt.isHybridType) } } func newStoreWithBootstrap() (kv.Storage, error) { store, err := tikv.NewMockTikvStore() if err != nil { return nil, errors.Trace(err) } tidb.SetSchemaLease(0) _, err = tidb.BootstrapSession(store) return store, errors.Trace(err) }