Merge remote-tracking branch 'origin/bb-10.2-ext' into 10.3

This commit is contained in:
Alexander Barkov 2017-09-23 09:37:18 +04:00
commit 41da3ca9cc
19 changed files with 892 additions and 304 deletions

View file

@ -442,6 +442,23 @@ CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/include/mysql_version.h.in
${CMAKE_BINARY_DIR}/include/mysql_version.h )
CONFIGURE_FILE(${CMAKE_SOURCE_DIR}/sql/sql_builtin.cc.in
${CMAKE_BINARY_DIR}/sql/sql_builtin.cc)
FIND_PACKAGE(Git)
IF(GIT_EXECUTABLE)
EXECUTE_PROCESS(
COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
OUTPUT_VARIABLE OUT RESULT_VARIABLE RES)
IF(RES EQUAL 0)
STRING(REGEX REPLACE "\n$" "" SOURCE_REVISION "${OUT}")
ENDIF()
ENDIF()
IF(SOURCE_REVISION OR
(NOT EXISTS ${PROJECT_SOURCE_DIR}/include/source_revision.h))
CONFIGURE_FILE(${PROJECT_SOURCE_DIR}/include/source_revision.h.in
${PROJECT_BINARY_DIR}/include/source_revision.h )
ENDIF()
CONFIGURE_FILE(
${CMAKE_SOURCE_DIR}/cmake/info_macros.cmake.in
${CMAKE_BINARY_DIR}/info_macros.cmake @ONLY)

View file

@ -40,7 +40,7 @@
#include "my_readline.h"
#include <signal.h>
#include <violite.h>
#include <source_revision.h>
#if defined(USE_LIBEDIT_INTERFACE) && defined(HAVE_LOCALE_H)
#include <locale.h>
#endif
@ -1719,8 +1719,8 @@ static void usage(int version)
my_progname, VER, MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,
readline, rl_library_version);
#else
printf("%s Ver %s Distrib %s, for %s (%s)\n", my_progname, VER,
MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE);
printf("%s Ver %s Distrib %s, for %s (%s), source revision %s\n", my_progname, VER,
MYSQL_SERVER_VERSION, SYSTEM_TYPE, MACHINE_TYPE,SOURCE_REVISION);
#endif
if (version)

View file

@ -52,6 +52,9 @@ IF(GIT_EXECUTABLE)
ENDIF()
ENDIF()
CONFIGURE_FILE(${CMAKE_BINARY_DIR}/include/source_revision.h
${PACKAGE_DIR}/include/source_revision.h COPYONLY)
IF(NOT GIT_EXECUTABLE)
MESSAGE(STATUS "git not found or source dir is not a repo, use CPack")

View file

@ -0,0 +1 @@
#cmakedefine SOURCE_REVISION "@SOURCE_REVISION@"

View file

@ -447,3 +447,51 @@ EXECUTE stmt;
good was_bad_now_good
one one
DEALLOCATE PREPARE stmt;
#
# MDEV-13864 Change Item_func_case to store the predicant in args[0]
#
SET NAMES latin1;
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1);
INSERT INTO t1 VALUES ('a'),('b'),('c');
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE a WHEN 'a' THEN 'a' ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN a THEN 'a' ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a' and (case 'a' when 'a' then `test`.`t1`.`a` else 'a' end) = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a' and (case 'a' when 'a' then 'a' else `test`.`t1`.`a` end) = 'a'
ALTER TABLE t1 MODIFY a VARBINARY(10);
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE a WHEN 'a' THEN 'a' ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN a THEN 'a' ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE 'a' END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a';
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE t1 ALL NULL NULL NULL NULL 3 100.00 Using where
Warnings:
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where `test`.`t1`.`a` = 'a'
DROP TABLE t1;

View file

@ -1629,8 +1629,8 @@ WHEN -9223372036854775808 THEN 'one'
c
NULL
Warnings:
Note 1105 DBUG: [0] arg=0 handler=0 (bigint)
Note 1105 DBUG: [1] arg=2 handler=1 (decimal)
Note 1105 DBUG: [0] arg=1 handler=0 (bigint)
Note 1105 DBUG: [1] arg=3 handler=1 (decimal)
DROP TABLE t1;
#
# MDEV-11555 CASE with a mixture of TIME and DATETIME returns a wrong result
@ -1648,10 +1648,10 @@ CASE TIME'10:20:30'
good was_bad_now_good
one one
Warnings:
Note 1105 DBUG: [0] arg=0 handler=0 (time)
Note 1105 DBUG: [1] arg=2 handler=0 (time)
Note 1105 DBUG: [0] arg=0 handler=0 (time)
Note 1105 DBUG: [1] arg=2 handler=0 (time)
Note 1105 DBUG: [2] arg=4 handler=2 (datetime)
Note 1105 DBUG: [0] arg=1 handler=0 (time)
Note 1105 DBUG: [1] arg=3 handler=0 (time)
Note 1105 DBUG: [0] arg=1 handler=0 (time)
Note 1105 DBUG: [1] arg=3 handler=0 (time)
Note 1105 DBUG: [2] arg=5 handler=2 (datetime)
SET SESSION debug_dbug="-d,Predicant_to_list_comparator";
SET SESSION debug_dbug="-d,Item_func_in";

View file

