mirror of
https://github.com/MariaDB/server.git
synced 2025-06-01 19:42:01 +03:00
Problems: 1. Unlike Item_field::fix_fields(), Item_sum_sp::fix_length_and_dec() and Item_func_sp::fix_length_and_dec() did not run the code which resided in adjust_max_effective_column_length(), therefore they did not extend max_length for the integer return data types from the user-specified length to the maximum length according to the data type capacity. 2. The code in adjust_max_effective_column_length() was not correct for TEXT data, because Field_blob::max_display_length() multiplies to mbmaxlen. So TEXT variants were unintentionally promoted to the next longer data type for multi-byte character sets: TINYTEXT->TEXT, TEXT->MEDIUMTEXT, MEDIUMTEXT->LONGTEXT. 3. Item_sum_sp::create_table_field_from_handler() Item_func_sp::create_table_field_from_handler() erroneously called tmp_table_field_from_field_type(), which converted VARCHAR(>512) to TEXT variants. So "CREATE..SELECT spfunc()" erroneously converted VARCHAR to TEXT. This was wrong, because stored functions have explicitly declared data types, which should be preserved. Solution: - Removing Type_std_attributes(const Field *) and using instead Type_std_attributes::set() in combination with field->type_str_attributes() all around the code, e.g.: Type_std_attributes::set(field->type_std_attributes()) These two ways of copying attributes from a Field to an Item duplicated each other, and were slightly different in how to mix max_length and mbmaxlen. - Removing adjust_max_effective_column_length() and fixing Field::type_std_attributes() to do all necessary type-specific calculations , so no further adjustments is needed. Field::type_std_attributes() is now called from all affected methods: Item_field::fix_fields() Item_sum_sp::fix_length_and_dec() Item_func_sp::fix_length_and_dec() This fixes the problem N1. - Making Field::type_std_attributes() virtual, to make sure that type-specific adjustments a properly done by individual Field_xxx classes. Implementing Field_blob::type_std_attributes() in the way that no TEXT promotion is done. This fixes the problem N2. - Fixing Item_sum_sp::create_table_field_from_handler() Item_func_sp::create_table_field_from_handler() to call create_table_field_from_handler() instead of tmp_table_field_from_field_type() to avoid VARCHAR->TEXT conversion on "CREATE..SELECT spfunc()". - Recording mysql-test/suite/compat/oracle/r/sp-param.result as "CREATE..SELECT spfunc()" now correctly preserve the data type as specified in the RETURNS clause. - Adding new tests
424 lines
12 KiB
Plaintext
424 lines
12 KiB
Plaintext
SET sql_mode=ORACLE;
|
|
#
|
|
# MDEV-10596 Allow VARCHAR and VARCHAR2 without length as a data type of routine parameters and in RETURN clause
|
|
#
|
|
CREATE FUNCTION f1(param CHAR) RETURN CHAR AS BEGIN RETURN param; END;;
|
|
SHOW CREATE FUNCTION f1;
|
|
Function sql_mode Create Function character_set_client collation_connection Database Collation
|
|
f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param CHAR) RETURN varchar(2000) CHARSET latin1
|
|
AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
|
|
SELECT LENGTH(f1(REPEAT('a',2000)));;
|
|
LENGTH(f1(REPEAT('a',2000)))
|
|
2000
|
|
CREATE TABLE t1 AS SELECT f1(REPEAT('a',2000)) AS a;;
|
|
SHOW CREATE TABLE t1;
|
|
Table Create Table
|
|
t1 CREATE TABLE "t1" (
|
|
"a" varchar(2000) DEFAULT NULL
|
|
)
|
|
DROP TABLE t1;
|
|
DROP FUNCTION f1;
|
|
CREATE FUNCTION f1(param NCHAR) RETURN NCHAR AS BEGIN RETURN param; END;;
|
|
SHOW CREATE FUNCTION f1;
|
|
Function sql_mode Create Function character_set_client collation_connection Database Collation
|
|
f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param NCHAR) RETURN varchar(2000) CHARSET utf8
|
|
AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
|
|
SELECT LENGTH(f1(REPEAT('a',2000)));;
|
|
LENGTH(f1(REPEAT('a',2000)))
|
|
2000
|
|
CREATE TABLE t1 AS SELECT f1(REPEAT('a',2000)) AS a;;
|
|
SHOW CREATE TABLE t1;
|
|
Table Create Table
|
|
t1 CREATE TABLE "t1" (
|
|
"a" varchar(2000) CHARACTER SET utf8 DEFAULT NULL
|
|
)
|
|
DROP TABLE t1;
|
|
DROP FUNCTION f1;
|
|
CREATE FUNCTION f1(param BINARY) RETURN BINARY AS BEGIN RETURN param; END;;
|
|
SHOW CREATE FUNCTION f1;
|
|
Function sql_mode Create Function character_set_client collation_connection Database Collation
|
|
f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param BINARY) RETURN varbinary(2000)
|
|
AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
|
|
SELECT LENGTH(f1(REPEAT('a',2000)));;
|
|
LENGTH(f1(REPEAT('a',2000)))
|
|
2000
|
|
CREATE TABLE t1 AS SELECT f1(REPEAT('a',2000)) AS a;;
|
|
SHOW CREATE TABLE t1;
|
|
Table Create Table
|
|
t1 CREATE TABLE "t1" (
|
|
"a" varbinary(2000) DEFAULT NULL
|
|
)
|
|
DROP TABLE t1;
|
|
DROP FUNCTION f1;
|
|
CREATE FUNCTION f1(param VARCHAR) RETURN VARCHAR AS BEGIN RETURN param; END;;
|
|
SHOW CREATE FUNCTION f1;
|
|
Function sql_mode Create Function character_set_client collation_connection Database Collation
|
|
f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param VARCHAR) RETURN varchar(4000) CHARSET latin1
|
|
AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
|
|
SELECT LENGTH(f1(REPEAT('a',4000)));;
|
|
LENGTH(f1(REPEAT('a',4000)))
|
|
4000
|
|
CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
|
|
SHOW CREATE TABLE t1;
|
|
Table Create Table
|
|
t1 CREATE TABLE "t1" (
|
|
"a" varchar(4000) DEFAULT NULL
|
|
)
|
|
DROP TABLE t1;
|
|
DROP FUNCTION f1;
|
|
CREATE FUNCTION f1(param VARCHAR2) RETURN VARCHAR2 AS BEGIN RETURN param; END;;
|
|
SHOW CREATE FUNCTION f1;
|
|
Function sql_mode Create Function character_set_client collation_connection Database Collation
|
|
f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param VARCHAR2) RETURN varchar(4000) CHARSET latin1
|
|
AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
|
|
SELECT LENGTH(f1(REPEAT('a',4000)));;
|
|
LENGTH(f1(REPEAT('a',4000)))
|
|
4000
|
|
CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
|
|
SHOW CREATE TABLE t1;
|
|
Table Create Table
|
|
t1 CREATE TABLE "t1" (
|
|
"a" varchar(4000) DEFAULT NULL
|
|
)
|
|
DROP TABLE t1;
|
|
DROP FUNCTION f1;
|
|
CREATE FUNCTION f1(param NVARCHAR) RETURN NVARCHAR AS BEGIN RETURN param; END;;
|
|
SHOW CREATE FUNCTION f1;
|
|
Function sql_mode Create Function character_set_client collation_connection Database Collation
|
|
f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param NVARCHAR) RETURN varchar(4000) CHARSET utf8
|
|
AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
|
|
SELECT LENGTH(f1(REPEAT('a',4000)));;
|
|
LENGTH(f1(REPEAT('a',4000)))
|
|
4000
|
|
CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
|
|
SHOW CREATE TABLE t1;
|
|
Table Create Table
|
|
t1 CREATE TABLE "t1" (
|
|
"a" varchar(4000) CHARACTER SET utf8 DEFAULT NULL
|
|
)
|
|
DROP TABLE t1;
|
|
DROP FUNCTION f1;
|
|
CREATE FUNCTION f1(param VARBINARY) RETURN VARBINARY AS BEGIN RETURN param; END;;
|
|
SHOW CREATE FUNCTION f1;
|
|
Function sql_mode Create Function character_set_client collation_connection Database Collation
|
|
f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param VARBINARY) RETURN varbinary(4000)
|
|
AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
|
|
SELECT LENGTH(f1(REPEAT('a',4000)));;
|
|
LENGTH(f1(REPEAT('a',4000)))
|
|
4000
|
|
CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
|
|
SHOW CREATE TABLE t1;
|
|
Table Create Table
|
|
t1 CREATE TABLE "t1" (
|
|
"a" varbinary(4000) DEFAULT NULL
|
|
)
|
|
DROP TABLE t1;
|
|
DROP FUNCTION f1;
|
|
CREATE FUNCTION f1(param RAW) RETURN RAW AS BEGIN RETURN param; END;;
|
|
SHOW CREATE FUNCTION f1;
|
|
Function sql_mode Create Function character_set_client collation_connection Database Collation
|
|
f1 PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,ORACLE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER,SIMULTANEOUS_ASSIGNMENT CREATE DEFINER="root"@"localhost" FUNCTION "f1"(param RAW) RETURN varbinary(4000)
|
|
AS BEGIN RETURN param; END latin1 latin1_swedish_ci latin1_swedish_ci
|
|
SELECT LENGTH(f1(REPEAT('a',4000)));;
|
|
LENGTH(f1(REPEAT('a',4000)))
|
|
4000
|
|
CREATE TABLE t1 AS SELECT f1(REPEAT('a',4000)) AS a;;
|
|
SHOW CREATE TABLE t1;
|
|
Table Create Table
|
|
t1 CREATE TABLE "t1" (
|
|
"a" varbinary(4000) DEFAULT NULL
|
|
)
|
|
DROP TABLE t1;
|
|
DROP FUNCTION f1;
|
|
|
|
MDEV-13919 sql_mode=ORACLE: Derive length of VARCHAR SP parameters with no length from actual parameters
|
|
|
|
set sql_mode= 'oracle,strict_trans_tables';
|
|
CREATE OR REPLACE PROCEDURE p1(pinout INOUT varchar, pin IN varchar)
|
|
AS
|
|
BEGIN
|
|
pinout:=pin;
|
|
END;
|
|
/
|
|
call p1(@w,'0123456789')
|
|
/
|
|
declare w varchar(10);
|
|
begin
|
|
call p1(w,'0123456789');
|
|
end;
|
|
/
|
|
declare w varchar(5);
|
|
begin
|
|
call p1(w,'0123456789');
|
|
end;
|
|
/
|
|
ERROR 22001: Data too long for column 'pinout' at row 1
|
|
declare w varchar(20);
|
|
begin
|
|
w:='aaa';
|
|
call p1(w,'0123456789');
|
|
end;
|
|
/
|
|
declare w varchar(8);
|
|
begin
|
|
w:='aaa';
|
|
call p1(w,'0123456789');
|
|
end;
|
|
/
|
|
ERROR 22001: Data too long for column 'pinout' at row 1
|
|
declare str varchar(6000);
|
|
pout varchar(6000);
|
|
begin
|
|
str:=lpad('x',6000,'y');
|
|
call p1(pout,str);
|
|
select length(pout);
|
|
end;
|
|
/
|
|
length(pout)
|
|
6000
|
|
declare str varchar(6000);
|
|
pout varchar(4000);
|
|
begin
|
|
str:=lpad('x',6000,'y');
|
|
call p1(pout,str);
|
|
select length(pout);
|
|
end;
|
|
/
|
|
ERROR 22001: Data too long for column 'pinout' at row 1
|
|
declare str varchar(40000);
|
|
pout varchar(60000);
|
|
begin
|
|
str:=lpad('x',40000,'y');
|
|
call p1(pout,str);
|
|
select length(pout);
|
|
end;
|
|
/
|
|
length(pout)
|
|
40000
|
|
declare str text(80000);
|
|
pout text(80000);
|
|
begin
|
|
str:=lpad('x',80000,'y');
|
|
call p1(pout,str);
|
|
select length(pout);
|
|
end;
|
|
/
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
declare str text(80000);
|
|
pout text(80000);
|
|
begin
|
|
str:=lpad('x',60000,'y');
|
|
call p1(pout,str);
|
|
select length(pout);
|
|
end;
|
|
/
|
|
length(pout)
|
|
60000
|
|
drop procedure p1
|
|
/
|
|
SET sql_mode=ORACLE;
|
|
CREATE PROCEDURE p1(pinout INOUT varchar, pin IN varchar)
|
|
AS
|
|
BEGIN
|
|
pinout:=pin;
|
|
END;
|
|
/
|
|
CREATE PROCEDURE p2(len INT)
|
|
AS
|
|
pinout VARCHAR(10);
|
|
pin VARCHAR(30);
|
|
BEGIN
|
|
pin:= REPEAT('x', len);
|
|
p1(pinout, pin);
|
|
SELECT LENGTH(pinout);
|
|
END;
|
|
/
|
|
CALL p2(10);
|
|
LENGTH(pinout)
|
|
10
|
|
CALL p2(11);
|
|
LENGTH(pinout)
|
|
10
|
|
Warnings:
|
|
Warning 1265 Data truncated for column 'pinout' at row 1
|
|
DROP PROCEDURE p1;
|
|
DROP PROCEDURE p2;
|
|
SET sql_mode=ORACLE;
|
|
CREATE FUNCTION f1(pin VARCHAR, padlen INT) RETURN TEXT
|
|
AS
|
|
BEGIN
|
|
pin:=LPAD(pin, padlen);
|
|
RETURN pin;
|
|
END;
|
|
/
|
|
CREATE PROCEDURE p2(padlen INT) AS
|
|
str TEXT :='x';
|
|
BEGIN
|
|
SELECT LENGTH(f1(str,padlen));
|
|
END;
|
|
/
|
|
CALL p2(65535);
|
|
LENGTH(f1(str,padlen))
|
|
65532
|
|
Warnings:
|
|
Warning 1265 Data truncated for column 'pin' at row 1
|
|
CALL p2(65536);
|
|
LENGTH(f1(str,padlen))
|
|
65532
|
|
Warnings:
|
|
Warning 1265 Data truncated for column 'pin' at row 1
|
|
DROP PROCEDURE p2;
|
|
DROP FUNCTION f1;
|
|
SET sql_mode='ORACLE,STRICT_TRANS_TABLES';
|
|
CREATE PROCEDURE p1(pinout INOUT VARCHAR CHARACTER SET utf8,
|
|
pin IN VARCHAR CHARACTER SET utf8)
|
|
AS
|
|
BEGIN
|
|
pinout:=pin;
|
|
END;
|
|
/
|
|
CREATE PROCEDURE p2(padlen INT) AS
|
|
str VARCHAR(40000) CHARACTER SET latin1;
|
|
pout VARCHAR(60000) CHARACTER SET latin1;
|
|
BEGIN
|
|
str:=lpad('x',padlen,'y');
|
|
p1(pout,str);
|
|
SELECT length(pout);
|
|
END;
|
|
/
|
|
CALL p2(21844);
|
|
length(pout)
|
|
21844
|
|
CALL p2(21845);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(21846);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
DROP PROCEDURE p2;
|
|
DROP PROCEDURE p1;
|
|
SET sql_mode='ORACLE,STRICT_TRANS_TABLES';
|
|
CREATE PROCEDURE p1(pinout INOUT VARCHAR CHARACTER SET utf8,
|
|
pin IN VARCHAR CHARACTER SET utf8)
|
|
AS
|
|
BEGIN
|
|
pinout:=pin;
|
|
END;
|
|
/
|
|
CREATE PROCEDURE p2(padlen INT) AS
|
|
str TEXT CHARACTER SET utf8;
|
|
pout TEXT CHARACTER SET utf8;
|
|
BEGIN
|
|
str:=lpad('x',padlen,'y');
|
|
p1(pout,str);
|
|
SELECT length(pout);
|
|
END;
|
|
/
|
|
CALL p2(21844);
|
|
length(pout)
|
|
21844
|
|
CALL p2(21845);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(21846);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
DROP PROCEDURE p2;
|
|
DROP PROCEDURE p1;
|
|
SET sql_mode='ORACLE,STRICT_TRANS_TABLES';
|
|
CREATE FUNCTION f1(pin VARCHAR CHARACTER SET latin1, padlen INT) RETURN TEXT
|
|
AS
|
|
BEGIN
|
|
pin:=LPAD(pin, padlen);
|
|
RETURN pin;
|
|
END;
|
|
/
|
|
CREATE PROCEDURE p2(padlen INT) AS
|
|
str TEXT CHARACTER SET latin1 :='x';
|
|
BEGIN
|
|
SELECT LENGTH(f1(str,padlen));
|
|
END;
|
|
/
|
|
CALL p2(65532);
|
|
LENGTH(f1(str,padlen))
|
|
65532
|
|
CALL p2(65533);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(65534);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(65535);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(65536);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
DROP PROCEDURE p2;
|
|
DROP FUNCTION f1;
|
|
SET sql_mode='ORACLE,STRICT_TRANS_TABLES';
|
|
CREATE FUNCTION f1(pin VARCHAR CHARACTER SET utf8, padlen INT) RETURN TEXT
|
|
AS
|
|
BEGIN
|
|
pin:=LPAD(pin, padlen);
|
|
RETURN pin;
|
|
END;
|
|
/
|
|
CREATE PROCEDURE p2(padlen INT) AS
|
|
str TEXT CHARACTER SET utf8 := 'x';
|
|
BEGIN
|
|
SELECT LENGTH(f1(str,padlen));
|
|
END;
|
|
/
|
|
CALL p2(21844);
|
|
LENGTH(f1(str,padlen))
|
|
21844
|
|
CALL p2(21845);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(21846);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
DROP PROCEDURE p2;
|
|
DROP FUNCTION f1;
|
|
SET sql_mode='ORACLE,STRICT_TRANS_TABLES';
|
|
CREATE FUNCTION f1(pin VARCHAR CHARACTER SET utf8, padlen INT) RETURN TEXT
|
|
AS
|
|
BEGIN
|
|
pin:=LPAD(pin, padlen);
|
|
RETURN pin;
|
|
END;
|
|
/
|
|
CREATE PROCEDURE p2(padlen INT) AS
|
|
str TEXT CHARACTER SET latin1 := 'x';
|
|
BEGIN
|
|
SELECT LENGTH(f1(str,padlen));
|
|
END;
|
|
/
|
|
CALL p2(21844);
|
|
LENGTH(f1(str,padlen))
|
|
21844
|
|
CALL p2(21845);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(21846);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
DROP PROCEDURE p2;
|
|
DROP FUNCTION f1;
|
|
SET sql_mode='ORACLE,STRICT_TRANS_TABLES';
|
|
CREATE FUNCTION f1(pin VARCHAR CHARACTER SET latin1, padlen INT) RETURN TEXT
|
|
AS
|
|
BEGIN
|
|
pin:=LPAD(pin, padlen);
|
|
RETURN pin;
|
|
END;
|
|
/
|
|
CREATE PROCEDURE p2(padlen INT) AS
|
|
str TEXT CHARACTER SET utf8 := 'x';
|
|
BEGIN
|
|
SELECT LENGTH(f1(str,padlen));
|
|
END;
|
|
/
|
|
CALL p2(65532);
|
|
LENGTH(f1(str,padlen))
|
|
65532
|
|
CALL p2(65533);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(65534);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(65535);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
CALL p2(65536);
|
|
ERROR 22001: Data too long for column 'pin' at row 1
|
|
DROP PROCEDURE p2;
|
|
DROP FUNCTION f1;
|