Skip to content

Commit 90f8178

Browse files
committed
MDEV-10152 Add support for TYPE .. IS REF CURSOR
Adding support for the strict cursor data types: Example 1a: TYPE rec0_t IS RECORD (a INT, VARCHAR(10)); TYPE cur0_t IS REF CURSOR RETURN rec0_t; Example 1b: TYPE rec0_t IS RECORD (a t1.a%TYPE, b t1.b%TYPE); TYPE cur0_t IS REF CURSOR RETURN rec0_t; Example 1c: TYPE rec0_t IS RECORD (a INT, VARCHAR(10)); r0 rec0_t; TYPE cur0_t IS REF CURSOR RETURN r0%TYPE; Example 1d: TYPE rec0_t IS RECORD (a t1.a%TYPE, b t1.b%TYPE); r0 rec0_t; TYPE cur0_t IS REF CURSOR RETURN r0%TYPE; Example2a: TYPE cur0_t IS REF CURSOR RETURN t1%ROWTYPE; -- t1 is a table Example 2b: r0 t1%ROWTYPE; TYPE cur0_t IS REF CURSOR RETURN r0%TYPE; Example3a: CURSOR cursor_sample IS SELECT a,b FROM t1; TYPE cur0_t IS REF CURSOR RETURN cursor_sample%ROWTYPE; Example3b: CURSOR cursor_sample IS SELECT a,b FROM t1; r0 cursor_sample%ROWTYPE; TYPE cur0_t IS REF CURSOR RETURN r0%TYPE; If a cursor variable is declared with a RETURN clause then: 1. At OPEN type the data type of the SELECT list row is compared for compatibility with the cursor RETURN data type. The SELECT list row must be assignable to the RETURN type row. If case if assignability is not meet, an error is raised Assignability means: - The arity of the SELECT list must be equal to the arity of the RETURN clause - Every n-th field of the SELECT list must be assignable to the n-th field of the RETURN Clause 2. At FETCH time, the data is fetched in two steps: a. On the first step the data is fetched into a virtual table with the row type described in the RETURN clause b. On the second step the data is copied from the virtual table to the target fetch list. Data type conversion can happen on this step. Change details: Adding new methods: - sp_cursor::check_assignability_to - Virtual_tmp_table::check_assignability_from - Virtual_tmp_table::sp_set_from_select_list - Virtual_tmp_table::sp_save_in_vtable - Virtual_tmp_table::sp_save_in_target_list - LEX::check_ref_cursor_components - LEX::make_sp_instr_copy_struct_for_last_context_variables - LEX::declare_type_ref_cursor - sp_cursor::Select_fetch_into_spvars::send_data_with_return_type Adding new members: - sp_instr_copen_by_ref::m_cursor_name - Select_fetch_into_spvars::m_return_type - Select_materialize::m_cursor_name - Select_materialize::m_return_type Adding new virtual methods: - Item::resolve_spvar_cursor_rowtype - Type_handler::Spvar_definition_resolve_type_refs - Server_side_cursor::check_assignability_to - Overriding Select_materialize::prepare to raise an error when the cursor returned data type is not compatible with the RETURN clause Making these methods virtual: - Field::check_assignability_from Adding new classes: - sp_type_def_ref - RowTypeBuffer Adding new constructors to: - Spvar_definition Adding new helper methods (e.g. to reuse the code) - Field::store_field_maybe_null - ChanBuffer::append_ulonglong - sp_pcontext::set_type_for_last_context_variables Minor changes: - Making TABLE::export_structure const - Overriding Item_splocal::type_extra_attributes. It was forgotten in earlier changes. Adding new error messages - ER_CANNOT_CAST_ON_IDENT1_ASSIGNMENT_FOR_OPERATION - ER_CANNOT_CAST_ON_IDENT2_ASSIGNMENT_FOR_OPERATION
1 parent bfcb303 commit 90f8178

153 files changed

Lines changed: 13881 additions & 96 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

mysql-test/suite/compat/oracle/r/sp-record.result

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,7 @@ CREATE PACKAGE pkg1 AS
817817
PROCEDURE p1();
818818
PROCEDURE p2();
819819
END;
820+
$$
820821
CREATE PACKAGE BODY pkg1 AS
821822
TYPE rec0_t IS RECORD (a INT, b VARCHAR(2), c INT);
822823
FUNCTION private_f1() RETURN rec0_t AS

