summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2021-12-14 11:45:34 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2021-12-14 11:45:34 +0200
commitbc9f505f80633e537d5077534f4d8809c65c8162 (patch)
tree64b10a617bef8a4245cf81445339bb7d2d2e4e22
parentea9489536911b083c5e28b15c071cf6931247b7e (diff)
downloadmariadb-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.result41
-rw-r--r--mysql-test/main/func_math.test11
-rw-r--r--sql/item_create.cc72
-rw-r--r--sql/item_strfunc.cc37
-rw-r--r--sql/item_strfunc.h33
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;