@ -28,6 +28,150 @@ EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select case 12 when 10 then 'x10' when 11 then 'x11' else 'def' end AS "DECODE(12,10,'x10',11,'x11','def')"
Note 1003 select decode_oracle(12,10,'x10',11,'x11','def') AS "DECODE(12,10,'x10',11,'x11','def')"
CREATE TABLE decode (decode int);
DROP TABLE decode;
#
# MDEV-13863 sql_mode=ORACLE: DECODE does not treat two NULLs as equivalent
#
SELECT DECODE(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 ')' at line 1
SELECT DECODE(10,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 ')' at line 1
SELECT DECODE_ORACLE(10);
ERROR 42000: Incorrect parameter count in the call to native function 'DECODE_ORACLE'
SELECT DECODE_ORACLE(10,10);
ERROR 42000: Incorrect parameter count in the call to native function 'DECODE_ORACLE'
EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select decode_oracle(12,10,'x10',11,'x11') AS "DECODE(12,10,'x10',11,'x11')"
EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select decode_oracle(12,10,'x10',11,'x11','def') AS "DECODE(12,10,'x10',11,'x11','def')"
EXPLAIN EXTENDED SELECT DECODE_ORACLE(12,10,'x10',11,'x11');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select decode_oracle(12,10,'x10',11,'x11') AS "DECODE_ORACLE(12,10,'x10',11,'x11')"
EXPLAIN EXTENDED SELECT DECODE_ORACLE(12,10,'x10',11,'x11','def');
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings:
Note 1003 select decode_oracle(12,10,'x10',11,'x11','def') AS "DECODE_ORACLE(12,10,'x10',11,'x11','def')"
CREATE TABLE t1 (a INT);
CREATE VIEW v1 AS
SELECT
DECODE(a,1,'x1',NULL,'xNULL') AS d1,
DECODE(a,1,'x1',NULL,'xNULL','xELSE') AS d2,
DECODE_ORACLE(a,1,'x1',NULL,'xNULL') AS d3,
DECODE_ORACLE(a,1,'x1',NULL,'xNULL','xELSE') AS d4
FROM t1;
SHOW CREATE VIEW v1;
View Create View character_set_client collation_connection
v1 CREATE VIEW "v1" AS select decode_oracle("t1"."a",1,'x1',NULL,'xNULL') AS "d1",decode_oracle("t1"."a",1,'x1',NULL,'xNULL','xELSE') AS "d2",decode_oracle("t1"."a",1,'x1',NULL,'xNULL') AS "d3",decode_oracle("t1"."a",1,'x1',NULL,'xNULL','xELSE') AS "d4" from "t1" latin1 latin1_swedish_ci
DROP VIEW v1;
DROP TABLE t1;
SELECT DECODE(TIME'10:20:31','10:20:31','then1','10:20:32','then2','def');
DECODE(TIME'10:20:31','10:20:31','then1','10:20:32','then2','def')
then1
SELECT DECODE(TIME'10:20:32','10:20:31','then1','10:20:32','then2','def');
DECODE(TIME'10:20:32','10:20:31','then1','10:20:32','then2','def')
then2
SELECT DECODE(TIME'10:20:33','10:20:31','then1',NULL,'then2NULL','10:20:33','then3','def');
DECODE(TIME'10:20:33','10:20:31','then1',NULL,'then2NULL','10:20:33','then3','def')
then3
SELECT DECODE(NULL,TIME'10:20:31','then1',NULL,'then2NULL','10:20:33','then3','def');
DECODE(NULL,TIME'10:20:31','then1',NULL,'then2NULL','10:20:33','then3','def')
then2NULL
SELECT DECODE(TIMESTAMP'2001-01-01 10:20:31','2001-01-01 10:20:31','then1','2001-01-01 10:20:32','then2','def');
DECODE(TIMESTAMP'2001-01-01 10:20:31','2001-01-01 10:20:31','then1','2001-01-01 10:20:32','then2','def')
then1
SELECT DECODE(TIMESTAMP'2001-01-01 10:20:32','2001-01-01 10:20:31','then1','2001-01-01 10:20:32','then2','def');
DECODE(TIMESTAMP'2001-01-01 10:20:32','2001-01-01 10:20:31','then1','2001-01-01 10:20:32','then2','def')
then2
SELECT DECODE(TIMESTAMP'2001-01-01 10:20:33','2001-01-01 10:20:31','then1',NULL,'then2NULL','2001-01-01 10:20:33','then3','def');
DECODE(TIMESTAMP'2001-01-01 10:20:33','2001-01-01 10:20:31','then1',NULL,'then2NULL','2001-01-01 10:20:33','then3','def')
then3
SELECT DECODE(NULL,TIMESTAMP'2001-01-01 10:20:31','then1',NULL,'then2NULL','2001-01-01 10:20:33','then3','def');
DECODE(NULL,TIMESTAMP'2001-01-01 10:20:31','then1',NULL,'then2NULL','2001-01-01 10:20:33','then3','def')
then2NULL
SELECT DECODE('w1','w1','then1','w2','then2','def');
DECODE('w1','w1','then1','w2','then2','def')
then1
SELECT DECODE('w2','w1','then1','w2','then2','def');
DECODE('w2','w1','then1','w2','then2','def')
then2
SELECT DECODE('w3','w1','then1',NULL,'then2NULL','w3','then3','def');
DECODE('w3','w1','then1',NULL,'then2NULL','w3','then3','def')
then3
SELECT DECODE(NULL,'w1','then1',NULL,'then2NULL','w3','then3','def');
DECODE(NULL,'w1','then1',NULL,'then2NULL','w3','then3','def')
then2NULL
SELECT DECODE(1,1,'then1',2,'then2','def');
DECODE(1,1,'then1',2,'then2','def')
then1
SELECT DECODE(2,1,'then1',2,'then2','def');
DECODE(2,1,'then1',2,'then2','def')
then2
SELECT DECODE(3,1,'then1',NULL,'then2NULL',3,'then3','def');
DECODE(3,1,'then1',NULL,'then2NULL',3,'then3','def')
then3
SELECT DECODE(NULL,1,'then1',NULL,'then2NULL',3,'then3','def');
DECODE(NULL,1,'then1',NULL,'then2NULL',3,'then3','def')
then2NULL
SELECT DECODE(CAST(NULL AS SIGNED),1,'then1',NULL,'then2NULL',3,'then3','def');
DECODE(CAST(NULL AS SIGNED),1,'then1',NULL,'then2NULL',3,'then3','def')
then2NULL
SELECT DECODE(1.0,1.0,'then1',2.0,'then2','def');
DECODE(1.0,1.0,'then1',2.0,'then2','def')
then1
SELECT DECODE(2.0,1.0,'then1',2.0,'then2','def');
DECODE(2.0,1.0,'then1',2.0,'then2','def')
then2
SELECT DECODE(3.0,1.0,'then1',NULL,'then2NULL',3.0,'then3','def');
DECODE(3.0,1.0,'then1',NULL,'then2NULL',3.0,'then3','def')
then3
SELECT DECODE(NULL,1.0,'then1',NULL,'then2NULL',3.0,'then3','def');
DECODE(NULL,1.0,'then1',NULL,'then2NULL',3.0,'then3','def')
then2NULL
SELECT DECODE(CAST(NULL AS DECIMAL),1.0,'then1',NULL,'then2NULL',3.0,'then3','def');
DECODE(CAST(NULL AS DECIMAL),1.0,'then1',NULL,'then2NULL',3.0,'then3','def')
then2NULL
SELECT DECODE(1e0,1e0,'then1',2e0,'then2','def');
DECODE(1e0,1e0,'then1',2e0,'then2','def')
then1
SELECT DECODE(2e0,1e0,'then1',2e0,'then2','def');
DECODE(2e0,1e0,'then1',2e0,'then2','def')
then2
SELECT DECODE(3e0,1e0,'then1',NULL,'then2NULL',3e0,'then3','def');
DECODE(3e0,1e0,'then1',NULL,'then2NULL',3e0,'then3','def')
then3
SELECT DECODE(NULL,1e0,'then1',NULL,'then2NULL',3e0,'then3','def');
DECODE(NULL,1e0,'then1',NULL,'then2NULL',3e0,'then3','def')
then2NULL
SELECT DECODE(CAST(NULL AS DOUBLE),1e0,'then1',NULL,'then2NULL',3e0,'then3','def');
DECODE(CAST(NULL AS DOUBLE),1e0,'then1',NULL,'then2NULL',3e0,'then3','def')
then2NULL
SELECT DECODE(NULL,NULL,1,2) FROM DUAL;
DECODE(NULL,NULL,1,2)
1
SELECT DECODE(NULL,10,10,NULL,1,2) FROM DUAL;
DECODE(NULL,10,10,NULL,1,2)
1
SELECT DECODE_ORACLE(NULL,NULL,1,2) FROM DUAL;
DECODE_ORACLE(NULL,NULL,1,2)
1
SELECT DECODE_ORACLE(NULL,10,10,NULL,1,2) FROM DUAL;
DECODE_ORACLE(NULL,10,10,NULL,1,2)
1
CREATE OR REPLACE TABLE t1 (a VARCHAR(10) DEFAULT NULL);
INSERT INTO t1 VALUES (NULL),(1);
SELECT a, DECODE(a,NULL,1,2) FROM t1;
a DECODE(a,NULL,1,2)
NULL 1
1 2
DROP TABLE t1;

View file

@ -19,3 +19,80 @@ EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def');
CREATE TABLE decode (decode int);
DROP TABLE decode;
--echo #
--echo # MDEV-13863 sql_mode=ORACLE: DECODE does not treat two NULLs as equivalent
--echo #
--error ER_PARSE_ERROR
SELECT DECODE(10);
--error ER_PARSE_ERROR
SELECT DECODE(10,10);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT DECODE_ORACLE(10);
--error ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT
SELECT DECODE_ORACLE(10,10);
EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11');
EXPLAIN EXTENDED SELECT DECODE(12,10,'x10',11,'x11','def');
EXPLAIN EXTENDED SELECT DECODE_ORACLE(12,10,'x10',11,'x11');
EXPLAIN EXTENDED SELECT DECODE_ORACLE(12,10,'x10',11,'x11','def');
CREATE TABLE t1 (a INT);
CREATE VIEW v1 AS
SELECT
DECODE(a,1,'x1',NULL,'xNULL') AS d1,
DECODE(a,1,'x1',NULL,'xNULL','xELSE') AS d2,
DECODE_ORACLE(a,1,'x1',NULL,'xNULL') AS d3,
DECODE_ORACLE(a,1,'x1',NULL,'xNULL','xELSE') AS d4
FROM t1;
SHOW CREATE VIEW v1;
DROP VIEW v1;
DROP TABLE t1;
SELECT DECODE(TIME'10:20:31','10:20:31','then1','10:20:32','then2','def');
SELECT DECODE(TIME'10:20:32','10:20:31','then1','10:20:32','then2','def');
SELECT DECODE(TIME'10:20:33','10:20:31','then1',NULL,'then2NULL','10:20:33','then3','def');
SELECT DECODE(NULL,TIME'10:20:31','then1',NULL,'then2NULL','10:20:33','then3','def');
SELECT DECODE(TIMESTAMP'2001-01-01 10:20:31','2001-01-01 10:20:31','then1','2001-01-01 10:20:32','then2','def');
SELECT DECODE(TIMESTAMP'2001-01-01 10:20:32','2001-01-01 10:20:31','then1','2001-01-01 10:20:32','then2','def');
SELECT DECODE(TIMESTAMP'2001-01-01 10:20:33','2001-01-01 10:20:31','then1',NULL,'then2NULL','2001-01-01 10:20:33','then3','def');
SELECT DECODE(NULL,TIMESTAMP'2001-01-01 10:20:31','then1',NULL,'then2NULL','2001-01-01 10:20:33','then3','def');
SELECT DECODE('w1','w1','then1','w2','then2','def');
SELECT DECODE('w2','w1','then1','w2','then2','def');
SELECT DECODE('w3','w1','then1',NULL,'then2NULL','w3','then3','def');
SELECT DECODE(NULL,'w1','then1',NULL,'then2NULL','w3','then3','def');
SELECT DECODE(1,1,'then1',2,'then2','def');
SELECT DECODE(2,1,'then1',2,'then2','def');
SELECT DECODE(3,1,'then1',NULL,'then2NULL',3,'then3','def');
SELECT DECODE(NULL,1,'then1',NULL,'then2NULL',3,'then3','def');
SELECT DECODE(CAST(NULL AS SIGNED),1,'then1',NULL,'then2NULL',3,'then3','def');
SELECT DECODE(1.0,1.0,'then1',2.0,'then2','def');
SELECT DECODE(2.0,1.0,'then1',2.0,'then2','def');
SELECT DECODE(3.0,1.0,'then1',NULL,'then2NULL',3.0,'then3','def');
SELECT DECODE(NULL,1.0,'then1',NULL,'then2NULL',3.0,'then3','def');
SELECT DECODE(CAST(NULL AS DECIMAL),1.0,'then1',NULL,'then2NULL',3.0,'then3','def');
SELECT DECODE(1e0,1e0,'then1',2e0,'then2','def');
SELECT DECODE(2e0,1e0,'then1',2e0,'then2','def');
SELECT DECODE(3e0,1e0,'then1',NULL,'then2NULL',3e0,'then3','def');
SELECT DECODE(NULL,1e0,'then1',NULL,'then2NULL',3e0,'then3','def');
SELECT DECODE(CAST(NULL AS DOUBLE),1e0,'then1',NULL,'then2NULL',3e0,'then3','def');
SELECT DECODE(NULL,NULL,1,2) FROM DUAL;
SELECT DECODE(NULL,10,10,NULL,1,2) FROM DUAL;
SELECT DECODE_ORACLE(NULL,NULL,1,2) FROM DUAL;
SELECT DECODE_ORACLE(NULL,10,10,NULL,1,2) FROM DUAL;
CREATE OR REPLACE TABLE t1 (a VARCHAR(10) DEFAULT NULL);
INSERT INTO t1 VALUES (NULL),(1);
SELECT a, DECODE(a,NULL,1,2) FROM t1;
DROP TABLE t1;

View file

@ -30,6 +30,7 @@ select * from information_schema.system_variables
'rand_seed2',
'system_time_zone',
'version_comment',
'version_source_revision',
'version_compile_machine', 'version_compile_os',
'version_malloc_library', 'version_ssl_library', 'version'
)
@ -53,6 +54,7 @@ select VARIABLE_NAME, VARIABLE_SCOPE, VARIABLE_TYPE, VARIABLE_COMMENT,
'rand_seed2',
'system_time_zone',
'version_comment',
'version_source_revision',
'version_compile_machine', 'version_compile_os',
'version_malloc_library', 'version_ssl_library', 'version'
)

