diff options
author | Vanislavsky <serzh7214@mail.ru> | 2022-02-13 23:19:02 +1000 |
---|---|---|
committer | Sergei Golubchik <serg@mariadb.org> | 2022-06-20 09:28:00 +0200 |
commit | 700a703d50d169a70b131618f0ca2b12179576f9 (patch) | |
tree | 0babb0c994df033d4ca0ca4bf0c59619ba13b408 | |
parent | 49182ad2a89ddccccc2737219d3ad54c7a4d733b (diff) | |
download | mariadb-git-700a703d50d169a70b131618f0ca2b12179576f9.tar.gz |
MDEV-25704 Add RANDOM_BYTES function
MySQL 5.6 added the RANDOM_BYTES function.
https://dev.mysql.com/doc/refman/5.6/en/encryption-functions.html#function_random-bytes
This is needed for compatibility purposes.
-rw-r--r-- | mysql-test/main/func_str.result | 56 | ||||
-rw-r--r-- | mysql-test/main/func_str.test | 57 | ||||
-rw-r--r-- | mysql-test/suite/binlog/r/binlog_unsafe.result | 3 | ||||
-rw-r--r-- | mysql-test/suite/binlog/t/binlog_unsafe.test | 3 | ||||
-rw-r--r-- | sql/item_create.cc | 23 | ||||
-rw-r--r-- | sql/item_strfunc.cc | 66 | ||||
-rw-r--r-- | sql/item_strfunc.h | 20 |
7 files changed, 227 insertions, 1 deletions
diff --git a/mysql-test/main/func_str.result b/mysql-test/main/func_str.result index 799fd1933dd..f983110627d 100644 --- a/mysql-test/main/func_str.result +++ b/mysql-test/main/func_str.result @@ -5265,3 +5265,59 @@ f # # End of 10.4 tests # +# +# MDEV-25704 Function random_bytes +# +create table t1 as select random_bytes(100); +show create table t1; +Table Create Table +t1 CREATE TABLE `t1` ( + `random_bytes(100)` varbinary(100) DEFAULT NULL +) ENGINE=MyISAM DEFAULT CHARSET=latin1 +drop table t1; +# The sequence starts at 17 so that the probability of test failure is small enough (about 2^(-136)) +select count(*) from seq_17_to_1024 where random_bytes(seq) <=> random_bytes(seq); +count(*) +0 +select (count(*) = 1024) from seq_1_to_1024 where length(random_bytes(seq)) = seq; +(count(*) = 1024) +1 +# +# Test NULL output for NULL input +# +SELECT random_bytes(NULL); +random_bytes(NULL) +NULL +# +# Test For values outside range from 1 to 1024, an error occurs +# +SELECT random_bytes(0); +ERROR 22003: length value is out of range in 'random_bytes(0)' +SELECT random_bytes(-1); +ERROR 22003: length value is out of range in 'random_bytes(-1)' +SELECT random_bytes(-100); +ERROR 22003: length value is out of range in 'random_bytes(-100)' +SELECT random_bytes(-26); +ERROR 22003: length value is out of range in 'random_bytes(-26)' +SELECT random_bytes(-132); +ERROR 22003: length value is out of range in 'random_bytes(-132)' +SELECT random_bytes(1025); +ERROR 22003: length value is out of range in 'random_bytes(1025)' +SELECT random_bytes(11111); +ERROR 22003: length value is out of range in 'random_bytes(11111)' +SELECT random_bytes(2056); +ERROR 22003: length value is out of range in 'random_bytes(2056)' +# +# Test For invalid argument, an error occurs +# +SELECT random_bytes('s'); +ERROR 22003: length value is out of range in 'random_bytes('s')' +SELECT random_bytes('r'); +ERROR 22003: length value is out of range in 'random_bytes('r')' +SELECT random_bytes('res'); +ERROR 22003: length value is out of range in 'random_bytes('res')' +SELECT random_bytes('test'); +ERROR 22003: length value is out of range in 'random_bytes('test')' +# +# End of 10.10 tests +# diff --git a/mysql-test/main/func_str.test b/mysql-test/main/func_str.test index bbdcead280f..af2e64a02ad 100644 --- a/mysql-test/main/func_str.test +++ b/mysql-test/main/func_str.test @@ -1,6 +1,7 @@ # Description # ----------- # Testing string functions +--source include/have_sequence.inc --disable_warnings drop table if exists t1,t2; @@ -2193,3 +2194,59 @@ SELECT GROUP_CONCAT( UpdateXML( '<a>new year</a>', '/a', '2019-01-01 00:00:00' ) --echo # --echo # End of 10.4 tests --echo # + +--echo # +--echo # MDEV-25704 Function random_bytes +--echo # + +create table t1 as select random_bytes(100); +show create table t1; +drop table t1; + +--echo # The sequence starts at 17 so that the probability of test failure is small enough (about 2^(-136)) +select count(*) from seq_17_to_1024 where random_bytes(seq) <=> random_bytes(seq); + +select (count(*) = 1024) from seq_1_to_1024 where length(random_bytes(seq)) = seq; + +--echo # +--echo # Test NULL output for NULL input +--echo # + +SELECT random_bytes(NULL); + +--echo # +--echo # Test For values outside range from 1 to 1024, an error occurs +--echo # + +--error 1690 +SELECT random_bytes(0); +--error 1690 +SELECT random_bytes(-1); +--error 1690 +SELECT random_bytes(-100); +--error 1690 +SELECT random_bytes(-26); +--error 1690 +SELECT random_bytes(-132); +--error 1690 +SELECT random_bytes(1025); +--error 1690 +SELECT random_bytes(11111); +--error 1690 +SELECT random_bytes(2056); + +--echo # +--echo # Test For invalid argument, an error occurs +--echo # +--error 1690 +SELECT random_bytes('s'); +--error 1690 +SELECT random_bytes('r'); +--error 1690 +SELECT random_bytes('res'); +--error 1690 +SELECT random_bytes('test'); + +--echo # +--echo # End of 10.10 tests +--echo # diff --git a/mysql-test/suite/binlog/r/binlog_unsafe.result b/mysql-test/suite/binlog/r/binlog_unsafe.result index a8143ef086e..0c0b0e77915 100644 --- a/mysql-test/suite/binlog/r/binlog_unsafe.result +++ b/mysql-test/suite/binlog/r/binlog_unsafe.result @@ -2609,6 +2609,9 @@ INSERT INTO t1 VALUES (VERSION()); Warnings: Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave INSERT INTO t1 VALUES (RAND()); +INSERT INTO t1 VALUES (RANDOM_BYTES(1000)); +Warnings: +Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it uses a system function that may return a different value on the slave DELETE FROM t1; SET TIME_ZONE= '+03:00'; SET TIMESTAMP=1000000; diff --git a/mysql-test/suite/binlog/t/binlog_unsafe.test b/mysql-test/suite/binlog/t/binlog_unsafe.test index 673712ff209..8b2a00e174c 100644 --- a/mysql-test/suite/binlog/t/binlog_unsafe.test +++ b/mysql-test/suite/binlog/t/binlog_unsafe.test @@ -651,7 +651,7 @@ DROP TABLE t1,t2,t3; # # BUG#47995: Mark user functions as unsafe -# BUG#49222: Mare RAND() unsafe +# BUG#49222: Mark RAND() unsafe # # Test that the system functions that are supposed to be marked unsafe # generate a warning. Each INSERT statement below should generate a @@ -678,6 +678,7 @@ INSERT INTO t1 VALUES (UUID()); #marked unsafe before BUG#47995 INSERT INTO t1 VALUES (UUID_SHORT()); #marked unsafe before BUG#47995 INSERT INTO t1 VALUES (VERSION()); #marked unsafe in BUG#47995 INSERT INTO t1 VALUES (RAND()); #marked unsafe in BUG#49222 +INSERT INTO t1 VALUES (RANDOM_BYTES(1000)); #marked unsafe in MDEV-25704 DELETE FROM t1; # Since we replicate the TIMESTAMP variable, functions affected by the diff --git a/sql/item_create.cc b/sql/item_create.cc index c34119e1d9e..bceff7fb43c 100644 --- a/sql/item_create.cc +++ b/sql/item_create.cc @@ -1873,6 +1873,19 @@ protected: }; +class Create_func_random_bytes : public Create_func_arg1 +{ +public: + virtual Item *create_1_arg(THD *thd, Item *arg1); + + static Create_func_random_bytes s_singleton; + +protected: + Create_func_random_bytes() {} + virtual ~Create_func_random_bytes() {} +}; + + class Create_func_release_all_locks : public Create_func_arg0 { public: @@ -4985,6 +4998,15 @@ Create_func_rand::create_native(THD *thd, const LEX_CSTRING *name, } +Create_func_random_bytes Create_func_random_bytes::s_singleton; + +Item *Create_func_random_bytes::create_1_arg(THD *thd, Item *arg1) +{ + thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_FUNCTION); + return new (thd->mem_root) Item_func_random_bytes(thd, arg1); +} + + Create_func_release_all_locks Create_func_release_all_locks::s_singleton; Item* @@ -5804,6 +5826,7 @@ Native_func_registry func_array[] = { { STRING_WITH_LEN("POW") }, BUILDER(Create_func_pow)}, { { STRING_WITH_LEN("POWER") }, BUILDER(Create_func_pow)}, { { STRING_WITH_LEN("QUOTE") }, BUILDER(Create_func_quote)}, + { { STRING_WITH_LEN("RANDOM_BYTES")}, BUILDER(Create_func_random_bytes)}, { { STRING_WITH_LEN("REGEXP_INSTR") }, BUILDER(Create_func_regexp_instr)}, { { STRING_WITH_LEN("REGEXP_REPLACE") }, BUILDER(Create_func_regexp_replace)}, { { STRING_WITH_LEN("REGEXP_SUBSTR") }, BUILDER(Create_func_regexp_substr)}, diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc index 0291ddcd5b3..f7fee8917bd 100644 --- a/sql/item_strfunc.cc +++ b/sql/item_strfunc.cc @@ -1449,6 +1449,72 @@ String *Item_func_sformat::val_str(String *res) return null_value ? NULL : res; } +#include"my_global.h" +#include <openssl/rand.h> +#include <openssl/err.h> + +bool Item_func_random_bytes::fix_length_and_dec(THD *thd) +{ + used_tables_cache|= RAND_TABLE_BIT; + if (args[0]->can_eval_in_optimize()) + { + max_length= MY_MIN((int32) args[0]->val_int(), MAX_BLOB_WIDTH); + return false; + } + max_length= MAX_BLOB_WIDTH; + return false; +} + + +void Item_func_random_bytes::update_used_tables() +{ + Item_str_func::update_used_tables(); + used_tables_cache|= RAND_TABLE_BIT; +} + + +String *Item_func_random_bytes::val_str(String *str) +{ + longlong count= args[0]->val_int(); + + if (args[0]->null_value) + goto err; + null_value= 0; + + if (count < 1 || count > 1024) + { + char buf[256]; + String msg(buf, sizeof(buf), system_charset_info); + msg.length(0); + print(&msg, QT_NO_DATA_EXPANSION); + my_error(ER_DATA_OUT_OF_RANGE, MYF(0), "length", msg.c_ptr_safe()); + return make_empty_result(str); + } + + if (str->alloc((uint) count)) + goto err; + + str->length(count); + if (!RAND_bytes((unsigned char *) str->ptr(), (int32) count)) + { + ulong ssl_err; + while ((ssl_err= ERR_get_error())) + { + char buf[256]; + ERR_error_string_n(ssl_err, buf, sizeof(buf)); + sql_print_warning("SSL error: %s", buf); + } + return make_empty_result(str); + } + + return str; + +err: + null_value= 1; + return 0; +} + + /*********************************************************************/ bool Item_func_regexp_replace::fix_length_and_dec(THD *thd) { diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h index 68b6f954b0a..4725779108c 100644 --- a/sql/item_strfunc.h +++ b/sql/item_strfunc.h @@ -384,6 +384,26 @@ public: { return get_item_copy<Item_func_concat_ws>(thd, this); } }; + +class Item_func_random_bytes : public Item_str_func +{ +public: + Item_func_random_bytes(THD *thd, Item *arg1) : Item_str_func(thd, arg1) {} + bool fix_length_and_dec(THD *thd) override; + void update_used_tables() override; + String *val_str(String *) override; + LEX_CSTRING func_name_cstring() const override + { + static LEX_CSTRING name= {STRING_WITH_LEN("random_bytes")}; + return name; + } + Item *get_copy(THD *thd) override + { + return get_item_copy<Item_func_random_bytes>(thd, this); + } +}; + + class Item_func_reverse :public Item_str_func { String tmp_value; |