mirror of
https://github.com/MariaDB/server.git
synced 2025-11-05 01:43:31 +03:00
Cleanup#1 for MDEV-34319: DECLARE TYPE .. TABLE OF .. INDEX BY
- Checking that the key expression is compatible with the INDEX BY data type
for assignment in expressions:
assoc_array_variable(key_expr)
assoc_array_variable(key_expr).field
in all contexts: SELECT, assignment target, INTO target.
Raising an error in case it's not compatible.
- Disallowing non-constant expressions as a key,
as the key is evaluated during the fix_fields() time.
- Disallowing stored functions as a key:
assoc_array(stored_function())
assoc_array(stored_function()).field
The underlying MariaDB code is not ready to call a stored function
during the fix_fields() time. This will be fixed in a separate MDEV.
- Removing the move Assoc_array_data's constructor.
Using the usual constructor instead.
- Setting m_key.thread_specific and m_value.thread_specific to true
in the Assoc_array_data constructor. This is needed to get assoc array
element data counted by the @@session.memory_used status variable.
Adding DBUG_ASSERTs to make sure the thread_specific flag never
disappears in Assoc_array_data members.
- Removing my_free(item) from Field_assoc_array::element_by_key.
It was a remainder from an earlier patch version.
In the current patch version all Items behind an assoc array are
created on a mem_root. It's wrong to use my_free() with them.
- Adding a helper method Field_assoc_array::assoc_tree_search()
- Fixing assoc_array_var.delete() to work as a procedure
rather than a function. It does not need SELECT/DO any more.
- Fixing the crash in a few ctype_xxx tests, caused by the grammar change.
- Fixing compilation failure on Windows
- Adding a new method LEX::set_field_type_udt_or_typedef()
and removing duplicate code from sql_yacc.yy
- Renaming the grammar rule field_type_all_with_composites to
field_type_all_with_typedefs
- Removing the grammar rule assoc_array_index_types.
Changing the grammar to "INDEX_SYM BY field_type".
Removing the grammar rule field_type_all_with_record.
Allow field_type_all_with_typedefs as an assoc array element.
Catching wrong index and element data types has been moved to
Type_handler_assoc_array::Column_definition_set_attributes().
It raises an SQL error on things like:
* assoc array of assoc arrays in TABLE OF
* index by a non-supported types in INDEX BY
- Removing four methods:
* sp_type_def_list::type_defs_add_record()
* sp_type_def_list::type_defs_add_composite2()
* sp_pcontext::type_defs_declare_record()
* sp_type_def_list::type_defs_declare_composite2()
Adding two methods instead:
* sp_type_def_list::type_defs_add()
* sp_pcontext::type_defs_add()
This allows to get rid of the duplicate code detecting data type
declarations with the same name in the same sp_pcontext frame.
- Adding new methods:
* LEX::declare_type_assoc_array()
* LEX::LEX::declare_type_record()
They create a type specific sp_type_def_xxx and the call the generic
sp_pcontext::type_defs_add().
- m_key_def.sp_prepare_create_field() inside
Field_assoc_array::create_fields() is now called for all key data types
(not only for integers)
- Removing the assignment of key_def->charset in
Type_handler_assoc_array::sp_variable_declarations_finalize().
The charset is now evaluated in m_key_def.sp_prepare_create_field().
- Fixing Item_assoc_array::get_key() to set the character set of the "key"
to utf8mb3 instead of binary
- Fixing Field_assoc_array::copy_and_convert_key() to set the key length
limit in terms of the character length as specified in
INDEX BY VARCHAR(N), instead of octet length. This is needed to make
keys with multi-byte characters work correctly.
Also it now raises different errors depending on the reason of the
key conversion failures:
* ER_INVALID_CHARACTER_STRING
* ER_CANNOT_CONVERT_CHARACTER
- Changing the prototype for Type_handler_composite::key_to_lex_cstring() to
virtual LEX_CSTRING key_to_lex_cstring(THD *thd,
const sp_rcontext_addr &var,
Item **key,
String *buffer) const;
* Now it returns a LEX_CSTRING, instead of getting it as an out parameter.
* Gets an sp_rcontext_addr instead of "name" and "def"
* Gets a String buffer which can be used to be passed to val_str(),
or for character set conversion purposes.
- Removing Field_assoc_array::m_key_def, as all required information
is available from Field_assoc_array::m_key_field.
In Field_assoc_array::create_fields turning m_key_def to a local variable
key_def.
- Fixing Field_assoc_array::copy_and_convert_key() to follow MariaDB coding
style: only constants can be passed by-reference, not-constants should
be passed by-pointer.
- Adding DBUG_ASSERTs into Type_handler_assoc_array::get_item()
and Type_handler_assoc_array::get_or_create_item() that the passed
key in "name" is well formed according to the charset of INDEX BY.
- Changing the error ER_TOO_LONG_KEY to ER_WRONG_STRING_LENGTH.
The former prints length limit in bytes, which is not applicable
for INDEX BY values, because its limit is in characters.
Also, the latter is more verbose.
- Fixing the problem that these wrong uses of an assoc array variable:
BEGIN
assoc_var;
assoc_var(1);
END;
raised a weird error message:
ERROR 1054 (42S22): Unknown column 'assoc_var' in '(null)'
Now a more readable parse error is raised.
- Adding a "Duplicate key" warning for the cases when assigning
between two assoc arrays rejects some records due to different
collations in their INDEX BY key definitions.
- Disallow INDEX OF propagation from VARCHAR to TEXT.
The underlying code cannot handle TEXT.
Adding tests.
- Adding a helper class StringBufferKey to pass to val_str() when
a key value is evaluated.
Fixing all val_str() calls to val_str(&buffer), as the former is
not desirable.
- Fixing a wrong use of args[0]->null_value in
Item_func_assoc_array_exists::val_bool()
- Fixing a problem that using TABLE OF TEXT crashed the server.
Thanks to Iqbal Hassan for the proposed patch.
- Changes in Qualified_ident:
* Fixing the Qualified_ident constructors to get all parst as
Lex_ident_cli_st, rather than the first part as Lex_ident_cli_st
with the following parts Lex_ident_sys.
This makes the code more symmetric.
* Fixing the grammar in sql_yacc.yy accordinly.
* Fixing the data type storing the possition in the client query
from "const char *" to Lex_ident_cli.
* Adding a new method Qualified_ident::is_sane().
It allows to reduce the code side in sql_yacc.yy.
Thanks to Iqbal Hassan for the idea.
- Replacing qs_append() to append_ulonglong() in:
* Item_method_func::print()
* Item_splocal_assoc_array_element::print()
* Item_splocal_assoc_array_element_field::print()
These methods do not use reserve()/alloc(), so calling qs_append()
was wrong and caused a crash.
- Changing the output formats of these methods:
* Item_splocal_assoc_array_element::print()
* Item_splocal_assoc_array_element_field::print()
not to print the key two times.
Also moving the `@123` part (the variable offset) immediately
after the variabl name and before the `[key]` part.
- Fixing a memory leak happened when trying to insert a duplicate
key into an assoc array. Also adding a new "THD *" parameter to
Field_assoc_array::insert_element(). Thanks to Iqbal Hassan for the fix.
Adding a test into sp-assoc-array-ctype.test.
- In Field_assoc_array::create_fields: m_element_field->field_name is now
set for all element data types (not only for records).
This fixed a wrong variable name in warnings. Adding tests.
- Adding tests:
* Adding tests for assoc array elements in UNIONs.
* Copying from an assoc array with a varchar key
to an assoc array with a shorter varchar key.
* A relatively big associative array.
* Memory usage for x86_64.
* Package variable as assoc array keys.
* Character set conversion
* TABLE OF TEXT
* TABLE OF VARCHAR(>64k bytes) propagation to TABLE OF TEXT.
* TEXT element fields in an array of records.
* VARCHAR->TEXT propagation in elements in an array of records.
* Some more tests
This commit is contained in:
committed by
Sergei Golubchik
parent
41014a4ecd
commit
e9d541f912
@@ -1997,6 +1997,10 @@ public:
|
||||
:Well_formed_prefix_status(cs, str.str, str.str + str.length, nchars),
|
||||
m_str(str.str)
|
||||
{ }
|
||||
Well_formed_prefix(CHARSET_INFO *cs, LEX_CSTRING str)
|
||||
:Well_formed_prefix_status(cs, str.str, str.str + str.length, str.length),
|
||||
m_str(str.str)
|
||||
{ }
|
||||
size_t length() const { return m_source_end_pos - m_str; }
|
||||
};
|
||||
|
||||
|
||||
@@ -28,6 +28,12 @@ TYPE first_names_t IS TABLE OF VARCHAR2(64) INDEX BY VARCHAR2(20);
|
||||
first_names first_names_t;
|
||||
nick VARCHAR(64):= 'Monty';
|
||||
BEGIN
|
||||
-- Make sure the method "DELETE" is not bin-logged per se
|
||||
first_names('Liv') := 'Liver';
|
||||
first_names('Sly') := 'Sylvester';
|
||||
first_names.DELETE('Liv');
|
||||
first_names.DELETE;
|
||||
-- Only DML statements are bin-logged
|
||||
first_names('Monty') := 'Michael';
|
||||
INSERT INTO t1 VALUES (first_names('Monty'));
|
||||
INSERT INTO t1 VALUES (first_names(nick));
|
||||
|
||||
@@ -45,6 +45,13 @@ DECLARE
|
||||
first_names first_names_t;
|
||||
nick VARCHAR(64):= 'Monty';
|
||||
BEGIN
|
||||
-- Make sure the method "DELETE" is not bin-logged per se
|
||||
first_names('Liv') := 'Liver';
|
||||
first_names('Sly') := 'Sylvester';
|
||||
first_names.DELETE('Liv');
|
||||
first_names.DELETE;
|
||||
|
||||
-- Only DML statements are bin-logged
|
||||
first_names('Monty') := 'Michael';
|
||||
|
||||
INSERT INTO t1 VALUES (first_names('Monty'));
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
set sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# Checking memory_used increment when inserting into an assoc array.
|
||||
# Checking that when the routine execution leaves
|
||||
# a DECLARE..BEGIN..END block with an assoc array declared,
|
||||
# the memory used by the assoc array is freed.
|
||||
#
|
||||
CREATE FUNCTION memory_used() RETURN BIGINT AS
|
||||
BEGIN
|
||||
RETURN (SELECT variable_value FROM INFORMATION_SCHEMA.SESSION_STATUS
|
||||
WHERE variable_name='memory_used');
|
||||
END;
|
||||
/
|
||||
CREATE PROCEDURE p1 AS
|
||||
memory_used0 BIGINT:= memory_used();
|
||||
BEGIN
|
||||
DECLARE
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(2048),
|
||||
last_name VARCHAR(2048)
|
||||
);
|
||||
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('p0'):= person_t('','');
|
||||
SELECT 'p0' AS id, memory_used()-memory_used0 AS diff;
|
||||
person_by_nickname('p1'):= person_t('first_name', 'last_name');
|
||||
SELECT 'p1' AS id, memory_used()-memory_used0 AS diff;
|
||||
person_by_nickname('p2'):= person_t(CONCAT('first_name', REPEAT('a',1024)),
|
||||
CONCAT('last_name', REPEAT('a',1024)));
|
||||
SELECT 'p2' AS id, memory_used()-memory_used0 AS diff;
|
||||
person_by_nickname('p2'):= person_t('first_name', 'last_name');
|
||||
SELECT 'p2upd' AS id, memory_used()-memory_used0 AS diff;
|
||||
person_by_nickname.delete('p2');
|
||||
SELECT 'p2del' AS id, memory_used()-memory_used0 AS diff;
|
||||
END;
|
||||
SELECT memory_used()-memory_used0 AS diff1;
|
||||
END;
|
||||
/
|
||||
CALL p1;
|
||||
id diff
|
||||
p0 176
|
||||
id diff
|
||||
p1 376
|
||||
id diff
|
||||
p2 2624
|
||||
id diff
|
||||
p2upd 2624
|
||||
id diff
|
||||
p2del 376
|
||||
diff1
|
||||
0
|
||||
DROP PROCEDURE p1;
|
||||
DROP FUNCTION memory_used;
|
||||
@@ -0,0 +1,58 @@
|
||||
--source include/have_64bit.inc
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
set sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # Checking memory_used increment when inserting into an assoc array.
|
||||
--echo # Checking that when the routine execution leaves
|
||||
--echo # a DECLARE..BEGIN..END block with an assoc array declared,
|
||||
--echo # the memory used by the assoc array is freed.
|
||||
--echo #
|
||||
|
||||
DELIMITER /;
|
||||
CREATE FUNCTION memory_used() RETURN BIGINT AS
|
||||
BEGIN
|
||||
RETURN (SELECT variable_value FROM INFORMATION_SCHEMA.SESSION_STATUS
|
||||
WHERE variable_name='memory_used');
|
||||
END;
|
||||
/
|
||||
CREATE PROCEDURE p1 AS
|
||||
memory_used0 BIGINT:= memory_used();
|
||||
BEGIN
|
||||
DECLARE
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(2048),
|
||||
last_name VARCHAR(2048)
|
||||
);
|
||||
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('p0'):= person_t('','');
|
||||
SELECT 'p0' AS id, memory_used()-memory_used0 AS diff;
|
||||
|
||||
person_by_nickname('p1'):= person_t('first_name', 'last_name');
|
||||
SELECT 'p1' AS id, memory_used()-memory_used0 AS diff;
|
||||
|
||||
person_by_nickname('p2'):= person_t(CONCAT('first_name', REPEAT('a',1024)),
|
||||
CONCAT('last_name', REPEAT('a',1024)));
|
||||
SELECT 'p2' AS id, memory_used()-memory_used0 AS diff;
|
||||
|
||||
person_by_nickname('p2'):= person_t('first_name', 'last_name');
|
||||
SELECT 'p2upd' AS id, memory_used()-memory_used0 AS diff;
|
||||
|
||||
person_by_nickname.delete('p2');
|
||||
SELECT 'p2del' AS id, memory_used()-memory_used0 AS diff;
|
||||
END;
|
||||
SELECT memory_used()-memory_used0 AS diff1;
|
||||
END;
|
||||
/
|
||||
DELIMITER ;/
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
DROP FUNCTION memory_used;
|
||||
@@ -0,0 +1,188 @@
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
set sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# Passing an expression of a wrong type as a key: POINT
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(POINT(1,1));
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type point for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(POINT(1,1));
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type point for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(POINT(1,1)) := 1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type point for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Passing an expression of a wrong type as a key: ROW
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(ROW(1,1));
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type row for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(ROW(1,1));
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type row for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(ROW(1,1)) := 1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type row for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Passing an expression of a wrong type as a key: anchored POINT
|
||||
#
|
||||
CREATE TABLE t1 (a POINT(1,1));
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1.a%TYPE;
|
||||
BEGIN
|
||||
SELECT marks(idx);
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type point for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a POINT(1,1));
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1.a%TYPE;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(idx);
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type point for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a POINT(1,1));
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1.a%TYPE;
|
||||
BEGIN
|
||||
marks(idx):= 1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type point for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Passing an expression of a wrong type as a key: anchored ROW
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b INT);
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1%ROWTYPE;
|
||||
BEGIN
|
||||
SELECT marks(idx);
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type row for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a INT, b INT);
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1%ROWTYPE;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(idx);
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type row for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a INT, b INT);
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1%ROWTYPE;
|
||||
BEGIN
|
||||
marks(idx):= 1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Illegal parameter data type row for operation '<subscript expression>'
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Passing a stored function as a key
|
||||
#
|
||||
CREATE FUNCTION f1 RETURN INT AS
|
||||
BEGIN
|
||||
RETURN 1;
|
||||
END;
|
||||
$$
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(f1());
|
||||
END;
|
||||
$$
|
||||
ERROR HY000: '"f1"()' is not allowed in this context
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(f1());
|
||||
END;
|
||||
$$
|
||||
ERROR HY000: '"f1"()' is not allowed in this context
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(f1()) := 1;
|
||||
END;
|
||||
$$
|
||||
ERROR HY000: '"f1"()' is not allowed in this context
|
||||
DROP FUNCTION f1;
|
||||
@@ -0,0 +1,248 @@
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
set sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Passing an expression of a wrong type as a key: POINT
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(POINT(1,1));
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(POINT(1,1));
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(POINT(1,1)) := 1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Passing an expression of a wrong type as a key: ROW
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(ROW(1,1));
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(ROW(1,1));
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(ROW(1,1)) := 1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Passing an expression of a wrong type as a key: anchored POINT
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a POINT(1,1));
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1.a%TYPE;
|
||||
BEGIN
|
||||
SELECT marks(idx);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (a POINT(1,1));
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1.a%TYPE;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(idx);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (a POINT(1,1));
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1.a%TYPE;
|
||||
BEGIN
|
||||
marks(idx):= 1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Passing an expression of a wrong type as a key: anchored ROW
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT, b INT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1%ROWTYPE;
|
||||
BEGIN
|
||||
SELECT marks(idx);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (a INT, b INT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1%ROWTYPE;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(idx);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1 (a INT, b INT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
idx t1%ROWTYPE;
|
||||
BEGIN
|
||||
marks(idx):= 1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Passing a stored function as a key
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE FUNCTION f1 RETURN INT AS
|
||||
BEGIN
|
||||
RETURN 1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(f1());
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
SELECT 1 INTO marks(f1());
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(f1()) := 1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
DROP FUNCTION f1;
|
||||
@@ -1,4 +1,5 @@
|
||||
SET sql_mode=ORACLE;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
@@ -105,3 +106,100 @@ Pos Instruction
|
||||
18 destruct associative_array assoc_of_record_0@0
|
||||
19 stmt 0 "SELECT '<block#0' AS comment"
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Call an associative array procedure method directly
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
m1 marks_t:= marks_t(1 => 61, 2 => 62, 3 => 63);
|
||||
BEGIN
|
||||
SELECT m1.count;
|
||||
m1.delete(2);
|
||||
SELECT m1.count, m1(1), m1(3);
|
||||
m1.delete;
|
||||
SELECT m1.count;
|
||||
END;
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set m1@0 marks_t('1'=>61,'2'=>62,'3'=>63)
|
||||
1 stmt 0 "SELECT m1.count"
|
||||
2 stmt 74 "m1.delete(2)"
|
||||
3 stmt 0 "SELECT m1.count, m1(1), m1(3)"
|
||||
4 stmt 74 "m1.delete"
|
||||
5 stmt 0 "SELECT m1.count"
|
||||
6 destruct associative_array m1@0
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Item_method_func::print()
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE salary IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
|
||||
salary_list salary;
|
||||
name VARCHAR2(20);
|
||||
BEGIN
|
||||
WHILE name IS NOT NULL
|
||||
LOOP
|
||||
name:= salary_list.NEXT(name);
|
||||
END LOOP;
|
||||
END;
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set salary_list@0 NULL
|
||||
1 set name@1 NULL
|
||||
2 jump_if_not 5(5) name@1 is not null
|
||||
3 set name@1 salary_list@0.next(name@1)
|
||||
4 jump 2
|
||||
5 destruct associative_array salary_list@0
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Item_splocal_assoc_array_element::print()
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE salary IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
|
||||
salary_list salary:= salary('Rajnisj'=> 62000);
|
||||
v0 NUMBER;
|
||||
BEGIN
|
||||
v0:= salary_list('Rajnisj');
|
||||
SELECT salary_list('Rajnisj') AS c0, v0;
|
||||
END;
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set salary_list@0 salary('Rajnisj'=>62000)
|
||||
1 set v0@1 NULL
|
||||
2 set v0@1 salary_list@0['Rajnisj']
|
||||
3 stmt 0 "SELECT salary_list('Rajnisj') AS c0, v0"
|
||||
4 destruct associative_array salary_list@0
|
||||
CALL p1;
|
||||
c0 v0
|
||||
62000 62000
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Item_splocal_assoc_array_element_field::print()
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE list_t IS TABLE OF person_t INDEX BY INT;
|
||||
list list_t := list_t(1=>person_t('Agnetha', 'Faltskog'));
|
||||
BEGIN
|
||||
list(1).last_name:= REPLACE(list(1).last_name,'Fa','Fä');
|
||||
SELECT list(1).first_name AS first_name, list(1).last_name AS last_name;
|
||||
END;
|
||||
$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
Pos Instruction
|
||||
0 set list@0 list_t('1'=>('Agnetha','Faltskog'))
|
||||
1 set list@0[1].last_name replace(list@0[1].last_name,'Fa','Fä')
|
||||
2 stmt 0 "SELECT list(1).first_name AS first_na..."
|
||||
3 destruct associative_array list@0
|
||||
CALL p1;
|
||||
first_name last_name
|
||||
Agnetha Fältskog
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
-- source include/have_debug.inc
|
||||
|
||||
SET sql_mode=ORACLE;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
@@ -87,3 +88,90 @@ $$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Call an associative array procedure method directly
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
m1 marks_t:= marks_t(1 => 61, 2 => 62, 3 => 63);
|
||||
BEGIN
|
||||
SELECT m1.count;
|
||||
m1.delete(2);
|
||||
SELECT m1.count, m1(1), m1(3);
|
||||
m1.delete;
|
||||
SELECT m1.count;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Item_method_func::print()
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE salary IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
|
||||
salary_list salary;
|
||||
name VARCHAR2(20);
|
||||
BEGIN
|
||||
WHILE name IS NOT NULL
|
||||
LOOP
|
||||
name:= salary_list.NEXT(name);
|
||||
END LOOP;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Item_splocal_assoc_array_element::print()
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE salary IS TABLE OF NUMBER INDEX BY VARCHAR2(20);
|
||||
salary_list salary:= salary('Rajnisj'=> 62000);
|
||||
v0 NUMBER;
|
||||
BEGIN
|
||||
v0:= salary_list('Rajnisj');
|
||||
SELECT salary_list('Rajnisj') AS c0, v0;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Item_splocal_assoc_array_element_field::print()
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE list_t IS TABLE OF person_t INDEX BY INT;
|
||||
list list_t := list_t(1=>person_t('Agnetha', 'Faltskog'));
|
||||
BEGIN
|
||||
list(1).last_name:= REPLACE(list(1).last_name,'Fa','Fä');
|
||||
SELECT list(1).first_name AS first_name, list(1).last_name AS last_name;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SHOW PROCEDURE CODE p1;
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
@@ -0,0 +1,382 @@
|
||||
SET sql_mode=ORACLE;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
#
|
||||
# Using a key expression with a different character set
|
||||
# than the one specified in the INDEX BY clause.
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
assoc assoc_t:= assoc_t('á' => 10);
|
||||
BEGIN
|
||||
assoc('ó'):=20;
|
||||
SELECT assoc('A') AS c1; -- should find 10
|
||||
SELECT assoc('Á') AS c1; -- should find 10
|
||||
SELECT assoc('O') AS c1; -- should find 20
|
||||
SELECT assoc('Ó') AS c1; -- should find 20
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c1
|
||||
10
|
||||
c1
|
||||
10
|
||||
c1
|
||||
20
|
||||
c1
|
||||
20
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Check that methods (exists, delete, next)
|
||||
# work when the passed key has a different character set
|
||||
# than the key character set specified in INDEX BY
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
assoc_latin1 assoc_t:= assoc_t('ß'=>0xDF,'á'=>0xE1,'é'=>0xE9,'ó'=>0xF3,'ú'=>0xFA);
|
||||
key_utf8mb4 VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
BEGIN
|
||||
key_utf8mb4:='ó';
|
||||
SELECT assoc_latin1.exists(key_utf8mb4);
|
||||
assoc_latin1.delete(key_utf8mb4);
|
||||
SELECT assoc_latin1.exists(key_utf8mb4);
|
||||
CREATE TEMPORARY TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
k VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci,
|
||||
val INT);
|
||||
key_utf8mb4:= assoc_latin1.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_utf8mb4, assoc_latin1(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_latin1.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
DROP TEMPORARY TABLE t1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
assoc_latin1.exists(key_utf8mb4)
|
||||
1
|
||||
assoc_latin1.exists(key_utf8mb4)
|
||||
0
|
||||
id k val
|
||||
1 á E1
|
||||
2 é E9
|
||||
3 ú FA
|
||||
4 ß DF
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Assigning arrays with different key character sets and collations
|
||||
# Dumping using a key variable of different characters set and collations
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_latin1_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
TYPE assoc_utf8mb4_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
assoc_latin1 assoc_latin1_t;
|
||||
assoc_utf8mb4 assoc_utf8mb4_t;
|
||||
key_latin1 VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
key_utf8mb4 VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
BEGIN
|
||||
SELECT '# Populating assoc_latin1' AS ``;
|
||||
assoc_latin1('ß'):=0xDF;
|
||||
assoc_latin1('á'):=0xE1;
|
||||
assoc_latin1('é'):=0xE9;
|
||||
assoc_latin1('ó'):=0xF3;
|
||||
assoc_latin1('ú'):=0xFA;
|
||||
SELECT '# Copying to assoc_utf8mb4 from assoc_latin1' AS ``;
|
||||
assoc_utf8mb4:=assoc_latin1;
|
||||
CREATE TEMPORARY TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
k VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci,
|
||||
val INT);
|
||||
SELECT '# Dumping assoc_latin1 using key_latin1. The expected order: á é ó ú ß' AS ``;
|
||||
key_latin1:= assoc_latin1.first;
|
||||
WHILE key_latin1 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_latin1, assoc_latin1(key_latin1));
|
||||
key_latin1:= assoc_latin1.NEXT(key_latin1);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
SELECT '# Dumping assoc_latin1 using key_utf8mb4. The expected order: á é ó ú ß' AS ``;
|
||||
key_utf8mb4:= assoc_latin1.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_utf8mb4, assoc_latin1(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_latin1.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
SELECT '# Dumping assoc_utf8mb4 using key_utf8mb4. The expected order: á é ó ß ú' AS ``;
|
||||
key_utf8mb4:= assoc_utf8mb4.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k,val) VALUES (key_utf8mb4, assoc_utf8mb4(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_utf8mb4.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
SELECT '# Dumping assoc_utf8mb4 using key_latin1. The expected order: á é ó ß ú' AS ``;
|
||||
key_latin1:= assoc_utf8mb4.first;
|
||||
WHILE key_latin1 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k,val) VALUES (key_latin1, assoc_utf8mb4(key_latin1));
|
||||
key_latin1:= assoc_utf8mb4.NEXT(key_latin1);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
DROP TEMPORARY TABLE t1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
|
||||
# Populating assoc_latin1
|
||||
|
||||
# Copying to assoc_utf8mb4 from assoc_latin1
|
||||
|
||||
# Dumping assoc_latin1 using key_latin1. The expected order: á é ó ú ß
|
||||
id k val
|
||||
1 á E1
|
||||
2 é E9
|
||||
3 ó F3
|
||||
4 ú FA
|
||||
5 ß DF
|
||||
|
||||
# Dumping assoc_latin1 using key_utf8mb4. The expected order: á é ó ú ß
|
||||
id k val
|
||||
1 á E1
|
||||
2 é E9
|
||||
3 ó F3
|
||||
4 ú FA
|
||||
5 ß DF
|
||||
|
||||
# Dumping assoc_utf8mb4 using key_utf8mb4. The expected order: á é ó ß ú
|
||||
id k val
|
||||
1 á E1
|
||||
2 é E9
|
||||
3 ó F3
|
||||
4 ß DF
|
||||
5 ú FA
|
||||
|
||||
# Dumping assoc_utf8mb4 using key_latin1. The expected order: á é ó ß ú
|
||||
id k val
|
||||
1 á E1
|
||||
2 é E9
|
||||
3 ó F3
|
||||
4 ß DF
|
||||
5 ú FA
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Assigning arrays with different key character sets and collations
|
||||
# Some values can cause a collision during the assignment, e.g.:
|
||||
# 'ü' is not equal to 'y' in utf8mb4_uca1400_as_ci
|
||||
# 'ü' is equal to 'y' in latin1_swedish_ci
|
||||
# 'y' disappears after the assignment, because it sorts after 'ü' in utf8mb4_uca1400_as_ci
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_latin1_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
TYPE assoc_utf8mb4_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE utf8mb4_uca1400_as_ci;
|
||||
assoc_latin1 assoc_latin1_t;
|
||||
assoc_utf8mb4 assoc_utf8mb4_t:= assoc_utf8mb4_t('å'=>0xC5,'ö'=>0xF6,'ü'=>0xFC,
|
||||
'y'=>0x79,'z'=>0x7A);
|
||||
key_utf8mb4 VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
BEGIN
|
||||
SELECT '# Copying to assoc_latin1 from assoc_utf8mb4' AS ``;
|
||||
assoc_latin1:= assoc_utf8mb4;
|
||||
SHOW WARNINGS;
|
||||
SELECT assoc_utf8mb4.count, assoc_latin1.count;
|
||||
CREATE TEMPORARY TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
k VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci,
|
||||
val INT);
|
||||
SELECT '# Dumping assoc_utf8mb4 using key_utf8mb4' AS ``;
|
||||
key_utf8mb4:= assoc_utf8mb4.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_utf8mb4, assoc_utf8mb4(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_utf8mb4.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
SELECT '# Dumping assoc_latin1 using key_utf8mb4' AS ``;
|
||||
key_utf8mb4:= assoc_latin1.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_utf8mb4, assoc_latin1(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_latin1.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
DROP TEMPORARY TABLE t1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
|
||||
# Copying to assoc_latin1 from assoc_utf8mb4
|
||||
Level Code Message
|
||||
Warning 1859 Duplicate entry for key 'y'
|
||||
assoc_utf8mb4.count assoc_latin1.count
|
||||
5 4
|
||||
|
||||
# Dumping assoc_utf8mb4 using key_utf8mb4
|
||||
id k val
|
||||
1 å C5
|
||||
2 ö F6
|
||||
3 ü FC
|
||||
4 y 79
|
||||
5 z 7A
|
||||
|
||||
# Dumping assoc_latin1 using key_utf8mb4
|
||||
id k val
|
||||
1 ü FC
|
||||
2 z 7A
|
||||
3 å C5
|
||||
4 ö F6
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Copying to a shorter key data type
|
||||
# Oracle does not allow this: expression is of wrong type
|
||||
# MariaDB allows but returns an error if some key does not fit
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_latin1_t IS TABLE OF INT INDEX BY VARCHAR(1) COLLATE latin1_swedish_ci;
|
||||
TYPE assoc_utf8mb4_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE utf8mb4_uca1400_as_ci;
|
||||
assoc_latin1 assoc_latin1_t;
|
||||
assoc_utf8mb4 assoc_utf8mb4_t:= assoc_utf8mb4_t('å'=>0xC5,'öö'=>0xF6,'ü'=>0xFC,
|
||||
'y'=>0x79,'zz'=>0x7A);
|
||||
key_utf8mb4 VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
BEGIN
|
||||
SELECT '# Copying to assoc_latin1 from assoc_utf8mb4' AS ``;
|
||||
assoc_latin1:= assoc_utf8mb4;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
|
||||
# Copying to assoc_latin1 from assoc_utf8mb4
|
||||
ERROR HY000: String 'öö' is too long for INDEX BY (should be no longer than 1)
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Using 2-byte characters in the key
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t:= assoc_t('áááááááááá' => 10);
|
||||
BEGIN
|
||||
SELECT assoc('AAAAAAAAAA'); -- should find
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
assoc('AAAAAAAAAA')
|
||||
10
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Using 3-byte characters in the key
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t:= assoc_t('ḁḁḁḁḁḁḁḁḁḁ' => 10);
|
||||
BEGIN
|
||||
SELECT assoc('AAAAAAAAAA'); -- should find
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
assoc('AAAAAAAAAA')
|
||||
10
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Using 4-byte characters in the key
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
assoc('🅰🅰🅰🅰🅰🅰🅰🅰🅰🅰'):=10;
|
||||
SELECT assoc('AAAAAAAAAA'); -- should find
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
assoc('AAAAAAAAAA')
|
||||
10
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Passing a too long key
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t:= assoc_t('ááááááááááá' => 10);
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: String 'ááááááááááá' is too long for INDEX BY (should be no longer than 10)
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Using a key which cannot be converted to the key character set
|
||||
# The non-convertable part is inside the VARCHAR length
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
assoc assoc_t:= assoc_t('áááááááááя' => 10); -- Nine á + я
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Cannot convert 'utf8mb3' character 0xD18F to 'latin1'
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Using a key which cannot be converted to the key data type
|
||||
# The non-convertable part is outside the VARCHAR length
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
assoc assoc_t:= assoc_t('ááááááááááя' => 10); -- Ten á + я
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: String 'ááááááááááя' is too long for INDEX BY (should be no longer than 10)
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# A binary key re-interpretting as utf8mb4
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
assoc(0x61616161616161616161):=10;
|
||||
SELECT assoc('AAAAAAAAAA') AS c1, assoc(0x41414141414141414141) AS c2;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c1 c2
|
||||
10 10
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# A binary key re-interpretting as utf8mb4
|
||||
# with a bad utf8mb4 sequence inside the VARCHAR length
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
assoc(0x616161616161616161FF):=10; -- Nine 0x61 + 0xFF
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: Invalid utf8mb4 character string: '\xFF'
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# A binary key re-interpretting as utf8mb4
|
||||
# with a bad utf8mb4 sequence outside the VARCHAR length
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
assoc(0x61616161616161616161FF):=10; -- Ten 0x61 + 0xFF
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: String 'aaaaaaaaaa\xFF' is too long for INDEX BY (should be no longer than 10)
|
||||
DROP PROCEDURE p1;
|
||||
@@ -0,0 +1,377 @@
|
||||
SET sql_mode=ORACLE;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Using a key expression with a different character set
|
||||
--echo # than the one specified in the INDEX BY clause.
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
assoc assoc_t:= assoc_t('á' => 10);
|
||||
BEGIN
|
||||
assoc('ó'):=20;
|
||||
SELECT assoc('A') AS c1; -- should find 10
|
||||
SELECT assoc('Á') AS c1; -- should find 10
|
||||
SELECT assoc('O') AS c1; -- should find 20
|
||||
SELECT assoc('Ó') AS c1; -- should find 20
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo #
|
||||
--echo # Check that methods (exists, delete, next)
|
||||
--echo # work when the passed key has a different character set
|
||||
--echo # than the key character set specified in INDEX BY
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
assoc_latin1 assoc_t:= assoc_t('ß'=>0xDF,'á'=>0xE1,'é'=>0xE9,'ó'=>0xF3,'ú'=>0xFA);
|
||||
key_utf8mb4 VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
BEGIN
|
||||
key_utf8mb4:='ó';
|
||||
SELECT assoc_latin1.exists(key_utf8mb4);
|
||||
assoc_latin1.delete(key_utf8mb4);
|
||||
SELECT assoc_latin1.exists(key_utf8mb4);
|
||||
|
||||
CREATE TEMPORARY TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
k VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci,
|
||||
val INT);
|
||||
key_utf8mb4:= assoc_latin1.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_utf8mb4, assoc_latin1(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_latin1.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
DROP TEMPORARY TABLE t1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Assigning arrays with different key character sets and collations
|
||||
--echo # Dumping using a key variable of different characters set and collations
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_latin1_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
TYPE assoc_utf8mb4_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
assoc_latin1 assoc_latin1_t;
|
||||
assoc_utf8mb4 assoc_utf8mb4_t;
|
||||
key_latin1 VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
key_utf8mb4 VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
BEGIN
|
||||
SELECT '# Populating assoc_latin1' AS ``;
|
||||
assoc_latin1('ß'):=0xDF;
|
||||
assoc_latin1('á'):=0xE1;
|
||||
assoc_latin1('é'):=0xE9;
|
||||
assoc_latin1('ó'):=0xF3;
|
||||
assoc_latin1('ú'):=0xFA;
|
||||
|
||||
SELECT '# Copying to assoc_utf8mb4 from assoc_latin1' AS ``;
|
||||
assoc_utf8mb4:=assoc_latin1;
|
||||
|
||||
CREATE TEMPORARY TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
k VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci,
|
||||
val INT);
|
||||
|
||||
SELECT '# Dumping assoc_latin1 using key_latin1. The expected order: á é ó ú ß' AS ``;
|
||||
key_latin1:= assoc_latin1.first;
|
||||
WHILE key_latin1 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_latin1, assoc_latin1(key_latin1));
|
||||
key_latin1:= assoc_latin1.NEXT(key_latin1);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
|
||||
SELECT '# Dumping assoc_latin1 using key_utf8mb4. The expected order: á é ó ú ß' AS ``;
|
||||
key_utf8mb4:= assoc_latin1.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_utf8mb4, assoc_latin1(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_latin1.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
|
||||
|
||||
SELECT '# Dumping assoc_utf8mb4 using key_utf8mb4. The expected order: á é ó ß ú' AS ``;
|
||||
key_utf8mb4:= assoc_utf8mb4.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k,val) VALUES (key_utf8mb4, assoc_utf8mb4(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_utf8mb4.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
|
||||
SELECT '# Dumping assoc_utf8mb4 using key_latin1. The expected order: á é ó ß ú' AS ``;
|
||||
key_latin1:= assoc_utf8mb4.first;
|
||||
WHILE key_latin1 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k,val) VALUES (key_latin1, assoc_utf8mb4(key_latin1));
|
||||
key_latin1:= assoc_utf8mb4.NEXT(key_latin1);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
|
||||
DROP TEMPORARY TABLE t1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo #
|
||||
--echo # Assigning arrays with different key character sets and collations
|
||||
--echo # Some values can cause a collision during the assignment, e.g.:
|
||||
--echo # 'ü' is not equal to 'y' in utf8mb4_uca1400_as_ci
|
||||
--echo # 'ü' is equal to 'y' in latin1_swedish_ci
|
||||
--echo # 'y' disappears after the assignment, because it sorts after 'ü' in utf8mb4_uca1400_as_ci
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_latin1_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
TYPE assoc_utf8mb4_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE utf8mb4_uca1400_as_ci;
|
||||
assoc_latin1 assoc_latin1_t;
|
||||
assoc_utf8mb4 assoc_utf8mb4_t:= assoc_utf8mb4_t('å'=>0xC5,'ö'=>0xF6,'ü'=>0xFC,
|
||||
'y'=>0x79,'z'=>0x7A);
|
||||
key_utf8mb4 VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
BEGIN
|
||||
SELECT '# Copying to assoc_latin1 from assoc_utf8mb4' AS ``;
|
||||
assoc_latin1:= assoc_utf8mb4;
|
||||
SHOW WARNINGS;
|
||||
SELECT assoc_utf8mb4.count, assoc_latin1.count;
|
||||
|
||||
CREATE TEMPORARY TABLE t1 (id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
k VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci,
|
||||
val INT);
|
||||
|
||||
SELECT '# Dumping assoc_utf8mb4 using key_utf8mb4' AS ``;
|
||||
key_utf8mb4:= assoc_utf8mb4.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_utf8mb4, assoc_utf8mb4(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_utf8mb4.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
TRUNCATE TABLE t1;
|
||||
|
||||
SELECT '# Dumping assoc_latin1 using key_utf8mb4' AS ``;
|
||||
key_utf8mb4:= assoc_latin1.first;
|
||||
WHILE key_utf8mb4 IS NOT NULL
|
||||
LOOP
|
||||
INSERT INTO t1 (k, val) VALUES (key_utf8mb4, assoc_latin1(key_utf8mb4));
|
||||
key_utf8mb4:= assoc_latin1.NEXT(key_utf8mb4);
|
||||
END LOOP;
|
||||
SELECT id, k, HEX(val) AS val FROM t1;
|
||||
|
||||
DROP TEMPORARY TABLE t1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo #
|
||||
--echo # Copying to a shorter key data type
|
||||
--echo # Oracle does not allow this: expression is of wrong type
|
||||
--echo # MariaDB allows but returns an error if some key does not fit
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_latin1_t IS TABLE OF INT INDEX BY VARCHAR(1) COLLATE latin1_swedish_ci;
|
||||
TYPE assoc_utf8mb4_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE utf8mb4_uca1400_as_ci;
|
||||
assoc_latin1 assoc_latin1_t;
|
||||
assoc_utf8mb4 assoc_utf8mb4_t:= assoc_utf8mb4_t('å'=>0xC5,'öö'=>0xF6,'ü'=>0xFC,
|
||||
'y'=>0x79,'zz'=>0x7A);
|
||||
key_utf8mb4 VARCHAR(10) COLLATE utf8mb4_uca1400_ai_ci;
|
||||
BEGIN
|
||||
SELECT '# Copying to assoc_latin1 from assoc_utf8mb4' AS ``;
|
||||
assoc_latin1:= assoc_utf8mb4;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_WRONG_STRING_LENGTH
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Using 2-byte characters in the key
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t:= assoc_t('áááááááááá' => 10);
|
||||
BEGIN
|
||||
SELECT assoc('AAAAAAAAAA'); -- should find
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Using 3-byte characters in the key
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t:= assoc_t('ḁḁḁḁḁḁḁḁḁḁ' => 10);
|
||||
BEGIN
|
||||
SELECT assoc('AAAAAAAAAA'); -- should find
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Using 4-byte characters in the key
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
assoc('🅰🅰🅰🅰🅰🅰🅰🅰🅰🅰'):=10;
|
||||
SELECT assoc('AAAAAAAAAA'); -- should find
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Passing a too long key
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t:= assoc_t('ááááááááááá' => 10);
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_WRONG_STRING_LENGTH
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Using a key which cannot be converted to the key character set
|
||||
--echo # The non-convertable part is inside the VARCHAR length
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
assoc assoc_t:= assoc_t('áááááááááя' => 10); -- Nine á + я
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_CANNOT_CONVERT_CHARACTER
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo #
|
||||
--echo # Using a key which cannot be converted to the key data type
|
||||
--echo # The non-convertable part is outside the VARCHAR length
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE latin1_swedish_ci;
|
||||
assoc assoc_t:= assoc_t('ááááááááááя' => 10); -- Ten á + я
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_WRONG_STRING_LENGTH
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # A binary key re-interpretting as utf8mb4
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
assoc(0x61616161616161616161):=10;
|
||||
SELECT assoc('AAAAAAAAAA') AS c1, assoc(0x41414141414141414141) AS c2;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # A binary key re-interpretting as utf8mb4
|
||||
--echo # with a bad utf8mb4 sequence inside the VARCHAR length
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
assoc(0x616161616161616161FF):=10; -- Nine 0x61 + 0xFF
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_INVALID_CHARACTER_STRING
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # A binary key re-interpretting as utf8mb4
|
||||
--echo # with a bad utf8mb4 sequence outside the VARCHAR length
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(10) COLLATE uca1400_ai_ci;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
assoc(0x61616161616161616161FF):=10; -- Ten 0x61 + 0xFF
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_WRONG_STRING_LENGTH
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
@@ -0,0 +1,11 @@
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR(10) INDEX BY VARCHAR(20);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
@@ -0,0 +1,16 @@
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
field_name VARCHAR(100),
|
||||
last_name VARCHAR(100)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY VARCHAR(20);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
@@ -0,0 +1,89 @@
|
||||
SET sql_mode=ORACLE;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
SET debug_dbug='d,assoc_array';
|
||||
CREATE DATABASE test1 CHARACTER SET utf8mb4 COLLATE uca1400_ai_ci;
|
||||
USE test1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR(10) INDEX BY VARCHAR(20);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
Warnings:
|
||||
Note 1003 create_fields: key: len= 80 cs=utf8mb4_uca1400_ai_ci
|
||||
Note 1003 create_fields: val: len= 40 cs=utf8mb4_uca1400_ai_ci
|
||||
Note 1003 create_fields: key: len= 80 cs=utf8mb4_uca1400_ai_ci
|
||||
Note 1003 create_fields: val: len= 40 cs=utf8mb4_uca1400_ai_ci
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
field_name VARCHAR(100),
|
||||
last_name VARCHAR(100)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY VARCHAR(20);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
Warnings:
|
||||
Note 1003 create_fields: key: len= 80 cs=utf8mb4_uca1400_ai_ci
|
||||
Note 1003 create_fields: val: len= 0 cs=binary
|
||||
Note 1003 create_fields: [0]: len= 400 cs=utf8mb4_uca1400_ai_ci
|
||||
Note 1003 create_fields: [1]: len= 400 cs=utf8mb4_uca1400_ai_ci
|
||||
Note 1003 create_fields: key: len= 80 cs=utf8mb4_uca1400_ai_ci
|
||||
Note 1003 create_fields: val: len= 0 cs=binary
|
||||
Note 1003 create_fields: [0]: len= 400 cs=utf8mb4_uca1400_ai_ci
|
||||
Note 1003 create_fields: [1]: len= 400 cs=utf8mb4_uca1400_ai_ci
|
||||
DROP PROCEDURE p1;
|
||||
DROP DATABASE test1;
|
||||
USE test;
|
||||
CREATE DATABASE test1 CHARACTER SET latin1;
|
||||
USE test1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR(10) INDEX BY VARCHAR(20);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
Warnings:
|
||||
Note 1003 create_fields: key: len= 20 cs=latin1_swedish_ci
|
||||
Note 1003 create_fields: val: len= 10 cs=latin1_swedish_ci
|
||||
Note 1003 create_fields: key: len= 20 cs=latin1_swedish_ci
|
||||
Note 1003 create_fields: val: len= 10 cs=latin1_swedish_ci
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
field_name VARCHAR(100),
|
||||
last_name VARCHAR(100)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY VARCHAR(20);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
Warnings:
|
||||
Note 1003 create_fields: key: len= 20 cs=latin1_swedish_ci
|
||||
Note 1003 create_fields: val: len= 0 cs=binary
|
||||
Note 1003 create_fields: [0]: len= 100 cs=latin1_swedish_ci
|
||||
Note 1003 create_fields: [1]: len= 100 cs=latin1_swedish_ci
|
||||
Note 1003 create_fields: key: len= 20 cs=latin1_swedish_ci
|
||||
Note 1003 create_fields: val: len= 0 cs=binary
|
||||
Note 1003 create_fields: [0]: len= 100 cs=latin1_swedish_ci
|
||||
Note 1003 create_fields: [1]: len= 100 cs=latin1_swedish_ci
|
||||
DROP PROCEDURE p1;
|
||||
DROP DATABASE test1;
|
||||
USE test;
|
||||
SET debug_dbug=DEFAULT;
|
||||
@@ -0,0 +1,26 @@
|
||||
-- source include/have_debug.inc
|
||||
|
||||
SET sql_mode=ORACLE;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
SET debug_dbug='d,assoc_array';
|
||||
|
||||
CREATE DATABASE test1 CHARACTER SET utf8mb4 COLLATE uca1400_ai_ci;
|
||||
USE test1;
|
||||
--source sp-assoc-array-debug-p00.inc
|
||||
--source sp-assoc-array-debug-p01.inc
|
||||
DROP DATABASE test1;
|
||||
USE test;
|
||||
|
||||
CREATE DATABASE test1 CHARACTER SET latin1;
|
||||
USE test1;
|
||||
--source sp-assoc-array-debug-p00.inc
|
||||
--source sp-assoc-array-debug-p01.inc
|
||||
DROP DATABASE test1;
|
||||
USE test;
|
||||
|
||||
SET debug_dbug=DEFAULT;
|
||||
@@ -0,0 +1,45 @@
|
||||
SET sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
#
|
||||
# Create a relatively big array, then search in it
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR(32) INDEX BY INT;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
FOR i IN 0..1024*128
|
||||
LOOP
|
||||
assoc(i):= CONCAT('value', i);
|
||||
END LOOP;
|
||||
CREATE TEMPORARY TABLE t1 (a INT, b VARCHAR(32));
|
||||
FOR i IN 0..16
|
||||
LOOP
|
||||
INSERT INTO t1 VALUES (i*10, assoc(i*10));
|
||||
END LOOP;
|
||||
SELECT * FROM t1;
|
||||
DROP TEMPORARY TABLE t1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
a b
|
||||
0 value0
|
||||
10 value10
|
||||
20 value20
|
||||
30 value30
|
||||
40 value40
|
||||
50 value50
|
||||
60 value60
|
||||
70 value70
|
||||
80 value80
|
||||
90 value90
|
||||
100 value100
|
||||
110 value110
|
||||
120 value120
|
||||
130 value130
|
||||
140 value140
|
||||
150 value150
|
||||
160 value160
|
||||
DROP PROCEDURE p1;
|
||||
@@ -0,0 +1,32 @@
|
||||
SET sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Create a relatively big array, then search in it
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR(32) INDEX BY INT;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
FOR i IN 0..1024*128
|
||||
LOOP
|
||||
assoc(i):= CONCAT('value', i);
|
||||
END LOOP;
|
||||
CREATE TEMPORARY TABLE t1 (a INT, b VARCHAR(32));
|
||||
FOR i IN 0..16
|
||||
LOOP
|
||||
INSERT INTO t1 VALUES (i*10, assoc(i*10));
|
||||
END LOOP;
|
||||
SELECT * FROM t1;
|
||||
DROP TEMPORARY TABLE t1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
@@ -0,0 +1,28 @@
|
||||
--echo #
|
||||
--echo # Using a package body variable as a key: a wrong data type: POINT
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PACKAGE pkg AS
|
||||
PROCEDURE p1;
|
||||
END;
|
||||
$$
|
||||
CREATE PACKAGE BODY pkg AS
|
||||
v POINT := POINT(1,1);
|
||||
PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(v);
|
||||
marks(v):= 'x43a';
|
||||
END;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
if (`SELECT @code`)
|
||||
{
|
||||
EXECUTE IMMEDIATE 'SHOW PROCEDURE CODE pkg.p1';
|
||||
}
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CALL pkg.p1;
|
||||
DROP PACKAGE pkg;
|
||||
@@ -0,0 +1,37 @@
|
||||
--echo #
|
||||
--echo # Using a package body variable as a key
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PACKAGE pkg AS
|
||||
PROCEDURE p1;
|
||||
END;
|
||||
$$
|
||||
CREATE PACKAGE BODY pkg AS
|
||||
v1 INT := 1;
|
||||
v2 INT := 2;
|
||||
PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x01', 2 => 'x02');
|
||||
BEGIN
|
||||
SELECT marks(v1);
|
||||
marks(v1):= 'x01a';
|
||||
SELECT marks(v1);
|
||||
SELECT 'x01b' INTO marks(v1);
|
||||
SELECT marks(v1);
|
||||
|
||||
SELECT marks(v2);
|
||||
marks(v2):= 'x02a';
|
||||
SELECT marks(v2);
|
||||
SELECT 'x02b' INTO marks(v2);
|
||||
SELECT marks(v2);
|
||||
END;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
if (`SELECT @code`)
|
||||
{
|
||||
EXECUTE IMMEDIATE 'SHOW PROCEDURE CODE pkg.p1';
|
||||
}
|
||||
CALL pkg.p1;
|
||||
DROP PACKAGE pkg;
|
||||
@@ -0,0 +1,88 @@
|
||||
SET @code=1;
|
||||
SET sql_mode=ORACLE;
|
||||
SET names utf8mb4;
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
#
|
||||
# Using a package body variable as a key: a wrong data type: POINT
|
||||
#
|
||||
CREATE PACKAGE pkg AS
|
||||
PROCEDURE p1;
|
||||
END;
|
||||
$$
|
||||
CREATE PACKAGE BODY pkg AS
|
||||
v POINT := POINT(1,1);
|
||||
PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(v);
|
||||
marks(v):= 'x43a';
|
||||
END;
|
||||
END;
|
||||
$$
|
||||
EXECUTE IMMEDIATE 'SHOW PROCEDURE CODE pkg.p1';
|
||||
Pos Instruction
|
||||
0 set marks@0 marks_t('1'=>'x43','2'=>'x99')
|
||||
1 stmt 0 "SELECT marks(v)"
|
||||
2 set marks@0[PACKAGE_BODY.v@0] 'x43a'
|
||||
3 destruct associative_array marks@0
|
||||
CALL pkg.p1;
|
||||
ERROR HY000: Illegal parameter data type point for operation '<subscript expression>'
|
||||
DROP PACKAGE pkg;
|
||||
#
|
||||
# Using a package body variable as a key
|
||||
#
|
||||
CREATE PACKAGE pkg AS
|
||||
PROCEDURE p1;
|
||||
END;
|
||||
$$
|
||||
CREATE PACKAGE BODY pkg AS
|
||||
v1 INT := 1;
|
||||
v2 INT := 2;
|
||||
PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x01', 2 => 'x02');
|
||||
BEGIN
|
||||
SELECT marks(v1);
|
||||
marks(v1):= 'x01a';
|
||||
SELECT marks(v1);
|
||||
SELECT 'x01b' INTO marks(v1);
|
||||
SELECT marks(v1);
|
||||
SELECT marks(v2);
|
||||
marks(v2):= 'x02a';
|
||||
SELECT marks(v2);
|
||||
SELECT 'x02b' INTO marks(v2);
|
||||
SELECT marks(v2);
|
||||
END;
|
||||
END;
|
||||
$$
|
||||
EXECUTE IMMEDIATE 'SHOW PROCEDURE CODE pkg.p1';
|
||||
Pos Instruction
|
||||
0 set marks@0 marks_t('1'=>'x01','2'=>'x02')
|
||||
1 stmt 0 "SELECT marks(v1)"
|
||||
2 set marks@0[PACKAGE_BODY.v1@0] 'x01a'
|
||||
3 stmt 0 "SELECT marks(v1)"
|
||||
4 stmt 0 "SELECT 'x01b' INTO marks(v1)"
|
||||
5 stmt 0 "SELECT marks(v1)"
|
||||
6 stmt 0 "SELECT marks(v2)"
|
||||
7 set marks@0[PACKAGE_BODY.v2@1] 'x02a'
|
||||
8 stmt 0 "SELECT marks(v2)"
|
||||
9 stmt 0 "SELECT 'x02b' INTO marks(v2)"
|
||||
10 stmt 0 "SELECT marks(v2)"
|
||||
11 destruct associative_array marks@0
|
||||
CALL pkg.p1;
|
||||
marks(v1)
|
||||
x01
|
||||
marks(v1)
|
||||
x01a
|
||||
marks(v1)
|
||||
x01b
|
||||
marks(v2)
|
||||
x02
|
||||
marks(v2)
|
||||
x02a
|
||||
marks(v2)
|
||||
x02b
|
||||
DROP PACKAGE pkg;
|
||||
@@ -0,0 +1,12 @@
|
||||
--source include/have_debug.inc
|
||||
|
||||
SET @code=1;
|
||||
SET sql_mode=ORACLE;
|
||||
SET names utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
--source sp-assoc-array-package-00.inc
|
||||
--source sp-assoc-array-package-01.inc
|
||||
@@ -0,0 +1,67 @@
|
||||
SET sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
#
|
||||
# Using a package body variable as a key: a wrong data type: POINT
|
||||
#
|
||||
CREATE PACKAGE pkg AS
|
||||
PROCEDURE p1;
|
||||
END;
|
||||
$$
|
||||
CREATE PACKAGE BODY pkg AS
|
||||
v POINT := POINT(1,1);
|
||||
PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x43', 2 => 'x99');
|
||||
BEGIN
|
||||
SELECT marks(v);
|
||||
marks(v):= 'x43a';
|
||||
END;
|
||||
END;
|
||||
$$
|
||||
CALL pkg.p1;
|
||||
ERROR HY000: Illegal parameter data type point for operation '<subscript expression>'
|
||||
DROP PACKAGE pkg;
|
||||
#
|
||||
# Using a package body variable as a key
|
||||
#
|
||||
CREATE PACKAGE pkg AS
|
||||
PROCEDURE p1;
|
||||
END;
|
||||
$$
|
||||
CREATE PACKAGE BODY pkg AS
|
||||
v1 INT := 1;
|
||||
v2 INT := 2;
|
||||
PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF VARCHAR(20) INDEX BY INT;
|
||||
marks marks_t:= marks_t(1 => 'x01', 2 => 'x02');
|
||||
BEGIN
|
||||
SELECT marks(v1);
|
||||
marks(v1):= 'x01a';
|
||||
SELECT marks(v1);
|
||||
SELECT 'x01b' INTO marks(v1);
|
||||
SELECT marks(v1);
|
||||
SELECT marks(v2);
|
||||
marks(v2):= 'x02a';
|
||||
SELECT marks(v2);
|
||||
SELECT 'x02b' INTO marks(v2);
|
||||
SELECT marks(v2);
|
||||
END;
|
||||
END;
|
||||
$$
|
||||
CALL pkg.p1;
|
||||
marks(v1)
|
||||
x01
|
||||
marks(v1)
|
||||
x01a
|
||||
marks(v1)
|
||||
x01b
|
||||
marks(v2)
|
||||
x02
|
||||
marks(v2)
|
||||
x02a
|
||||
marks(v2)
|
||||
x02b
|
||||
DROP PACKAGE pkg;
|
||||
@@ -0,0 +1,9 @@
|
||||
SET sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
--source sp-assoc-array-package-00.inc
|
||||
--source sp-assoc-array-package-01.inc
|
||||
@@ -0,0 +1,140 @@
|
||||
SET sql_mode=ORACLE;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
#
|
||||
# Disallow VARCHAR->TEXT propagation for the INDEX BY field
|
||||
# Even for non-strict sql_mode.
|
||||
#
|
||||
SET @sql_mode_old=@@sql_mode;
|
||||
SET sql_mode=REPLACE(@@sql_mode,'STRING_ALL_TABLES','');
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(100000) COLLATE latin1_bin;
|
||||
assoc assoc_t:= assoc_t('a'=>1,'b'=>2);
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR 42000: Column length too big for column '' (max = 65532); use BLOB or TEXT instead
|
||||
DROP PROCEDURE p1;
|
||||
SET sql_mode=@sql_mode_old;
|
||||
#
|
||||
# Check that TEXT works in an array of scalars
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF TEXT INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(1=>'val1',2=>'val2');
|
||||
BEGIN
|
||||
SELECT assoc(1) AS a1, assoc(2) AS a2;
|
||||
CREATE TABLE t1 AS SELECT assoc(1) AS a1, assoc(2) AS a2;
|
||||
SHOW CREATE TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
a1 a2
|
||||
val1 val2
|
||||
Table Create Table
|
||||
t1 CREATE TABLE "t1" (
|
||||
"a1" text DEFAULT NULL,
|
||||
"a2" text DEFAULT NULL
|
||||
)
|
||||
a1 a2
|
||||
val1 val2
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# VARCHAR->TEXT propagation is ok for the data scalar value
|
||||
#
|
||||
SET @sql_mode_old=@@sql_mode;
|
||||
SET sql_mode=REPLACE(@@sql_mode,'STRING_ALL_TABLES','');
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR(100000) INDEX BY VARCHAR(20);
|
||||
assoc assoc_t := assoc_t(1=>'val1',2=>'val2');
|
||||
BEGIN
|
||||
SELECT assoc(1) AS a1, assoc(2) AS a2;
|
||||
CREATE TABLE t1 AS SELECT assoc(1) AS a1, assoc(2) AS a2;
|
||||
SELECT * FROM t1;
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
END;
|
||||
$$
|
||||
Warnings:
|
||||
Note 1246 Converting column 'assoc_t' from VARCHAR to TEXT
|
||||
CALL p1;
|
||||
a1 a2
|
||||
val1 val2
|
||||
a1 a2
|
||||
val1 val2
|
||||
Table Create Table
|
||||
t1 CREATE TABLE "t1" (
|
||||
"a1" mediumtext DEFAULT NULL,
|
||||
"a2" mediumtext DEFAULT NULL
|
||||
)
|
||||
Warnings:
|
||||
Note 1246 Converting column 'assoc_t' from VARCHAR to TEXT
|
||||
DROP PROCEDURE p1;
|
||||
SET sql_mode=@sql_mode_old;
|
||||
#
|
||||
# Check that TEXT record fields work in an array of records
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE rec_t IS RECORD (a TEXT, b LONGTEXT);
|
||||
TYPE assoc_t IS TABLE OF rec_t INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(1=>rec_t('a1','b1'),2=>rec_t('a2','b2'));
|
||||
BEGIN
|
||||
CREATE TABLE t1 AS
|
||||
SELECT assoc(1).a AS a1a, assoc(1).b AS a1b, assoc(2).a AS a2a, assoc(2).b AS a2b;
|
||||
SHOW CREATE TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE "t1" (
|
||||
"a1a" text DEFAULT NULL,
|
||||
"a1b" longtext DEFAULT NULL,
|
||||
"a2a" text DEFAULT NULL,
|
||||
"a2b" longtext DEFAULT NULL
|
||||
)
|
||||
a1a a1b a2a a2b
|
||||
a1 b1 a2 b2
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# VARCHAR->TEXT propagation is ok for the data fields
|
||||
#
|
||||
SET @sql_mode_old=@@sql_mode;
|
||||
SET sql_mode=REPLACE(@@sql_mode,'STRING_ALL_TABLES','');
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE rec_t IS RECORD (a VARCHAR(100000), b VARCHAR(100000000));
|
||||
TYPE assoc_t IS TABLE OF rec_t INDEX BY VARCHAR(20) COLLATE latin1_bin;
|
||||
assoc assoc_t := assoc_t(1=>rec_t('a1','b1'),2=>rec_t('a2','b2'));
|
||||
BEGIN
|
||||
SELECT assoc(1).a, assoc(1).b, assoc(2).a, assoc(2).b;
|
||||
CREATE TABLE t1 AS
|
||||
SELECT assoc(1).a AS a1a, assoc(1).b AS a1b, assoc(2).a AS a2a, assoc(2).b AS a2b;
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
END;
|
||||
$$
|
||||
Warnings:
|
||||
Note 1246 Converting column 'a' from VARCHAR to TEXT
|
||||
Note 1246 Converting column 'b' from VARCHAR to TEXT
|
||||
CALL p1;
|
||||
assoc(1).a assoc(1).b assoc(2).a assoc(2).b
|
||||
a1 b1 a2 b2
|
||||
Table Create Table
|
||||
t1 CREATE TABLE "t1" (
|
||||
"a1a" mediumtext DEFAULT NULL,
|
||||
"a1b" longtext DEFAULT NULL,
|
||||
"a2a" mediumtext DEFAULT NULL,
|
||||
"a2b" longtext DEFAULT NULL
|
||||
)
|
||||
Warnings:
|
||||
Note 1246 Converting column 'a' from VARCHAR to TEXT
|
||||
Note 1246 Converting column 'b' from VARCHAR to TEXT
|
||||
DROP PROCEDURE p1;
|
||||
SET sql_mode=@sql_mode_old;
|
||||
@@ -0,0 +1,119 @@
|
||||
SET sql_mode=ORACLE;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Disallow VARCHAR->TEXT propagation for the INDEX BY field
|
||||
--echo # Even for non-strict sql_mode.
|
||||
--echo #
|
||||
|
||||
SET @sql_mode_old=@@sql_mode;
|
||||
SET sql_mode=REPLACE(@@sql_mode,'STRING_ALL_TABLES','');
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY VARCHAR(100000) COLLATE latin1_bin;
|
||||
assoc assoc_t:= assoc_t('a'=>1,'b'=>2);
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_TOO_BIG_FIELDLENGTH
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
SET sql_mode=@sql_mode_old;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Check that TEXT works in an array of scalars
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF TEXT INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(1=>'val1',2=>'val2');
|
||||
BEGIN
|
||||
SELECT assoc(1) AS a1, assoc(2) AS a2;
|
||||
CREATE TABLE t1 AS SELECT assoc(1) AS a1, assoc(2) AS a2;
|
||||
SHOW CREATE TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # VARCHAR->TEXT propagation is ok for the data scalar value
|
||||
--echo #
|
||||
|
||||
SET @sql_mode_old=@@sql_mode;
|
||||
SET sql_mode=REPLACE(@@sql_mode,'STRING_ALL_TABLES','');
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR(100000) INDEX BY VARCHAR(20);
|
||||
assoc assoc_t := assoc_t(1=>'val1',2=>'val2');
|
||||
BEGIN
|
||||
SELECT assoc(1) AS a1, assoc(2) AS a2;
|
||||
CREATE TABLE t1 AS SELECT assoc(1) AS a1, assoc(2) AS a2;
|
||||
SELECT * FROM t1;
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
SET sql_mode=@sql_mode_old;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Check that TEXT record fields work in an array of records
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE rec_t IS RECORD (a TEXT, b LONGTEXT);
|
||||
TYPE assoc_t IS TABLE OF rec_t INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(1=>rec_t('a1','b1'),2=>rec_t('a2','b2'));
|
||||
BEGIN
|
||||
CREATE TABLE t1 AS
|
||||
SELECT assoc(1).a AS a1a, assoc(1).b AS a1b, assoc(2).a AS a2a, assoc(2).b AS a2b;
|
||||
SHOW CREATE TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # VARCHAR->TEXT propagation is ok for the data fields
|
||||
--echo #
|
||||
|
||||
SET @sql_mode_old=@@sql_mode;
|
||||
SET sql_mode=REPLACE(@@sql_mode,'STRING_ALL_TABLES','');
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE rec_t IS RECORD (a VARCHAR(100000), b VARCHAR(100000000));
|
||||
TYPE assoc_t IS TABLE OF rec_t INDEX BY VARCHAR(20) COLLATE latin1_bin;
|
||||
assoc assoc_t := assoc_t(1=>rec_t('a1','b1'),2=>rec_t('a2','b2'));
|
||||
BEGIN
|
||||
SELECT assoc(1).a, assoc(1).b, assoc(2).a, assoc(2).b;
|
||||
CREATE TABLE t1 AS
|
||||
SELECT assoc(1).a AS a1a, assoc(1).b AS a1b, assoc(2).a AS a2a, assoc(2).b AS a2b;
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
SET sql_mode=@sql_mode_old;
|
||||
@@ -0,0 +1,63 @@
|
||||
set sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
#
|
||||
# MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
#
|
||||
#
|
||||
# Using assoc array scalar elements in a UNION
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(1=>10,2=>20,3=>30);
|
||||
BEGIN
|
||||
SELECT assoc(1) AS c1 UNION SELECT assoc(2) UNION SELECT assoc(3);
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c1
|
||||
10
|
||||
20
|
||||
30
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF TEXT INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(1=>'10',2=>'20',3=>'30');
|
||||
BEGIN
|
||||
SELECT assoc(1) AS c1 UNION SELECT assoc(2) UNION SELECT assoc(3);
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c1
|
||||
10
|
||||
20
|
||||
30
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Using assoc array record elements in a UNION
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(
|
||||
1=>person_t('Agnetha','Fältskog'),
|
||||
2=>person_t('Benny','Andersson'),
|
||||
3=>person_t('Björn', 'Ulvaeus'),
|
||||
4=>person_t('Anni-Frid','Lyngstad'));
|
||||
BEGIN
|
||||
SELECT assoc(1).first_name AS first_name, assoc(1).last_name AS last_name
|
||||
UNION SELECT assoc(2).first_name, assoc(2).last_name
|
||||
UNION SELECT assoc(3).first_name, assoc(3).last_name
|
||||
UNION SELECT assoc(4).first_name, assoc(4).last_name;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
first_name last_name
|
||||
Agnetha Fältskog
|
||||
Benny Andersson
|
||||
Björn Ulvaeus
|
||||
Anni-Frid Lyngstad
|
||||
DROP PROCEDURE p1;
|
||||
@@ -0,0 +1,63 @@
|
||||
set sql_mode=oracle;
|
||||
SET NAMES utf8mb4;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-34319 DECLARE TYPE .. TABLE OF .. INDEX BY in stored routines
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Using assoc array scalar elements in a UNION
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(1=>10,2=>20,3=>30);
|
||||
BEGIN
|
||||
SELECT assoc(1) AS c1 UNION SELECT assoc(2) UNION SELECT assoc(3);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF TEXT INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(1=>'10',2=>'20',3=>'30');
|
||||
BEGIN
|
||||
SELECT assoc(1) AS c1 UNION SELECT assoc(2) UNION SELECT assoc(3);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Using assoc array record elements in a UNION
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY INT;
|
||||
assoc assoc_t:= assoc_t(
|
||||
1=>person_t('Agnetha','Fältskog'),
|
||||
2=>person_t('Benny','Andersson'),
|
||||
3=>person_t('Björn', 'Ulvaeus'),
|
||||
4=>person_t('Anni-Frid','Lyngstad'));
|
||||
BEGIN
|
||||
SELECT assoc(1).first_name AS first_name, assoc(1).last_name AS last_name
|
||||
UNION SELECT assoc(2).first_name, assoc(2).last_name
|
||||
UNION SELECT assoc(3).first_name, assoc(3).last_name
|
||||
UNION SELECT assoc(4).first_name, assoc(4).last_name;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
@@ -43,6 +43,45 @@ END;
|
||||
$$
|
||||
ERROR HY000: 'associative_array' is not allowed in this context
|
||||
#
|
||||
# Bad key data type
|
||||
#
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR2(20) INDEX BY DOUBLE;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
ERROR HY000: Illegal parameter data type double for operation '<array index data type>'
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR2(20) INDEX BY POINT;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
ERROR HY000: Illegal parameter data type point for operation '<array index data type>'
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR2(20) INDEX BY DATE;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
ERROR HY000: Illegal parameter data type datetime for operation '<array index data type>'
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR2(20) INDEX BY ROW(a INT, b INT);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'ROW(a INT, b INT);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END' at line 2
|
||||
#
|
||||
# RECORD element type
|
||||
#
|
||||
DECLARE
|
||||
@@ -207,6 +246,48 @@ BEGIN
|
||||
NULL;
|
||||
END' at line 3
|
||||
#
|
||||
# Wrong use: assoc_array_var;
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
assoc0;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'assoc0;
|
||||
END' at line 5
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
`assoc0`;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '`assoc0`;
|
||||
END' at line 5
|
||||
#
|
||||
# Wrong use: assoc_array_var(1);
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
assoc0(1);
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'assoc0(1);
|
||||
END' at line 5
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
`assoc0`(1);
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near '`assoc0`(1);
|
||||
END' at line 5
|
||||
#
|
||||
# Wrong use: assoc_array_var.x(1)
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
@@ -354,9 +435,9 @@ END LOOP;
|
||||
END;
|
||||
$$
|
||||
Warnings:
|
||||
Warning 1366 Incorrect double value: 'Klaus' for column ``.``.`` at row 0
|
||||
Warning 1366 Incorrect double value: 'Lee' for column ``.``.`` at row 0
|
||||
Warning 1366 Incorrect double value: 'Arun' for column ``.``.`` at row 0
|
||||
Warning 1366 Incorrect double value: 'Klaus' for column ``.``.`marks` at row 0
|
||||
Warning 1366 Incorrect double value: 'Lee' for column ``.``.`marks` at row 0
|
||||
Warning 1366 Incorrect double value: 'Arun' for column ``.``.`marks` at row 0
|
||||
#
|
||||
# Anchored ROWTYPE for array element
|
||||
#
|
||||
@@ -662,6 +743,45 @@ $$
|
||||
marks.EXISTS(4)
|
||||
0
|
||||
#
|
||||
# Make sure DELETE does not work as a method-function
|
||||
#
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
SELECT marks.DELETE;
|
||||
END;
|
||||
$$
|
||||
ERROR 42S22: Unknown column 'marks' in 'DELETE'
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
DO marks.DELETE;
|
||||
END;
|
||||
$$
|
||||
ERROR 42S22: Unknown column 'marks' in 'DELETE'
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
SELECT marks.DELETE(0);
|
||||
END;
|
||||
$$
|
||||
ERROR 42S22: Unknown column 'marks' in 'DELETE'
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
DO marks.DELETE(0);
|
||||
END;
|
||||
$$
|
||||
ERROR 42S22: Unknown column 'marks' in 'DELETE'
|
||||
#
|
||||
# DELETE
|
||||
#
|
||||
DECLARE
|
||||
@@ -671,18 +791,14 @@ BEGIN
|
||||
marks(0) := 62;
|
||||
marks(1) := 78;
|
||||
marks(2) := 99;
|
||||
SELECT marks.DELETE(1);
|
||||
marks.DELETE(1);
|
||||
SELECT marks.EXISTS(0), marks.EXISTS(1), marks.EXISTS(2);
|
||||
SELECT marks.DELETE;
|
||||
marks.DELETE;
|
||||
SELECT marks.EXISTS(0), marks.EXISTS(1), marks.EXISTS(2);
|
||||
END;
|
||||
$$
|
||||
marks.DELETE(1)
|
||||
0
|
||||
marks.EXISTS(0) marks.EXISTS(1) marks.EXISTS(2)
|
||||
1 0 1
|
||||
marks.DELETE
|
||||
0
|
||||
marks.EXISTS(0) marks.EXISTS(1) marks.EXISTS(2)
|
||||
0 0 0
|
||||
#
|
||||
@@ -695,7 +811,7 @@ BEGIN
|
||||
marks(0) := 62;
|
||||
marks(1) := 78;
|
||||
marks(2) := 99;
|
||||
SELECT marks.DELETE(1, 2);
|
||||
marks.DELETE(1, 2);
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: Incorrect number of arguments for DELETE ; expected 1, got 2
|
||||
@@ -707,21 +823,40 @@ TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
SELECT marks.DELETE(NULL);
|
||||
marks.DELETE(NULL);
|
||||
END;
|
||||
$$
|
||||
marks.DELETE(NULL)
|
||||
0
|
||||
#
|
||||
# DELETE on scalar
|
||||
#
|
||||
DECLARE
|
||||
marks INTEGER;
|
||||
BEGIN
|
||||
SELECT marks.DELETE(1);
|
||||
marks.DELETE(1);
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: FUNCTION marks.DELETE does not exist. Check the 'Function Name Parsing and Resolution' section in the Reference Manual
|
||||
ERROR 42000: PROCEDURE marks.DELETE does not exist
|
||||
#
|
||||
# Make sure COUNT does not work as a method-procedure
|
||||
#
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
marks.COUNT;
|
||||
END;
|
||||
$$
|
||||
ERROR 42S22: Unknown column 'marks' in 'COUNT'
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
marks.COUNT();
|
||||
END;
|
||||
$$
|
||||
ERROR 42S22: Unknown column 'marks' in 'COUNT'
|
||||
#
|
||||
# COUNT
|
||||
#
|
||||
@@ -735,7 +870,7 @@ marks(2) := 99;
|
||||
SELECT marks.COUNT;
|
||||
marks(3) := 44;
|
||||
SELECT marks.COUNT;
|
||||
SELECT marks.DELETE(1);
|
||||
marks.DELETE(1);
|
||||
SELECT marks.COUNT;
|
||||
END;
|
||||
$$
|
||||
@@ -743,8 +878,6 @@ marks.COUNT
|
||||
3
|
||||
marks.COUNT
|
||||
4
|
||||
marks.DELETE(1)
|
||||
0
|
||||
marks.COUNT
|
||||
3
|
||||
#
|
||||
@@ -767,7 +900,7 @@ BEGIN
|
||||
marks('Clementine Montgomery') := 99;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: Specified key was too long; max key length is 10 bytes
|
||||
ERROR HY000: String 'Clementine Montgomery' is too long for INDEX BY (should be no longer than 10)
|
||||
#
|
||||
# VARCHAR2 key fix
|
||||
#
|
||||
@@ -2069,7 +2202,7 @@ BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: This version of MariaDB doesn't yet support 'nested associative arrays'
|
||||
ERROR HY000: Illegal parameter data type associative_array for operation '<array element data type>'
|
||||
#
|
||||
# Ensure that nested assoc array types cannot be used for record field
|
||||
#
|
||||
@@ -2138,7 +2271,7 @@ person_t('Michael', 'Widenius') IN (person_by_nickname('Monty'))
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 select ('Michael','Widenius') = person_by_nickname['Monty']@0['Monty'] AS "person_t('Michael', 'Widenius') IN (person_by_nickname('Monty'))"
|
||||
Note 1003 select ('Michael','Widenius') = person_by_nickname@0['Monty'] AS "person_t('Michael', 'Widenius') IN (person_by_nickname('Monty'))"
|
||||
#
|
||||
# EXPLAIN SELECT for field of element of array
|
||||
#
|
||||
@@ -2158,7 +2291,7 @@ $$
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 select person_by_nickname['Monty'].first_name@0['Monty'].0 AS "person_by_nickname('Monty').first_name"
|
||||
Note 1003 select person_by_nickname@0['Monty'].first_name AS "person_by_nickname('Monty').first_name"
|
||||
#
|
||||
# EXPLAIN SELECT for IS NULL with array argument
|
||||
#
|
||||
@@ -2233,17 +2366,25 @@ m1 IS NULL m1 IS NOT NULL m2 is NULL m2 IS NOT NULL
|
||||
m1 IS NULL m1 IS NOT NULL m2 is NULL m2 IS NOT NULL
|
||||
0 1 0 1
|
||||
#
|
||||
# Call associative array method directly
|
||||
# Call an associative array procedure method directly
|
||||
#
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
m1 marks_t:= marks_t(1 => 62);
|
||||
m1 marks_t:= marks_t(1 => 61, 2 => 62, 3 => 63);
|
||||
BEGIN
|
||||
SELECT m1.count;
|
||||
m1.delete(2);
|
||||
SELECT m1.count, m1(1), m1(3);
|
||||
m1.delete;
|
||||
SELECT m1.count;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'm1.delete;
|
||||
END' at line 5
|
||||
m1.count
|
||||
3
|
||||
m1.count m1(1) m1(3)
|
||||
2 61 63
|
||||
m1.count
|
||||
0
|
||||
#
|
||||
# Create an associative array type sharing the same name as a built-in function
|
||||
# TODO: This should be allowed
|
||||
@@ -2591,3 +2732,134 @@ END;
|
||||
$$
|
||||
ERROR HY000: 'count("t1"."a")' is not allowed in this context
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Non-constant expressions are not allowed as a key: a scalar value
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(1) := 78;
|
||||
SELECT marks(rand());
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: 'rand()' is not allowed in this context
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(1) := 78;
|
||||
SELECT marks(78+rand());
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: '78 + rand()' is not allowed in this context
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(rand()) := 78;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: 'rand()' is not allowed in this context
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(1) := 78;
|
||||
SELECT 79 INTO marks(rand());
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: 'rand()' is not allowed in this context
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Non-constant expressions are not allowed as a key: a row value field
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY INTEGER;
|
||||
assoc assoc_t:= assoc_t (1 => person_t('Iqbal','Hassan'));
|
||||
BEGIN
|
||||
SELECT assoc(rand()).first_name;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: 'rand()' is not allowed in this context
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY INTEGER;
|
||||
assoc assoc_t:= assoc_t(1 => person_t('Iqbal','Hassan'));
|
||||
BEGIN
|
||||
assoc(rand()).first_name:= 'John';
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: 'rand()' is not allowed in this context
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY INTEGER;
|
||||
assoc assoc_t:= assoc_t(1 => person_t('Iqbal','Hassan'));
|
||||
BEGIN
|
||||
SELECT 'John' INTO assoc(rand()).first_name;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR HY000: 'rand()' is not allowed in this context
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# The below script with a scalar element produces a warning.
|
||||
# Make sure the variable name is correct in the warning.
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
assoc0(1):= 10e10;
|
||||
SELECT assoc0(1) AS c1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c1
|
||||
2147483647
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'assoc0' at row 0
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# The below script with a record element produces a warning.
|
||||
# Make sure the variable name is correct in the warning.
|
||||
#
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE rec_t IS RECORD (i INT);
|
||||
TYPE assoc0_t IS TABLE OF rec_t INDEX BY INT;
|
||||
assoc0 assoc0_t := assoc0_t(1 => rec_t(0));
|
||||
BEGIN
|
||||
assoc0(1).i := 10e10;
|
||||
SELECT assoc0(1).i AS c1;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c1
|
||||
2147483647
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'i' at row 0
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
@@ -66,6 +66,58 @@ $$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Bad key data type
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR2(20) INDEX BY DOUBLE;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR2(20) INDEX BY POINT;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR2(20) INDEX BY DATE;
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_PARSE_ERROR
|
||||
CREATE OR REPLACE PROCEDURE p1 AS
|
||||
TYPE assoc_t IS TABLE OF VARCHAR2(20) INDEX BY ROW(a INT, b INT);
|
||||
assoc assoc_t;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # RECORD element type
|
||||
--echo #
|
||||
@@ -224,6 +276,62 @@ $$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Wrong use: assoc_array_var;
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_PARSE_ERROR
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
assoc0;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_PARSE_ERROR
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
`assoc0`;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Wrong use: assoc_array_var(1);
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_PARSE_ERROR
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
assoc0(1);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_PARSE_ERROR
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
`assoc0`(1);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Wrong use: assoc_array_var.x(1)
|
||||
--echo #
|
||||
@@ -718,6 +826,60 @@ END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Make sure DELETE does not work as a method-function
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
SELECT marks.DELETE;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
DO marks.DELETE;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
SELECT marks.DELETE(0);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
DO marks.DELETE(0);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # DELETE
|
||||
--echo #
|
||||
@@ -729,10 +891,10 @@ BEGIN
|
||||
marks(0) := 62;
|
||||
marks(1) := 78;
|
||||
marks(2) := 99;
|
||||
SELECT marks.DELETE(1);
|
||||
marks.DELETE(1);
|
||||
SELECT marks.EXISTS(0), marks.EXISTS(1), marks.EXISTS(2);
|
||||
|
||||
SELECT marks.DELETE;
|
||||
marks.DELETE;
|
||||
SELECT marks.EXISTS(0), marks.EXISTS(1), marks.EXISTS(2);
|
||||
END;
|
||||
$$
|
||||
@@ -750,7 +912,7 @@ BEGIN
|
||||
marks(0) := 62;
|
||||
marks(1) := 78;
|
||||
marks(2) := 99;
|
||||
SELECT marks.DELETE(1, 2);
|
||||
marks.DELETE(1, 2);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
@@ -764,7 +926,7 @@ DECLARE
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
SELECT marks.DELETE(NULL);
|
||||
marks.DELETE(NULL);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
@@ -773,15 +935,46 @@ DELIMITER ;$$
|
||||
--echo # DELETE on scalar
|
||||
--echo #
|
||||
DELIMITER $$;
|
||||
--error ER_FUNC_INEXISTENT_NAME_COLLISION
|
||||
--error ER_SP_DOES_NOT_EXIST
|
||||
DECLARE
|
||||
marks INTEGER;
|
||||
BEGIN
|
||||
SELECT marks.DELETE(1);
|
||||
marks.DELETE(1);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Make sure COUNT does not work as a method-procedure
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
marks.COUNT;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(0) := 62;
|
||||
marks.COUNT();
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # COUNT
|
||||
--echo #
|
||||
@@ -798,7 +991,7 @@ BEGIN
|
||||
marks(3) := 44;
|
||||
SELECT marks.COUNT;
|
||||
|
||||
SELECT marks.DELETE(1);
|
||||
marks.DELETE(1);
|
||||
SELECT marks.COUNT;
|
||||
END;
|
||||
$$
|
||||
@@ -822,7 +1015,7 @@ DELIMITER ;$$
|
||||
--echo # VARCHAR2 key length error
|
||||
--echo #
|
||||
DELIMITER $$;
|
||||
--error ER_TOO_LONG_KEY
|
||||
--error ER_WRONG_STRING_LENGTH
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY VARCHAR2(10);
|
||||
marks marks_t;
|
||||
@@ -2380,7 +2573,7 @@ SET sql_mode=ORACLE;
|
||||
--echo # Ensure that nested assoc array types are properly parsed (without crash, etc)
|
||||
--echo #
|
||||
DELIMITER $$;
|
||||
--error ER_NOT_SUPPORTED_YET
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
TYPE classes_t IS TABLE OF marks_t INDEX BY INTEGER;
|
||||
@@ -2546,15 +2739,18 @@ DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Call associative array method directly
|
||||
--echo # Call an associative array procedure method directly
|
||||
--echo #
|
||||
DELIMITER $$;
|
||||
--error ER_PARSE_ERROR
|
||||
DECLARE
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
m1 marks_t:= marks_t(1 => 62);
|
||||
m1 marks_t:= marks_t(1 => 61, 2 => 62, 3 => 63);
|
||||
BEGIN
|
||||
SELECT m1.count;
|
||||
m1.delete(2);
|
||||
SELECT m1.count, m1(1), m1(3);
|
||||
m1.delete;
|
||||
SELECT m1.count;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
@@ -2946,3 +3142,163 @@ $$
|
||||
DELIMITER ;$$
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Non-constant expressions are not allowed as a key: a scalar value
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(1) := 78;
|
||||
SELECT marks(rand());
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(1) := 78;
|
||||
SELECT marks(78+rand());
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(rand()) := 78;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE marks_t IS TABLE OF NUMBER INDEX BY INTEGER;
|
||||
marks marks_t;
|
||||
BEGIN
|
||||
marks(1) := 78;
|
||||
SELECT 79 INTO marks(rand());
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Non-constant expressions are not allowed as a key: a row value field
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY INTEGER;
|
||||
assoc assoc_t:= assoc_t (1 => person_t('Iqbal','Hassan'));
|
||||
BEGIN
|
||||
SELECT assoc(rand()).first_name;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY INTEGER;
|
||||
assoc assoc_t:= assoc_t(1 => person_t('Iqbal','Hassan'));
|
||||
BEGIN
|
||||
assoc(rand()).first_name:= 'John';
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE person_t IS RECORD
|
||||
(
|
||||
first_name VARCHAR(64),
|
||||
last_name VARCHAR(64)
|
||||
);
|
||||
TYPE assoc_t IS TABLE OF person_t INDEX BY INTEGER;
|
||||
assoc assoc_t:= assoc_t(1 => person_t('Iqbal','Hassan'));
|
||||
BEGIN
|
||||
SELECT 'John' INTO assoc(rand()).first_name;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NOT_ALLOWED_IN_THIS_CONTEXT
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # The below script with a scalar element produces a warning.
|
||||
--echo # Make sure the variable name is correct in the warning.
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE assoc0_t IS TABLE OF INT INDEX BY INT;
|
||||
assoc0 assoc0_t;
|
||||
BEGIN
|
||||
assoc0(1):= 10e10;
|
||||
SELECT assoc0(1) AS c1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # The below script with a record element produces a warning.
|
||||
--echo # Make sure the variable name is correct in the warning.
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1 AS
|
||||
TYPE rec_t IS RECORD (i INT);
|
||||
TYPE assoc0_t IS TABLE OF rec_t INDEX BY INT;
|
||||
assoc0 assoc0_t := assoc0_t(1 => rec_t(0));
|
||||
BEGIN
|
||||
assoc0(1).i := 10e10;
|
||||
SELECT assoc0(1).i AS c1;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -26,6 +26,7 @@
|
||||
|
||||
|
||||
class Item_field_packable;
|
||||
class Assoc_array_data;
|
||||
|
||||
|
||||
/*
|
||||
@@ -35,7 +36,11 @@ class Type_handler_assoc_array: public Type_handler_composite
|
||||
{
|
||||
public:
|
||||
static const Type_handler_assoc_array *singleton();
|
||||
|
||||
static bool check_key_expression_type(Item *key);
|
||||
static bool check_functor_args(THD *thd, List<Item> *args,
|
||||
const char *opname);
|
||||
static bool check_subscript_expression(const Type_handler *formal_th,
|
||||
Item *key);
|
||||
public:
|
||||
bool has_methods() const override { return true; }
|
||||
bool has_functors() const override { return true; }
|
||||
@@ -59,22 +64,7 @@ public:
|
||||
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);
|
||||
}
|
||||
const override;
|
||||
|
||||
bool sp_variable_declarations_finalize(THD *thd,
|
||||
LEX *lex, int nvars,
|
||||
@@ -194,18 +184,36 @@ public:
|
||||
Item *item,
|
||||
const LEX_CSTRING &expr_str)
|
||||
const override;
|
||||
virtual
|
||||
Item *create_item_method(THD *thd,
|
||||
protected:
|
||||
Item *create_item_method_func(THD *thd,
|
||||
const Lex_ident_sys &ca,
|
||||
const Lex_ident_sys &cb,
|
||||
List<Item> *args,
|
||||
const Lex_ident_cli_st &query_fragment)
|
||||
const override;
|
||||
const;
|
||||
Item *create_item_method_proc(THD *thd,
|
||||
const Lex_ident_sys &ca,
|
||||
const Lex_ident_sys &cb,
|
||||
List<Item> *args,
|
||||
const Lex_ident_cli_st &query_fragment)
|
||||
const;
|
||||
public:
|
||||
virtual
|
||||
Item *create_item_method(THD *thd,
|
||||
object_method_type_t type,
|
||||
const Lex_ident_sys &ca,
|
||||
const Lex_ident_sys &cb,
|
||||
List<Item> *args,
|
||||
const Lex_ident_cli_st &query_fragment)
|
||||
const override
|
||||
{
|
||||
return type == object_method_type_t::PROCEDURE ?
|
||||
create_item_method_proc(thd, ca, cb, args, query_fragment) :
|
||||
create_item_method_func(thd, ca, cb, args, query_fragment);
|
||||
}
|
||||
|
||||
bool key_to_lex_cstring(THD *thd,
|
||||
Item **key,
|
||||
const LEX_CSTRING& name,
|
||||
LEX_CSTRING& out_key) const override;
|
||||
LEX_CSTRING key_to_lex_cstring(THD *thd, const sp_rcontext_addr &var,
|
||||
Item **key, String *buffer) const override;
|
||||
|
||||
bool get_item_index(THD *thd,
|
||||
const Item_field *item,
|
||||
@@ -242,10 +250,14 @@ protected:
|
||||
Item_field_packable *m_item_pack;
|
||||
Item *m_item;
|
||||
|
||||
/*
|
||||
Modified copy of the key definition
|
||||
*/
|
||||
Spvar_definition m_key_def;
|
||||
// A helper method
|
||||
Assoc_array_data *assoc_tree_search(String *key) const
|
||||
{
|
||||
return reinterpret_cast<Assoc_array_data *>(tree_search((TREE*) &m_tree,
|
||||
key,
|
||||
m_key_field));
|
||||
}
|
||||
|
||||
public:
|
||||
Field_assoc_array(uchar *ptr_arg,
|
||||
const LEX_CSTRING *field_name_arg);
|
||||
@@ -263,6 +275,11 @@ public:
|
||||
return m_def;
|
||||
}
|
||||
|
||||
const Spvar_definition *get_key_def() const
|
||||
{
|
||||
return m_def->head();
|
||||
}
|
||||
|
||||
Item_field *make_item_field_spvar(THD *thd,
|
||||
const Spvar_definition &def) override;
|
||||
|
||||
@@ -292,7 +309,7 @@ public:
|
||||
Field *get_key_field() const { return m_key_field; }
|
||||
|
||||
protected:
|
||||
bool copy_and_convert_key(const String *key, String &key_copy) const;
|
||||
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);
|
||||
|
||||
@@ -303,7 +320,7 @@ protected:
|
||||
bool init_element_base(THD *thd);
|
||||
|
||||
bool create_element_buffer(THD *thd, Binary_string *buffer);
|
||||
bool insert_element(String &&key, Binary_string &&element);
|
||||
bool insert_element(THD *thd, Assoc_array_data *data, bool warn_on_dup_key);
|
||||
bool get_next_or_prior_key(const String *curr_key,
|
||||
String *new_key,
|
||||
bool is_next);
|
||||
@@ -403,7 +420,17 @@ class Item_splocal_assoc_array_base :public Item_composite_base
|
||||
{
|
||||
protected:
|
||||
Item *m_key;
|
||||
|
||||
/*
|
||||
In expressions:
|
||||
- assoc_array(key_expr)
|
||||
- assoc_array(key_expr).field
|
||||
execute "fix_fields_if_needed" for the key_expr and check if it's
|
||||
compatible with the "INDEX_BY key_type" clause of the assoc array
|
||||
definition.
|
||||
@param thd - Current thd
|
||||
@param array_addr - The run-time address of the assoc array variable.
|
||||
*/
|
||||
bool fix_key(THD *thd, const sp_rcontext_addr &array_addr);
|
||||
public:
|
||||
Item_splocal_assoc_array_base(Item *key);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
# MDEV-34319 DECLARE TYPE type_name IS RECORD (..) with scalar members in stored routines
|
||||
#
|
||||
#
|
||||
# UUID is not allowed as an assoc array key type
|
||||
#
|
||||
SET sql_mode=ORACLE;
|
||||
DECLARE
|
||||
TYPE assoc_t IS TABLE OF INTEGER INDEX BY UUID;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
ERROR HY000: Illegal parameter data type uuid for operation '<array index data type>'
|
||||
#
|
||||
# Demonstrate UDT field type for associative array element
|
||||
#
|
||||
SET sql_mode=ORACLE;
|
||||
|
||||
@@ -2,6 +2,21 @@
|
||||
--echo # MDEV-34319 DECLARE TYPE type_name IS RECORD (..) with scalar members in stored routines
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # UUID is not allowed as an assoc array key type
|
||||
--echo #
|
||||
|
||||
SET sql_mode=ORACLE;
|
||||
DELIMITER $$;
|
||||
--error ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION
|
||||
DECLARE
|
||||
TYPE assoc_t IS TABLE OF INTEGER INDEX BY UUID;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Demonstrate UDT field type for associative array element
|
||||
|
||||
@@ -3264,6 +3264,11 @@ protected:
|
||||
sp_rcontext *get_rcontext(sp_rcontext *local_ctx) const;
|
||||
Item_field *get_variable(sp_rcontext *ctx) const;
|
||||
|
||||
sp_rcontext_addr rcontext_addr() const
|
||||
{
|
||||
return sp_rcontext_addr(m_rcontext_handler, m_var_idx);
|
||||
}
|
||||
|
||||
public:
|
||||
Item_splocal(THD *thd, const Sp_rcontext_handler *rh,
|
||||
const LEX_CSTRING *sp_var_name, uint sp_var_idx,
|
||||
|
||||
@@ -1319,13 +1319,15 @@ sp_instr_set_row_field::print(String *str)
|
||||
int
|
||||
sp_instr_set_composite_field_by_name::exec_core(THD *thd, uint *nextp)
|
||||
{
|
||||
StringBuffer<64> buffer;
|
||||
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))
|
||||
m_field_name= handler->key_to_lex_cstring(thd, *this, &m_key, &buffer);
|
||||
if (!m_field_name.str)
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1391,8 +1393,10 @@ sp_instr_set_composite_field_by_key::exec_core(THD *thd, uint *nextp)
|
||||
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))
|
||||
StringBuffer<64> buffer;
|
||||
const LEX_CSTRING key= handler->key_to_lex_cstring(thd, *this, &m_key,
|
||||
&buffer);
|
||||
if (!key.str)
|
||||
return true;
|
||||
|
||||
int res= get_rcontext(thd)->set_variable_composite_field_by_key(thd,
|
||||
|
||||
@@ -432,19 +432,6 @@ sp_condition_value *sp_pcontext::find_condition(const LEX_CSTRING *name,
|
||||
}
|
||||
|
||||
|
||||
bool sp_type_def_list::type_defs_add_record(THD *thd,
|
||||
const Lex_ident_column &name,
|
||||
Row_definition_list *field)
|
||||
{
|
||||
auto p= new (thd->mem_root) sp_type_def_record(name, field);
|
||||
|
||||
if (p == nullptr)
|
||||
return true;
|
||||
|
||||
return m_type_defs.append(p);
|
||||
}
|
||||
|
||||
|
||||
sp_type_def *sp_pcontext::find_type_def(const LEX_CSTRING &name,
|
||||
bool current_scope_only) const
|
||||
{
|
||||
@@ -458,21 +445,6 @@ 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_pcontext::find_declared_or_predefined_condition(THD *thd,
|
||||
const LEX_CSTRING *name)
|
||||
|
||||
@@ -739,37 +739,14 @@ public:
|
||||
sp_type_def *find_type_def(const LEX_CSTRING &name,
|
||||
bool current_scope_only) const;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
// Record.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool type_defs_declare_record(THD *thd,
|
||||
const Lex_ident_column &name,
|
||||
Row_definition_list *field)
|
||||
bool type_defs_add(THD *thd, sp_type_def *def)
|
||||
{
|
||||
if (unlikely(find_type_def(name, true)))
|
||||
if (unlikely(find_type_def(def->get_name(), true)))
|
||||
{
|
||||
my_error(ER_SP_DUP_DECL, MYF(0), name.str);
|
||||
my_error(ER_SP_DUP_DECL, MYF(0), def->get_name().str);
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
return sp_type_def_list::type_defs_add(def);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -108,14 +108,10 @@ public:
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool type_defs_add_record(THD *thd, const Lex_ident_column &name,
|
||||
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);
|
||||
bool type_defs_add(sp_type_def *def)
|
||||
{
|
||||
return m_type_defs.append(def);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -8954,7 +8954,7 @@ 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_pos(Lex_ident_cli(a.pos(), a.end() - a.pos())),
|
||||
m_spvar(nullptr),
|
||||
m_defined_parts(1)
|
||||
{
|
||||
@@ -8964,32 +8964,34 @@ Qualified_ident::Qualified_ident(THD *thd, const Lex_ident_cli_st &a)
|
||||
|
||||
|
||||
Qualified_ident::Qualified_ident(THD *thd, const Lex_ident_cli_st &a,
|
||||
const Lex_ident_sys_st &b)
|
||||
:m_cli_pos(a.pos()),
|
||||
const Lex_ident_cli_st &b)
|
||||
:m_pos(Lex_ident_cli(a.pos(), b.end() - a.pos())),
|
||||
m_spvar(nullptr),
|
||||
m_defined_parts(2)
|
||||
{
|
||||
DBUG_ASSERT(a.pos() < b.end());
|
||||
m_parts[0]= Lex_ident_sys(thd, &a);
|
||||
m_parts[1]= b;
|
||||
m_parts[1]= Lex_ident_sys(thd, &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()),
|
||||
const Lex_ident_cli_st &b,
|
||||
const Lex_ident_cli_st &c)
|
||||
:m_pos(Lex_ident_cli(a.pos(), c.end() - a.pos())),
|
||||
m_spvar(nullptr),
|
||||
m_defined_parts(3)
|
||||
{
|
||||
DBUG_ASSERT(a.pos() < c.end());
|
||||
m_parts[0]= Lex_ident_sys(thd, &a);
|
||||
m_parts[1]= b;
|
||||
m_parts[2]= c;
|
||||
m_parts[1]= Lex_ident_sys(thd, &b);
|
||||
m_parts[2]= Lex_ident_sys(thd, &c);
|
||||
}
|
||||
|
||||
|
||||
Qualified_ident::Qualified_ident(const Lex_ident_sys_st &a)
|
||||
:m_cli_pos(nullptr),
|
||||
:m_pos(Lex_ident_cli((const char *) nullptr, 0)),
|
||||
m_spvar(nullptr),
|
||||
m_defined_parts(1)
|
||||
{
|
||||
|
||||
@@ -7407,28 +7407,29 @@ public:
|
||||
class Qualified_ident: public Sql_alloc
|
||||
{
|
||||
protected:
|
||||
const char *m_cli_pos;
|
||||
Lex_ident_sys_st m_parts[3];
|
||||
Lex_ident_cli_st m_pos;
|
||||
Lex_ident_sys 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);
|
||||
const Lex_ident_cli_st &b);
|
||||
Qualified_ident(THD *thd,
|
||||
const Lex_ident_cli_st &a,
|
||||
const Lex_ident_sys_st &b,
|
||||
const Lex_ident_sys_st &c);
|
||||
const Lex_ident_cli_st &b,
|
||||
const Lex_ident_cli_st &c);
|
||||
|
||||
Qualified_ident(const Lex_ident_sys_st &a);
|
||||
/*
|
||||
Returns the position of the first character of the identifier in
|
||||
the client string.
|
||||
Returns the client query fragment starting at the first character
|
||||
of the leftmost identifier and ending at after the last character
|
||||
of the rightmist identifier.
|
||||
*/
|
||||
const char *pos() const
|
||||
const Lex_ident_cli_st &pos() const
|
||||
{
|
||||
return m_cli_pos;
|
||||
return m_pos;
|
||||
}
|
||||
|
||||
sp_variable *spvar() const
|
||||
@@ -7436,7 +7437,7 @@ public:
|
||||
return m_spvar;
|
||||
}
|
||||
|
||||
const Lex_ident_sys_st &part(uint i) const
|
||||
const Lex_ident_sys &part(uint i) const
|
||||
{
|
||||
DBUG_ASSERT(i < array_elements(m_parts));
|
||||
return m_parts[i];
|
||||
@@ -7447,9 +7448,23 @@ public:
|
||||
return m_defined_parts;
|
||||
}
|
||||
|
||||
void set_cli_pos(const char *pos)
|
||||
/*
|
||||
When initializing m_parts[n] in the constructor, a EOM could happen.
|
||||
This method checks that all defined parts were initialized without error.
|
||||
*/
|
||||
bool is_sane() const
|
||||
{
|
||||
m_cli_pos= pos;
|
||||
for (uint i= 0; i < m_defined_parts; i++)
|
||||
{
|
||||
if (m_parts[i].is_null())
|
||||
return false; // E.g. EOM happened in the constructor
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void set_pos(const Lex_ident_cli_st &pos)
|
||||
{
|
||||
m_pos= pos;
|
||||
}
|
||||
void set_spvar(sp_variable *spvar)
|
||||
{
|
||||
|
||||
141
sql/sql_lex.cc
141
sql/sql_lex.cc
@@ -8966,8 +8966,10 @@ Item *LEX::create_item_ident(THD *thd,
|
||||
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);
|
||||
return spv->type_handler()->
|
||||
create_item_method(thd,
|
||||
Type_handler::object_method_type_t::FUNCTION,
|
||||
sys_a, sys_b, NULL, query_fragment);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9291,7 +9293,7 @@ bool LEX::set_variable(const Qualified_ident *ident,
|
||||
{
|
||||
if (unlikely(ident->part(2).length))
|
||||
{
|
||||
thd->parse_error(ER_SYNTAX_ERROR, ident->pos());
|
||||
thd->parse_error(ER_SYNTAX_ERROR, ident->pos().str);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -10124,6 +10126,51 @@ bool LEX::call_statement_start_or_lvalue_assign(THD *thd,
|
||||
}
|
||||
|
||||
|
||||
bool LEX::direct_call(THD *thd, const Qualified_ident *ident,
|
||||
List<Item> *args)
|
||||
{
|
||||
DBUG_ASSERT(ident);
|
||||
if (!ident->spvar())
|
||||
return false; // A procedure call
|
||||
|
||||
/*
|
||||
ident->part(0) is a known SP variable.
|
||||
Search for a procedure method of the variable, e.g.:
|
||||
assoc_array_var.delete('key');
|
||||
*/
|
||||
Item *item;
|
||||
if (!ident->spvar()->type_handler()->has_methods() ||
|
||||
ident->part(1).is_null() ||
|
||||
!ident->part(2).is_null())
|
||||
{
|
||||
/*
|
||||
E.g.:
|
||||
spvar_int.method(); -- The SP variable data type does not have methods
|
||||
spvar.step1.step2(); -- A 3-step method call of an SP variable
|
||||
(we don't have 3-step methods yet)
|
||||
*/
|
||||
thd->parse_error(ER_SYNTAX_ERROR, ident->pos().str);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(item= ident->spvar()->type_handler()->
|
||||
create_item_method(thd,
|
||||
Type_handler::object_method_type_t::PROCEDURE,
|
||||
ident->part(0), ident->part(1),
|
||||
args, ident->pos())))
|
||||
{
|
||||
DBUG_ASSERT(thd->is_error());
|
||||
return true;
|
||||
}
|
||||
sql_command= SQLCOM_DO;
|
||||
DBUG_ASSERT(insert_list == nullptr);
|
||||
if (!(insert_list= List<Item>::make(thd->mem_root, item)))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LEX::assoc_assign_start(THD *thd, Qualified_ident *ident)
|
||||
{
|
||||
if (unlikely(ident->spvar() == NULL))
|
||||
@@ -10134,7 +10181,7 @@ bool LEX::assoc_assign_start(THD *thd, Qualified_ident *ident)
|
||||
|
||||
LEX *lex= this;
|
||||
lex->set_stmt_init();
|
||||
if (sp_create_assignment_lex(thd, ident->pos()))
|
||||
if (sp_create_assignment_lex(thd, ident->pos().str))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
@@ -10523,9 +10570,10 @@ Item *LEX::make_item_func_or_method_call(THD *thd,
|
||||
(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))
|
||||
if (Item *item= spv->type_handler()->
|
||||
create_item_method(thd,
|
||||
Type_handler::object_method_type_t::FUNCTION,
|
||||
sys_a, sys_b, args, query_fragment))
|
||||
{
|
||||
item->set_name(thd, query_fragment, thd->charset());
|
||||
return item;
|
||||
@@ -12766,6 +12814,60 @@ Lex_field_type_st::set_handler_length_flags(const Type_handler *handler,
|
||||
}
|
||||
|
||||
|
||||
bool LEX::declare_type_record(THD *thd,
|
||||
const Lex_ident_sys_st &type_name,
|
||||
Row_definition_list *fields)
|
||||
{
|
||||
sp_type_def *tdef=
|
||||
new (thd->mem_root) sp_type_def_record(Lex_ident_column(type_name), fields);
|
||||
if (unlikely(!tdef || spcont->type_defs_add(thd, tdef)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool LEX::declare_type_assoc_array(THD *thd,
|
||||
const Lex_ident_sys_st &type_name,
|
||||
Spvar_definition *key,
|
||||
Spvar_definition *value)
|
||||
{
|
||||
const auto aa= "associative_array"_Lex_ident_plugin;
|
||||
const Type_handler *th= Type_handler::handler_by_name_or_error(thd, aa);
|
||||
if (unlikely(!th))
|
||||
return true;
|
||||
|
||||
sp_type_def *tdef=
|
||||
new (thd->mem_root) sp_type_def_composite2(Lex_ident_column(type_name),
|
||||
th, key, value);
|
||||
if (unlikely(!tdef || spcont->type_defs_add(thd, tdef)))
|
||||
return true;
|
||||
|
||||
Column_definition def;
|
||||
def.set_handler(th);
|
||||
def.set_attr_const_void_ptr(0, tdef);
|
||||
Lex_field_type_st ltype;
|
||||
ltype.set(th);
|
||||
return def.type_handler()->
|
||||
Column_definition_set_attributes(thd, &def, ltype,
|
||||
COLUMN_DEFINITION_ROUTINE_LOCAL);
|
||||
}
|
||||
|
||||
|
||||
bool LEX::set_field_type_udt_or_typedef(Lex_field_type_st *type,
|
||||
const LEX_CSTRING &name,
|
||||
const Lex_length_and_dec_st &attr)
|
||||
{
|
||||
bool is_typedef= false;
|
||||
if (unlikely(set_field_type_typedef(type, name, &is_typedef)))
|
||||
return true;
|
||||
|
||||
if (is_typedef)
|
||||
return false;
|
||||
|
||||
return set_field_type_udt(type, name, attr);
|
||||
}
|
||||
|
||||
|
||||
bool LEX::set_field_type_udt(Lex_field_type_st *type,
|
||||
const LEX_CSTRING &name,
|
||||
const Lex_length_and_dec_st &attr)
|
||||
@@ -12789,34 +12891,21 @@ bool LEX::set_cast_type_udt(Lex_cast_type_st *type,
|
||||
}
|
||||
|
||||
|
||||
bool LEX::set_field_type_composite(Lex_field_type_st *type,
|
||||
bool LEX::set_field_type_typedef(Lex_field_type_st *type,
|
||||
const LEX_CSTRING &name,
|
||||
bool with_collection,
|
||||
bool *is_composite)
|
||||
bool *is_typedef)
|
||||
{
|
||||
DBUG_ASSERT(type);
|
||||
DBUG_ASSERT(is_composite);
|
||||
DBUG_ASSERT(is_typedef);
|
||||
|
||||
sp_type_def *composite= NULL;
|
||||
|
||||
*is_composite= false;
|
||||
*is_typedef= false;
|
||||
if (spcont)
|
||||
{
|
||||
if ((composite= spcont->find_type_def(name, false)))
|
||||
{
|
||||
if (with_collection ||
|
||||
likely(composite->type_handler() == &type_handler_row))
|
||||
if (const sp_type_def *composite= spcont->find_type_def(name, false))
|
||||
{
|
||||
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;
|
||||
*is_typedef= true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3918,6 +3918,15 @@ public:
|
||||
bool call_statement_start(THD *thd, const Qualified_ident *ident);
|
||||
bool call_statement_start_or_lvalue_assign(THD *thd,
|
||||
Qualified_ident *ident);
|
||||
/*
|
||||
Create instructions for a direct call (without the CALL keyword):
|
||||
sp1; - a schema procedure call
|
||||
db1.sp1; - a schema procedure call
|
||||
pkg1.sp1; - a package procedure call
|
||||
db1.pkg1.sp1; - a package procedure call
|
||||
assoc_array.delete - an SP variable procedure method call
|
||||
*/
|
||||
bool direct_call(THD *thd, const Qualified_ident *ident, List<Item> *args);
|
||||
|
||||
bool assoc_assign_start(THD *thd, Qualified_ident *ident);
|
||||
sp_variable *find_variable(const LEX_CSTRING *name,
|
||||
@@ -4988,10 +4997,19 @@ public:
|
||||
bool set_cast_type_udt(Lex_cast_type_st *type,
|
||||
const LEX_CSTRING &name);
|
||||
|
||||
bool set_field_type_composite(Lex_field_type_st *type,
|
||||
bool declare_type_record(THD *thd,
|
||||
const Lex_ident_sys_st &type_name,
|
||||
Row_definition_list *fields);
|
||||
bool declare_type_assoc_array(THD *thd,
|
||||
const Lex_ident_sys_st &type_name,
|
||||
Spvar_definition *key,
|
||||
Spvar_definition *value);
|
||||
bool set_field_type_typedef(Lex_field_type_st *type,
|
||||
const LEX_CSTRING &name,
|
||||
bool with_collection,
|
||||
bool *is_composite);
|
||||
bool *is_typedef);
|
||||
bool set_field_type_udt_or_typedef(Lex_field_type_st *type,
|
||||
const LEX_CSTRING &name,
|
||||
const Lex_length_and_dec_st &attr);
|
||||
|
||||
bool map_data_type(const Lex_ident_sys_st &schema,
|
||||
Lex_field_type_st *type) const;
|
||||
|
||||
@@ -293,6 +293,7 @@ public:
|
||||
inline list_node* last_node() { return *last; }
|
||||
inline list_node* first_node() { return first;}
|
||||
inline void *head() { return first->info; }
|
||||
inline const void *head() const { return first->info; }
|
||||
inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
|
||||
inline bool is_empty() const { return first == &end_of_list ; }
|
||||
inline list_node *last_ref() { return &end_of_list; }
|
||||
@@ -503,6 +504,7 @@ public:
|
||||
inline bool push_front(const T *a, MEM_ROOT *mem_root)
|
||||
{ return base_list::push_front((void*) a, mem_root); }
|
||||
inline T* head() {return (T*) base_list::head(); }
|
||||
inline const T* head() const {return (const T*) base_list::head(); }
|
||||
inline T** head_ref() {return (T**) base_list::head_ref(); }
|
||||
inline T* pop() {return (T*) base_list::pop(); }
|
||||
inline void append(List<T> *list) { base_list::append(list); }
|
||||
|
||||
@@ -489,6 +489,10 @@ public:
|
||||
if (!alloced)
|
||||
thread_specific= 1;
|
||||
}
|
||||
bool get_thread_specific() const
|
||||
{
|
||||
return thread_specific;
|
||||
}
|
||||
bool is_alloced() const { return alloced; }
|
||||
inline uint32 alloced_length() const { return Alloced_length;}
|
||||
inline uint32 extra_allocation() const { return extra_alloc;}
|
||||
|
||||
@@ -5297,7 +5297,7 @@ raise_bad_data_type_for_functor(const Qualified_ident &ident,
|
||||
DBUG_ASSERT(ident.defined_parts() > 0 && ident.defined_parts() <= 3);
|
||||
|
||||
char param[MYSQL_ERRMSG_SIZE];
|
||||
uint used= 0;
|
||||
size_t used= 0;
|
||||
for (uint i= 0; i < ident.defined_parts() && used < sizeof(param); i++)
|
||||
{
|
||||
used+= my_snprintf(param + used,
|
||||
|
||||
@@ -3924,6 +3924,13 @@ protected:
|
||||
enum_field_types type)
|
||||
const;
|
||||
public:
|
||||
|
||||
enum class object_method_type_t
|
||||
{
|
||||
FUNCTION,
|
||||
PROCEDURE
|
||||
};
|
||||
|
||||
static const Type_handler *handler_by_name(THD *thd, const LEX_CSTRING &name);
|
||||
static const Type_handler *handler_by_name_or_error(THD *thd,
|
||||
const LEX_CSTRING &name);
|
||||
@@ -4690,7 +4697,7 @@ public:
|
||||
DBUG_ASSERT(0); // Should have checked has_functors().
|
||||
return nullptr;
|
||||
}
|
||||
virtual Item *create_item_method(THD *thd,
|
||||
virtual Item *create_item_method(THD *thd, object_method_type_t type,
|
||||
const Lex_ident_sys &ca,
|
||||
const Lex_ident_sys &cb,
|
||||
List<Item> *args,
|
||||
|
||||
@@ -392,11 +392,34 @@ public:
|
||||
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
|
||||
/*
|
||||
Get a key value from an expression and convert it into the internal form
|
||||
suitable for the variable.
|
||||
|
||||
@param thd - Current thd
|
||||
@param var - The variable aaddress
|
||||
@param key - The expression
|
||||
@param buffer - The string buffer, e.g. used for val_str().
|
||||
|
||||
@retutns - An null LEX_CSTRING {0,0} in case if key->val_str()
|
||||
returned NULL, or if could not convert the value to
|
||||
the internal form
|
||||
- A non-null LEX_CSTRING, usually pointing to "buffer",
|
||||
with an internal key representation
|
||||
|
||||
In case of an VARCHAR-key asssoc array, the key value is converted
|
||||
to the character set explicitlye or implicitly specified in the
|
||||
INDEX BY clause.
|
||||
In case of an integer-key assoc array, the key value is checked to
|
||||
be inside the allowed range according to the integer type specified
|
||||
in the INDEX BY clause.
|
||||
*/
|
||||
virtual LEX_CSTRING key_to_lex_cstring(THD *thd,
|
||||
const sp_rcontext_addr &var,
|
||||
Item **key,
|
||||
String *buffer) const
|
||||
{
|
||||
return false;
|
||||
return Lex_cstring();
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
112
sql/sql_yacc.yy
112
sql/sql_yacc.yy
@@ -1437,7 +1437,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
%type <json_on_response> json_on_response
|
||||
|
||||
%type <Lex_field_type> field_type field_type_all field_type_all_builtin
|
||||
field_type_all_with_composites
|
||||
field_type_all_with_typedefs
|
||||
qualified_field_type
|
||||
field_type_numeric
|
||||
field_type_string
|
||||
@@ -1448,8 +1448,6 @@ bool my_yyoverflow(short **a, YYSTYPE **b, size_t *yystacksize);
|
||||
|
||||
%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>
|
||||
@@ -3633,7 +3631,7 @@ sp_decl_idents_init_vars:
|
||||
|
||||
sp_decl_variable_list:
|
||||
sp_decl_idents_init_vars
|
||||
field_type_all_with_composites
|
||||
field_type_all_with_typedefs
|
||||
{
|
||||
if (Lex->last_field->set_attributes(thd, $2,
|
||||
COLUMN_DEFINITION_ROUTINE_LOCAL))
|
||||
@@ -6536,45 +6534,15 @@ field_type_all:
|
||||
}
|
||||
;
|
||||
|
||||
%ifdef ORACLE
|
||||
field_type_all_with_record:
|
||||
field_type_all_with_typedefs:
|
||||
field_type_all_builtin
|
||||
{
|
||||
Lex->map_data_type(Lex_ident_sys(), &($$= $1));
|
||||
}
|
||||
| udt_name float_options srid_option
|
||||
{
|
||||
bool is_composite= false;
|
||||
if (unlikely(Lex->set_field_type_composite(&$$, $1, false,
|
||||
&is_composite)))
|
||||
if (unlikely(Lex->set_field_type_udt_or_typedef(&$$, $1, $2)))
|
||||
MYSQL_YYABORT;
|
||||
|
||||
if (!is_composite)
|
||||
{
|
||||
if (Lex->set_field_type_udt(&$$, $1, $2))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
}
|
||||
;
|
||||
%endif
|
||||
|
||||
field_type_all_with_composites:
|
||||
field_type_all_builtin
|
||||
{
|
||||
Lex->map_data_type(Lex_ident_sys(), &($$= $1));
|
||||
}
|
||||
| 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;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
@@ -19454,13 +19422,8 @@ direct_call_or_lvalue_assign:
|
||||
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())
|
||||
if (Lex->direct_call(thd, $1, $2) ||
|
||||
Lex->check_cte_dependencies_and_resolve_references())
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
@@ -19736,19 +19699,22 @@ ident_cli_directly_assignable:
|
||||
optionally_qualified_directly_assignable:
|
||||
ident_cli_directly_assignable
|
||||
{
|
||||
if (unlikely(!($$= new (thd->mem_root) Qualified_ident(thd, $1))))
|
||||
if (unlikely(!($$= new (thd->mem_root) Qualified_ident(thd, $1)) ||
|
||||
!$$->is_sane()))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| ident_cli_directly_assignable '.' ident
|
||||
| ident_cli_directly_assignable '.' ident_cli
|
||||
{
|
||||
if (unlikely(!($$= new (thd->mem_root) Qualified_ident(thd, $1,
|
||||
$3))))
|
||||
$3)) ||
|
||||
!$$->is_sane()))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| ident_cli_directly_assignable '.' ident '.' ident
|
||||
| ident_cli_directly_assignable '.' ident_cli '.' ident_cli
|
||||
{
|
||||
if (unlikely(!($$= new (thd->mem_root) Qualified_ident(thd, $1,
|
||||
$3, $5))))
|
||||
$3, $5)) ||
|
||||
!$$->is_sane()))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
@@ -19759,7 +19725,7 @@ set_assign:
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
lex->set_stmt_init();
|
||||
if (sp_create_assignment_lex(thd, $1->pos()))
|
||||
if (sp_create_assignment_lex(thd, $1->pos().str))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
set_expr_or_default
|
||||
@@ -20364,7 +20330,7 @@ typed_ident:
|
||||
;
|
||||
|
||||
assoc_array_table_types:
|
||||
field_type_all_with_record
|
||||
field_type_all_with_typedefs
|
||||
{
|
||||
if (Lex->last_field->set_attributes(thd, $1,
|
||||
COLUMN_DEFINITION_ROUTINE_LOCAL))
|
||||
@@ -20403,31 +20369,6 @@ assoc_array_table_types:
|
||||
}
|
||||
;
|
||||
|
||||
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_variable_list
|
||||
| ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond
|
||||
@@ -20468,27 +20409,22 @@ sp_decl_non_handler:
|
||||
}
|
||||
| typed_ident IS RECORD_SYM rec_type_body
|
||||
{
|
||||
if (unlikely(Lex->spcont->
|
||||
type_defs_declare_record(thd, Lex_ident_column($1), $4)))
|
||||
if (unlikely(Lex->declare_type_record(thd, $1, $4)))
|
||||
MYSQL_YYABORT;
|
||||
|
||||
$$.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(),
|
||||
Lex->init_last_field(new (thd->mem_root) Spvar_definition(),
|
||||
&empty_clex_str);
|
||||
}
|
||||
assoc_array_index_type
|
||||
INDEX_SYM BY field_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)))
|
||||
if (Lex->last_field->set_attributes(thd, $9,
|
||||
COLUMN_DEFINITION_ROUTINE_LOCAL))
|
||||
MYSQL_YYABORT;
|
||||
auto def= static_cast<Spvar_definition*>(Lex->last_field);
|
||||
if (unlikely(Lex->declare_type_assoc_array(thd, $1, def, $5)))
|
||||
MYSQL_YYABORT;
|
||||
$$.vars= $$.conds= $$.hndlrs= $$.curs= 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user