View file

@ -19,6 +19,7 @@ variable_name not in (
'rand_seed2',
'system_time_zone',
'version_comment',
'version_source_revision',
'version_compile_machine', 'version_compile_os',
'version_malloc_library', 'version_ssl_library', 'version'
)
@ -4407,6 +4408,7 @@ where variable_name in (
'rand_seed2',
'system_time_zone',
'version_comment',
'version_source_revision',
'version_compile_machine', 'version_compile_os',
'version_malloc_library', 'version_ssl_library', 'version'
)
@ -4561,6 +4563,16 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME VERSION_SOURCE_REVISION
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT Source control revision id for MariaDB source code
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME VERSION_SSL_LIBRARY
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR

View file

@ -19,6 +19,7 @@ variable_name not in (
'rand_seed2',
'system_time_zone',
'version_comment',
'version_source_revision',
'version_compile_machine', 'version_compile_os',
'version_malloc_library', 'version_ssl_library', 'version'
)
@ -5303,6 +5304,7 @@ where variable_name in (
'rand_seed2',
'system_time_zone',
'version_comment',
'version_source_revision',
'version_compile_machine', 'version_compile_os',
'version_malloc_library', 'version_ssl_library', 'version'
)
@ -5457,6 +5459,16 @@ NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME VERSION_SOURCE_REVISION
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR
VARIABLE_COMMENT Source control revision id for MariaDB source code
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST NULL
READ_ONLY YES
COMMAND_LINE_ARGUMENT NULL
VARIABLE_NAME VERSION_SSL_LIBRARY
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE VARCHAR

View file

@ -330,3 +330,31 @@ PREPARE stmt FROM "SELECT
EXECUTE stmt;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
--echo #
--echo # MDEV-13864 Change Item_func_case to store the predicant in args[0]
--echo #
SET NAMES latin1;
CREATE TABLE t1 (a VARCHAR(10) CHARACTER SET latin1);
INSERT INTO t1 VALUES ('a'),('b'),('c');
# should propagate the predicant and the WHEN arguments (they are in comparison and use ANY_SUBST)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE a WHEN 'a' THEN 'a' ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN a THEN 'a' ELSE 'a' END='a';
# should not propagate the THEN and the ELSE arguments (they are not in comparison and use IDENTITY_SUBST)
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a';
ALTER TABLE t1 MODIFY a VARBINARY(10);
# with VARBINARY it should propagate all arguments
# as IDENTITY_SUBST for VARBINARY allows substitution
# of even those arguments that are not in comparison
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE a WHEN 'a' THEN 'a' ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN a THEN 'a' ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN a ELSE 'a' END='a';
EXPLAIN EXTENDED SELECT * FROM t1 WHERE a='a' AND CASE 'a' WHEN 'a' THEN 'a' ELSE a END='a';
DROP TABLE t1;