mysql-test/suite/compat/oracle/t/sp-record.test

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -887,6 +887,7 @@ CREATE PACKAGE pkg1 AS
887887
PROCEDURE p1();
888888
PROCEDURE p2();
889889
END;
890+
$$
890891
CREATE PACKAGE BODY pkg1 AS
891892
TYPE rec0_t IS RECORD (a INT, b VARCHAR(2), c INT);
892893
FUNCTION private_f1() RETURN rec0_t AS

plugin/type_assoc_array/sql_type_assoc_array.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2425,7 +2425,11 @@ bool Type_handler_assoc_array::
24252425
return true;
24262426
}
24272427

2428-
if (unlikely(tdef->def(1).type_handler() == this))
2428+
/*
2429+
Disallow complex types such as assoc array, ref cursors
2430+
as assoc array elements.
2431+
*/
2432+
if (unlikely(tdef->def(1).type_handler()->is_complex()))
24292433
{
24302434
my_error(ER_ILLEGAL_PARAMETER_DATA_TYPE_FOR_OPERATION, MYF(0),
24312435
tdef->def(1).type_handler()->name().ptr(),
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
SET sql_mode=ORACLE;
2+
#
3+
# MDEV-10152 Add support for TYPE .. IS REF CURSOR
4+
#
5+
CREATE PROCEDURE p1 AS
6+
TYPE rec0_t IS RECORD (a INT, b VARCHAR(32), c INT);
7+
TYPE rec1_t IS RECORD (a INT, b VARCHAR(32));
8+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
9+
TYPE cur1_t IS REF CURSOR RETURN rec1_t;
10+
c0 cur0_t;
11+
c1 cur1_t;
12+
BEGIN
13+
SELECT COALESCE(c0,c1);
14+
END;
15+
$$
16+
CALL p1;
17+
ERROR HY000: Illegal parameter data types row<2> and row<3> for operation 'coalesce'
18+
DROP PROCEDURE p1;
19+
CREATE PROCEDURE p1 AS
20+
TYPE rec0_t IS RECORD (a INT, b VARCHAR(10));
21+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
22+
c0 cur0_t;
23+
c1 SYS_REFCURSOR;
24+
c2 SYS_REFCURSOR;
25+
BEGIN
26+
c2:= COALESCE(c0, c1);
27+
c2:= COALESCE(c1, c0);
28+
END
29+
$$
30+
CALL p1;
31+
DROP PROCEDURE p1;
32+
CREATE PROCEDURE p1 AS
33+
TYPE rec0_t IS RECORD (a INT, b TIME);
34+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
35+
c0, c1, c2 cur0_t;
36+
r0 rec0_t;
37+
BEGIN
38+
OPEN c1 FOR SELECT 1 AS a,'10:20:30' AS b;
39+
c2:= COALESCE(c0,c1);
40+
FETCH c2 INTO r0;
41+
CLOSE c2;
42+
SELECT r0.a, r0.b;
43+
END;
44+
$$
45+
CALL p1;
46+
r0.a r0.b
47+
1 10:20:30
48+
DROP PROCEDURE p1;
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
SET sql_mode=ORACLE;
2+
3+
--echo #
4+
--echo # MDEV-10152 Add support for TYPE .. IS REF CURSOR
5+
--echo #
6+
7+
8+
# COALESCE for two different strong cursors is not allowed
9+
10+
DELIMITER $$;
11+
CREATE PROCEDURE p1 AS
12+
TYPE rec0_t IS RECORD (a INT, b VARCHAR(32), c INT);
13+
TYPE rec1_t IS RECORD (a INT, b VARCHAR(32));
14+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
15+
TYPE cur1_t IS REF CURSOR RETURN rec1_t;
16+
c0 cur0_t;
17+
c1 cur1_t;
18+
BEGIN
19+
SELECT COALESCE(c0,c1);
20+
END;
21+
$$
22+
DELIMITER ;$$
23+
--error ER_ILLEGAL_PARAMETER_DATA_TYPES2_FOR_OPERATION
24+
CALL p1;
25+
DROP PROCEDURE p1;
26+
27+
28+
29+
# COALESCE(weak,strong) and COALESCE(strong,weak) is allowed (weak is returned)
30+
31+
DELIMITER $$;
32+
CREATE PROCEDURE p1 AS
33+
TYPE rec0_t IS RECORD (a INT, b VARCHAR(10));
34+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
35+
c0 cur0_t;
36+
c1 SYS_REFCURSOR;
37+
c2 SYS_REFCURSOR;
38+
BEGIN
39+
c2:= COALESCE(c0, c1);
40+
c2:= COALESCE(c1, c0);
41+
END
42+
$$
43+
DELIMITER ;$$
44+
CALL p1;
45+
DROP PROCEDURE p1;
46+
47+
48+
# Testing COALESCE for two equal strong cursors
49+
50+
DELIMITER $$;
51+
CREATE PROCEDURE p1 AS
52+
TYPE rec0_t IS RECORD (a INT, b TIME);
53+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
54+
c0, c1, c2 cur0_t;
55+
r0 rec0_t;
56+
BEGIN
57+
OPEN c1 FOR SELECT 1 AS a,'10:20:30' AS b;
58+
c2:= COALESCE(c0,c1);
59+
FETCH c2 INTO r0;
60+
CLOSE c2;
61+
SELECT r0.a, r0.b;
62+
END;
63+
$$
64+
DELIMITER ;$$
65+
CALL p1;
66+
DROP PROCEDURE p1;
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
SET sql_mode=ORACLE;
2+
#
3+
# MDEV-10152 Add support for TYPE .. IS REF CURSOR
4+
#
5+
CREATE PROCEDURE p1 IS
6+
TYPE rec0_t IS RECORD (a INT, b TIME);
7+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
8+
c0 cur0_t;
9+
BEGIN
10+
c0:= 10;
11+
END;
12+
$$
13+
CALL p1;
14+
ERROR HY000: Cannot cast 'int' as 'sys_refcursor' in assignment of `c0` for operation SET
15+
DROP PROCEDURE p1;
16+
CREATE PROCEDURE p1 IS
17+
TYPE rec0_t IS RECORD (a INT, b TIME);
18+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
19+
c0 cur0_t;
20+
BEGIN
21+
c0:= @a;
22+
END;
23+
$$
24+
SET @a=10;
25+
CALL p1;
26+
ERROR HY000: Cannot cast 'bigint' as 'sys_refcursor' in assignment of `c0` for operation SET
27+
SET @a='test';
28+
CALL p1;
29+
ERROR HY000: Cannot cast 'longblob' as 'sys_refcursor' in assignment of `c0` for operation SET
30+
DROP PROCEDURE p1;
31+
CREATE PROCEDURE p1 IS
32+
TYPE rec0_t IS RECORD (a INT, b TIME);
33+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
34+
c0 cur0_t;
35+
BEGIN
36+
c0:= ROW(1,TIME'10:20:30');
37+
END;
38+
$$
39+
CALL p1;
40+
ERROR HY000: Cannot cast 'row' as 'sys_refcursor' in assignment of `c0` for operation SET
41+
DROP PROCEDURE p1;
42+
CREATE PROCEDURE p1 IS
43+
TYPE rec0_t IS RECORD (a INT, b TIME);
44+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
45+
TYPE cur1_t IS REF CURSOR;
46+
c0 cur0_t;
47+
c1 cur1_t;
48+
BEGIN
49+
OPEN c1 FOR SELECT 1 AS a,TIME'10:20:30',10 AS b;
50+
c0:= c1;
51+
CLOSE c1;
52+
END;
53+
$$
54+
CALL p1;
55+
ERROR HY000: Cannot cast 'row<3>' as 'row<2>' in assignment of `c0` for operation SET
56+
DROP PROCEDURE p1;
57+
CREATE PROCEDURE p1 IS
58+
TYPE rec0_t IS RECORD (a INT, b INET6);
59+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
60+
TYPE cur1_t IS REF CURSOR;
61+
c0 cur0_t;
62+
c1 cur1_t;
63+
BEGIN
64+
OPEN c1 FOR SELECT 1 AS a,TIME'10:20:30' AS b;
65+
c0:= c1;
66+
CLOSE c1;
67+
END;
68+
$$
69+
CALL p1;
70+
ERROR HY000: Cannot cast 'time' as 'inet6' in assignment of `c0`.`b` for operation SET
71+
DROP PROCEDURE p1;
72+
CREATE PROCEDURE p1 IS
73+
TYPE rec0_t IS RECORD (a INT, b TIME);
74+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
75+
TYPE cur1_t IS REF CURSOR;
76+
c0 cur0_t;
77+
c1 cur1_t;
78+
v0a INT;
79+
v0b TIME;
80+
BEGIN
81+
OPEN c1 FOR SELECT 1 AS a,TIME'10:20:30' AS b;
82+
c0:= c1;
83+
FETCH c0 INTO v0a, v0b;
84+
CLOSE c1;
85+
SELECT v0a, v0b;
86+
END;
87+
$$
88+
CALL p1;
89+
v0a v0b
90+
1 10:20:30
91+
DROP PROCEDURE p1;
92+
CREATE PROCEDURE p1 AS
93+
TYPE rec0_t IS RECORD (a INT, b TIME, c VARCHAR(10));
94+
TYPE rec1_t IS RECORD (a INT, b TIME);
95+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
96+
TYPE cur1_t IS REF CURSOR RETURN rec1_t;
97+
c0 cur0_t;
98+
c1 cur1_t;
99+
a INT;
100+
BEGIN
101+
OPEN c0 FOR SELECT 1 AS a, TIME'10:20:30' AS b, 'c' AS c;
102+
c1:= c0;
103+
END;
104+
$$
105+
CALL p1;
106+
ERROR HY000: Cannot cast 'row<3>' as 'row<2>' in assignment of `c1` for operation SET
107+
DROP PROCEDURE p1;
108+
CREATE PROCEDURE p1 AS
109+
TYPE rec0_t IS RECORD (a INT,b INET6);
110+
TYPE rec1_t IS RECORD (a INT, b TIME);
111+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
112+
TYPE cur1_t IS REF CURSOR RETURN rec1_t;
113+
c0 cur0_t;
114+
c1 cur1_t;
115+
a INT;
116+
BEGIN
117+
OPEN c0 FOR SELECT 1 AS a,CAST('::' AS INET6) AS b;
118+
c1:= c0;
119+
END;
120+
$$
121+
CALL p1;
122+
ERROR HY000: Cannot cast 'inet6' as 'time' in assignment of `c1`.`b` for operation SET
123+
DROP PROCEDURE p1;
124+
CREATE TABLE t1 (a INT, b UUID);
125+
CREATE PROCEDURE p1 AS
126+
TYPE rec0_t IS RECORD (a INT,b INET6);
127+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
128+
TYPE cur1_t IS REF CURSOR RETURN t1%ROWTYPE;
129+
c0 cur0_t;
130+
c1 cur1_t;
131+
a INT;
132+
BEGIN
133+
OPEN c0 FOR SELECT 1 AS a, CAST('::' AS INET6) AS b;
134+
c1:= c0;
135+
END;
136+
$$
137+
CALL p1;
138+
ERROR HY000: Cannot cast 'inet6' as 'uuid' in assignment of `c1`.`b` for operation SET
139+
DROP PROCEDURE p1;
140+
DROP TABLE t1;
141+
CREATE PROCEDURE p1 IS
142+
TYPE rec0_t IS RECORD (a INT, b TIME);
143+
TYPE cur0_t IS REF CURSOR RETURN rec0_t;
144+
c0, c1 cur0_t;
145+
v0a INT;
146+
v0b TIME;
147+
BEGIN
148+
OPEN c1 FOR SELECT 1 AS a,TIME'10:20:30' AS b;
149+
c0:= c1;
150+
FETCH c0 INTO v0a, v0b;
151+
CLOSE c1;
152+
SELECT v0a, v0b;
153+
END;
154+
$$
155+
CALL p1;
156+
v0a v0b
157+
1 10:20:30
158+
DROP PROCEDURE p1;

0 commit comments

Comments
 (0)