diff options
author | Marko Mäkelä <marko.makela@mariadb.com> | 2021-12-14 11:45:34 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@mariadb.com> | 2021-12-14 11:45:34 +0200 |
commit | bc9f505f80633e537d5077534f4d8809c65c8162 (patch) | |
tree | 64b10a617bef8a4245cf81445339bb7d2d2e4e22 | |
parent | ea9489536911b083c5e28b15c071cf6931247b7e (diff) | |
download | mariadb-git-preview-10.8-MDEV-27208.tar.gz |
MDEV-27208: Extend CRC32() and implement CRC32C()preview-10.8-MDEV-27208
We used to define a native unary function crc32() that computes the CRC-32
of a string using the ISO 3309 polynomial that is being used by zlib
and many others.
Often, CRC is computed in pieces. To faciliate this, we introduce an
optional second parameter: CRC32('MariaDB')=CRC32('DB',CRC32('Maria')).
InnoDB and MyRocks use a different polynomial, which was implemented
in SSE4.2 instructions that were introduced in the
Intel Nehalem microarchitecture. This is commonly called CRC-32C
(Castagnoli).
We introduce a native function that uses the Castagnoli polynomial:
CRC32C('MariaDB')=CRC32C('DB',CRC32C('Maria')). This allows
SELECT...INTO DUMPFILE to be used for the creation of files with
valid checksums, such as a logically empty InnoDB redo log file
ib_logfile0 corresponding to a particular log sequence number.
-rw-r--r-- | mysql-test/main/func_math.result | 41 | ||||
-rw-r--r-- | mysql-test/main/func_math.test | 11 | ||||
-rw-r--r-- | sql/item_create.cc | 72 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 37 | ||||
-rw-r--r-- | sql/item_strfunc.h | 33 |
5 files changed, 172 insertions, 22 deletions
diff --git a/mysql-test/main/func_math.result b/mysql-test/main/func_math.result index ec2521bcfd7..43eb6377b83 100644 --- a/mysql-test/main/func_math.result +++ b/mysql-test/main/func_math.result @@ -1840,24 +1840,39 @@ CRC32(99999999999999999999999999999999) SELECT CRC32(-99999999999999999999999999999999); CRC32(-99999999999999999999999999999999) 1052326872 +SELECT CRC32C(NULL), CRC32C(''), CRC32C('MariaDB'), CRC32C('mariadb'); +CRC32C(NULL) CRC32C('') CRC32C('MariaDB') CRC32C('mariadb') +NULL 0 809606978 1378644259 +SELECT CRC32(NULL,1),CRC32C(NULL,1), CRC32('',1), CRC32C('',1); +CRC32(NULL,1) CRC32C(NULL,1) CRC32('',1) CRC32C('',1) +NULL NULL 1 1 +SELECT CRC32('MariaDB',NULL),CRC32C('MariaDB',NULL); +CRC32('MariaDB',NULL) CRC32C('MariaDB',NULL) +NULL NULL +SELECT CRC32('',CRC32('MySQL')),CRC32('SQL',CRC32('My')); +CRC32('',CRC32('MySQL')) CRC32('SQL',CRC32('My')) +3259397556 3259397556 +SELECT CRC32C('',CRC32C('MariaDB')),CRC32C('DB',CRC32C('Maria')); +CRC32C('',CRC32C('MariaDB')) CRC32C('DB',CRC32C('Maria')) +809606978 809606978 DROP TABLE IF EXISTS t; Warnings: Note 1051 Unknown table 'test.t' CREATE TABLE t(a INT, b VARCHAR(2)); INSERT INTO t VALUES (1,'a'), (2,'qw'), (1,'t'), (3,'t'); -SELECT crc32(SUM(a)) FROM t; -crc32(SUM(a)) -1790921346 -SELECT crc32(AVG(a)) FROM t GROUP BY b; -crc32(AVG(a)) -768278432 -2875100430 -2875100430 -SELECT crc32(MAX(b)) FROM t GROUP BY a; -crc32(MAX(b)) -2238339752 -3114057431 -2238339752 +SELECT crc32(SUM(a)),crc32c(SUM(a)) FROM t; +crc32(SUM(a)) crc32c(SUM(a)) +1790921346 3058990603 +SELECT crc32(AVG(a)),crc32c(AVG(a)) FROM t GROUP BY b; +crc32(AVG(a)) crc32c(AVG(a)) +768278432 1816172052 +2875100430 1492934094 +2875100430 1492934094 +SELECT crc32(MAX(b)),crc32c(MAX(b)) FROM t GROUP BY a; +crc32(MAX(b)) crc32c(MAX(b)) +2238339752 3833565251 +3114057431 4173859780 +2238339752 3833565251 SELECT a, b, crc32(a) FROM t GROUP BY a,b HAVING crc32(MAX(a))=450215437; a b crc32(a) 2 qw 450215437 diff --git a/mysql-test/main/func_math.test b/mysql-test/main/func_math.test index 572e0fd0f6b..92d2e015404 100644 --- a/mysql-test/main/func_math.test +++ b/mysql-test/main/func_math.test @@ -849,15 +849,20 @@ SELECT CRC32('01234567'), CRC32('012345678'); SELECT CRC32('~!@$%^*'), CRC32('-0.0001'); SELECT CRC32(99999999999999999999999999999999); SELECT CRC32(-99999999999999999999999999999999); +SELECT CRC32C(NULL), CRC32C(''), CRC32C('MariaDB'), CRC32C('mariadb'); +SELECT CRC32(NULL,1),CRC32C(NULL,1), CRC32('',1), CRC32C('',1); +SELECT CRC32('MariaDB',NULL),CRC32C('MariaDB',NULL); +SELECT CRC32('',CRC32('MySQL')),CRC32('SQL',CRC32('My')); +SELECT CRC32C('',CRC32C('MariaDB')),CRC32C('DB',CRC32C('Maria')); # Test cases for using the function in aggregate functions, group-by, having # and order-by clauses DROP TABLE IF EXISTS t; CREATE TABLE t(a INT, b VARCHAR(2)); INSERT INTO t VALUES (1,'a'), (2,'qw'), (1,'t'), (3,'t'); -SELECT crc32(SUM(a)) FROM t; -SELECT crc32(AVG(a)) FROM t GROUP BY b; -SELECT crc32(MAX(b)) FROM t GROUP BY a; +SELECT crc32(SUM(a)),crc32c(SUM(a)) FROM t; +SELECT crc32(AVG(a)),crc32c(AVG(a)) FROM t GROUP BY b; +SELECT crc32(MAX(b)),crc32c(MAX(b)) FROM t GROUP BY a; SELECT a, b, crc32(a) FROM t GROUP BY a,b HAVING crc32(MAX(a))=450215437; SELECT a,b,concat(a,b),crc32(concat(a,b)) FROM t ORDER BY crc32(concat(a,b)); DROP TABLE t; diff --git a/sql/item_create.cc b/sql/item_create.cc index 1aa7d02e76b..2d17c0ffc1f 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -512,10 +512,10 @@ protected: }; -class Create_func_crc32 : public Create_func_arg1 +class Create_func_crc32 : public Create_native_func { public: - virtual Item *create_1_arg(THD *thd, Item *arg1); + Item *create_native(THD *thd, LEX_CSTRING *, List<Item> *item_list) override; static Create_func_crc32 s_singleton; @@ -525,6 +525,19 @@ protected: }; +class Create_func_crc32c : public Create_native_func +{ +public: + Item *create_native(THD *thd, LEX_CSTRING *, List<Item> *item_list) override; + + static Create_func_crc32c s_singleton; + +protected: + Create_func_crc32c() {} + virtual ~Create_func_crc32c() {} +}; + + class Create_func_datediff : public Create_func_arg2 { public: @@ -3118,11 +3131,61 @@ Create_func_cot::create_1_arg(THD *thd, Item *arg1) Create_func_crc32 Create_func_crc32::s_singleton; Item* -Create_func_crc32::create_1_arg(THD *thd, Item *arg1) +Create_func_crc32::create_native(THD *thd, LEX_CSTRING *name, + List<Item> *item_list) +{ + int argc= item_list ? item_list->elements : 0; + + if (unlikely(argc != 1 && argc != 2)) + { + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str); + return nullptr; + } + + Item *arg1= item_list->pop(), *arg2= argc < 2 ? nullptr : item_list->pop(); + + if (unlikely(arg1->is_explicit_name() || + (arg2 && arg2->is_explicit_name()))) + { + my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name->str); + return nullptr; + } + + return arg2 + ? new (thd->mem_root) Item_func_crc32(thd, arg1, arg2) + : new (thd->mem_root) Item_func_crc32(thd, arg1); +} + + +Create_func_crc32c Create_func_crc32c::s_singleton; + +Item* +Create_func_crc32c::create_native(THD *thd, LEX_CSTRING *name, + List<Item> *item_list) { - return new (thd->mem_root) Item_func_crc32(thd, arg1); + int argc= item_list ? item_list->elements : 0; + + if (unlikely(argc != 1 && argc != 2)) + { + my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str); + return nullptr; + } + + Item *arg1= item_list->pop(), *arg2= argc < 2 ? nullptr : item_list->pop(); + + if (unlikely(arg1->is_explicit_name() || + (arg2 && arg2->is_explicit_name()))) + { + my_error(ER_WRONG_PARAMETERS_TO_NATIVE_FCT, MYF(0), name->str); + return nullptr; + } + + return arg2 + ? new (thd->mem_root) Item_func_crc32c(thd, arg1, arg2) + : new (thd->mem_root) Item_func_crc32c(thd, arg1); } + Create_func_datediff Create_func_datediff::s_singleton; Item* @@ -5555,6 +5618,7 @@ Native_func_registry func_array[] = { { STRING_WITH_LEN("COS") }, BUILDER(Create_func_cos)}, { { STRING_WITH_LEN("COT") }, BUILDER(Create_func_cot)}, { { STRING_WITH_LEN("CRC32") }, BUILDER(Create_func_crc32)}, + { { STRING_WITH_LEN("CRC32C") }, BUILDER(Create_func_crc32c)}, { { STRING_WITH_LEN("DATEDIFF") }, BUILDER(Create_func_datediff)}, { { STRING_WITH_LEN("DAYNAME") }, BUILDER(Create_func_dayname)}, { { STRING_WITH_LEN("DAYOFMONTH") }, BUILDER(Create_func_dayofmonth)}, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index d4bf28a9c21..76f4dbbc4ce 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -4377,6 +4377,7 @@ longlong Item_func_uncompressed_length::val_int() longlong Item_func_crc32::val_int() { DBUG_ASSERT(fixed()); + DBUG_ASSERT(arg_count == 1 || arg_count == 2); String *res=args[0]->val_str(&value); if (!res) { @@ -4384,7 +4385,41 @@ longlong Item_func_crc32::val_int() return 0; /* purecov: inspected */ } null_value=0; - return (longlong) my_checksum(0L, (uchar*)res->ptr(), res->length()); + longlong crc= 0; + if (arg_count > 1) + { + crc= args[1]->val_int(); + null_value= args[1]->null_value; + if (null_value) + return 0; + } + + return static_cast<longlong> + (my_checksum(static_cast<uint32_t>(crc), + reinterpret_cast<const uchar*>(res->ptr()), res->length())); +} + +longlong Item_func_crc32c::val_int() +{ + DBUG_ASSERT(fixed()); + DBUG_ASSERT(arg_count == 1 || arg_count == 2); + String *res=args[0]->val_str(&value); + if (!res) + { + null_value=1; + return 0; /* purecov: inspected */ + } + null_value=0; + longlong crc= 0; + if (arg_count > 1) + { + crc= args[1]->val_int(); + null_value= args[1]->null_value; + if (null_value) + return 0; + } + return static_cast<longlong> + (my_crc32c(static_cast<uint32_t>(crc), res->ptr(), res->length())); } #ifdef HAVE_COMPRESS diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index ba61206d8d9..7c415034b37 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -1945,11 +1945,17 @@ public: class Item_func_crc32 :public Item_long_func { bool check_arguments() const override - { return args[0]->check_type_can_return_str(func_name_cstring()); } + { + return args[0]->check_type_can_return_str(func_name_cstring()) && + (arg_count == 1 || + args[1]->check_type_can_return_int(func_name_cstring())); + } String value; public: Item_func_crc32(THD *thd, Item *a): Item_long_func(thd, a) { unsigned_flag= 1; } + Item_func_crc32(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) + { unsigned_flag= 1; } LEX_CSTRING func_name_cstring() const override { static LEX_CSTRING name= {STRING_WITH_LEN("crc32") }; @@ -1961,6 +1967,31 @@ public: { return get_item_copy<Item_func_crc32>(thd, this); } }; +class Item_func_crc32c :public Item_long_func +{ + bool check_arguments() const override + { + return args[0]->check_type_can_return_str(func_name_cstring()) && + (arg_count == 1 || + args[1]->check_type_can_return_int(func_name_cstring())); + } + String value; +public: + Item_func_crc32c(THD *thd, Item *a): Item_long_func(thd, a) + { unsigned_flag= 1; } + Item_func_crc32c(THD *thd, Item *a, Item *b): Item_long_func(thd, a, b) + { unsigned_flag= 1; } + LEX_CSTRING func_name_cstring() const override + { + static LEX_CSTRING name= {STRING_WITH_LEN("crc32c") }; + return name; + } + bool fix_length_and_dec() override { max_length=10; return FALSE; } + longlong val_int() override; + Item *get_copy(THD *thd) override + { return get_item_copy<Item_func_crc32c>(thd, this); } +}; + class Item_func_uncompressed_length : public Item_long_func_length { String value; |