View file

@ -56,8 +56,23 @@ struct st_value
C_MODE_END
class Value: public st_value
{
public:
bool is_null() const { return m_type == DYN_COL_NULL; }
bool is_longlong() const
{
return m_type == DYN_COL_UINT || m_type == DYN_COL_INT;
}
bool is_double() const { return m_type == DYN_COL_DOUBLE; }
bool is_temporal() const { return m_type == DYN_COL_DATETIME; }
bool is_string() const { return m_type == DYN_COL_STRING; }
bool is_decimal() const { return m_type == DYN_COL_DECIMAL; }
};
template<size_t buffer_size>
class ValueBuffer: public st_value
class ValueBuffer: public Value
{
char buffer[buffer_size];
void reset_buffer()

View file

@ -2814,27 +2814,6 @@ Item_func_nullif::is_null()
}
Item_func_case::Item_func_case(THD *thd, List<Item> &list,
Item *first_expr_arg, Item *else_expr_arg):
Item_func_case_expression(thd),
Predicant_to_list_comparator(thd, list.elements/*QQ*/),
first_expr_num(-1), else_expr_num(-1),
m_found_types(0)
{
ncases= list.elements;
if (first_expr_arg)
{
first_expr_num= list.elements;
list.push_back(first_expr_arg, thd->mem_root);
}
if (else_expr_arg)
{
else_expr_num= list.elements;
list.push_back(else_expr_arg, thd->mem_root);
}
set_arguments(thd, list);
}
/**
Find and return matching items for CASE or ELSE item if all compares
are failed or NULL if ELSE item isn't defined.
@ -2856,27 +2835,37 @@ Item_func_case::Item_func_case(THD *thd, List<Item> &list,
failed
*/
Item *Item_func_case::find_item(String *str)
Item *Item_func_case_searched::find_item()
{
if (first_expr_num == -1)
uint count= when_count();
for (uint i= 0 ; i < count ; i++)
{
for (uint i=0 ; i < ncases ; i+=2)
{
// No expression between CASE and the first WHEN
if (args[i]->val_bool())
return args[i+1];
continue;
}
if (args[2 * i]->val_bool())
return args[2 * i + 1];
}
else
{
/* Compare every WHEN argument with it and return the first match */
uint idx;
if (!Predicant_to_list_comparator::cmp(this, &idx, NULL))
return args[idx + 1];
}
// No, WHEN clauses all missed, return ELSE expression
return else_expr_num != -1 ? args[else_expr_num] : 0;
Item **pos= Item_func_case_searched::else_expr_addr();
return pos ? pos[0] : 0;
}
Item *Item_func_case_simple::find_item()
{
/* Compare every WHEN argument with it and return the first match */
uint idx;
if (!Predicant_to_list_comparator::cmp(this, &idx, NULL))
return args[idx + 1];
Item **pos= Item_func_case_simple::else_expr_addr();
return pos ? pos[0] : 0;
}
Item *Item_func_decode_oracle::find_item()
{
uint idx;
if (!Predicant_to_list_comparator::cmp_nulls_equal(this, &idx))
return args[idx + 1];
Item **pos= Item_func_decode_oracle::else_expr_addr();
return pos ? pos[0] : 0;
}
@ -2884,7 +2873,7 @@ String *Item_func_case::str_op(String *str)
{
DBUG_ASSERT(fixed == 1);
String *res;
Item *item=find_item(str);
Item *item= find_item();
if (!item)
{
@ -2901,9 +2890,7 @@ String *Item_func_case::str_op(String *str)
longlong Item_func_case::int_op()
{
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String dummy_str(buff,sizeof(buff),default_charset());
Item *item=find_item(&dummy_str);
Item *item= find_item();
longlong res;
if (!item)
@ -2919,9 +2906,7 @@ longlong Item_func_case::int_op()
double Item_func_case::real_op()
{
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String dummy_str(buff,sizeof(buff),default_charset());
Item *item=find_item(&dummy_str);
Item *item= find_item();
double res;
if (!item)
@ -2938,9 +2923,7 @@ double Item_func_case::real_op()
my_decimal *Item_func_case::decimal_op(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String dummy_str(buff, sizeof(buff), default_charset());
Item *item= find_item(&dummy_str);
Item *item= find_item();
my_decimal *res;
if (!item)
@ -2958,9 +2941,7 @@ my_decimal *Item_func_case::decimal_op(my_decimal *decimal_value)
bool Item_func_case::date_op(MYSQL_TIME *ltime, uint fuzzydate)
{
DBUG_ASSERT(fixed == 1);
char buff[MAX_FIELD_WIDTH];
String dummy_str(buff, sizeof(buff), default_charset());
Item *item= find_item(&dummy_str);
Item *item= find_item();
if (!item)
return (null_value= true);
return (null_value= item->get_date_with_conversion(ltime, fuzzydate));
@ -2975,10 +2956,15 @@ bool Item_func_case::fix_fields(THD *thd, Item **ref)
*/
uchar buff[MAX_FIELD_WIDTH*2+sizeof(String)*2+sizeof(String*)*2+sizeof(double)*2+sizeof(longlong)*2];
if (!(arg_buffer= (Item**) thd->alloc(sizeof(Item*)*(ncases+1))))
if (!(arg_buffer= (Item**) thd->alloc(sizeof(Item*)*(arg_count))))
return TRUE;
bool res= Item_func::fix_fields(thd, ref);
Item **pos= else_expr_addr();
if (!pos || pos[0]->maybe_null)
maybe_null= 1;
/*
Call check_stack_overrun after fix_fields to be sure that stack variable
is not optimized away
@ -3011,15 +2997,20 @@ static void change_item_tree_if_needed(THD *thd,
}
bool Item_func_case::prepare_predicant_and_values(THD *thd, uint *found_types)
bool Item_func_case_simple::prepare_predicant_and_values(THD *thd,
uint *found_types,
bool nulls_equal)
{
bool have_null= false;
uint type_cnt;
Type_handler_hybrid_field_type tmp;
add_predicant(this, (uint) first_expr_num);
for (uint i= 0 ; i < ncases / 2; i++)
uint ncases= when_count();
add_predicant(this, 0);
for (uint i= 0 ; i < ncases; i++)
{
if (add_value_skip_null("case..when", this, i * 2, &have_null))
if (nulls_equal ?
add_value("case..when", this, i * 2 + 1) :
add_value_skip_null("case..when", this, i * 2 + 1, &have_null))
return true;
}
all_values_added(&tmp, &type_cnt, &m_found_types);
@ -3030,131 +3021,163 @@ bool Item_func_case::prepare_predicant_and_values(THD *thd, uint *found_types)
}
void Item_func_case::fix_length_and_dec()
void Item_func_case_searched::fix_length_and_dec()
{
Item **agg= arg_buffer;
uint nagg;
THD *thd= current_thd;
m_found_types= 0;
if (else_expr_num == -1 || args[else_expr_num]->maybe_null)
maybe_null= 1;
/*
Aggregate all THEN and ELSE expression types
and collations when string result
*/
for (nagg= 0 ; nagg < ncases/2 ; nagg++)
agg[nagg]= args[nagg*2+1];
if (else_expr_num != -1)
agg[nagg++]= args[else_expr_num];
if (aggregate_for_result(func_name(), agg, nagg, true))
return;
if (fix_attributes(agg, nagg))
return;
/*
Copy all modified THEN and ELSE items back to args[] array.
Some of the items might have been changed to Item_func_conv_charset.
*/
for (nagg= 0 ; nagg < ncases / 2 ; nagg++)
change_item_tree_if_needed(thd, &args[nagg * 2 + 1], agg[nagg]);
if (else_expr_num != -1)
change_item_tree_if_needed(thd, &args[else_expr_num], agg[nagg++]);
/*
Aggregate first expression and all WHEN expression types
and collations when string comparison
*/
if (first_expr_num != -1)
{
if (prepare_predicant_and_values(thd, &m_found_types))
{
/*
If Predicant_to_list_comparator() fails to prepare components,
it must put an error into the diagnostics area. This is needed
to make fix_fields() catches such errors.
*/
DBUG_ASSERT(thd->is_error());
return;
}
agg[0]= args[first_expr_num];
/*
As the first expression and WHEN expressions
are intermixed in args[] array THEN and ELSE items,
extract the first expression and all WHEN expressions into
a temporary array, to process them easier.
*/
for (nagg= 0; nagg < ncases/2 ; nagg++)
agg[nagg+1]= args[nagg*2];
nagg++;
if (!(m_found_types= collect_cmp_types(agg, nagg)))
return;
if (m_found_types & (1U << STRING_RESULT))
{
/*
If we'll do string comparison, we also need to aggregate
character set and collation for first/WHEN items and
install converters for some of them to cmp_collation when necessary.
This is done because cmp_item compatators cannot compare
strings in two different character sets.
Some examples when we install converters:
1. Converter installed for the first expression:
CASE latin1_item WHEN utf16_item THEN ... END
is replaced to:
CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END
2. Converter installed for the left WHEN item:
CASE utf16_item WHEN latin1_item THEN ... END
is replaced to:
CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END
*/
if (agg_arg_charsets_for_comparison(cmp_collation, agg, nagg))
return;
/*
Now copy first expression and all WHEN expressions back to args[]
arrray, because some of the items might have been changed to converters
(e.g. Item_func_conv_charset, or Item_string for constants).
*/
change_item_tree_if_needed(thd, &args[first_expr_num], agg[0]);
for (nagg= 0; nagg < ncases / 2; nagg++)
change_item_tree_if_needed(thd, &args[nagg * 2], agg[nagg + 1]);
}
if (make_unique_cmp_items(thd, cmp_collation.collation))
return;
}
Item **else_ptr= Item_func_case_searched::else_expr_addr();
aggregate_then_and_else_arguments(thd, &args[1], when_count(), else_ptr);
}
Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
void Item_func_case_simple::fix_length_and_dec()
{
const Type_handler *first_expr_cmp_handler;
if (first_expr_num == -1)
THD *thd= current_thd;
Item **else_ptr= Item_func_case_simple::else_expr_addr();
if (!aggregate_then_and_else_arguments(thd, &args[2], when_count(), else_ptr))
aggregate_switch_and_when_arguments(thd, false);
}
void Item_func_decode_oracle::fix_length_and_dec()
{
THD *thd= current_thd;
Item **else_ptr= Item_func_decode_oracle::else_expr_addr();
if (!aggregate_then_and_else_arguments(thd, &args[2], when_count(), else_ptr))
aggregate_switch_and_when_arguments(thd, true);
}
/*
Aggregate all THEN and ELSE expression types
and collations when string result
@param THD - current thd
@param them_expr - the pointer to the leftmost THEN argument in args[]
@param count - the number or THEN..ELSE pairs
@param else_epxr - the pointer to the ELSE arguments in args[]
(or NULL is there is not ELSE)
*/
bool Item_func_case::aggregate_then_and_else_arguments(THD *thd,
Item **then_expr,
uint count,
Item **else_expr)
{
Item **agg= arg_buffer;
uint nagg;
for (nagg= 0 ; nagg < count ; nagg++)
agg[nagg]= then_expr[nagg * 2];
if (else_expr)
agg[nagg++]= *else_expr;
if (aggregate_for_result(func_name(), agg, nagg, true))
return true;
if (fix_attributes(agg, nagg))
return true;
/*
Copy all modified THEN and ELSE items back to then_expr[] array.
Some of the items might have been changed to Item_func_conv_charset.
*/
for (nagg= 0 ; nagg < count ; nagg++)
change_item_tree_if_needed(thd, &then_expr[nagg * 2], agg[nagg]);
if (else_expr)
change_item_tree_if_needed(thd, else_expr, agg[nagg++]);
return false;
}
/*
Aggregate the predicant expression and all WHEN expression types
and collations when string comparison
*/
bool Item_func_case_simple::aggregate_switch_and_when_arguments(THD *thd,
bool nulls_eq)
{
Item **agg= arg_buffer;
uint nagg;
uint ncases= when_count();
m_found_types= 0;
if (prepare_predicant_and_values(thd, &m_found_types, nulls_eq))
{
// None of the arguments are in a comparison context
Item_args::propagate_equal_fields(thd, Context_identity(), cond);
return this;
/*
If Predicant_to_list_comparator() fails to prepare components,
it must put an error into the diagnostics area. This is needed
to make fix_fields() catches such errors.
*/
DBUG_ASSERT(thd->is_error());
return true;
}
first_expr_cmp_handler= args[first_expr_num]->type_handler_for_comparison();
/*
As the predicant expression and WHEN expressions
are intermixed in args[] array THEN and ELSE items,
extract the first expression and all WHEN expressions into
a temporary array, to process them easier.
*/
agg[0]= args[0]; // The predicant
for (nagg= 0; nagg < ncases ; nagg++)
agg[nagg+1]= args[nagg * 2 + 1];
nagg++;
if (!(m_found_types= collect_cmp_types(agg, nagg)))
return true;
if (m_found_types & (1U << STRING_RESULT))
{
/*
If we'll do string comparison, we also need to aggregate
character set and collation for first/WHEN items and
install converters for some of them to cmp_collation when necessary.
This is done because cmp_item compatators cannot compare
strings in two different character sets.
Some examples when we install converters:
1. Converter installed for the first expression:
CASE latin1_item WHEN utf16_item THEN ... END
is replaced to:
CASE CONVERT(latin1_item USING utf16) WHEN utf16_item THEN ... END
2. Converter installed for the left WHEN item:
CASE utf16_item WHEN latin1_item THEN ... END
is replaced to:
CASE utf16_item WHEN CONVERT(latin1_item USING utf16) THEN ... END
*/
if (agg_arg_charsets_for_comparison(cmp_collation, agg, nagg))
return true;
/*
Now copy first expression and all WHEN expressions back to args[]
arrray, because some of the items might have been changed to converters
(e.g. Item_func_conv_charset, or Item_string for constants).
*/
change_item_tree_if_needed(thd, &args[0], agg[0]);
for (nagg= 0; nagg < ncases; nagg++)
change_item_tree_if_needed(thd, &args[nagg * 2 + 1], agg[nagg + 1]);
}
if (make_unique_cmp_items(thd, cmp_collation.collation))
return true;
return false;
}
Item* Item_func_case_simple::propagate_equal_fields(THD *thd,
const Context &ctx,
COND_EQUAL *cond)
{
const Type_handler *first_expr_cmp_handler;
first_expr_cmp_handler= args[0]->type_handler_for_comparison();
for (uint i= 0; i < arg_count; i++)
{
/*
@ -3164,7 +3187,7 @@ Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_
CASE ... THEN y1 ... THEN y2 ... THEN y3 ... ELSE y4 END
*/
Item *new_item= 0;
if ((int) i == first_expr_num) // Then CASE (the switch) argument
if (i == 0) // Then CASE (the switch) argument
{
/*
Cannot replace the CASE (the switch) argument if
@ -3201,7 +3224,7 @@ Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_
cmp_collation.collation),
cond);
}
else if ((i % 2) == 0) // WHEN arguments
else if ((i % 2) == 1 && i != arg_count - 1) // WHEN arguments
{
/*
These arguments are in comparison.
@ -3230,33 +3253,51 @@ Item* Item_func_case::propagate_equal_fields(THD *thd, const Context &ctx, COND_
}
/**
@todo
Fix this so that it prints the whole CASE expression
*/
void Item_func_case::print(String *str, enum_query_type query_type)
void Item_func_case::print_when_then_arguments(String *str,
enum_query_type query_type,
Item **items, uint count)
{
str->append(STRING_WITH_LEN("case "));
if (first_expr_num != -1)
{
args[first_expr_num]->print_parenthesised(str, query_type, precedence());
str->append(' ');
}
for (uint i=0 ; i < ncases ; i+=2)
for (uint i=0 ; i < count ; i++)
{
str->append(STRING_WITH_LEN("when "));
args[i]->print_parenthesised(str, query_type, precedence());
items[i * 2]->print_parenthesised(str, query_type, precedence());
str->append(STRING_WITH_LEN(" then "));
args[i+1]->print_parenthesised(str, query_type, precedence());
str->append(' ');
}
if (else_expr_num != -1)
{
str->append(STRING_WITH_LEN("else "));
args[else_expr_num]->print_parenthesised(str, query_type, precedence());
items[i * 2 + 1]->print_parenthesised(str, query_type, precedence());
str->append(' ');
}
}
void Item_func_case::print_else_argument(String *str,
enum_query_type query_type,
Item *item)
{
str->append(STRING_WITH_LEN("else "));
item->print_parenthesised(str, query_type, precedence());
str->append(' ');
}
void Item_func_case_searched::print(String *str, enum_query_type query_type)
{
Item **pos;
str->append(STRING_WITH_LEN("case "));
print_when_then_arguments(str, query_type, &args[0], when_count());
if ((pos= Item_func_case_searched::else_expr_addr()))
print_else_argument(str, query_type, pos[0]);
str->append(STRING_WITH_LEN("end"));
}
void Item_func_case_simple::print(String *str, enum_query_type query_type)
{
Item **pos;
str->append(STRING_WITH_LEN("case "));
args[0]->print_parenthesised(str, query_type, precedence());
str->append(' ');
print_when_then_arguments(str, query_type, &args[1], when_count());
if ((pos= Item_func_case_simple::else_expr_addr()))
print_else_argument(str, query_type, pos[0]);
str->append(STRING_WITH_LEN("end"));
}
@ -3944,6 +3985,14 @@ void cmp_item_decimal::store_value(Item *item)
}
int cmp_item_decimal::cmp_not_null(const Value *val)
{
DBUG_ASSERT(!val->is_null());
DBUG_ASSERT(val->is_decimal());
return my_decimal_cmp(&value, &val->m_decimal);
}
int cmp_item_decimal::cmp(Item *arg)
{
my_decimal tmp_buf, *tmp= arg->val_decimal(&tmp_buf);
@ -3975,6 +4024,14 @@ void cmp_item_temporal::store_value_internal(Item *item,
}
int cmp_item_datetime::cmp_not_null(const Value *val)
{
DBUG_ASSERT(!val->is_null());
DBUG_ASSERT(val->is_temporal());
return value != pack_time(&val->value.m_time);
}
int cmp_item_datetime::cmp(Item *arg)
{
const bool rc= value != arg->val_datetime_packed();
@ -3982,6 +4039,14 @@ int cmp_item_datetime::cmp(Item *arg)
}
int cmp_item_time::cmp_not_null(const Value *val)
{
DBUG_ASSERT(!val->is_null());
DBUG_ASSERT(val->is_temporal());
return value != pack_time(&val->value.m_time);
}
int cmp_item_time::cmp(Item *arg)
{
const bool rc= value != arg->val_time_packed();

View file

@ -1475,6 +1475,7 @@ public:
"stored argument's value <> item's value"
*/
virtual int cmp(Item *item)= 0;
virtual int cmp_not_null(const Value *value)= 0;
// for optimized IN with row
virtual int compare(cmp_item *item)= 0;
virtual cmp_item *make_same()= 0;
@ -1519,6 +1520,12 @@ public:
value_res= item->val_str(&value);
m_null_value= item->null_value;
}
int cmp_not_null(const Value *val)
{
DBUG_ASSERT(!val->is_null());
DBUG_ASSERT(val->is_string());
return sortcmp(value_res, &val->m_string, cmp_charset) != 0;
}
int cmp(Item *arg)
{
char buff[STRING_BUFFER_USUAL_SIZE];
@ -1555,6 +1562,12 @@ public:
value= item->val_int();
m_null_value= item->null_value;
}
int cmp_not_null(const Value *val)
{
DBUG_ASSERT(!val->is_null());
DBUG_ASSERT(val->is_longlong());
return value != val->value.m_longlong;
}
int cmp(Item *arg)
{
const bool rc= value != arg->val_int();
@ -1599,6 +1612,7 @@ public:
{
store_value_internal(item, MYSQL_TYPE_DATETIME);
}
int cmp_not_null(const Value *val);
int cmp(Item *arg);
cmp_item *make_same();
};
@ -1614,6 +1628,7 @@ public:
{
store_value_internal(item, MYSQL_TYPE_TIME);
}
int cmp_not_null(const Value *val);
int cmp(Item *arg);
cmp_item *make_same();
};
@ -1628,6 +1643,12 @@ public:
value= item->val_real();
m_null_value= item->null_value;
}
int cmp_not_null(const Value *val)
{
DBUG_ASSERT(!val->is_null());
DBUG_ASSERT(val->is_double());
return value != val->value.m_double;
}
int cmp(Item *arg)
{
const bool rc= value != arg->val_real();
@ -1649,6 +1670,7 @@ public:
cmp_item_decimal() {} /* Remove gcc warning */
void store_value(Item *item);
int cmp(Item *arg);
int cmp_not_null(const Value *val);
int compare(cmp_item *c);
cmp_item *make_same();
};
@ -1671,6 +1693,11 @@ public:
value_res= item->val_str(&value);
m_null_value= item->null_value;
}
int cmp_not_null(const Value *val)
{
DBUG_ASSERT(false);
return TRUE;
}
int cmp(Item *item)
{
// Should never be called
@ -1837,7 +1864,24 @@ class Predicant_to_list_comparator
return UNKNOWN;
return in_item->cmp(args->arguments()[m_comparators[i].m_arg_index]);
}
int cmp_args_nulls_equal(Item_args *args, uint i)
{
Predicant_to_value_comparator *cmp=
&m_comparators[m_comparators[i].m_handler_index];
cmp_item *in_item= cmp->m_cmp_item;
DBUG_ASSERT(in_item);
Item *predicant= args->arguments()[m_predicant_index];
Item *arg= args->arguments()[m_comparators[i].m_arg_index];
ValueBuffer<MAX_FIELD_WIDTH> val;
if (m_comparators[i].m_handler_index == i)
in_item->store_value(predicant);
m_comparators[i].m_handler->Item_save_in_value(arg, &val);
if (predicant->null_value && val.is_null())
return FALSE; // Two nulls are equal
if (predicant->null_value || val.is_null())
return UNKNOWN;
return in_item->cmp_not_null(&val);
}
/**
Predicant_to_value_comparator - a comparator for one pair (pred,valueN).
See comments above.
@ -2009,78 +2053,172 @@ public:
}
return true; // Not found
}
/*
Same as above, but treats two NULLs as equal, e.g. as in DECODE_ORACLE().
*/
bool cmp_nulls_equal(Item_args *args, uint *idx)
{
for (uint i= 0 ; i < m_comparator_count ; i++)
{
DBUG_ASSERT(m_comparators[i].m_handler != NULL);
if (cmp_args_nulls_equal(args, i) == FALSE)
{
*idx= m_comparators[i].m_arg_index;
return false; // Found a matching value
}
}
return true; // Not found
}
};
/*
The class Item_func_case is the CASE ... WHEN ... THEN ... END function
implementation.
When there is no expression between CASE and the first WHEN
(the CASE expression) then this function simple checks all WHEN expressions
one after another. When some WHEN expression evaluated to TRUE then the
value of the corresponding THEN expression is returned.
When the CASE expression is specified then it is compared to each WHEN
expression individually. When an equal WHEN expression is found
corresponding THEN expression is returned.
In order to do correct comparisons several comparators are used. One for
each result type. Different result types that are used in particular
CASE ... END expression are collected in the fix_length_and_dec() member
function and only comparators for there result types are used.
*/
class Item_func_case :public Item_func_case_expression,
public Predicant_to_list_comparator
class Item_func_case :public Item_func_case_expression
{
int first_expr_num, else_expr_num;
protected:
String tmp_value;
uint ncases;
DTCollation cmp_collation;
Item **arg_buffer;
uint m_found_types;
bool prepare_predicant_and_values(THD *thd, uint *found_types);
bool aggregate_then_and_else_arguments(THD *thd,
Item **items, uint count,
Item **else_expr);
virtual Item **else_expr_addr() const= 0;
virtual Item *find_item()= 0;
void print_when_then_arguments(String *str, enum_query_type query_type,
Item **items, uint count);
void print_else_argument(String *str, enum_query_type query_type, Item *item);
public:
Item_func_case(THD *thd, List<Item> &list, Item *first_expr_arg,
Item *else_expr_arg);
Item_func_case(THD *thd, List<Item> &list)
:Item_func_case_expression(thd, list)
{ }
double real_op();
longlong int_op();
String *str_op(String *);
my_decimal *decimal_op(my_decimal *);
bool date_op(MYSQL_TIME *ltime, uint fuzzydate);
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
table_map not_null_tables() const { return 0; }
const char *func_name() const { return "case"; }
enum precedence precedence() const { return BETWEEN_PRECEDENCE; }
virtual void print(String *str, enum_query_type query_type);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() const { return cmp_collation.collation; }
void cleanup()
{
DBUG_ENTER("Item_func_case::cleanup");
Item_func::cleanup();
Predicant_to_list_comparator::cleanup();
DBUG_VOID_RETURN;
}
Item* propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond);
bool need_parentheses_in_default() { return true; }
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_case>(thd, mem_root, this); }
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_func_case *clone= (Item_func_case *) Item_func::build_clone(thd, mem_root);
if (clone)
{
clone->arg_buffer= 0;
if (clone->Predicant_to_list_comparator::init_clone(thd, ncases))
return NULL;
}
return clone;
}
};
/*
CASE WHEN cond THEN res [WHEN cond THEN res...] [ELSE res] END
Searched CASE checks all WHEN expressions one after another.
When some WHEN expression evaluated to TRUE then the
value of the corresponding THEN expression is returned.
*/
class Item_func_case_searched: public Item_func_case
{
uint when_count() const { return arg_count / 2; }
bool with_else() const { return arg_count % 2; }
Item **else_expr_addr() const { return with_else() ? &args[arg_count - 1] : 0; }
public:
Item_func_case_searched(THD *thd, List<Item> &list)
:Item_func_case(thd, list)
{
DBUG_ASSERT(arg_count >= 2);
}
void print(String *str, enum_query_type query_type);
void fix_length_and_dec();
Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond)
{
// None of the arguments are in a comparison context
Item_args::propagate_equal_fields(thd, Context_identity(), cond);
return this;
}
Item *find_item();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_case_searched>(thd, mem_root, this); }
};
/*
CASE pred WHEN value THEN res [WHEN value THEN res...] [ELSE res] END
When the predicant expression is specified then it is compared to each WHEN
expression individually. When an equal WHEN expression is found
the corresponding THEN expression is returned.
In order to do correct comparisons several comparators are used. One for
each result type. Different result types that are used in particular
CASE ... END expression are collected in the fix_length_and_dec() member
function and only comparators for there result types are used.
*/
class Item_func_case_simple: public Item_func_case,
public Predicant_to_list_comparator
{
protected:
uint m_found_types;
uint when_count() const { return (arg_count - 1) / 2; }
bool with_else() const { return arg_count % 2 == 0; }
Item **else_expr_addr() const { return with_else() ? &args[arg_count - 1] : 0; }
bool aggregate_switch_and_when_arguments(THD *thd, bool nulls_equal);
bool prepare_predicant_and_values(THD *thd, uint *found_types,
bool nulls_equal);
public:
Item_func_case_simple(THD *thd, List<Item> &list)
:Item_func_case(thd, list),
Predicant_to_list_comparator(thd, arg_count),
m_found_types(0)
{
DBUG_ASSERT(arg_count >= 3);
}
void cleanup()
{
DBUG_ENTER("Item_func_case_simple::cleanup");
Item_func::cleanup();
Predicant_to_list_comparator::cleanup();
DBUG_VOID_RETURN;
}
void print(String *str, enum_query_type query_type);
void fix_length_and_dec();
Item *propagate_equal_fields(THD *thd, const Context &ctx, COND_EQUAL *cond);
Item *find_item();
Item *build_clone(THD *thd, MEM_ROOT *mem_root)
{
Item_func_case_simple *clone= (Item_func_case_simple *)
Item_func_case::build_clone(thd, mem_root);
uint ncases= when_count();
if (clone && clone->Predicant_to_list_comparator::init_clone(thd, ncases))
return NULL;
return clone;
}
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_case_simple>(thd, mem_root, this); }
};
class Item_func_decode_oracle: public Item_func_case_simple
{
public:
Item_func_decode_oracle(THD *thd, List<Item> &list)
:Item_func_case_simple(thd, list)
{ }
const char *func_name() const { return "decode_oracle"; }
void print(String *str, enum_query_type query_type)
{ Item_func::print(str, query_type); }
void fix_length_and_dec();
Item *find_item();
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
{ return get_item_copy<Item_func_decode_oracle>(thd, mem_root, this); }
};
/*
The Item_func_in class implements
in_expr IN (<in value list>)
@ -2260,6 +2398,11 @@ public:
bool alloc_comparators(THD *thd, uint n);
bool prepare_comparators(THD *, Item **args, uint arg_count);
int cmp(Item *arg);
int cmp_not_null(const Value *val)
{
DBUG_ASSERT(false);
return TRUE;
}
int compare(cmp_item *arg);
cmp_item *make_same();
void store_value_by_template(THD *thd, cmp_item *tmpl, Item *);

View file

@ -623,6 +623,19 @@ protected:
};
class Create_func_decode_oracle : public Create_native_func
{
public:
virtual Item *create_native(THD *thd, LEX_CSTRING *name, List<Item> *item_list);
static Create_func_decode_oracle s_singleton;
protected:
Create_func_decode_oracle() {}
virtual ~Create_func_decode_oracle() {}
};
class Create_func_concat_ws : public Create_native_func
{
public:
@ -3894,6 +3907,21 @@ Create_func_decode_histogram::create_2_arg(THD *thd, Item *arg1, Item *arg2)
return new (thd->mem_root) Item_func_decode_histogram(thd, arg1, arg2);
}
Create_func_decode_oracle Create_func_decode_oracle::s_singleton;
Item*
Create_func_decode_oracle::create_native(THD *thd, LEX_CSTRING *name,
List<Item> *item_list)
{
uint arg_count= item_list ? item_list->elements : 0;
if (arg_count < 3)
{
my_error(ER_WRONG_PARAMCOUNT_TO_NATIVE_FCT, MYF(0), name->str);
return NULL;
}
return new (thd->mem_root) Item_func_decode_oracle(thd, *item_list);
}
Create_func_concat_ws Create_func_concat_ws::s_singleton;
Item*
@ -6851,6 +6879,7 @@ static Native_func_registry func_array[] =
{ { C_STRING_WITH_LEN("DAYOFYEAR") }, BUILDER(Create_func_dayofyear)},
{ { C_STRING_WITH_LEN("DEGREES") }, BUILDER(Create_func_degrees)},
{ { C_STRING_WITH_LEN("DECODE_HISTOGRAM") }, BUILDER(Create_func_decode_histogram)},
{ { C_STRING_WITH_LEN("DECODE_ORACLE") }, BUILDER(Create_func_decode_oracle)},
{ { C_STRING_WITH_LEN("DES_DECRYPT") }, BUILDER(Create_func_des_decrypt)},
{ { C_STRING_WITH_LEN("DES_ENCRYPT") }, BUILDER(Create_func_des_encrypt)},
{ { C_STRING_WITH_LEN("DIMENSION") }, GEOM_BUILDER(Create_func_dimension)},

View file

@ -1718,7 +1718,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item>
literal text_literal insert_ident order_ident temporal_literal
simple_ident expr opt_expr opt_else sum_expr in_sum_expr
simple_ident expr sum_expr in_sum_expr
variable variable_aux bool_pri
predicate bit_expr parenthesized_expr
table_wild simple_expr column_default_non_parenthesized_expr udf_expr
@ -1746,7 +1746,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
NUM_literal
%type <item_list>
expr_list opt_udf_expr_list udf_expr_list when_list
expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else
ident_list ident_list_arg opt_expr_list
%type <sp_cursor_stmt>
@ -9431,10 +9431,15 @@ column_default_non_parenthesized_expr:
if (!($$= $5.create_typecast_item(thd, $3, Lex->charset)))
MYSQL_YYABORT;
}
| CASE_SYM opt_expr when_list opt_else END
| CASE_SYM when_list_opt_else END
{
$$= new (thd->mem_root) Item_func_case(thd, *$3, $2, $4);
if ($$ == NULL)
if (!($$= new(thd->mem_root) Item_func_case_searched(thd, *$2)))
MYSQL_YYABORT;
}
| CASE_SYM expr when_list_opt_else END
{
$3->push_front($2, thd->mem_root);
if (!($$= new (thd->mem_root) Item_func_case_simple(thd, *$3)))
MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr ',' cast_type ')'
@ -10856,16 +10861,6 @@ ident_list:
}
;
opt_expr:
/* empty */ { $$= NULL; }
| expr { $$= $1; }
;
opt_else:
/* empty */ { $$= NULL; }
| ELSE expr { $$= $2; }
;
when_list:
WHEN_SYM expr THEN_SYM expr
{
@ -10883,6 +10878,15 @@ when_list:
}
;
when_list_opt_else:
when_list
| when_list ELSE expr
{
$1->push_back($3, thd->mem_root);
$$= $1;
}
;
/* Equivalent to <table reference> in the SQL:2003 standard. */
/* Warning - may return NULL in case of incomplete SELECT */
table_ref:

