mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
MDEV-10867 PREPARE..EXECUTE is not consistent about non-ASCII characters
This commit is contained in:
212
mysql-test/extra/binlog_tests/ctype_ucs_binlog.result
Normal file
212
mysql-test/extra/binlog_tests/ctype_ucs_binlog.result
Normal file
@ -0,0 +1,212 @@
|
|||||||
|
SET TIMESTAMP=10000;
|
||||||
|
create table t2 (c char(30)) charset=ucs2;
|
||||||
|
set @v=convert('abc' using ucs2);
|
||||||
|
reset master;
|
||||||
|
insert into t2 values (@v);
|
||||||
|
include/show_binlog_events.inc
|
||||||
|
Log_name Pos Event_type Server_id End_log_pos Info
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # User var # # @`v`=_ucs2 X'006100620063' COLLATE ucs2_general_ci
|
||||||
|
master-bin.000001 # Query # # use `test`; insert into t2 values (@v)
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
flush logs;
|
||||||
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
|
||||||
|
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||||
|
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||||
|
DELIMITER /*!*/;
|
||||||
|
ROLLBACK/*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
SET @`v`:=_ucs2 X'006100620063' COLLATE `ucs2_general_ci`/*!*/;
|
||||||
|
use `test`/*!*/;
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
SET @@session.pseudo_thread_id=999999999/*!*/;
|
||||||
|
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
|
||||||
|
SET @@session.sql_mode=1342177280/*!*/;
|
||||||
|
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
|
||||||
|
/*!\C latin1 *//*!*/;
|
||||||
|
SET @@session.character_set_client=8,@@session.collation_connection=8,@@session.collation_server=8/*!*/;
|
||||||
|
SET @@session.lc_time_names=0/*!*/;
|
||||||
|
SET @@session.collation_database=DEFAULT/*!*/;
|
||||||
|
insert into t2 values (@v)
|
||||||
|
/*!*/;
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
DELIMITER ;
|
||||||
|
# End of log file
|
||||||
|
ROLLBACK /* added by mysqlbinlog */;
|
||||||
|
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
||||||
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
||||||
|
drop table t2;
|
||||||
|
#
|
||||||
|
# Start of 10.2 tests
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
#
|
||||||
|
FLUSH LOGS;
|
||||||
|
SET NAMES utf8;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8);
|
||||||
|
EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (''ä(i1)'')';
|
||||||
|
EXECUTE IMMEDIATE CONVERT('INSERT INTO t1 VALUES (''ä(i2)'')' USING ucs2);
|
||||||
|
SET @stmt=CONVERT('INSERT INTO t1 VALUES (''ä(i3)'')' USING ucs2);
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
PREPARE stmt FROM 'INSERT INTO t1 VALUES (''ä(p1)'')';
|
||||||
|
EXECUTE stmt;
|
||||||
|
PREPARE stmt FROM CONVERT('INSERT INTO t1 VALUES (''ä(p2)'')' USING ucs2);
|
||||||
|
EXECUTE stmt;
|
||||||
|
SET @stmt=CONVERT('INSERT INTO t1 VALUES (''ä(p3)'')' USING ucs2);
|
||||||
|
PREPARE stmt FROM @stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a
|
||||||
|
ä(i1)
|
||||||
|
ä(i2)
|
||||||
|
ä(i3)
|
||||||
|
ä(p1)
|
||||||
|
ä(p2)
|
||||||
|
ä(p3)
|
||||||
|
DROP TABLE t1;
|
||||||
|
FLUSH LOGS;
|
||||||
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
|
||||||
|
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||||
|
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||||
|
DELIMITER /*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Start: binlog v 4, server v #.##.## created 700101 6:46:40
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Gtid list [#-#-#]
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Binlog checkpoint master-bin.000002
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Binlog checkpoint master-bin.000003
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-# ddl
|
||||||
|
/*!100101 SET @@session.skip_parallel_replication=0*//*!*/;
|
||||||
|
/*!100001 SET @@session.gtid_domain_id=#*//*!*/;
|
||||||
|
/*!100001 SET @@session.server_id=#*//*!*/;
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
use `test`/*!*/;
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
SET @@session.pseudo_thread_id=#/*!*/;
|
||||||
|
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
|
||||||
|
SET @@session.sql_mode=1342177280/*!*/;
|
||||||
|
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
|
||||||
|
/*!\C utf8 *//*!*/;
|
||||||
|
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
|
||||||
|
SET @@session.lc_time_names=0/*!*/;
|
||||||
|
SET @@session.collation_database=DEFAULT/*!*/;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8)
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(i1)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(i2)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(i3)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(p1)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(p2)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(p3)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-# ddl
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
DROP TABLE `t1` /* generated by server */
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Rotate to master-bin.000004 pos: 4
|
||||||
|
DELIMITER ;
|
||||||
|
# End of log file
|
||||||
|
ROLLBACK /* added by mysqlbinlog */;
|
||||||
|
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
||||||
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
||||||
|
#
|
||||||
|
# End of 10.2 tests
|
||||||
|
#
|
@ -20,3 +20,40 @@ let $MYSQLD_DATADIR= `select @@datadir`;
|
|||||||
drop table t2;
|
drop table t2;
|
||||||
|
|
||||||
# End of 4.1 tests
|
# End of 4.1 tests
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Start of 10.2 tests
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
FLUSH LOGS;
|
||||||
|
SET NAMES utf8;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8);
|
||||||
|
EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (''ä(i1)'')';
|
||||||
|
EXECUTE IMMEDIATE CONVERT('INSERT INTO t1 VALUES (''ä(i2)'')' USING ucs2);
|
||||||
|
SET @stmt=CONVERT('INSERT INTO t1 VALUES (''ä(i3)'')' USING ucs2);
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
|
||||||
|
PREPARE stmt FROM 'INSERT INTO t1 VALUES (''ä(p1)'')';
|
||||||
|
EXECUTE stmt;
|
||||||
|
PREPARE stmt FROM CONVERT('INSERT INTO t1 VALUES (''ä(p2)'')' USING ucs2);
|
||||||
|
EXECUTE stmt;
|
||||||
|
SET @stmt=CONVERT('INSERT INTO t1 VALUES (''ä(p3)'')' USING ucs2);
|
||||||
|
PREPARE stmt FROM @stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SELECT * FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
FLUSH LOGS;
|
||||||
|
let $MYSQLD_DATADIR= `select @@datadir`;
|
||||||
|
--replace_regex /# at [0-9]*/# at #/ /(exec_time=|end_log_pos |Xid = |thread_id=|server id |table id |mapped to number )[0-9]+/\1#/ /server v [^ ]*/server v #.##.##/ /CRC32 0x[0-9a-f]*/CRC32 XXX/ /GTID [0-9]+-[0-9]+-[0-9]+/GTID #-#-#/ /Gtid list [[][0-9]+-[0-9]+-[0-9]+[\]]/Gtid list [#-#-#]/ /session[.](gtid_domain_id|server_id|gtid_seq_no)=[0-9]+/session.\1=#/
|
||||||
|
--exec $MYSQL_BINLOG --base64-output=decode-rows -vv $MYSQLD_DATADIR/master-bin.000003
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of 10.2 tests
|
||||||
|
--echo #
|
||||||
|
@ -6230,7 +6230,60 @@ COLLATION("a")
|
|||||||
ucs2_general_ci
|
ucs2_general_ci
|
||||||
SET @stmt='SELECT COLLATION("a")';
|
SET @stmt='SELECT COLLATION("a")';
|
||||||
EXECUTE IMMEDIATE @stmt;
|
EXECUTE IMMEDIATE @stmt;
|
||||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '' at line 1
|
COLLATION("a")
|
||||||
|
ucs2_general_ci
|
||||||
|
#
|
||||||
|
# MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
#
|
||||||
|
SET NAMES utf8, collation_connection=ucs2_bin;
|
||||||
|
SET @stmt='SELECT COLLATION(''a'')';
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
COLLATION('a')
|
||||||
|
ucs2_bin
|
||||||
|
SET NAMES utf8, character_set_connection=ucs2;
|
||||||
|
SET @stmt='SELECT COLLATION(''a'')';
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
COLLATION('a')
|
||||||
|
ucs2_general_ci
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT ''a'' FROM DUAL');
|
||||||
|
a
|
||||||
|
a
|
||||||
|
SELECT HEX('aä') FROM DUAL;
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
EXECUTE IMMEDIATE 'SELECT HEX(''aä'') FROM DUAL';
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT HEX(''aä'') FROM DUAL');
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT HEX(''aä'') FROM ', 'DUAL');
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
PREPARE stmt FROM 'SELECT HEX(''aä'') FROM DUAL';
|
||||||
|
EXECUTE stmt;
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
SET @table='DUAL';
|
||||||
|
SELECT HEX(@table);
|
||||||
|
HEX(@table)
|
||||||
|
004400550041004C
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT HEX(''aä'') FROM ', @table);
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT HEX(''aä'') FROM ', CONVERT(@table USING utf8));
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
SET @stmt='SELECT HEX(''aä'') FROM DUAL';
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
PREPARE stmt FROM @stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
HEX('aä')
|
||||||
|
006100E4
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
#
|
#
|
||||||
# End of 10.2 tests
|
# End of 10.2 tests
|
||||||
#
|
#
|
||||||
|
@ -4014,5 +4014,27 @@ DROP TABLE t1;
|
|||||||
#
|
#
|
||||||
SET STORAGE_ENGINE=Default;
|
SET STORAGE_ENGINE=Default;
|
||||||
#
|
#
|
||||||
|
# MDEV-10867 PREPARE..EXECUTE is not consistent about non-ASCII characters
|
||||||
|
#
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
SELECT '😎' AS c;
|
||||||
|
c
|
||||||
|
😎
|
||||||
|
SET @src='SELECT ''😎'' AS c';
|
||||||
|
PREPARE stmt FROM @src;
|
||||||
|
EXECUTE stmt;
|
||||||
|
c
|
||||||
|
😎
|
||||||
|
EXECUTE IMMEDIATE @src;
|
||||||
|
c
|
||||||
|
😎
|
||||||
|
PREPARE stmt FROM 'SELECT ''😎'' AS c';
|
||||||
|
EXECUTE stmt;
|
||||||
|
c
|
||||||
|
😎
|
||||||
|
EXECUTE IMMEDIATE 'SELECT ''😎'' AS c';
|
||||||
|
c
|
||||||
|
😎
|
||||||
|
#
|
||||||
# End of 10.2 tests
|
# End of 10.2 tests
|
||||||
#
|
#
|
||||||
|
@ -4502,5 +4502,150 @@ DROP FUNCTION get_status_var;
|
|||||||
# End of MDEV-10585 EXECUTE IMMEDIATE statement
|
# End of MDEV-10585 EXECUTE IMMEDIATE statement
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
# MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Testing erroneous and diallowed prepare source
|
||||||
|
#
|
||||||
|
EXECUTE IMMEDIATE CONCAT(_latin1'SELECT 1 AS c FROM ', _latin2 'DUAL');
|
||||||
|
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat'
|
||||||
|
PREPARE stmt FROM CONCAT(_latin1'SELECT 1 AS c FROM ', _latin2 'DUAL');
|
||||||
|
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'concat'
|
||||||
|
EXECUTE IMMEDIATE (SELECT 'SELECT 1');
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 'SELECT 1')' at line 1
|
||||||
|
PREPARE stmt FROM (SELECT 'SELECT 1');
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'SELECT 'SELECT 1')' at line 1
|
||||||
|
EXECUTE IMMEDIATE a;
|
||||||
|
ERROR 42S22: Unknown column 'a' in 'field list'
|
||||||
|
PREPARE stmt FROM a;
|
||||||
|
ERROR 42S22: Unknown column 'a' in 'field list'
|
||||||
|
EXECUTE IMMEDIATE NULL;
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NULL' at line 1
|
||||||
|
PREPARE stmt FROM NULL;
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NULL' at line 1
|
||||||
|
EXECUTE IMMEDIATE CONCAT(NULL);
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NULL' at line 1
|
||||||
|
PREPARE stmt FROM CONCAT(NULL);
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'NULL' at line 1
|
||||||
|
EXECUTE IMMEDIATE ? USING 'SELECT 1';
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '? USING 'SELECT 1'' at line 1
|
||||||
|
EXECUTE IMMEDIATE 10;
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '10' at line 1
|
||||||
|
EXECUTE IMMEDIATE TIME'10:20:30';
|
||||||
|
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '10:20:30' at line 1
|
||||||
|
EXECUTE IMMEDIATE ROW('SELECT 1','SELECT 2');
|
||||||
|
ERROR 21000: Operand should contain 1 column(s)
|
||||||
|
EXECUTE IMMEDIATE MAX('SELECT 1 AS c');
|
||||||
|
ERROR HY000: Invalid use of group function
|
||||||
|
EXECUTE IMMEDIATE DEFAULT(a);
|
||||||
|
ERROR 42S22: Unknown column 'a' in 'field list'
|
||||||
|
EXECUTE IMMEDIATE VALUES(a);
|
||||||
|
ERROR 42S22: Unknown column 'a' in 'field list'
|
||||||
|
CREATE FUNCTION f1() RETURNS VARCHAR(64) RETURN 't1';
|
||||||
|
EXECUTE IMMEDIATE f1();
|
||||||
|
ERROR 42000: EXECUTE IMMEDIATE does not support subqueries or stored functions
|
||||||
|
PREPARE stmt FROM f1();
|
||||||
|
ERROR 42000: PREPARE..FROM does not support subqueries or stored functions
|
||||||
|
DROP FUNCTION f1;
|
||||||
|
EXECUTE IMMEDIATE non_existent();
|
||||||
|
ERROR 42000: EXECUTE IMMEDIATE does not support subqueries or stored functions
|
||||||
|
#
|
||||||
|
# Testing literals in prepare source
|
||||||
|
#
|
||||||
|
EXECUTE IMMEDIATE N'SELECT 1 AS c';
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE _latin1'SELECT 1 AS c';
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE 'SELECT ' '1' ' AS c' ' FROM ' 'DUAL';
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE 0x53454C4543542031 /*This is 'SELECT 1'*/;
|
||||||
|
1
|
||||||
|
1
|
||||||
|
#
|
||||||
|
# Testing user variables in prepare source
|
||||||
|
#
|
||||||
|
SET @stmt='SELECT 1 AS c FROM DUAL';
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
c
|
||||||
|
1
|
||||||
|
PREPARE stmt FROM @stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
c
|
||||||
|
1
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
SET @table_name='DUAL';
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT 1 AS a FROM ', @table_name);
|
||||||
|
a
|
||||||
|
1
|
||||||
|
PREPARE stmt FROM CONCAT('SELECT 1 AS a FROM ', @table_name);
|
||||||
|
EXECUTE stmt;
|
||||||
|
a
|
||||||
|
1
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
#
|
||||||
|
# Testing SP parameters and variables in prepare source
|
||||||
|
#
|
||||||
|
CREATE PROCEDURE p1(table_name VARCHAR(64))
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT 1 AS c FROM ', table_name);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
CALL p1('DUAL');
|
||||||
|
c
|
||||||
|
1
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
BEGIN
|
||||||
|
DECLARE table_name VARCHAR(64) DEFAULT 'DUAL';
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT 1 AS c FROM ', table_name);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
CALL p1();
|
||||||
|
c
|
||||||
|
1
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
#
|
||||||
|
# Testing complex expressions
|
||||||
|
#
|
||||||
|
EXECUTE IMMEDIATE CONVERT('SELECT 1 AS c' USING utf8);
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE CAST('SELECT 1 AS c' AS CHAR);
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE _latin1'SELECT 1 AS c' COLLATE latin1_bin;
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE (((('SELECT 1 AS c'))));
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE CASE WHEN 1>2 THEN 'SELECT 1 AS c' ELSE 'SELECT 2 AS c' END;
|
||||||
|
c
|
||||||
|
2
|
||||||
|
EXECUTE IMMEDIATE TRIM('SELECT 1 AS c');
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE SUBSTRING('SELECT 1 AS c' FROM 1);
|
||||||
|
c
|
||||||
|
1
|
||||||
|
EXECUTE IMMEDIATE COALESCE(NULL, 'SELECT 1 AS c');
|
||||||
|
c
|
||||||
|
1
|
||||||
|
#
|
||||||
|
# Testing SET STATEMENT and system variables
|
||||||
|
#
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
SET STATEMENT max_sort_length=1025 FOR EXECUTE IMMEDIATE CONCAT('INSERT INTO t1 VALUES (', @@max_sort_length, ')');
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a
|
||||||
|
1025
|
||||||
|
DROP TABLE t1;
|
||||||
|
#
|
||||||
|
# End of MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
#
|
||||||
|
#
|
||||||
# End of 10.2 tests
|
# End of 10.2 tests
|
||||||
#
|
#
|
||||||
|
@ -34,3 +34,186 @@ ROLLBACK /* added by mysqlbinlog */;
|
|||||||
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
||||||
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
#
|
||||||
|
# Start of 10.2 tests
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
#
|
||||||
|
FLUSH LOGS;
|
||||||
|
SET NAMES utf8;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8);
|
||||||
|
EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (''ä(i1)'')';
|
||||||
|
EXECUTE IMMEDIATE CONVERT('INSERT INTO t1 VALUES (''ä(i2)'')' USING ucs2);
|
||||||
|
SET @stmt=CONVERT('INSERT INTO t1 VALUES (''ä(i3)'')' USING ucs2);
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
PREPARE stmt FROM 'INSERT INTO t1 VALUES (''ä(p1)'')';
|
||||||
|
EXECUTE stmt;
|
||||||
|
PREPARE stmt FROM CONVERT('INSERT INTO t1 VALUES (''ä(p2)'')' USING ucs2);
|
||||||
|
EXECUTE stmt;
|
||||||
|
SET @stmt=CONVERT('INSERT INTO t1 VALUES (''ä(p3)'')' USING ucs2);
|
||||||
|
PREPARE stmt FROM @stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a
|
||||||
|
ä(i1)
|
||||||
|
ä(i2)
|
||||||
|
ä(i3)
|
||||||
|
ä(p1)
|
||||||
|
ä(p2)
|
||||||
|
ä(p3)
|
||||||
|
DROP TABLE t1;
|
||||||
|
FLUSH LOGS;
|
||||||
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
|
||||||
|
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||||
|
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||||
|
DELIMITER /*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Start: binlog v 4, server v #.##.## created 700101 6:46:40
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Gtid list [#-#-#]
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Binlog checkpoint master-bin.000002
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Binlog checkpoint master-bin.000003
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-# ddl
|
||||||
|
/*!100101 SET @@session.skip_parallel_replication=0*//*!*/;
|
||||||
|
/*!100001 SET @@session.gtid_domain_id=#*//*!*/;
|
||||||
|
/*!100001 SET @@session.server_id=#*//*!*/;
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
use `test`/*!*/;
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
SET @@session.pseudo_thread_id=#/*!*/;
|
||||||
|
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
|
||||||
|
SET @@session.sql_mode=1342177280/*!*/;
|
||||||
|
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
|
||||||
|
/*!\C utf8 *//*!*/;
|
||||||
|
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
|
||||||
|
SET @@session.lc_time_names=0/*!*/;
|
||||||
|
SET @@session.collation_database=DEFAULT/*!*/;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8)
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Table_map: `test`.`t1` mapped to number #
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Write_rows: table id # flags: STMT_END_F
|
||||||
|
### INSERT INTO `test`.`t1`
|
||||||
|
### SET
|
||||||
|
### @1='ä(i1)' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Table_map: `test`.`t1` mapped to number #
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Write_rows: table id # flags: STMT_END_F
|
||||||
|
### INSERT INTO `test`.`t1`
|
||||||
|
### SET
|
||||||
|
### @1='ä(i2)' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Table_map: `test`.`t1` mapped to number #
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Write_rows: table id # flags: STMT_END_F
|
||||||
|
### INSERT INTO `test`.`t1`
|
||||||
|
### SET
|
||||||
|
### @1='ä(i3)' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Table_map: `test`.`t1` mapped to number #
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Write_rows: table id # flags: STMT_END_F
|
||||||
|
### INSERT INTO `test`.`t1`
|
||||||
|
### SET
|
||||||
|
### @1='ä(p1)' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Table_map: `test`.`t1` mapped to number #
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Write_rows: table id # flags: STMT_END_F
|
||||||
|
### INSERT INTO `test`.`t1`
|
||||||
|
### SET
|
||||||
|
### @1='ä(p2)' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Table_map: `test`.`t1` mapped to number #
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Write_rows: table id # flags: STMT_END_F
|
||||||
|
### INSERT INTO `test`.`t1`
|
||||||
|
### SET
|
||||||
|
### @1='ä(p3)' /* VARSTRING(30) meta=30 nullable=1 is_null=0 */
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-# ddl
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
DROP TABLE `t1` /* generated by server */
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Rotate to master-bin.000004 pos: 4
|
||||||
|
DELIMITER ;
|
||||||
|
# End of log file
|
||||||
|
ROLLBACK /* added by mysqlbinlog */;
|
||||||
|
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
||||||
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
||||||
|
#
|
||||||
|
# End of 10.2 tests
|
||||||
|
#
|
||||||
|
@ -39,3 +39,174 @@ ROLLBACK /* added by mysqlbinlog */;
|
|||||||
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
||||||
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
|
#
|
||||||
|
# Start of 10.2 tests
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
#
|
||||||
|
FLUSH LOGS;
|
||||||
|
SET NAMES utf8;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8);
|
||||||
|
EXECUTE IMMEDIATE 'INSERT INTO t1 VALUES (''ä(i1)'')';
|
||||||
|
EXECUTE IMMEDIATE CONVERT('INSERT INTO t1 VALUES (''ä(i2)'')' USING ucs2);
|
||||||
|
SET @stmt=CONVERT('INSERT INTO t1 VALUES (''ä(i3)'')' USING ucs2);
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
PREPARE stmt FROM 'INSERT INTO t1 VALUES (''ä(p1)'')';
|
||||||
|
EXECUTE stmt;
|
||||||
|
PREPARE stmt FROM CONVERT('INSERT INTO t1 VALUES (''ä(p2)'')' USING ucs2);
|
||||||
|
EXECUTE stmt;
|
||||||
|
SET @stmt=CONVERT('INSERT INTO t1 VALUES (''ä(p3)'')' USING ucs2);
|
||||||
|
PREPARE stmt FROM @stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
SELECT * FROM t1;
|
||||||
|
a
|
||||||
|
ä(i1)
|
||||||
|
ä(i2)
|
||||||
|
ä(i3)
|
||||||
|
ä(p1)
|
||||||
|
ä(p2)
|
||||||
|
ä(p3)
|
||||||
|
DROP TABLE t1;
|
||||||
|
FLUSH LOGS;
|
||||||
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
|
||||||
|
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
|
||||||
|
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
|
||||||
|
DELIMITER /*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Start: binlog v 4, server v #.##.## created 700101 6:46:40
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Gtid list [#-#-#]
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Binlog checkpoint master-bin.000002
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Binlog checkpoint master-bin.000003
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-# ddl
|
||||||
|
/*!100101 SET @@session.skip_parallel_replication=0*//*!*/;
|
||||||
|
/*!100001 SET @@session.gtid_domain_id=#*//*!*/;
|
||||||
|
/*!100001 SET @@session.server_id=#*//*!*/;
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
use `test`/*!*/;
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
SET @@session.pseudo_thread_id=#/*!*/;
|
||||||
|
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1, @@session.check_constraint_checks=1/*!*/;
|
||||||
|
SET @@session.sql_mode=1342177280/*!*/;
|
||||||
|
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
|
||||||
|
/*!\C utf8 *//*!*/;
|
||||||
|
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=8/*!*/;
|
||||||
|
SET @@session.lc_time_names=0/*!*/;
|
||||||
|
SET @@session.collation_database=DEFAULT/*!*/;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET utf8)
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(i1)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(i2)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(i3)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(p1)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(p2)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-#
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
BEGIN
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
INSERT INTO t1 VALUES ('ä(p3)')
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
COMMIT
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX GTID #-#-# ddl
|
||||||
|
/*!100001 SET @@session.gtid_seq_no=#*//*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Query thread_id=# exec_time=# error_code=0
|
||||||
|
SET TIMESTAMP=10000/*!*/;
|
||||||
|
DROP TABLE `t1` /* generated by server */
|
||||||
|
/*!*/;
|
||||||
|
# at #
|
||||||
|
#700101 6:46:40 server id # end_log_pos # CRC32 XXX Rotate to master-bin.000004 pos: 4
|
||||||
|
DELIMITER ;
|
||||||
|
# End of log file
|
||||||
|
ROLLBACK /* added by mysqlbinlog */;
|
||||||
|
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
|
||||||
|
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
|
||||||
|
#
|
||||||
|
# End of 10.2 tests
|
||||||
|
#
|
||||||
|
@ -980,12 +980,40 @@ let $coll_pad='ucs2_bin';
|
|||||||
SET character_set_connection=ucs2;
|
SET character_set_connection=ucs2;
|
||||||
EXECUTE IMMEDIATE 'SELECT COLLATION("a")';
|
EXECUTE IMMEDIATE 'SELECT COLLATION("a")';
|
||||||
|
|
||||||
# We don't support character sets with mbminlen>1 in the parser yet
|
|
||||||
# Returning "syntax error" is fine
|
|
||||||
SET @stmt='SELECT COLLATION("a")';
|
SET @stmt='SELECT COLLATION("a")';
|
||||||
--error ER_PARSE_ERROR
|
|
||||||
EXECUTE IMMEDIATE @stmt;
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
--echo #
|
||||||
|
SET NAMES utf8, collation_connection=ucs2_bin;
|
||||||
|
SET @stmt='SELECT COLLATION(''a'')';
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
|
||||||
|
SET NAMES utf8, character_set_connection=ucs2;
|
||||||
|
SET @stmt='SELECT COLLATION(''a'')';
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT ''a'' FROM DUAL');
|
||||||
|
|
||||||
|
SELECT HEX('aä') FROM DUAL;
|
||||||
|
EXECUTE IMMEDIATE 'SELECT HEX(''aä'') FROM DUAL';
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT HEX(''aä'') FROM DUAL');
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT HEX(''aä'') FROM ', 'DUAL');
|
||||||
|
PREPARE stmt FROM 'SELECT HEX(''aä'') FROM DUAL';
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @table='DUAL';
|
||||||
|
SELECT HEX(@table);
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT HEX(''aä'') FROM ', @table);
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT HEX(''aä'') FROM ', CONVERT(@table USING utf8));
|
||||||
|
SET @stmt='SELECT HEX(''aä'') FROM DUAL';
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
PREPARE stmt FROM @stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.2 tests
|
--echo # End of 10.2 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -1964,6 +1964,21 @@ let $coll='utf8mb4_nopad_bin';
|
|||||||
let $coll_pad='utf8mb4_bin';
|
let $coll_pad='utf8mb4_bin';
|
||||||
--source include/ctype_pad_all_engines.inc
|
--source include/ctype_pad_all_engines.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-10867 PREPARE..EXECUTE is not consistent about non-ASCII characters
|
||||||
|
--echo #
|
||||||
|
SET NAMES utf8mb4;
|
||||||
|
SELECT '😎' AS c;
|
||||||
|
|
||||||
|
SET @src='SELECT ''😎'' AS c';
|
||||||
|
PREPARE stmt FROM @src;
|
||||||
|
EXECUTE stmt;
|
||||||
|
EXECUTE IMMEDIATE @src;
|
||||||
|
|
||||||
|
PREPARE stmt FROM 'SELECT ''😎'' AS c';
|
||||||
|
EXECUTE stmt;
|
||||||
|
EXECUTE IMMEDIATE 'SELECT ''😎'' AS c';
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.2 tests
|
--echo # End of 10.2 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -4045,6 +4045,146 @@ DROP FUNCTION get_status_var;
|
|||||||
--echo # End of MDEV-10585 EXECUTE IMMEDIATE statement
|
--echo # End of MDEV-10585 EXECUTE IMMEDIATE statement
|
||||||
--echo #
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing erroneous and diallowed prepare source
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
--error ER_CANT_AGGREGATE_2COLLATIONS
|
||||||
|
EXECUTE IMMEDIATE CONCAT(_latin1'SELECT 1 AS c FROM ', _latin2 'DUAL');
|
||||||
|
--error ER_CANT_AGGREGATE_2COLLATIONS
|
||||||
|
PREPARE stmt FROM CONCAT(_latin1'SELECT 1 AS c FROM ', _latin2 'DUAL');
|
||||||
|
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
EXECUTE IMMEDIATE (SELECT 'SELECT 1');
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
PREPARE stmt FROM (SELECT 'SELECT 1');
|
||||||
|
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
EXECUTE IMMEDIATE a;
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
PREPARE stmt FROM a;
|
||||||
|
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
EXECUTE IMMEDIATE NULL;
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
PREPARE stmt FROM NULL;
|
||||||
|
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
EXECUTE IMMEDIATE CONCAT(NULL);
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
PREPARE stmt FROM CONCAT(NULL);
|
||||||
|
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
EXECUTE IMMEDIATE ? USING 'SELECT 1';
|
||||||
|
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
EXECUTE IMMEDIATE 10;
|
||||||
|
|
||||||
|
--error ER_PARSE_ERROR
|
||||||
|
EXECUTE IMMEDIATE TIME'10:20:30';
|
||||||
|
|
||||||
|
--error ER_OPERAND_COLUMNS
|
||||||
|
EXECUTE IMMEDIATE ROW('SELECT 1','SELECT 2');
|
||||||
|
|
||||||
|
--error ER_INVALID_GROUP_FUNC_USE
|
||||||
|
EXECUTE IMMEDIATE MAX('SELECT 1 AS c');
|
||||||
|
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
EXECUTE IMMEDIATE DEFAULT(a);
|
||||||
|
|
||||||
|
--error ER_BAD_FIELD_ERROR
|
||||||
|
EXECUTE IMMEDIATE VALUES(a);
|
||||||
|
|
||||||
|
|
||||||
|
CREATE FUNCTION f1() RETURNS VARCHAR(64) RETURN 't1';
|
||||||
|
--error ER_SUBQUERIES_NOT_SUPPORTED
|
||||||
|
EXECUTE IMMEDIATE f1();
|
||||||
|
--error ER_SUBQUERIES_NOT_SUPPORTED
|
||||||
|
PREPARE stmt FROM f1();
|
||||||
|
DROP FUNCTION f1;
|
||||||
|
|
||||||
|
--error ER_SUBQUERIES_NOT_SUPPORTED
|
||||||
|
EXECUTE IMMEDIATE non_existent();
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing literals in prepare source
|
||||||
|
--echo #
|
||||||
|
EXECUTE IMMEDIATE N'SELECT 1 AS c';
|
||||||
|
EXECUTE IMMEDIATE _latin1'SELECT 1 AS c';
|
||||||
|
EXECUTE IMMEDIATE 'SELECT ' '1' ' AS c' ' FROM ' 'DUAL';
|
||||||
|
EXECUTE IMMEDIATE 0x53454C4543542031 /*This is 'SELECT 1'*/;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing user variables in prepare source
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET @stmt='SELECT 1 AS c FROM DUAL';
|
||||||
|
EXECUTE IMMEDIATE @stmt;
|
||||||
|
PREPARE stmt FROM @stmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
SET @table_name='DUAL';
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT 1 AS a FROM ', @table_name);
|
||||||
|
PREPARE stmt FROM CONCAT('SELECT 1 AS a FROM ', @table_name);
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing SP parameters and variables in prepare source
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1(table_name VARCHAR(64))
|
||||||
|
BEGIN
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT 1 AS c FROM ', table_name);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
CALL p1('DUAL');
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1()
|
||||||
|
BEGIN
|
||||||
|
DECLARE table_name VARCHAR(64) DEFAULT 'DUAL';
|
||||||
|
EXECUTE IMMEDIATE CONCAT('SELECT 1 AS c FROM ', table_name);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
CALL p1();
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing complex expressions
|
||||||
|
--echo #
|
||||||
|
EXECUTE IMMEDIATE CONVERT('SELECT 1 AS c' USING utf8);
|
||||||
|
EXECUTE IMMEDIATE CAST('SELECT 1 AS c' AS CHAR);
|
||||||
|
EXECUTE IMMEDIATE _latin1'SELECT 1 AS c' COLLATE latin1_bin;
|
||||||
|
EXECUTE IMMEDIATE (((('SELECT 1 AS c'))));
|
||||||
|
EXECUTE IMMEDIATE CASE WHEN 1>2 THEN 'SELECT 1 AS c' ELSE 'SELECT 2 AS c' END;
|
||||||
|
EXECUTE IMMEDIATE TRIM('SELECT 1 AS c');
|
||||||
|
EXECUTE IMMEDIATE SUBSTRING('SELECT 1 AS c' FROM 1);
|
||||||
|
EXECUTE IMMEDIATE COALESCE(NULL, 'SELECT 1 AS c');
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Testing SET STATEMENT and system variables
|
||||||
|
--echo #
|
||||||
|
CREATE TABLE t1 (a INT);
|
||||||
|
SET STATEMENT max_sort_length=1025 FOR EXECUTE IMMEDIATE CONCAT('INSERT INTO t1 VALUES (', @@max_sort_length, ')');
|
||||||
|
SELECT * FROM t1;
|
||||||
|
DROP TABLE t1;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # End of MDEV-10866 Extend PREPARE and EXECUTE IMMEDIATE to understand expressions
|
||||||
|
--echo #
|
||||||
|
|
||||||
--echo #
|
--echo #
|
||||||
--echo # End of 10.2 tests
|
--echo # End of 10.2 tests
|
||||||
--echo #
|
--echo #
|
||||||
|
@ -2720,13 +2720,8 @@ public:
|
|||||||
TABLE_LIST *create_last_non_select_table;
|
TABLE_LIST *create_last_non_select_table;
|
||||||
/* Prepared statements SQL syntax:*/
|
/* Prepared statements SQL syntax:*/
|
||||||
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
|
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
|
||||||
/*
|
/* PREPARE or EXECUTE IMMEDIATE source expression */
|
||||||
Prepared statement query text or name of variable that holds the
|
Item *prepared_stmt_code;
|
||||||
prepared statement (in PREPARE ... queries)
|
|
||||||
*/
|
|
||||||
LEX_STRING prepared_stmt_code;
|
|
||||||
/* If true, prepared_stmt_code is a name of variable that holds the query */
|
|
||||||
bool prepared_stmt_code_is_varref;
|
|
||||||
/* Names of user variables holding parameters (in EXECUTE) */
|
/* Names of user variables holding parameters (in EXECUTE) */
|
||||||
List<Item> prepared_stmt_params;
|
List<Item> prepared_stmt_params;
|
||||||
sp_head *sphead;
|
sp_head *sphead;
|
||||||
@ -3007,6 +3002,7 @@ public:
|
|||||||
void set_last_field_type(const Lex_field_type_st &type);
|
void set_last_field_type(const Lex_field_type_st &type);
|
||||||
bool set_bincmp(CHARSET_INFO *cs, bool bin);
|
bool set_bincmp(CHARSET_INFO *cs, bool bin);
|
||||||
|
|
||||||
|
bool get_dynamic_sql_string(LEX_CSTRING *dst, String *buffer);
|
||||||
bool prepared_stmt_params_fix_fields(THD *thd)
|
bool prepared_stmt_params_fix_fields(THD *thd)
|
||||||
{
|
{
|
||||||
// Fix Items in the EXECUTE..USING list
|
// Fix Items in the EXECUTE..USING list
|
||||||
|
@ -704,6 +704,7 @@ void init_update_queries(void)
|
|||||||
CF_CAN_GENERATE_ROW_EVENTS |
|
CF_CAN_GENERATE_ROW_EVENTS |
|
||||||
CF_OPTIMIZER_TRACE; // (1)
|
CF_OPTIMIZER_TRACE; // (1)
|
||||||
sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS;
|
sql_command_flags[SQLCOM_EXECUTE]= CF_CAN_GENERATE_ROW_EVENTS;
|
||||||
|
sql_command_flags[SQLCOM_EXECUTE_IMMEDIATE]= CF_CAN_GENERATE_ROW_EVENTS;
|
||||||
sql_command_flags[SQLCOM_COMPOUND]= CF_CAN_GENERATE_ROW_EVENTS;
|
sql_command_flags[SQLCOM_COMPOUND]= CF_CAN_GENERATE_ROW_EVENTS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2601,95 +2601,99 @@ end:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get an SQL statement text from a user variable or from plain text.
|
Get an SQL statement from an item in lex->prepared_stmt_code.
|
||||||
|
|
||||||
If the statement is plain text, just assign the
|
This function can return pointers to very different memory classes:
|
||||||
pointers, otherwise allocate memory in thd->mem_root and copy
|
- a static string "NULL", if the item returned NULL
|
||||||
the contents of the variable, possibly with character
|
- the result of prepare_stmt_code->val_str(), if no conversion was needed
|
||||||
set conversion.
|
- a thd->mem_root allocated string with the result of
|
||||||
|
prepare_stmt_code->val_str() converted to @@collation_connection,
|
||||||
|
if conversion was needed
|
||||||
|
|
||||||
@param[in] lex main lex
|
The caller must dispose the result before the life cycle of "buffer" ends.
|
||||||
@param[out] query_len length of the SQL statement (is set only
|
As soon as buffer's destructor is called, the value is not valid any more!
|
||||||
in case of success)
|
|
||||||
|
|
||||||
@retval
|
mysql_sql_stmt_prepare() and mysql_sql_stmt_execute_immediate()
|
||||||
non-zero success
|
call get_dynamic_sql_string() and then call respectively
|
||||||
@retval
|
Prepare_statement::prepare() and Prepare_statment::execute_immediate(),
|
||||||
0 in case of error (out of memory)
|
who store the returned result into its permanent location using
|
||||||
|
alloc_query(). "buffer" is still not destructed at that time.
|
||||||
|
|
||||||
|
@param[out] dst the result is stored here
|
||||||
|
@param[inout] buffer
|
||||||
|
|
||||||
|
@retval false on success
|
||||||
|
@retval true on error (out of memory)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static const char *get_dynamic_sql_string(LEX *lex, uint *query_len)
|
bool LEX::get_dynamic_sql_string(LEX_CSTRING *dst, String *buffer)
|
||||||
{
|
{
|
||||||
THD *thd= lex->thd;
|
if (prepared_stmt_code->fix_fields(thd, NULL) ||
|
||||||
char *query_str= 0;
|
prepared_stmt_code->check_cols(1))
|
||||||
|
return true;
|
||||||
|
|
||||||
if (lex->prepared_stmt_code_is_varref)
|
const String *str= prepared_stmt_code->val_str(buffer);
|
||||||
|
if (prepared_stmt_code->null_value)
|
||||||
{
|
{
|
||||||
/* This is PREPARE stmt FROM or EXECUTE IMMEDIATE @var. */
|
|
||||||
String str;
|
|
||||||
CHARSET_INFO *to_cs= thd->variables.collation_connection;
|
|
||||||
bool needs_conversion;
|
|
||||||
user_var_entry *entry;
|
|
||||||
String *var_value= &str;
|
|
||||||
uint32 unused, len;
|
|
||||||
/*
|
/*
|
||||||
Convert @var contents to string in connection character set. Although
|
Prepare source was NULL, so we need to set "str" to
|
||||||
it is known that int/real/NULL value cannot be a valid query we still
|
something reasonable to get a readable error message during parsing
|
||||||
convert it for error messages to be uniform.
|
|
||||||
*/
|
*/
|
||||||
if ((entry=
|
dst->str= "NULL";
|
||||||
(user_var_entry*)my_hash_search(&thd->user_vars,
|
dst->length= 4;
|
||||||
(uchar*)lex->prepared_stmt_code.str,
|
return false;
|
||||||
lex->prepared_stmt_code.length))
|
|
||||||
&& entry->value)
|
|
||||||
{
|
|
||||||
bool is_var_null;
|
|
||||||
var_value= entry->val_str(&is_var_null, &str, NOT_FIXED_DEC);
|
|
||||||
/*
|
|
||||||
NULL value of variable checked early as entry->value so here
|
|
||||||
we can't get NULL in normal conditions
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(!is_var_null);
|
|
||||||
if (!var_value)
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
variable absent or equal to NULL, so we need to set variable to
|
|
||||||
something reasonable to get a readable error message during parsing
|
|
||||||
*/
|
|
||||||
str.set(STRING_WITH_LEN("NULL"), &my_charset_latin1);
|
|
||||||
}
|
|
||||||
|
|
||||||
needs_conversion= String::needs_conversion(var_value->length(),
|
|
||||||
var_value->charset(), to_cs,
|
|
||||||
&unused);
|
|
||||||
|
|
||||||
len= (needs_conversion ? var_value->length() * to_cs->mbmaxlen :
|
|
||||||
var_value->length());
|
|
||||||
if (!(query_str= (char*) alloc_root(thd->mem_root, len+1)))
|
|
||||||
goto end;
|
|
||||||
|
|
||||||
if (needs_conversion)
|
|
||||||
{
|
|
||||||
uint dummy_errors;
|
|
||||||
len= copy_and_convert(query_str, len, to_cs, var_value->ptr(),
|
|
||||||
var_value->length(), var_value->charset(),
|
|
||||||
&dummy_errors);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
memcpy(query_str, var_value->ptr(), var_value->length());
|
|
||||||
query_str[len]= '\0'; // Safety (mostly for debug)
|
|
||||||
*query_len= len;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/*
|
||||||
|
Character set conversion notes:
|
||||||
|
|
||||||
|
1) When PREPARE or EXECUTE IMMEDIATE are used with string literals:
|
||||||
|
PREPARE stmt FROM 'SELECT ''str''';
|
||||||
|
EXECUTE IMMEDIATE 'SELECT ''str''';
|
||||||
|
it's very unlikely that any conversion will happen below, because
|
||||||
|
@@character_set_client and @@collation_connection are normally
|
||||||
|
set to the same CHARSET_INFO pointer.
|
||||||
|
|
||||||
|
In tricky environments when @@collation_connection is set to something
|
||||||
|
different from @@character_set_client, double conversion may happen:
|
||||||
|
- When the parser scans the string literal
|
||||||
|
(sql_yacc.yy rules "prepare_src" -> "expr" -> ... -> "text_literal")
|
||||||
|
it will convert 'str' from @@character_set_client to
|
||||||
|
@@collation_connection.
|
||||||
|
- Then in the code below will convert 'str' from @@collation_connection
|
||||||
|
back to @@character_set_client.
|
||||||
|
|
||||||
|
2) When PREPARE or EXECUTE IMMEDIATE is used with a user variable,
|
||||||
|
it should work about the same way, because user variables are usually
|
||||||
|
assigned like this:
|
||||||
|
SET @str='str';
|
||||||
|
and thus have the same character set with string literals.
|
||||||
|
|
||||||
|
3) When PREPARE or EXECUTE IMMEDIATE is used with some
|
||||||
|
more complex expression, conversion will depend on this expression.
|
||||||
|
For example, a concatenation of string literals:
|
||||||
|
EXECUTE IMMEDIATE 'SELECT * FROM'||'t1';
|
||||||
|
should work the same way with just a single literal,
|
||||||
|
so no conversion normally.
|
||||||
|
*/
|
||||||
|
CHARSET_INFO *to_cs= thd->variables.character_set_client;
|
||||||
|
|
||||||
|
uint32 unused;
|
||||||
|
if (String::needs_conversion(str->length(), str->charset(), to_cs, &unused))
|
||||||
{
|
{
|
||||||
query_str= lex->prepared_stmt_code.str;
|
if (!(dst->str= sql_strmake_with_convert(thd, str->ptr(), str->length(),
|
||||||
*query_len= lex->prepared_stmt_code.length;
|
str->charset(), UINT_MAX32,
|
||||||
|
to_cs, &dst->length)))
|
||||||
|
{
|
||||||
|
dst->length= 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
DBUG_ASSERT(dst->length <= UINT_MAX32);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
end:
|
dst->str= str->ptr();
|
||||||
return query_str;
|
dst->length= str->length();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2712,8 +2716,7 @@ void mysql_sql_stmt_prepare(THD *thd)
|
|||||||
LEX *lex= thd->lex;
|
LEX *lex= thd->lex;
|
||||||
LEX_STRING *name= &lex->prepared_stmt_name;
|
LEX_STRING *name= &lex->prepared_stmt_name;
|
||||||
Prepared_statement *stmt;
|
Prepared_statement *stmt;
|
||||||
const char *query;
|
LEX_CSTRING query;
|
||||||
uint query_len= 0;
|
|
||||||
DBUG_ENTER("mysql_sql_stmt_prepare");
|
DBUG_ENTER("mysql_sql_stmt_prepare");
|
||||||
|
|
||||||
if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
|
if ((stmt= (Prepared_statement*) thd->stmt_map.find_by_name(name)))
|
||||||
@ -2731,7 +2734,12 @@ void mysql_sql_stmt_prepare(THD *thd)
|
|||||||
stmt->deallocate();
|
stmt->deallocate();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! (query= get_dynamic_sql_string(lex, &query_len)) ||
|
/*
|
||||||
|
It's important for "buffer" not to be destructed before stmt->prepare()!
|
||||||
|
See comments in get_dynamic_sql_string().
|
||||||
|
*/
|
||||||
|
StringBuffer<256> buffer;
|
||||||
|
if (lex->get_dynamic_sql_string(&query, &buffer) ||
|
||||||
! (stmt= new Prepared_statement(thd)))
|
! (stmt= new Prepared_statement(thd)))
|
||||||
{
|
{
|
||||||
DBUG_VOID_RETURN; /* out of memory */
|
DBUG_VOID_RETURN; /* out of memory */
|
||||||
@ -2752,7 +2760,7 @@ void mysql_sql_stmt_prepare(THD *thd)
|
|||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stmt->prepare(query, query_len))
|
if (stmt->prepare(query.str, (uint) query.length))
|
||||||
{
|
{
|
||||||
/* Statement map deletes the statement on erase */
|
/* Statement map deletes the statement on erase */
|
||||||
thd->stmt_map.erase(stmt);
|
thd->stmt_map.erase(stmt);
|
||||||
@ -2771,8 +2779,7 @@ void mysql_sql_stmt_execute_immediate(THD *thd)
|
|||||||
{
|
{
|
||||||
LEX *lex= thd->lex;
|
LEX *lex= thd->lex;
|
||||||
Prepared_statement *stmt;
|
Prepared_statement *stmt;
|
||||||
const char *query;
|
LEX_CSTRING query;
|
||||||
uint query_len= 0;
|
|
||||||
DBUG_ENTER("mysql_sql_stmt_execute_immediate");
|
DBUG_ENTER("mysql_sql_stmt_execute_immediate");
|
||||||
|
|
||||||
if (lex->prepared_stmt_params_fix_fields(thd))
|
if (lex->prepared_stmt_params_fix_fields(thd))
|
||||||
@ -2781,15 +2788,20 @@ void mysql_sql_stmt_execute_immediate(THD *thd)
|
|||||||
/*
|
/*
|
||||||
Prepared_statement is quite large,
|
Prepared_statement is quite large,
|
||||||
let's allocate it on the heap rather than on the stack.
|
let's allocate it on the heap rather than on the stack.
|
||||||
|
|
||||||
|
It's important for "buffer" not to be destructed
|
||||||
|
before stmt->execute_immediate().
|
||||||
|
See comments in get_dynamic_sql_string().
|
||||||
*/
|
*/
|
||||||
if (!(query= get_dynamic_sql_string(lex, &query_len)) ||
|
StringBuffer<256> buffer;
|
||||||
|
if (lex->get_dynamic_sql_string(&query, &buffer) ||
|
||||||
!(stmt= new Prepared_statement(thd)))
|
!(stmt= new Prepared_statement(thd)))
|
||||||
DBUG_VOID_RETURN; // out of memory
|
DBUG_VOID_RETURN; // out of memory
|
||||||
|
|
||||||
// See comments on thd->free_list in mysql_sql_stmt_execute()
|
// See comments on thd->free_list in mysql_sql_stmt_execute()
|
||||||
Item *free_list_backup= thd->free_list;
|
Item *free_list_backup= thd->free_list;
|
||||||
thd->free_list= NULL;
|
thd->free_list= NULL;
|
||||||
(void) stmt->execute_immediate(query, query_len);
|
(void) stmt->execute_immediate(query.str, (uint) query.length);
|
||||||
thd->free_items();
|
thd->free_items();
|
||||||
thd->free_list= free_list_backup;
|
thd->free_list= free_list_backup;
|
||||||
|
|
||||||
|
@ -2223,23 +2223,20 @@ prepare:
|
|||||||
PREPARE_SYM ident FROM prepare_src
|
PREPARE_SYM ident FROM prepare_src
|
||||||
{
|
{
|
||||||
LEX *lex= thd->lex;
|
LEX *lex= thd->lex;
|
||||||
|
if (lex->table_or_sp_used())
|
||||||
|
my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
|
||||||
|
"PREPARE..FROM"));
|
||||||
lex->sql_command= SQLCOM_PREPARE;
|
lex->sql_command= SQLCOM_PREPARE;
|
||||||
lex->prepared_stmt_name= $2;
|
lex->prepared_stmt_name= $2;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
prepare_src:
|
prepare_src:
|
||||||
TEXT_STRING_sys
|
{ Lex->expr_allows_subselect= false; }
|
||||||
|
expr
|
||||||
{
|
{
|
||||||
LEX *lex= thd->lex;
|
Lex->prepared_stmt_code= $2;
|
||||||
lex->prepared_stmt_code= $1;
|
Lex->expr_allows_subselect= true;
|
||||||
lex->prepared_stmt_code_is_varref= FALSE;
|
|
||||||
}
|
|
||||||
| '@' ident_or_text
|
|
||||||
{
|
|
||||||
LEX *lex= thd->lex;
|
|
||||||
lex->prepared_stmt_code= $2;
|
|
||||||
lex->prepared_stmt_code_is_varref= TRUE;
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -2254,6 +2251,9 @@ execute:
|
|||||||
{}
|
{}
|
||||||
| EXECUTE_SYM IMMEDIATE_SYM prepare_src
|
| EXECUTE_SYM IMMEDIATE_SYM prepare_src
|
||||||
{
|
{
|
||||||
|
if (Lex->table_or_sp_used())
|
||||||
|
my_yyabort_error((ER_SUBQUERIES_NOT_SUPPORTED, MYF(0),
|
||||||
|
"EXECUTE IMMEDIATE"));
|
||||||
Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE;
|
Lex->sql_command= SQLCOM_EXECUTE_IMMEDIATE;
|
||||||
}
|
}
|
||||||
execute_using
|
execute_using
|
||||||
|
Reference in New Issue
Block a user