diff --git a/mysql-test/main/func_regexp.result b/mysql-test/main/func_regexp.result index 8e32732e12d..7a9e24f8262 100644 --- a/mysql-test/main/func_regexp.result +++ b/mysql-test/main/func_regexp.result @@ -192,4 +192,20 @@ SELECT SUM(a.t) FROM (SELECT (c1 RLIKE c1) = (c0 IS NULL) as t FROM t0) as a; SUM(a.t) 0 DROP TABLE t0; +# +# MDEV-21058 CREATE TABLE with generated column and RLIKE results in sigabrt +# +CREATE TABLE t1 (c0 INT); +INSERT INTO t1 VALUES (1),(2),(3); +SELECT ('' RLIKE '[') AS c1 FROM t1; +ERROR 42000: Regex error 'missing terminating ] for character class at offset 1' +SELECT REGEXP_INSTR('','[') AS c1 FROM t1; +ERROR 42000: Regex error 'missing terminating ] for character class at offset 1' +SELECT c0, '' RLIKE NULL AS c1, REGEXP_INSTR('', NULL) AS c2 +FROM t1 ORDER BY c0; +c0 c1 c2 +1 NULL NULL +2 NULL NULL +3 NULL NULL +DROP TABLE t1; # End of 10.5 tests diff --git a/mysql-test/main/func_regexp.test b/mysql-test/main/func_regexp.test index 48a273f6979..fb441bde4d2 100644 --- a/mysql-test/main/func_regexp.test +++ b/mysql-test/main/func_regexp.test @@ -132,5 +132,22 @@ SELECT (c1 RLIKE c1), (c0 IS NULL) FROM t0; SELECT SUM(a.t) FROM (SELECT (c1 RLIKE c1) = (c0 IS NULL) as t FROM t0) as a; DROP TABLE t0; +--echo # +--echo # MDEV-21058 CREATE TABLE with generated column and RLIKE results in sigabrt +--echo # + +CREATE TABLE t1 (c0 INT); +INSERT INTO t1 VALUES (1),(2),(3); + +--error ER_REGEXP_ERROR +SELECT ('' RLIKE '[') AS c1 FROM t1; + +--error ER_REGEXP_ERROR +SELECT REGEXP_INSTR('','[') AS c1 FROM t1; + +SELECT c0, '' RLIKE NULL AS c1, REGEXP_INSTR('', NULL) AS c2 +FROM t1 ORDER BY c0; + +DROP TABLE t1; --echo # End of 10.5 tests diff --git a/mysql-test/suite/vcol/r/func_regexp.result b/mysql-test/suite/vcol/r/func_regexp.result new file mode 100644 index 00000000000..f7ae11f79b1 --- /dev/null +++ b/mysql-test/suite/vcol/r/func_regexp.result @@ -0,0 +1,24 @@ +# +# Start of 10.5 tests +# +# +# MDEV-21058 CREATE TABLE with generated column and RLIKE results in sigabrt +# +CREATE TABLE t1 (c0 INT AS(('' RLIKE '['))); +ERROR 42000: Regex error 'missing terminating ] for character class at offset 1' +CREATE TABLE t1 (c0 INT AS(REGEXP_INSTR('','['))); +ERROR 42000: Regex error 'missing terminating ] for character class at offset 1' +CREATE TABLE t1 +( +c0 INT, +c1 INT AS(('' RLIKE NULL)), +c2 INT AS(REGEXP_INSTR('',NULL)) +); +INSERT INTO t1 (c0) VALUES (0); +SELECT * FROM t1; +c0 c1 c2 +0 NULL NULL +DROP TABLE t1; +# +# End of 10.5 tests +# diff --git a/mysql-test/suite/vcol/t/func_regexp.test b/mysql-test/suite/vcol/t/func_regexp.test new file mode 100644 index 00000000000..5e97009ab7b --- /dev/null +++ b/mysql-test/suite/vcol/t/func_regexp.test @@ -0,0 +1,30 @@ +--source inc/vcol_init_vars.pre +--source inc/vcol_cleanup.inc + +--echo # +--echo # Start of 10.5 tests +--echo # + +--echo # +--echo # MDEV-21058 CREATE TABLE with generated column and RLIKE results in sigabrt +--echo # + +--error ER_REGEXP_ERROR +CREATE TABLE t1 (c0 INT AS(('' RLIKE '['))); + +--error ER_REGEXP_ERROR +CREATE TABLE t1 (c0 INT AS(REGEXP_INSTR('','['))); + +CREATE TABLE t1 +( + c0 INT, + c1 INT AS(('' RLIKE NULL)), + c2 INT AS(REGEXP_INSTR('',NULL)) +); +INSERT INTO t1 (c0) VALUES (0); +SELECT * FROM t1; +DROP TABLE t1; + +--echo # +--echo # End of 10.5 tests +--echo # diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index f8959cfd2bf..a755cac49ad 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -6215,7 +6215,17 @@ bool Regexp_processor_pcre::exec(Item *item, int offset, } -void Regexp_processor_pcre::fix_owner(Item_func *owner, +/* + This method determines the owner's maybe_null flag. + Generally, the result is NULL-able. However, in case + of a constant pattern and a NOT NULL subject, the + result can also be NOT NULL. + @return true - in case if the constant regex compilation failed + (e.g. due to a wrong regex syntax in the pattern). + The compilation error message is put to the DA in this case. + false - otherwise. +*/ +bool Regexp_processor_pcre::fix_owner(Item_func *owner, Item *subject_arg, Item *pattern_arg) { @@ -6223,16 +6233,30 @@ void Regexp_processor_pcre::fix_owner(Item_func *owner, pattern_arg->const_item() && !pattern_arg->is_expensive()) { - if (compile(pattern_arg, true)) + if (compile(pattern_arg, true/* raise errors to DA, e.g. on bad syntax */)) { - owner->maybe_null= 1; // Will always return NULL - return; + owner->maybe_null= 1; + if (pattern_arg->null_value) + { + /* + The pattern evaluated to NULL. Regex compilation did not happen. + No errors were put to DA. Continue with maybe_null==true. + The function will return NULL per row. + */ + return false; + } + /* + A syntax error in the pattern, an error was raised to the DA. + Let's abort the query. The caller will send the error to the client. + */ + return true; } set_const(true); owner->maybe_null= subject_arg->maybe_null; } else owner->maybe_null= 1; + return false; } @@ -6244,8 +6268,7 @@ Item_func_regex::fix_length_and_dec() return TRUE; re.init(cmp_collation.collation, 0); - re.fix_owner(this, args[0], args[1]); - return FALSE; + return re.fix_owner(this, args[0], args[1]); } @@ -6269,9 +6292,8 @@ Item_func_regexp_instr::fix_length_and_dec() return TRUE; re.init(cmp_collation.collation, 0); - re.fix_owner(this, args[0], args[1]); max_length= MY_INT32_NUM_DECIMAL_DIGITS; // See also Item_func_locate - return FALSE; + return re.fix_owner(this, args[0], args[1]); } diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h index 465625f69bf..4674f935aed 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -2893,7 +2893,7 @@ public: {} int default_regex_flags(); void init(CHARSET_INFO *data_charset, int extra_flags); - void fix_owner(Item_func *owner, Item *subject_arg, Item *pattern_arg); + bool fix_owner(Item_func *owner, Item *subject_arg, Item *pattern_arg); bool compile(String *pattern, bool send_error); bool compile(Item *item, bool send_error); bool recompile(Item *item)