View file

@ -1134,7 +1134,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%type <item>
literal text_literal insert_ident order_ident temporal_literal
simple_ident expr opt_expr opt_else sum_expr in_sum_expr
simple_ident expr sum_expr in_sum_expr
variable variable_aux bool_pri
predicate bit_expr parenthesized_expr
table_wild simple_expr column_default_non_parenthesized_expr udf_expr
@ -1164,7 +1164,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
NUM_literal
%type <item_list>
expr_list opt_udf_expr_list udf_expr_list when_list
expr_list opt_udf_expr_list udf_expr_list when_list when_list_opt_else
ident_list ident_list_arg opt_expr_list
decode_when_list
@ -9441,10 +9441,15 @@ column_default_non_parenthesized_expr:
if (!($$= $5.create_typecast_item(thd, $3, Lex->charset)))
MYSQL_YYABORT;
}
| CASE_SYM opt_expr when_list opt_else END
| CASE_SYM when_list_opt_else END
{
$$= new (thd->mem_root) Item_func_case(thd, *$3, $2, $4);
if ($$ == NULL)
if (!($$= new(thd->mem_root) Item_func_case_searched(thd, *$2)))
MYSQL_YYABORT;
}
| CASE_SYM expr when_list_opt_else END
{
$3->push_front($2, thd->mem_root);
if (!($$= new (thd->mem_root) Item_func_case_simple(thd, *$3)))
MYSQL_YYABORT;
}
| CONVERT_SYM '(' expr ',' cast_type ')'
@ -9460,32 +9465,8 @@ column_default_non_parenthesized_expr:
}
| DECODE_SYM '(' expr ',' decode_when_list ')'
{
if (($5->elements % 2) == 0)
{
// No default expression
$$= new (thd->mem_root) Item_func_case(thd, *$5, $3, NULL);
}
else
{
/*
There is a default expression at the end of the list $5.
Create a new list without the default expression.
*/
List<Item> tmp;
List_iterator_fast<Item> it(*$5);
for (uint i= 0; i < $5->elements - 1; i++) // copy all but last
{
Item *item= it++;
tmp.push_back(item);
}
/*
Now the new list "tmp" contains only WHEN-THEN pairs,
The default expression is pointed by the iterator "it"
and will be returned by the next call for it++ below.
*/
$$= new (thd->mem_root) Item_func_case(thd, tmp, $3, it++);
}
if ($$ == NULL)
$5->push_front($3, thd->mem_root);
if (!($$= new (thd->mem_root) Item_func_decode_oracle(thd, *$5)))
MYSQL_YYABORT;
}
| DEFAULT '(' simple_ident ')'
@ -10908,16 +10889,6 @@ ident_list:
}
;
opt_expr:
/* empty */ { $$= NULL; }
| expr { $$= $1; }
;
opt_else:
/* empty */ { $$= NULL; }
| ELSE expr { $$= $2; }
;
when_list:
WHEN_SYM expr THEN_SYM expr
{
@ -10936,6 +10907,15 @@ when_list:
;
when_list_opt_else:
when_list
| when_list ELSE expr
{
$1->push_back($3, thd->mem_root);
$$= $1;
}
;
decode_when_list:
expr ',' expr
{

View file

@ -3552,6 +3552,14 @@ static Sys_var_charptr Sys_version_compile_os(
CMD_LINE_HELP_ONLY,
IN_SYSTEM_CHARSET, DEFAULT(SYSTEM_TYPE));
#include <source_revision.h>
static char *server_version_source_revision;
static Sys_var_charptr Sys_version_source_revision(
"version_source_revision", "Source control revision id for MariaDB source code",
READ_ONLY GLOBAL_VAR(server_version_source_revision),
CMD_LINE_HELP_ONLY,
IN_SYSTEM_CHARSET, DEFAULT(SOURCE_REVISION));
static char *guess_malloc_library()
{
if (strcmp(MALLOC_LIBRARY, "system") == 0)