From f9878128761809fb4f85492e982ee778b02e944e Mon Sep 17 00:00:00 2001 From: hustjieke Date: Thu, 2 Feb 2023 03:20:33 +0000 Subject: [PATCH] feat(tianmu): support_unsigned_data [tinyint~int32] #1267 [summary] 1. expand unsigned boundary from signed boundary to max valued. 2. code cover create/insert(delayed/no delayed mode)/update/delete/select. 3. functions and operators(agg and math calculation) refs: https://github.com/stoneatom/stonedb/issues/1266 related issue: #1151 --- mysql-test/suite/tianmu/README.md | 2 +- .../r/unsigned_support_issue1267.result | 363 ++++++++++++++++++ .../tianmu/t/unsigned_support_issue1267.test | 242 ++++++++++++ storage/tianmu/common/common_definitions.cpp | 40 +- storage/tianmu/core/column_type.cpp | 5 +- storage/tianmu/core/column_type.h | 6 +- storage/tianmu/core/data_type.cpp | 20 +- storage/tianmu/core/data_type.h | 7 +- storage/tianmu/core/engine.h | 5 +- storage/tianmu/core/engine_convert.cpp | 12 +- storage/tianmu/core/engine_results.cpp | 4 +- storage/tianmu/core/temp_table.cpp | 3 + storage/tianmu/handler/ha_tianmu.cpp | 60 ++- 13 files changed, 710 insertions(+), 59 deletions(-) create mode 100644 mysql-test/suite/tianmu/r/unsigned_support_issue1267.result create mode 100644 mysql-test/suite/tianmu/t/unsigned_support_issue1267.test diff --git a/mysql-test/suite/tianmu/README.md b/mysql-test/suite/tianmu/README.md index c9aed8fd9..c21432af5 100644 --- a/mysql-test/suite/tianmu/README.md +++ b/mysql-test/suite/tianmu/README.md @@ -32,6 +32,6 @@ The sample is as follows: ``` # Run Test Cases -1. Setting Running Parameters:mysql-test/include/default_mysqld.cnf +1. Setting Running Parameters: mysql-test/include/default_mysqld.cnf - default-storage-engine=tianmu - tianmu_insert_delayed=0 diff --git a/mysql-test/suite/tianmu/r/unsigned_support_issue1267.result b/mysql-test/suite/tianmu/r/unsigned_support_issue1267.result new file mode 100644 index 000000000..5139b74b5 --- /dev/null +++ b/mysql-test/suite/tianmu/r/unsigned_support_issue1267.result @@ -0,0 +1,363 @@ +drop database if exists unsigned_support; +Warnings: +Note 1008 Can't drop database 'unsigned_support'; database doesn't exist +create database unsigned_support; +use unsigned_support; +create table tiny(a tinyint, b tinyint unsigned) engine = tianmu DEFAULT CHARSET=utf8mb4; +insert into tiny values(-128, 0); +insert into tiny values(127, 127); +insert into tiny values(0, 127); +insert into tiny values(-0, -0); +insert into tiny values(+0, +0); +insert into tiny values(0, 129); +insert into tiny values(0, 255); +select * from tiny; +a b +-128 0 +127 127 +0 127 +0 0 +0 0 +0 129 +0 255 +insert into tiny values(-129, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into tiny values(128, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into tiny values(1234, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into tiny values(0, -1); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into tiny values(0, -127); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into tiny values(0, 256); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into tiny values(0, 1234567); +ERROR 22003: Out of range value for column 'b' at row 1 +select * from tiny; +a b +-128 0 +127 127 +0 127 +0 0 +0 0 +0 129 +0 255 +select avg(b), sum(b), max(b), min(b), count(b) from tiny; +avg(b) sum(b) max(b) min(b) count(b) +91.1429 638 255 0 7 +select bit_and(b), bit_or(b), bit_xor(b), group_concat(b), std(b), stddev(b), stddev_pop(b), stddev_samp(b), var_pop(b), var_samp(b), variance(b) from tiny; +bit_and(b) bit_or(b) bit_xor(b) group_concat(b) std(b) stddev(b) stddev_pop(b) stddev_samp(b) var_pop(b) var_samp(b) variance(b) +0 255 126 0,127,127,0,0,129,255 89.26273990133777 89.26273990133777 89.26273990133777 96.41477855499916 7967.836734693878 9295.809523809525 7967.836734693878 +select a+0, b+0 from tiny where a = -128 and b = 0 limit 2; +a+0 b+0 +-128 0 +select a+0, b+0 from tiny where a = 0 and b = -256; +a+0 b+0 +select a+0, b+0 from tiny where a != 0 and b != 0 and a=b; +a+0 b+0 +127 127 +select a+0, b+0 from tiny order by b desc; +a+0 b+0 +0 255 +0 129 +127 127 +0 127 +-128 0 +0 0 +0 0 +select b * 12345678910111213 from tiny; +b * 12345678910111213 +0 +1567901221584124051 +1567901221584124051 +0 +0 +1592592579404346477 +3148148122078359315 +select b * 123456789101112131 from tiny; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`unsigned_support`.`tiny`.`b` * 123456789101112131)' +select b * 12345678910111213123 from tiny; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`unsigned_support`.`tiny`.`b` * 12345678910111213123)' +select b * 12345678910111213123456 from tiny; +ERROR HY000: Numeric result of an expression is too large and cannot be handled by tianmu. Please use an explicit cast to a data type handled by tianmu, e.g. CAST( AS DECIMAL(18,6)). +drop table tiny; +create table small(a smallint, b smallint unsigned) engine = tianmu DEFAULT CHARSET=utf8mb4; +insert into small values(-32768, 0); +insert into small values(0, 0); +insert into small values(122, 122); +insert into small values(32767, 32767); +insert into small values(-0, -0); +insert into small values(+0, +0); +insert into small values(0, 32769); +insert into small values(0, 41234); +insert into small values(0, 65535); +select * from small; +a b +-32768 0 +0 0 +122 122 +32767 32767 +0 0 +0 0 +0 32769 +0 41234 +0 65535 +insert into small values(-32769, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into small values(32768, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into small values(-3276911, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into small values(3276811, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into small values(0, -1); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into small values(0, -32768); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into small values(0, 65536); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into small values(0, 1234567); +ERROR 22003: Out of range value for column 'b' at row 1 +select * from small; +a b +-32768 0 +0 0 +122 122 +32767 32767 +0 0 +0 0 +0 32769 +0 41234 +0 65535 +select avg(b), sum(b), max(b), min(b), count(b) from small; +avg(b) sum(b) max(b) min(b) count(b) +19158.5556 172427 65535 0 9 +select bit_and(b), bit_or(b), bit_xor(b), group_concat(b), std(b), stddev(b), stddev_pop(b), stddev_samp(b), var_pop(b), var_samp(b), variance(b) from small; +bit_and(b) bit_or(b) bit_xor(b) group_concat(b) std(b) stddev(b) stddev_pop(b) stddev_samp(b) var_pop(b) var_samp(b) variance(b) +0 65535 41321 0,0,122,32767,0,0,32769,41234,65535 23187.94048691456 23187.94048691456 23187.94048691456 24594.524940071067 537680584.0246913 604890657.0277778 537680584.0246913 +select a+0, b+0 from small where a = -32768 and b = 0 limit 2; +a+0 b+0 +-32768 0 +select a+0, b+0 from small where a = 0 and b = -32768; +a+0 b+0 +select a+0, b+0 from small where a != 0 and b != 0 and a=b; +a+0 b+0 +122 122 +32767 32767 +select a+0, b+0 from small order by b desc; +a+0 b+0 +0 65535 +0 41234 +0 32769 +32767 32767 +122 122 +-32768 0 +0 0 +0 0 +0 0 +select b * 123456789101112 from small; +b * 123456789101112 +0 +0 +15061728270335664 +4045308608476136904 +0 +0 +4045555522054339128 +5090617241795252208 +8090740673741374920 +select b * 123456789101112131 from small; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`unsigned_support`.`small`.`b` * 123456789101112131)' +select b * 12345678910111213123 from small; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`unsigned_support`.`small`.`b` * 12345678910111213123)' +select b * 12345678910111213123456 from small; +ERROR HY000: Numeric result of an expression is too large and cannot be handled by tianmu. Please use an explicit cast to a data type handled by tianmu, e.g. CAST( AS DECIMAL(18,6)). +drop table small; +create table medium(a mediumint, b mediumint unsigned) engine = tianmu DEFAULT CHARSET=utf8mb4; +insert into medium values(-8388608, 0); +insert into medium values(0, 0); +insert into medium values(122, 122); +insert into medium values(8388607, 8388607); +insert into medium values(-0, -0); +insert into medium values(+0, +0); +insert into medium values(0, 8388609); +insert into medium values(0, 8388610); +insert into medium values(0, 16777215); +select * from medium; +a b +-8388608 0 +0 0 +122 122 +8388607 8388607 +0 0 +0 0 +0 8388609 +0 8388610 +0 16777215 +insert into medium values(-8388609, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into medium values(8388608, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into medium values(-8388608111, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into medium values(8388608111, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into medium values(0, -1); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into medium values(0, -8388608); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into medium values(0, 16777216); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into medium values(0, 1677721511); +ERROR 22003: Out of range value for column 'b' at row 1 +select * from medium; +a b +-8388608 0 +0 0 +122 122 +8388607 8388607 +0 0 +0 0 +0 8388609 +0 8388610 +0 16777215 +select avg(b), sum(b), max(b), min(b), count(b) from medium; +avg(b) sum(b) max(b) min(b) count(b) +4660351.4444 41943163 16777215 0 9 +select bit_and(b), bit_or(b), bit_xor(b), group_concat(b), std(b), stddev(b), stddev_pop(b), stddev_samp(b), var_pop(b), var_samp(b), variance(b) from medium; +bit_and(b) bit_or(b) bit_xor(b) group_concat(b) std(b) stddev(b) stddev_pop(b) stddev_samp(b) var_pop(b) var_samp(b) variance(b) +0 16777215 8388729 0,0,122,8388607,0,0,8388609,8388610,16777215 5745639.206166323 5745639.206166323 5745639.206166323 6094170.667397249 33012369887435.582 37138916123365.03 33012369887435.582 +select a+0, b+0 from medium where a = -8388608 and b = 0 limit 2; +a+0 b+0 +-8388608 0 +select a+0, b+0 from medium where a = 0 and b = -8388608; +a+0 b+0 +select a+0, b+0 from medium where a != 0 and b != 0 and a=b; +a+0 b+0 +122 122 +8388607 8388607 +select a+0, b+0 from medium order by b desc; +a+0 b+0 +0 16777215 +0 8388610 +0 8388609 +8388607 8388607 +122 122 +-8388608 0 +0 0 +0 0 +0 0 +select b * 123456789101 from medium; +b * 123456789101 +0 +0 +15061728270322 +1035630485250172307 +0 +0 +1035630732163750509 +1035630855620539610 +2071261093957133715 +select b * 12345678910123 from medium; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`unsigned_support`.`medium`.`b` * 12345678910123)' +select b * 12345678910111213123 from medium; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`unsigned_support`.`medium`.`b` * 12345678910111213123)' +select b * 123456789101112131234 from medium; +ERROR HY000: Numeric result of an expression is too large and cannot be handled by tianmu. Please use an explicit cast to a data type handled by tianmu, e.g. CAST( AS DECIMAL(18,6)). +drop table medium; +create table int_(a int, b int unsigned) engine = tianmu DEFAULT CHARSET=utf8mb4; +insert into int_ values(-2147483647, 0); +insert into int_ values(0, 0); +insert into int_ values(122, 122); +insert into int_ values(2147483647, 2147483647); +insert into int_ values(-0, -0); +insert into int_ values(+0, +0); +insert into int_ values(0, 2147483649); +insert into int_ values(0, 3294967295); +insert into int_ values(0, 4294967295); +select * from int_; +a b +-2147483647 0 +0 0 +122 122 +2147483647 2147483647 +0 0 +0 0 +0 2147483649 +0 3294967295 +0 4294967295 +insert into int_ values(-2147483649, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into int_ values(2147483648, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into int_ values(-214748364811, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into int_ values(214748364811, 0); +ERROR 22003: Out of range value for column 'a' at row 1 +insert into int_ values(-2147483648, 0); +ERROR 22003: Out of range[-2147483647, 2147483647] for column 'a' value: -2147483648 +insert into int_ values(0, -1); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into int_ values(0, -4294967295); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into int_ values(0, 4294967296); +ERROR 22003: Out of range value for column 'b' at row 1 +insert into int_ values(0, 429496729611); +ERROR 22003: Out of range value for column 'b' at row 1 +select * from int_; +a b +-2147483647 0 +0 0 +122 122 +2147483647 2147483647 +0 0 +0 0 +0 2147483649 +0 3294967295 +0 4294967295 +select avg(b), sum(b), max(b), min(b), count(b) from int_; +avg(b) sum(b) max(b) min(b) count(b) +1320544667.5556 11884902008 4294967295 0 9 +select bit_and(b), bit_or(b), bit_xor(b), group_concat(b), std(b), stddev(b), stddev_pop(b), stddev_samp(b), var_pop(b), var_samp(b), variance(b) from int_; +bit_and(b) bit_or(b) bit_xor(b) group_concat(b) std(b) stddev(b) stddev_pop(b) stddev_samp(b) var_pop(b) var_samp(b) variance(b) +0 4294967295 3294967172 0,0,122,2147483647,0,0,2147483649,3294967295,4294967295 1592774713.9996257 1592774713.9996257 1592774713.9996257 1689392701.7573988 2.5369312895565896e18 2.8540477007511634e18 2.5369312895565896e18 +select a+0, b+0 from int_ where a = -2147483647 and b = 0 limit 2; +a+0 b+0 +-2147483647 0 +select a+0, b+0 from int_ where a = 0 and b = -2147483648; +a+0 b+0 +select a+0, b+0 from int_ where a != 0 and b != 0 and a=b; +a+0 b+0 +122 122 +2147483647 2147483647 +select a+0, b+0 from int_ order by b desc; +a+0 b+0 +0 4294967295 +0 3294967295 +0 2147483649 +2147483647 2147483647 +122 122 +-2147483647 0 +0 0 +0 0 +0 0 +select b * 1234567891 from int_; +b * 1234567891 +0 +0 +150617282702 +2651214357033778477 +0 +0 +2651214359502914259 +4067860824302124845 +5302428715302124845 +select b * 12345678910 from int_; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`unsigned_support`.`int_`.`b` * 12345678910)' +select b * 12345678910123456789 from int_; +ERROR 22003: BIGINT UNSIGNED value is out of range in '(`unsigned_support`.`int_`.`b` * 12345678910123456789)' +select b * 123456789101234567891 from int_; +ERROR HY000: Numeric result of an expression is too large and cannot be handled by tianmu. Please use an explicit cast to a data type handled by tianmu, e.g. CAST( AS DECIMAL(18,6)). +drop table int_; +drop database unsigned_support; diff --git a/mysql-test/suite/tianmu/t/unsigned_support_issue1267.test b/mysql-test/suite/tianmu/t/unsigned_support_issue1267.test new file mode 100644 index 000000000..41ef95c09 --- /dev/null +++ b/mysql-test/suite/tianmu/t/unsigned_support_issue1267.test @@ -0,0 +1,242 @@ +--source include/have_tianmu.inc + +drop database if exists unsigned_support; +create database unsigned_support; +use unsigned_support; +create table tiny(a tinyint, b tinyint unsigned) engine = tianmu DEFAULT CHARSET=utf8mb4; +# test insert correctly +insert into tiny values(-128, 0); +insert into tiny values(127, 127); +insert into tiny values(0, 127); +insert into tiny values(-0, -0); +insert into tiny values(+0, +0); +# unsigned > 127 +#TODO deal with treated 128 as null, only exists in agg: insert into tiny values(0, 128); +insert into tiny values(0, 129); +insert into tiny values(0, 255); +select * from tiny; +# before: test out of range, currently the max value of unsigned is equal to signed +# after: the max value of unsigned is equal to max unsigned +# column signed a out of value +--error 1264 +insert into tiny values(-129, 0); +--error 1264 +insert into tiny values(128, 0); +--error 1264 +insert into tiny values(1234, 0); +# column unsigned b out of value(>255 || <0), deal with mysql +--error 1264 +insert into tiny values(0, -1); +--error 1264 +insert into tiny values(0, -127); +--error 1264 +insert into tiny values(0, 256); +--error 1264 +insert into tiny values(0, 1234567); +select * from tiny; + +# test agg, refs: https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions.html#function_bit-and +# test basic agg, Item func override impl by tianmu +select avg(b), sum(b), max(b), min(b), count(b) from tiny; +# advanced agg, override by tianmu +select bit_and(b), bit_or(b), bit_xor(b), group_concat(b), std(b), stddev(b), stddev_pop(b), stddev_samp(b), var_pop(b), var_samp(b), variance(b) from tiny; +# test operators +# test where, limit, order by clause +select a+0, b+0 from tiny where a = -128 and b = 0 limit 2; +select a+0, b+0 from tiny where a = 0 and b = -256; +select a+0, b+0 from tiny where a != 0 and b != 0 and a=b; +select a+0, b+0 from tiny order by b desc; + +# test boundary operations, unsigned bigint is 20 bits digits +select b * 12345678910111213 from tiny; +# error like mysql does: BIGINT UNSIGNED value is out of range in '(`test`.`tiny`.`b` * 1234567891011121312)' +--error 1690 +select b * 123456789101112131 from tiny; +--error 1690 +select b * 12345678910111213123 from tiny; +# error(mysql will be numeric results, diff with tianmu): Numeric result of an expression is too large and cannot be handled by tianmu. Please use an explicit cast to a data type handled by tianmu, e.g. CAST( AS DECIMAL(18,6)). +--error 1105 +select b * 12345678910111213123456 from tiny; + +drop table tiny; + +create table small(a smallint, b smallint unsigned) engine = tianmu DEFAULT CHARSET=utf8mb4; +# test insert correctly +insert into small values(-32768, 0); +insert into small values(0, 0); +insert into small values(122, 122); +insert into small values(32767, 32767); +insert into small values(-0, -0); +insert into small values(+0, +0); +#TODO deal with null: insert into small values(0, 32768); +insert into small values(0, 32769); +insert into small values(0, 41234); +insert into small values(0, 65535); +select * from small; +# test out of range, currently the max value of unsigned is equal to signed +# column signed a out of value +--error 1264 +insert into small values(-32769, 0); +--error 1264 +insert into small values(32768, 0); +--error 1264 +insert into small values(-3276911, 0); +--error 1264 +insert into small values(3276811, 0); +# column unsigned b out of value(>65535 || <0), deal with mysql +--error 1264 +insert into small values(0, -1); +--error 1264 +insert into small values(0, -32768); +--error 1264 +insert into small values(0, 65536); +--error 1264 +insert into small values(0, 1234567); +select * from small; + +# test agg, refs: https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions.html#function_bit-and +# test basic agg, Item func override impl by tianmu +select avg(b), sum(b), max(b), min(b), count(b) from small; +# advanced agg, override by tianmu +select bit_and(b), bit_or(b), bit_xor(b), group_concat(b), std(b), stddev(b), stddev_pop(b), stddev_samp(b), var_pop(b), var_samp(b), variance(b) from small; +# test operators +# test where, limit, order by clause +select a+0, b+0 from small where a = -32768 and b = 0 limit 2; +select a+0, b+0 from small where a = 0 and b = -32768; +select a+0, b+0 from small where a != 0 and b != 0 and a=b; +select a+0, b+0 from small order by b desc; + +# test boundary operations, unsigned bigint is 20 bits digits +select b * 123456789101112 from small; +# error like mysql does: BIGINT UNSIGNED value is out of range in '(`test`.`small`.`b` * 1234567891011121312)' +--error 1690 +select b * 123456789101112131 from small; +--error 1690 +select b * 12345678910111213123 from small; +# error(mysql will be numeric results, diff with tianmu): Numeric result of an expression is too large and cannot be handled by tianmu. Please use an explicit cast to a data type handled by tianmu, e.g. CAST( AS DECIMAL(18,6)). +--error 1105 +select b * 12345678910111213123456 from small; + +drop table small; + +create table medium(a mediumint, b mediumint unsigned) engine = tianmu DEFAULT CHARSET=utf8mb4; +# test insert correctly +insert into medium values(-8388608, 0); +insert into medium values(0, 0); +insert into medium values(122, 122); +insert into medium values(8388607, 8388607); +insert into medium values(-0, -0); +insert into medium values(+0, +0); +#TODO deal with null: insert into medium values(0, 8388608); +insert into medium values(0, 8388609); +insert into medium values(0, 8388610); +insert into medium values(0, 16777215); +select * from medium; +# test out of range, currently the max value of unsigned is equal to signed +# column signed a out of value +--error 1264 +insert into medium values(-8388609, 0); +--error 1264 +insert into medium values(8388608, 0); +--error 1264 +insert into medium values(-8388608111, 0); +--error 1264 +insert into medium values(8388608111, 0); +# column unsigned b out of value(>8388607 || <0), deal with mysql +--error 1264 +insert into medium values(0, -1); +--error 1264 +insert into medium values(0, -8388608); +--error 1264 +insert into medium values(0, 16777216); +--error 1264 +insert into medium values(0, 1677721511); +select * from medium; + +# test agg, refs: https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions.html#function_bit-and +# test basic agg, Item func override impl by tianmu +select avg(b), sum(b), max(b), min(b), count(b) from medium; +# advanced agg, override by tianmu +select bit_and(b), bit_or(b), bit_xor(b), group_concat(b), std(b), stddev(b), stddev_pop(b), stddev_samp(b), var_pop(b), var_samp(b), variance(b) from medium; +# test operators +# test where, limit, order by clause +select a+0, b+0 from medium where a = -8388608 and b = 0 limit 2; +select a+0, b+0 from medium where a = 0 and b = -8388608; +select a+0, b+0 from medium where a != 0 and b != 0 and a=b; +select a+0, b+0 from medium order by b desc; + +# test boundary operations, unsigned bigint is 20 bits digits +select b * 123456789101 from medium; +# error like mysql does: BIGINT UNSIGNED value is out of range in '(`test`.`medium`.`b` * 1234567891011121312)' +--error 1690 +select b * 12345678910123 from medium; +--error 1690 +select b * 12345678910111213123 from medium; +# error(mysql will be numeric results, diff with tianmu): Numeric result of an expression is too large and cannot be handled by tianmu. Please use an explicit cast to a data type handled by tianmu, e.g. CAST( AS DECIMAL(18,6)). +--error 1105 +select b * 123456789101112131234 from medium; + +drop table medium; + +create table int_(a int, b int unsigned) engine = tianmu DEFAULT CHARSET=utf8mb4; +# test insert correctly, range[-2147483647, 2147483647] +insert into int_ values(-2147483647, 0); +insert into int_ values(0, 0); +insert into int_ values(122, 122); +insert into int_ values(2147483647, 2147483647); +insert into int_ values(-0, -0); +insert into int_ values(+0, +0); +#TODO: deal with 2147483648 +insert into int_ values(0, 2147483649); +insert into int_ values(0, 3294967295); +insert into int_ values(0, 4294967295); +select * from int_; +# test out of range, currently the max value of unsigned is equal to signed +# column signed a out of value +--error 1264 +insert into int_ values(-2147483649, 0); +--error 1264 +insert into int_ values(2147483648, 0); +--error 1264 +insert into int_ values(-214748364811, 0); +--error 1264 +insert into int_ values(214748364811, 0); +# deal with tianmu, -2147483648 also deal with tianmu +--error 1264 +insert into int_ values(-2147483648, 0); +# column unsigned b out of value(>4294967295 || <0), deal with mysql +--error 1264 +insert into int_ values(0, -1); +--error 1264 +insert into int_ values(0, -4294967295); +--error 1264 +insert into int_ values(0, 4294967296); +--error 1264 +insert into int_ values(0, 429496729611); +select * from int_; + +# test agg, refs: https://dev.mysql.com/doc/refman/5.7/en/aggregate-functions.html#function_bit-and +# test basic agg, Item func override impl by tianmu +select avg(b), sum(b), max(b), min(b), count(b) from int_; +# advanced agg, override by tianmu +select bit_and(b), bit_or(b), bit_xor(b), group_concat(b), std(b), stddev(b), stddev_pop(b), stddev_samp(b), var_pop(b), var_samp(b), variance(b) from int_; +# test operators +# test where, limit, order by clause +select a+0, b+0 from int_ where a = -2147483647 and b = 0 limit 2; +select a+0, b+0 from int_ where a = 0 and b = -2147483648; +select a+0, b+0 from int_ where a != 0 and b != 0 and a=b; +select a+0, b+0 from int_ order by b desc; + +# test boundary operations, unsigned bigint is 20 bits digits +select b * 1234567891 from int_; +# error like mysql does: BIGINT UNSIGNED value is out of range in '(`test`.`int_`.`b` * 1234567891011121312)' +--error 1690 +select b * 12345678910 from int_; +--error 1690 +select b * 12345678910123456789 from int_; +# error(mysql will be numeric results, diff with tianmu): Numeric result of an expression is too large and cannot be handled by tianmu. Please use an explicit cast to a data type handled by tianmu, e.g. CAST( AS DECIMAL(18,6)). +--error 1105 +select b * 123456789101234567891 from int_; + +drop table int_; +drop database unsigned_support; diff --git a/storage/tianmu/common/common_definitions.cpp b/storage/tianmu/common/common_definitions.cpp index 15d44c77c..a57f164a0 100644 --- a/storage/tianmu/common/common_definitions.cpp +++ b/storage/tianmu/common/common_definitions.cpp @@ -40,10 +40,12 @@ void PushWarningIfOutOfRange(THD *thd, std::string col_name, int64_t v, int type // below `0` is for min unsigned value. switch (type) { case 1: { // MYSQL_TYPE_TINY - if (unsigned_flag && (static_cast(v) > TIANMU_TINYINT_MAX)) { - PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, - getErrMsg(col_name, 0, TIANMU_TINYINT_MAX, unsigned_flag, v).c_str()); - throw std::exception(); + if (unsigned_flag) { + if (static_cast(v) > UINT_MAX8) { + PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, + getErrMsg(col_name, 0, UINT_MAX8, unsigned_flag, v).c_str()); + throw std::exception(); + } } else if (v > TIANMU_TINYINT_MAX || v < TIANMU_TINYINT_MIN) { PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, getErrMsg(col_name, TIANMU_TINYINT_MIN, TIANMU_TINYINT_MAX, unsigned_flag, v).c_str()); @@ -51,10 +53,12 @@ void PushWarningIfOutOfRange(THD *thd, std::string col_name, int64_t v, int type } } break; case 2: { // MYSQL_TYPE_SHORT - if (unsigned_flag && (static_cast(v) > TIANMU_SMALLINT_MAX)) { - PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, - getErrMsg(col_name, 0, TIANMU_SMALLINT_MAX, unsigned_flag, v).c_str()); - throw std::exception(); + if (unsigned_flag) { + if (static_cast(v) > UINT_MAX16) { + PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, + getErrMsg(col_name, 0, UINT_MAX16, unsigned_flag, v).c_str()); + throw std::exception(); + } } else if (v > TIANMU_SMALLINT_MAX || v < TIANMU_SMALLINT_MIN) { PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, getErrMsg(col_name, TIANMU_SMALLINT_MIN, TIANMU_SMALLINT_MAX, unsigned_flag, v).c_str()); @@ -62,10 +66,12 @@ void PushWarningIfOutOfRange(THD *thd, std::string col_name, int64_t v, int type }; } break; case 9: { // MYSQL_TYPE_INT24 - if (unsigned_flag && (static_cast(v) > TIANMU_MEDIUMINT_MAX)) { - PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, - getErrMsg(col_name, 0, TIANMU_MEDIUMINT_MAX, unsigned_flag, v).c_str()); - throw std::exception(); + if (unsigned_flag) { + if (static_cast(v) > UINT_MAX24) { + PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, + getErrMsg(col_name, 0, UINT_MAX24, unsigned_flag, v).c_str()); + throw std::exception(); + } } else if (v > TIANMU_MEDIUMINT_MAX || v < TIANMU_MEDIUMINT_MIN) { PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, getErrMsg(col_name, TIANMU_MEDIUMINT_MIN, TIANMU_MEDIUMINT_MAX, unsigned_flag, v).c_str()); @@ -73,10 +79,12 @@ void PushWarningIfOutOfRange(THD *thd, std::string col_name, int64_t v, int type } } break; case 3: { // MYSQL_TYPE_LONG - if (unsigned_flag && (static_cast(v) > TIANMU_INT_MAX)) { - PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, - getErrMsg(col_name, 0, TIANMU_INT_MAX, unsigned_flag, v).c_str()); - throw std::exception(); + if (unsigned_flag) { + if (static_cast(v) > UINT_MAX32) { + PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, + getErrMsg(col_name, 0, UINT_MAX32, unsigned_flag, v).c_str()); + throw std::exception(); + } } else if (v > TIANMU_INT_MAX || v < TIANMU_INT_MIN) { PushWarning(thd, Sql_condition::SL_WARNING, ER_WARN_DATA_OUT_OF_RANGE, getErrMsg(col_name, TIANMU_INT_MIN, TIANMU_INT_MAX, unsigned_flag, v).c_str()); diff --git a/storage/tianmu/core/column_type.cpp b/storage/tianmu/core/column_type.cpp index 159954c53..906255d58 100644 --- a/storage/tianmu/core/column_type.cpp +++ b/storage/tianmu/core/column_type.cpp @@ -26,6 +26,7 @@ namespace core { ColumnType::ColumnType(const DataType &dt) { if (dt.IsFixed()) { ColumnType ct(dt.attrtype, false, common::PackFmt::DEFAULT, QuickMath::precision10(dt.fixmax), dt.fixscale); + ct.SetUnsigned(dt.unsigned_flag_); std::swap(ct, *this); } else if (dt.IsFloat()) { ColumnType ct(common::ColumnType::REAL, false, common::PackFmt::DEFAULT, QuickMath::precision10(dt.fixmax), -1); @@ -41,7 +42,7 @@ ColumnType::ColumnType(const DataType &dt) { } bool ColumnType::operator==(const ColumnType &ct2) const { - if (type == ct2.type && Lookup() == ct2.Lookup() && + if (type == ct2.type && Lookup() == ct2.Lookup() && unsigned_flag_ == ct2.GetUnsigned() && std::strcmp(collation.collation->csname, ct2.collation.collation->csname) == 0 && (type != common::ColumnType::NUM || (type == common::ColumnType::NUM && precision == ct2.precision && scale == ct2.scale))) @@ -70,4 +71,4 @@ ColumnType ColumnType::RemovedLookup() const { return noLookup; } } // namespace core -} // namespace Tianmu \ No newline at end of file +} // namespace Tianmu diff --git a/storage/tianmu/core/column_type.h b/storage/tianmu/core/column_type.h index f3bc87d78..a2683c18e 100644 --- a/storage/tianmu/core/column_type.h +++ b/storage/tianmu/core/column_type.h @@ -142,12 +142,12 @@ struct ColumnType { bool GetAutoInc() const { return flag[static_cast(enumCT::AUTO_INC)]; } void SetAutoInc(bool inc) { flag[static_cast(enumCT::AUTO_INC)] = inc; } bool HasFilter() const { return flag[static_cast(enumCT::BLOOM_FILTER)]; } - bool GetUnsigned() const { return is_unsigned; } - void SetUnsigned(bool unsigned_) { is_unsigned = unsigned_; } + bool GetUnsigned() const { return unsigned_flag_; } + void SetUnsigned(bool unsigned_flag) { unsigned_flag_ = unsigned_flag; } private: common::ColumnType type; - bool is_unsigned = false; + bool unsigned_flag_ = false; uint precision = 0; int scale = 0; uint internal_size; diff --git a/storage/tianmu/core/data_type.cpp b/storage/tianmu/core/data_type.cpp index 82dad3162..f7de0138c 100644 --- a/storage/tianmu/core/data_type.cpp +++ b/storage/tianmu/core/data_type.cpp @@ -25,33 +25,39 @@ namespace Tianmu { namespace core { #define MAX(a, b) ((a) > (b) ? (a) : (b)) -DataType::DataType(common::ColumnType atype, int prec, int scale, DTCollation collation) : precision(prec) { +// TODO: why not pass struct ColumnType& in column_type.h? +DataType::DataType(common::ColumnType atype, int prec, int scale, DTCollation collation, bool unsigned_flag) + : precision(prec) { valtype = ValueType::VT_NOTKNOWN; attrtype = atype; fixscale = scale; fixmax = -1; this->collation = collation; + unsigned_flag_ = unsigned_flag; + // TODO(gry): change all enum TIANMU_INT_MIN into mysql form. switch (attrtype) { case common::ColumnType::INT: valtype = ValueType::VT_FIXED; - fixmax = MAX(std::numeric_limits::max(), -TIANMU_INT_MIN); + // MySQL does not have UINT_MAX32, used from ndb + fixmax = unsigned_flag ? UINT_MAX32 : MAX(std::numeric_limits::max(), -TIANMU_INT_MIN); break; case common::ColumnType::BIGINT: valtype = ValueType::VT_FIXED; - fixmax = MAX(common::TIANMU_BIGINT_MAX, -common::TIANMU_BIGINT_MIN); + fixmax = unsigned_flag ? common::TIANMU_BIGINT_UNSIGNED_MAX + : MAX(common::TIANMU_BIGINT_MAX, -common::TIANMU_BIGINT_MIN); break; case common::ColumnType::MEDIUMINT: valtype = ValueType::VT_FIXED; - fixmax = MAX(TIANMU_MEDIUMINT_MAX, -TIANMU_MEDIUMINT_MIN); + fixmax = unsigned_flag ? UINT_MAX24 : MAX(TIANMU_MEDIUMINT_MAX, -TIANMU_MEDIUMINT_MIN); break; case common::ColumnType::SMALLINT: valtype = ValueType::VT_FIXED; - fixmax = MAX(TIANMU_SMALLINT_MAX, -TIANMU_SMALLINT_MIN); + fixmax = unsigned_flag ? UINT_MAX16 : MAX(TIANMU_SMALLINT_MAX, -TIANMU_SMALLINT_MIN); break; case common::ColumnType::BYTEINT: valtype = ValueType::VT_FIXED; - fixmax = MAX(TIANMU_TINYINT_MAX, -TIANMU_TINYINT_MIN); + fixmax = unsigned_flag ? UINT_MAX8 : MAX(TIANMU_TINYINT_MAX, -TIANMU_TINYINT_MIN); break; case common::ColumnType::BIT: valtype = ValueType::VT_FIXED; @@ -106,7 +112,7 @@ DataType &DataType::operator=(const ColumnType &ct) { if (!ct.IsKnown()) return *this; - *this = DataType(ct.GetTypeName(), ct.GetPrecision(), ct.GetScale(), ct.GetCollation()); + *this = DataType(ct.GetTypeName(), ct.GetPrecision(), ct.GetScale(), ct.GetCollation(), ct.GetUnsigned()); if (valtype == ValueType::VT_NOTKNOWN) { char s[128]; diff --git a/storage/tianmu/core/data_type.h b/storage/tianmu/core/data_type.h index b9d4deb30..11e055d4d 100644 --- a/storage/tianmu/core/data_type.h +++ b/storage/tianmu/core/data_type.h @@ -40,11 +40,12 @@ struct DataType final { // otherwise common::CT::UNK) int fixscale; // base-10 scale of ValueType::VT_FIXED (no. of decimal digits after // comma) - int64_t fixmax; // maximum _absolute_ value possible (upper bound) of ValueType::VT_FIXED; + uint64_t fixmax; // maximum _absolute_ value possible (upper bound) of ValueType::VT_FIXED; // fixmax = -1 when upper bound is unknown or doesn't fit in int64_t; // precision of a decimal = QuickMath::precision10(fixmax) DTCollation collation; // character set of ValueType::VT_STRING + coercibility int precision; + bool unsigned_flag_ = false; DataType() { valtype = ValueType::VT_NOTKNOWN; @@ -53,8 +54,10 @@ struct DataType final { fixmax = -1; collation = DTCollation(); precision = -1; + unsigned_flag_ = false; } - DataType(common::ColumnType atype, int prec = 0, int scale = 0, DTCollation collation = DTCollation()); + DataType(common::ColumnType atype, int prec = 0, int scale = 0, DTCollation collation = DTCollation(), + bool unsigned_flag_ = false); DataType &operator=(const ColumnType &ct); bool IsKnown() const { return valtype != ValueType::VT_NOTKNOWN; } diff --git a/storage/tianmu/core/engine.h b/storage/tianmu/core/engine.h index 84b37c0aa..c9baa2adc 100644 --- a/storage/tianmu/core/engine.h +++ b/storage/tianmu/core/engine.h @@ -153,7 +153,10 @@ class Engine final { static bool IsTianmuTable(TABLE *table); static bool ConvertToField(Field *field, types::TianmuDataType &tianmu_item, std::vector *blob_buf); static int Convert(int &is_null, my_decimal *value, types::TianmuDataType &tianmu_item, int output_scale = -1); - static int Convert(int &is_null, int64_t &value, types::TianmuDataType &tianmu_item, enum_field_types f_type); + // Add args unsigned_flag here is much more easier to construct TianmuNum in Convert function, another way is + // add unsigned_flag in TianmuNum, it's more complex. + static int Convert(int &is_null, int64_t &value, types::TianmuDataType &tianmu_item, enum_field_types f_type, + bool unsigned_flag); static int Convert(int &is_null, double &value, types::TianmuDataType &tianmu_item); static int Convert(int &is_null, String *value, types::TianmuDataType &tianmu_item, enum_field_types f_type); static void ComputeTimeZoneDiffInMinutes(THD *thd, short &sign, short &minutes); diff --git a/storage/tianmu/core/engine_convert.cpp b/storage/tianmu/core/engine_convert.cpp index 341678843..b2cdd6581 100644 --- a/storage/tianmu/core/engine_convert.cpp +++ b/storage/tianmu/core/engine_convert.cpp @@ -361,7 +361,8 @@ int Engine::Convert(int &is_null, my_decimal *value, types::TianmuDataType &tian return 1; } -int Engine::Convert(int &is_null, int64_t &value, types::TianmuDataType &tianmu_item, enum_field_types f_type) { +int Engine::Convert(int &is_null, int64_t &value, types::TianmuDataType &tianmu_item, enum_field_types f_type, + bool unsigned_flag) { if (tianmu_item.IsNull()) is_null = 1; else { @@ -400,13 +401,16 @@ int Engine::Convert(int &is_null, int64_t &value, types::TianmuDataType &tianmu_ } return 1; } else if (tianmu_item.Type() == common::ColumnType::INT || tianmu_item.Type() == common::ColumnType::MEDIUMINT) { - value = (int)(int64_t) dynamic_cast(tianmu_item); + value = (unsigned_flag ? (uint)(int64_t) dynamic_cast(tianmu_item) + : (int)(int64_t) dynamic_cast(tianmu_item)); return 1; } else if (tianmu_item.Type() == common::ColumnType::BYTEINT) { - value = (char)(int64_t) dynamic_cast(tianmu_item); + value = (unsigned_flag ? (uchar)(int64_t) dynamic_cast(tianmu_item) + : (char)(int64_t) dynamic_cast(tianmu_item)); return 1; } else if (tianmu_item.Type() == common::ColumnType::SMALLINT) { - value = (short)(int64_t) dynamic_cast(tianmu_item); + value = (unsigned_flag ? (ushort)(int64_t) dynamic_cast(tianmu_item) + : (short)(int64_t) dynamic_cast(tianmu_item)); return 1; } else if (tianmu_item.Type() == common::ColumnType::YEAR) { value = dynamic_cast(tianmu_item).Year(); diff --git a/storage/tianmu/core/engine_results.cpp b/storage/tianmu/core/engine_results.cpp index 6432dbb9b..9fee88879 100644 --- a/storage/tianmu/core/engine_results.cpp +++ b/storage/tianmu/core/engine_results.cpp @@ -324,7 +324,7 @@ void ResultSender::SendRecord(const std::vectornull_value = is_null; } else if (isum_hybrid_rcbase->result_type() == INT_RESULT) { Engine::Convert(is_null, isum_hybrid_rcbase->int64_value(), tianmu_dt, - isum_hybrid_rcbase->hybrid_field_type_); + isum_hybrid_rcbase->hybrid_field_type_, is->unsigned_flag); isum_hybrid_rcbase->null_value = is_null; } else if (isum_hybrid_rcbase->result_type() == REAL_RESULT) { Engine::Convert(is_null, isum_hybrid_rcbase->real_value(), tianmu_dt); @@ -339,7 +339,7 @@ void ResultSender::SendRecord(const std::vectorfield_type()); + Engine::Convert(is_null, value, tianmu_dt, is->field_type(), is->unsigned_flag); if (is_null) value = 0; isum_int_rcbase->int64_value(value); diff --git a/storage/tianmu/core/temp_table.cpp b/storage/tianmu/core/temp_table.cpp index 00703f1ca..9bcc9b0ea 100644 --- a/storage/tianmu/core/temp_table.cpp +++ b/storage/tianmu/core/temp_table.cpp @@ -55,6 +55,7 @@ class AttrBuffer : public CachedBuffer { void Set(int64_t idx, T value) { CachedBuffer::Set(idx, value); } }; +// here we stored data both signed/unsigned, the exact values will be converted on send results phase. template class AttrBuffer; template class AttrBuffer; template class AttrBuffer; @@ -273,6 +274,7 @@ void TempTable::Attr::DeleteBuffer() { no_obj = 0; } +// here we stored data both signed/unsigned, the exact values will be converted on send results phase. void TempTable::Attr::SetValueInt64(int64_t obj, int64_t val) { no_materialized = obj + 1; no_obj = obj >= no_obj ? obj + 1 : no_obj; @@ -2146,6 +2148,7 @@ void TempTable::Materialize(bool in_subq, ResultSender *sender, bool lazy) { materialized = true; } +// here we stored data both signed/unsigned, the exact values will be converted on send results phase. void TempTable::RecordIterator::PrepareValues() { if (_currentRNo < uint64_t(table->NumOfObj())) { uint no_disp_attr = table->NumOfDisplaybleAttrs(); diff --git a/storage/tianmu/handler/ha_tianmu.cpp b/storage/tianmu/handler/ha_tianmu.cpp index abfd811bd..91ac975a2 100644 --- a/storage/tianmu/handler/ha_tianmu.cpp +++ b/storage/tianmu/handler/ha_tianmu.cpp @@ -1838,41 +1838,59 @@ void ha_tianmu::key_convert(const uchar *key, uint key_len, std::vector co std::unique_ptr buf(new char[length]); char *ptr = buf.get(); + // TODO(gry): why truncate when v out of range? Is here need to keep consistent with write data? + auto unsigned_flag = f->flags & UNSIGNED_FLAG; switch (f->type()) { case MYSQL_TYPE_TINY: { int64_t v = f->val_int(); - if (v > TIANMU_TINYINT_MAX) - v = TIANMU_TINYINT_MAX; - else if (v < TIANMU_TINYINT_MIN) - v = TIANMU_TINYINT_MIN; - *(int64_t *)ptr = v; + if (unsigned_flag) { + v = (v > UINT_MAX8) ? UINT_MAX8 : v; + } else { + if (v > TIANMU_TINYINT_MAX) + v = TIANMU_TINYINT_MAX; + else if (v < TIANMU_TINYINT_MIN) + v = TIANMU_TINYINT_MIN; + } + *reinterpret_cast(ptr) = v; ptr += sizeof(int64_t); } break; case MYSQL_TYPE_SHORT: { int64_t v = f->val_int(); - if (v > TIANMU_SMALLINT_MAX) - v = TIANMU_SMALLINT_MAX; - else if (v < TIANMU_SMALLINT_MIN) - v = TIANMU_SMALLINT_MIN; - *(int64_t *)ptr = v; + if (unsigned_flag) { + v = (v > UINT_MAX16) ? UINT_MAX16 : v; + } else { + if (v > TIANMU_SMALLINT_MAX) + v = TIANMU_SMALLINT_MAX; + else if (v < TIANMU_SMALLINT_MIN) + v = TIANMU_SMALLINT_MIN; + } + *reinterpret_cast(ptr) = v; ptr += sizeof(int64_t); } break; case MYSQL_TYPE_LONG: { int64_t v = f->val_int(); - if (v > std::numeric_limits::max()) - v = std::numeric_limits::max(); - else if (v < TIANMU_INT_MIN) - v = TIANMU_INT_MIN; - *(int64_t *)ptr = v; + if (unsigned_flag) { + v = (v > UINT_MAX32) ? UINT_MAX32 : v; + } else { + if (v > std::numeric_limits::max()) + v = std::numeric_limits::max(); + else if (v < TIANMU_INT_MIN) + v = TIANMU_INT_MIN; + } + *reinterpret_cast(ptr) = v; ptr += sizeof(int64_t); } break; case MYSQL_TYPE_INT24: { int64_t v = f->val_int(); - if (v > TIANMU_MEDIUMINT_MAX) - v = TIANMU_MEDIUMINT_MAX; - else if (v < TIANMU_MEDIUMINT_MIN) - v = TIANMU_MEDIUMINT_MIN; - *(int64_t *)ptr = v; + if (unsigned_flag) { + v = (v > UINT_MAX24) ? UINT_MAX24 : v; + } else { + if (v > TIANMU_MEDIUMINT_MAX) + v = TIANMU_MEDIUMINT_MAX; + else if (v < TIANMU_MEDIUMINT_MIN) + v = TIANMU_MEDIUMINT_MIN; + } + *reinterpret_cast(ptr) = v; ptr += sizeof(int64_t); } break; case MYSQL_TYPE_LONGLONG: { @@ -1881,7 +1899,7 @@ void ha_tianmu::key_convert(const uchar *key, uint key_len, std::vector co v = common::TIANMU_BIGINT_MAX; else if (v < common::TIANMU_BIGINT_MIN) v = common::TIANMU_BIGINT_MIN; - *(int64_t *)ptr = v; + *reinterpret_cast(ptr) = v; ptr += sizeof(int64_t); } break; case MYSQL_TYPE_BIT: {