MDEV-34319: DECLARE TYPE .. TABLE OF .. INDEX BY
in stored routines This patch adds support for associative arrays in stored procedures for sql_mode=ORACLE. The syntax follows Oracle's PL/SQL syntax for associative arrays - TYPE assoc_array_t IS TABLE OF VARCHAR2(100) INDEX BY INTEGER; or TYPE assoc_array_t IS TABLE OF record_t INDEX BY VARCHAR2(100); where record_t is a record type. The following functions were added for associative arrays: - COUNT - Retrieve the number of elements within the arra - EXISTS - Check whether given key exists in the array - FIRST - Retrieve the first key in the array - LAST - Retrieve the last key in the array - PRIOR - Retrieve the key before the given key - NEXT - Retrieve the key after the given key - DELETE - Remove the element with the given key or remove all elements if no key is given The arrays/elements can be initialized with the following methods: - Constructor i.e. array:= assoc_array_t('key1'=>1, 'key2'=>2, 'key3'=>3) - Assignment i.e. array(key):= record_t(1, 2) - SELECT INTO i.e. SELECT x INTO array(key) TODOs: - Nested tables are not supported yet. i.e. TYPE assoc_array_t IS TABLE OF other_assoc_array_t INDEX BY INTEGER; - Associative arrays comparisons are not supported yet.
This commit is contained in:
parent
9e13cf0862
commit
5930c48c41
@ -136,6 +136,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc libmysqld.c lib_sql.cc
|
|||||||
../sql/sql_schema.cc
|
../sql/sql_schema.cc
|
||||||
../sql/lex_charset.cc ../sql/charset_collations.cc
|
../sql/lex_charset.cc ../sql/charset_collations.cc
|
||||||
../sql/sql_type.cc ../sql/sql_type.h
|
../sql/sql_type.cc ../sql/sql_type.h
|
||||||
|
../sql/sql_type_composite.cc ../sql/item_composite.cc
|
||||||
../sql/sql_type_row.cc
|
../sql/sql_type_row.cc
|
||||||
../sql/sql_mode.cc
|
../sql/sql_mode.cc
|
||||||
../sql/sql_type_string.cc
|
../sql/sql_type_string.cc
|
||||||
|
18
plugin/type_assoc_array/CMakeLists.txt
Normal file
18
plugin/type_assoc_array/CMakeLists.txt
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# Copyright (c) 2023-2025, MariaDB corporation
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; version 2 of the License.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
|
||||||
|
MYSQL_ADD_PLUGIN(type_assoc_array sql_type_assoc_array.cc
|
||||||
|
RECOMPILE_FOR_EMBEDDED
|
||||||
|
MANDATORY COMPONENT Assoc_array)
|
@ -0,0 +1,89 @@
|
|||||||
|
SET sql_mode=oracle;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(64));
|
||||||
|
#
|
||||||
|
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||||
|
#
|
||||||
|
DECLARE
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
person_by_nickname table_of_peson_t;
|
||||||
|
BEGIN
|
||||||
|
person_by_nickname('Monty') := person_t('Michael', 'Widenius');
|
||||||
|
INSERT INTO t1 VALUES (person_by_nickname.FIRST);
|
||||||
|
INSERT INTO t1 VALUES (person_by_nickname('Monty').first_name);
|
||||||
|
DELETE FROM t1 WHERE person_by_nickname.EXISTS('Monty');
|
||||||
|
INSERT INTO t1 VALUES ('1');
|
||||||
|
DELETE FROM t1 WHERE person_by_nickname IS NOT NULL;
|
||||||
|
person_by_nickname:= NULL;
|
||||||
|
INSERT INTO t1 VALUES ('1');
|
||||||
|
DELETE FROM t1 WHERE person_by_nickname IS NULL;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DECLARE
|
||||||
|
TYPE first_names_t IS TABLE OF VARCHAR2(64) INDEX BY VARCHAR2(20);
|
||||||
|
first_names first_names_t;
|
||||||
|
nick VARCHAR(64):= 'Monty';
|
||||||
|
BEGIN
|
||||||
|
first_names('Monty') := 'Michael';
|
||||||
|
INSERT INTO t1 VALUES (first_names('Monty'));
|
||||||
|
INSERT INTO t1 VALUES (first_names(nick));
|
||||||
|
INSERT INTO t1 VALUES (first_names(TRIM(nick || ' ')));
|
||||||
|
INSERT INTO t1 VALUES (first_names(TRIM(first_names.LAST)));
|
||||||
|
SELECT * FROM t1;
|
||||||
|
CREATE TABLE t2 AS SELECT first_names('Monty');
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
a
|
||||||
|
Michael
|
||||||
|
Michael
|
||||||
|
Michael
|
||||||
|
Michael
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
include/show_binlog_events.inc
|
||||||
|
Log_name Pos Event_type Server_id End_log_pos Info
|
||||||
|
master-bin.000001 # Gtid # # GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a VARCHAR(64))
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (NAME_CONST('person_by_nickname.FIRST',_utf8mb4'Monty' COLLATE 'utf8mb4_uca1400_ai_ci'))
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (NAME_CONST('person_by_nickname(\'Monty\').first_name',_utf8mb4'Michael' COLLATE 'utf8mb4_uca1400_ai_ci'))
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; DELETE FROM t1 WHERE NAME_CONST('person_by_nickname.EXISTS(\'Monty\')',1)
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ('1')
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; DELETE FROM t1 WHERE NAME_CONST('person_by_nickname',1) IS NOT NULL
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES ('1')
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; DELETE FROM t1 WHERE NAME_CONST('person_by_nickname',NULL) IS NULL
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (NAME_CONST('first_names(\'Monty\')',_utf8mb4'Michael' COLLATE 'utf8mb4_uca1400_ai_ci'))
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (NAME_CONST('first_names(nick)',_utf8mb4'Michael' COLLATE 'utf8mb4_uca1400_ai_ci'))
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (NAME_CONST('first_names(TRIM(nick || \' \'))',_utf8mb4'Michael' COLLATE 'utf8mb4_uca1400_ai_ci'))
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # BEGIN GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (NAME_CONST('first_names(TRIM(first_names.LAST))',_utf8mb4'Michael' COLLATE 'utf8mb4_uca1400_ai_ci'))
|
||||||
|
master-bin.000001 # Query # # COMMIT
|
||||||
|
master-bin.000001 # Gtid # # GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; CREATE TABLE t2 AS SELECT NAME_CONST('first_names(\'Monty\')',_utf8mb4'Michael' COLLATE 'utf8mb4_uca1400_ai_ci')
|
||||||
|
master-bin.000001 # Gtid # # GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; DROP TABLE "t1" /* generated by server */
|
||||||
|
master-bin.000001 # Gtid # # GTID #-#-#
|
||||||
|
master-bin.000001 # Query # # use `test`; DROP TABLE "t2" /* generated by server */
|
@ -0,0 +1,67 @@
|
|||||||
|
--source include/not_embedded.inc
|
||||||
|
--source include/have_binlog_format_statement.inc
|
||||||
|
|
||||||
|
SET sql_mode=oracle;
|
||||||
|
|
||||||
|
--disable_query_log
|
||||||
|
reset master; # get rid of previous tests binlog
|
||||||
|
--enable_query_log
|
||||||
|
|
||||||
|
CREATE TABLE t1 (a VARCHAR(64));
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||||
|
--echo #
|
||||||
|
DELIMITER $$;
|
||||||
|
DECLARE
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
person_by_nickname table_of_peson_t;
|
||||||
|
BEGIN
|
||||||
|
person_by_nickname('Monty') := person_t('Michael', 'Widenius');
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (person_by_nickname.FIRST);
|
||||||
|
INSERT INTO t1 VALUES (person_by_nickname('Monty').first_name);
|
||||||
|
|
||||||
|
DELETE FROM t1 WHERE person_by_nickname.EXISTS('Monty');
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES ('1');
|
||||||
|
DELETE FROM t1 WHERE person_by_nickname IS NOT NULL;
|
||||||
|
|
||||||
|
person_by_nickname:= NULL;
|
||||||
|
INSERT INTO t1 VALUES ('1');
|
||||||
|
DELETE FROM t1 WHERE person_by_nickname IS NULL;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
DECLARE
|
||||||
|
TYPE first_names_t IS TABLE OF VARCHAR2(64) INDEX BY VARCHAR2(20);
|
||||||
|
first_names first_names_t;
|
||||||
|
nick VARCHAR(64):= 'Monty';
|
||||||
|
BEGIN
|
||||||
|
first_names('Monty') := 'Michael';
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (first_names('Monty'));
|
||||||
|
INSERT INTO t1 VALUES (first_names(nick));
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (first_names(TRIM(nick || ' ')));
|
||||||
|
INSERT INTO t1 VALUES (first_names(TRIM(first_names.LAST)));
|
||||||
|
|
||||||
|
SELECT * FROM t1;
|
||||||
|
|
||||||
|
CREATE TABLE t2 AS SELECT first_names('Monty');
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
|
||||||
|
--let $binlog_file = LAST
|
||||||
|
source include/show_binlog_events.inc;
|
@ -0,0 +1,75 @@
|
|||||||
|
include/master-slave.inc
|
||||||
|
[connection master]
|
||||||
|
#
|
||||||
|
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||||
|
#
|
||||||
|
SET sql_mode=oracle;
|
||||||
|
SET NAMES utf8;
|
||||||
|
connection master;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(64));
|
||||||
|
DECLARE
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
person_by_nickname table_of_peson_t;
|
||||||
|
BEGIN
|
||||||
|
person_by_nickname('Monty') := person_t('Michael', 'Widenius');
|
||||||
|
INSERT INTO t1 VALUES (person_by_nickname.FIRST);
|
||||||
|
INSERT INTO t1 VALUES (person_by_nickname('Monty').first_name);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
connection slave;
|
||||||
|
SELECT a FROM t1;
|
||||||
|
a
|
||||||
|
Monty
|
||||||
|
Michael
|
||||||
|
connection master;
|
||||||
|
DECLARE
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
person_by_nickname table_of_peson_t;
|
||||||
|
BEGIN
|
||||||
|
person_by_nickname('Monty') := person_t('Michael', 'Widenius');
|
||||||
|
DELETE FROM t1 WHERE person_by_nickname IS NOT NULL;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
connection slave;
|
||||||
|
SELECT a FROM t1;
|
||||||
|
a
|
||||||
|
connection master;
|
||||||
|
DECLARE
|
||||||
|
TYPE first_names_t IS TABLE OF VARCHAR2(64) INDEX BY VARCHAR2(20);
|
||||||
|
first_names first_names_t;
|
||||||
|
`first names` first_names_t;
|
||||||
|
nick VARCHAR(64):= 'Monty';
|
||||||
|
BEGIN
|
||||||
|
first_names('Monty') := 'Michael';
|
||||||
|
`first names`('Alex') := 'Alexander';
|
||||||
|
INSERT INTO t1 VALUES (first_names('Monty'));
|
||||||
|
INSERT INTO t1 VALUES (first_names(nick));
|
||||||
|
INSERT INTO t1 VALUES (first_names(TRIM(nick || ' ')));
|
||||||
|
INSERT INTO t1 VALUES (first_names(TRIM(first_names.LAST)));
|
||||||
|
INSERT INTO t1 VALUES (`first names`(`first names`.LAST));
|
||||||
|
CREATE TABLE t2 AS SELECT first_names('Monty');
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
connection slave;
|
||||||
|
SELECT a FROM t1;
|
||||||
|
a
|
||||||
|
Michael
|
||||||
|
Michael
|
||||||
|
Michael
|
||||||
|
Michael
|
||||||
|
Alexander
|
||||||
|
connection master;
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
connection slave;
|
||||||
|
include/rpl_end.inc
|
@ -0,0 +1,87 @@
|
|||||||
|
--source include/master-slave.inc
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
SET sql_mode=oracle;
|
||||||
|
SET NAMES utf8;
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
CREATE TABLE t1 (a VARCHAR(64));
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
DECLARE
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
person_by_nickname table_of_peson_t;
|
||||||
|
BEGIN
|
||||||
|
person_by_nickname('Monty') := person_t('Michael', 'Widenius');
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (person_by_nickname.FIRST);
|
||||||
|
INSERT INTO t1 VALUES (person_by_nickname('Monty').first_name);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
|
||||||
|
sync_slave_with_master;
|
||||||
|
SELECT a FROM t1;
|
||||||
|
connection master;
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
DECLARE
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
person_by_nickname table_of_peson_t;
|
||||||
|
BEGIN
|
||||||
|
person_by_nickname('Monty') := person_t('Michael', 'Widenius');
|
||||||
|
|
||||||
|
DELETE FROM t1 WHERE person_by_nickname IS NOT NULL;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
|
||||||
|
sync_slave_with_master;
|
||||||
|
SELECT a FROM t1;
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
DELIMITER $$;
|
||||||
|
DECLARE
|
||||||
|
TYPE first_names_t IS TABLE OF VARCHAR2(64) INDEX BY VARCHAR2(20);
|
||||||
|
first_names first_names_t;
|
||||||
|
`first names` first_names_t;
|
||||||
|
nick VARCHAR(64):= 'Monty';
|
||||||
|
BEGIN
|
||||||
|
first_names('Monty') := 'Michael';
|
||||||
|
`first names`('Alex') := 'Alexander';
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (first_names('Monty'));
|
||||||
|
INSERT INTO t1 VALUES (first_names(nick));
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (first_names(TRIM(nick || ' ')));
|
||||||
|
INSERT INTO t1 VALUES (first_names(TRIM(first_names.LAST)));
|
||||||
|
|
||||||
|
INSERT INTO t1 VALUES (`first names`(`first names`.LAST));
|
||||||
|
|
||||||
|
CREATE TABLE t2 AS SELECT first_names('Monty');
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
|
||||||
|
sync_slave_with_master;
|
||||||
|
SELECT a FROM t1;
|
||||||
|
|
||||||
|
connection master;
|
||||||
|
DROP TABLE t1;
|
||||||
|
DROP TABLE t2;
|
||||||
|
sync_slave_with_master;
|
||||||
|
|
||||||
|
--source include/rpl_end.inc
|
@ -0,0 +1,107 @@
|
|||||||
|
SET sql_mode=ORACLE;
|
||||||
|
#
|
||||||
|
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||||
|
#
|
||||||
|
CREATE PROCEDURE p1() AS
|
||||||
|
TYPE marks_t IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
|
||||||
|
marks marks_t:= marks_t('1' => 43, '2' => 99);
|
||||||
|
BEGIN
|
||||||
|
marks(1) := 62;
|
||||||
|
SELECT marks(1);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
Pos Instruction
|
||||||
|
0 set marks@0 marks_t('1'=>43,'2'=>99)
|
||||||
|
1 set marks@0[1] 62
|
||||||
|
2 stmt 0 "SELECT marks(1)"
|
||||||
|
3 destruct associative_array marks@0
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
CREATE PROCEDURE p1() AS
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
person_by_nickname table_of_peson_t:=
|
||||||
|
table_of_peson_t(
|
||||||
|
'Monty' => person_t('Michael', 'Widenius'),
|
||||||
|
'Serg' => person_t('Sergei ', 'Golubchik')) ;
|
||||||
|
nick VARCHAR(20);
|
||||||
|
BEGIN
|
||||||
|
nick:= person_by_nickname.FIRST;
|
||||||
|
person_by_nickname(nick).first_name:= 'Michael';
|
||||||
|
person_by_nickname(nick):= person_t('Michael', 'Widenius');
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
Pos Instruction
|
||||||
|
0 set person_by_nickname@0 table_of_peson_t('Monty'=>('Michael','Widenius'),'Serg'=>('Sergei ','Golubchik'))
|
||||||
|
1 set nick@1 NULL
|
||||||
|
2 set nick@1 person_by_nickname@0.first()
|
||||||
|
3 set person_by_nickname@0[nick@1].first_name 'Michael'
|
||||||
|
4 set person_by_nickname@0[nick@1] ('Michael','Widenius')
|
||||||
|
5 destruct associative_array person_by_nickname@0
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
#
|
||||||
|
# Make sure assoc array variables generate sp_instr_destruct_variable
|
||||||
|
#
|
||||||
|
CREATE PROCEDURE p1 AS
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
TYPE table_of_int_t IS TABLE OF INT INDEX BY INT;
|
||||||
|
BEGIN
|
||||||
|
SELECT '>block#0' AS comment;
|
||||||
|
DECLARE
|
||||||
|
assoc_of_record_0 table_of_peson_t;
|
||||||
|
assoc_of_scalar_0 table_of_int_t;
|
||||||
|
BEGIN
|
||||||
|
SELECT '>block#1' AS comment;
|
||||||
|
DECLARE
|
||||||
|
assoc_of_record_1 table_of_peson_t;
|
||||||
|
assoc_of_scalar_1 table_of_int_t;
|
||||||
|
BEGIN
|
||||||
|
SELECT '>block#2' AS comment;
|
||||||
|
DECLARE
|
||||||
|
assoc_of_record_2 table_of_peson_t;
|
||||||
|
assoc_of_scalar_2 table_of_int_t;
|
||||||
|
BEGIN
|
||||||
|
SELECT '>block#3' AS comment;
|
||||||
|
NULL;
|
||||||
|
SELECT '<block#3' AS comment;
|
||||||
|
END;
|
||||||
|
SELECT '<block#2' AS comment;
|
||||||
|
END;
|
||||||
|
SELECT '<block#1' AS comment;
|
||||||
|
END;
|
||||||
|
SELECT '<block#0' AS comment;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
Pos Instruction
|
||||||
|
0 stmt 0 "SELECT '>block#0' AS comment"
|
||||||
|
1 set assoc_of_record_0@0 NULL
|
||||||
|
2 set assoc_of_scalar_0@1 NULL
|
||||||
|
3 stmt 0 "SELECT '>block#1' AS comment"
|
||||||
|
4 set assoc_of_record_1@2 NULL
|
||||||
|
5 set assoc_of_scalar_1@3 NULL
|
||||||
|
6 stmt 0 "SELECT '>block#2' AS comment"
|
||||||
|
7 set assoc_of_record_2@4 NULL
|
||||||
|
8 set assoc_of_scalar_2@5 NULL
|
||||||
|
9 stmt 0 "SELECT '>block#3' AS comment"
|
||||||
|
10 stmt 0 "SELECT '<block#3' AS comment"
|
||||||
|
11 destruct associative_array assoc_of_scalar_2@5
|
||||||
|
12 destruct associative_array assoc_of_record_2@4
|
||||||
|
13 stmt 0 "SELECT '<block#2' AS comment"
|
||||||
|
14 destruct associative_array assoc_of_scalar_1@3
|
||||||
|
15 destruct associative_array assoc_of_record_1@2
|
||||||
|
16 stmt 0 "SELECT '<block#1' AS comment"
|
||||||
|
17 destruct associative_array assoc_of_scalar_0@1
|
||||||
|
18 destruct associative_array assoc_of_record_0@0
|
||||||
|
19 stmt 0 "SELECT '<block#0' AS comment"
|
||||||
|
DROP PROCEDURE p1;
|
@ -0,0 +1,89 @@
|
|||||||
|
-- source include/have_debug.inc
|
||||||
|
|
||||||
|
SET sql_mode=ORACLE;
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1() AS
|
||||||
|
TYPE marks_t IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
|
||||||
|
marks marks_t:= marks_t('1' => 43, '2' => 99);
|
||||||
|
BEGIN
|
||||||
|
marks(1) := 62;
|
||||||
|
SELECT marks(1);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1() AS
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
person_by_nickname table_of_peson_t:=
|
||||||
|
table_of_peson_t(
|
||||||
|
'Monty' => person_t('Michael', 'Widenius'),
|
||||||
|
'Serg' => person_t('Sergei ', 'Golubchik')) ;
|
||||||
|
nick VARCHAR(20);
|
||||||
|
BEGIN
|
||||||
|
nick:= person_by_nickname.FIRST;
|
||||||
|
person_by_nickname(nick).first_name:= 'Michael';
|
||||||
|
|
||||||
|
person_by_nickname(nick):= person_t('Michael', 'Widenius');
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
DROP PROCEDURE p1;
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Make sure assoc array variables generate sp_instr_destruct_variable
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
DELIMITER $$;
|
||||||
|
CREATE PROCEDURE p1 AS
|
||||||
|
TYPE person_t IS RECORD
|
||||||
|
(
|
||||||
|
first_name VARCHAR(64),
|
||||||
|
last_name VARCHAR(64)
|
||||||
|
);
|
||||||
|
TYPE table_of_peson_t IS TABLE OF person_t INDEX BY VARCHAR2(20);
|
||||||
|
TYPE table_of_int_t IS TABLE OF INT INDEX BY INT;
|
||||||
|
BEGIN
|
||||||
|
SELECT '>block#0' AS comment;
|
||||||
|
DECLARE
|
||||||
|
assoc_of_record_0 table_of_peson_t;
|
||||||
|
assoc_of_scalar_0 table_of_int_t;
|
||||||
|
BEGIN
|
||||||
|
SELECT '>block#1' AS comment;
|
||||||
|
DECLARE
|
||||||
|
assoc_of_record_1 table_of_peson_t;
|
||||||
|
assoc_of_scalar_1 table_of_int_t;
|
||||||
|
BEGIN
|
||||||
|
SELECT '>block#2' AS comment;
|
||||||
|
DECLARE
|
||||||
|
assoc_of_record_2 table_of_peson_t;
|
||||||
|
assoc_of_scalar_2 table_of_int_t;
|
||||||
|
BEGIN
|
||||||
|
SELECT '>block#3' AS comment;
|
||||||
|
NULL;
|
||||||
|
SELECT '<block#3' AS comment;
|
||||||
|
END;
|
||||||
|
SELECT '<block#2' AS comment;
|
||||||
|
END;
|
||||||
|
SELECT '<block#1' AS comment;
|
||||||
|
END;
|
||||||
|
SELECT '<block#0' AS comment;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
SHOW PROCEDURE CODE p1;
|
||||||
|
DROP PROCEDURE p1;
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
|||||||
|
package My::Suite::Type_assoc_array;
|
||||||
|
|
||||||
|
@ISA = qw(My::Suite);
|
||||||
|
|
||||||
|
sub is_default { 1 }
|
||||||
|
|
||||||
|
bless { };
|
2573
plugin/type_assoc_array/sql_type_assoc_array.cc
Normal file
2573
plugin/type_assoc_array/sql_type_assoc_array.cc
Normal file
File diff suppressed because it is too large
Load Diff
462
plugin/type_assoc_array/sql_type_assoc_array.h
Normal file
462
plugin/type_assoc_array/sql_type_assoc_array.h
Normal file
@ -0,0 +1,462 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2025, Rakuten Securities
|
||||||
|
Copyright (c) 2025, MariaDB plc
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; version 2 of
|
||||||
|
the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
*/
|
||||||
|
#ifndef SQL_TYPE_ASSOC_ARRAY_INCLUDED
|
||||||
|
#define SQL_TYPE_ASSOC_ARRAY_INCLUDED
|
||||||
|
|
||||||
|
#include "sql_type_composite.h"
|
||||||
|
#include "field_composite.h"
|
||||||
|
#include "item_composite.h"
|
||||||
|
#include "sp_type_def.h"
|
||||||
|
|
||||||
|
|
||||||
|
class Item_field_packable;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Special handler associative arrays
|
||||||
|
*/
|
||||||
|
class Type_handler_assoc_array: public Type_handler_composite
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static const Type_handler_assoc_array *singleton();
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool has_methods() const override { return true; }
|
||||||
|
bool has_functors() const override { return true; }
|
||||||
|
bool is_complex() const override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Have an assoc array variable generate an sp_instr_destruct_variable
|
||||||
|
instruction in the end of the DECLARE/BEGIN/END block declaring
|
||||||
|
the variable.
|
||||||
|
*/
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const Type_collection *type_collection() const override;
|
||||||
|
const Type_handler *type_handler_for_comparison() const override
|
||||||
|
{
|
||||||
|
return singleton();
|
||||||
|
}
|
||||||
|
bool Spvar_definition_with_complex_data_types(Spvar_definition *def)
|
||||||
|
const override;
|
||||||
|
bool Column_definition_set_attributes(THD *thd,
|
||||||
|
Column_definition *def,
|
||||||
|
const Lex_field_type_st &attr,
|
||||||
|
column_definition_type_t type)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Disallow wrong use of associative_array:
|
||||||
|
CREATE TABLE t1 (a ASSOCIATIVE_ARRAY);
|
||||||
|
CREATE FUNCTION .. RETURN ASSOCIATEIVE ARRAY ..;
|
||||||
|
*/
|
||||||
|
if (!def->get_attr_const_void_ptr(0))
|
||||||
|
{
|
||||||
|
my_error(ER_NOT_ALLOWED_IN_THIS_CONTEXT, MYF(0), name().ptr());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return Type_handler_composite::Column_definition_set_attributes(thd, def,
|
||||||
|
attr,
|
||||||
|
type);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sp_variable_declarations_finalize(THD *thd,
|
||||||
|
LEX *lex, int nvars,
|
||||||
|
const Column_definition &def)
|
||||||
|
const override;
|
||||||
|
|
||||||
|
Field *make_table_field_from_def(TABLE_SHARE *share,
|
||||||
|
MEM_ROOT *mem_root,
|
||||||
|
const LEX_CSTRING *name,
|
||||||
|
const Record_addr &addr,
|
||||||
|
const Bit_addr &bit,
|
||||||
|
const Column_definition_attributes *attr,
|
||||||
|
uint32 flags) const override;
|
||||||
|
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static bool lex_ident_col_eq(Lex_ident_column *a, Lex_ident_column *b)
|
||||||
|
{
|
||||||
|
return a->streq(*b);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sp_check_assoc_array_args(const sp_type_def &def, List<Item> &args) const
|
||||||
|
{
|
||||||
|
List<Lex_ident_column> names;
|
||||||
|
|
||||||
|
List_iterator<Item> it(args);
|
||||||
|
for (Item *item= it++; item; item= it++)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Make sure all value have keys:
|
||||||
|
assoc_array_type('key1'=>'val1', 'key2'=>'val2') -- correct
|
||||||
|
assoc_array_type('val1' , 'val2' ) -- wrong
|
||||||
|
*/
|
||||||
|
if (unlikely(!item->is_explicit_name()))
|
||||||
|
{
|
||||||
|
my_error(ER_NEED_NAMED_ASSOCIATION, MYF(0), def.get_name());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Make sure keys are unique in:
|
||||||
|
assoc_array_type('key1'=>'val1', 'key2'=>'val2')
|
||||||
|
*/
|
||||||
|
if (unlikely(names.add_unique(&item->name, lex_ident_col_eq)))
|
||||||
|
{
|
||||||
|
my_error(ER_DUP_UNKNOWN_IN_INDEX, MYF(0), item->name.str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*
|
||||||
|
SELECT 1 INTO spvar(arg);
|
||||||
|
SELECT 1 INTO spvar(arg).field_name;
|
||||||
|
*/
|
||||||
|
my_var *make_outvar_lvalue_functor(THD *thd, const Lex_ident_sys_st &name,
|
||||||
|
Item *arg,
|
||||||
|
const Lex_ident_sys &opt_field,
|
||||||
|
sp_head *sphead,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
bool validate_only) const override;
|
||||||
|
// assoc_array_var:= assoc_array_type('key1'=>'val1', 'key2'=>'val2')
|
||||||
|
Item *make_typedef_constructor_item(THD *thd, const sp_type_def &def,
|
||||||
|
List<Item> *args) const override;
|
||||||
|
|
||||||
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||||
|
Item_func_in *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String *print_item_value(THD *thd, Item *item, String *str) const override;
|
||||||
|
|
||||||
|
virtual Item_splocal *create_item_functor(THD *thd,
|
||||||
|
const Lex_ident_sys &varname,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
List<Item> *args,
|
||||||
|
const Lex_ident_sys &member,
|
||||||
|
const Lex_ident_cli_st &name_cli)
|
||||||
|
const override;
|
||||||
|
sp_instr *create_instr_set_assign_functor(THD *thd, LEX *lex,
|
||||||
|
const Qualified_ident &ident,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
List<Item> *params,
|
||||||
|
const Lex_ident_sys_st &field_name,
|
||||||
|
Item *item,
|
||||||
|
const LEX_CSTRING &expr_str)
|
||||||
|
const override;
|
||||||
|
virtual
|
||||||
|
Item *create_item_method(THD *thd,
|
||||||
|
const Lex_ident_sys &ca,
|
||||||
|
const Lex_ident_sys &cb,
|
||||||
|
List<Item> *args,
|
||||||
|
const Lex_ident_cli_st &query_fragment)
|
||||||
|
const override;
|
||||||
|
|
||||||
|
bool key_to_lex_cstring(THD *thd,
|
||||||
|
Item **key,
|
||||||
|
const LEX_CSTRING& name,
|
||||||
|
LEX_CSTRING& out_key) const override;
|
||||||
|
|
||||||
|
bool get_item_index(THD *thd,
|
||||||
|
const Item_field *item,
|
||||||
|
const LEX_CSTRING& name,
|
||||||
|
uint& idx) const override
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Item_field *get_item(THD *thd,
|
||||||
|
const Item_field *item,
|
||||||
|
const LEX_CSTRING& name) const override;
|
||||||
|
Item_field *get_or_create_item(THD *thd,
|
||||||
|
Item_field *item,
|
||||||
|
const LEX_CSTRING& name) const override;
|
||||||
|
|
||||||
|
void prepare_for_set(Item_field *item) const override;
|
||||||
|
bool finalize_for_set(Item_field *item) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Field_assoc_array final :public Field_composite
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
MEM_ROOT m_mem_root;
|
||||||
|
TREE m_tree;
|
||||||
|
|
||||||
|
TABLE *m_table;
|
||||||
|
TABLE_SHARE *m_table_share;
|
||||||
|
Row_definition_list *m_def;
|
||||||
|
|
||||||
|
Field *m_key_field;
|
||||||
|
Field *m_element_field;
|
||||||
|
Item_field_packable *m_item_pack;
|
||||||
|
Item *m_item;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Modified copy of the key definition
|
||||||
|
*/
|
||||||
|
Spvar_definition m_key_def;
|
||||||
|
public:
|
||||||
|
Field_assoc_array(uchar *ptr_arg,
|
||||||
|
const LEX_CSTRING *field_name_arg);
|
||||||
|
~Field_assoc_array();
|
||||||
|
|
||||||
|
void set_array_def(Row_definition_list *def)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(def);
|
||||||
|
DBUG_ASSERT(def->elements == 2);
|
||||||
|
m_def= def;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Row_definition_list *get_array_def() const
|
||||||
|
{
|
||||||
|
return m_def;
|
||||||
|
}
|
||||||
|
|
||||||
|
Item_field *make_item_field_spvar(THD *thd,
|
||||||
|
const Spvar_definition &def) override;
|
||||||
|
|
||||||
|
bool sp_prepare_and_store_item(THD *thd, Item **value) override;
|
||||||
|
|
||||||
|
uint rows() const override;
|
||||||
|
bool get_key(String *key, bool is_first) override;
|
||||||
|
bool get_next_key(const String *curr_key, String *next_key) override;
|
||||||
|
bool get_prior_key(const String *curr_key, String *prior_key) override;
|
||||||
|
Item_field *element_by_key(THD *thd, String *key) override;
|
||||||
|
Item_field *element_by_key(THD *thd, String *key) const override;
|
||||||
|
Item **element_addr_by_key(THD *thd, String *key) override;
|
||||||
|
bool delete_all_elements() override;
|
||||||
|
bool delete_element_by_key(String *key) override;
|
||||||
|
void expr_event_handler(THD *thd, expr_event_t event) override
|
||||||
|
{
|
||||||
|
if ((bool) (event & expr_event_t::DESTRUCT_ANY))
|
||||||
|
{
|
||||||
|
delete_all_elements();
|
||||||
|
set_null();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Item *get_element_item() const override { return m_item; }
|
||||||
|
Field *get_key_field() const { return m_key_field; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool copy_and_convert_key(const String *key, String &key_copy) const;
|
||||||
|
bool unpack_key(const Binary_string &key, String *key_dst) const;
|
||||||
|
bool create_fields(THD *thd);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Initialize the element base Field and Item_field for the
|
||||||
|
associative array.
|
||||||
|
*/
|
||||||
|
bool init_element_base(THD *thd);
|
||||||
|
|
||||||
|
bool create_element_buffer(THD *thd, Binary_string *buffer);
|
||||||
|
bool insert_element(String &&key, Binary_string &&element);
|
||||||
|
bool get_next_or_prior_key(const String *curr_key,
|
||||||
|
String *new_key,
|
||||||
|
bool is_next);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
Item_field for the associative array data type
|
||||||
|
*/
|
||||||
|
class Item_field_assoc_array: public Item_field, public Item_composite_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Item_field_assoc_array(THD *thd, Field *field)
|
||||||
|
:Item_field(thd, field)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Item *do_get_copy(THD *thd) const override
|
||||||
|
{ return get_item_copy<Item_field_assoc_array>(thd, this); }
|
||||||
|
|
||||||
|
const Type_handler *type_handler() const override
|
||||||
|
{ return Type_handler_assoc_array::singleton(); }
|
||||||
|
|
||||||
|
bool set_array_def(THD *thd, Row_definition_list *def);
|
||||||
|
|
||||||
|
uint rows() const override
|
||||||
|
{
|
||||||
|
return get_composite_field()->rows();
|
||||||
|
}
|
||||||
|
bool get_key(String *key, bool is_first) override
|
||||||
|
{
|
||||||
|
return get_composite_field()->get_key(key, is_first);
|
||||||
|
}
|
||||||
|
bool get_next_key(const String *curr_key, String *next_key) override
|
||||||
|
{
|
||||||
|
return get_composite_field()->get_next_key(curr_key, next_key);
|
||||||
|
}
|
||||||
|
Item *element_by_key(THD *thd, String *key) override
|
||||||
|
{
|
||||||
|
return ((const Field_composite *)get_composite_field())->
|
||||||
|
element_by_key(thd, key);
|
||||||
|
}
|
||||||
|
Item **element_addr_by_key(THD *thd, Item **ref, String *key) override
|
||||||
|
{
|
||||||
|
return get_composite_field()->element_addr_by_key(thd, key);
|
||||||
|
}
|
||||||
|
Field_composite *get_composite_field() const override
|
||||||
|
{
|
||||||
|
return dynamic_cast<Field_composite *>(field);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_assoc_array: public Item_composite
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Lex_ident_column m_name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Item_assoc_array(THD *thd, const Lex_ident_column &name)
|
||||||
|
:Item_composite(thd),
|
||||||
|
m_name(name)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
Item_assoc_array(THD *thd, const Lex_ident_column &name, List<Item> &list)
|
||||||
|
:Item_composite(thd, list),
|
||||||
|
m_name(name)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
const Type_handler *type_handler() const override
|
||||||
|
{
|
||||||
|
return Type_handler_assoc_array::singleton();
|
||||||
|
}
|
||||||
|
|
||||||
|
Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
|
||||||
|
const Tmp_field_param *param) override
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint rows() const override;
|
||||||
|
bool get_key(String *key, bool is_first) override;
|
||||||
|
bool get_next_key(const String *curr_key, String *next_key) override;
|
||||||
|
Item *element_by_key(THD *thd, String *key) override;
|
||||||
|
Item **element_addr_by_key(THD *thd, Item **addr_arg, String *key) override;
|
||||||
|
|
||||||
|
bool fix_fields(THD *thd, Item **ref) override;
|
||||||
|
void bring_value() override;
|
||||||
|
void print(String *str, enum_query_type query_type) override;
|
||||||
|
|
||||||
|
Item *do_get_copy(THD *thd) const override
|
||||||
|
{ return get_item_copy<Item_assoc_array>(thd, this); }
|
||||||
|
Item *do_build_clone(THD *thd) const override;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_splocal_assoc_array_base :public Item_composite_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Item *m_key;
|
||||||
|
|
||||||
|
public:
|
||||||
|
Item_splocal_assoc_array_base(Item *key);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_splocal_assoc_array_element :public Item_splocal,
|
||||||
|
public Item_splocal_assoc_array_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
bool set_value(THD *thd, sp_rcontext *ctx, Item **it) override;
|
||||||
|
public:
|
||||||
|
Item_splocal_assoc_array_element(THD *thd,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
const Lex_ident_sys &sp_var_name,
|
||||||
|
Item *key, const Type_handler *handler,
|
||||||
|
uint pos_in_q= 0, uint len_in_q= 0);
|
||||||
|
bool fix_fields(THD *thd, Item **) override;
|
||||||
|
Item *this_item() override;
|
||||||
|
const Item *this_item() const override;
|
||||||
|
Item **this_item_addr(THD *thd, Item **) override;
|
||||||
|
bool append_for_log(THD *thd, String *str) override;
|
||||||
|
void print(String *str, enum_query_type query_type) override;
|
||||||
|
|
||||||
|
Item *do_get_copy(THD *) const override { return nullptr; }
|
||||||
|
Item *do_build_clone(THD *thd) const override { return nullptr; }
|
||||||
|
|
||||||
|
Item_composite_base *get_composite_variable(sp_rcontext *ctx) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_splocal_assoc_array_element_field :
|
||||||
|
public Item_splocal_row_field_by_name,
|
||||||
|
public Item_splocal_assoc_array_base
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
Item_field *m_element_item;
|
||||||
|
public:
|
||||||
|
Item_splocal_assoc_array_element_field(THD *thd,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
const Lex_ident_sys &sp_var_name,
|
||||||
|
Item *key,
|
||||||
|
const Lex_ident_sys &sp_field_name,
|
||||||
|
const Type_handler *handler,
|
||||||
|
uint pos_in_q= 0, uint len_in_q= 0);
|
||||||
|
bool fix_fields(THD *thd, Item **) override;
|
||||||
|
Item *this_item() override;
|
||||||
|
const Item *this_item() const override;
|
||||||
|
Item **this_item_addr(THD *thd, Item **) override;
|
||||||
|
bool append_for_log(THD *thd, String *str) override;
|
||||||
|
void print(String *str, enum_query_type query_type) override;
|
||||||
|
|
||||||
|
Item_composite_base *get_composite_variable(sp_rcontext *ctx) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* SQL_TYPE_ASSOC_ARRAY_INCLUDED */
|
@ -0,0 +1,35 @@
|
|||||||
|
#
|
||||||
|
# MDEV-34319 DECLARE TYPE type_name IS RECORD (..) with scalar members in stored routines
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Demonstrate UDT field type for associative array element
|
||||||
|
#
|
||||||
|
SET sql_mode=ORACLE;
|
||||||
|
DECLARE
|
||||||
|
TYPE uuids_t IS TABLE OF UUID INDEX BY INTEGER;
|
||||||
|
uuids uuids_t;
|
||||||
|
BEGIN
|
||||||
|
uuids(1):= 'e7a69166-a557-4bbe-ab4d-d390114b51fa';
|
||||||
|
SELECT uuids(1);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
uuids(1)
|
||||||
|
e7a69166-a557-4bbe-ab4d-d390114b51fa
|
||||||
|
#
|
||||||
|
# Demonstrate UDT field type for associative array RECORD field
|
||||||
|
#
|
||||||
|
SET sql_mode=ORACLE;
|
||||||
|
DECLARE
|
||||||
|
TYPE rec_t IS RECORD (
|
||||||
|
a INT,
|
||||||
|
b UUID
|
||||||
|
);
|
||||||
|
TYPE uuids_t IS TABLE OF rec_t INDEX BY INTEGER;
|
||||||
|
uuids uuids_t;
|
||||||
|
BEGIN
|
||||||
|
uuids(1):= rec_t(1, 'e7a69166-a557-4bbe-ab4d-d390114b51fa');
|
||||||
|
SELECT uuids(1).a,uuids(1).b;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
uuids(1).a uuids(1).b
|
||||||
|
1 e7a69166-a557-4bbe-ab4d-d390114b51fa
|
@ -0,0 +1,38 @@
|
|||||||
|
--echo #
|
||||||
|
--echo # MDEV-34319 DECLARE TYPE type_name IS RECORD (..) with scalar members in stored routines
|
||||||
|
--echo #
|
||||||
|
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Demonstrate UDT field type for associative array element
|
||||||
|
--echo #
|
||||||
|
SET sql_mode=ORACLE;
|
||||||
|
DELIMITER $$;
|
||||||
|
DECLARE
|
||||||
|
TYPE uuids_t IS TABLE OF UUID INDEX BY INTEGER;
|
||||||
|
uuids uuids_t;
|
||||||
|
BEGIN
|
||||||
|
uuids(1):= 'e7a69166-a557-4bbe-ab4d-d390114b51fa';
|
||||||
|
SELECT uuids(1);
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
||||||
|
|
||||||
|
--echo #
|
||||||
|
--echo # Demonstrate UDT field type for associative array RECORD field
|
||||||
|
--echo #
|
||||||
|
SET sql_mode=ORACLE;
|
||||||
|
DELIMITER $$;
|
||||||
|
DECLARE
|
||||||
|
TYPE rec_t IS RECORD (
|
||||||
|
a INT,
|
||||||
|
b UUID
|
||||||
|
);
|
||||||
|
TYPE uuids_t IS TABLE OF rec_t INDEX BY INTEGER;
|
||||||
|
uuids uuids_t;
|
||||||
|
BEGIN
|
||||||
|
uuids(1):= rec_t(1, 'e7a69166-a557-4bbe-ab4d-d390114b51fa');
|
||||||
|
SELECT uuids(1).a,uuids(1).b;
|
||||||
|
END;
|
||||||
|
$$
|
||||||
|
DELIMITER ;$$
|
@ -196,6 +196,8 @@ SET (SQL_SOURCE
|
|||||||
opt_hints_parser.cc opt_hints_parser.h scan_char.h
|
opt_hints_parser.cc opt_hints_parser.h scan_char.h
|
||||||
opt_hints.cc opt_hints.h
|
opt_hints.cc opt_hints.h
|
||||||
sql_type_row.cc
|
sql_type_row.cc
|
||||||
|
sql_type_composite.cc sql_type_composite.h
|
||||||
|
item_composite.cc item_composite.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
|
${CMAKE_CURRENT_BINARY_DIR}/lex_hash.h
|
||||||
${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
|
${CMAKE_CURRENT_BINARY_DIR}/lex_token.h
|
||||||
${GEN_SOURCES}
|
${GEN_SOURCES}
|
||||||
|
18
sql/field.h
18
sql/field.h
@ -44,6 +44,7 @@ class Item_bool_func;
|
|||||||
class Item_equal;
|
class Item_equal;
|
||||||
class Virtual_tmp_table;
|
class Virtual_tmp_table;
|
||||||
class Qualified_column_ident;
|
class Qualified_column_ident;
|
||||||
|
class Qualified_ident;
|
||||||
class Table_ident;
|
class Table_ident;
|
||||||
class SEL_ARG;
|
class SEL_ARG;
|
||||||
class RANGE_OPT_PARAM;
|
class RANGE_OPT_PARAM;
|
||||||
@ -5722,6 +5723,7 @@ public:
|
|||||||
- variables with explicit data types: DECLARE a INT;
|
- variables with explicit data types: DECLARE a INT;
|
||||||
- variables with data type references: DECLARE a t1.a%TYPE;
|
- variables with data type references: DECLARE a t1.a%TYPE;
|
||||||
- ROW type variables
|
- ROW type variables
|
||||||
|
- Associative arrays
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
- Scalar variables have m_field_definitions==NULL.
|
- Scalar variables have m_field_definitions==NULL.
|
||||||
@ -5757,6 +5759,14 @@ public:
|
|||||||
m_cursor_rowtype_offset(0),
|
m_cursor_rowtype_offset(0),
|
||||||
m_row_field_definitions(NULL)
|
m_row_field_definitions(NULL)
|
||||||
{ }
|
{ }
|
||||||
|
Spvar_definition(const Column_definition &col_def)
|
||||||
|
: Column_definition(col_def),
|
||||||
|
m_column_type_ref(NULL),
|
||||||
|
m_table_rowtype_ref(NULL),
|
||||||
|
m_cursor_rowtype_ref(false),
|
||||||
|
m_cursor_rowtype_offset(0),
|
||||||
|
m_row_field_definitions(NULL)
|
||||||
|
{ }
|
||||||
const Type_handler *type_handler() const
|
const Type_handler *type_handler() const
|
||||||
{
|
{
|
||||||
return Type_handler_hybrid_field_type::type_handler();
|
return Type_handler_hybrid_field_type::type_handler();
|
||||||
@ -5812,7 +5822,8 @@ public:
|
|||||||
}
|
}
|
||||||
uint is_row() const
|
uint is_row() const
|
||||||
{
|
{
|
||||||
return m_row_field_definitions != NULL;
|
return m_row_field_definitions != NULL &&
|
||||||
|
type_handler() == &type_handler_row;
|
||||||
}
|
}
|
||||||
// Check if "this" defines a ROW variable with n elements
|
// Check if "this" defines a ROW variable with n elements
|
||||||
uint is_row(uint n) const
|
uint is_row(uint n) const
|
||||||
@ -5824,10 +5835,11 @@ public:
|
|||||||
{
|
{
|
||||||
return m_row_field_definitions;
|
return m_row_field_definitions;
|
||||||
}
|
}
|
||||||
void set_row_field_definitions(Row_definition_list *list)
|
void set_row_field_definitions(const Type_handler *th,
|
||||||
|
Row_definition_list *list)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(list);
|
DBUG_ASSERT(list);
|
||||||
set_handler(&type_handler_row);
|
set_handler(th);
|
||||||
m_row_field_definitions= list;
|
m_row_field_definitions= list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
73
sql/field_composite.h
Normal file
73
sql/field_composite.h
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2025, Rakuten Securities
|
||||||
|
Copyright (c) 2025, MariaDB plc
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; version 2 of
|
||||||
|
the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
*/
|
||||||
|
#ifndef FIELD_COMPOSITE_INCLUDED
|
||||||
|
#define FIELD_COMPOSITE_INCLUDED
|
||||||
|
|
||||||
|
#include "field.h"
|
||||||
|
|
||||||
|
class Field_composite: public Field_null
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Field_composite(uchar *ptr_arg, const LEX_CSTRING *field_name_arg)
|
||||||
|
:Field_null(ptr_arg, 0, Field::NONE, field_name_arg, &my_charset_bin)
|
||||||
|
{}
|
||||||
|
en_fieldtype tmp_engine_column_type(bool use_packed_rows) const override
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return Field::tmp_engine_column_type(use_packed_rows);
|
||||||
|
}
|
||||||
|
enum_conv_type rpl_conv_type_from(const Conv_source &source,
|
||||||
|
const Relay_log_info *rli,
|
||||||
|
const Conv_param ¶m) const override
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return CONV_TYPE_IMPOSSIBLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint rows() const { return 0; }
|
||||||
|
virtual bool get_key(String *key, bool is_first) { return true; }
|
||||||
|
virtual bool get_next_key(const String *curr_key, String *next_key)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual bool get_prior_key(const String *curr_key, String *prior_key)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual Item_field *element_by_key(THD *thd, String *key) { return NULL; }
|
||||||
|
virtual Item_field *element_by_key(THD *thd, String *key) const
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
virtual Item **element_addr_by_key(THD *thd, String *key) { return NULL; }
|
||||||
|
virtual bool delete_all_elements() { return true; }
|
||||||
|
virtual bool delete_element_by_key(String *key) { return true; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve the Item representing the element of the composite field.
|
||||||
|
Note that the item here may not represent a particular element but
|
||||||
|
it does contain the information about the element type.
|
||||||
|
|
||||||
|
Use element_by_key() to retrieve the item representing a particular
|
||||||
|
element of the composite field.
|
||||||
|
*/
|
||||||
|
virtual Item *get_element_item() const { return NULL; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FIELD_COMPOSITE_INCLUDED */
|
31
sql/item_composite.cc
Normal file
31
sql/item_composite.cc
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2025, Rakuten Securities
|
||||||
|
Copyright (c) 2025, MariaDB plc
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; version 2 of
|
||||||
|
the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
*/
|
||||||
|
#include "my_global.h"
|
||||||
|
#include "item.h"
|
||||||
|
#include "item_composite.h"
|
||||||
|
|
||||||
|
void Item_composite::illegal_method_call(const char *method)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("Item_composite::illegal_method_call");
|
||||||
|
DBUG_PRINT("error", ("!!! %s method was called for %s",
|
||||||
|
method, type_handler()->name().ptr()));
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
|
||||||
|
DBUG_VOID_RETURN;
|
||||||
|
}
|
103
sql/item_composite.h
Normal file
103
sql/item_composite.h
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2025, Rakuten Securities
|
||||||
|
Copyright (c) 2025, MariaDB plc
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; version 2 of
|
||||||
|
the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
*/
|
||||||
|
#ifndef ITEM_COMPOSITE_INCLUDED
|
||||||
|
#define ITEM_COMPOSITE_INCLUDED
|
||||||
|
|
||||||
|
#include "item.h"
|
||||||
|
|
||||||
|
class Field_composite;
|
||||||
|
|
||||||
|
class Item_composite_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~Item_composite_base() = default;
|
||||||
|
|
||||||
|
// For associative arrays
|
||||||
|
/// Returns the number of columns for the elements of the array
|
||||||
|
virtual uint rows() const { return 1; }
|
||||||
|
virtual bool get_key(String *key, bool is_first) { return true; }
|
||||||
|
virtual bool get_next_key(const String *curr_key, String *next_key)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
virtual Item *element_by_key(THD *thd, String *key) { return nullptr; }
|
||||||
|
virtual Item **element_addr_by_key(THD *thd, Item **addr_arg, String *key)
|
||||||
|
{
|
||||||
|
return addr_arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the composite field for the item, when applicable.
|
||||||
|
*/
|
||||||
|
virtual Field_composite *get_composite_field() const { return nullptr; }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Item_composite: public Item_fixed_hybrid,
|
||||||
|
protected Item_args,
|
||||||
|
public Item_composite_base
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Item_composite(THD *thd, List<Item> &list)
|
||||||
|
:Item_fixed_hybrid(thd), Item_args(thd, list)
|
||||||
|
{ }
|
||||||
|
Item_composite(THD *thd, Item_args *other)
|
||||||
|
:Item_fixed_hybrid(thd), Item_args(thd, other)
|
||||||
|
{ }
|
||||||
|
Item_composite(THD *thd)
|
||||||
|
:Item_fixed_hybrid(thd)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
enum Type type() const override { return ROW_ITEM; }
|
||||||
|
|
||||||
|
void illegal_method_call(const char *);
|
||||||
|
|
||||||
|
void make_send_field(THD *thd, Send_field *) override
|
||||||
|
{
|
||||||
|
illegal_method_call((const char*)"make_send_field");
|
||||||
|
};
|
||||||
|
double val_real() override
|
||||||
|
{
|
||||||
|
illegal_method_call((const char*)"val");
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
longlong val_int() override
|
||||||
|
{
|
||||||
|
illegal_method_call((const char*)"val_int");
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
String *val_str(String *) override
|
||||||
|
{
|
||||||
|
illegal_method_call((const char*)"val_str");
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
my_decimal *val_decimal(my_decimal *) override
|
||||||
|
{
|
||||||
|
illegal_method_call((const char*)"val_decimal");
|
||||||
|
return 0;
|
||||||
|
};
|
||||||
|
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
|
||||||
|
{
|
||||||
|
illegal_method_call((const char*)"get_date");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* ITEM_COMPOSITE_INCLUDED */
|
@ -4812,7 +4812,7 @@ bool Item_func_set_user_var::fix_fields(THD *thd, Item **ref)
|
|||||||
break;
|
break;
|
||||||
case ROW_RESULT:
|
case ROW_RESULT:
|
||||||
DBUG_ASSERT(0);
|
DBUG_ASSERT(0);
|
||||||
set_handler(&type_handler_row);
|
set_handler(args[0]->type_handler());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (thd->lex->current_select)
|
if (thd->lex->current_select)
|
||||||
|
@ -826,6 +826,8 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
const Handler *m_func_handler;
|
const Handler *m_func_handler;
|
||||||
public:
|
public:
|
||||||
|
Item_handled_func(THD *thd)
|
||||||
|
:Item_func(thd), m_func_handler(NULL) { }
|
||||||
Item_handled_func(THD *thd, Item *a)
|
Item_handled_func(THD *thd, Item *a)
|
||||||
:Item_func(thd, a), m_func_handler(NULL) { }
|
:Item_func(thd, a), m_func_handler(NULL) { }
|
||||||
Item_handled_func(THD *thd, Item *a, Item *b)
|
Item_handled_func(THD *thd, Item *a, Item *b)
|
||||||
|
@ -25,15 +25,6 @@
|
|||||||
#include "sql_class.h" // THD, set_var.h: THD
|
#include "sql_class.h" // THD, set_var.h: THD
|
||||||
#include "set_var.h"
|
#include "set_var.h"
|
||||||
|
|
||||||
void Item_row::illegal_method_call(const char *method)
|
|
||||||
{
|
|
||||||
DBUG_ENTER("Item_row::illegal_method_call");
|
|
||||||
DBUG_PRINT("error", ("!!! %s method was called for row item", method));
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
my_error(ER_OPERAND_COLUMNS, MYF(0), 1);
|
|
||||||
DBUG_VOID_RETURN;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Item_row::fix_fields(THD *thd, Item **ref)
|
bool Item_row::fix_fields(THD *thd, Item **ref)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(fixed() == 0);
|
DBUG_ASSERT(fixed() == 0);
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
#ifndef ITEM_ROW_INCLUDED
|
#ifndef ITEM_ROW_INCLUDED
|
||||||
#define ITEM_ROW_INCLUDED
|
#define ITEM_ROW_INCLUDED
|
||||||
|
|
||||||
|
#include "item_composite.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2002, 2013, Oracle and/or its affiliates.
|
Copyright (c) 2002, 2013, Oracle and/or its affiliates.
|
||||||
|
|
||||||
@ -33,8 +35,7 @@
|
|||||||
Item which stores (x,y,...) and ROW(x,y,...).
|
Item which stores (x,y,...) and ROW(x,y,...).
|
||||||
Note that this can be recursive: ((x,y),(z,t)) is a ROW of ROWs.
|
Note that this can be recursive: ((x,y),(z,t)) is a ROW of ROWs.
|
||||||
*/
|
*/
|
||||||
class Item_row: public Item_fixed_hybrid,
|
class Item_row: public Item_composite,
|
||||||
private Item_args,
|
|
||||||
private Used_tables_and_const_cache
|
private Used_tables_and_const_cache
|
||||||
{
|
{
|
||||||
table_map not_null_tables_cache;
|
table_map not_null_tables_cache;
|
||||||
@ -45,53 +46,22 @@ class Item_row: public Item_fixed_hybrid,
|
|||||||
bool with_null;
|
bool with_null;
|
||||||
public:
|
public:
|
||||||
Item_row(THD *thd, List<Item> &list)
|
Item_row(THD *thd, List<Item> &list)
|
||||||
:Item_fixed_hybrid(thd), Item_args(thd, list),
|
:Item_composite(thd, list),
|
||||||
not_null_tables_cache(0), with_null(0)
|
not_null_tables_cache(0), with_null(0)
|
||||||
{ }
|
{ }
|
||||||
Item_row(THD *thd, Item_row *row)
|
Item_row(THD *thd, Item_row *row)
|
||||||
:Item_fixed_hybrid(thd), Item_args(thd, static_cast<Item_args*>(row)),
|
:Item_composite(thd, static_cast<Item_args*>(row)),
|
||||||
Used_tables_and_const_cache(),
|
Used_tables_and_const_cache(),
|
||||||
not_null_tables_cache(0), with_null(0)
|
not_null_tables_cache(0), with_null(0)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
enum Type type() const override { return ROW_ITEM; };
|
|
||||||
const Type_handler *type_handler() const override { return &type_handler_row; }
|
const Type_handler *type_handler() const override { return &type_handler_row; }
|
||||||
Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
|
Field *create_tmp_field_ex(MEM_ROOT *root, TABLE *table, Tmp_field_src *src,
|
||||||
const Tmp_field_param *param) override
|
const Tmp_field_param *param) override
|
||||||
{
|
{
|
||||||
return NULL; // Check with Vicentiu why it's called for Item_row
|
return NULL; // Check with Vicentiu why it's called for Item_row
|
||||||
}
|
}
|
||||||
void illegal_method_call(const char *);
|
|
||||||
bool is_null() override { return null_value; }
|
bool is_null() override { return null_value; }
|
||||||
void make_send_field(THD *thd, Send_field *) override
|
|
||||||
{
|
|
||||||
illegal_method_call((const char*)"make_send_field");
|
|
||||||
};
|
|
||||||
double val_real() override
|
|
||||||
{
|
|
||||||
illegal_method_call((const char*)"val");
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
longlong val_int() override
|
|
||||||
{
|
|
||||||
illegal_method_call((const char*)"val_int");
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
String *val_str(String *) override
|
|
||||||
{
|
|
||||||
illegal_method_call((const char*)"val_str");
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
my_decimal *val_decimal(my_decimal *) override
|
|
||||||
{
|
|
||||||
illegal_method_call((const char*)"val_decimal");
|
|
||||||
return 0;
|
|
||||||
};
|
|
||||||
bool get_date(THD *thd, MYSQL_TIME *ltime, date_mode_t fuzzydate) override
|
|
||||||
{
|
|
||||||
illegal_method_call((const char*)"get_date");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool fix_fields(THD *thd, Item **ref) override;
|
bool fix_fields(THD *thd, Item **ref) override;
|
||||||
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge)
|
void fix_after_pullout(st_select_lex *new_parent, Item **ref, bool merge)
|
||||||
override;
|
override;
|
||||||
|
@ -55,6 +55,7 @@ SYMBOL symbols[] = {
|
|||||||
{ "<<", SYM(SHIFT_LEFT)},
|
{ "<<", SYM(SHIFT_LEFT)},
|
||||||
{ ">>", SYM(SHIFT_RIGHT)},
|
{ ">>", SYM(SHIFT_RIGHT)},
|
||||||
{ "<=>", SYM(EQUAL_SYM)},
|
{ "<=>", SYM(EQUAL_SYM)},
|
||||||
|
{ "=>", SYM(ARROW_SYM)},
|
||||||
{ "ACCOUNT", SYM(ACCOUNT_SYM)},
|
{ "ACCOUNT", SYM(ACCOUNT_SYM)},
|
||||||
{ "ACTION", SYM(ACTION)},
|
{ "ACTION", SYM(ACTION)},
|
||||||
{ "ADD", SYM(ADD)},
|
{ "ADD", SYM(ADD)},
|
||||||
|
@ -12328,3 +12328,9 @@ ER_WARN_MALFORMED_HINT
|
|||||||
eng "Hint %s is ignored as malformed"
|
eng "Hint %s is ignored as malformed"
|
||||||
ER_WARN_HINTS_ON_INSERT_PART_OF_INSERT_SELECT
|
ER_WARN_HINTS_ON_INSERT_PART_OF_INSERT_SELECT
|
||||||
eng "Optimizer hints at the INSERT part of a INSERT..SELECT statement are not supported"
|
eng "Optimizer hints at the INSERT part of a INSERT..SELECT statement are not supported"
|
||||||
|
ER_ASSOC_ARRAY_ELEM_NOT_FOUND
|
||||||
|
eng "Element not found with key '%s'"
|
||||||
|
ER_NULL_FOR_ASSOC_ARRAY_INDEX
|
||||||
|
eng "NULL key used for associative array '%s'"
|
||||||
|
ER_NEED_NAMED_ASSOCIATION
|
||||||
|
eng "Initializing %s requires named association"
|
||||||
|
@ -3856,8 +3856,8 @@ sp_head::set_local_variable_row_field_by_name(THD *thd, sp_pcontext *spcont,
|
|||||||
if (!(val= adjust_assignment_source(thd, val, NULL)))
|
if (!(val= adjust_assignment_source(thd, val, NULL)))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
sp_instr_set_row_field_by_name *sp_set=
|
sp_instr_set_composite_field_by_name *sp_set=
|
||||||
new (thd->mem_root) sp_instr_set_row_field_by_name(instructions(),
|
new (thd->mem_root) sp_instr_set_composite_field_by_name(instructions(),
|
||||||
spcont, rh,
|
spcont, rh,
|
||||||
spv->offset,
|
spv->offset,
|
||||||
*field_name,
|
*field_name,
|
||||||
@ -3982,7 +3982,7 @@ bool sp_head::spvar_fill_row(THD *thd,
|
|||||||
sp_variable *spvar,
|
sp_variable *spvar,
|
||||||
Row_definition_list *defs)
|
Row_definition_list *defs)
|
||||||
{
|
{
|
||||||
spvar->field_def.set_row_field_definitions(defs);
|
spvar->field_def.set_row_field_definitions(&type_handler_row, defs);
|
||||||
spvar->field_def.field_name= spvar->name;
|
spvar->field_def.field_name= spvar->name;
|
||||||
if (fill_spvar_definition(thd, &spvar->field_def))
|
if (fill_spvar_definition(thd, &spvar->field_def))
|
||||||
return true;
|
return true;
|
||||||
@ -4050,6 +4050,35 @@ bool sp_head::spvar_def_fill_type_reference(THD *thd, Spvar_definition *def,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool sp_head::spvar_def_fill_rowtype_reference(THD *thd, Spvar_definition *def,
|
||||||
|
const LEX_CSTRING &table)
|
||||||
|
{
|
||||||
|
Table_ident *ref;
|
||||||
|
if (!(ref= new (thd->mem_root) Table_ident(&table)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
def->set_table_rowtype_ref(ref);
|
||||||
|
m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool sp_head::spvar_def_fill_rowtype_reference(THD *thd, Spvar_definition *def,
|
||||||
|
const LEX_CSTRING &db,
|
||||||
|
const LEX_CSTRING &table)
|
||||||
|
{
|
||||||
|
Table_ident *ref;
|
||||||
|
if (!(ref= new (thd->mem_root) Table_ident(thd, &db, &table, false)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
def->set_table_rowtype_ref(ref);
|
||||||
|
m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool sp_head::spvar_fill_table_rowtype_reference(THD *thd,
|
bool sp_head::spvar_fill_table_rowtype_reference(THD *thd,
|
||||||
sp_variable *spvar,
|
sp_variable *spvar,
|
||||||
const LEX_CSTRING &table)
|
const LEX_CSTRING &table)
|
||||||
|
@ -825,6 +825,11 @@ public:
|
|||||||
const LEX_CSTRING &db,
|
const LEX_CSTRING &db,
|
||||||
const LEX_CSTRING &table,
|
const LEX_CSTRING &table,
|
||||||
const LEX_CSTRING &column);
|
const LEX_CSTRING &column);
|
||||||
|
bool spvar_def_fill_rowtype_reference(THD *thd, Spvar_definition *def,
|
||||||
|
const LEX_CSTRING &table);
|
||||||
|
bool spvar_def_fill_rowtype_reference(THD *thd, Spvar_definition *def,
|
||||||
|
const LEX_CSTRING &db,
|
||||||
|
const LEX_CSTRING &table);
|
||||||
|
|
||||||
void set_c_chistics(const st_sp_chistics &chistics);
|
void set_c_chistics(const st_sp_chistics &chistics);
|
||||||
void set_info(longlong created, longlong modified,
|
void set_info(longlong created, longlong modified,
|
||||||
|
115
sql/sp_instr.cc
115
sql/sp_instr.cc
@ -1313,13 +1313,23 @@ sp_instr_set_row_field::print(String *str)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
sp_instr_set_field_by_name class functions
|
sp_instr_set_composite_field_by_name class functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
sp_instr_set_row_field_by_name::exec_core(THD *thd, uint *nextp)
|
sp_instr_set_composite_field_by_name::exec_core(THD *thd, uint *nextp)
|
||||||
{
|
{
|
||||||
int res= get_rcontext(thd)->set_variable_row_field_by_name(thd, m_offset,
|
if (m_key)
|
||||||
|
{
|
||||||
|
auto var= get_rcontext(thd)->get_variable(m_offset);
|
||||||
|
auto handler= var->type_handler()->to_composite();
|
||||||
|
DBUG_ASSERT(handler);
|
||||||
|
|
||||||
|
if (handler->key_to_lex_cstring(thd, &m_key, var->name, m_field_name))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int res= get_rcontext(thd)->set_variable_composite_by_name(thd, m_offset,
|
||||||
m_field_name,
|
m_field_name,
|
||||||
&m_value);
|
&m_value);
|
||||||
*nextp= m_ip + 1;
|
*nextp= m_ip + 1;
|
||||||
@ -1328,30 +1338,93 @@ sp_instr_set_row_field_by_name::exec_core(THD *thd, uint *nextp)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
sp_instr_set_row_field_by_name::print(String *str)
|
sp_instr_set_composite_field_by_name::print(String *str)
|
||||||
{
|
{
|
||||||
/* set name.field@offset["field"] ... */
|
/* set name.field@offset["field"] ... */
|
||||||
size_t rsrv= SP_INSTR_UINT_MAXLEN + 6 + 6 + 3 + 2;
|
/* set name.field["key"] ... */
|
||||||
sp_variable *var= m_ctx->find_variable(m_offset);
|
sp_variable *var= m_ctx->find_variable(m_offset);
|
||||||
const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
|
const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
|
||||||
DBUG_ASSERT(var);
|
DBUG_ASSERT(var);
|
||||||
DBUG_ASSERT(var->field_def.is_table_rowtype_ref() ||
|
DBUG_ASSERT(dynamic_cast<const Type_handler_composite*>(var->type_handler()));
|
||||||
var->field_def.is_cursor_rowtype_ref());
|
|
||||||
|
|
||||||
rsrv+= var->name.length + 2 * m_field_name.length + prefix->length;
|
str->append(STRING_WITH_LEN("set "));
|
||||||
if (str->reserve(rsrv))
|
str->append(prefix);
|
||||||
return;
|
str->append(&var->name);
|
||||||
str->qs_append(STRING_WITH_LEN("set "));
|
|
||||||
str->qs_append(prefix);
|
if (!m_key)
|
||||||
str->qs_append(&var->name);
|
{
|
||||||
str->qs_append('.');
|
str->append('.');
|
||||||
str->qs_append(&m_field_name);
|
str->append(&m_field_name);
|
||||||
str->qs_append('@');
|
}
|
||||||
str->qs_append(m_offset);
|
|
||||||
str->qs_append("[\"",2);
|
str->append('@');
|
||||||
str->qs_append(&m_field_name);
|
str->append_ulonglong(m_offset);
|
||||||
str->qs_append("\"]",2);
|
|
||||||
str->qs_append(' ');
|
if (!m_key)
|
||||||
|
{
|
||||||
|
str->append(STRING_WITH_LEN("[\""));
|
||||||
|
str->append(&m_field_name);
|
||||||
|
str->append(STRING_WITH_LEN("\"]"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
str->append('[');
|
||||||
|
m_key->print(str, enum_query_type(QT_ORDINARY |
|
||||||
|
QT_ITEM_ORIGINAL_FUNC_NULLIF));
|
||||||
|
str->append(']');
|
||||||
|
}
|
||||||
|
|
||||||
|
str->append(' ');
|
||||||
|
m_value->print(str, enum_query_type(QT_ORDINARY |
|
||||||
|
QT_ITEM_ORIGINAL_FUNC_NULLIF));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
sp_instr_set_composite_field_by_key class functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
sp_instr_set_composite_field_by_key::exec_core(THD *thd, uint *nextp)
|
||||||
|
{
|
||||||
|
auto var= get_rcontext(thd)->get_variable(m_offset);
|
||||||
|
auto handler= var->type_handler()->to_composite();
|
||||||
|
DBUG_ASSERT(handler);
|
||||||
|
|
||||||
|
LEX_CSTRING key;
|
||||||
|
if (handler->key_to_lex_cstring(thd, &m_key, var->name, key))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int res= get_rcontext(thd)->set_variable_composite_field_by_key(thd,
|
||||||
|
m_offset,
|
||||||
|
key,
|
||||||
|
m_field_name,
|
||||||
|
&m_value);
|
||||||
|
*nextp= m_ip + 1;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
sp_instr_set_composite_field_by_key::print(String *str)
|
||||||
|
{
|
||||||
|
sp_variable *var= m_ctx->find_variable(m_offset);
|
||||||
|
const LEX_CSTRING *prefix= m_rcontext_handler->get_name_prefix();
|
||||||
|
DBUG_ASSERT(var);
|
||||||
|
DBUG_ASSERT(dynamic_cast<const Type_handler_composite*>(var->type_handler()));
|
||||||
|
|
||||||
|
str->append(STRING_WITH_LEN("set "));
|
||||||
|
str->append(prefix);
|
||||||
|
str->append(&var->name);
|
||||||
|
str->append('@');
|
||||||
|
str->append_ulonglong(m_offset);
|
||||||
|
str->append('[');
|
||||||
|
m_key->print(str, enum_query_type(QT_ORDINARY |
|
||||||
|
QT_ITEM_ORIGINAL_FUNC_NULLIF));
|
||||||
|
str->append(']');
|
||||||
|
str->append('.');
|
||||||
|
str->append(&m_field_name);
|
||||||
|
str->append(' ');
|
||||||
m_value->print(str, enum_query_type(QT_ORDINARY |
|
m_value->print(str, enum_query_type(QT_ORDINARY |
|
||||||
QT_ITEM_ORIGINAL_FUNC_NULLIF));
|
QT_ITEM_ORIGINAL_FUNC_NULLIF));
|
||||||
}
|
}
|
||||||
|
@ -749,35 +749,100 @@ public:
|
|||||||
structure of "rec". It gets resolved at run time, during the corresponding
|
structure of "rec". It gets resolved at run time, during the corresponding
|
||||||
sp_instr_cursor_copy_struct::exec_core().
|
sp_instr_cursor_copy_struct::exec_core().
|
||||||
|
|
||||||
So sp_instr_set_row_field_by_name searches for ROW fields by name,
|
So sp_instr_set_composite_field_by_name searches for ROW fields by name,
|
||||||
while sp_instr_set_row_field (see above) searches for ROW fields by index.
|
while sp_instr_set_row_field (see above) searches for ROW fields by index.
|
||||||
*/
|
|
||||||
|
|
||||||
class sp_instr_set_row_field_by_name : public sp_instr_set
|
Additionally, this class is used for assignments of associative arrays
|
||||||
|
by key:
|
||||||
|
DECLARE
|
||||||
|
TYPE t IS TABLE OF rec_t INDEX BY VARCHAR2(20);
|
||||||
|
arr t;
|
||||||
|
BEGIN
|
||||||
|
arr('key'):= rec_t(10, 20); -- This instruction
|
||||||
|
END;
|
||||||
|
*/
|
||||||
|
class sp_instr_set_composite_field_by_name : public sp_instr_set
|
||||||
{
|
{
|
||||||
// Prevent use of this
|
using SELF= sp_instr_set_composite_field_by_name;
|
||||||
sp_instr_set_row_field_by_name(const sp_instr_set_row_field &);
|
sp_instr_set_composite_field_by_name(const SELF &);
|
||||||
void operator=(sp_instr_set_row_field_by_name &);
|
void operator=(SELF &);
|
||||||
const LEX_CSTRING m_field_name;
|
LEX_CSTRING m_field_name;
|
||||||
|
Item* m_key;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
sp_instr_set_composite_field_by_name(uint ip, sp_pcontext *ctx,
|
||||||
sp_instr_set_row_field_by_name(uint ip, sp_pcontext *ctx,
|
|
||||||
const Sp_rcontext_handler *rh,
|
const Sp_rcontext_handler *rh,
|
||||||
uint offset, const LEX_CSTRING &field_name,
|
uint offset,
|
||||||
|
const LEX_CSTRING &field_name,
|
||||||
Item *val,
|
Item *val,
|
||||||
LEX *lex, bool lex_resp,
|
LEX *lex, bool lex_resp,
|
||||||
const LEX_CSTRING &value_query)
|
const LEX_CSTRING &value_query)
|
||||||
: sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp, value_query),
|
: sp_instr_set(ip, ctx, rh, offset, val, lex, lex_resp, value_query),
|
||||||
m_field_name(field_name)
|
m_field_name(field_name),
|
||||||
|
m_key(nullptr)
|
||||||
|
{}
|
||||||
|
sp_instr_set_composite_field_by_name(uint ip, sp_pcontext *ctx,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
Item* key, Item *val,
|
||||||
|
LEX *lex, bool lex_resp,
|
||||||
|
const LEX_CSTRING &value_query)
|
||||||
|
: sp_instr_set(ip, ctx,
|
||||||
|
addr.rcontext_handler(),
|
||||||
|
addr.offset(), val, lex,
|
||||||
|
lex_resp, value_query),
|
||||||
|
m_key(key)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
virtual ~sp_instr_set_row_field_by_name() = default;
|
virtual ~sp_instr_set_composite_field_by_name() = default;
|
||||||
|
|
||||||
int exec_core(THD *thd, uint *nextp) override;
|
int exec_core(THD *thd, uint *nextp) override;
|
||||||
|
|
||||||
void print(String *str) override;
|
void print(String *str) override;
|
||||||
}; // class sp_instr_set_field_by_name : public sp_instr_set
|
}; // class sp_instr_set_composite_field_by_name : public sp_instr_set
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This class handles assignments of non scalar associative array's element
|
||||||
|
assignments.
|
||||||
|
|
||||||
|
DECLARE
|
||||||
|
TYPE t IS TABLE OF rec_t INDEX BY VARCHAR2(20);
|
||||||
|
arr t;
|
||||||
|
BEGIN
|
||||||
|
arr('key'):= rec_t(10, 20);
|
||||||
|
arr('key').field:= 30; -- This instruction
|
||||||
|
END;
|
||||||
|
*/
|
||||||
|
class sp_instr_set_composite_field_by_key : public sp_instr_set
|
||||||
|
{
|
||||||
|
using SELF= sp_instr_set_composite_field_by_key;
|
||||||
|
sp_instr_set_composite_field_by_key(const SELF &);
|
||||||
|
void operator=(SELF &);
|
||||||
|
Item* m_key;
|
||||||
|
const LEX_CSTRING m_field_name;
|
||||||
|
|
||||||
|
public:
|
||||||
|
sp_instr_set_composite_field_by_key(uint ip, sp_pcontext *ctx,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
Item* key,
|
||||||
|
const LEX_CSTRING &field_name,
|
||||||
|
Item *val,
|
||||||
|
LEX *lex, bool lex_resp,
|
||||||
|
const LEX_CSTRING &value_query)
|
||||||
|
: sp_instr_set(ip, ctx,
|
||||||
|
addr.rcontext_handler(),
|
||||||
|
addr.offset(), val, lex,
|
||||||
|
lex_resp, value_query),
|
||||||
|
m_key(key),
|
||||||
|
m_field_name(field_name)
|
||||||
|
{}
|
||||||
|
|
||||||
|
virtual ~sp_instr_set_composite_field_by_key() = default;
|
||||||
|
|
||||||
|
int exec_core(THD *thd, uint *nextp) override;
|
||||||
|
|
||||||
|
void print(String *str) override;
|
||||||
|
}; // class sp_instr_set_composite_field_by_key : public sp_instr_set
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -458,6 +458,21 @@ sp_type_def *sp_pcontext::find_type_def(const LEX_CSTRING &name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool sp_type_def_list::type_defs_add_composite2(THD *thd,
|
||||||
|
const Lex_ident_column &name,
|
||||||
|
const Type_handler *th,
|
||||||
|
Spvar_definition *key,
|
||||||
|
Spvar_definition *value)
|
||||||
|
{
|
||||||
|
auto p= new (thd->mem_root) sp_type_def_composite2(name, th, key, value);
|
||||||
|
|
||||||
|
if (p == nullptr)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return m_type_defs.append(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sp_condition_value *
|
sp_condition_value *
|
||||||
sp_pcontext::find_declared_or_predefined_condition(THD *thd,
|
sp_pcontext::find_declared_or_predefined_condition(THD *thd,
|
||||||
const LEX_CSTRING *name)
|
const LEX_CSTRING *name)
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "field.h" // Create_field
|
#include "field.h" // Create_field
|
||||||
#include "sql_array.h" // Dynamic_array
|
#include "sql_array.h" // Dynamic_array
|
||||||
#include "sp_type_def.h"
|
#include "sp_type_def.h"
|
||||||
|
#include "sp_rcontext_handler.h"
|
||||||
|
|
||||||
|
|
||||||
/// This class represents a stored program variable or a parameter
|
/// This class represents a stored program variable or a parameter
|
||||||
@ -343,30 +344,6 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/// This class represents 'DECLARE RECORD' statement.
|
|
||||||
|
|
||||||
class sp_record : public Sql_alloc
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/// Name of the record.
|
|
||||||
Lex_ident_column name;
|
|
||||||
Row_definition_list *field;
|
|
||||||
|
|
||||||
public:
|
|
||||||
sp_record(const Lex_ident_column &name_arg, Row_definition_list *prmfield)
|
|
||||||
:Sql_alloc(),
|
|
||||||
name(name_arg),
|
|
||||||
field(prmfield)
|
|
||||||
{ }
|
|
||||||
bool eq_name(const LEX_CSTRING *str) const
|
|
||||||
{
|
|
||||||
return name.streq(*str);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// The class represents parse-time context, which keeps track of declared
|
/// The class represents parse-time context, which keeps track of declared
|
||||||
@ -565,6 +542,11 @@ public:
|
|||||||
void declare_var_boundary(uint n)
|
void declare_var_boundary(uint n)
|
||||||
{ m_pboundary= n; }
|
{ m_pboundary= n; }
|
||||||
|
|
||||||
|
const sp_variable *get_pvariable(const sp_rcontext_addr &addr) const
|
||||||
|
{
|
||||||
|
return addr.rcontext_handler()->get_pvariable(this, addr.offset());
|
||||||
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
// CASE expressions.
|
// CASE expressions.
|
||||||
/////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////
|
||||||
@ -773,6 +755,23 @@ public:
|
|||||||
return type_defs_add_record(thd, name, field);
|
return type_defs_add_record(thd, name, field);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
// Composites, e.g. associative arrays.
|
||||||
|
/////////////////////////////////////////////////////////////////////////
|
||||||
|
bool type_defs_declare_composite2(THD *thd,
|
||||||
|
const Lex_ident_column &name,
|
||||||
|
const Type_handler *th,
|
||||||
|
Spvar_definition *key,
|
||||||
|
Spvar_definition *value)
|
||||||
|
{
|
||||||
|
if (unlikely(find_type_def(name, true)))
|
||||||
|
{
|
||||||
|
my_error(ER_SP_DUP_DECL, MYF(0), name.str);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return type_defs_add_composite2(thd, name, th, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Constructor for a tree node.
|
/// Constructor for a tree node.
|
||||||
/// @param prev the parent parsing context
|
/// @param prev the parent parsing context
|
||||||
|
@ -33,6 +33,12 @@ Sp_rcontext_handler_package_body sp_rcontext_handler_package_body;
|
|||||||
Sp_rcontext_handler_statement sp_rcontext_handler_statement;
|
Sp_rcontext_handler_statement sp_rcontext_handler_statement;
|
||||||
|
|
||||||
|
|
||||||
|
const sp_variable *
|
||||||
|
Sp_rcontext_handler_local::get_pvariable(const sp_pcontext *pctx, uint i) const
|
||||||
|
{
|
||||||
|
return pctx->find_variable(i);
|
||||||
|
}
|
||||||
|
|
||||||
sp_cursor *Sp_rcontext_handler::get_open_cursor_or_error(THD *thd,
|
sp_cursor *Sp_rcontext_handler::get_open_cursor_or_error(THD *thd,
|
||||||
const sp_rcontext_ref &ref)
|
const sp_rcontext_ref &ref)
|
||||||
{
|
{
|
||||||
@ -49,6 +55,14 @@ sp_rcontext *Sp_rcontext_handler_local::get_rcontext(sp_rcontext *ctx) const
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sp_variable *
|
||||||
|
Sp_rcontext_handler_package_body::get_pvariable(const sp_pcontext *pctx, uint i)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
sp_rcontext *Sp_rcontext_handler_package_body::get_rcontext(sp_rcontext *ctx) const
|
sp_rcontext *Sp_rcontext_handler_package_body::get_rcontext(sp_rcontext *ctx) const
|
||||||
{
|
{
|
||||||
return ctx->m_sp->m_parent->m_rcontext;
|
return ctx->m_sp->m_parent->m_rcontext;
|
||||||
@ -663,7 +677,10 @@ int sp_rcontext::set_variable(THD *thd, uint idx, Item **value)
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("sp_rcontext::set_variable");
|
DBUG_ENTER("sp_rcontext::set_variable");
|
||||||
DBUG_ASSERT(value);
|
DBUG_ASSERT(value);
|
||||||
DBUG_RETURN(thd->sp_eval_expr(m_var_table->field[idx], value));
|
|
||||||
|
auto handler= get_variable(idx)->type_handler()->to_composite();
|
||||||
|
DBUG_RETURN(thd->sp_eval_expr(m_var_table->field[idx], value) ||
|
||||||
|
(handler && handler->finalize_for_set(get_variable(idx))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -677,18 +694,6 @@ int sp_rcontext::set_variable_row_field(THD *thd, uint var_idx, uint field_idx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int sp_rcontext::set_variable_row_field_by_name(THD *thd, uint var_idx,
|
|
||||||
const LEX_CSTRING &field_name,
|
|
||||||
Item **value)
|
|
||||||
{
|
|
||||||
DBUG_ENTER("sp_rcontext::set_variable_row_field_by_name");
|
|
||||||
uint field_idx;
|
|
||||||
if (find_row_field_by_name_or_error(&field_idx, var_idx, field_name))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
DBUG_RETURN(set_variable_row_field(thd, var_idx, field_idx, value));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int sp_rcontext::set_variable_row(THD *thd, uint var_idx, List<Item> &items)
|
int sp_rcontext::set_variable_row(THD *thd, uint var_idx, List<Item> &items)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("sp_rcontext::set_variable_row");
|
DBUG_ENTER("sp_rcontext::set_variable_row");
|
||||||
@ -709,6 +714,64 @@ Virtual_tmp_table *sp_rcontext::virtual_tmp_table_for_row(uint var_idx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int sp_rcontext::set_variable_composite_by_name(THD *thd, uint var_idx,
|
||||||
|
const LEX_CSTRING &name,
|
||||||
|
Item **value)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_rcontext::set_variable_composite_by_name");
|
||||||
|
DBUG_ASSERT(get_variable(var_idx)->type() == Item::FIELD_ITEM);
|
||||||
|
DBUG_ASSERT(get_variable(var_idx)->cmp_type() == ROW_RESULT);
|
||||||
|
|
||||||
|
DBUG_RETURN(set_variable_composite_by_name(thd, get_variable(var_idx),
|
||||||
|
name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int sp_rcontext::set_variable_composite_by_name(THD *thd, Item_field *composite,
|
||||||
|
const LEX_CSTRING &name,
|
||||||
|
Item **value)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_rcontext::set_variable_composite_by_name");
|
||||||
|
|
||||||
|
auto handler= composite->type_handler()->to_composite();
|
||||||
|
DBUG_ASSERT(handler);
|
||||||
|
|
||||||
|
auto elem= handler->get_or_create_item(thd, composite, name);
|
||||||
|
if (!elem)
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
DBUG_RETURN(thd->sp_eval_expr(elem->field, value) ||
|
||||||
|
handler->finalize_for_set(elem));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
sp_rcontext::set_variable_composite_field_by_key(THD *thd,
|
||||||
|
uint var_idx,
|
||||||
|
const LEX_CSTRING &elem_name,
|
||||||
|
const LEX_CSTRING &field_name,
|
||||||
|
Item **value)
|
||||||
|
{
|
||||||
|
DBUG_ENTER("sp_rcontext::set_variable_composite_field_by_key");
|
||||||
|
DBUG_ASSERT(value);
|
||||||
|
|
||||||
|
DBUG_ASSERT(get_variable(var_idx)->type() == Item::FIELD_ITEM);
|
||||||
|
|
||||||
|
auto composite= get_variable(var_idx);
|
||||||
|
auto handler= composite->type_handler()->to_composite();
|
||||||
|
DBUG_ASSERT(handler);
|
||||||
|
|
||||||
|
auto elem= handler->get_item(thd, composite, elem_name);
|
||||||
|
if (!elem)
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
handler->prepare_for_set(elem);
|
||||||
|
|
||||||
|
DBUG_RETURN(set_variable_composite_by_name(thd, elem, field_name, value) ||
|
||||||
|
handler->finalize_for_set(elem));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool sp_rcontext::find_row_field_by_name_or_error(uint *field_idx,
|
bool sp_rcontext::find_row_field_by_name_or_error(uint *field_idx,
|
||||||
uint var_idx,
|
uint var_idx,
|
||||||
const LEX_CSTRING &field_name)
|
const LEX_CSTRING &field_name)
|
||||||
|
@ -209,11 +209,18 @@ public:
|
|||||||
int set_variable(THD *thd, uint var_idx, Item **value);
|
int set_variable(THD *thd, uint var_idx, Item **value);
|
||||||
int set_variable_row_field(THD *thd, uint var_idx, uint field_idx,
|
int set_variable_row_field(THD *thd, uint var_idx, uint field_idx,
|
||||||
Item **value);
|
Item **value);
|
||||||
int set_variable_row_field_by_name(THD *thd, uint var_idx,
|
|
||||||
const LEX_CSTRING &field_name,
|
|
||||||
Item **value);
|
|
||||||
int set_variable_row(THD *thd, uint var_idx, List<Item> &items);
|
int set_variable_row(THD *thd, uint var_idx, List<Item> &items);
|
||||||
|
|
||||||
|
int set_variable_composite_field_by_key(THD *thd,
|
||||||
|
uint var_idx,
|
||||||
|
const LEX_CSTRING &elem_name,
|
||||||
|
const LEX_CSTRING &field_name,
|
||||||
|
Item **value);
|
||||||
|
int set_variable_composite_by_name(THD *thd, uint var_idx,
|
||||||
|
const LEX_CSTRING &name,
|
||||||
|
Item **value);
|
||||||
|
int set_variable_composite_by_name(THD *thd, Item_field *composite,
|
||||||
|
const LEX_CSTRING &name, Item **value);
|
||||||
int set_parameter(THD *thd, uint var_idx, Item **value)
|
int set_parameter(THD *thd, uint var_idx, Item **value)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(var_idx < argument_count());
|
DBUG_ASSERT(var_idx < argument_count());
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
|
|
||||||
class sp_rcontext;
|
class sp_rcontext;
|
||||||
|
class sp_pcontext;
|
||||||
class sp_cursor;
|
class sp_cursor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -73,6 +74,11 @@ public:
|
|||||||
name with a package body variable.
|
name with a package body variable.
|
||||||
*/
|
*/
|
||||||
virtual const LEX_CSTRING *get_name_prefix() const= 0;
|
virtual const LEX_CSTRING *get_name_prefix() const= 0;
|
||||||
|
|
||||||
|
// Find a parse time SP variable
|
||||||
|
virtual const sp_variable *get_pvariable(const sp_pcontext *pctx,
|
||||||
|
uint offset) const= 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
At execution time THD->spcont points to the run-time context (sp_rcontext)
|
At execution time THD->spcont points to the run-time context (sp_rcontext)
|
||||||
of the currently executed routine.
|
of the currently executed routine.
|
||||||
@ -95,6 +101,8 @@ class Sp_rcontext_handler_local final :public Sp_rcontext_handler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const LEX_CSTRING *get_name_prefix() const override;
|
const LEX_CSTRING *get_name_prefix() const override;
|
||||||
|
const sp_variable *get_pvariable(const sp_pcontext *pctx,
|
||||||
|
uint offset) const override;
|
||||||
sp_rcontext *get_rcontext(sp_rcontext *ctx) const override;
|
sp_rcontext *get_rcontext(sp_rcontext *ctx) const override;
|
||||||
Item_field *get_variable(THD *thd, uint offset) const override;
|
Item_field *get_variable(THD *thd, uint offset) const override;
|
||||||
sp_cursor *get_cursor(THD *thd, uint offset) const override;
|
sp_cursor *get_cursor(THD *thd, uint offset) const override;
|
||||||
@ -111,6 +119,8 @@ class Sp_rcontext_handler_package_body final :public Sp_rcontext_handler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const LEX_CSTRING *get_name_prefix() const override;
|
const LEX_CSTRING *get_name_prefix() const override;
|
||||||
|
const sp_variable *get_pvariable(const sp_pcontext *pctx,
|
||||||
|
uint offset) const override;
|
||||||
sp_rcontext *get_rcontext(sp_rcontext *ctx) const override;
|
sp_rcontext *get_rcontext(sp_rcontext *ctx) const override;
|
||||||
Item_field *get_variable(THD *thd, uint offset) const override;
|
Item_field *get_variable(THD *thd, uint offset) const override;
|
||||||
sp_cursor *get_cursor(THD *thd, uint offset) const override
|
sp_cursor *get_cursor(THD *thd, uint offset) const override
|
||||||
@ -145,6 +155,12 @@ public:
|
|||||||
DBUG_ASSERT(0); // There are no session wide SP variables yet.
|
DBUG_ASSERT(0); // There are no session wide SP variables yet.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
const sp_variable *get_pvariable(const sp_pcontext *pctx,
|
||||||
|
uint offset) const override
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
sp_cursor *get_cursor(THD *thd, uint offset) const override;
|
sp_cursor *get_cursor(THD *thd, uint offset) const override;
|
||||||
sp_cursor *get_cursor_by_ref(THD *thd, const sp_rcontext_addr &ref,
|
sp_cursor *get_cursor_by_ref(THD *thd, const sp_rcontext_addr &ref,
|
||||||
bool for_open) const override;
|
bool for_open) const override;
|
||||||
|
@ -72,6 +72,25 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
This class represents 'DECLARE TYPE .. TABLE OF' statement.
|
||||||
|
*/
|
||||||
|
class sp_type_def_composite2 : public sp_type_def
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Spvar_definition *m_def[2];
|
||||||
|
|
||||||
|
public:
|
||||||
|
sp_type_def_composite2(const Lex_ident_column &name_arg,
|
||||||
|
const Type_handler *th,
|
||||||
|
Spvar_definition *key_def_arg,
|
||||||
|
Spvar_definition *value_def_arg)
|
||||||
|
:sp_type_def(name_arg, th),
|
||||||
|
m_def{key_def_arg, value_def_arg}
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class sp_type_def_list
|
class sp_type_def_list
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -92,6 +111,11 @@ public:
|
|||||||
|
|
||||||
bool type_defs_add_record(THD *thd, const Lex_ident_column &name,
|
bool type_defs_add_record(THD *thd, const Lex_ident_column &name,
|
||||||
Row_definition_list *field);
|
Row_definition_list *field);
|
||||||
|
bool type_defs_add_composite2(THD *thd,
|
||||||
|
const Lex_ident_column &name,
|
||||||
|
const Type_handler *th,
|
||||||
|
Spvar_definition *key,
|
||||||
|
Spvar_definition *value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -8949,6 +8949,51 @@ bool Qualified_column_ident::append_to(THD *thd, String *str) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Qualified_ident::Qualified_ident(THD *thd, const Lex_ident_cli_st &a)
|
||||||
|
:m_cli_pos(a.pos()),
|
||||||
|
m_spvar(nullptr),
|
||||||
|
m_defined_parts(1)
|
||||||
|
{
|
||||||
|
m_parts[0]= Lex_ident_sys(thd, &a);
|
||||||
|
m_parts[1]= m_parts[2]= Lex_ident_sys();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Qualified_ident::Qualified_ident(THD *thd, const Lex_ident_cli_st &a,
|
||||||
|
const Lex_ident_sys_st &b)
|
||||||
|
:m_cli_pos(a.pos()),
|
||||||
|
m_spvar(nullptr),
|
||||||
|
m_defined_parts(2)
|
||||||
|
{
|
||||||
|
m_parts[0]= Lex_ident_sys(thd, &a);
|
||||||
|
m_parts[1]= b;
|
||||||
|
m_parts[2]= Lex_ident_sys();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Qualified_ident::Qualified_ident(THD *thd, const Lex_ident_cli_st &a,
|
||||||
|
const Lex_ident_sys_st &b,
|
||||||
|
const Lex_ident_sys_st &c)
|
||||||
|
:m_cli_pos(a.pos()),
|
||||||
|
m_spvar(nullptr),
|
||||||
|
m_defined_parts(3)
|
||||||
|
{
|
||||||
|
m_parts[0]= Lex_ident_sys(thd, &a);
|
||||||
|
m_parts[1]= b;
|
||||||
|
m_parts[2]= c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Qualified_ident::Qualified_ident(const Lex_ident_sys_st &a)
|
||||||
|
:m_cli_pos(nullptr),
|
||||||
|
m_spvar(nullptr),
|
||||||
|
m_defined_parts(1)
|
||||||
|
{
|
||||||
|
m_parts[0]= a;
|
||||||
|
m_parts[1]= m_parts[2]= Lex_ident_sys();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif /* !defined(MYSQL_CLIENT) */
|
#endif /* !defined(MYSQL_CLIENT) */
|
||||||
|
|
||||||
|
|
||||||
|
@ -7401,6 +7401,60 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Qualified_ident: public Sql_alloc
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
const char *m_cli_pos;
|
||||||
|
Lex_ident_sys_st m_parts[3];
|
||||||
|
sp_variable *m_spvar;
|
||||||
|
uint m_defined_parts;
|
||||||
|
public:
|
||||||
|
Qualified_ident(THD *thd, const Lex_ident_cli_st &a);
|
||||||
|
Qualified_ident(THD *thd,
|
||||||
|
const Lex_ident_cli_st &a,
|
||||||
|
const Lex_ident_sys_st &b);
|
||||||
|
Qualified_ident(THD *thd,
|
||||||
|
const Lex_ident_cli_st &a,
|
||||||
|
const Lex_ident_sys_st &b,
|
||||||
|
const Lex_ident_sys_st &c);
|
||||||
|
|
||||||
|
Qualified_ident(const Lex_ident_sys_st &a);
|
||||||
|
/*
|
||||||
|
Returns the position of the first character of the identifier in
|
||||||
|
the client string.
|
||||||
|
*/
|
||||||
|
const char *pos() const
|
||||||
|
{
|
||||||
|
return m_cli_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp_variable *spvar() const
|
||||||
|
{
|
||||||
|
return m_spvar;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Lex_ident_sys_st &part(uint i) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(i < array_elements(m_parts));
|
||||||
|
return m_parts[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint defined_parts() const
|
||||||
|
{
|
||||||
|
return m_defined_parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_cli_pos(const char *pos)
|
||||||
|
{
|
||||||
|
m_cli_pos= pos;
|
||||||
|
}
|
||||||
|
void set_spvar(sp_variable *spvar)
|
||||||
|
{
|
||||||
|
m_spvar= spvar;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// this is needed for user_vars hash
|
// this is needed for user_vars hash
|
||||||
class user_var_entry: public Type_handler_hybrid_field_type
|
class user_var_entry: public Type_handler_hybrid_field_type
|
||||||
{
|
{
|
||||||
|
288
sql/sql_lex.cc
288
sql/sql_lex.cc
@ -6709,7 +6709,7 @@ bool LEX::sf_return_fill_definition(const Lex_field_type_st &def)
|
|||||||
|
|
||||||
bool LEX::sf_return_fill_definition_row(Row_definition_list *def)
|
bool LEX::sf_return_fill_definition_row(Row_definition_list *def)
|
||||||
{
|
{
|
||||||
sphead->m_return_field_def.set_row_field_definitions(def);
|
sphead->m_return_field_def.set_row_field_definitions(&type_handler_row, def);
|
||||||
return sphead->fill_spvar_definition(thd, &sphead->m_return_field_def) ||
|
return sphead->fill_spvar_definition(thd, &sphead->m_return_field_def) ||
|
||||||
sphead->row_fill_field_definitions(thd, def);
|
sphead->row_fill_field_definitions(thd, def);
|
||||||
}
|
}
|
||||||
@ -6914,7 +6914,7 @@ LEX::sp_variable_declarations_copy_type_finalize_internal(THD *thd, int nvars,
|
|||||||
if (fields)
|
if (fields)
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(ref.type_handler() == &type_handler_row);
|
DBUG_ASSERT(ref.type_handler() == &type_handler_row);
|
||||||
spvar->field_def.set_row_field_definitions(fields);
|
spvar->field_def.set_row_field_definitions(&type_handler_row, fields);
|
||||||
}
|
}
|
||||||
spvar->field_def.field_name= spvar->name;
|
spvar->field_def.field_name= spvar->name;
|
||||||
}
|
}
|
||||||
@ -6959,6 +6959,41 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Make instructions for:
|
||||||
|
var('key') := expr;
|
||||||
|
var('key').member := expr;
|
||||||
|
*/
|
||||||
|
bool LEX::sp_set_assign_lvalue_function(THD *thd,
|
||||||
|
const Qualified_ident *ident,
|
||||||
|
List<Item> *args,
|
||||||
|
const Lex_ident_sys_st &field_name,
|
||||||
|
Item *item, const LEX_CSTRING &expr_str)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(ident);
|
||||||
|
DBUG_ASSERT(item);
|
||||||
|
|
||||||
|
sp_pcontext *ctx;
|
||||||
|
const Sp_rcontext_handler *rh;
|
||||||
|
|
||||||
|
sp_variable *spv= find_variable(&ident->part(0), &ctx, &rh);
|
||||||
|
if (!spv->type_handler()->has_functors())
|
||||||
|
{
|
||||||
|
spv->type_handler()->raise_bad_data_type_for_functor(*ident);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sp_rcontext_addr addr(rh, spv->offset);
|
||||||
|
item= sphead->adjust_assignment_source(thd, item, nullptr);
|
||||||
|
|
||||||
|
sp_instr *i= spv->type_handler()->
|
||||||
|
create_instr_set_assign_functor(thd, this, *ident, addr,
|
||||||
|
args, field_name,
|
||||||
|
item, expr_str);
|
||||||
|
return !i || sphead->add_instr(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LEX::sp_variable_declarations_row_finalize(THD *thd, int nvars,
|
bool LEX::sp_variable_declarations_row_finalize(THD *thd, int nvars,
|
||||||
Row_definition_list *row,
|
Row_definition_list *row,
|
||||||
Item *dflt_value_item,
|
Item *dflt_value_item,
|
||||||
@ -8717,6 +8752,44 @@ Item_splocal *LEX::create_item_spvar_row_field(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Generate an Item for expressions of these types:
|
||||||
|
1. varname(args)
|
||||||
|
2. varname(args).member
|
||||||
|
|
||||||
|
@param thd - Current thd
|
||||||
|
@param name - The variable name. It's known to be an existing variable.
|
||||||
|
@param args - The list of arguments
|
||||||
|
@param member - The member name. If member.is_null() then it's
|
||||||
|
an expression of the type #1, otherwise of the type #2.
|
||||||
|
@param name_cli - The query fragment for the entire expression,
|
||||||
|
starting from 'ident' and ending after ')' or 'field'.
|
||||||
|
*/
|
||||||
|
Item_splocal *
|
||||||
|
LEX::create_item_functor(THD *thd,
|
||||||
|
const Lex_ident_sys &varname, List<Item> *args,
|
||||||
|
const Lex_ident_sys &member,
|
||||||
|
const Lex_ident_cli_st &name_cli)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!varname.is_null());
|
||||||
|
const Sp_rcontext_handler *rh;
|
||||||
|
sp_variable *spv= find_variable(&varname, &rh);
|
||||||
|
DBUG_ASSERT(spv);
|
||||||
|
DBUG_ASSERT(spv->type_handler()->has_functors());
|
||||||
|
const sp_rcontext_addr addr(rh, spv->offset);
|
||||||
|
Item_splocal *item= spv->type_handler()->create_item_functor(thd, varname,
|
||||||
|
addr, args,
|
||||||
|
member,
|
||||||
|
name_cli);
|
||||||
|
#ifdef DBUG_ASSERT_EXISTS
|
||||||
|
if (item)
|
||||||
|
item->m_sp= sphead;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
my_var *LEX::create_outvar(THD *thd, const Lex_ident_sys_st &name)
|
my_var *LEX::create_outvar(THD *thd, const Lex_ident_sys_st &name)
|
||||||
{
|
{
|
||||||
const Sp_rcontext_handler *rh;
|
const Sp_rcontext_handler *rh;
|
||||||
@ -8753,6 +8826,55 @@ my_var *LEX::create_outvar(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
In a statement like:
|
||||||
|
SELECT val INTO spvar(key); -- if field_name.length == 0 or
|
||||||
|
SELECT val INTO spvar(key).field; -- if field_name.length > 0
|
||||||
|
validate the INTO expression and optionally create a my_var instance.
|
||||||
|
|
||||||
|
spvar is a structured variable, such as an assoc array.
|
||||||
|
We don't support other kinds of lvalue functions yet.
|
||||||
|
|
||||||
|
@param thd - Current thd
|
||||||
|
@param name - The SP variable name
|
||||||
|
@param key - The argument (e.g. an assoc array key value)
|
||||||
|
@param field_name - The field name to be used in the expression
|
||||||
|
spvar(key).field .
|
||||||
|
|
||||||
|
@returns - The pointer to a new my_var created or nullptr.
|
||||||
|
* nullptr if the INTO expression is not a correct
|
||||||
|
lvalue expression.
|
||||||
|
* nullptr if LEX::result is NULL.
|
||||||
|
* nullptr if EOM happened (e.g. during "new").
|
||||||
|
* A pointer to a new my_var instance if
|
||||||
|
LEX::result is not NULL and the lvalue expression
|
||||||
|
spvar(key) is correct.
|
||||||
|
*/
|
||||||
|
my_var *LEX::create_outvar_lvalue_function(THD *thd,
|
||||||
|
const Lex_ident_sys_st &name,
|
||||||
|
Item *key,
|
||||||
|
const Lex_ident_sys &opt_field_name)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(key);
|
||||||
|
// So far we support only data type functors as lvalue functions.
|
||||||
|
const Sp_rcontext_handler *rh;
|
||||||
|
sp_variable *t;
|
||||||
|
if (unlikely(!(t= find_variable(&name, &rh))))
|
||||||
|
{
|
||||||
|
my_error(ER_SP_UNDECLARED_VAR, MYF(0), name.str);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sp_rcontext_addr addr(rh, t->offset);
|
||||||
|
my_var *var= t->type_handler()->make_outvar_lvalue_functor(thd, name, key,
|
||||||
|
opt_field_name,
|
||||||
|
sphead, addr,
|
||||||
|
!result);
|
||||||
|
DBUG_ASSERT(var || thd->is_error() || !result);
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Item *LEX::create_item_func_nextval(THD *thd, Table_ident *table_ident)
|
Item *LEX::create_item_func_nextval(THD *thd, Table_ident *table_ident)
|
||||||
{
|
{
|
||||||
TABLE_LIST *table;
|
TABLE_LIST *table;
|
||||||
@ -8832,11 +8954,22 @@ Item *LEX::create_item_ident(THD *thd,
|
|||||||
Lex_ident_sys a(thd, ca), b(thd, cb);
|
Lex_ident_sys a(thd, ca), b(thd, cb);
|
||||||
if (a.is_null() || b.is_null())
|
if (a.is_null() || b.is_null())
|
||||||
return NULL; // OEM
|
return NULL; // OEM
|
||||||
if ((spv= find_variable(&a, &rh)) &&
|
if ((spv= find_variable(&a, &rh)))
|
||||||
(spv->field_def.is_row() ||
|
{
|
||||||
|
if (spv->field_def.is_row() ||
|
||||||
spv->field_def.is_table_rowtype_ref() ||
|
spv->field_def.is_table_rowtype_ref() ||
|
||||||
spv->field_def.is_cursor_rowtype_ref()))
|
spv->field_def.is_cursor_rowtype_ref())
|
||||||
return create_item_spvar_row_field(thd, rh, &a, &b, spv, start, end);
|
return create_item_spvar_row_field(thd, rh, &a, &b, spv, start, end);
|
||||||
|
if (spv->type_handler()->has_methods())
|
||||||
|
{
|
||||||
|
const Lex_ident_sys sys_a(thd, ca), sys_b(thd, cb);
|
||||||
|
const Lex_ident_cli query_fragment(start, end - start);
|
||||||
|
if (sys_a.is_null() || sys_b.is_null())
|
||||||
|
return nullptr; // EOM
|
||||||
|
return spv->type_handler()->create_item_method(thd, sys_a, sys_b,
|
||||||
|
NULL, query_fragment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ((thd->variables.sql_mode & MODE_ORACLE) && b.length == 7)
|
if ((thd->variables.sql_mode & MODE_ORACLE) && b.length == 7)
|
||||||
{
|
{
|
||||||
@ -9153,6 +9286,22 @@ bool LEX::set_variable(const Lex_ident_sys_st *name1,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LEX::set_variable(const Qualified_ident *ident,
|
||||||
|
Item *item, const LEX_CSTRING &expr_str)
|
||||||
|
{
|
||||||
|
if (unlikely(ident->part(2).length))
|
||||||
|
{
|
||||||
|
thd->parse_error(ER_SYNTAX_ERROR, ident->pos());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ident->part(1).length)
|
||||||
|
return set_variable(&ident->part(0), &ident->part(1), item, expr_str);
|
||||||
|
|
||||||
|
return set_variable(&ident->part(0), item, expr_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool LEX::set_default_system_variable(enum_var_type var_type,
|
bool LEX::set_default_system_variable(enum_var_type var_type,
|
||||||
const Lex_ident_sys_st *name,
|
const Lex_ident_sys_st *name,
|
||||||
Item *val)
|
Item *val)
|
||||||
@ -9911,7 +10060,7 @@ bool LEX::call_statement_start(THD *thd,
|
|||||||
DBUG_ASSERT(db->str);
|
DBUG_ASSERT(db->str);
|
||||||
Identifier_chain2 q_pkg_proc(*pkg, *proc);
|
Identifier_chain2 q_pkg_proc(*pkg, *proc);
|
||||||
sp_name *spname;
|
sp_name *spname;
|
||||||
|
value_list.empty();
|
||||||
sql_command= SQLCOM_CALL;
|
sql_command= SQLCOM_CALL;
|
||||||
|
|
||||||
const Lex_ident_db_normalized dbn= thd->to_ident_db_normalized_with_error(*db);
|
const Lex_ident_db_normalized dbn= thd->to_ident_db_normalized_with_error(*db);
|
||||||
@ -9937,6 +10086,61 @@ bool LEX::call_statement_start(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LEX::call_statement_start(THD *thd, const Qualified_ident *ident)
|
||||||
|
{
|
||||||
|
if (ident->part(2).length)
|
||||||
|
return call_statement_start(thd, &ident->part(0),
|
||||||
|
&ident->part(1), &ident->part(2));
|
||||||
|
else if (ident->part(1).length)
|
||||||
|
return call_statement_start(thd, &ident->part(0), &ident->part(1));
|
||||||
|
|
||||||
|
return call_statement_start(thd, &ident->part(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LEX::call_statement_start_or_lvalue_assign(THD *thd,
|
||||||
|
Qualified_ident *ident)
|
||||||
|
{
|
||||||
|
sp_variable *spv;
|
||||||
|
if (spcont &&
|
||||||
|
(spv= spcont->find_variable(&ident->part(0), false)) &&
|
||||||
|
(likely(spv->field_def.type_handler()->has_methods())))
|
||||||
|
{
|
||||||
|
ident->set_spvar(spv);
|
||||||
|
|
||||||
|
thd->where= THD_WHERE::USE_WHERE_STRING;
|
||||||
|
thd->where_str= "SPVAR LVALUE METHOD";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Direct procedure call (without the CALL keyword)
|
||||||
|
if (unlikely(call_statement_start(thd, ident)))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
thd->where= THD_WHERE::USE_WHERE_STRING;
|
||||||
|
thd->where_str= "CALL";
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LEX::assoc_assign_start(THD *thd, Qualified_ident *ident)
|
||||||
|
{
|
||||||
|
if (unlikely(ident->spvar() == NULL))
|
||||||
|
{
|
||||||
|
thd->parse_error();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
LEX *lex= this;
|
||||||
|
lex->set_stmt_init();
|
||||||
|
if (sp_create_assignment_lex(thd, ident->pos()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
sp_package *LEX::get_sp_package() const
|
sp_package *LEX::get_sp_package() const
|
||||||
{
|
{
|
||||||
return sphead ? sphead->get_package() : NULL;
|
return sphead ? sphead->get_package() : NULL;
|
||||||
@ -10304,6 +10508,36 @@ Item *LEX::make_item_func_call_generic(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item *LEX::make_item_func_or_method_call(THD *thd,
|
||||||
|
const Lex_ident_cli_st &ca,
|
||||||
|
const Lex_ident_cli_st &cb,
|
||||||
|
List<Item> *args,
|
||||||
|
const Lex_ident_cli_st &query_fragment)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(!thd->is_error());
|
||||||
|
const Lex_ident_sys sys_a(thd, &ca), sys_b(thd, &cb);
|
||||||
|
if (sys_a.is_null() || sys_b.is_null())
|
||||||
|
return nullptr; // EOM
|
||||||
|
sp_variable *spv;
|
||||||
|
if (spcont &&
|
||||||
|
(spv= spcont->find_variable(&sys_a, false)) &&
|
||||||
|
spv->type_handler()->has_methods())
|
||||||
|
{
|
||||||
|
if (Item *item= spv->type_handler()->create_item_method(thd,
|
||||||
|
sys_a, sys_b, args,
|
||||||
|
query_fragment))
|
||||||
|
{
|
||||||
|
item->set_name(thd, query_fragment, thd->charset());
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
DBUG_ASSERT(thd->is_error());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return make_item_func_call_generic(thd, &ca, &cb, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Item *LEX::make_item_func_call_generic(THD *thd,
|
Item *LEX::make_item_func_call_generic(THD *thd,
|
||||||
const Lex_ident_db &db,
|
const Lex_ident_db &db,
|
||||||
const Lex_ident_routine &name,
|
const Lex_ident_routine &name,
|
||||||
@ -12454,6 +12688,13 @@ bool LEX::stmt_alter_procedure_start(sp_name *name)
|
|||||||
|
|
||||||
|
|
||||||
Spvar_definition *LEX::row_field_name(THD *thd, const Lex_ident_sys_st &name)
|
Spvar_definition *LEX::row_field_name(THD *thd, const Lex_ident_sys_st &name)
|
||||||
|
{
|
||||||
|
return init_spvar_definition(thd, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Spvar_definition *LEX::init_spvar_definition(THD *thd,
|
||||||
|
const Lex_ident_sys_st &name)
|
||||||
{
|
{
|
||||||
Spvar_definition *res;
|
Spvar_definition *res;
|
||||||
if (unlikely(check_string_char_length(&name, 0, NAME_CHAR_LEN,
|
if (unlikely(check_string_char_length(&name, 0, NAME_CHAR_LEN,
|
||||||
@ -12548,6 +12789,41 @@ bool LEX::set_cast_type_udt(Lex_cast_type_st *type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool LEX::set_field_type_composite(Lex_field_type_st *type,
|
||||||
|
const LEX_CSTRING &name,
|
||||||
|
bool with_collection,
|
||||||
|
bool *is_composite)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(type);
|
||||||
|
DBUG_ASSERT(is_composite);
|
||||||
|
|
||||||
|
sp_type_def *composite= NULL;
|
||||||
|
|
||||||
|
*is_composite= false;
|
||||||
|
if (spcont)
|
||||||
|
{
|
||||||
|
if ((composite= spcont->find_type_def(name, false)))
|
||||||
|
{
|
||||||
|
if (with_collection ||
|
||||||
|
likely(composite->type_handler() == &type_handler_row))
|
||||||
|
{
|
||||||
|
type->set(composite->type_handler(), NULL);
|
||||||
|
last_field->set_attr_const_void_ptr(0, composite);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "nested associative arrays");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*is_composite= true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool sp_expr_lex::sp_repeat_loop_finalize(THD *thd)
|
bool sp_expr_lex::sp_repeat_loop_finalize(THD *thd)
|
||||||
{
|
{
|
||||||
uint ip= sphead->instructions();
|
uint ip= sphead->instructions();
|
||||||
|
@ -165,6 +165,7 @@ class sp_variable;
|
|||||||
class sp_fetch_target;
|
class sp_fetch_target;
|
||||||
class sp_expr_lex;
|
class sp_expr_lex;
|
||||||
class sp_assignment_lex;
|
class sp_assignment_lex;
|
||||||
|
class sp_type_def;
|
||||||
class partition_info;
|
class partition_info;
|
||||||
class Event_parse_data;
|
class Event_parse_data;
|
||||||
class set_var_base;
|
class set_var_base;
|
||||||
@ -3914,6 +3915,11 @@ public:
|
|||||||
const Lex_ident_sys_st *db,
|
const Lex_ident_sys_st *db,
|
||||||
const Lex_ident_sys_st *pkg,
|
const Lex_ident_sys_st *pkg,
|
||||||
const Lex_ident_sys_st *proc);
|
const Lex_ident_sys_st *proc);
|
||||||
|
bool call_statement_start(THD *thd, const Qualified_ident *ident);
|
||||||
|
bool call_statement_start_or_lvalue_assign(THD *thd,
|
||||||
|
Qualified_ident *ident);
|
||||||
|
|
||||||
|
bool assoc_assign_start(THD *thd, Qualified_ident *ident);
|
||||||
sp_variable *find_variable(const LEX_CSTRING *name,
|
sp_variable *find_variable(const LEX_CSTRING *name,
|
||||||
sp_pcontext **ctx,
|
sp_pcontext **ctx,
|
||||||
const Sp_rcontext_handler **rh) const;
|
const Sp_rcontext_handler **rh) const;
|
||||||
@ -3937,6 +3943,8 @@ public:
|
|||||||
bool set_variable(const Lex_ident_sys_st *name1,
|
bool set_variable(const Lex_ident_sys_st *name1,
|
||||||
const Lex_ident_sys_st *name2, Item *item,
|
const Lex_ident_sys_st *name2, Item *item,
|
||||||
const LEX_CSTRING &expr_str);
|
const LEX_CSTRING &expr_str);
|
||||||
|
bool set_variable(const Qualified_ident *ident, Item *item,
|
||||||
|
const LEX_CSTRING &expr_str);
|
||||||
void sp_variable_declarations_init(THD *thd, int nvars);
|
void sp_variable_declarations_init(THD *thd, int nvars);
|
||||||
bool sp_variable_declarations_finalize(THD *thd, int nvars,
|
bool sp_variable_declarations_finalize(THD *thd, int nvars,
|
||||||
const Column_definition *cdef,
|
const Column_definition *cdef,
|
||||||
@ -3944,10 +3952,11 @@ public:
|
|||||||
const LEX_CSTRING &expr_str);
|
const LEX_CSTRING &expr_str);
|
||||||
bool sp_variable_declarations_set_default(THD *thd, int nvars, Item *def,
|
bool sp_variable_declarations_set_default(THD *thd, int nvars, Item *def,
|
||||||
const LEX_CSTRING &expr_str);
|
const LEX_CSTRING &expr_str);
|
||||||
bool sp_variable_declarations_rec_finalize(THD *thd, int nvars,
|
bool sp_set_assign_lvalue_function(THD *thd,
|
||||||
Row_definition_list *src_row,
|
const Qualified_ident *ident,
|
||||||
Item *def,
|
List<Item> *params,
|
||||||
const LEX_CSTRING &expr_str);
|
const Lex_ident_sys_st &field_name,
|
||||||
|
Item *item, const LEX_CSTRING &expr_str);
|
||||||
bool sp_variable_declarations_row_finalize(THD *thd, int nvars,
|
bool sp_variable_declarations_row_finalize(THD *thd, int nvars,
|
||||||
Row_definition_list *row,
|
Row_definition_list *row,
|
||||||
Item *def,
|
Item *def,
|
||||||
@ -4177,6 +4186,17 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create items of this kind:
|
||||||
|
SELECT name(args); -- e.g. spvar_assoc_array('key')
|
||||||
|
SELECT name(args).member; -- e.g. spvar_assoc_array('key').member
|
||||||
|
*/
|
||||||
|
Item_splocal *create_item_functor(THD *thd,
|
||||||
|
const Lex_ident_sys &name,
|
||||||
|
List<Item> *args,
|
||||||
|
const Lex_ident_sys &member,
|
||||||
|
const Lex_ident_cli_st &query_fragment);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create an item for "NEXT VALUE FOR sequence_name"
|
Create an item for "NEXT VALUE FOR sequence_name"
|
||||||
*/
|
*/
|
||||||
@ -4274,6 +4294,12 @@ public:
|
|||||||
Item *make_item_func_call_native_or_parse_error(THD *thd,
|
Item *make_item_func_call_native_or_parse_error(THD *thd,
|
||||||
Lex_ident_cli_st &name,
|
Lex_ident_cli_st &name,
|
||||||
List<Item> *args);
|
List<Item> *args);
|
||||||
|
Item *make_item_func_or_method_call(THD *thd,
|
||||||
|
const Lex_ident_cli_st &ident0,
|
||||||
|
const Lex_ident_cli_st &ident1,
|
||||||
|
List<Item> *args,
|
||||||
|
const Lex_ident_cli_st &query_fragment);
|
||||||
|
|
||||||
my_var *create_outvar(THD *thd, const Lex_ident_sys_st &name);
|
my_var *create_outvar(THD *thd, const Lex_ident_sys_st &name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4287,6 +4313,10 @@ public:
|
|||||||
const Lex_ident_sys_st &var_name,
|
const Lex_ident_sys_st &var_name,
|
||||||
const Lex_ident_sys_st &field_name);
|
const Lex_ident_sys_st &field_name);
|
||||||
|
|
||||||
|
my_var *create_outvar_lvalue_function(THD *thd, const Lex_ident_sys_st &name,
|
||||||
|
Item *arg,
|
||||||
|
const Lex_ident_sys &opt_field_name);
|
||||||
|
|
||||||
bool is_trigger_new_or_old_reference(const LEX_CSTRING *name) const;
|
bool is_trigger_new_or_old_reference(const LEX_CSTRING *name) const;
|
||||||
|
|
||||||
Item *create_and_link_Item_trigger_field(THD *thd, const LEX_CSTRING *name,
|
Item *create_and_link_Item_trigger_field(THD *thd, const LEX_CSTRING *name,
|
||||||
@ -4949,6 +4979,8 @@ public:
|
|||||||
sp_condition_value *stmt_signal_value(const Lex_ident_sys_st &ident);
|
sp_condition_value *stmt_signal_value(const Lex_ident_sys_st &ident);
|
||||||
|
|
||||||
Spvar_definition *row_field_name(THD *thd, const Lex_ident_sys_st &name);
|
Spvar_definition *row_field_name(THD *thd, const Lex_ident_sys_st &name);
|
||||||
|
Spvar_definition *init_spvar_definition(THD *thd,
|
||||||
|
const Lex_ident_sys_st &name);
|
||||||
|
|
||||||
bool set_field_type_udt(Lex_field_type_st *type,
|
bool set_field_type_udt(Lex_field_type_st *type,
|
||||||
const LEX_CSTRING &name,
|
const LEX_CSTRING &name,
|
||||||
@ -4956,6 +4988,11 @@ public:
|
|||||||
bool set_cast_type_udt(Lex_cast_type_st *type,
|
bool set_cast_type_udt(Lex_cast_type_st *type,
|
||||||
const LEX_CSTRING &name);
|
const LEX_CSTRING &name);
|
||||||
|
|
||||||
|
bool set_field_type_composite(Lex_field_type_st *type,
|
||||||
|
const LEX_CSTRING &name,
|
||||||
|
bool with_collection,
|
||||||
|
bool *is_composite);
|
||||||
|
|
||||||
bool map_data_type(const Lex_ident_sys_st &schema,
|
bool map_data_type(const Lex_ident_sys_st &schema,
|
||||||
Lex_field_type_st *type) const;
|
Lex_field_type_st *type) const;
|
||||||
|
|
||||||
|
@ -800,6 +800,15 @@ void Binary_string::qs_append(ulonglong i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Binary_string::qs_append_int64(longlong i)
|
||||||
|
{
|
||||||
|
char *buff= Ptr + str_length;
|
||||||
|
char *end= longlong10_to_str(i, buff, -10);
|
||||||
|
ASSERT_LENGTH((size_t) (end-buff));
|
||||||
|
str_length+= (uint32) (end-buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Binary_string::copy_printable_hhhh(CHARSET_INFO *to_cs,
|
bool Binary_string::copy_printable_hhhh(CHARSET_INFO *to_cs,
|
||||||
CHARSET_INFO *from_cs,
|
CHARSET_INFO *from_cs,
|
||||||
const char *from,
|
const char *from,
|
||||||
|
@ -392,6 +392,12 @@ public:
|
|||||||
int4store(Ptr + str_length, n);
|
int4store(Ptr + str_length, n);
|
||||||
str_length += 4;
|
str_length += 4;
|
||||||
}
|
}
|
||||||
|
void q_append_int64(const longlong n)
|
||||||
|
{
|
||||||
|
ASSERT_LENGTH(8);
|
||||||
|
int8store(Ptr + str_length, n);
|
||||||
|
str_length += 8;
|
||||||
|
}
|
||||||
void q_append(double d)
|
void q_append(double d)
|
||||||
{
|
{
|
||||||
ASSERT_LENGTH(8);
|
ASSERT_LENGTH(8);
|
||||||
@ -475,6 +481,8 @@ public:
|
|||||||
str_length+= (uint32) (end-buff);
|
str_length+= (uint32) (end-buff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void qs_append_int64(longlong i);
|
||||||
|
|
||||||
/* Mark variable thread specific it it's not allocated already */
|
/* Mark variable thread specific it it's not allocated already */
|
||||||
inline void set_thread_specific()
|
inline void set_thread_specific()
|
||||||
{
|
{
|
||||||
|
369
sql/sql_type.cc
369
sql/sql_type.cc
@ -123,8 +123,6 @@ bool DTCollation::merge_collation(Sql_used *used,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Named_type_handler<Type_handler_row> type_handler_row("row");
|
|
||||||
|
|
||||||
Named_type_handler<Type_handler_null> type_handler_null("null");
|
Named_type_handler<Type_handler_null> type_handler_null("null");
|
||||||
|
|
||||||
Named_type_handler<Type_handler_bool> type_handler_bool("boolean");
|
Named_type_handler<Type_handler_bool> type_handler_bool("boolean");
|
||||||
@ -217,55 +215,6 @@ bool Type_handler::is_traditional_scalar_type() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Type_collection_row: public Type_collection
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
bool init(Type_handler_data *data) override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const Type_handler *aggregate_for_result(const Type_handler *a,
|
|
||||||
const Type_handler *b)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
const Type_handler *aggregate_for_comparison(const Type_handler *a,
|
|
||||||
const Type_handler *b)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Allowed combinations:
|
|
||||||
ROW+ROW, NULL+ROW, ROW+NULL
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(a == &type_handler_row || a == &type_handler_null);
|
|
||||||
DBUG_ASSERT(b == &type_handler_row || b == &type_handler_null);
|
|
||||||
DBUG_ASSERT(a == &type_handler_row || b == &type_handler_row);
|
|
||||||
return &type_handler_row;
|
|
||||||
}
|
|
||||||
const Type_handler *aggregate_for_min_max(const Type_handler *a,
|
|
||||||
const Type_handler *b)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
const Type_handler *aggregate_for_num_op(const Type_handler *a,
|
|
||||||
const Type_handler *b)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static Type_collection_row type_collection_row;
|
|
||||||
|
|
||||||
const Type_collection *Type_handler_row::type_collection() const
|
|
||||||
{
|
|
||||||
return &type_collection_row;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_data::init()
|
bool Type_handler_data::init()
|
||||||
{
|
{
|
||||||
return type_collection_geometry.init(this);
|
return type_collection_geometry.init(this);
|
||||||
@ -1771,11 +1720,6 @@ const Type_handler *Type_handler_timestamp_common::type_handler_for_comparison()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const Type_handler *Type_handler_row::type_handler_for_comparison() const
|
|
||||||
{
|
|
||||||
return &type_handler_row;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
const Type_handler *
|
const Type_handler *
|
||||||
@ -3128,19 +3072,6 @@ bool Type_handler_null::
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Column_definition_prepare_stage1(THD *thd,
|
|
||||||
MEM_ROOT *mem_root,
|
|
||||||
Column_definition *def,
|
|
||||||
column_definition_type_t type,
|
|
||||||
const Column_derived_attributes
|
|
||||||
*derived_attr)
|
|
||||||
const
|
|
||||||
{
|
|
||||||
def->charset= &my_charset_bin;
|
|
||||||
def->create_length_to_internal_length_null();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type_handler_temporal_result::
|
bool Type_handler_temporal_result::
|
||||||
Column_definition_prepare_stage1(THD *thd,
|
Column_definition_prepare_stage1(THD *thd,
|
||||||
@ -3446,24 +3377,6 @@ bool Type_handler_bit::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************/
|
|
||||||
bool Type_handler_row::Spvar_definition_with_complex_data_types(
|
|
||||||
Spvar_definition *def) const
|
|
||||||
{
|
|
||||||
if (def->row_field_definitions())
|
|
||||||
{
|
|
||||||
List_iterator<Spvar_definition> it(*(def->row_field_definitions()));
|
|
||||||
Spvar_definition *member;
|
|
||||||
while ((member= it++))
|
|
||||||
{
|
|
||||||
if (member->type_handler()->is_complex())
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
bool Type_handler::Key_part_spec_init_primary(Key_part_spec *part,
|
bool Type_handler::Key_part_spec_init_primary(Key_part_spec *part,
|
||||||
const Column_definition &def,
|
const Column_definition &def,
|
||||||
@ -3699,6 +3612,23 @@ my_var *Type_handler::make_outvar_field(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
SELECT 1 INTO spvar(arg);
|
||||||
|
SELECT 1 INTO spvar(arg).field;
|
||||||
|
*/
|
||||||
|
my_var *Type_handler::make_outvar_lvalue_functor(THD *thd,
|
||||||
|
const Lex_ident_sys_st &name,
|
||||||
|
Item *arg,
|
||||||
|
const Lex_ident_sys &opt_field,
|
||||||
|
sp_head *sphead,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
bool validate_only) const
|
||||||
|
{
|
||||||
|
raise_bad_data_type_for_functor(Qualified_ident(name));
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
Field *Type_handler::make_and_init_table_field(MEM_ROOT *root,
|
Field *Type_handler::make_and_init_table_field(MEM_ROOT *root,
|
||||||
const LEX_CSTRING *name,
|
const LEX_CSTRING *name,
|
||||||
@ -4393,13 +4323,6 @@ Type_handler_bit::Bit_decimal_notation_int_digits_by_nbits(uint nbits)
|
|||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
void Type_handler_row::Item_update_null_value(Item *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
item->null_value= true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Type_handler_time_common::Item_update_null_value(Item *item) const
|
void Type_handler_time_common::Item_update_null_value(Item *item) const
|
||||||
{
|
{
|
||||||
MYSQL_TIME ltime;
|
MYSQL_TIME ltime;
|
||||||
@ -4514,12 +4437,6 @@ int Type_handler_bool::Item_save_in_field(Item *item, Field *field,
|
|||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
set_comparator_func(THD *thd, Arg_comparator *cmp) const
|
|
||||||
{
|
|
||||||
return cmp->set_cmp_func_row(thd);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
set_comparator_func(THD *thd, Arg_comparator *cmp) const
|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
|
||||||
{
|
{
|
||||||
@ -4660,12 +4577,6 @@ bool Type_handler_numeric::
|
|||||||
|
|
||||||
/*************************************************************************/
|
/*************************************************************************/
|
||||||
|
|
||||||
Item_cache *
|
|
||||||
Type_handler_row::Item_get_cache(THD *thd, const Item *item) const
|
|
||||||
{
|
|
||||||
return new (thd->mem_root) Item_cache_row(thd);
|
|
||||||
}
|
|
||||||
|
|
||||||
Item_cache *
|
Item_cache *
|
||||||
Type_handler_int_result::Item_get_cache(THD *thd, const Item *item) const
|
Type_handler_int_result::Item_get_cache(THD *thd, const Item *item) const
|
||||||
{
|
{
|
||||||
@ -5379,6 +5290,32 @@ Type_handler::Item_func_hybrid_field_type_val_ref(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Type_handler::
|
||||||
|
raise_bad_data_type_for_functor(const Qualified_ident &ident,
|
||||||
|
const Lex_ident_sys &field) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(ident.defined_parts() > 0 && ident.defined_parts() <= 3);
|
||||||
|
|
||||||
|
char param[MYSQL_ERRMSG_SIZE];
|
||||||
|
uint used= 0;
|
||||||
|
for (uint i= 0; i < ident.defined_parts() && used < sizeof(param); i++)
|
||||||
|
{
|
||||||
|
used+= my_snprintf(param + used,
|
||||||
|
sizeof(param) - used,
|
||||||
|
"%sQ.",
|
||||||
|
ident.part(i).str);
|
||||||
|
}
|
||||||
|
used-= 1;
|
||||||
|
if (!field.str)
|
||||||
|
my_snprintf(param + used, sizeof(param) - used, "(..)");
|
||||||
|
else
|
||||||
|
my_snprintf(param + used, sizeof(param) - used, "(..).%sQ", field.str);
|
||||||
|
|
||||||
|
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
|
||||||
|
name().ptr(), param);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
void Type_handler_decimal_result::Item_get_date(THD *thd, Item *item,
|
void Type_handler_decimal_result::Item_get_date(THD *thd, Item *item,
|
||||||
Temporal::Warn *warn,
|
Temporal::Warn *warn,
|
||||||
@ -5927,14 +5864,6 @@ bool Type_handler_string_result::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
longlong Type_handler_row::
|
|
||||||
Item_func_between_val_int(Item_func_between *func) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
func->null_value= true;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
longlong Type_handler_string_result::
|
longlong Type_handler_string_result::
|
||||||
Item_func_between_val_int(Item_func_between *func) const
|
Item_func_between_val_int(Item_func_between *func) const
|
||||||
{
|
{
|
||||||
@ -6004,12 +5933,6 @@ cmp_item *Type_handler_string_result::make_cmp_item(THD *thd,
|
|||||||
return new (thd->mem_root) cmp_item_sort_string(cs);
|
return new (thd->mem_root) cmp_item_sort_string(cs);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmp_item *Type_handler_row::make_cmp_item(THD *thd,
|
|
||||||
CHARSET_INFO *cs) const
|
|
||||||
{
|
|
||||||
return new (thd->mem_root) cmp_item_row;
|
|
||||||
}
|
|
||||||
|
|
||||||
cmp_item *Type_handler_time_common::make_cmp_item(THD *thd,
|
cmp_item *Type_handler_time_common::make_cmp_item(THD *thd,
|
||||||
CHARSET_INFO *cs) const
|
CHARSET_INFO *cs) const
|
||||||
{
|
{
|
||||||
@ -6096,13 +6019,6 @@ Type_handler_timestamp_common::make_in_vector(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
in_vector *Type_handler_row::make_in_vector(THD *thd,
|
|
||||||
const Item_func_in *func,
|
|
||||||
uint nargs) const
|
|
||||||
{
|
|
||||||
return new (thd->mem_root) in_row(thd, nargs, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_string_result::
|
bool Type_handler_string_result::
|
||||||
@ -6173,14 +6089,6 @@ bool Type_handler_temporal_result::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_row::Item_func_in_fix_comparator_compatible_types(THD *thd,
|
|
||||||
Item_func_in *func) const
|
|
||||||
{
|
|
||||||
return func->compatible_types_row_bisection_possible() ?
|
|
||||||
func->fix_for_row_comparison_using_bisection(thd) :
|
|
||||||
func->fix_for_row_comparison_using_cmp_items(thd);
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
String *Type_handler_string_result::
|
String *Type_handler_string_result::
|
||||||
@ -6449,32 +6357,6 @@ bool Type_handler_timestamp_common::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
/**
|
|
||||||
Get a string representation of the Item value.
|
|
||||||
See sql_type.h for details.
|
|
||||||
*/
|
|
||||||
String *Type_handler_row::
|
|
||||||
print_item_value(THD *thd, Item *item, String *str) const
|
|
||||||
{
|
|
||||||
CHARSET_INFO *cs= thd->variables.character_set_client;
|
|
||||||
StringBuffer<STRING_BUFFER_USUAL_SIZE> val(cs);
|
|
||||||
str->append(STRING_WITH_LEN("ROW("));
|
|
||||||
for (uint i= 0 ; i < item->cols(); i++)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
str->append(',');
|
|
||||||
Item *elem= item->element_index(i);
|
|
||||||
String *tmp= elem->type_handler()->print_item_value(thd, elem, &val);
|
|
||||||
if (tmp)
|
|
||||||
str->append(*tmp);
|
|
||||||
else
|
|
||||||
str->append(NULL_clex_str);
|
|
||||||
}
|
|
||||||
str->append(')');
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Get a string representation of the Item value,
|
Get a string representation of the Item value,
|
||||||
using the character string format with its charset and collation, e.g.
|
using the character string format with its charset and collation, e.g.
|
||||||
@ -6513,6 +6395,18 @@ String *Type_handler_numeric::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
String *Type_handler_bool::
|
||||||
|
print_item_value(THD *thd, Item *item, String *str) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(item->fixed());
|
||||||
|
bool b=item->val_bool();
|
||||||
|
if (item->null_value)
|
||||||
|
return 0;
|
||||||
|
str->set_int(b, item->unsigned_flag, item->collation.collation);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String *Type_handler::
|
String *Type_handler::
|
||||||
print_item_value_temporal(THD *thd, Item *item, String *str,
|
print_item_value_temporal(THD *thd, Item *item, String *str,
|
||||||
const Name &type_name, String *buf) const
|
const Name &type_name, String *buf) const
|
||||||
@ -6567,14 +6461,6 @@ String *Type_handler_timestamp_common::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||||
{
|
{
|
||||||
@ -6685,14 +6571,6 @@ bool Type_handler_string_result::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
|
Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
|
||||||
{
|
{
|
||||||
@ -6797,14 +6675,6 @@ bool Type_handler_string_result::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
|
Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
|
||||||
{
|
{
|
||||||
@ -6855,14 +6725,6 @@ bool Type_handler_string_result::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
|
Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
|
||||||
{
|
{
|
||||||
@ -7070,14 +6932,6 @@ bool Type_handler::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
|
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
|
||||||
{
|
{
|
||||||
@ -7119,14 +6973,6 @@ bool Type_handler_string_result::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
|
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
|
||||||
{
|
{
|
||||||
@ -7168,14 +7014,6 @@ bool Type_handler_string_result::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
|
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
|
||||||
{
|
{
|
||||||
@ -7217,14 +7055,6 @@ bool Type_handler_string_result::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_div_fix_length_and_dec(Item_func_div *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_div_fix_length_and_dec(Item_func_div *item) const
|
Item_func_div_fix_length_and_dec(Item_func_div *item) const
|
||||||
{
|
{
|
||||||
@ -7266,14 +7096,6 @@ bool Type_handler_string_result::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
|
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
|
||||||
{
|
{
|
||||||
@ -7588,15 +7410,6 @@ bool Type_handler_null::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_save_in_value(THD *thd, Item *item, st_value *value) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
value->m_type= DYN_COL_NULL;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::
|
bool Type_handler_int_result::
|
||||||
Item_save_in_value(THD *thd, Item *item, st_value *value) const
|
Item_save_in_value(THD *thd, Item *item, st_value *value) const
|
||||||
{
|
{
|
||||||
@ -7657,18 +7470,6 @@ bool Type_handler_time_common::
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::
|
|
||||||
Item_param_set_from_value(THD *thd,
|
|
||||||
Item_param *param,
|
|
||||||
const Type_all_attributes *attr,
|
|
||||||
const st_value *val) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
param->set_null();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_real_result::
|
bool Type_handler_real_result::
|
||||||
Item_param_set_from_value(THD *thd,
|
Item_param_set_from_value(THD *thd,
|
||||||
Item_param *param,
|
Item_param *param,
|
||||||
@ -7937,38 +7738,6 @@ Item *Type_handler_temporal_with_date::
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Item *Type_handler_row::
|
|
||||||
make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
|
|
||||||
{
|
|
||||||
if (item->type() == Item::ROW_ITEM && cmp->type() == Item::ROW_ITEM)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
Substitute constants only in Item_row's. Don't affect other Items
|
|
||||||
with ROW_RESULT (eg Item_singlerow_subselect).
|
|
||||||
|
|
||||||
For such Items more optimal is to detect if it is constant and replace
|
|
||||||
it with Item_row. This would optimize queries like this:
|
|
||||||
SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1);
|
|
||||||
*/
|
|
||||||
Item_row *item_row= (Item_row*) item;
|
|
||||||
Item_row *comp_item_row= (Item_row*) cmp;
|
|
||||||
uint col;
|
|
||||||
/*
|
|
||||||
If item and comp_item are both Item_row's and have same number of cols
|
|
||||||
then process items in Item_row one by one.
|
|
||||||
We can't ignore NULL values here as this item may be used with <=>, in
|
|
||||||
which case NULL's are significant.
|
|
||||||
*/
|
|
||||||
DBUG_ASSERT(item->result_type() == cmp->result_type());
|
|
||||||
DBUG_ASSERT(item_row->cols() == comp_item_row->cols());
|
|
||||||
col= item_row->cols();
|
|
||||||
while (col-- > 0)
|
|
||||||
resolve_const_item(thd, item_row->addr(col),
|
|
||||||
comp_item_row->element_index(col));
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -8403,19 +8172,6 @@ void Type_handler_typelib::Item_param_set_param_func(Item_param *param,
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
Field *Type_handler_row::
|
|
||||||
make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
|
|
||||||
const LEX_CSTRING *name,
|
|
||||||
const Record_addr &rec, const Bit_addr &bit,
|
|
||||||
const Column_definition_attributes *attr,
|
|
||||||
uint32 flags) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(attr->length == 0);
|
|
||||||
DBUG_ASSERT(f_maybe_null(attr->pack_flag));
|
|
||||||
return new (mem_root) Field_row(rec.ptr(), name);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Field *Type_handler_olddecimal::
|
Field *Type_handler_olddecimal::
|
||||||
make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
|
make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
|
||||||
const LEX_CSTRING *name,
|
const LEX_CSTRING *name,
|
||||||
@ -9146,14 +8902,6 @@ Type_handler_hex_hybrid::cast_to_int_type_handler() const
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
bool Type_handler_row::Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
|
|
||||||
Item *a, Item *b) const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_int_result::Item_eq_value(THD *thd,
|
bool Type_handler_int_result::Item_eq_value(THD *thd,
|
||||||
const Type_cmp_attributes *attr,
|
const Type_cmp_attributes *attr,
|
||||||
Item *a, Item *b) const
|
Item *a, Item *b) const
|
||||||
@ -9646,13 +9394,6 @@ bool Type_handler_datetime_common::validate_implicit_default_value(THD *thd,
|
|||||||
|
|
||||||
/***************************************************************************/
|
/***************************************************************************/
|
||||||
|
|
||||||
const Name & Type_handler_row::default_value() const
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(0);
|
|
||||||
static Name def(STRING_WITH_LEN(""));
|
|
||||||
return def;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Name & Type_handler_numeric::default_value() const
|
const Name & Type_handler_numeric::default_value() const
|
||||||
{
|
{
|
||||||
static Name def(STRING_WITH_LEN("0"));
|
static Name def(STRING_WITH_LEN("0"));
|
||||||
|
147
sql/sql_type.h
147
sql/sql_type.h
@ -35,6 +35,7 @@ C_MODE_START
|
|||||||
C_MODE_END
|
C_MODE_END
|
||||||
|
|
||||||
class Field;
|
class Field;
|
||||||
|
class Qualified_ident;
|
||||||
class Column_definition;
|
class Column_definition;
|
||||||
class Column_definition_attributes;
|
class Column_definition_attributes;
|
||||||
class Key_part_spec;
|
class Key_part_spec;
|
||||||
@ -79,6 +80,7 @@ class Item_func_mul;
|
|||||||
class Item_func_div;
|
class Item_func_div;
|
||||||
class Item_func_mod;
|
class Item_func_mod;
|
||||||
class Item_type_holder;
|
class Item_type_holder;
|
||||||
|
class Item_splocal;
|
||||||
class cmp_item;
|
class cmp_item;
|
||||||
class in_vector;
|
class in_vector;
|
||||||
class Type_handler_data;
|
class Type_handler_data;
|
||||||
@ -98,8 +100,10 @@ class Conv_source;
|
|||||||
class ST_FIELD_INFO;
|
class ST_FIELD_INFO;
|
||||||
class Type_collection;
|
class Type_collection;
|
||||||
class Create_func;
|
class Create_func;
|
||||||
|
class Type_handler_composite;
|
||||||
class sp_type_def;
|
class sp_type_def;
|
||||||
class sp_head;
|
class sp_head;
|
||||||
|
class sp_instr;
|
||||||
class my_var;
|
class my_var;
|
||||||
|
|
||||||
#define my_charset_numeric my_charset_latin1
|
#define my_charset_numeric my_charset_latin1
|
||||||
@ -4135,6 +4139,15 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Convert "this" to a composite type handler.
|
||||||
|
Scalar type handlers return nullptr meaning that they are not composite.
|
||||||
|
*/
|
||||||
|
virtual const Type_handler_composite *to_composite() const
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool partition_field_check(const LEX_CSTRING &field_name, Item *)
|
virtual bool partition_field_check(const LEX_CSTRING &field_name, Item *)
|
||||||
const
|
const
|
||||||
{
|
{
|
||||||
@ -4185,6 +4198,12 @@ public:
|
|||||||
virtual bool can_return_extract_source(interval_type type) const;
|
virtual bool can_return_extract_source(interval_type type) const;
|
||||||
virtual bool is_bool_type() const { return false; }
|
virtual bool is_bool_type() const { return false; }
|
||||||
virtual bool is_general_purpose_string_type() const { return false; }
|
virtual bool is_general_purpose_string_type() const { return false; }
|
||||||
|
virtual bool has_methods() const { return false; }
|
||||||
|
/*
|
||||||
|
If an SP variable supports: spvar(expr_list).
|
||||||
|
For example, assoc arrays support: spvar_assoc_array('key')
|
||||||
|
*/
|
||||||
|
virtual bool has_functors() const { return false; }
|
||||||
virtual bool has_null_predicate() const { return true; }
|
virtual bool has_null_predicate() const { return true; }
|
||||||
virtual decimal_digits_t Item_time_precision(THD *thd, Item *item) const;
|
virtual decimal_digits_t Item_time_precision(THD *thd, Item *item) const;
|
||||||
virtual decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const;
|
virtual decimal_digits_t Item_datetime_precision(THD *thd, Item *item) const;
|
||||||
@ -4409,6 +4428,17 @@ public:
|
|||||||
const Lex_ident_sys_st &field,
|
const Lex_ident_sys_st &field,
|
||||||
sp_head *sphead,
|
sp_head *sphead,
|
||||||
bool validate_only) const;
|
bool validate_only) const;
|
||||||
|
/*
|
||||||
|
SELECT 1 INTO spvar(arg);
|
||||||
|
SELECT 1 INTO spvar(arg).field;
|
||||||
|
*/
|
||||||
|
virtual my_var *make_outvar_lvalue_functor(THD *thd,
|
||||||
|
const Lex_ident_sys_st &name,
|
||||||
|
Item *arg,
|
||||||
|
const Lex_ident_sys &opt_field,
|
||||||
|
sp_head *sphead,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
bool validate_only) const;
|
||||||
virtual void
|
virtual void
|
||||||
Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
|
Column_definition_attributes_frm_pack(const Column_definition_attributes *at,
|
||||||
uchar *buff) const;
|
uchar *buff) const;
|
||||||
@ -4627,6 +4657,50 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
virtual Item_copy *create_item_copy(THD *thd, Item *item) const;
|
virtual Item_copy *create_item_copy(THD *thd, Item *item) const;
|
||||||
|
/*
|
||||||
|
Create an Item for an expression of this kind:
|
||||||
|
SELECT spvar(args); -- e.g. spvar_assoc_array('key')
|
||||||
|
SELECT spvar(args).field; -- e.g. spvar_assoc_array('key').field
|
||||||
|
*/
|
||||||
|
virtual Item_splocal *create_item_functor(THD *thd,
|
||||||
|
const Lex_ident_sys &a,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
List<Item> *item_list,
|
||||||
|
const Lex_ident_sys &b,
|
||||||
|
const Lex_ident_cli_st &name)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0); // Should have checked has_functors().
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
Generate instructions for:
|
||||||
|
spvar(args) := expr; -- e.g. spvar_assoc_array('key') := 10;
|
||||||
|
spvar(args).member := expr; -- e.g. spvar_assoc_array('key').field:= 10;
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
sp_instr *create_instr_set_assign_functor(THD *thd, LEX *lex,
|
||||||
|
const Qualified_ident &ident,
|
||||||
|
const sp_rcontext_addr &addr,
|
||||||
|
List<Item> *args,
|
||||||
|
const Lex_ident_sys_st &member,
|
||||||
|
Item *item,
|
||||||
|
const LEX_CSTRING &expr_str) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0); // Should have checked has_functors().
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
virtual Item *create_item_method(THD *thd,
|
||||||
|
const Lex_ident_sys &ca,
|
||||||
|
const Lex_ident_sys &cb,
|
||||||
|
List<Item> *args,
|
||||||
|
const Lex_ident_cli_st &query_fragment)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0); // Should have checked has_methods().
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
virtual int cmp_native(const Native &a, const Native &b) const
|
virtual int cmp_native(const Native &a, const Native &b) const
|
||||||
{
|
{
|
||||||
MY_ASSERT_UNREACHABLE();
|
MY_ASSERT_UNREACHABLE();
|
||||||
@ -4778,6 +4852,10 @@ public:
|
|||||||
Item_func_mod_fix_length_and_dec(Item_func_mod *func) const= 0;
|
Item_func_mod_fix_length_and_dec(Item_func_mod *func) const= 0;
|
||||||
|
|
||||||
virtual const Vers_type_handler *vers() const { return NULL; }
|
virtual const Vers_type_handler *vers() const { return NULL; }
|
||||||
|
|
||||||
|
void raise_bad_data_type_for_functor(const Qualified_ident &ident,
|
||||||
|
const Lex_ident_sys &field=
|
||||||
|
Lex_ident_sys()) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -5076,14 +5154,53 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Type_limits_int
|
class Type_range_int
|
||||||
|
{
|
||||||
|
const longlong m_min_signed;
|
||||||
|
const longlong m_max_signed;
|
||||||
|
const ulonglong m_max_unsigned;
|
||||||
|
public:
|
||||||
|
Type_range_int(longlong min_signed, longlong max_signed,
|
||||||
|
ulonglong max_unsigned)
|
||||||
|
:m_min_signed(min_signed), m_max_signed(max_signed),
|
||||||
|
m_max_unsigned(max_unsigned)
|
||||||
|
{ }
|
||||||
|
longlong min_signed() const { return m_min_signed; }
|
||||||
|
longlong max_signed() const { return m_max_signed; }
|
||||||
|
ulonglong max_unsigned() const { return m_max_unsigned; }
|
||||||
|
|
||||||
|
static Type_range_int range8()
|
||||||
|
{
|
||||||
|
return Type_range_int(INT_MIN8, INT_MAX8, UINT_MAX8);
|
||||||
|
}
|
||||||
|
static Type_range_int range16()
|
||||||
|
{
|
||||||
|
return Type_range_int(INT_MIN16, INT_MAX16, UINT_MAX16);
|
||||||
|
}
|
||||||
|
static Type_range_int range24()
|
||||||
|
{
|
||||||
|
return Type_range_int(INT_MIN24, INT_MAX24, UINT_MAX24);
|
||||||
|
}
|
||||||
|
static Type_range_int range32()
|
||||||
|
{
|
||||||
|
return Type_range_int(INT_MIN32, INT_MAX32, UINT_MAX32);
|
||||||
|
}
|
||||||
|
static Type_range_int range64()
|
||||||
|
{
|
||||||
|
return Type_range_int(INT_MIN64, INT_MAX64, UINT64_MAX);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Type_limits_int: public Type_range_int
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint32 m_precision;
|
uint32 m_precision;
|
||||||
uint32 m_char_length;
|
uint32 m_char_length;
|
||||||
public:
|
public:
|
||||||
Type_limits_int(uint32 prec, uint32 nchars)
|
Type_limits_int(uint32 prec, uint32 nchars, const Type_range_int &range)
|
||||||
:m_precision(prec), m_char_length(nchars)
|
:Type_range_int(range),
|
||||||
|
m_precision(prec), m_char_length(nchars)
|
||||||
{ }
|
{ }
|
||||||
uint32 precision() const { return m_precision; }
|
uint32 precision() const { return m_precision; }
|
||||||
uint32 char_length() const { return m_char_length; }
|
uint32 char_length() const { return m_char_length; }
|
||||||
@ -5098,7 +5215,7 @@ class Type_limits_uint8: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_uint8()
|
Type_limits_uint8()
|
||||||
:Type_limits_int(MAX_TINYINT_WIDTH, MAX_TINYINT_WIDTH)
|
:Type_limits_int(MAX_TINYINT_WIDTH, MAX_TINYINT_WIDTH, range8())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5107,7 +5224,7 @@ class Type_limits_sint8: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_sint8()
|
Type_limits_sint8()
|
||||||
:Type_limits_int(MAX_TINYINT_WIDTH, MAX_TINYINT_WIDTH + 1)
|
:Type_limits_int(MAX_TINYINT_WIDTH, MAX_TINYINT_WIDTH + 1, range8())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5120,7 +5237,7 @@ class Type_limits_uint16: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_uint16()
|
Type_limits_uint16()
|
||||||
:Type_limits_int(MAX_SMALLINT_WIDTH, MAX_SMALLINT_WIDTH)
|
:Type_limits_int(MAX_SMALLINT_WIDTH, MAX_SMALLINT_WIDTH, range16())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5129,7 +5246,7 @@ class Type_limits_sint16: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_sint16()
|
Type_limits_sint16()
|
||||||
:Type_limits_int(MAX_SMALLINT_WIDTH, MAX_SMALLINT_WIDTH + 1)
|
:Type_limits_int(MAX_SMALLINT_WIDTH, MAX_SMALLINT_WIDTH + 1, range16())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5142,7 +5259,7 @@ class Type_limits_uint24: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_uint24()
|
Type_limits_uint24()
|
||||||
:Type_limits_int(MAX_MEDIUMINT_WIDTH, MAX_MEDIUMINT_WIDTH)
|
:Type_limits_int(MAX_MEDIUMINT_WIDTH, MAX_MEDIUMINT_WIDTH, range24())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5151,7 +5268,7 @@ class Type_limits_sint24: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_sint24()
|
Type_limits_sint24()
|
||||||
:Type_limits_int(MAX_MEDIUMINT_WIDTH - 1, MAX_MEDIUMINT_WIDTH)
|
:Type_limits_int(MAX_MEDIUMINT_WIDTH - 1, MAX_MEDIUMINT_WIDTH, range24())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5164,7 +5281,7 @@ class Type_limits_uint32: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_uint32()
|
Type_limits_uint32()
|
||||||
:Type_limits_int(MAX_INT_WIDTH, MAX_INT_WIDTH)
|
:Type_limits_int(MAX_INT_WIDTH, MAX_INT_WIDTH, range32())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5174,7 +5291,7 @@ class Type_limits_sint32: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_sint32()
|
Type_limits_sint32()
|
||||||
:Type_limits_int(MAX_INT_WIDTH, MAX_INT_WIDTH + 1)
|
:Type_limits_int(MAX_INT_WIDTH, MAX_INT_WIDTH + 1, range32())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5186,7 +5303,8 @@ public:
|
|||||||
class Type_limits_uint64: public Type_limits_int
|
class Type_limits_uint64: public Type_limits_int
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_uint64(): Type_limits_int(MAX_BIGINT_WIDTH, MAX_BIGINT_WIDTH)
|
Type_limits_uint64()
|
||||||
|
:Type_limits_int(MAX_BIGINT_WIDTH, MAX_BIGINT_WIDTH, range64())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5195,7 +5313,7 @@ class Type_limits_sint64: public Type_limits_int
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Type_limits_sint64()
|
Type_limits_sint64()
|
||||||
:Type_limits_int(MAX_BIGINT_WIDTH - 1, MAX_BIGINT_WIDTH)
|
:Type_limits_int(MAX_BIGINT_WIDTH - 1, MAX_BIGINT_WIDTH, range64())
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -5817,6 +5935,7 @@ public:
|
|||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
|
||||||
int Item_save_in_field(Item *item, Field *field, bool no_conversions)
|
int Item_save_in_field(Item *item, Field *field, bool no_conversions)
|
||||||
const override;
|
const override;
|
||||||
|
String *print_item_value(THD *thd, Item *item, String *str) const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -7615,7 +7734,7 @@ class Named_type_handler : public TypeHandler
|
|||||||
{ Type_handler::set_name(Name(n, static_cast<uint>(strlen(n)))); }
|
{ Type_handler::set_name(Name(n, static_cast<uint>(strlen(n)))); }
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Named_type_handler<Type_handler_row> type_handler_row;
|
extern const Type_handler_composite &type_handler_row;
|
||||||
extern Named_type_handler<Type_handler_null> type_handler_null;
|
extern Named_type_handler<Type_handler_null> type_handler_null;
|
||||||
|
|
||||||
extern Named_type_handler<Type_handler_float> type_handler_float;
|
extern Named_type_handler<Type_handler_float> type_handler_float;
|
||||||
|
211
sql/sql_type_composite.cc
Normal file
211
sql/sql_type_composite.cc
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2025, Rakuten Securities
|
||||||
|
Copyright (c) 2025, MariaDB plc
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; version 2 of
|
||||||
|
the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
*/
|
||||||
|
#include "sql_type.h"
|
||||||
|
#include "sql_type_composite.h"
|
||||||
|
#include "item.h"
|
||||||
|
#include "item_cmpfunc.h"
|
||||||
|
#include "sp_head.h"
|
||||||
|
|
||||||
|
|
||||||
|
const Name & Type_handler_composite::default_value() const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
static Name def(STRING_WITH_LEN(""));
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
sp_variable_declarations_row_finalize(THD *thd, LEX *lex, int nvars,
|
||||||
|
Row_definition_list *row)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(row);
|
||||||
|
/*
|
||||||
|
Prepare all row fields.
|
||||||
|
Note, we do it only one time outside of the below loop.
|
||||||
|
The converted list in "row" is further reused by all variable
|
||||||
|
declarations processed by the current call.
|
||||||
|
Example:
|
||||||
|
DECLARE
|
||||||
|
a, b, c ROW(x VARCHAR(10) CHARACTER SET utf8);
|
||||||
|
BEGIN
|
||||||
|
...
|
||||||
|
END;
|
||||||
|
*/
|
||||||
|
if (lex->sphead->row_fill_field_definitions(thd, row))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (uint i= 0 ; i < (uint) nvars ; i++)
|
||||||
|
{
|
||||||
|
uint offset= (uint) nvars - 1 - i;
|
||||||
|
sp_variable *spvar= lex->spcont->get_last_context_variable(offset);
|
||||||
|
spvar->field_def.set_row_field_definitions(&type_handler_row, row);
|
||||||
|
if (lex->sphead->fill_spvar_definition(thd, &spvar->field_def,
|
||||||
|
&spvar->name))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Column_definition_prepare_stage1(THD *thd,
|
||||||
|
MEM_ROOT *mem_root,
|
||||||
|
Column_definition *def,
|
||||||
|
column_definition_type_t type,
|
||||||
|
const Column_derived_attributes
|
||||||
|
*derived_attr)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
def->charset= &my_charset_bin;
|
||||||
|
def->create_length_to_internal_length_null();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::Item_eq_value(THD *thd,
|
||||||
|
const Type_cmp_attributes *attr,
|
||||||
|
Item *a, Item *b) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_save_in_value(THD *thd, Item *item, st_value *value) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
value->m_type= DYN_COL_NULL;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_param_set_from_value(THD *thd,
|
||||||
|
Item_param *param,
|
||||||
|
const Type_all_attributes *attr,
|
||||||
|
const st_value *val) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
param->set_null();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Type_handler_composite::Item_update_null_value(Item *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
item->null_value= true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
longlong Type_handler_composite::
|
||||||
|
Item_func_between_val_int(Item_func_between *func) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
func->null_value= true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_round_fix_length_and_dec(Item_func_round *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_int_val_fix_length_and_dec(Item_func_int_val *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_abs_fix_length_and_dec(Item_func_abs *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_neg_fix_length_and_dec(Item_func_neg *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_plus_fix_length_and_dec(Item_func_plus *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_minus_fix_length_and_dec(Item_func_minus *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_mul_fix_length_and_dec(Item_func_mul *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_div_fix_length_and_dec(Item_func_div *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_func_mod_fix_length_and_dec(Item_func_mod *item) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_composite::
|
||||||
|
Item_hybrid_func_fix_attributes(THD *thd,
|
||||||
|
const LEX_CSTRING &opname,
|
||||||
|
Type_handler_hybrid_field_type *,
|
||||||
|
Type_all_attributes *atrr,
|
||||||
|
Item **items, uint nitems)
|
||||||
|
const
|
||||||
|
{
|
||||||
|
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
|
||||||
|
name().ptr(), opname.str);
|
||||||
|
return true;
|
||||||
|
}
|
425
sql/sql_type_composite.h
Normal file
425
sql/sql_type_composite.h
Normal file
@ -0,0 +1,425 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2025, Rakuten Securities
|
||||||
|
Copyright (c) 2025, MariaDB plc
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License
|
||||||
|
as published by the Free Software Foundation; version 2 of
|
||||||
|
the License.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
|
||||||
|
*/
|
||||||
|
#ifndef SQL_TYPE_COMPOSITE_INCLUDED
|
||||||
|
#define SQL_TYPE_COMPOSITE_INCLUDED
|
||||||
|
|
||||||
|
#include "sql_type.h"
|
||||||
|
|
||||||
|
class Item_splocal;
|
||||||
|
class Field_composite;
|
||||||
|
class Item_composite;
|
||||||
|
class Item_field;
|
||||||
|
class Row_definition_list;
|
||||||
|
|
||||||
|
class Type_handler_composite: public Type_handler
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static bool sp_variable_declarations_row_finalize(THD *thd, LEX *lex,
|
||||||
|
int nvars,
|
||||||
|
Row_definition_list *row);
|
||||||
|
public:
|
||||||
|
virtual ~Type_handler_composite() = default;
|
||||||
|
const Name &default_value() const override;
|
||||||
|
bool validate_implicit_default_value(THD *, const Column_definition &)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
const Type_handler_composite *to_composite() const override
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
bool is_scalar_type() const override { return false; }
|
||||||
|
bool can_return_int() const override { return false; }
|
||||||
|
bool can_return_decimal() const override { return false; }
|
||||||
|
bool can_return_real() const override { return false; }
|
||||||
|
bool can_return_str() const override { return false; }
|
||||||
|
bool can_return_text() const override { return false; }
|
||||||
|
bool can_return_date() const override { return false; }
|
||||||
|
bool can_return_time() const override { return false; }
|
||||||
|
enum_field_types field_type() const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return MYSQL_TYPE_NULL;
|
||||||
|
};
|
||||||
|
protocol_send_type_t protocol_send_type() const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return PROTOCOL_SEND_STRING;
|
||||||
|
}
|
||||||
|
Item_result result_type() const override
|
||||||
|
{
|
||||||
|
return ROW_RESULT;
|
||||||
|
}
|
||||||
|
Item_result cmp_type() const override
|
||||||
|
{
|
||||||
|
return ROW_RESULT;
|
||||||
|
}
|
||||||
|
enum_dynamic_column_type dyncol_type(const Type_all_attributes *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return DYN_COL_NULL;
|
||||||
|
}
|
||||||
|
int stored_field_cmp_to_item(THD *, Field *, Item *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool subquery_type_allows_materialization(const Item *, const Item *, bool)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
Field *make_conversion_table_field(MEM_ROOT *, TABLE *, uint, const Field *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
bool Column_definition_fix_attributes(Column_definition *) const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void Column_definition_reuse_fix_attributes(THD *, Column_definition *,
|
||||||
|
const Field *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
}
|
||||||
|
bool Column_definition_prepare_stage1(THD *thd,
|
||||||
|
MEM_ROOT *mem_root,
|
||||||
|
Column_definition *c,
|
||||||
|
column_definition_type_t type,
|
||||||
|
const Column_derived_attributes
|
||||||
|
*derived_attr)
|
||||||
|
const override;
|
||||||
|
bool Column_definition_redefine_stage1(Column_definition *,
|
||||||
|
const Column_definition *,
|
||||||
|
const handler *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Column_definition_prepare_stage2(Column_definition *, handler *,
|
||||||
|
ulonglong) const override
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Field *make_table_field(MEM_ROOT *, const LEX_CSTRING *, const Record_addr &,
|
||||||
|
const Type_all_attributes &, TABLE_SHARE *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void make_sort_key_part(uchar *to, Item *item,
|
||||||
|
const SORT_FIELD_ATTR *sort_field,
|
||||||
|
String *tmp) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
}
|
||||||
|
uint make_packed_sort_key_part(uchar *, Item *, const SORT_FIELD_ATTR *,
|
||||||
|
String *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
void sort_length(THD *, const Type_std_attributes *, SORT_FIELD_ATTR *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
}
|
||||||
|
uint32 max_display_length(const Item *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint32 max_display_length_for_field(const Conv_source &) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint32 calc_pack_length(uint32) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
|
||||||
|
Item *a, Item *b) const override;
|
||||||
|
decimal_digits_t Item_decimal_precision(const Item *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return DECIMAL_MAX_PRECISION;
|
||||||
|
}
|
||||||
|
bool Item_save_in_value(THD *thd, Item *item, st_value *value) const
|
||||||
|
override;
|
||||||
|
bool Item_param_set_from_value(THD *thd,
|
||||||
|
Item_param *param,
|
||||||
|
const Type_all_attributes *attr,
|
||||||
|
const st_value *value) const override;
|
||||||
|
bool Item_send(Item *, Protocol *, st_value *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
void Item_update_null_value(Item *item) const override;
|
||||||
|
int Item_save_in_field(Item *, Field *, bool) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
bool can_change_cond_ref_to_const(Item_bool_func2 *, Item *, Item *,
|
||||||
|
Item_bool_func2 *, Item *, Item *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Item_copy *create_item_copy(THD *, Item *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
bool Item_hybrid_func_fix_attributes(THD *thd,
|
||||||
|
const LEX_CSTRING &name,
|
||||||
|
Type_handler_hybrid_field_type *,
|
||||||
|
Type_all_attributes *atrr,
|
||||||
|
Item **items, uint nitems)
|
||||||
|
const override;
|
||||||
|
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_val_bool(Item *item) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
void Item_get_date(THD *, Item *, Temporal::Warn *, MYSQL_TIME *ltime,
|
||||||
|
date_mode_t) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
|
||||||
|
}
|
||||||
|
longlong Item_val_int_signed_typecast(Item *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
longlong Item_val_int_unsigned_typecast(Item *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
String *Item_func_hex_val_str_ascii(Item_func_hex *, String *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
|
||||||
|
String *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
my_decimal *Item_func_hybrid_field_type_val_decimal(
|
||||||
|
Item_func_hybrid_field_type *,
|
||||||
|
my_decimal *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
void Item_func_hybrid_field_type_get_date(THD *,
|
||||||
|
Item_func_hybrid_field_type *,
|
||||||
|
Temporal::Warn *,
|
||||||
|
MYSQL_TIME *ltime,
|
||||||
|
date_mode_t) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
double Item_func_min_max_val_real(Item_func_min_max *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
longlong Item_func_min_max_val_int(Item_func_min_max *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
||||||
|
my_decimal *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
bool Item_func_min_max_get_date(THD *, Item_func_min_max*, MYSQL_TIME *,
|
||||||
|
date_mode_t) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_func_between_fix_length_and_dec(Item_func_between *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
longlong Item_func_between_val_int(Item_func_between *func) const override;
|
||||||
|
bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
|
||||||
|
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const
|
||||||
|
override;
|
||||||
|
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
|
||||||
|
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
|
||||||
|
|
||||||
|
bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const
|
||||||
|
override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
MY_ASSERT_UNREACHABLE();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
|
||||||
|
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
|
||||||
|
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
|
||||||
|
bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
|
||||||
|
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
|
||||||
|
|
||||||
|
virtual bool key_to_lex_cstring(THD *thd, Item **key,
|
||||||
|
const LEX_CSTRING& name,
|
||||||
|
LEX_CSTRING& out_key) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Get the index of the item with the given name in the composite item.
|
||||||
|
|
||||||
|
This is only implemented for composite items that have a fixed number of
|
||||||
|
fields, such as ROWs.
|
||||||
|
*/
|
||||||
|
virtual bool get_item_index(THD *thd, const Item_field *item,
|
||||||
|
const LEX_CSTRING& name, uint& idx) const = 0;
|
||||||
|
virtual Item_field *get_item(THD *thd, const Item_field *item,
|
||||||
|
const LEX_CSTRING& name) const = 0;
|
||||||
|
virtual Item_field *get_or_create_item(THD *thd, Item_field *item,
|
||||||
|
const LEX_CSTRING& name) const = 0;
|
||||||
|
|
||||||
|
virtual void prepare_for_set(Item_field *item) const
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
virtual bool finalize_for_set(Item_field *item) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* SQL_TYPE_COMPOSITE_INCLUDED */
|
@ -23,40 +23,61 @@
|
|||||||
#include "field.h"
|
#include "field.h"
|
||||||
#include "sp_rcontext.h"
|
#include "sp_rcontext.h"
|
||||||
#include "sp_type_def.h"
|
#include "sp_type_def.h"
|
||||||
#include "sp_head.h"
|
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_row::
|
class Type_collection_row: public Type_collection
|
||||||
sp_variable_declarations_row_finalize(THD *thd, LEX *lex, int nvars,
|
|
||||||
Row_definition_list *row)
|
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(row);
|
public:
|
||||||
/*
|
bool init(Type_handler_data *data) override
|
||||||
Prepare all row fields.
|
|
||||||
Note, we do it only one time outside of the below loop.
|
|
||||||
The converted list in "row" is further reused by all variable
|
|
||||||
declarations processed by the current call.
|
|
||||||
Example:
|
|
||||||
DECLARE
|
|
||||||
a, b, c ROW(x VARCHAR(10) CHARACTER SET utf8);
|
|
||||||
BEGIN
|
|
||||||
...
|
|
||||||
END;
|
|
||||||
*/
|
|
||||||
if (lex->sphead->row_fill_field_definitions(thd, row))
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (uint i= 0 ; i < (uint) nvars ; i++)
|
|
||||||
{
|
{
|
||||||
uint offset= (uint) nvars - 1 - i;
|
|
||||||
sp_variable *spvar= lex->spcont->get_last_context_variable(offset);
|
|
||||||
spvar->field_def.set_row_field_definitions(row);
|
|
||||||
if (lex->sphead->fill_spvar_definition(thd, &spvar->field_def,
|
|
||||||
&spvar->name))
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const Type_handler *aggregate_for_result(const Type_handler *a,
|
||||||
|
const Type_handler *b)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const Type_handler *aggregate_for_comparison(const Type_handler *a,
|
||||||
|
const Type_handler *b)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Allowed combinations:
|
||||||
|
ROW+ROW, NULL+ROW, ROW+NULL
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(a == &type_handler_row || a == &type_handler_null);
|
||||||
|
DBUG_ASSERT(b == &type_handler_row || b == &type_handler_null);
|
||||||
|
DBUG_ASSERT(a == &type_handler_row || b == &type_handler_row);
|
||||||
|
return &type_handler_row;
|
||||||
|
}
|
||||||
|
const Type_handler *aggregate_for_min_max(const Type_handler *a,
|
||||||
|
const Type_handler *b)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const Type_handler *aggregate_for_num_op(const Type_handler *a,
|
||||||
|
const Type_handler *b)
|
||||||
|
const override
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static Type_collection_row type_collection_row;
|
||||||
|
|
||||||
|
const Type_collection *Type_handler_row::type_collection() const
|
||||||
|
{
|
||||||
|
return &type_collection_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const Type_handler *Type_handler_row::type_handler_for_comparison() const
|
||||||
|
{
|
||||||
|
return &type_handler_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class my_var_sp_row: public my_var_sp
|
class my_var_sp_row: public my_var_sp
|
||||||
@ -170,6 +191,23 @@ Item_field *Field_row::make_item_field_spvar(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_row::Spvar_definition_with_complex_data_types(
|
||||||
|
Spvar_definition *def) const
|
||||||
|
{
|
||||||
|
if (def->row_field_definitions() && def->is_row())
|
||||||
|
{
|
||||||
|
List_iterator<Spvar_definition> it(*(def->row_field_definitions()));
|
||||||
|
Spvar_definition *member;
|
||||||
|
while ((member= it++))
|
||||||
|
{
|
||||||
|
if (member->type_handler()->is_complex())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Type_handler_row::
|
Type_handler_row::
|
||||||
sp_variable_declarations_finalize(THD *thd, LEX *lex, int nvars,
|
sp_variable_declarations_finalize(THD *thd, LEX *lex, int nvars,
|
||||||
@ -188,13 +226,117 @@ Type_handler_row::
|
|||||||
// TYPE row_t IS RECORD
|
// TYPE row_t IS RECORD
|
||||||
Row_definition_list *row= rec->field->deep_copy(thd);
|
Row_definition_list *row= rec->field->deep_copy(thd);
|
||||||
return row == nullptr ||
|
return row == nullptr ||
|
||||||
Type_handler_row::sp_variable_declarations_row_finalize(thd,
|
Type_handler_composite::sp_variable_declarations_row_finalize(thd,
|
||||||
lex,
|
lex,
|
||||||
nvars,
|
nvars,
|
||||||
row);
|
row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Type_handler_row::
|
||||||
|
set_comparator_func(THD *thd, Arg_comparator *cmp) const
|
||||||
|
{
|
||||||
|
return cmp->set_cmp_func_row(thd);
|
||||||
|
}
|
||||||
|
|
||||||
|
Item_cache *
|
||||||
|
Type_handler_row::Item_get_cache(THD *thd, const Item *item) const
|
||||||
|
{
|
||||||
|
return new (thd->mem_root) Item_cache_row(thd);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmp_item *Type_handler_row::make_cmp_item(THD *thd,
|
||||||
|
CHARSET_INFO *cs) const
|
||||||
|
{
|
||||||
|
return new (thd->mem_root) cmp_item_row;
|
||||||
|
}
|
||||||
|
|
||||||
|
in_vector *Type_handler_row::make_in_vector(THD *thd,
|
||||||
|
const Item_func_in *func,
|
||||||
|
uint nargs) const
|
||||||
|
{
|
||||||
|
return new (thd->mem_root) in_row(thd, nargs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Type_handler_row::Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||||
|
Item_func_in *func) const
|
||||||
|
{
|
||||||
|
return func->compatible_types_row_bisection_possible() ?
|
||||||
|
func->fix_for_row_comparison_using_bisection(thd) :
|
||||||
|
func->fix_for_row_comparison_using_cmp_items(thd);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Get a string representation of the Item value.
|
||||||
|
See sql_type.h for details.
|
||||||
|
*/
|
||||||
|
String *Type_handler_row::
|
||||||
|
print_item_value(THD *thd, Item *item, String *str) const
|
||||||
|
{
|
||||||
|
CHARSET_INFO *cs= thd->variables.character_set_client;
|
||||||
|
StringBuffer<STRING_BUFFER_USUAL_SIZE> val(cs);
|
||||||
|
str->append(STRING_WITH_LEN("ROW("));
|
||||||
|
for (uint i= 0 ; i < item->cols(); i++)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
str->append(',');
|
||||||
|
Item *elem= item->element_index(i);
|
||||||
|
String *tmp= elem->type_handler()->print_item_value(thd, elem, &val);
|
||||||
|
if (tmp)
|
||||||
|
str->append(*tmp);
|
||||||
|
else
|
||||||
|
str->append(NULL_clex_str);
|
||||||
|
}
|
||||||
|
str->append(')');
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item *Type_handler_row::
|
||||||
|
make_const_item_for_comparison(THD *thd, Item *item, const Item *cmp) const
|
||||||
|
{
|
||||||
|
if (item->type() == Item::ROW_ITEM && cmp->type() == Item::ROW_ITEM)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Substitute constants only in Item_row's. Don't affect other Items
|
||||||
|
with ROW_RESULT (eg Item_singlerow_subselect).
|
||||||
|
|
||||||
|
For such Items more optimal is to detect if it is constant and replace
|
||||||
|
it with Item_row. This would optimize queries like this:
|
||||||
|
SELECT * FROM t1 WHERE (a,b) = (SELECT a,b FROM t2 LIMIT 1);
|
||||||
|
*/
|
||||||
|
Item_row *item_row= (Item_row*) item;
|
||||||
|
Item_row *comp_item_row= (Item_row*) cmp;
|
||||||
|
uint col;
|
||||||
|
/*
|
||||||
|
If item and comp_item are both Item_row's and have same number of cols
|
||||||
|
then process items in Item_row one by one.
|
||||||
|
We can't ignore NULL values here as this item may be used with <=>, in
|
||||||
|
which case NULL's are significant.
|
||||||
|
*/
|
||||||
|
DBUG_ASSERT(item->result_type() == cmp->result_type());
|
||||||
|
DBUG_ASSERT(item_row->cols() == comp_item_row->cols());
|
||||||
|
col= item_row->cols();
|
||||||
|
while (col-- > 0)
|
||||||
|
resolve_const_item(thd, item_row->addr(col),
|
||||||
|
comp_item_row->element_index(col));
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Field *Type_handler_row::
|
||||||
|
make_table_field_from_def(TABLE_SHARE *share, MEM_ROOT *mem_root,
|
||||||
|
const LEX_CSTRING *name,
|
||||||
|
const Record_addr &rec, const Bit_addr &bit,
|
||||||
|
const Column_definition_attributes *attr,
|
||||||
|
uint32 flags) const
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(attr->length == 0);
|
||||||
|
DBUG_ASSERT(f_maybe_null(attr->pack_flag));
|
||||||
|
return new (mem_root) Field_row(rec.ptr(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Item *Type_handler_row::make_typedef_constructor_item(THD *thd,
|
Item *Type_handler_row::make_typedef_constructor_item(THD *thd,
|
||||||
const sp_type_def &def,
|
const sp_type_def &def,
|
||||||
List<Item> *args) const
|
List<Item> *args) const
|
||||||
@ -209,15 +351,40 @@ Item *Type_handler_row::make_typedef_constructor_item(THD *thd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Type_handler_row::
|
bool Type_handler_row::get_item_index(THD *thd,
|
||||||
Item_hybrid_func_fix_attributes(THD *thd,
|
const Item_field *item,
|
||||||
const LEX_CSTRING &opname,
|
const LEX_CSTRING& name,
|
||||||
Type_handler_hybrid_field_type *,
|
uint& idx) const
|
||||||
Type_all_attributes *atrr,
|
|
||||||
Item **items, uint nitems)
|
|
||||||
const
|
|
||||||
{
|
{
|
||||||
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
|
auto item_row=
|
||||||
name().ptr(), opname.str);
|
dynamic_cast<Item_field_row *>(const_cast<Item_field *> (item));
|
||||||
|
DBUG_ASSERT(item_row);
|
||||||
|
|
||||||
|
auto vtable= item_row->field->virtual_tmp_table();
|
||||||
|
if (!vtable)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
return vtable->sp_find_field_by_name_or_error(&idx,
|
||||||
|
item_row->field->field_name,
|
||||||
|
name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item_field *Type_handler_row::get_item(THD *thd,
|
||||||
|
const Item_field *item,
|
||||||
|
const LEX_CSTRING& name) const
|
||||||
|
{
|
||||||
|
auto item_row=
|
||||||
|
dynamic_cast<Item_field_row *>(const_cast<Item_field *> (item));
|
||||||
|
DBUG_ASSERT(item_row);
|
||||||
|
|
||||||
|
uint field_idx;
|
||||||
|
if (get_item_index(thd, item_row, name, field_idx))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
return item_row->element_index(field_idx)->field_for_view_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Named_type_handler<Type_handler_row> type_handler_row_internal("row");
|
||||||
|
const Type_handler_composite &type_handler_row=
|
||||||
|
type_handler_row_internal;
|
||||||
|
@ -20,127 +20,26 @@
|
|||||||
#define SQL_TYPE_ROW_INCLUDED
|
#define SQL_TYPE_ROW_INCLUDED
|
||||||
|
|
||||||
|
|
||||||
|
#include "sql_type_composite.h"
|
||||||
|
|
||||||
class Row_definition_list;
|
class Row_definition_list;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Special handler for ROW
|
Special handler for ROW
|
||||||
*/
|
*/
|
||||||
class Type_handler_row: public Type_handler
|
class Type_handler_row: public Type_handler_composite
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
static bool sp_variable_declarations_row_finalize(THD *thd, LEX *lex,
|
|
||||||
int nvars,
|
|
||||||
Row_definition_list *row);
|
|
||||||
public:
|
public:
|
||||||
virtual ~Type_handler_row() = default;
|
virtual ~Type_handler_row() = default;
|
||||||
const Name &default_value() const override;
|
|
||||||
bool validate_implicit_default_value(THD *, const Column_definition &)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const Type_collection *type_collection() const override;
|
const Type_collection *type_collection() const override;
|
||||||
bool is_scalar_type() const override { return false; }
|
|
||||||
bool can_return_int() const override { return false; }
|
|
||||||
bool can_return_decimal() const override { return false; }
|
|
||||||
bool can_return_real() const override { return false; }
|
|
||||||
bool can_return_str() const override { return false; }
|
|
||||||
bool can_return_text() const override { return false; }
|
|
||||||
bool can_return_date() const override { return false; }
|
|
||||||
bool can_return_time() const override { return false; }
|
|
||||||
enum_field_types field_type() const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return MYSQL_TYPE_NULL;
|
|
||||||
};
|
|
||||||
protocol_send_type_t protocol_send_type() const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return PROTOCOL_SEND_STRING;
|
|
||||||
}
|
|
||||||
Item_result result_type() const override
|
|
||||||
{
|
|
||||||
return ROW_RESULT;
|
|
||||||
}
|
|
||||||
Item_result cmp_type() const override
|
|
||||||
{
|
|
||||||
return ROW_RESULT;
|
|
||||||
}
|
|
||||||
enum_dynamic_column_type dyncol_type(const Type_all_attributes *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return DYN_COL_NULL;
|
|
||||||
}
|
|
||||||
const Type_handler *type_handler_for_comparison() const override;
|
const Type_handler *type_handler_for_comparison() const override;
|
||||||
bool has_null_predicate() const override { return false; }
|
bool has_null_predicate() const override { return false; }
|
||||||
int stored_field_cmp_to_item(THD *, Field *, Item *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
bool subquery_type_allows_materialization(const Item *, const Item *, bool)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Field *make_num_distinct_aggregator_field(MEM_ROOT *, const Item *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
Field *make_conversion_table_field(MEM_ROOT *, TABLE *, uint, const Field *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
bool Column_definition_fix_attributes(Column_definition *) const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void Column_definition_reuse_fix_attributes(THD *, Column_definition *,
|
|
||||||
const Field *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
bool Column_definition_prepare_stage1(THD *thd,
|
|
||||||
MEM_ROOT *mem_root,
|
|
||||||
Column_definition *c,
|
|
||||||
column_definition_type_t type,
|
|
||||||
const Column_derived_attributes
|
|
||||||
*derived_attr)
|
|
||||||
const override;
|
|
||||||
bool Column_definition_redefine_stage1(Column_definition *,
|
|
||||||
const Column_definition *,
|
|
||||||
const handler *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Column_definition_prepare_stage2(Column_definition *, handler *,
|
|
||||||
ulonglong) const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
bool Spvar_definition_with_complex_data_types(Spvar_definition *def)
|
bool Spvar_definition_with_complex_data_types(Spvar_definition *def)
|
||||||
const override;
|
const override;
|
||||||
bool sp_variable_declarations_finalize(THD *thd,
|
bool sp_variable_declarations_finalize(THD *thd,
|
||||||
LEX *lex, int nvars,
|
LEX *lex, int nvars,
|
||||||
const Column_definition &def)
|
const Column_definition &def)
|
||||||
const override;
|
const override;
|
||||||
|
|
||||||
Field *make_table_field(MEM_ROOT *, const LEX_CSTRING *, const Record_addr &,
|
|
||||||
const Type_all_attributes &, TABLE_SHARE *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
Field *make_table_field_from_def(TABLE_SHARE *share,
|
Field *make_table_field_from_def(TABLE_SHARE *share,
|
||||||
MEM_ROOT *mem_root,
|
MEM_ROOT *mem_root,
|
||||||
const LEX_CSTRING *name,
|
const LEX_CSTRING *name,
|
||||||
@ -148,62 +47,6 @@ public:
|
|||||||
const Bit_addr &bit,
|
const Bit_addr &bit,
|
||||||
const Column_definition_attributes *attr,
|
const Column_definition_attributes *attr,
|
||||||
uint32 flags) const override;
|
uint32 flags) const override;
|
||||||
void make_sort_key_part(uchar *to, Item *item,
|
|
||||||
const SORT_FIELD_ATTR *sort_field,
|
|
||||||
String *tmp) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
uint make_packed_sort_key_part(uchar *, Item *, const SORT_FIELD_ATTR *,
|
|
||||||
String *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
void sort_length(THD *, const Type_std_attributes *, SORT_FIELD_ATTR *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
}
|
|
||||||
uint32 max_display_length(const Item *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint32 max_display_length_for_field(const Conv_source &) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
uint32 calc_pack_length(uint32) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
bool Item_eq_value(THD *thd, const Type_cmp_attributes *attr,
|
|
||||||
Item *a, Item *b) const override;
|
|
||||||
decimal_digits_t Item_decimal_precision(const Item *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return DECIMAL_MAX_PRECISION;
|
|
||||||
}
|
|
||||||
bool Item_save_in_value(THD *thd, Item *item, st_value *value) const
|
|
||||||
override;
|
|
||||||
bool Item_param_set_from_value(THD *thd,
|
|
||||||
Item_param *param,
|
|
||||||
const Type_all_attributes *attr,
|
|
||||||
const st_value *value) const override;
|
|
||||||
bool Item_send(Item *, Protocol *, st_value *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
void Item_update_null_value(Item *item) const override;
|
|
||||||
int Item_save_in_field(Item *, Field *, bool) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
// SELECT 1,2,3 INTO spvar_row;
|
// SELECT 1,2,3 INTO spvar_row;
|
||||||
my_var *make_outvar(THD *thd,
|
my_var *make_outvar(THD *thd,
|
||||||
const Lex_ident_sys_st &name,
|
const Lex_ident_sys_st &name,
|
||||||
@ -218,216 +61,31 @@ public:
|
|||||||
sp_head *sphead,
|
sp_head *sphead,
|
||||||
bool validate_only) const override;
|
bool validate_only) const override;
|
||||||
String *print_item_value(THD *thd, Item *item, String *str) const override;
|
String *print_item_value(THD *thd, Item *item, String *str) const override;
|
||||||
bool can_change_cond_ref_to_const(Item_bool_func2 *, Item *, Item *,
|
|
||||||
Item_bool_func2 *, Item *, Item *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
|
Item *make_const_item_for_comparison(THD *, Item *src, const Item *cmp) const
|
||||||
override;
|
override;
|
||||||
Item *make_typedef_constructor_item(THD *thd, const sp_type_def &def,
|
Item *make_typedef_constructor_item(THD *thd, const sp_type_def &def,
|
||||||
List<Item> *arg_list) const override;
|
List<Item> *arg_list) const override;
|
||||||
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
|
Item_cache *Item_get_cache(THD *thd, const Item *item) const override;
|
||||||
Item_copy *create_item_copy(THD *, Item *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override;
|
bool set_comparator_func(THD *thd, Arg_comparator *cmp) const override;
|
||||||
bool Item_hybrid_func_fix_attributes(THD *thd,
|
|
||||||
const LEX_CSTRING &name,
|
|
||||||
Type_handler_hybrid_field_type *,
|
|
||||||
Type_all_attributes *atrr,
|
|
||||||
Item **items, uint nitems)
|
|
||||||
const override;
|
|
||||||
bool Item_sum_hybrid_fix_length_and_dec(Item_sum_hybrid *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_sum_sum_fix_length_and_dec(Item_sum_sum *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_sum_avg_fix_length_and_dec(Item_sum_avg *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_sum_variance_fix_length_and_dec(Item_sum_variance *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_val_bool(Item *item) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void Item_get_date(THD *, Item *, Temporal::Warn *, MYSQL_TIME *ltime,
|
|
||||||
date_mode_t) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
|
|
||||||
}
|
|
||||||
longlong Item_val_int_signed_typecast(Item *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
longlong Item_val_int_unsigned_typecast(Item *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
String *Item_func_hex_val_str_ascii(Item_func_hex *, String *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
String *Item_func_hybrid_field_type_val_str(Item_func_hybrid_field_type *,
|
|
||||||
String *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
double Item_func_hybrid_field_type_val_real(Item_func_hybrid_field_type *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
longlong Item_func_hybrid_field_type_val_int(Item_func_hybrid_field_type *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
my_decimal *Item_func_hybrid_field_type_val_decimal(
|
|
||||||
Item_func_hybrid_field_type *,
|
|
||||||
my_decimal *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
void Item_func_hybrid_field_type_get_date(THD *,
|
|
||||||
Item_func_hybrid_field_type *,
|
|
||||||
Temporal::Warn *,
|
|
||||||
MYSQL_TIME *ltime,
|
|
||||||
date_mode_t) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
set_zero_time(ltime, MYSQL_TIMESTAMP_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
String *Item_func_min_max_val_str(Item_func_min_max *, String *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
double Item_func_min_max_val_real(Item_func_min_max *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
longlong Item_func_min_max_val_int(Item_func_min_max *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
my_decimal *Item_func_min_max_val_decimal(Item_func_min_max *,
|
|
||||||
my_decimal *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
bool Item_func_min_max_get_date(THD *, Item_func_min_max*, MYSQL_TIME *,
|
|
||||||
date_mode_t) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_func_between_fix_length_and_dec(Item_func_between *) const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
longlong Item_func_between_val_int(Item_func_between *func) const override;
|
|
||||||
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
|
cmp_item *make_cmp_item(THD *thd, CHARSET_INFO *cs) const override;
|
||||||
in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const
|
in_vector *make_in_vector(THD *thd, const Item_func_in *f, uint nargs) const
|
||||||
override;
|
override;
|
||||||
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
bool Item_func_in_fix_comparator_compatible_types(THD *thd,
|
||||||
Item_func_in *) const
|
Item_func_in *) const
|
||||||
override;
|
override;
|
||||||
bool Item_func_round_fix_length_and_dec(Item_func_round *) const override;
|
bool get_item_index(THD *thd,
|
||||||
bool Item_func_int_val_fix_length_and_dec(Item_func_int_val *) const
|
const Item_field *item,
|
||||||
override;
|
const LEX_CSTRING& name,
|
||||||
bool Item_func_abs_fix_length_and_dec(Item_func_abs *) const override;
|
uint& idx) const override;
|
||||||
bool Item_func_neg_fix_length_and_dec(Item_func_neg *) const override;
|
Item_field *get_item(THD *thd,
|
||||||
|
const Item_field *item,
|
||||||
bool Item_func_signed_fix_length_and_dec(Item_func_signed *) const override
|
const LEX_CSTRING& name) const override;
|
||||||
|
Item_field *get_or_create_item(THD *thd,
|
||||||
|
Item_field *item,
|
||||||
|
const LEX_CSTRING& name) const override
|
||||||
{
|
{
|
||||||
MY_ASSERT_UNREACHABLE();
|
return get_item(thd, const_cast<const Item_field *>(item), name);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
bool Item_func_unsigned_fix_length_and_dec(Item_func_unsigned *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_double_typecast_fix_length_and_dec(Item_double_typecast *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_float_typecast_fix_length_and_dec(Item_float_typecast *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_decimal_typecast_fix_length_and_dec(Item_decimal_typecast *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_char_typecast_fix_length_and_dec(Item_char_typecast *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_time_typecast_fix_length_and_dec(Item_time_typecast *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_date_typecast_fix_length_and_dec(Item_date_typecast *) const
|
|
||||||
override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
bool Item_datetime_typecast_fix_length_and_dec(Item_datetime_typecast *)
|
|
||||||
const override
|
|
||||||
{
|
|
||||||
MY_ASSERT_UNREACHABLE();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Item_func_plus_fix_length_and_dec(Item_func_plus *) const override;
|
|
||||||
bool Item_func_minus_fix_length_and_dec(Item_func_minus *) const override;
|
|
||||||
bool Item_func_mul_fix_length_and_dec(Item_func_mul *) const override;
|
|
||||||
bool Item_func_div_fix_length_and_dec(Item_func_div *) const override;
|
|
||||||
bool Item_func_mod_fix_length_and_dec(Item_func_mod *) const override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
444
sql/sql_yacc.yy
444
sql/sql_yacc.yy
@ -280,6 +280,7 @@ void _CONCAT_UNDERSCORED(turn_parser_debug_on,yyparse)()
|
|||||||
Table_ident *table;
|
Table_ident *table;
|
||||||
Qualified_column_ident *qualified_column_ident;
|
Qualified_column_ident *qualified_column_ident;
|
||||||
Optimizer_hint_parser_output *opt_hints;
|
Optimizer_hint_parser_output *opt_hints;
|
||||||
|
Qualified_ident *qualified_ident;
|
||||||
char *simple_string;
|
char *simple_string;
|
||||||
const char *const_simple_string;
|
const char *const_simple_string;
|
||||||
chooser_compare_func_creator boolfunc2creator;
|
chooser_compare_func_creator boolfunc2creator;
|
||||||
@ -447,6 +448,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
|||||||
%token <NONE> SET_VAR /* OPERATOR */
|
%token <NONE> SET_VAR /* OPERATOR */
|
||||||
%token <NONE> SHIFT_LEFT /* OPERATOR */
|
%token <NONE> SHIFT_LEFT /* OPERATOR */
|
||||||
%token <NONE> SHIFT_RIGHT /* OPERATOR */
|
%token <NONE> SHIFT_RIGHT /* OPERATOR */
|
||||||
|
%token <NONE> ARROW_SYM /* OPERATOR */
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1338,6 +1340,11 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
|||||||
sp_block_label sp_control_label opt_place opt_db
|
sp_block_label sp_control_label opt_place opt_db
|
||||||
udt_name
|
udt_name
|
||||||
|
|
||||||
|
%ifdef ORACLE
|
||||||
|
%type <lex_str>
|
||||||
|
assoc_name
|
||||||
|
%endif
|
||||||
|
|
||||||
%type <ident_sys>
|
%type <ident_sys>
|
||||||
IDENT_sys
|
IDENT_sys
|
||||||
ident
|
ident
|
||||||
@ -1400,6 +1407,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
|||||||
%type <qualified_column_ident>
|
%type <qualified_column_ident>
|
||||||
optionally_qualified_column_ident
|
optionally_qualified_column_ident
|
||||||
|
|
||||||
|
%ifdef ORACLE
|
||||||
|
%type <qualified_ident>
|
||||||
|
optionally_qualified_directly_assignable
|
||||||
|
direct_call_or_lvalue_assign
|
||||||
|
%endif
|
||||||
|
|
||||||
%type <simple_string>
|
%type <simple_string>
|
||||||
remember_name remember_end
|
remember_name remember_end
|
||||||
remember_tok_start
|
remember_tok_start
|
||||||
@ -1424,7 +1437,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
|||||||
%type <json_on_response> json_on_response
|
%type <json_on_response> json_on_response
|
||||||
|
|
||||||
%type <Lex_field_type> field_type field_type_all field_type_all_builtin
|
%type <Lex_field_type> field_type field_type_all field_type_all_builtin
|
||||||
field_type_all_with_record
|
field_type_all_with_composites
|
||||||
qualified_field_type
|
qualified_field_type
|
||||||
field_type_numeric
|
field_type_numeric
|
||||||
field_type_string
|
field_type_string
|
||||||
@ -1433,6 +1446,15 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
|||||||
field_type_misc
|
field_type_misc
|
||||||
json_table_field_type
|
json_table_field_type
|
||||||
|
|
||||||
|
%ifdef ORACLE
|
||||||
|
%type <spvar_definition> assoc_array_table_types
|
||||||
|
%type <spvar_definition> assoc_array_index_type
|
||||||
|
%type <Lex_field_type> field_type_all_with_record assoc_array_index_types
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%type <ident_cli>
|
||||||
|
opt_object_member_access
|
||||||
|
|
||||||
%type <Lex_exact_charset_extended_collation_attrs>
|
%type <Lex_exact_charset_extended_collation_attrs>
|
||||||
binary
|
binary
|
||||||
opt_binary
|
opt_binary
|
||||||
@ -1576,6 +1598,20 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
|||||||
ident_list ident_list_arg opt_expr_list
|
ident_list ident_list_arg opt_expr_list
|
||||||
execute_using
|
execute_using
|
||||||
execute_params
|
execute_params
|
||||||
|
opt_sp_cparam_list
|
||||||
|
opt_sp_cparams
|
||||||
|
sp_cparams
|
||||||
|
|
||||||
|
%ifdef ORACLE
|
||||||
|
%type <item_list>
|
||||||
|
parenthesized_opt_sp_cparams
|
||||||
|
opt_parenthesized_opt_sp_cparams
|
||||||
|
%endif
|
||||||
|
|
||||||
|
%ifdef ORACLE
|
||||||
|
%type <item> named_expr
|
||||||
|
%type <item_list> named_expr_list
|
||||||
|
%endif
|
||||||
|
|
||||||
%type <sp_cursor_stmt>
|
%type <sp_cursor_stmt>
|
||||||
sp_cursor_stmt_lex
|
sp_cursor_stmt_lex
|
||||||
@ -1990,6 +2026,7 @@ rule:
|
|||||||
%type <kwd> reserved_keyword_udt_param_type
|
%type <kwd> reserved_keyword_udt_param_type
|
||||||
%else
|
%else
|
||||||
%type <NONE> set_assign
|
%type <NONE> set_assign
|
||||||
|
%type <NONE> set_assign_lvalue_function
|
||||||
%type <spvar_mode> sp_opt_inout
|
%type <spvar_mode> sp_opt_inout
|
||||||
%type <NONE> sp_tail_standalone
|
%type <NONE> sp_tail_standalone
|
||||||
%type <NONE> sp_labelable_stmt
|
%type <NONE> sp_labelable_stmt
|
||||||
@ -2010,6 +2047,7 @@ rule:
|
|||||||
%type <spblock_handlers> sp_block_statements_and_exceptions
|
%type <spblock_handlers> sp_block_statements_and_exceptions
|
||||||
%type <sp_instr_addr> sp_instr_addr
|
%type <sp_instr_addr> sp_instr_addr
|
||||||
%type <num> opt_exception_clause exception_handlers
|
%type <num> opt_exception_clause exception_handlers
|
||||||
|
%type <ident_sys> typed_ident
|
||||||
%endif ORACLE
|
%endif ORACLE
|
||||||
|
|
||||||
%%
|
%%
|
||||||
@ -3349,27 +3387,43 @@ call:
|
|||||||
|
|
||||||
/* CALL parameters */
|
/* CALL parameters */
|
||||||
opt_sp_cparam_list:
|
opt_sp_cparam_list:
|
||||||
/* Empty */
|
/* Empty */ { $$= nullptr; }
|
||||||
| '('
|
| '('
|
||||||
{
|
{
|
||||||
thd->where= THD_WHERE::USE_WHERE_STRING;
|
thd->where= THD_WHERE::USE_WHERE_STRING;
|
||||||
thd->where_str= "CALL";
|
thd->where_str= "CALL";
|
||||||
} opt_sp_cparams ')'
|
} opt_sp_cparams ')'
|
||||||
|
{
|
||||||
|
$$= $3;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
%ifdef ORACLE
|
||||||
|
opt_parenthesized_opt_sp_cparams:
|
||||||
|
/* Empty */ { $$= nullptr; }
|
||||||
|
| parenthesized_opt_sp_cparams { $$= $1; }
|
||||||
|
;
|
||||||
|
|
||||||
|
parenthesized_opt_sp_cparams:
|
||||||
|
'(' opt_sp_cparams ')' { $$= $2; }
|
||||||
|
;
|
||||||
|
%endif
|
||||||
|
|
||||||
|
|
||||||
opt_sp_cparams:
|
opt_sp_cparams:
|
||||||
/* Empty */
|
/* Empty */ { $$= nullptr; }
|
||||||
| sp_cparams
|
| sp_cparams { $$= $1; }
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_cparams:
|
sp_cparams:
|
||||||
sp_cparams ',' expr
|
sp_cparams ',' expr
|
||||||
{
|
{
|
||||||
Lex->value_list.push_back($3, thd->mem_root);
|
($$= $1)->push_back($3, thd->mem_root);
|
||||||
}
|
}
|
||||||
| expr
|
| expr
|
||||||
{
|
{
|
||||||
Lex->value_list.push_back($1, thd->mem_root);
|
($$= &Lex->value_list)->push_back($1, thd->mem_root);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -3501,8 +3555,9 @@ optionally_qualified_column_ident:
|
|||||||
row_field_definition:
|
row_field_definition:
|
||||||
row_field_name field_type
|
row_field_name field_type
|
||||||
{
|
{
|
||||||
Lex->last_field->set_attributes(thd, $2,
|
if (Lex->last_field->set_attributes(thd, $2,
|
||||||
COLUMN_DEFINITION_ROUTINE_LOCAL);
|
COLUMN_DEFINITION_ROUTINE_LOCAL))
|
||||||
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -3527,8 +3582,9 @@ row_type_body:
|
|||||||
rec_field_definition:
|
rec_field_definition:
|
||||||
row_field_name field_type
|
row_field_name field_type
|
||||||
{
|
{
|
||||||
Lex->last_field->set_attributes(thd, $2,
|
if (Lex->last_field->set_attributes(thd, $2,
|
||||||
COLUMN_DEFINITION_ROUTINE_LOCAL);
|
COLUMN_DEFINITION_ROUTINE_LOCAL))
|
||||||
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| rec_field_definition_anchored
|
| rec_field_definition_anchored
|
||||||
;
|
;
|
||||||
@ -3577,10 +3633,11 @@ sp_decl_idents_init_vars:
|
|||||||
|
|
||||||
sp_decl_variable_list:
|
sp_decl_variable_list:
|
||||||
sp_decl_idents_init_vars
|
sp_decl_idents_init_vars
|
||||||
field_type_all_with_record
|
field_type_all_with_composites
|
||||||
{
|
{
|
||||||
Lex->last_field->set_attributes(thd, $2,
|
if (Lex->last_field->set_attributes(thd, $2,
|
||||||
COLUMN_DEFINITION_ROUTINE_LOCAL);
|
COLUMN_DEFINITION_ROUTINE_LOCAL))
|
||||||
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
sp_opt_default
|
sp_opt_default
|
||||||
{
|
{
|
||||||
@ -6247,8 +6304,9 @@ field_spec:
|
|||||||
field_type_or_serial:
|
field_type_or_serial:
|
||||||
qualified_field_type
|
qualified_field_type
|
||||||
{
|
{
|
||||||
Lex->last_field->set_attributes(thd, $1,
|
if (Lex->last_field->set_attributes(thd, $1,
|
||||||
COLUMN_DEFINITION_TABLE_FIELD);
|
COLUMN_DEFINITION_TABLE_FIELD))
|
||||||
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
field_def
|
field_def
|
||||||
{
|
{
|
||||||
@ -6475,6 +6533,7 @@ field_type_all:
|
|||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
%ifdef ORACLE
|
||||||
field_type_all_with_record:
|
field_type_all_with_record:
|
||||||
field_type_all_builtin
|
field_type_all_builtin
|
||||||
{
|
{
|
||||||
@ -6482,19 +6541,36 @@ field_type_all_with_record:
|
|||||||
}
|
}
|
||||||
| udt_name float_options srid_option
|
| udt_name float_options srid_option
|
||||||
{
|
{
|
||||||
sp_type_def *sprec = NULL;
|
bool is_composite= false;
|
||||||
if (Lex->spcont)
|
if (unlikely(Lex->set_field_type_composite(&$$, $1, false,
|
||||||
sprec = Lex->spcont->find_type_def($1, false);
|
&is_composite)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
|
||||||
if (sprec == NULL)
|
if (!is_composite)
|
||||||
{
|
{
|
||||||
if (Lex->set_field_type_udt(&$$, $1, $2))
|
if (Lex->set_field_type_udt(&$$, $1, $2))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
;
|
||||||
|
%endif
|
||||||
|
|
||||||
|
field_type_all_with_composites:
|
||||||
|
field_type_all_builtin
|
||||||
{
|
{
|
||||||
$$.set(&type_handler_row, NULL);
|
Lex->map_data_type(Lex_ident_sys(), &($$= $1));
|
||||||
Lex->last_field->set_attr_const_void_ptr(0, sprec);
|
}
|
||||||
|
| udt_name float_options srid_option
|
||||||
|
{
|
||||||
|
bool is_composite= false;
|
||||||
|
if (unlikely(Lex->set_field_type_composite(&$$, $1, true,
|
||||||
|
&is_composite)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
|
||||||
|
if (!is_composite)
|
||||||
|
{
|
||||||
|
if (Lex->set_field_type_udt(&$$, $1, $2))
|
||||||
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
@ -10953,13 +11029,15 @@ function_call_generic:
|
|||||||
$<udf>$= udf;
|
$<udf>$= udf;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
opt_udf_expr_list ')'
|
opt_udf_expr_list ')' opt_object_member_access
|
||||||
{
|
{
|
||||||
const Type_handler *h;
|
const Type_handler *h;
|
||||||
Create_func *builder;
|
Create_func *builder;
|
||||||
Item *item= NULL;
|
Item *item= NULL;
|
||||||
const sp_type_def *tdef= NULL;
|
const sp_type_def *tdef= NULL;
|
||||||
const Lex_ident_sys ident(thd, &$1);
|
const Lex_ident_sys ident(thd, &$1);
|
||||||
|
sp_variable *spv= NULL;
|
||||||
|
bool allow_field_accessor= false;
|
||||||
|
|
||||||
if (unlikely(ident.is_null() ||
|
if (unlikely(ident.is_null() ||
|
||||||
Lex_ident_routine::check_name_with_error(ident)))
|
Lex_ident_routine::check_name_with_error(ident)))
|
||||||
@ -10991,6 +11069,22 @@ function_call_generic:
|
|||||||
{
|
{
|
||||||
item= tdef->make_constructor_item(thd, $4);
|
item= tdef->make_constructor_item(thd, $4);
|
||||||
}
|
}
|
||||||
|
else if (Lex->spcont &&
|
||||||
|
(spv= Lex->spcont->find_variable(&ident, false)) &&
|
||||||
|
spv->type_handler()->has_functors())
|
||||||
|
{
|
||||||
|
const char *end= $6.str ? $6.end() : $5.end();
|
||||||
|
const Lex_ident_cli name_cli($1.pos(), end - $1.pos());
|
||||||
|
auto ident2= $6.str ? Lex_ident_sys(thd, &$6) : Lex_ident_sys();
|
||||||
|
if (($6.str && ident2.is_null()) ||
|
||||||
|
!(item= Lex->create_item_functor(thd, ident, $4,
|
||||||
|
ident2, name_cli)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
item->set_name(thd, $1.pos(), end - $1.pos(), thd->charset());
|
||||||
|
|
||||||
|
// Only allow 'result accessors' for associative arrays
|
||||||
|
allow_field_accessor= true;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef HAVE_DLOPEN
|
#ifdef HAVE_DLOPEN
|
||||||
@ -11015,6 +11109,13 @@ function_call_generic:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($6.str && !allow_field_accessor)
|
||||||
|
{
|
||||||
|
Lex_ident_sys field_sys(thd, &$6);
|
||||||
|
my_error(ER_BAD_FIELD_ERROR, MYF(0), field_sys.str, ident.str);
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(! ($$= item)))
|
if (unlikely(! ($$= item)))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
@ -11038,7 +11139,10 @@ function_call_generic:
|
|||||||
}
|
}
|
||||||
| ident_cli '.' ident_cli '(' opt_expr_list ')'
|
| ident_cli '.' ident_cli '(' opt_expr_list ')'
|
||||||
{
|
{
|
||||||
if (unlikely(!($$= Lex->make_item_func_call_generic(thd, &$1, &$3, $5))))
|
const Lex_ident_cli pos($1.pos(), $6.pos() - $1.pos() + 1);
|
||||||
|
if (unlikely(!($$= Lex->make_item_func_or_method_call(thd, $1,
|
||||||
|
$3, $5,
|
||||||
|
pos))))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
| ident_cli '.' ident_cli '.' ident_cli '(' opt_expr_list ')'
|
| ident_cli '.' ident_cli '.' ident_cli '(' opt_expr_list ')'
|
||||||
@ -11085,6 +11189,11 @@ function_call_generic:
|
|||||||
*/
|
*/
|
||||||
;
|
;
|
||||||
|
|
||||||
|
opt_object_member_access:
|
||||||
|
/* empty */ { $$= Lex_ident_cli((const char *)nullptr, 0); }
|
||||||
|
| '.' ident_cli { $$= $2; }
|
||||||
|
;
|
||||||
|
|
||||||
fulltext_options:
|
fulltext_options:
|
||||||
opt_natural_language_mode opt_query_expansion
|
opt_natural_language_mode opt_query_expansion
|
||||||
{ $$= $1 | $2; }
|
{ $$= $1 | $2; }
|
||||||
@ -11105,6 +11214,9 @@ opt_query_expansion:
|
|||||||
opt_udf_expr_list:
|
opt_udf_expr_list:
|
||||||
/* empty */ { $$= NULL; }
|
/* empty */ { $$= NULL; }
|
||||||
| udf_expr_list { $$= $1; }
|
| udf_expr_list { $$= $1; }
|
||||||
|
%ifdef ORACLE
|
||||||
|
| named_expr_list { $$= $1; }
|
||||||
|
%endif
|
||||||
;
|
;
|
||||||
|
|
||||||
udf_expr_list:
|
udf_expr_list:
|
||||||
@ -11901,16 +12013,18 @@ json_table_column_type:
|
|||||||
{
|
{
|
||||||
Lex_field_type_st type;
|
Lex_field_type_st type;
|
||||||
type.set(&type_handler_slong);
|
type.set(&type_handler_slong);
|
||||||
Lex->last_field->set_attributes(thd, type,
|
if (Lex->last_field->set_attributes(thd, type,
|
||||||
COLUMN_DEFINITION_TABLE_FIELD);
|
COLUMN_DEFINITION_TABLE_FIELD))
|
||||||
|
MYSQL_YYABORT;
|
||||||
Lex->json_table->m_cur_json_table_column->
|
Lex->json_table->m_cur_json_table_column->
|
||||||
set(Json_table_column::FOR_ORDINALITY);
|
set(Json_table_column::FOR_ORDINALITY);
|
||||||
}
|
}
|
||||||
| json_table_field_type PATH_SYM json_text_literal
|
| json_table_field_type PATH_SYM json_text_literal
|
||||||
json_opt_on_empty_or_error
|
json_opt_on_empty_or_error
|
||||||
{
|
{
|
||||||
Lex->last_field->set_attributes(thd, $1,
|
if (Lex->last_field->set_attributes(thd, $1,
|
||||||
COLUMN_DEFINITION_TABLE_FIELD);
|
COLUMN_DEFINITION_TABLE_FIELD))
|
||||||
|
MYSQL_YYABORT;
|
||||||
if (Lex->json_table->m_cur_json_table_column->
|
if (Lex->json_table->m_cur_json_table_column->
|
||||||
set(thd, Json_table_column::PATH, $3,
|
set(thd, Json_table_column::PATH, $3,
|
||||||
$1.charset_collation_attrs()))
|
$1.charset_collation_attrs()))
|
||||||
@ -11920,8 +12034,9 @@ json_table_column_type:
|
|||||||
}
|
}
|
||||||
| json_table_field_type EXISTS PATH_SYM json_text_literal
|
| json_table_field_type EXISTS PATH_SYM json_text_literal
|
||||||
{
|
{
|
||||||
Lex->last_field->set_attributes(thd, $1,
|
if (Lex->last_field->set_attributes(thd, $1,
|
||||||
COLUMN_DEFINITION_TABLE_FIELD);
|
COLUMN_DEFINITION_TABLE_FIELD))
|
||||||
|
MYSQL_YYABORT;
|
||||||
if (Lex->json_table->m_cur_json_table_column->
|
if (Lex->json_table->m_cur_json_table_column->
|
||||||
set(thd, Json_table_column::EXISTS_PATH, $4,
|
set(thd, Json_table_column::EXISTS_PATH, $4,
|
||||||
$1.charset_collation_attrs()))
|
$1.charset_collation_attrs()))
|
||||||
@ -13358,6 +13473,15 @@ select_outvar:
|
|||||||
if (unlikely(!($$= Lex->create_outvar(thd, $1, $3)) && Lex->result))
|
if (unlikely(!($$= Lex->create_outvar(thd, $1, $3)) && Lex->result))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
|
| ident '(' expr ')' opt_object_member_access
|
||||||
|
{
|
||||||
|
auto field= $5.str ? Lex_ident_sys(thd, &$5) : Lex_ident_sys();
|
||||||
|
if (unlikely(($5.str && !field.str) ||
|
||||||
|
(!($$= Lex->create_outvar_lvalue_function(thd, $1, $3,
|
||||||
|
field)) &&
|
||||||
|
Lex->result)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
into:
|
into:
|
||||||
@ -19282,46 +19406,56 @@ sp_unlabeled_block_not_atomic:
|
|||||||
statement:
|
statement:
|
||||||
verb_clause
|
verb_clause
|
||||||
| set_assign
|
| set_assign
|
||||||
|
| set_assign_lvalue_function
|
||||||
|
;
|
||||||
|
|
||||||
|
direct_call_or_lvalue_assign:
|
||||||
|
optionally_qualified_directly_assignable
|
||||||
|
{
|
||||||
|
if (Lex->call_statement_start_or_lvalue_assign(thd, $$= $1))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
direct_call_statement:
|
||||||
|
direct_call_or_lvalue_assign opt_parenthesized_opt_sp_cparams
|
||||||
|
{
|
||||||
|
if (unlikely($1->spvar()))
|
||||||
|
{
|
||||||
|
thd->parse_error(ER_SYNTAX_ERROR, $1->pos());
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Lex->check_cte_dependencies_and_resolve_references())
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
set_assign_lvalue_function:
|
||||||
|
direct_call_or_lvalue_assign parenthesized_opt_sp_cparams
|
||||||
|
opt_object_member_access SET_VAR
|
||||||
|
{
|
||||||
|
if (unlikely(Lex->assoc_assign_start(thd, $1)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
set_expr_or_default
|
||||||
|
{
|
||||||
|
const Lex_ident_sys member= $3.str ? Lex_ident_sys(thd, &$3) :
|
||||||
|
Lex_ident_sys();
|
||||||
|
if (unlikely($3.str && member.is_null()) ||
|
||||||
|
unlikely(Lex->sp_set_assign_lvalue_function(thd, $1, $2,
|
||||||
|
member,
|
||||||
|
$6.expr,
|
||||||
|
$6.expr_str)) ||
|
||||||
|
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
|
||||||
|
false)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_statement:
|
sp_statement:
|
||||||
statement
|
statement
|
||||||
| ident_cli_directly_assignable
|
| direct_call_statement
|
||||||
{
|
|
||||||
// Direct procedure call (without the CALL keyword)
|
|
||||||
Lex_ident_sys tmp(thd, &$1);
|
|
||||||
if (unlikely(!tmp.str) ||
|
|
||||||
unlikely(Lex->call_statement_start(thd, &tmp)))
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
opt_sp_cparam_list
|
|
||||||
{
|
|
||||||
if (Lex->check_cte_dependencies_and_resolve_references())
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
| ident_cli_directly_assignable '.' ident
|
|
||||||
{
|
|
||||||
Lex_ident_sys tmp(thd, &$1);
|
|
||||||
if (unlikely(!tmp.str) ||
|
|
||||||
unlikely(Lex->call_statement_start(thd, &tmp, &$3)))
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
opt_sp_cparam_list
|
|
||||||
{
|
|
||||||
if (Lex->check_cte_dependencies_and_resolve_references())
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
| ident_cli_directly_assignable '.' ident '.' ident
|
|
||||||
{
|
|
||||||
Lex_ident_sys tmp(thd, &$1);
|
|
||||||
if (unlikely(Lex->call_statement_start(thd, &tmp, &$3, &$5)))
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
opt_sp_cparam_list
|
|
||||||
{
|
|
||||||
if (Lex->check_cte_dependencies_and_resolve_references())
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
;
|
;
|
||||||
|
|
||||||
sp_if_then_statements:
|
sp_if_then_statements:
|
||||||
@ -19565,39 +19699,38 @@ ident_cli_directly_assignable:
|
|||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
optionally_qualified_directly_assignable:
|
||||||
|
ident_cli_directly_assignable
|
||||||
|
{
|
||||||
|
if (unlikely(!($$= new (thd->mem_root) Qualified_ident(thd, $1))))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
| ident_cli_directly_assignable '.' ident
|
||||||
|
{
|
||||||
|
if (unlikely(!($$= new (thd->mem_root) Qualified_ident(thd, $1,
|
||||||
|
$3))))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
| ident_cli_directly_assignable '.' ident '.' ident
|
||||||
|
{
|
||||||
|
if (unlikely(!($$= new (thd->mem_root) Qualified_ident(thd, $1,
|
||||||
|
$3, $5))))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
set_assign:
|
set_assign:
|
||||||
ident_cli_directly_assignable SET_VAR
|
optionally_qualified_directly_assignable SET_VAR
|
||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
lex->set_stmt_init();
|
lex->set_stmt_init();
|
||||||
if (sp_create_assignment_lex(thd, $1.pos()))
|
if (sp_create_assignment_lex(thd, $1->pos()))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
}
|
}
|
||||||
set_expr_or_default
|
set_expr_or_default
|
||||||
{
|
{
|
||||||
Lex_ident_sys tmp(thd, &$1);
|
if (unlikely(Lex->set_variable($1, $4.expr, $4.expr_str)) ||
|
||||||
|
|
||||||
if (unlikely(!tmp.str) ||
|
|
||||||
unlikely(Lex->set_variable(&tmp, $4.expr, $4.expr_str)) ||
|
|
||||||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
|
|
||||||
false)))
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
| ident_cli_directly_assignable '.' ident SET_VAR
|
|
||||||
{
|
|
||||||
LEX *lex=Lex;
|
|
||||||
lex->set_stmt_init();
|
|
||||||
if (sp_create_assignment_lex(thd, $1.pos()))
|
|
||||||
MYSQL_YYABORT;
|
|
||||||
}
|
|
||||||
set_expr_or_default
|
|
||||||
{
|
|
||||||
LEX *lex= Lex;
|
|
||||||
DBUG_ASSERT(lex->var_list.is_empty());
|
|
||||||
Lex_ident_sys tmp(thd, &$1);
|
|
||||||
|
|
||||||
if (unlikely(!tmp.str) ||
|
|
||||||
unlikely(lex->set_variable(&tmp, &$3, $6.expr, $6.expr_str)) ||
|
|
||||||
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
|
unlikely(sp_create_assignment_instr(thd, yychar == YYEMPTY,
|
||||||
false)))
|
false)))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
@ -19762,6 +19895,40 @@ package_implementation_executable_section:
|
|||||||
| BEGIN_ORACLE_SYM sp_block_statements_and_exceptions END { $$= $2; }
|
| BEGIN_ORACLE_SYM sp_block_statements_and_exceptions END { $$= $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
named_expr_list:
|
||||||
|
remember_name named_expr remember_end
|
||||||
|
{
|
||||||
|
if (unlikely(!($$= new (thd->mem_root) List<Item>) ||
|
||||||
|
$$->push_back($2, thd->mem_root)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
| named_expr_list ',' remember_name named_expr remember_end
|
||||||
|
{
|
||||||
|
if (($$= $1)->push_back($4, thd->mem_root))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
assoc_name:
|
||||||
|
TEXT_STRING_sys
|
||||||
|
| LONG_NUM
|
||||||
|
| ULONGLONG_NUM
|
||||||
|
| DECIMAL_NUM
|
||||||
|
| NUM
|
||||||
|
;
|
||||||
|
|
||||||
|
named_expr:
|
||||||
|
assoc_name ARROW_SYM expr
|
||||||
|
{
|
||||||
|
if ($1.str)
|
||||||
|
{
|
||||||
|
$3->base_flags|= item_base_t::IS_EXPLICIT_NAME;
|
||||||
|
$3->set_name(thd, $1);
|
||||||
|
}
|
||||||
|
$$= $3;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
%endif ORACLE
|
%endif ORACLE
|
||||||
|
|
||||||
|
|
||||||
@ -20154,6 +20321,79 @@ opt_sp_decl_handler_list:
|
|||||||
| sp_decl_handler_list
|
| sp_decl_handler_list
|
||||||
;
|
;
|
||||||
|
|
||||||
|
typed_ident:
|
||||||
|
TYPE_SYM ident_directly_assignable
|
||||||
|
{
|
||||||
|
if (unlikely(!Lex->init_spvar_definition(thd, ($$= $2))))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
assoc_array_table_types:
|
||||||
|
field_type_all_with_record
|
||||||
|
{
|
||||||
|
if (Lex->last_field->set_attributes(thd, $1,
|
||||||
|
COLUMN_DEFINITION_ROUTINE_LOCAL))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
$$= static_cast<Spvar_definition*>(Lex->last_field);
|
||||||
|
}
|
||||||
|
| sp_decl_ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
|
||||||
|
{
|
||||||
|
$$= static_cast<Spvar_definition*>(Lex->last_field);
|
||||||
|
if (unlikely(Lex->sphead->spvar_def_fill_type_reference(thd, $$,
|
||||||
|
$1, $3)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
| sp_decl_ident '.' ident '.' ident PERCENT_ORACLE_SYM TYPE_SYM
|
||||||
|
{
|
||||||
|
$$= static_cast<Spvar_definition*>(Lex->last_field);
|
||||||
|
if (unlikely(Lex->sphead->spvar_def_fill_type_reference(thd, $$,
|
||||||
|
$1, $3,
|
||||||
|
$5)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
| ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
|
||||||
|
{
|
||||||
|
$$= static_cast<Spvar_definition*>(Lex->last_field);
|
||||||
|
if (unlikely(Lex->sphead->spvar_def_fill_rowtype_reference(thd, $$,
|
||||||
|
$1)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
| sp_decl_ident '.' ident PERCENT_ORACLE_SYM ROWTYPE_ORACLE_SYM
|
||||||
|
{
|
||||||
|
$$= static_cast<Spvar_definition*>(Lex->last_field);
|
||||||
|
if (unlikely(Lex->sphead->spvar_def_fill_rowtype_reference(thd,
|
||||||
|
$$,
|
||||||
|
$1, $3)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
assoc_array_index_types:
|
||||||
|
int_type opt_field_length last_field_options
|
||||||
|
{
|
||||||
|
$$.set_handler_length_flags($1, $2, (uint32) $3);
|
||||||
|
}
|
||||||
|
| varchar opt_field_length opt_binary_and_compression
|
||||||
|
{
|
||||||
|
$$.set(&type_handler_varchar, $2, $3);
|
||||||
|
}
|
||||||
|
| VARCHAR2_ORACLE_SYM opt_field_length opt_binary_and_compression
|
||||||
|
{
|
||||||
|
$$.set(&type_handler_varchar, $2, $3);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
assoc_array_index_type:
|
||||||
|
INDEX_SYM BY assoc_array_index_types
|
||||||
|
{
|
||||||
|
if (Lex->last_field->set_attributes(thd, $3,
|
||||||
|
COLUMN_DEFINITION_ROUTINE_LOCAL))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
$$= new (thd->mem_root) Spvar_definition(*Lex->last_field);
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
sp_decl_non_handler:
|
sp_decl_non_handler:
|
||||||
sp_decl_variable_list
|
sp_decl_variable_list
|
||||||
| ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond
|
| ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond
|
||||||
@ -20192,14 +20432,32 @@ sp_decl_non_handler:
|
|||||||
$$.vars= $$.conds= $$.hndlrs= 0;
|
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||||
$$.curs= 1;
|
$$.curs= 1;
|
||||||
}
|
}
|
||||||
| TYPE_SYM ident_directly_assignable IS RECORD_SYM rec_type_body
|
| typed_ident IS RECORD_SYM rec_type_body
|
||||||
{
|
{
|
||||||
if (unlikely(Lex->spcont->
|
if (unlikely(Lex->spcont->
|
||||||
type_defs_declare_record(thd, Lex_ident_column($2), $5)))
|
type_defs_declare_record(thd, Lex_ident_column($1), $4)))
|
||||||
MYSQL_YYABORT;
|
MYSQL_YYABORT;
|
||||||
|
|
||||||
$$.vars= $$.conds= $$.hndlrs= $$.curs= 0;
|
$$.vars= $$.conds= $$.hndlrs= $$.curs= 0;
|
||||||
}
|
}
|
||||||
|
| typed_ident IS TABLE_SYM OF_SYM assoc_array_table_types
|
||||||
|
{
|
||||||
|
Lex->init_last_field(new (thd->mem_root) Column_definition(),
|
||||||
|
&empty_clex_str);
|
||||||
|
}
|
||||||
|
assoc_array_index_type
|
||||||
|
{
|
||||||
|
const auto aa= "associative_array"_Lex_ident_plugin;
|
||||||
|
const Type_handler *th=
|
||||||
|
Type_handler::handler_by_name_or_error(thd, aa);
|
||||||
|
if (unlikely(!th ||
|
||||||
|
Lex->spcont->
|
||||||
|
type_defs_declare_composite2(thd,
|
||||||
|
Lex_ident_column($1),
|
||||||
|
th, $7, $5)))
|
||||||
|
MYSQL_YYABORT;
|
||||||
|
$$.vars= $$.conds= $$.hndlrs= $$.curs= 0;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user