mariadb/mysql-test/suite/compat/oracle/r/sp-cursor-decl.result
Alexander Barkov 109bc47084 Fixing a few data type related problems: MDEV-12875, MDEV-12886, MDEV-12916
This is a joint patch fixing the following problems:

MDEV-12875 Wrong VIEW column data type for COALESCE(int_column)
MDEV-12886 Different default for INT and BIGINT column in a VIEW for a SELECT with ROLLUP
MDEV-12916 Wrong column data type for an INT field of a cursor-anchored ROW variable

All above problem happened because the global function ::create_tmp_field()
called the top-level Item::create_tmp_field(), which made some tranformation
for INT-result data types. For example, INT(11) became BIGINT(11), because 11
is a corner case and it's not known if it fits or does not fit into INT range,
so Item::create_tmp_field() converted it to BIGINT(11) for safety.

The main idea of this patch is to avoid such tranformations.

1. Fixing Item::create_tmp_field() not to have a special case for INT_RESULT.

   Item::create_tmp_field() is changed not to have a special case
   for INT_RESULT (which earlier made a decision based on Item's max_length).
   It now calls tmp_table_field_from_field_type() for INT_RESULT,
   therefore preserves the original data type (e.g. INT, YEAR) without
   conversion to BIGINT.

   This change is valid, because a number of recent fixes
   (e.g. in Item_func_int, Item_hybrid_func, Item_int, Item_splocal)
   guarantee that item->type_handler() now properly returns
   type_handler_long vs type_handler_longlong. So no adjustment by length
   is needed any more for Items returning INT_RESULT.

   After this change, Item::create_tmp_field() calls
   tmp_table_field_from_field_type() for all XXX_RESULT, except REAL_RESULT.

2. Fixing Item::create_tmp_field() not to have a special case for REAL_RESULT.

   Note, the reason for a special case for REAL_RESULT is to have a special
   constructor for Field_double(), forcing Field_real::not_fixed to be set
   to true.

   Taking into account that only Item_sum descendants actually need a special
   constructor call Field_double(not_fixed=true), not too loose precision
   when mixing individual rows to the aggregate result:
   - renaming Item::create_tmp_field() to Item_sum::create_tmp_field().
   - changing Item::create_tmp_field() just to call
     tmp_table_field_from_field_type() for all XXX_RESULT types.

   A special case for REAL_RESULT in Item::create_tmp_field() is now gone.
   Item::create_tmp_field() is now symmetric for all XXX_RESULT types,
   and now just calls tmp_table_field_from_field_type().

3. Fixing Item_func::create_field_for_create_select() not to have
   a special case for STRING_RESULT.

   After changes #1 and #2, the code in
   Item_func::create_field_for_create_select(), testing result_type(),
   becomes useless, because: now Item::create_tmp_field() and
   tmp_table_field_from_field_type() do exactly the same thing for all
   XXX_RESULT types for Item_func descendants:
   a. It calls tmp_table_field_from_field_type for STRING_RESULT directly.
   b. For other XXX_RESULT, it goes through Item::create_tmp_field(),
      which calls the global function ::create_tmp_field(),
      which calls item->create_tmp_field() for FUNC_ITEM,
      which calls tmp_table_field_from_field_type() again.

   So removing the virtual implementation of
   Item_func::create_field_for_create_select().
   The inherited Item::create_field_for_create_select() now perfectly
   does the job, as it also calls tmp_table_field_from_field_type()
   for FUNC_ITEM, independently from XXX_RESULT type.

4. Taking into account #1 and #2, as well as some recent changes,
   removing virtual implementations:
   - Item_hybrid_func::create_tmp_field()
   - Item_hybrid_func::create_field_for_create_select()
   - Item_int_func::create_tmp_field()
   - Item_int_func::create_field_for_create_select()
   - Item_temporal_func::create_field_for_create_select()
   The derived versions from Item now perfectly work.

5. Moving a piece of code from create_tmp_field_from_item()
   to a new function create_tmp_field_from_item_finalize(),
   to reuse it in two places (see #6).

6. Changing the code responsible for BIT->INT/BIGIN tranformation
   (which is called for the cases when the created table, e.g. HEAP,
    does not fully support BIT) not to call create_tmp_field_from_item(),
   because the latter now calls tmp_table_field_from_field_type() instead
   of create_tmp_field() and thefore cannot do BIT transformation.
   So rewriting this code using a sequence of these calls:
   - item->type_handler_long_or_longlong()
   - handler->make_and_init_table_field()
   - create_tmp_field_from_item_finalize()

7. Miscelaneous changes:
   - Moving type_handler_long_or_longlong() from "protected" to "public",
     as it's now needed in the global function create_tmp_field().

8. The above changes fixed MDEV-12875, MDEV-12886, MDEV-12916.
   So adding tests for these bugs.
2017-05-25 15:15:39 +04:00

290 lines
5.5 KiB
Text

SET sql_mode=ORACLE;
#
# MDEV-10598 sql_mode=ORACLE: Variable declarations can go after cursor declarations
#
#
# Variable after cursor declaration
#
CREATE TABLE t1 (a INT);
insert into t1 values (1);
insert into t1 values (2);
CREATE PROCEDURE p1
AS
CURSOR c IS SELECT a FROM t1;
var1 varchar(10);
BEGIN
OPEN c;
fetch c into var1;
SELECT c%ROWCOUNT,var1;
close c;
END;
$$
CALL p1;
c%ROWCOUNT var1
1 1
DROP PROCEDURE p1;
drop table t1;
#
# Variable after condition declaration
#
CREATE TABLE t1 (col1 INT);
insert into t1 values (1);
create unique index t1_col1 on t1 (col1);
CREATE PROCEDURE p1
AS
dup_key CONDITION FOR SQLSTATE '23000';
var1 varchar(40);
CONTINUE HANDLER FOR dup_key
BEGIN
var1:='duplicate key in index';
END;
BEGIN
var1:='';
insert into t1 values (1);
select var1;
END;
$$
CALL p1;
var1
duplicate key in index
DROP PROCEDURE p1;
drop table t1;
#
# Condition after cursor declaration
#
CREATE TABLE t1 (col1 INT);
insert into t1 values (1);
create unique index t1_col1 on t1 (col1);
CREATE PROCEDURE p1
AS
var1 varchar(40);
var2 integer;
CURSOR c IS SELECT col1 FROM t1;
dup_key CONDITION FOR SQLSTATE '23000';
CONTINUE HANDLER FOR dup_key
BEGIN
var1:='duplicate key in index';
END;
BEGIN
var1:='';
insert into t1 values (1);
SELECT var1;
END;
$$
CALL p1;
var1
duplicate key in index
DROP PROCEDURE p1;
drop table t1;
#
# Cursor after handler declaration
#
CREATE TABLE t1 (col1 INT);
insert into t1 values (1);
create unique index t1_col1 on t1 (col1);
CREATE PROCEDURE p1
AS
var1 varchar(40);
var2 integer;
dup_key CONDITION FOR SQLSTATE '23000';
CONTINUE HANDLER FOR dup_key
BEGIN
var1:='duplicate key in index';
END;
CURSOR c IS SELECT col1 FROM t1;
BEGIN
var1:='';
insert into t1 values (1);
SELECT var1;
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 'CURSOR c IS SELECT col1 FROM t1;
BEGIN
var1:='';
insert into t1 values (1);
SELE' at line 10
drop table t1;
#
# Condition after handler declaration
#
CREATE TABLE t1 (col1 INT);
insert into t1 values (1);
create unique index t1_col1 on t1 (col1);
CREATE PROCEDURE p1
AS
var1 varchar(40);
var2 integer;
dup_key CONDITION FOR SQLSTATE '23000';
CURSOR c IS SELECT col1 FROM t1;
CONTINUE HANDLER FOR dup_key
BEGIN
var1:='duplicate key in index';
END;
divide_by_zero CONDITION FOR SQLSTATE '22012';
BEGIN
var1:='';
insert into t1 values (1);
SELECT var1;
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 'divide_by_zero CONDITION FOR SQLSTATE '22012';
BEGIN
var1:='';
insert into t1 va' at line 11
drop table t1;
#
# Variable after handler declaration
#
CREATE TABLE t1 (col1 INT);
insert into t1 values (1);
create unique index t1_col1 on t1 (col1);
CREATE PROCEDURE p1
AS
var1 varchar(40);
var2 integer;
dup_key CONDITION FOR SQLSTATE '23000';
CURSOR c IS SELECT col1 FROM t1;
CONTINUE HANDLER FOR dup_key
BEGIN
var1:='duplicate key in index';
END;
divide_by_zero CONDITION FOR SQLSTATE '22012';
BEGIN
var1:='';
insert into t1 values (1);
SELECT var1;
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 'divide_by_zero CONDITION FOR SQLSTATE '22012';
BEGIN
var1:='';
insert into t1 va' at line 11
drop table t1;
#
# Variable after cursor (inner block)
#
CREATE TABLE t1 (col1 INT);
insert into t1 values (1);
insert into t1 values (2);
create unique index t1_col1 on t1 (col1);
CREATE PROCEDURE p1
AS
CURSOR c IS SELECT col1 FROM t1;
var1 varchar(40);
BEGIN
OPEN c;
begin
declare
CURSOR c IS SELECT col1 FROM t1 where col1=2;
var2 integer;
dup_key CONDITION FOR SQLSTATE '23000';
CONTINUE HANDLER FOR dup_key
BEGIN
var1:='duplicate key in index';
END;
begin
OPEN c;
fetch c into var1;
SELECT 'inner cursor',var1;
insert into t1 values (2);
close c;
end;
end;
SELECT var1;
fetch c into var1;
SELECT c%ROWCOUNT,var1;
begin
insert into t1 values (2);
exception when 1062 then
begin
SELECT 'dup key caugth';
end;
end;
close c;
END;
$$
CALL p1;
inner cursor var1
inner cursor 2
var1
duplicate key in index
c%ROWCOUNT var1
1 1
dup key caugth
dup key caugth
DROP PROCEDURE p1;
drop table t1;
#
# Cursor declaration and row type declaration in same block
#
CREATE TABLE t1 (a INT, b VARCHAR(10));
insert into t1 values(1,'a');
CREATE PROCEDURE p1()
AS
CURSOR cur1 IS SELECT a FROM t1;
rec1 cur1%ROWTYPE;
BEGIN
rec1.a:= 10;
END;
$$
call p1;
DROP PROCEDURE p1;
drop table t1;
#
# Recursive cursor and cursor%ROWTYPE declarations in the same block
#
CREATE PROCEDURE p1
AS
a INT:=10;
b VARCHAR(10):='b0';
c DOUBLE:=0.1;
CURSOR cur1 IS SELECT a, b, c;
rec1 cur1%ROWTYPE;
CURSOR cur2 IS SELECT rec1.a + 1 "a", rec1.b||'0' AS b, rec1.c AS c;
rec2 cur2%ROWTYPE;
BEGIN
OPEN cur1;
FETCH cur1 INTO rec1;
CLOSE cur1;
SELECT rec1.a;
OPEN cur2;
FETCH cur2 INTO rec2;
CLOSE cur2;
SELECT rec2.a;
CREATE TABLE t2 AS SELECT rec2.a AS a, rec2.b AS b, rec2.c AS c;
SHOW CREATE TABLE t2;
DROP TABLE t2;
END;
$$
CALL p1();
rec1.a
10
rec2.a
11
Table Create Table
t2 CREATE TABLE "t2" (
"a" bigint(20) DEFAULT NULL,
"b" varchar(11) DEFAULT NULL,
"c" double DEFAULT NULL
)
DROP PROCEDURE p1;
#
# MDEV-12916 Wrong column data type for an INT field of a cursor-anchored ROW variable
#
CREATE PROCEDURE p1
AS
a INT DEFAULT 10;
CURSOR cur1 IS SELECT a;
rec1 cur1%ROWTYPE;
BEGIN
CREATE TABLE t1 AS SELECT rec1.a;
SHOW CREATE TABLE t1;
DROP TABLE t1;
END;
$$
CALL p1();
Table Create Table
t1 CREATE TABLE "t1" (
"rec1.a" int(11) DEFAULT NULL
)
DROP PROCEDURE p1;