mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
This commit is contained in:
@@ -752,3 +752,34 @@ DROP PROCEDURE p1;
|
||||
#
|
||||
# End of MDEV-10597 Cursors with parameters
|
||||
#
|
||||
#
|
||||
# MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b VARCHAR(10),c DATETIME(3));
|
||||
INSERT INTO t1 VALUES (1,'b1','2001-01-01 10:20:30.123');
|
||||
INSERT INTO t1 VALUES (2,'b2','2001-01-02 10:20:30.123');
|
||||
CREATE TABLE t2 LIKE t1;
|
||||
CREATE PROCEDURE p1()
|
||||
AS
|
||||
v_a t1.a%TYPE;
|
||||
v_b t1.b%TYPE;
|
||||
v_c t1.c%TYPE;
|
||||
CURSOR c IS SELECT a,b,c FROM t1;
|
||||
BEGIN
|
||||
OPEN c;
|
||||
LOOP
|
||||
FETCH c INTO v_a, v_b, v_c;
|
||||
EXIT WHEN c%NOTFOUND;
|
||||
INSERT INTO t2 (a,b,c) VALUES (v_a, v_b, v_c);
|
||||
END LOOP;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
SELECT * FROM t2;
|
||||
a b c
|
||||
1 b1 2001-01-01 10:20:30.123
|
||||
2 b2 2001-01-02 10:20:30.123
|
||||
DROP TABLE t2;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
239
mysql-test/suite/compat/oracle/r/sp-security.result
Normal file
239
mysql-test/suite/compat/oracle/r/sp-security.result
Normal file
@@ -0,0 +1,239 @@
|
||||
SET sql_mode=ORACLE;
|
||||
#
|
||||
# MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
#
|
||||
#
|
||||
# Initiation:
|
||||
# - creating database db1
|
||||
# - creating user user1 with access rights to db1
|
||||
#
|
||||
CREATE DATABASE db1;
|
||||
CREATE TABLE db1.t1 (a INT, b VARCHAR(10));
|
||||
CREATE USER user1;
|
||||
GRANT ALL PRIVILEGES ON test.* TO user1;
|
||||
connect conn1,localhost,user1,,test;
|
||||
SET sql_mode=ORACLE;
|
||||
SELECT database();
|
||||
database()
|
||||
test
|
||||
SELECT user();
|
||||
user()
|
||||
user1@localhost
|
||||
#
|
||||
# Making sure that user1 does not have privileges to db1.t1
|
||||
#
|
||||
SHOW CREATE TABLE db1.t1;
|
||||
ERROR 42000: SHOW command denied to user 'user1'@'localhost' for table 't1'
|
||||
SHOW FIELDS IN db1.t1;
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
|
||||
#
|
||||
# Trigger: using %TYPE with a table we don't have access to
|
||||
#
|
||||
CREATE TABLE test.t1 (a INT, b INT);
|
||||
INSERT INTO test.t1 (a,b) VALUES (10,20);
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
10 20
|
||||
CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE b db1.t1.b%TYPE := 20;
|
||||
BEGIN
|
||||
:NEW.b := 10;
|
||||
END;
|
||||
END
|
||||
$$
|
||||
INSERT INTO t1 (a) VALUES (10);
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
10 20
|
||||
DROP TRIGGER tr1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Stored procedure: Using %TYPE for with a table that we don't have access to
|
||||
# DEFINER user1, SQL SECURITY DEFAULT
|
||||
#
|
||||
CREATE PROCEDURE p1()
|
||||
AS
|
||||
a db1.t1.a%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Stored procedure: Using %TYPE for with a table that we don't have access to
|
||||
# DEFINER root, SQL SECURITY INVOKER
|
||||
#
|
||||
connection default;
|
||||
CREATE PROCEDURE p1()
|
||||
SQL SECURITY INVOKER
|
||||
AS
|
||||
a db1.t1.a%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
connection conn1;
|
||||
CALL p1;
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Stored procedure: Using %TYPE for with a table that we don't have access to
|
||||
# DEFINER root, SQL SECURITY DEFINER
|
||||
#
|
||||
connection default;
|
||||
CREATE PROCEDURE p1()
|
||||
SQL SECURITY DEFINER
|
||||
AS
|
||||
a db1.t1.a%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
connection conn1;
|
||||
CALL p1;
|
||||
a
|
||||
10
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Stored function: Using %TYPE for with a table that we don't have access to
|
||||
# DEFINER user1, SQL SECURITY DEFAULT
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE FUNCTION f1() RETURN INT
|
||||
AS
|
||||
a db1.t1.a%TYPE:=0;
|
||||
BEGIN
|
||||
RETURN OCTET_LENGTH(a);
|
||||
END;
|
||||
$$
|
||||
SELECT f1();
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Stored function: Using %TYPE for with a table that we don't have access to
|
||||
# DEFINER root, SQL SECURITY INVOKER
|
||||
#
|
||||
connection default;
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE FUNCTION f1() RETURN INT
|
||||
SQL SECURITY INVOKER
|
||||
AS
|
||||
a db1.t1.a%TYPE:=0;
|
||||
BEGIN
|
||||
RETURN OCTET_LENGTH(a);
|
||||
END;
|
||||
$$
|
||||
connection conn1;
|
||||
SELECT f1();
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for table 't1'
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Stored function: Using %TYPE for with a table that we don't have access to
|
||||
# DEFINER root, SQL SECURITY DEFINER
|
||||
#
|
||||
connection default;
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE FUNCTION f1() RETURN INT
|
||||
SQL SECURITY DEFINER
|
||||
AS
|
||||
a db1.t1.a%TYPE:=0;
|
||||
BEGIN
|
||||
RETURN OCTET_LENGTH(a);
|
||||
END;
|
||||
$$
|
||||
connection conn1;
|
||||
SELECT f1();
|
||||
f1()
|
||||
1
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1;
|
||||
connection default;
|
||||
GRANT SELECT (a) ON db1.t1 TO user1;
|
||||
connection conn1;
|
||||
#
|
||||
# Making sure that user1 has access to db1.t1.a, but not to db1.t1.b
|
||||
#
|
||||
SHOW CREATE TABLE db1.t1;
|
||||
ERROR 42000: SHOW command denied to user 'user1'@'localhost' for table 't1'
|
||||
SHOW FIELDS IN db1.t1;
|
||||
Field Type Null Key Default Extra
|
||||
a int(11) YES NULL
|
||||
#
|
||||
# Trigger: Per-column privileges
|
||||
#
|
||||
CREATE TABLE test.t1 (a INT, b INT);
|
||||
INSERT INTO test.t1 (a,b) VALUES (10,20);
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
10 20
|
||||
CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE a db1.t1.a%TYPE := 20;
|
||||
BEGIN
|
||||
:NEW.b := 10;
|
||||
END;
|
||||
END
|
||||
$$
|
||||
INSERT INTO t1 (a) VALUES (10);
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
10 20
|
||||
10 10
|
||||
DROP TRIGGER tr1;
|
||||
CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE b db1.t1.b%TYPE := 20;
|
||||
BEGIN
|
||||
:NEW.b := 10;
|
||||
END;
|
||||
END
|
||||
$$
|
||||
INSERT INTO t1 (a) VALUES (10);
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for column 'b' in table 't1'
|
||||
SELECT * FROM t1;
|
||||
a b
|
||||
10 20
|
||||
10 10
|
||||
DROP TRIGGER tr1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Stored procedure: Per-column privileges
|
||||
# DEFINER user1, SQL SECURITY DEFAULT
|
||||
#
|
||||
CREATE PROCEDURE p1()
|
||||
AS
|
||||
a db1.t1.a%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
a
|
||||
10
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1()
|
||||
AS
|
||||
b db1.t1.b%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT b;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR 42000: SELECT command denied to user 'user1'@'localhost' for column 'b' in table 't1'
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
disconnect conn1;
|
||||
connection default;
|
||||
DROP USER user1;
|
||||
DROP DATABASE db1;
|
||||
#
|
||||
# End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
#
|
@@ -1240,3 +1240,939 @@ DROP TABLE t1, t2;
|
||||
#
|
||||
# End of MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT
|
||||
#
|
||||
#
|
||||
# MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
#
|
||||
#
|
||||
# Missing table
|
||||
#
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
ERROR 42S02: Table 'test.t1' doesn't exist
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Missing column
|
||||
#
|
||||
CREATE TABLE t1 (b INT);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
ERROR 42S22: Unknown column 'a' in 't1'
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# One %TYPE variable
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
BEGIN
|
||||
a:= 123;
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
a
|
||||
123
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Two %TYPE variables, with a truncation warning on assignment
|
||||
#
|
||||
CREATE TABLE t1 (a TINYINT, b INT);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
b t1.b%TYPE;
|
||||
BEGIN
|
||||
a:= 200;
|
||||
b:= 200;
|
||||
SELECT a, b;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
a b
|
||||
127 200
|
||||
Warnings:
|
||||
Warning 1264 Out of range value for column 'a' at row 1
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# %TYPE variables for fields with various attributes
|
||||
#
|
||||
CREATE TABLE t1 (
|
||||
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
a TINYINT NOT NULL,
|
||||
b INT NOT NULL,
|
||||
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE(a)
|
||||
);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
id t1.id%TYPE;
|
||||
a t1.a%TYPE;
|
||||
b t1.b%TYPE;
|
||||
ts t1.ts%TYPE;
|
||||
BEGIN
|
||||
SELECT id, a, b, ts;
|
||||
CREATE TABLE t2 AS SELECT id, a, b, ts;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
id a b ts
|
||||
NULL NULL NULL NULL
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"id" int(11) DEFAULT NULL,
|
||||
"a" tinyint(4) DEFAULT NULL,
|
||||
"b" int(11) DEFAULT NULL,
|
||||
"ts" timestamp NULL DEFAULT NULL
|
||||
)
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# %TYPE + virtual columns
|
||||
#
|
||||
CREATE TABLE t1 (
|
||||
a INT NOT NULL,
|
||||
b VARCHAR(32),
|
||||
c INT AS (a + 10) VIRTUAL,
|
||||
d VARCHAR(5) AS (left(b,5)) PERSISTENT
|
||||
);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
c t1.c%TYPE;
|
||||
d t1.d%TYPE;
|
||||
BEGIN
|
||||
SELECT c, d;
|
||||
CREATE TABLE t2 AS SELECT c, d;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
c d
|
||||
NULL NULL
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"c" int(11) DEFAULT NULL,
|
||||
"d" varchar(5) DEFAULT NULL
|
||||
)
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# %TYPE + the ZEROFILL attribute
|
||||
#
|
||||
CREATE TABLE t1 (
|
||||
dz DECIMAL(10,3) ZEROFILL
|
||||
);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
dzr t1.dz%TYPE := 10;
|
||||
dzt DECIMAL(10,3) ZEROFILL := 10;
|
||||
BEGIN
|
||||
SELECT dzr, dzt;
|
||||
CREATE TABLE t2 AS SELECT dzr,dzt;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
dzr dzt
|
||||
0000010.000 0000010.000
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"dzr" decimal(10,3) unsigned DEFAULT NULL,
|
||||
"dzt" decimal(10,3) unsigned DEFAULT NULL
|
||||
)
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Temporary tables shadow real tables for %TYPE purposes
|
||||
#
|
||||
CREATE TABLE t1 (a VARCHAR(10));
|
||||
INSERT INTO t1 VALUES ('t1');
|
||||
CREATE TEMPORARY TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
10
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE:=11;
|
||||
BEGIN
|
||||
CREATE TABLE t2 AS SELECT a;
|
||||
END;
|
||||
$$
|
||||
#
|
||||
# Should use INT(11) as %TYPE, as in the temporary table
|
||||
#
|
||||
CALL p1();
|
||||
SHOW CREATE TABLE t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"a" int(11) DEFAULT NULL
|
||||
)
|
||||
SELECT * FROM t2;
|
||||
a
|
||||
11
|
||||
DROP TABLE t2;
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
10
|
||||
DROP TEMPORARY TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
a
|
||||
t1
|
||||
#
|
||||
# Should use VARCHAR(10) as %TYPE, as in the real table
|
||||
#
|
||||
CALL p1();
|
||||
SHOW CREATE TABLE t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"a" varchar(10) DEFAULT NULL
|
||||
)
|
||||
SELECT * FROM t2;
|
||||
a
|
||||
11
|
||||
DROP TABLE t2;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# t1.a%TYPE searches for "t1" in the current database
|
||||
#
|
||||
CREATE TABLE t1 (a VARCHAR(10));
|
||||
CREATE DATABASE test1;
|
||||
CREATE TABLE test1.t1 (a INT);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE:=11;
|
||||
BEGIN
|
||||
CREATE TABLE test.t2 AS SELECT a;
|
||||
END;
|
||||
$$
|
||||
#
|
||||
# This interprets t1.a%TYPE as VARCHAR(10), as in test.t1.a
|
||||
#
|
||||
USE test;
|
||||
CALL test.p1();
|
||||
SHOW CREATE TABLE test.t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"a" varchar(10) DEFAULT NULL
|
||||
)
|
||||
DROP TABLE test.t2;
|
||||
#
|
||||
# This interprets t1.a%TYPE as INT, as in test1.t1.a
|
||||
#
|
||||
USE test1;
|
||||
CALL test.p1();
|
||||
SHOW CREATE TABLE test.t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"a" int(11) DEFAULT NULL
|
||||
)
|
||||
DROP TABLE test.t2;
|
||||
#
|
||||
# Error if there is no an active database
|
||||
#
|
||||
DROP DATABASE test1;
|
||||
CALL test.p1();
|
||||
ERROR 3D000: No database selected
|
||||
USE test;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# A reference to a table in a non-existing database
|
||||
#
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a test1.t1.a%TYPE;
|
||||
BEGIN
|
||||
CREATE TABLE t1 AS SELECT a;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR 42S02: Table 'test1.t1' doesn't exist
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# A reference to a table in a different database
|
||||
#
|
||||
CREATE TABLE t1(a INT);
|
||||
CREATE DATABASE test1;
|
||||
CREATE TABLE test1.t1 (a VARCHAR(10));
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
b test1.t1.a%TYPE;
|
||||
BEGIN
|
||||
CREATE TABLE t2 AS SELECT a,b;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
SHOW CREATE TABLE t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"a" int(11) DEFAULT NULL,
|
||||
"b" varchar(10) DEFAULT NULL
|
||||
)
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t2;
|
||||
DROP DATABASE test1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Using a table before it appears in a %TYPE declaration + multiple %TYPE declarations
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b VARCHAR(10));
|
||||
INSERT INTO t1 (a,b) VALUES (10,'b10');
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
INSERT INTO t1 (a,b) VALUES (11, 'b11');
|
||||
SELECT * FROM t1;
|
||||
DECLARE
|
||||
va t1.a%TYPE:= 30;
|
||||
vb t1.b%TYPE:= 'b30';
|
||||
BEGIN
|
||||
INSERT INTO t1 (a,b) VALUES (12,'b12');
|
||||
SELECT * FROM t1;
|
||||
INSERT INTO t1 (a,b) VALUES (va, vb);
|
||||
SELECT * FROM t1;
|
||||
END;
|
||||
DECLARE
|
||||
va t1.a%TYPE:= 40;
|
||||
vb t1.b%TYPE:= 'b40';
|
||||
BEGIN
|
||||
INSERT INTO t1 (a,b) VALUES (va,vb);
|
||||
SELECT * FROM t1;
|
||||
END;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
a b
|
||||
10 b10
|
||||
11 b11
|
||||
a b
|
||||
10 b10
|
||||
11 b11
|
||||
12 b12
|
||||
a b
|
||||
10 b10
|
||||
11 b11
|
||||
12 b12
|
||||
30 b30
|
||||
a b
|
||||
10 b10
|
||||
11 b11
|
||||
12 b12
|
||||
30 b30
|
||||
40 b40
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# %TYPE variables + TABLE vs VIEW
|
||||
#
|
||||
CREATE TABLE t1 (
|
||||
bit6 BIT(6),
|
||||
bit7 BIT(7),
|
||||
bit8 BIT(8),
|
||||
i1 TINYINT,
|
||||
i2 SMALLINT,
|
||||
i3 MEDIUMINT,
|
||||
i4 INT,
|
||||
i8 BIGINT,
|
||||
ff FLOAT,
|
||||
fd DOUBLE,
|
||||
cc CHAR(10),
|
||||
cv VARCHAR(10),
|
||||
cvu VARCHAR(10) CHARACTER SET utf8,
|
||||
t1 TINYTEXT,
|
||||
t2 TEXT,
|
||||
t3 MEDIUMTEXT,
|
||||
t4 LONGTEXT,
|
||||
enum1 ENUM('a','b','c'),
|
||||
set1 SET('a','b','c'),
|
||||
blob1 TINYBLOB,
|
||||
blob2 BLOB,
|
||||
blob3 MEDIUMBLOB,
|
||||
blob4 LONGBLOB,
|
||||
yy YEAR,
|
||||
dd DATE,
|
||||
tm0 TIME,
|
||||
tm3 TIME(3),
|
||||
tm6 TIME(6),
|
||||
dt0 DATETIME,
|
||||
dt3 DATETIME(3),
|
||||
dt6 DATETIME(6),
|
||||
ts0 TIMESTAMP,
|
||||
ts3 TIMESTAMP(3),
|
||||
ts6 TIMESTAMP(6),
|
||||
dc100 DECIMAL(10,0),
|
||||
dc103 DECIMAL(10,3),
|
||||
dc209 DECIMAL(20,9)
|
||||
);
|
||||
CREATE PROCEDURE p1(command enum('create','select'))
|
||||
AS
|
||||
bit6 t1.bit6%TYPE := 0x30;
|
||||
bit7 t1.bit7%TYPE := 0x41;
|
||||
bit8 t1.bit8%TYPE := 0x7E;
|
||||
i1 t1.i1%TYPE := 11;
|
||||
i2 t1.i2%TYPE := 12;
|
||||
i3 t1.i3%TYPE := 13;
|
||||
i4 t1.i4%TYPE := 14;
|
||||
i8 t1.i8%TYPE := 18;
|
||||
ff t1.ff%TYPE := 21;
|
||||
fd t1.fd%TYPE := 22;
|
||||
cc t1.cc%TYPE := 'char';
|
||||
cv t1.cv%TYPE := 'varchar';
|
||||
cvu t1.cvu%TYPE := 'varcharu8';
|
||||
t1 t1.t1%TYPE := 'text1';
|
||||
t2 t1.t2%TYPE := 'text2';
|
||||
t3 t1.t3%TYPE := 'text3';
|
||||
t4 t1.t4%TYPE := 'text4';
|
||||
enum1 t1.enum1%TYPE := 'b';
|
||||
set1 t1.set1%TYPE := 'a,c';
|
||||
blob1 t1.blob1%TYPE := 'blob1';
|
||||
blob2 t1.blob2%TYPE := 'blob2';
|
||||
blob3 t1.blob3%TYPE := 'blob3';
|
||||
blob4 t1.blob4%TYPE := 'blob4';
|
||||
yy t1.yy%TYPE := 2001;
|
||||
dd t1.dd%TYPE := '2001-01-01';
|
||||
tm0 t1.tm0%TYPE := '00:00:01';
|
||||
tm3 t1.tm3%TYPE := '00:00:03.333';
|
||||
tm6 t1.tm6%TYPE := '00:00:06.666666';
|
||||
dt0 t1.dt0%TYPE := '2001-01-01 00:00:01';
|
||||
dt3 t1.dt3%TYPE := '2001-01-03 00:00:01.333';
|
||||
dt6 t1.dt6%TYPE := '2001-01-06 00:00:01.666666';
|
||||
ts0 t1.ts0%TYPE := '2002-01-01 00:00:01';
|
||||
ts3 t1.ts3%TYPE := '2002-01-03 00:00:01.333';
|
||||
ts6 t1.ts6%TYPE := '2002-01-06 00:00:01.666666';
|
||||
dc100 t1.dc100%TYPE := 10;
|
||||
dc103 t1.dc103%TYPE := 10.123;
|
||||
dc209 t1.dc209%TYPE := 10.123456789;
|
||||
BEGIN
|
||||
CASE
|
||||
WHEN command='create' THEN
|
||||
CREATE TABLE t2 AS SELECT
|
||||
bit6, bit7, bit8,
|
||||
i1,i2,i3,i4,i8,
|
||||
ff,fd, dc100, dc103, dc209,
|
||||
cc,cv,cvu,
|
||||
t1,t2,t3,t4,
|
||||
enum1, set1,
|
||||
blob1, blob2, blob3, blob4,
|
||||
dd, yy,
|
||||
tm0, tm3, tm6,
|
||||
dt0, dt3, dt6,
|
||||
ts0, ts3, ts6;
|
||||
WHEN command='select' THEN
|
||||
SELECT
|
||||
bit6, bit7, bit8,
|
||||
i1,i2,i3,i4,i8,
|
||||
ff,fd, dc100, dc103, dc209,
|
||||
cc,cv,cvu,
|
||||
t1,t2,t3,t4,
|
||||
enum1, set1,
|
||||
blob1, blob2, blob3, blob4,
|
||||
dd, yy,
|
||||
tm0, tm3, tm6,
|
||||
dt0, dt3, dt6,
|
||||
ts0, ts3, ts6;
|
||||
END CASE;
|
||||
END;
|
||||
$$
|
||||
#
|
||||
# TABLE
|
||||
#
|
||||
CALL p1('create');
|
||||
SHOW CREATE TABLE t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"bit6" bit(6) DEFAULT NULL,
|
||||
"bit7" bit(7) DEFAULT NULL,
|
||||
"bit8" bit(8) DEFAULT NULL,
|
||||
"i1" tinyint(4) DEFAULT NULL,
|
||||
"i2" smallint(6) DEFAULT NULL,
|
||||
"i3" mediumint(9) DEFAULT NULL,
|
||||
"i4" int(11) DEFAULT NULL,
|
||||
"i8" bigint(20) DEFAULT NULL,
|
||||
"ff" float DEFAULT NULL,
|
||||
"fd" double DEFAULT NULL,
|
||||
"dc100" decimal(10,0) DEFAULT NULL,
|
||||
"dc103" decimal(10,3) DEFAULT NULL,
|
||||
"dc209" decimal(20,9) DEFAULT NULL,
|
||||
"cc" varchar(10) DEFAULT NULL,
|
||||
"cv" varchar(10) DEFAULT NULL,
|
||||
"cvu" varchar(10) CHARACTER SET utf8 DEFAULT NULL,
|
||||
"t1" tinytext DEFAULT NULL,
|
||||
"t2" text DEFAULT NULL,
|
||||
"t3" mediumtext DEFAULT NULL,
|
||||
"t4" longtext DEFAULT NULL,
|
||||
"enum1" varchar(1) DEFAULT NULL,
|
||||
"set1" varchar(5) DEFAULT NULL,
|
||||
"blob1" tinyblob DEFAULT NULL,
|
||||
"blob2" longblob DEFAULT NULL,
|
||||
"blob3" mediumblob DEFAULT NULL,
|
||||
"blob4" longblob DEFAULT NULL,
|
||||
"dd" datetime DEFAULT NULL,
|
||||
"yy" year(4) DEFAULT NULL,
|
||||
"tm0" time DEFAULT NULL,
|
||||
"tm3" time(3) DEFAULT NULL,
|
||||
"tm6" time(6) DEFAULT NULL,
|
||||
"dt0" datetime DEFAULT NULL,
|
||||
"dt3" datetime(3) DEFAULT NULL,
|
||||
"dt6" datetime(6) DEFAULT NULL,
|
||||
"ts0" timestamp NULL DEFAULT NULL,
|
||||
"ts3" timestamp(3) NULL DEFAULT NULL,
|
||||
"ts6" timestamp(6) NULL DEFAULT NULL
|
||||
)
|
||||
SELECT * FROM t2;
|
||||
bit6 0
|
||||
bit7 A
|
||||
bit8 ~
|
||||
i1 11
|
||||
i2 12
|
||||
i3 13
|
||||
i4 14
|
||||
i8 18
|
||||
ff 21
|
||||
fd 22
|
||||
dc100 10
|
||||
dc103 10.123
|
||||
dc209 10.123456789
|
||||
cc char
|
||||
cv varchar
|
||||
cvu varcharu8
|
||||
t1 text1
|
||||
t2 text2
|
||||
t3 text3
|
||||
t4 text4
|
||||
enum1 b
|
||||
set1 a,c
|
||||
blob1 blob1
|
||||
blob2 blob2
|
||||
blob3 blob3
|
||||
blob4 blob4
|
||||
dd 2001-01-01 00:00:00
|
||||
yy 2001
|
||||
tm0 00:00:01
|
||||
tm3 00:00:03.333
|
||||
tm6 00:00:06.666666
|
||||
dt0 2001-01-01 00:00:01
|
||||
dt3 2001-01-03 00:00:01.333
|
||||
dt6 2001-01-06 00:00:01.666666
|
||||
ts0 2002-01-01 00:00:01
|
||||
ts3 2002-01-03 00:00:01.333
|
||||
ts6 2002-01-06 00:00:01.666666
|
||||
DROP TABLE t2;
|
||||
CALL p1('select');
|
||||
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||
def bit6 bit6 16 6 1 Y 32 0 63
|
||||
def bit7 bit7 16 7 1 Y 32 0 63
|
||||
def bit8 bit8 16 8 1 Y 32 0 63
|
||||
def i1 i1 1 4 2 Y 32768 0 63
|
||||
def i2 i2 2 6 2 Y 32768 0 63
|
||||
def i3 i3 9 9 2 Y 32768 0 63
|
||||
def i4 i4 3 11 2 Y 32768 0 63
|
||||
def i8 i8 8 20 2 Y 32768 0 63
|
||||
def ff ff 4 12 2 Y 32768 31 63
|
||||
def fd fd 5 22 2 Y 32768 31 63
|
||||
def dc100 dc100 246 11 2 Y 32768 0 63
|
||||
def dc103 dc103 246 12 6 Y 32768 3 63
|
||||
def dc209 dc209 246 22 12 Y 32768 9 63
|
||||
def cc cc 254 10 4 Y 0 0 8
|
||||
def cv cv 253 10 7 Y 0 0 8
|
||||
def cvu cvu 253 10 9 Y 0 0 8
|
||||
def t1 t1 252 255 5 Y 16 0 8
|
||||
def t2 t2 252 65535 5 Y 16 0 8
|
||||
def t3 t3 252 16777215 5 Y 16 0 8
|
||||
def t4 t4 252 4294967295 5 Y 16 0 8
|
||||
def enum1 enum1 254 1 1 Y 256 0 8
|
||||
def set1 set1 254 5 3 Y 2048 0 8
|
||||
def blob1 blob1 252 255 5 Y 144 0 63
|
||||
def blob2 blob2 252 4294967295 5 Y 144 0 63
|
||||
def blob3 blob3 252 16777215 5 Y 144 0 63
|
||||
def blob4 blob4 252 4294967295 5 Y 144 0 63
|
||||
def dd dd 12 19 19 Y 128 0 63
|
||||
def yy yy 13 4 4 Y 32864 0 63
|
||||
def tm0 tm0 11 10 8 Y 128 0 63
|
||||
def tm3 tm3 11 14 12 Y 128 3 63
|
||||
def tm6 tm6 11 17 15 Y 128 6 63
|
||||
def dt0 dt0 12 19 19 Y 128 0 63
|
||||
def dt3 dt3 12 23 23 Y 128 3 63
|
||||
def dt6 dt6 12 26 26 Y 128 6 63
|
||||
def ts0 ts0 7 19 19 Y 9376 0 63
|
||||
def ts3 ts3 7 23 23 Y 160 3 63
|
||||
def ts6 ts6 7 26 26 Y 160 6 63
|
||||
bit6 0
|
||||
bit7 A
|
||||
bit8 ~
|
||||
i1 11
|
||||
i2 12
|
||||
i3 13
|
||||
i4 14
|
||||
i8 18
|
||||
ff 21
|
||||
fd 22
|
||||
dc100 10
|
||||
dc103 10.123
|
||||
dc209 10.123456789
|
||||
cc char
|
||||
cv varchar
|
||||
cvu varcharu8
|
||||
t1 text1
|
||||
t2 text2
|
||||
t3 text3
|
||||
t4 text4
|
||||
enum1 b
|
||||
set1 a,c
|
||||
blob1 blob1
|
||||
blob2 blob2
|
||||
blob3 blob3
|
||||
blob4 blob4
|
||||
dd 2001-01-01 00:00:00
|
||||
yy 2001
|
||||
tm0 00:00:01
|
||||
tm3 00:00:03.333
|
||||
tm6 00:00:06.666666
|
||||
dt0 2001-01-01 00:00:01
|
||||
dt3 2001-01-03 00:00:01.333
|
||||
dt6 2001-01-06 00:00:01.666666
|
||||
ts0 2002-01-01 00:00:01
|
||||
ts3 2002-01-03 00:00:01.333
|
||||
ts6 2002-01-06 00:00:01.666666
|
||||
#
|
||||
# VIEW
|
||||
#
|
||||
ALTER TABLE t1 RENAME t0;
|
||||
CREATE VIEW t1 AS SELECT * FROM t0;
|
||||
CALL p1('create');
|
||||
SHOW CREATE TABLE t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"bit6" bit(6) DEFAULT NULL,
|
||||
"bit7" bit(7) DEFAULT NULL,
|
||||
"bit8" bit(8) DEFAULT NULL,
|
||||
"i1" tinyint(4) DEFAULT NULL,
|
||||
"i2" smallint(6) DEFAULT NULL,
|
||||
"i3" mediumint(9) DEFAULT NULL,
|
||||
"i4" int(11) DEFAULT NULL,
|
||||
"i8" bigint(20) DEFAULT NULL,
|
||||
"ff" float DEFAULT NULL,
|
||||
"fd" double DEFAULT NULL,
|
||||
"dc100" decimal(10,0) DEFAULT NULL,
|
||||
"dc103" decimal(10,3) DEFAULT NULL,
|
||||
"dc209" decimal(20,9) DEFAULT NULL,
|
||||
"cc" varchar(10) DEFAULT NULL,
|
||||
"cv" varchar(10) DEFAULT NULL,
|
||||
"cvu" varchar(10) CHARACTER SET utf8 DEFAULT NULL,
|
||||
"t1" tinytext DEFAULT NULL,
|
||||
"t2" text DEFAULT NULL,
|
||||
"t3" mediumtext DEFAULT NULL,
|
||||
"t4" longtext DEFAULT NULL,
|
||||
"enum1" varchar(1) DEFAULT NULL,
|
||||
"set1" varchar(5) DEFAULT NULL,
|
||||
"blob1" tinyblob DEFAULT NULL,
|
||||
"blob2" longblob DEFAULT NULL,
|
||||
"blob3" mediumblob DEFAULT NULL,
|
||||
"blob4" longblob DEFAULT NULL,
|
||||
"dd" datetime DEFAULT NULL,
|
||||
"yy" year(4) DEFAULT NULL,
|
||||
"tm0" time DEFAULT NULL,
|
||||
"tm3" time(3) DEFAULT NULL,
|
||||
"tm6" time(6) DEFAULT NULL,
|
||||
"dt0" datetime DEFAULT NULL,
|
||||
"dt3" datetime(3) DEFAULT NULL,
|
||||
"dt6" datetime(6) DEFAULT NULL,
|
||||
"ts0" timestamp NULL DEFAULT NULL,
|
||||
"ts3" timestamp(3) NULL DEFAULT NULL,
|
||||
"ts6" timestamp(6) NULL DEFAULT NULL
|
||||
)
|
||||
SELECT * FROM t2;
|
||||
bit6 0
|
||||
bit7 A
|
||||
bit8 ~
|
||||
i1 11
|
||||
i2 12
|
||||
i3 13
|
||||
i4 14
|
||||
i8 18
|
||||
ff 21
|
||||
fd 22
|
||||
dc100 10
|
||||
dc103 10.123
|
||||
dc209 10.123456789
|
||||
cc char
|
||||
cv varchar
|
||||
cvu varcharu8
|
||||
t1 text1
|
||||
t2 text2
|
||||
t3 text3
|
||||
t4 text4
|
||||
enum1 b
|
||||
set1 a,c
|
||||
blob1 blob1
|
||||
blob2 blob2
|
||||
blob3 blob3
|
||||
blob4 blob4
|
||||
dd 2001-01-01 00:00:00
|
||||
yy 2001
|
||||
tm0 00:00:01
|
||||
tm3 00:00:03.333
|
||||
tm6 00:00:06.666666
|
||||
dt0 2001-01-01 00:00:01
|
||||
dt3 2001-01-03 00:00:01.333
|
||||
dt6 2001-01-06 00:00:01.666666
|
||||
ts0 2002-01-01 00:00:01
|
||||
ts3 2002-01-03 00:00:01.333
|
||||
ts6 2002-01-06 00:00:01.666666
|
||||
DROP TABLE t2;
|
||||
CALL p1('select');
|
||||
Catalog Database Table Table_alias Column Column_alias Type Length Max length Is_null Flags Decimals Charsetnr
|
||||
def bit6 bit6 16 6 1 Y 32 0 63
|
||||
def bit7 bit7 16 7 1 Y 32 0 63
|
||||
def bit8 bit8 16 8 1 Y 32 0 63
|
||||
def i1 i1 1 4 2 Y 32768 0 63
|
||||
def i2 i2 2 6 2 Y 32768 0 63
|
||||
def i3 i3 9 9 2 Y 32768 0 63
|
||||
def i4 i4 3 11 2 Y 32768 0 63
|
||||
def i8 i8 8 20 2 Y 32768 0 63
|
||||
def ff ff 4 12 2 Y 32768 31 63
|
||||
def fd fd 5 22 2 Y 32768 31 63
|
||||
def dc100 dc100 246 11 2 Y 32768 0 63
|
||||
def dc103 dc103 246 12 6 Y 32768 3 63
|
||||
def dc209 dc209 246 22 12 Y 32768 9 63
|
||||
def cc cc 254 10 4 Y 0 0 8
|
||||
def cv cv 253 10 7 Y 0 0 8
|
||||
def cvu cvu 253 10 9 Y 0 0 8
|
||||
def t1 t1 252 255 5 Y 16 0 8
|
||||
def t2 t2 252 65535 5 Y 16 0 8
|
||||
def t3 t3 252 16777215 5 Y 16 0 8
|
||||
def t4 t4 252 4294967295 5 Y 16 0 8
|
||||
def enum1 enum1 254 1 1 Y 256 0 8
|
||||
def set1 set1 254 5 3 Y 2048 0 8
|
||||
def blob1 blob1 252 255 5 Y 144 0 63
|
||||
def blob2 blob2 252 4294967295 5 Y 144 0 63
|
||||
def blob3 blob3 252 16777215 5 Y 144 0 63
|
||||
def blob4 blob4 252 4294967295 5 Y 144 0 63
|
||||
def dd dd 12 19 19 Y 128 0 63
|
||||
def yy yy 13 4 4 Y 32864 0 63
|
||||
def tm0 tm0 11 10 8 Y 128 0 63
|
||||
def tm3 tm3 11 14 12 Y 128 3 63
|
||||
def tm6 tm6 11 17 15 Y 128 6 63
|
||||
def dt0 dt0 12 19 19 Y 128 0 63
|
||||
def dt3 dt3 12 23 23 Y 128 3 63
|
||||
def dt6 dt6 12 26 26 Y 128 6 63
|
||||
def ts0 ts0 7 19 19 Y 160 0 63
|
||||
def ts3 ts3 7 23 23 Y 160 3 63
|
||||
def ts6 ts6 7 26 26 Y 160 6 63
|
||||
bit6 0
|
||||
bit7 A
|
||||
bit8 ~
|
||||
i1 11
|
||||
i2 12
|
||||
i3 13
|
||||
i4 14
|
||||
i8 18
|
||||
ff 21
|
||||
fd 22
|
||||
dc100 10
|
||||
dc103 10.123
|
||||
dc209 10.123456789
|
||||
cc char
|
||||
cv varchar
|
||||
cvu varcharu8
|
||||
t1 text1
|
||||
t2 text2
|
||||
t3 text3
|
||||
t4 text4
|
||||
enum1 b
|
||||
set1 a,c
|
||||
blob1 blob1
|
||||
blob2 blob2
|
||||
blob3 blob3
|
||||
blob4 blob4
|
||||
dd 2001-01-01 00:00:00
|
||||
yy 2001
|
||||
tm0 00:00:01
|
||||
tm3 00:00:03.333
|
||||
tm6 00:00:06.666666
|
||||
dt0 2001-01-01 00:00:01
|
||||
dt3 2001-01-03 00:00:01.333
|
||||
dt6 2001-01-06 00:00:01.666666
|
||||
ts0 2002-01-01 00:00:01
|
||||
ts3 2002-01-03 00:00:01.333
|
||||
ts6 2002-01-06 00:00:01.666666
|
||||
DROP VIEW t1;
|
||||
DROP TABLE t0;
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# VIEW with subqueries
|
||||
#
|
||||
CREATE TABLE t1 (a INT,b INT);
|
||||
INSERT INTO t1 VALUES (10,1),(20,2),(30,3),(40,4);
|
||||
SELECT AVG(a) FROM t1;
|
||||
AVG(a)
|
||||
25.0000
|
||||
CREATE VIEW v1 AS SELECT a,1 as b FROM t1 WHERE a>(SELECT AVG(a) FROM t1) AND b>(SELECT 1);
|
||||
SELECT * FROM v1;
|
||||
a b
|
||||
30 1
|
||||
40 1
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a v1.a%TYPE := 10;
|
||||
b v1.b%TYPE := 1;
|
||||
BEGIN
|
||||
SELECT a,b;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
a b
|
||||
10 1
|
||||
DROP PROCEDURE p1;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
AS
|
||||
a v1.a%TYPE := 10;
|
||||
b v1.b%TYPE := 1;
|
||||
BEGIN
|
||||
RETURN a+b;
|
||||
END;
|
||||
$$
|
||||
SELECT f1();
|
||||
f1()
|
||||
11
|
||||
DROP FUNCTION f1;
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# %TYPE variables + INFORMATION_SCHEMA
|
||||
#
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
tables_table_name INFORMATION_SCHEMA.TABLES.TABLE_NAME%TYPE;
|
||||
tables_table_rows INFORMATION_SCHEMA.TABLES.TABLE_ROWS%TYPE;
|
||||
processlist_info INFORMATION_SCHEMA.PROCESSLIST.INFO%TYPE;
|
||||
processlist_info_binary INFORMATION_SCHEMA.PROCESSLIST.INFO_BINARY%TYPE;
|
||||
BEGIN
|
||||
CREATE TABLE t1 AS SELECT
|
||||
tables_table_name,
|
||||
tables_table_rows,
|
||||
processlist_info,
|
||||
processlist_info_binary;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE "t1" (
|
||||
"tables_table_name" varchar(64) CHARACTER SET utf8 DEFAULT NULL,
|
||||
"tables_table_rows" bigint(21) unsigned DEFAULT NULL,
|
||||
"processlist_info" longtext CHARACTER SET utf8 DEFAULT NULL,
|
||||
"processlist_info_binary" blob DEFAULT NULL
|
||||
)
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# %TYPE + Table structure change
|
||||
# Data type for both a0 and a1 is chosen in the very beginning
|
||||
#
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a0 t1.a%TYPE;
|
||||
BEGIN
|
||||
ALTER TABLE t1 MODIFY a VARCHAR(10); -- This does not affect a1
|
||||
DECLARE
|
||||
a1 t1.a%TYPE;
|
||||
BEGIN
|
||||
CREATE TABLE t2 AS SELECT a0, a1;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
END;
|
||||
END
|
||||
$$
|
||||
CREATE TABLE t1 (a INT);
|
||||
CALL p1;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"a0" int(11) DEFAULT NULL,
|
||||
"a1" int(11) DEFAULT NULL
|
||||
)
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# %TYPE in parameters
|
||||
#
|
||||
CREATE TABLE t1 (a VARCHAR(10));
|
||||
CREATE DATABASE test1;
|
||||
CREATE TABLE test1.t1 (b SMALLINT);
|
||||
CREATE PROCEDURE p1(a t1.a%TYPE, b test1.t1.b%TYPE)
|
||||
AS
|
||||
BEGIN
|
||||
CREATE TABLE t2 AS SELECT a, b;
|
||||
END;
|
||||
$$
|
||||
CALL p1('test', 123);
|
||||
SHOW CREATE TABLE t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"a" varchar(10) DEFAULT NULL,
|
||||
"b" smallint(6) DEFAULT NULL
|
||||
)
|
||||
SELECT * FROM t2;
|
||||
a b
|
||||
test 123
|
||||
DROP TABLE t2;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE test1.t1;
|
||||
DROP DATABASE test1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# %TYPE in a stored function variables and arguments
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
SET sql_mode=ORACLE;
|
||||
CREATE FUNCTION f1 (prm t1.a%TYPE) RETURN INT
|
||||
AS
|
||||
a t1.a%TYPE:= prm;
|
||||
BEGIN
|
||||
RETURN a;
|
||||
END;
|
||||
$$
|
||||
SELECT f1(20);
|
||||
f1(20)
|
||||
20
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# %TYPE in function RETURN clause is not supported yet
|
||||
#
|
||||
CREATE FUNCTION f1 RETURN t1.a%TYPE
|
||||
AS
|
||||
BEGIN
|
||||
RETURN 0;
|
||||
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 't1.a%TYPE
|
||||
AS
|
||||
BEGIN
|
||||
RETURN 0;
|
||||
END' at line 1
|
||||
#
|
||||
# End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
#
|
||||
|
@@ -80,3 +80,21 @@ NULL NULL 2
|
||||
NULL 1 1
|
||||
1 1 0
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
#
|
||||
CREATE TABLE t1 (a INT, b INT, total INT);
|
||||
CREATE TRIGGER tr1 BEFORE INSERT ON t1
|
||||
FOR EACH ROW
|
||||
DECLARE
|
||||
va t1.a%TYPE:= :NEW.a;
|
||||
vb t1.b%TYPE:= :NEW.b;
|
||||
BEGIN
|
||||
:NEW.total:= va + vb;
|
||||
END;
|
||||
$$
|
||||
INSERT INTO t1 (a,b) VALUES (10, 20);
|
||||
SELECT * FROM t1;
|
||||
a b total
|
||||
10 20 30
|
||||
DROP TABLE t1;
|
||||
|
@@ -750,3 +750,36 @@ DROP PROCEDURE p1;
|
||||
--echo #
|
||||
--echo # End of MDEV-10597 Cursors with parameters
|
||||
--echo #
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT, b VARCHAR(10),c DATETIME(3));
|
||||
INSERT INTO t1 VALUES (1,'b1','2001-01-01 10:20:30.123');
|
||||
INSERT INTO t1 VALUES (2,'b2','2001-01-02 10:20:30.123');
|
||||
CREATE TABLE t2 LIKE t1;
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1()
|
||||
AS
|
||||
v_a t1.a%TYPE;
|
||||
v_b t1.b%TYPE;
|
||||
v_c t1.c%TYPE;
|
||||
CURSOR c IS SELECT a,b,c FROM t1;
|
||||
BEGIN
|
||||
OPEN c;
|
||||
LOOP
|
||||
FETCH c INTO v_a, v_b, v_c;
|
||||
EXIT WHEN c%NOTFOUND;
|
||||
INSERT INTO t2 (a,b,c) VALUES (v_a, v_b, v_c);
|
||||
END LOOP;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
SELECT * FROM t2;
|
||||
DROP TABLE t2;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
285
mysql-test/suite/compat/oracle/t/sp-security.test
Normal file
285
mysql-test/suite/compat/oracle/t/sp-security.test
Normal file
@@ -0,0 +1,285 @@
|
||||
--source include/not_embedded.inc
|
||||
|
||||
SET sql_mode=ORACLE;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
--echo #
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Initiation:
|
||||
--echo # - creating database db1
|
||||
--echo # - creating user user1 with access rights to db1
|
||||
--echo #
|
||||
|
||||
CREATE DATABASE db1;
|
||||
CREATE TABLE db1.t1 (a INT, b VARCHAR(10));
|
||||
|
||||
CREATE USER user1;
|
||||
|
||||
GRANT ALL PRIVILEGES ON test.* TO user1;
|
||||
|
||||
connect (conn1,localhost,user1,,test);
|
||||
SET sql_mode=ORACLE;
|
||||
|
||||
SELECT database();
|
||||
SELECT user();
|
||||
|
||||
--echo #
|
||||
--echo # Making sure that user1 does not have privileges to db1.t1
|
||||
--echo #
|
||||
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
SHOW CREATE TABLE db1.t1;
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
SHOW FIELDS IN db1.t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Trigger: using %TYPE with a table we don't have access to
|
||||
--echo #
|
||||
CREATE TABLE test.t1 (a INT, b INT);
|
||||
INSERT INTO test.t1 (a,b) VALUES (10,20);
|
||||
SELECT * FROM t1;
|
||||
DELIMITER $$;
|
||||
CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE b db1.t1.b%TYPE := 20;
|
||||
BEGIN
|
||||
:NEW.b := 10;
|
||||
END;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
INSERT INTO t1 (a) VALUES (10);
|
||||
SELECT * FROM t1;
|
||||
DROP TRIGGER tr1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Stored procedure: Using %TYPE for with a table that we don't have access to
|
||||
--echo # DEFINER user1, SQL SECURITY DEFAULT
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1()
|
||||
AS
|
||||
a db1.t1.a%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Stored procedure: Using %TYPE for with a table that we don't have access to
|
||||
--echo # DEFINER root, SQL SECURITY INVOKER
|
||||
--echo #
|
||||
|
||||
connection default;
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1()
|
||||
SQL SECURITY INVOKER
|
||||
AS
|
||||
a db1.t1.a%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
connection conn1;
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Stored procedure: Using %TYPE for with a table that we don't have access to
|
||||
--echo # DEFINER root, SQL SECURITY DEFINER
|
||||
--echo #
|
||||
|
||||
connection default;
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1()
|
||||
SQL SECURITY DEFINER
|
||||
AS
|
||||
a db1.t1.a%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
connection conn1;
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Stored function: Using %TYPE for with a table that we don't have access to
|
||||
--echo # DEFINER user1, SQL SECURITY DEFAULT
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
DELIMITER $$;
|
||||
CREATE FUNCTION f1() RETURN INT
|
||||
AS
|
||||
a db1.t1.a%TYPE:=0;
|
||||
BEGIN
|
||||
RETURN OCTET_LENGTH(a);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
SELECT f1();
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Stored function: Using %TYPE for with a table that we don't have access to
|
||||
--echo # DEFINER root, SQL SECURITY INVOKER
|
||||
--echo #
|
||||
|
||||
connection default;
|
||||
CREATE TABLE t1 (a INT);
|
||||
DELIMITER $$;
|
||||
CREATE FUNCTION f1() RETURN INT
|
||||
SQL SECURITY INVOKER
|
||||
AS
|
||||
a db1.t1.a%TYPE:=0;
|
||||
BEGIN
|
||||
RETURN OCTET_LENGTH(a);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
connection conn1;
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
SELECT f1();
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Stored function: Using %TYPE for with a table that we don't have access to
|
||||
--echo # DEFINER root, SQL SECURITY DEFINER
|
||||
--echo #
|
||||
|
||||
connection default;
|
||||
CREATE TABLE t1 (a INT);
|
||||
DELIMITER $$;
|
||||
CREATE FUNCTION f1() RETURN INT
|
||||
SQL SECURITY DEFINER
|
||||
AS
|
||||
a db1.t1.a%TYPE:=0;
|
||||
BEGIN
|
||||
RETURN OCTET_LENGTH(a);
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
connection conn1;
|
||||
SELECT f1();
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
connection default;
|
||||
GRANT SELECT (a) ON db1.t1 TO user1;
|
||||
connection conn1;
|
||||
|
||||
--echo #
|
||||
--echo # Making sure that user1 has access to db1.t1.a, but not to db1.t1.b
|
||||
--echo #
|
||||
|
||||
--error ER_TABLEACCESS_DENIED_ERROR
|
||||
SHOW CREATE TABLE db1.t1;
|
||||
SHOW FIELDS IN db1.t1;
|
||||
|
||||
--echo #
|
||||
--echo # Trigger: Per-column privileges
|
||||
--echo #
|
||||
CREATE TABLE test.t1 (a INT, b INT);
|
||||
INSERT INTO test.t1 (a,b) VALUES (10,20);
|
||||
SELECT * FROM t1;
|
||||
# %TYPE reference using a column we have access to
|
||||
DELIMITER $$;
|
||||
CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE a db1.t1.a%TYPE := 20;
|
||||
BEGIN
|
||||
:NEW.b := 10;
|
||||
END;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
INSERT INTO t1 (a) VALUES (10);
|
||||
SELECT * FROM t1;
|
||||
DROP TRIGGER tr1;
|
||||
# %TYPE reference using a column that we don't have access to
|
||||
DELIMITER $$;
|
||||
CREATE TRIGGER test.tr1 BEFORE INSERT ON test.t1 FOR EACH ROW
|
||||
BEGIN
|
||||
DECLARE b db1.t1.b%TYPE := 20;
|
||||
BEGIN
|
||||
:NEW.b := 10;
|
||||
END;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_COLUMNACCESS_DENIED_ERROR
|
||||
INSERT INTO t1 (a) VALUES (10);
|
||||
SELECT * FROM t1;
|
||||
DROP TRIGGER tr1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Stored procedure: Per-column privileges
|
||||
--echo # DEFINER user1, SQL SECURITY DEFAULT
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1()
|
||||
AS
|
||||
a db1.t1.a%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1()
|
||||
AS
|
||||
b db1.t1.b%TYPE := 10;
|
||||
BEGIN
|
||||
SELECT b;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_COLUMNACCESS_DENIED_ERROR
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Clean up
|
||||
--echo #
|
||||
disconnect conn1;
|
||||
connection default;
|
||||
|
||||
DROP USER user1;
|
||||
DROP DATABASE db1;
|
||||
|
||||
--echo #
|
||||
--echo # End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
--echo #
|
@@ -1348,3 +1348,648 @@ DROP TABLE t1, t2;
|
||||
--echo #
|
||||
--echo # End of MDEV-10583 sql_mode=ORACLE: SQL%ROWCOUNT
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
--echo #
|
||||
|
||||
--echo #
|
||||
--echo # Missing table
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NO_SUCH_TABLE
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Missing column
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (b INT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
BEGIN
|
||||
NULL;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_BAD_FIELD_ERROR
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # One %TYPE variable
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
BEGIN
|
||||
a:= 123;
|
||||
SELECT a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # Two %TYPE variables, with a truncation warning on assignment
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a TINYINT, b INT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
b t1.b%TYPE;
|
||||
BEGIN
|
||||
a:= 200;
|
||||
b:= 200;
|
||||
SELECT a, b;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE variables for fields with various attributes
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (
|
||||
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
a TINYINT NOT NULL,
|
||||
b INT NOT NULL,
|
||||
ts TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE(a)
|
||||
);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
id t1.id%TYPE;
|
||||
a t1.a%TYPE;
|
||||
b t1.b%TYPE;
|
||||
ts t1.ts%TYPE;
|
||||
BEGIN
|
||||
SELECT id, a, b, ts;
|
||||
CREATE TABLE t2 AS SELECT id, a, b, ts;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE + virtual columns
|
||||
--echo #
|
||||
|
||||
#
|
||||
# TODO: Changing 'a + 10' to 'a mod 10' make it fail, because
|
||||
# it's Item::print() returns 'a % 10' which makes grammar conflict
|
||||
# with cursor attributes
|
||||
|
||||
CREATE TABLE t1 (
|
||||
a INT NOT NULL,
|
||||
b VARCHAR(32),
|
||||
c INT AS (a + 10) VIRTUAL,
|
||||
d VARCHAR(5) AS (left(b,5)) PERSISTENT
|
||||
);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
c t1.c%TYPE;
|
||||
d t1.d%TYPE;
|
||||
BEGIN
|
||||
SELECT c, d;
|
||||
CREATE TABLE t2 AS SELECT c, d;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE + the ZEROFILL attribute
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (
|
||||
dz DECIMAL(10,3) ZEROFILL
|
||||
);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
dzr t1.dz%TYPE := 10;
|
||||
dzt DECIMAL(10,3) ZEROFILL := 10;
|
||||
BEGIN
|
||||
SELECT dzr, dzt;
|
||||
CREATE TABLE t2 AS SELECT dzr,dzt;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Temporary tables shadow real tables for %TYPE purposes
|
||||
--echo #
|
||||
CREATE TABLE t1 (a VARCHAR(10));
|
||||
INSERT INTO t1 VALUES ('t1');
|
||||
CREATE TEMPORARY TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
SELECT * FROM t1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE:=11;
|
||||
BEGIN
|
||||
CREATE TABLE t2 AS SELECT a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--echo #
|
||||
--echo # Should use INT(11) as %TYPE, as in the temporary table
|
||||
--echo #
|
||||
CALL p1();
|
||||
SHOW CREATE TABLE t2;
|
||||
SELECT * FROM t2;
|
||||
DROP TABLE t2;
|
||||
SELECT * FROM t1;
|
||||
DROP TEMPORARY TABLE t1;
|
||||
SELECT * FROM t1;
|
||||
--echo #
|
||||
--echo # Should use VARCHAR(10) as %TYPE, as in the real table
|
||||
--echo #
|
||||
CALL p1();
|
||||
SHOW CREATE TABLE t2;
|
||||
SELECT * FROM t2;
|
||||
DROP TABLE t2;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # t1.a%TYPE searches for "t1" in the current database
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a VARCHAR(10));
|
||||
CREATE DATABASE test1;
|
||||
CREATE TABLE test1.t1 (a INT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE:=11;
|
||||
BEGIN
|
||||
CREATE TABLE test.t2 AS SELECT a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
--echo #
|
||||
--echo # This interprets t1.a%TYPE as VARCHAR(10), as in test.t1.a
|
||||
--echo #
|
||||
|
||||
USE test;
|
||||
CALL test.p1();
|
||||
SHOW CREATE TABLE test.t2;
|
||||
DROP TABLE test.t2;
|
||||
|
||||
--echo #
|
||||
--echo # This interprets t1.a%TYPE as INT, as in test1.t1.a
|
||||
--echo #
|
||||
|
||||
USE test1;
|
||||
CALL test.p1();
|
||||
SHOW CREATE TABLE test.t2;
|
||||
DROP TABLE test.t2;
|
||||
|
||||
--echo #
|
||||
--echo # Error if there is no an active database
|
||||
--echo #
|
||||
|
||||
DROP DATABASE test1;
|
||||
--error ER_NO_DB_ERROR
|
||||
CALL test.p1();
|
||||
|
||||
USE test;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # A reference to a table in a non-existing database
|
||||
--echo #
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a test1.t1.a%TYPE;
|
||||
BEGIN
|
||||
CREATE TABLE t1 AS SELECT a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_NO_SUCH_TABLE
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # A reference to a table in a different database
|
||||
--echo #
|
||||
CREATE TABLE t1(a INT);
|
||||
CREATE DATABASE test1;
|
||||
CREATE TABLE test1.t1 (a VARCHAR(10));
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a t1.a%TYPE;
|
||||
b test1.t1.a%TYPE;
|
||||
BEGIN
|
||||
CREATE TABLE t2 AS SELECT a,b;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t2;
|
||||
DROP DATABASE test1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Using a table before it appears in a %TYPE declaration + multiple %TYPE declarations
|
||||
--echo #
|
||||
CREATE TABLE t1 (a INT, b VARCHAR(10));
|
||||
INSERT INTO t1 (a,b) VALUES (10,'b10');
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
INSERT INTO t1 (a,b) VALUES (11, 'b11');
|
||||
SELECT * FROM t1;
|
||||
DECLARE
|
||||
va t1.a%TYPE:= 30;
|
||||
vb t1.b%TYPE:= 'b30';
|
||||
BEGIN
|
||||
INSERT INTO t1 (a,b) VALUES (12,'b12');
|
||||
SELECT * FROM t1;
|
||||
INSERT INTO t1 (a,b) VALUES (va, vb);
|
||||
SELECT * FROM t1;
|
||||
END;
|
||||
DECLARE
|
||||
va t1.a%TYPE:= 40;
|
||||
vb t1.b%TYPE:= 'b40';
|
||||
BEGIN
|
||||
INSERT INTO t1 (a,b) VALUES (va,vb);
|
||||
SELECT * FROM t1;
|
||||
END;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE variables + TABLE vs VIEW
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (
|
||||
bit6 BIT(6),
|
||||
bit7 BIT(7),
|
||||
bit8 BIT(8),
|
||||
i1 TINYINT,
|
||||
i2 SMALLINT,
|
||||
i3 MEDIUMINT,
|
||||
i4 INT,
|
||||
i8 BIGINT,
|
||||
ff FLOAT,
|
||||
fd DOUBLE,
|
||||
cc CHAR(10),
|
||||
cv VARCHAR(10),
|
||||
cvu VARCHAR(10) CHARACTER SET utf8,
|
||||
t1 TINYTEXT,
|
||||
t2 TEXT,
|
||||
t3 MEDIUMTEXT,
|
||||
t4 LONGTEXT,
|
||||
enum1 ENUM('a','b','c'),
|
||||
set1 SET('a','b','c'),
|
||||
blob1 TINYBLOB,
|
||||
blob2 BLOB,
|
||||
blob3 MEDIUMBLOB,
|
||||
blob4 LONGBLOB,
|
||||
yy YEAR,
|
||||
dd DATE,
|
||||
tm0 TIME,
|
||||
tm3 TIME(3),
|
||||
tm6 TIME(6),
|
||||
dt0 DATETIME,
|
||||
dt3 DATETIME(3),
|
||||
dt6 DATETIME(6),
|
||||
ts0 TIMESTAMP,
|
||||
ts3 TIMESTAMP(3),
|
||||
ts6 TIMESTAMP(6),
|
||||
dc100 DECIMAL(10,0),
|
||||
dc103 DECIMAL(10,3),
|
||||
dc209 DECIMAL(20,9)
|
||||
);
|
||||
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1(command enum('create','select'))
|
||||
AS
|
||||
bit6 t1.bit6%TYPE := 0x30;
|
||||
bit7 t1.bit7%TYPE := 0x41;
|
||||
bit8 t1.bit8%TYPE := 0x7E;
|
||||
i1 t1.i1%TYPE := 11;
|
||||
i2 t1.i2%TYPE := 12;
|
||||
i3 t1.i3%TYPE := 13;
|
||||
i4 t1.i4%TYPE := 14;
|
||||
i8 t1.i8%TYPE := 18;
|
||||
ff t1.ff%TYPE := 21;
|
||||
fd t1.fd%TYPE := 22;
|
||||
cc t1.cc%TYPE := 'char';
|
||||
cv t1.cv%TYPE := 'varchar';
|
||||
cvu t1.cvu%TYPE := 'varcharu8';
|
||||
t1 t1.t1%TYPE := 'text1';
|
||||
t2 t1.t2%TYPE := 'text2';
|
||||
t3 t1.t3%TYPE := 'text3';
|
||||
t4 t1.t4%TYPE := 'text4';
|
||||
enum1 t1.enum1%TYPE := 'b';
|
||||
set1 t1.set1%TYPE := 'a,c';
|
||||
blob1 t1.blob1%TYPE := 'blob1';
|
||||
blob2 t1.blob2%TYPE := 'blob2';
|
||||
blob3 t1.blob3%TYPE := 'blob3';
|
||||
blob4 t1.blob4%TYPE := 'blob4';
|
||||
yy t1.yy%TYPE := 2001;
|
||||
dd t1.dd%TYPE := '2001-01-01';
|
||||
tm0 t1.tm0%TYPE := '00:00:01';
|
||||
tm3 t1.tm3%TYPE := '00:00:03.333';
|
||||
tm6 t1.tm6%TYPE := '00:00:06.666666';
|
||||
dt0 t1.dt0%TYPE := '2001-01-01 00:00:01';
|
||||
dt3 t1.dt3%TYPE := '2001-01-03 00:00:01.333';
|
||||
dt6 t1.dt6%TYPE := '2001-01-06 00:00:01.666666';
|
||||
ts0 t1.ts0%TYPE := '2002-01-01 00:00:01';
|
||||
ts3 t1.ts3%TYPE := '2002-01-03 00:00:01.333';
|
||||
ts6 t1.ts6%TYPE := '2002-01-06 00:00:01.666666';
|
||||
dc100 t1.dc100%TYPE := 10;
|
||||
dc103 t1.dc103%TYPE := 10.123;
|
||||
dc209 t1.dc209%TYPE := 10.123456789;
|
||||
BEGIN
|
||||
CASE
|
||||
WHEN command='create' THEN
|
||||
CREATE TABLE t2 AS SELECT
|
||||
bit6, bit7, bit8,
|
||||
i1,i2,i3,i4,i8,
|
||||
ff,fd, dc100, dc103, dc209,
|
||||
cc,cv,cvu,
|
||||
t1,t2,t3,t4,
|
||||
enum1, set1,
|
||||
blob1, blob2, blob3, blob4,
|
||||
dd, yy,
|
||||
tm0, tm3, tm6,
|
||||
dt0, dt3, dt6,
|
||||
ts0, ts3, ts6;
|
||||
WHEN command='select' THEN
|
||||
SELECT
|
||||
bit6, bit7, bit8,
|
||||
i1,i2,i3,i4,i8,
|
||||
ff,fd, dc100, dc103, dc209,
|
||||
cc,cv,cvu,
|
||||
t1,t2,t3,t4,
|
||||
enum1, set1,
|
||||
blob1, blob2, blob3, blob4,
|
||||
dd, yy,
|
||||
tm0, tm3, tm6,
|
||||
dt0, dt3, dt6,
|
||||
ts0, ts3, ts6;
|
||||
END CASE;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
--echo #
|
||||
--echo # TABLE
|
||||
--echo #
|
||||
CALL p1('create');
|
||||
SHOW CREATE TABLE t2;
|
||||
--vertical_results
|
||||
SELECT * FROM t2;
|
||||
--horizontal_results
|
||||
DROP TABLE t2;
|
||||
|
||||
--disable_ps_protocol
|
||||
--enable_metadata
|
||||
--vertical_results
|
||||
CALL p1('select');
|
||||
--horizontal_results
|
||||
--disable_metadata
|
||||
--enable_ps_protocol
|
||||
|
||||
--echo #
|
||||
--echo # VIEW
|
||||
--echo #
|
||||
ALTER TABLE t1 RENAME t0;
|
||||
CREATE VIEW t1 AS SELECT * FROM t0;
|
||||
|
||||
CALL p1('create');
|
||||
SHOW CREATE TABLE t2;
|
||||
--vertical_results
|
||||
SELECT * FROM t2;
|
||||
--horizontal_results
|
||||
DROP TABLE t2;
|
||||
|
||||
--disable_ps_protocol
|
||||
--enable_metadata
|
||||
--vertical_results
|
||||
CALL p1('select');
|
||||
--horizontal_results
|
||||
--disable_metadata
|
||||
--enable_ps_protocol
|
||||
|
||||
DROP VIEW t1;
|
||||
DROP TABLE t0;
|
||||
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
--echo #
|
||||
--echo # VIEW with subqueries
|
||||
--echo #
|
||||
CREATE TABLE t1 (a INT,b INT);
|
||||
INSERT INTO t1 VALUES (10,1),(20,2),(30,3),(40,4);
|
||||
SELECT AVG(a) FROM t1;
|
||||
CREATE VIEW v1 AS SELECT a,1 as b FROM t1 WHERE a>(SELECT AVG(a) FROM t1) AND b>(SELECT 1);
|
||||
SELECT * FROM v1;
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a v1.a%TYPE := 10;
|
||||
b v1.b%TYPE := 1;
|
||||
BEGIN
|
||||
SELECT a,b;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
DELIMITER $$;
|
||||
CREATE FUNCTION f1 RETURN INT
|
||||
AS
|
||||
a v1.a%TYPE := 10;
|
||||
b v1.b%TYPE := 1;
|
||||
BEGIN
|
||||
RETURN a+b;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SELECT f1();
|
||||
DROP FUNCTION f1;
|
||||
DROP VIEW v1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE variables + INFORMATION_SCHEMA
|
||||
--echo #
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
tables_table_name INFORMATION_SCHEMA.TABLES.TABLE_NAME%TYPE;
|
||||
tables_table_rows INFORMATION_SCHEMA.TABLES.TABLE_ROWS%TYPE;
|
||||
processlist_info INFORMATION_SCHEMA.PROCESSLIST.INFO%TYPE;
|
||||
processlist_info_binary INFORMATION_SCHEMA.PROCESSLIST.INFO_BINARY%TYPE;
|
||||
BEGIN
|
||||
CREATE TABLE t1 AS SELECT
|
||||
tables_table_name,
|
||||
tables_table_rows,
|
||||
processlist_info,
|
||||
processlist_info_binary;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
SHOW CREATE TABLE t1;
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE + Table structure change
|
||||
--echo # Data type for both a0 and a1 is chosen in the very beginning
|
||||
--echo #
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a0 t1.a%TYPE;
|
||||
BEGIN
|
||||
ALTER TABLE t1 MODIFY a VARCHAR(10); -- This does not affect a1
|
||||
DECLARE
|
||||
a1 t1.a%TYPE;
|
||||
BEGIN
|
||||
CREATE TABLE t2 AS SELECT a0, a1;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
END;
|
||||
END
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CREATE TABLE t1 (a INT);
|
||||
CALL p1;
|
||||
DROP TABLE t1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE in parameters
|
||||
--echo #
|
||||
CREATE TABLE t1 (a VARCHAR(10));
|
||||
CREATE DATABASE test1;
|
||||
CREATE TABLE test1.t1 (b SMALLINT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1(a t1.a%TYPE, b test1.t1.b%TYPE)
|
||||
AS
|
||||
BEGIN
|
||||
CREATE TABLE t2 AS SELECT a, b;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1('test', 123);
|
||||
SHOW CREATE TABLE t2;
|
||||
SELECT * FROM t2;
|
||||
DROP TABLE t2;
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE test1.t1;
|
||||
DROP DATABASE test1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE in a stored function variables and arguments
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
SET sql_mode=ORACLE;
|
||||
DELIMITER $$;
|
||||
CREATE FUNCTION f1 (prm t1.a%TYPE) RETURN INT
|
||||
AS
|
||||
a t1.a%TYPE:= prm;
|
||||
BEGIN
|
||||
RETURN a;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
SELECT f1(20);
|
||||
DROP FUNCTION f1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %TYPE in function RETURN clause is not supported yet
|
||||
--echo #
|
||||
DELIMITER $$;
|
||||
--error ER_PARSE_ERROR
|
||||
CREATE FUNCTION f1 RETURN t1.a%TYPE
|
||||
AS
|
||||
BEGIN
|
||||
RETURN 0;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # End of MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
--echo #
|
||||
|
@@ -84,3 +84,23 @@ INSERT INTO t1 VALUES (NULL, 1, NULL);
|
||||
INSERT INTO t1 VALUES (1, 1, NULL);
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-10577 sql_mode=ORACLE: %TYPE in variable declarations
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT, b INT, total INT);
|
||||
DELIMITER $$;
|
||||
CREATE TRIGGER tr1 BEFORE INSERT ON t1
|
||||
FOR EACH ROW
|
||||
DECLARE
|
||||
va t1.a%TYPE:= :NEW.a;
|
||||
vb t1.b%TYPE:= :NEW.b;
|
||||
BEGIN
|
||||
:NEW.total:= va + vb;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
INSERT INTO t1 (a,b) VALUES (10, 20);
|
||||
SELECT * FROM t1;
|
||||
DROP TABLE t1;
|
||||
|
39
sql/field.h
39
sql/field.h
@@ -3853,7 +3853,7 @@ public:
|
||||
Column_definition(const char *name, enum_field_types type):
|
||||
field_name(name),
|
||||
comment(null_lex_str),
|
||||
on_update(0), sql_type(type), length(0), decimals(0),
|
||||
on_update(NULL), sql_type(type), length(0), decimals(0),
|
||||
flags(0), pack_length(0), key_length(0), unireg_check(Field::NONE),
|
||||
interval(0), charset(&my_charset_bin),
|
||||
srid(0), geom_type(Field::GEOM_GEOMETRY),
|
||||
@@ -3948,6 +3948,43 @@ public:
|
||||
return unireg_check == Field::TIMESTAMP_DN_FIELD
|
||||
|| unireg_check == Field::TIMESTAMP_DNUN_FIELD;
|
||||
}
|
||||
|
||||
// Replace the entire value by another definition
|
||||
void set_column_definition(const Column_definition *def)
|
||||
{
|
||||
*this= *def;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
This class is used during a stored routine or a trigger execution,
|
||||
at sp_rcontext::create() time.
|
||||
Currently it can represent:
|
||||
- variables with explicit data types: DECLARE a INT;
|
||||
- variables with data type references: DECLARE a t1.a%TYPE;
|
||||
|
||||
Data type references to other object types will be added soon, e.g.:
|
||||
- DECLARE a table_name%ROWTYPE;
|
||||
- DECLARE a cursor_name%ROWTYPE;
|
||||
- DECLARE a record_name%TYPE;
|
||||
- DECLARE a variable_name%TYPE;
|
||||
*/
|
||||
class Spvar_definition: public Column_definition
|
||||
{
|
||||
class Qualified_column_ident *m_column_type_ref; // for %TYPE
|
||||
public:
|
||||
Spvar_definition()
|
||||
:m_column_type_ref(NULL) { }
|
||||
bool is_column_type_ref() const { return m_column_type_ref != 0; }
|
||||
class Qualified_column_ident *column_type_ref() const
|
||||
{
|
||||
return m_column_type_ref;
|
||||
}
|
||||
void set_column_type_ref(class Qualified_column_ident *ref)
|
||||
{
|
||||
m_column_type_ref= ref;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@@ -6100,8 +6100,11 @@ Field *Item::make_string_field(TABLE *table)
|
||||
/**
|
||||
Create a field based on field_type of argument.
|
||||
|
||||
For now, this is only used to create a field for
|
||||
IFNULL(x,something) and time functions
|
||||
This is used to create a field for
|
||||
- IFNULL(x,something)
|
||||
- time functions
|
||||
- prepared statement placeholders
|
||||
- SP variables with data type references: DECLARE a t1.a%TYPE;
|
||||
|
||||
@retval
|
||||
NULL error
|
||||
|
34
sql/item.h
34
sql/item.h
@@ -2122,6 +2122,40 @@ public:
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root) { return 0; }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
An Item_splocal variant whose data type becomes known only at
|
||||
sp_rcontext creation time, e.g. "DECLARE var1 t1.col1%TYPE".
|
||||
*/
|
||||
class Item_splocal_with_delayed_data_type: public Item_splocal
|
||||
{
|
||||
public:
|
||||
Item_splocal_with_delayed_data_type(THD *thd,
|
||||
const LEX_STRING &sp_var_name,
|
||||
uint sp_var_idx,
|
||||
uint pos_in_q, uint len_in_q)
|
||||
:Item_splocal(thd, sp_var_name, sp_var_idx, MYSQL_TYPE_NULL,
|
||||
pos_in_q, len_in_q)
|
||||
{ }
|
||||
bool fix_fields(THD *thd, Item **it)
|
||||
{
|
||||
if (Item_splocal::fix_fields(thd, it))
|
||||
return true;
|
||||
set_handler(this_item()->type_handler());
|
||||
return false;
|
||||
}
|
||||
/*
|
||||
Override the inherited create_field_for_create_select(),
|
||||
because we want to preserve the exact data type for:
|
||||
DECLARE a t1.a%TYPE;
|
||||
CREATE TABLE t1 AS SELECT a;
|
||||
The inherited implementation would create a column
|
||||
based on result_type(), which is less exact.
|
||||
*/
|
||||
Field *create_field_for_create_select(TABLE *table)
|
||||
{ return tmp_table_field_from_field_type(table, false, true); }
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
Item_splocal inline implementation.
|
||||
*****************************************************************************/
|
||||
|
@@ -1396,6 +1396,41 @@ set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc,
|
||||
#endif // ! NO_EMBEDDED_ACCESS_CHECKS
|
||||
|
||||
|
||||
/**
|
||||
Create rcontext using the routine security.
|
||||
This is important for sql_mode=ORACLE to make sure that the invoker has
|
||||
access to the tables mentioned in the %TYPE references.
|
||||
|
||||
In non-Oracle sql_modes we do not need access to any tables,
|
||||
so we can omit the security context switch for performance purposes.
|
||||
|
||||
@param thd
|
||||
@param sphead
|
||||
@param is_proc
|
||||
@param root_pctx
|
||||
@param ret_value
|
||||
@retval NULL - error (access denided or EOM)
|
||||
@retval !NULL - success (the invoker has rights to all %TYPE tables)
|
||||
*/
|
||||
sp_rcontext *sp_head::rcontext_create(THD *thd, bool is_proc, Field *ret_value)
|
||||
{
|
||||
bool has_column_type_refs= m_flags & HAS_COLUMN_TYPE_REFS;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *save_security_ctx;
|
||||
if (has_column_type_refs &&
|
||||
set_routine_security_ctx(thd, this, is_proc, &save_security_ctx))
|
||||
return NULL;
|
||||
#endif
|
||||
sp_rcontext *res= sp_rcontext::create(thd, m_pcont, ret_value,
|
||||
has_column_type_refs);
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
if (has_column_type_refs)
|
||||
m_security_ctx.restore_security_context(thd, save_security_ctx);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Execute trigger stored program.
|
||||
|
||||
@@ -1493,7 +1528,8 @@ sp_head::execute_trigger(THD *thd,
|
||||
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
|
||||
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
|
||||
|
||||
if (!(nctx= sp_rcontext::create(thd, m_pcont, NULL)))
|
||||
if (!(nctx= sp_rcontext::create(thd, m_pcont, NULL,
|
||||
m_flags & HAS_COLUMN_TYPE_REFS)))
|
||||
{
|
||||
err_status= TRUE;
|
||||
goto err_with_cleanup;
|
||||
@@ -1608,7 +1644,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
|
||||
init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0, MYF(0));
|
||||
thd->set_n_backup_active_arena(&call_arena, &backup_arena);
|
||||
|
||||
if (!(nctx= sp_rcontext::create(thd, m_pcont, return_value_fld)))
|
||||
if (!(nctx= rcontext_create(thd, false, return_value_fld)))
|
||||
{
|
||||
thd->restore_active_arena(&call_arena, &backup_arena);
|
||||
err_status= TRUE;
|
||||
@@ -1823,7 +1859,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
||||
if (! octx)
|
||||
{
|
||||
/* Create a temporary old context. */
|
||||
if (!(octx= sp_rcontext::create(thd, m_pcont, NULL)))
|
||||
if (!(octx= rcontext_create(thd, true, NULL)))
|
||||
{
|
||||
DBUG_PRINT("error", ("Could not create octx"));
|
||||
DBUG_RETURN(TRUE);
|
||||
@@ -1838,7 +1874,7 @@ sp_head::execute_procedure(THD *thd, List<Item> *args)
|
||||
thd->spcont->callers_arena= thd;
|
||||
}
|
||||
|
||||
if (!(nctx= sp_rcontext::create(thd, m_pcont, NULL)))
|
||||
if (!(nctx= rcontext_create(thd, true, NULL)))
|
||||
{
|
||||
delete nctx; /* Delete nctx if it was init() that failed. */
|
||||
thd->spcont= save_spcont;
|
||||
|
@@ -165,7 +165,11 @@ public:
|
||||
b) because in CONTAINS SQL case they don't provide enough
|
||||
information anyway.
|
||||
*/
|
||||
MODIFIES_DATA= 4096
|
||||
MODIFIES_DATA= 4096,
|
||||
/*
|
||||
Marks routines that have column type references: DECLARE a t1.a%TYPE;
|
||||
*/
|
||||
HAS_COLUMN_TYPE_REFS= 8192
|
||||
};
|
||||
|
||||
stored_procedure_type m_type;
|
||||
@@ -201,6 +205,9 @@ public:
|
||||
{
|
||||
m_sp_cache_version= version_arg;
|
||||
}
|
||||
|
||||
sp_rcontext *rcontext_create(THD *thd, bool is_proc, Field *ret_value);
|
||||
|
||||
private:
|
||||
/**
|
||||
Version of the stored routine cache at the moment when the
|
||||
@@ -539,7 +546,8 @@ public:
|
||||
|
||||
/**
|
||||
Check and prepare an instance of Column_definition for field creation
|
||||
(fill all necessary attributes).
|
||||
(fill all necessary attributes), for variables, parameters and
|
||||
function return values.
|
||||
|
||||
@param[in] thd Thread handle
|
||||
@param[in] lex Yacc parsing context
|
||||
@@ -553,6 +561,32 @@ public:
|
||||
return field_def->check(thd) ||
|
||||
field_def->sp_prepare_create_field(thd, mem_root);
|
||||
}
|
||||
/**
|
||||
Check and prepare a Column_definition for a variable or a parameter.
|
||||
*/
|
||||
bool fill_spvar_definition(THD *thd, Column_definition *def)
|
||||
{
|
||||
if (fill_field_definition(thd, def))
|
||||
return true;
|
||||
def->pack_flag|= FIELDFLAG_MAYBE_NULL;
|
||||
return false;
|
||||
}
|
||||
bool fill_spvar_definition(THD *thd, Column_definition *def, const char *name)
|
||||
{
|
||||
def->field_name= name;
|
||||
return fill_spvar_definition(thd, def);
|
||||
}
|
||||
/**
|
||||
Set a column type reference for a parameter definition
|
||||
*/
|
||||
void fill_spvar_using_type_reference(sp_variable *spvar,
|
||||
Qualified_column_ident *ref)
|
||||
{
|
||||
spvar->field_def.set_column_type_ref(ref);
|
||||
spvar->field_def.field_name= spvar->name.str;
|
||||
m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
|
||||
}
|
||||
|
||||
void set_info(longlong created, longlong modified,
|
||||
st_sp_chistics *chistics, sql_mode_t sql_mode);
|
||||
|
||||
|
@@ -533,7 +533,7 @@ const sp_pcursor *sp_pcontext::find_cursor(const LEX_STRING name,
|
||||
|
||||
|
||||
void sp_pcontext::retrieve_field_definitions(
|
||||
List<Column_definition> *field_def_lst) const
|
||||
List<Spvar_definition> *field_def_lst) const
|
||||
{
|
||||
/* Put local/context fields in the result list. */
|
||||
|
||||
|
@@ -57,7 +57,7 @@ public:
|
||||
Item *default_value;
|
||||
|
||||
/// Full type information (field meta-data) of the SP-variable.
|
||||
Column_definition field_def;
|
||||
Spvar_definition field_def;
|
||||
|
||||
/// Field-type of the SP-variable.
|
||||
enum_field_types sql_type() const { return field_def.sql_type; }
|
||||
@@ -436,7 +436,7 @@ public:
|
||||
/// context and its children.
|
||||
///
|
||||
/// @param field_def_lst[out] Container to store type information.
|
||||
void retrieve_field_definitions(List<Column_definition> *field_def_lst) const;
|
||||
void retrieve_field_definitions(List<Spvar_definition> *field_def_lst) const;
|
||||
|
||||
/// Find SP-variable by name.
|
||||
///
|
||||
|
@@ -26,6 +26,9 @@
|
||||
#include "sp_rcontext.h"
|
||||
#include "sp_pcontext.h"
|
||||
#include "sql_select.h" // create_virtual_tmp_table
|
||||
#include "sql_base.h" // open_tables_only_view_structure
|
||||
#include "sql_acl.h" // SELECT_ACL
|
||||
#include "sql_parse.h" // check_table_access
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// sp_rcontext implementation.
|
||||
@@ -59,7 +62,8 @@ sp_rcontext::~sp_rcontext()
|
||||
|
||||
sp_rcontext *sp_rcontext::create(THD *thd,
|
||||
const sp_pcontext *root_parsing_ctx,
|
||||
Field *return_value_fld)
|
||||
Field *return_value_fld,
|
||||
bool resolve_type_refs)
|
||||
{
|
||||
sp_rcontext *ctx= new (thd->mem_root) sp_rcontext(root_parsing_ctx,
|
||||
return_value_fld,
|
||||
@@ -68,9 +72,13 @@ sp_rcontext *sp_rcontext::create(THD *thd,
|
||||
if (!ctx)
|
||||
return NULL;
|
||||
|
||||
List<Spvar_definition> field_def_lst;
|
||||
ctx->m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
|
||||
|
||||
if (ctx->alloc_arrays(thd) ||
|
||||
ctx->init_var_table(thd) ||
|
||||
ctx->init_var_items(thd))
|
||||
(resolve_type_refs && ctx->resolve_type_refs(thd, field_def_lst)) ||
|
||||
ctx->init_var_table(thd, field_def_lst) ||
|
||||
ctx->init_var_items(thd, field_def_lst))
|
||||
{
|
||||
delete ctx;
|
||||
return NULL;
|
||||
@@ -102,28 +110,107 @@ bool sp_rcontext::alloc_arrays(THD *thd)
|
||||
}
|
||||
|
||||
|
||||
bool sp_rcontext::init_var_table(THD *thd)
|
||||
bool sp_rcontext::init_var_table(THD *thd,
|
||||
List<Spvar_definition> &field_def_lst)
|
||||
{
|
||||
List<Column_definition> field_def_lst;
|
||||
|
||||
if (!m_root_parsing_ctx->max_var_index())
|
||||
return false;
|
||||
|
||||
m_root_parsing_ctx->retrieve_field_definitions(&field_def_lst);
|
||||
|
||||
DBUG_ASSERT(field_def_lst.elements == m_root_parsing_ctx->max_var_index());
|
||||
|
||||
if (!(m_var_table= create_virtual_tmp_table(thd, field_def_lst)))
|
||||
return true;
|
||||
|
||||
m_var_table->copy_blobs= true;
|
||||
m_var_table->alias.set("", 0, m_var_table->alias.charset());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool sp_rcontext::init_var_items(THD *thd)
|
||||
/**
|
||||
Check if we have access to use a column as a %TYPE reference.
|
||||
@return false - OK
|
||||
@return true - access denied
|
||||
*/
|
||||
static inline bool
|
||||
check_column_grant_for_type_ref(THD *thd, TABLE_LIST *table_list,
|
||||
const Qualified_column_ident *col)
|
||||
{
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
table_list->table->grant.want_privilege= SELECT_ACL;
|
||||
return check_column_grant_in_table_ref(thd, table_list,
|
||||
col->m_column.str,
|
||||
col->m_column.length);
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This method implementation is very close to fill_schema_table_by_open().
|
||||
*/
|
||||
bool sp_rcontext::resolve_type_ref(THD *thd, Column_definition *def,
|
||||
Qualified_column_ident *ref)
|
||||
{
|
||||
Open_tables_backup open_tables_state_backup;
|
||||
thd->reset_n_backup_open_tables_state(&open_tables_state_backup);
|
||||
|
||||
TABLE_LIST *table_list;
|
||||
Field *src;
|
||||
LEX *save_lex= thd->lex;
|
||||
bool rc= true;
|
||||
|
||||
sp_lex_local lex(thd, thd->lex);
|
||||
thd->lex= &lex;
|
||||
|
||||
lex.context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
|
||||
// Make %TYPE variables see temporary tables that shadow permanent tables
|
||||
thd->temporary_tables= open_tables_state_backup.temporary_tables;
|
||||
|
||||
if ((table_list= lex.select_lex.add_table_to_list(thd, ref, NULL, 0,
|
||||
TL_READ_NO_INSERT,
|
||||
MDL_SHARED_READ)) &&
|
||||
!check_table_access(thd, SELECT_ACL, table_list, TRUE, UINT_MAX, FALSE) &&
|
||||
!open_tables_only_view_structure(thd, table_list,
|
||||
thd->mdl_context.has_locks()))
|
||||
{
|
||||
if ((src= lex.query_tables->table->find_field_by_name(ref->m_column.str)))
|
||||
{
|
||||
if (!(rc= check_column_grant_for_type_ref(thd, table_list, ref)))
|
||||
{
|
||||
*def= Column_definition(thd, src, NULL/*No defaults,no constraints*/);
|
||||
def->flags&= (uint) ~NOT_NULL_FLAG;
|
||||
rc= def->sp_prepare_create_field(thd, thd->mem_root);
|
||||
}
|
||||
}
|
||||
else
|
||||
my_error(ER_BAD_FIELD_ERROR, MYF(0), ref->m_column.str, ref->table.str);
|
||||
}
|
||||
|
||||
lex.unit.cleanup();
|
||||
thd->temporary_tables= NULL; // Avoid closing temporary tables
|
||||
close_thread_tables(thd);
|
||||
thd->lex= save_lex;
|
||||
thd->restore_backup_open_tables_state(&open_tables_state_backup);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
bool sp_rcontext::resolve_type_refs(THD *thd, List<Spvar_definition> &defs)
|
||||
{
|
||||
List_iterator<Spvar_definition> it(defs);
|
||||
Spvar_definition *def;
|
||||
while ((def= it++))
|
||||
{
|
||||
if (def->is_column_type_ref() &&
|
||||
resolve_type_ref(thd, def, def->column_type_ref()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
|
||||
bool sp_rcontext::init_var_items(THD *thd,
|
||||
List<Spvar_definition> &field_def_lst)
|
||||
{
|
||||
uint num_vars= m_root_parsing_ctx->max_var_index();
|
||||
|
||||
@@ -360,8 +447,9 @@ uint sp_rcontext::exit_handler(Diagnostics_area *da)
|
||||
}
|
||||
|
||||
|
||||
int sp_rcontext::set_variable(THD *thd, Field *field, Item **value)
|
||||
int sp_rcontext::set_variable(THD *thd, uint idx, Item **value)
|
||||
{
|
||||
Field *field= m_var_table->field[idx];
|
||||
if (!value)
|
||||
{
|
||||
field->set_null();
|
||||
|
@@ -70,7 +70,8 @@ public:
|
||||
/// @return valid sp_rcontext object or NULL in case of OOM-error.
|
||||
static sp_rcontext *create(THD *thd,
|
||||
const sp_pcontext *root_parsing_ctx,
|
||||
Field *return_value_fld);
|
||||
Field *return_value_fld,
|
||||
bool resolve_type_refs);
|
||||
|
||||
~sp_rcontext();
|
||||
|
||||
@@ -185,8 +186,7 @@ public:
|
||||
// SP-variables.
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int set_variable(THD *thd, uint var_idx, Item **value)
|
||||
{ return set_variable(thd, m_var_table->field[var_idx], value); }
|
||||
int set_variable(THD *thd, uint var_idx, Item **value);
|
||||
|
||||
Item *get_item(uint var_idx) const
|
||||
{ return m_var_items[var_idx]; }
|
||||
@@ -334,7 +334,11 @@ private:
|
||||
/// @return error flag.
|
||||
/// @retval false on success.
|
||||
/// @retval true on error.
|
||||
bool init_var_table(THD *thd);
|
||||
bool init_var_table(THD *thd, List<Spvar_definition> &defs);
|
||||
|
||||
bool resolve_type_refs(THD *, List<Spvar_definition> &defs);
|
||||
bool resolve_type_ref(THD *thd, Column_definition *def,
|
||||
Qualified_column_ident *ref);
|
||||
|
||||
/// Create and initialize an Item-adapter (Item_field) for each SP-var field.
|
||||
///
|
||||
@@ -343,7 +347,7 @@ private:
|
||||
/// @return error flag.
|
||||
/// @retval false on success.
|
||||
/// @retval true on error.
|
||||
bool init_var_items(THD *thd);
|
||||
bool init_var_items(THD *thd, List<Spvar_definition> &defs);
|
||||
|
||||
/// Create an instance of appropriate Item_cache class depending on the
|
||||
/// specified type in the callers arena.
|
||||
@@ -357,8 +361,6 @@ private:
|
||||
/// @return Pointer to valid object on success, or NULL in case of error.
|
||||
Item_cache *create_case_expr_holder(THD *thd, const Item *item) const;
|
||||
|
||||
int set_variable(THD *thd, Field *field, Item **value);
|
||||
|
||||
private:
|
||||
/// Top-level (root) parsing context for this runtime context.
|
||||
const sp_pcontext *m_root_parsing_ctx;
|
||||
|
@@ -4763,6 +4763,51 @@ end:
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Open a table to read its structure, e.g. for:
|
||||
- SHOW FIELDS
|
||||
- delayed SP variable data type definition: DECLARE a t1.a%TYPE
|
||||
|
||||
The flag MYSQL_OPEN_GET_NEW_TABLE is passed to make %TYPE work
|
||||
in stored functions, as during a stored function call
|
||||
(e.g. in a SELECT query) the tables referenced in %TYPE can already be locked,
|
||||
and attempt to open it again would return an error in open_table().
|
||||
|
||||
The flag MYSQL_OPEN_GET_NEW_TABLE is not really needed for
|
||||
SHOW FIELDS or for a "CALL sp()" statement, but it's not harmful,
|
||||
so let's pass it unconditionally.
|
||||
*/
|
||||
|
||||
bool open_tables_only_view_structure(THD *thd, TABLE_LIST *table_list,
|
||||
bool can_deadlock)
|
||||
{
|
||||
DBUG_ENTER("open_tables_only_view_structure");
|
||||
/*
|
||||
Let us set fake sql_command so views won't try to merge
|
||||
themselves into main statement. If we don't do this,
|
||||
SELECT * from information_schema.xxxx will cause problems.
|
||||
SQLCOM_SHOW_FIELDS is used because it satisfies
|
||||
'LEX::only_view_structure()'.
|
||||
*/
|
||||
enum_sql_command save_sql_command= thd->lex->sql_command;
|
||||
thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||||
bool rc= (thd->open_temporary_tables(table_list) ||
|
||||
open_normal_and_derived_tables(thd, table_list,
|
||||
(MYSQL_OPEN_IGNORE_FLUSH |
|
||||
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
|
||||
MYSQL_OPEN_GET_NEW_TABLE |
|
||||
(can_deadlock ?
|
||||
MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)),
|
||||
DT_PREPARE | DT_CREATE));
|
||||
/*
|
||||
Restore old value of sql_command back as it is being looked at in
|
||||
process_table() function.
|
||||
*/
|
||||
thd->lex->sql_command= save_sql_command;
|
||||
DBUG_RETURN(rc);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Mark all real tables in the list as free for reuse.
|
||||
|
||||
|
@@ -254,6 +254,8 @@ TABLE *open_n_lock_single_table(THD *thd, TABLE_LIST *table_l,
|
||||
Prelocking_strategy *prelocking_strategy);
|
||||
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags,
|
||||
uint dt_phases);
|
||||
bool open_tables_only_view_structure(THD *thd, TABLE_LIST *tables,
|
||||
bool can_deadlock);
|
||||
bool lock_tables(THD *thd, TABLE_LIST *tables, uint counter, uint flags);
|
||||
int decide_logging_format(THD *thd, TABLE_LIST *tables);
|
||||
void close_thread_table(THD *thd, TABLE **table_ptr);
|
||||
|
@@ -5370,6 +5370,26 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class Qualified_column_ident: public Table_ident
|
||||
{
|
||||
public:
|
||||
LEX_STRING m_column;
|
||||
public:
|
||||
Qualified_column_ident(const LEX_STRING table, const LEX_STRING column)
|
||||
:Table_ident(table),
|
||||
m_column(column)
|
||||
{ }
|
||||
Qualified_column_ident(THD *thd,
|
||||
const LEX_STRING db,
|
||||
const LEX_STRING table,
|
||||
const LEX_STRING column)
|
||||
:Table_ident(thd, db, table, false),
|
||||
m_column(column)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
// this is needed for user_vars hash
|
||||
class user_var_entry
|
||||
{
|
||||
|
@@ -5098,11 +5098,7 @@ sp_variable *LEX::sp_param_init(LEX_STRING name)
|
||||
|
||||
bool LEX::sp_param_fill_definition(sp_variable *spvar)
|
||||
{
|
||||
if (sphead->fill_field_definition(thd, last_field))
|
||||
return true;
|
||||
spvar->field_def.field_name= spvar->name.str;
|
||||
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
|
||||
return false;
|
||||
return sphead->fill_spvar_definition(thd, last_field, spvar->name.str);
|
||||
}
|
||||
|
||||
|
||||
@@ -5222,7 +5218,7 @@ void LEX::sp_variable_declarations_init(THD *thd, int nvars)
|
||||
}
|
||||
|
||||
bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
|
||||
const Column_definition &cdef,
|
||||
const Column_definition *cdef,
|
||||
Item *dflt_value_item)
|
||||
{
|
||||
uint num_vars= spcont->context_var_count();
|
||||
@@ -5241,16 +5237,15 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
|
||||
if (!spvar)
|
||||
return true;
|
||||
|
||||
if (!last)
|
||||
spvar->field_def= cdef;
|
||||
|
||||
spvar->default_value= dflt_value_item;
|
||||
spvar->field_def.field_name= spvar->name.str;
|
||||
|
||||
if (sphead->fill_field_definition(thd, &spvar->field_def))
|
||||
return true;
|
||||
|
||||
spvar->field_def.pack_flag |= FIELDFLAG_MAYBE_NULL;
|
||||
if (cdef)
|
||||
{
|
||||
if (!last)
|
||||
spvar->field_def.set_column_definition(cdef);
|
||||
if (sphead->fill_spvar_definition(thd, &spvar->field_def, spvar->name.str))
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The last instruction is responsible for freeing LEX. */
|
||||
sp_instr_set *is= new (this->thd->mem_root)
|
||||
@@ -5266,6 +5261,23 @@ bool LEX::sp_variable_declarations_finalize(THD *thd, int nvars,
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LEX::sp_variable_declarations_with_ref_finalize(THD *thd, int nvars,
|
||||
Qualified_column_ident *ref,
|
||||
Item *def)
|
||||
{
|
||||
uint num_vars= spcont->context_var_count();
|
||||
for (uint i= num_vars - nvars; i < num_vars; i++)
|
||||
{
|
||||
sp_variable *spvar= spcont->find_context_variable(i);
|
||||
spvar->field_def.set_column_type_ref(ref);
|
||||
spvar->field_def.field_name= spvar->name.str;
|
||||
}
|
||||
sphead->m_flags|= sp_head::HAS_COLUMN_TYPE_REFS;
|
||||
return sp_variable_declarations_finalize(thd, nvars, NULL, def);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
The FOR LOOP statement
|
||||
|
||||
@@ -5295,8 +5307,9 @@ sp_variable *LEX::sp_add_for_loop_variable(THD *thd, const LEX_STRING name,
|
||||
{
|
||||
sp_variable *spvar= spcont->add_variable(thd, name);
|
||||
spcont->declare_var_boundary(1);
|
||||
spvar->field_def= Column_definition(spvar->name.str, MYSQL_TYPE_LONGLONG);
|
||||
if (sp_variable_declarations_finalize(thd, 1, spvar->field_def, value))
|
||||
spvar->field_def.field_name= spvar->name.str;
|
||||
spvar->field_def.sql_type= MYSQL_TYPE_LONGLONG;
|
||||
if (sp_variable_declarations_finalize(thd, 1, NULL, value))
|
||||
return NULL;
|
||||
return spvar;
|
||||
}
|
||||
@@ -6016,10 +6029,14 @@ Item *LEX::create_item_ident_sp(THD *thd, LEX_STRING name,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Item_splocal *splocal;
|
||||
splocal= new (thd->mem_root) Item_splocal(thd, name,
|
||||
spv->offset, spv->sql_type(),
|
||||
start_in_q, length_in_q);
|
||||
Item_splocal *splocal= spv->field_def.is_column_type_ref() ?
|
||||
new (thd->mem_root) Item_splocal_with_delayed_data_type(thd, name,
|
||||
spv->offset,
|
||||
start_in_q,
|
||||
length_in_q) :
|
||||
new (thd->mem_root) Item_splocal(thd, name,
|
||||
spv->offset, spv->sql_type(),
|
||||
start_in_q, length_in_q);
|
||||
if (splocal == NULL)
|
||||
return NULL;
|
||||
#ifndef DBUG_OFF
|
||||
|
@@ -3110,8 +3110,11 @@ public:
|
||||
bool set_variable(struct sys_var_with_base *variable, Item *item);
|
||||
void sp_variable_declarations_init(THD *thd, int nvars);
|
||||
bool sp_variable_declarations_finalize(THD *thd, int nvars,
|
||||
const Column_definition &cdef,
|
||||
const Column_definition *cdef,
|
||||
Item *def);
|
||||
bool sp_variable_declarations_with_ref_finalize(THD *thd, int nvars,
|
||||
Qualified_column_ident *col,
|
||||
Item *def);
|
||||
bool sp_handler_declaration_init(THD *thd, int type);
|
||||
bool sp_handler_declaration_finalize(THD *thd, int type);
|
||||
|
||||
|
@@ -17086,11 +17086,11 @@ bool Virtual_tmp_table::init(uint field_count)
|
||||
};
|
||||
|
||||
|
||||
bool Virtual_tmp_table::add(List<Column_definition> &field_list)
|
||||
bool Virtual_tmp_table::add(List<Spvar_definition> &field_list)
|
||||
{
|
||||
/* Create all fields and calculate the total length of record */
|
||||
Column_definition *cdef; /* column definition */
|
||||
List_iterator_fast<Column_definition> it(field_list);
|
||||
Spvar_definition *cdef; /* column definition */
|
||||
List_iterator_fast<Spvar_definition> it(field_list);
|
||||
for ( ; (cdef= it++); )
|
||||
{
|
||||
Field *tmp;
|
||||
|
@@ -2032,6 +2032,8 @@ public:
|
||||
bzero(this, sizeof(*this));
|
||||
temp_pool_slot= MY_BIT_NONE;
|
||||
in_use= thd;
|
||||
copy_blobs= true;
|
||||
alias.set("", 0, &my_charset_bin);
|
||||
}
|
||||
|
||||
~Virtual_tmp_table()
|
||||
@@ -2075,11 +2077,11 @@ public:
|
||||
}
|
||||
|
||||
/**
|
||||
Add fields from a Column_definition list
|
||||
Add fields from a Spvar_definition list
|
||||
@returns false - on success.
|
||||
@returns true - on error.
|
||||
*/
|
||||
bool add(List<Column_definition> &field_list);
|
||||
bool add(List<Spvar_definition> &field_list);
|
||||
|
||||
/**
|
||||
Open a virtual table for read/write:
|
||||
@@ -2117,7 +2119,7 @@ public:
|
||||
*/
|
||||
|
||||
inline TABLE *
|
||||
create_virtual_tmp_table(THD *thd, List<Column_definition> &field_list)
|
||||
create_virtual_tmp_table(THD *thd, List<Spvar_definition> &field_list)
|
||||
{
|
||||
Virtual_tmp_table *table;
|
||||
if (!(table= new(thd) Virtual_tmp_table(thd)))
|
||||
|
@@ -4207,6 +4207,7 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
|
||||
/* Prepare temporary LEX. */
|
||||
thd->lex= lex= &temp_lex;
|
||||
lex_start(thd);
|
||||
lex->sql_command= old_lex->sql_command;
|
||||
|
||||
/* Disable constant subquery evaluation as we won't be locking tables. */
|
||||
lex->context_analysis_only= CONTEXT_ANALYSIS_ONLY_VIEW;
|
||||
@@ -4259,26 +4260,8 @@ fill_schema_table_by_open(THD *thd, bool is_show_fields_or_keys,
|
||||
table_list->i_s_requested_object= schema_table->i_s_requested_object;
|
||||
}
|
||||
|
||||
/*
|
||||
Let us set fake sql_command so views won't try to merge
|
||||
themselves into main statement. If we don't do this,
|
||||
SELECT * from information_schema.xxxx will cause problems.
|
||||
SQLCOM_SHOW_FIELDS is used because it satisfies
|
||||
'only_view_structure()'.
|
||||
*/
|
||||
lex->sql_command= SQLCOM_SHOW_FIELDS;
|
||||
result= (thd->open_temporary_tables(table_list) ||
|
||||
open_normal_and_derived_tables(thd, table_list,
|
||||
(MYSQL_OPEN_IGNORE_FLUSH |
|
||||
MYSQL_OPEN_FORCE_SHARED_HIGH_PRIO_MDL |
|
||||
(can_deadlock ?
|
||||
MYSQL_OPEN_FAIL_ON_MDL_CONFLICT : 0)),
|
||||
DT_PREPARE | DT_CREATE));
|
||||
/*
|
||||
Restore old value of sql_command back as it is being looked at in
|
||||
process_table() function.
|
||||
*/
|
||||
lex->sql_command= old_lex->sql_command;
|
||||
DBUG_ASSERT(thd->lex == lex);
|
||||
result= open_tables_only_view_structure(thd, table_list, can_deadlock);
|
||||
|
||||
DEBUG_SYNC(thd, "after_open_table_ignore_flush");
|
||||
|
||||
|
@@ -2940,7 +2940,7 @@ sp_decl_body:
|
||||
sp_opt_default
|
||||
{
|
||||
if (Lex->sp_variable_declarations_finalize(thd, $1,
|
||||
Lex->last_field[0], $4))
|
||||
&Lex->last_field[0], $4))
|
||||
MYSQL_YYABORT;
|
||||
$$.vars= $1;
|
||||
$$.conds= $$.hndlrs= $$.curs= 0;
|
||||
|
@@ -209,6 +209,7 @@ void ORAerror(THD *thd, const char *s)
|
||||
String *string;
|
||||
TABLE_LIST *table_list;
|
||||
Table_ident *table;
|
||||
Qualified_column_ident *qualified_column_ident;
|
||||
char *simple_string;
|
||||
const char *const_simple_string;
|
||||
chooser_compare_func_creator boolfunc2creator;
|
||||
@@ -1002,6 +1003,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
sp_opt_label BIN_NUM label_ident TEXT_STRING_filesystem ident_or_empty
|
||||
opt_constraint constraint opt_ident
|
||||
label_declaration_oracle ident_directly_assignable
|
||||
sp_decl_ident
|
||||
sp_block_label
|
||||
|
||||
%type <lex_string_with_metadata>
|
||||
@@ -1015,6 +1017,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
table_ident table_ident_nodb references xid
|
||||
table_ident_opt_wild create_like
|
||||
|
||||
%type <qualified_column_ident>
|
||||
qualified_column_ident
|
||||
|
||||
%type <simple_string>
|
||||
remember_name remember_end opt_db remember_tok_start
|
||||
wild_and_where
|
||||
@@ -1184,6 +1189,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%type <symbol> keyword keyword_sp
|
||||
keyword_directly_assignable
|
||||
keyword_directly_not_assignable
|
||||
sp_decl_ident_keyword
|
||||
keyword_sp_data_type
|
||||
keyword_sp_not_data_type
|
||||
|
||||
%type <lex_user> user grant_user grant_role user_or_role current_role
|
||||
admin_option_for_role user_maybe_role
|
||||
@@ -2307,6 +2315,10 @@ sp_param_name_and_type:
|
||||
if (Lex->sp_param_fill_definition($$= $1))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| sp_param_name qualified_column_ident '%' TYPE_SYM
|
||||
{
|
||||
Lex->sphead->fill_spvar_using_type_reference($$= $1, $2);
|
||||
}
|
||||
;
|
||||
|
||||
/* Stored PROCEDURE parameter declaration list */
|
||||
@@ -2327,6 +2339,10 @@ sp_pdparam:
|
||||
if (Lex->sp_param_fill_definition($1))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| sp_param_name sp_opt_inout qualified_column_ident '%' TYPE_SYM
|
||||
{
|
||||
Lex->sphead->fill_spvar_using_type_reference($1, $3);
|
||||
}
|
||||
;
|
||||
|
||||
sp_opt_inout:
|
||||
@@ -2406,6 +2422,20 @@ sp_decl_body_list:
|
||||
}
|
||||
;
|
||||
|
||||
qualified_column_ident:
|
||||
sp_decl_ident '.' ident
|
||||
{
|
||||
if (!($$= new (thd->mem_root) Qualified_column_ident($1, $3)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| sp_decl_ident '.' ident '.' ident
|
||||
{
|
||||
if (!($$= new (thd->mem_root) Qualified_column_ident(thd,
|
||||
$1, $3, $5)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
sp_decl_body:
|
||||
sp_decl_idents
|
||||
{
|
||||
@@ -2415,10 +2445,20 @@ sp_decl_body:
|
||||
sp_opt_default
|
||||
{
|
||||
if (Lex->sp_variable_declarations_finalize(thd, $1,
|
||||
Lex->last_field[0], $4))
|
||||
&Lex->last_field[0], $4))
|
||||
MYSQL_YYABORT;
|
||||
$$.vars= $1;
|
||||
$$.conds= $$.hndlrs= $$.curs= 0;
|
||||
$$.init_using_vars($1);
|
||||
}
|
||||
| sp_decl_idents
|
||||
{
|
||||
Lex->sp_variable_declarations_init(thd, $1);
|
||||
}
|
||||
qualified_column_ident '%' TYPE_SYM
|
||||
sp_opt_default
|
||||
{
|
||||
if (Lex->sp_variable_declarations_with_ref_finalize(thd, $1, $3, $6))
|
||||
MYSQL_YYABORT;
|
||||
$$.init_using_vars($1);
|
||||
}
|
||||
| ident_directly_assignable CONDITION_SYM FOR_SYM sp_cond
|
||||
{
|
||||
@@ -2875,8 +2915,25 @@ condition_information_item_name:
|
||||
{ $$= Condition_information_item::RETURNED_SQLSTATE; }
|
||||
;
|
||||
|
||||
sp_decl_ident:
|
||||
IDENT_sys
|
||||
| sp_decl_ident_keyword
|
||||
{
|
||||
$$.str= thd->strmake($1.str, $1.length);
|
||||
if ($$.str == NULL)
|
||||
MYSQL_YYABORT;
|
||||
$$.length= $1.length;
|
||||
}
|
||||
;
|
||||
|
||||
sp_decl_ident_keyword:
|
||||
keyword_directly_assignable
|
||||
| keyword_sp_not_data_type
|
||||
;
|
||||
|
||||
|
||||
sp_decl_idents:
|
||||
ident_directly_assignable
|
||||
sp_decl_ident
|
||||
{
|
||||
/* NOTE: field definition is filled in sp_decl section. */
|
||||
|
||||
@@ -14276,6 +14333,48 @@ keyword_directly_not_assignable:
|
||||
* conflicts.
|
||||
*/
|
||||
keyword_sp:
|
||||
keyword_sp_data_type
|
||||
| keyword_sp_not_data_type
|
||||
;
|
||||
|
||||
|
||||
/*
|
||||
These keywords are generally allowed as identifiers,
|
||||
but not allowed as non-delimited SP variable names.
|
||||
*/
|
||||
keyword_sp_data_type:
|
||||
BIT_SYM {}
|
||||
| BOOLEAN_SYM {} /* PLSQL-R */
|
||||
| BOOL_SYM {}
|
||||
| CLOB {}
|
||||
| DATE_SYM {} /* Oracle-R, PLSQL-R */
|
||||
| DATETIME {}
|
||||
| ENUM {}
|
||||
| FIXED_SYM {}
|
||||
| GEOMETRYCOLLECTION {}
|
||||
| GEOMETRY_SYM {}
|
||||
| LINESTRING {}
|
||||
| MEDIUM_SYM {}
|
||||
| MULTILINESTRING {}
|
||||
| MULTIPOINT {}
|
||||
| MULTIPOLYGON {}
|
||||
| NATIONAL_SYM {}
|
||||
| NCHAR_SYM {}
|
||||
| NUMBER_SYM {} /* Oracle-R, PLSQL-R */
|
||||
| NVARCHAR_SYM {}
|
||||
| POINT_SYM {}
|
||||
| POLYGON {}
|
||||
| RAW {} /* Oracle-R */
|
||||
| SERIAL_SYM {}
|
||||
| TEXT_SYM {}
|
||||
| TIMESTAMP {}
|
||||
| TIME_SYM {} /* Oracle-R */
|
||||
| VARCHAR2 {} /* Oracle-R, PLSQL-R */
|
||||
| YEAR_SYM {}
|
||||
;
|
||||
|
||||
|
||||
keyword_sp_not_data_type:
|
||||
ACTION {}
|
||||
| ADDDATE_SYM {}
|
||||
| ADMIN_SYM {}
|
||||
@@ -14293,10 +14392,7 @@ keyword_sp:
|
||||
| AUTO_SYM {}
|
||||
| AVG_ROW_LENGTH {}
|
||||
| AVG_SYM {}
|
||||
| BIT_SYM {}
|
||||
| BLOCK_SYM {}
|
||||
| BOOL_SYM {}
|
||||
| BOOLEAN_SYM {}
|
||||
| BTREE_SYM {}
|
||||
| CASCADED {}
|
||||
| CATALOG_NAME_SYM {}
|
||||
@@ -14305,7 +14401,6 @@ keyword_sp:
|
||||
| CIPHER_SYM {}
|
||||
| CLIENT_SYM {}
|
||||
| CLASS_ORIGIN_SYM {}
|
||||
| CLOB {}
|
||||
| COALESCE {}
|
||||
| CODE_SYM {}
|
||||
| COLLATION_SYM {}
|
||||
@@ -14334,8 +14429,6 @@ keyword_sp:
|
||||
| CURSOR_NAME_SYM {}
|
||||
| DATA_SYM {}
|
||||
| DATAFILE_SYM {}
|
||||
| DATETIME {}
|
||||
| DATE_SYM {}
|
||||
| DAY_SYM {}
|
||||
| DECODE_SYM {}
|
||||
| DEFINER_SYM {}
|
||||
@@ -14350,7 +14443,6 @@ keyword_sp:
|
||||
| DUPLICATE_SYM {}
|
||||
| DYNAMIC_SYM {}
|
||||
| ENDS_SYM {}
|
||||
| ENUM {}
|
||||
| ENGINE_SYM {}
|
||||
| ENGINES_SYM {}
|
||||
| ERROR_SYM {}
|
||||
@@ -14371,11 +14463,8 @@ keyword_sp:
|
||||
| FULL {}
|
||||
| FILE_SYM {}
|
||||
| FIRST_SYM {}
|
||||
| FIXED_SYM {}
|
||||
| GENERAL {}
|
||||
| GENERATED_SYM {}
|
||||
| GEOMETRY_SYM {}
|
||||
| GEOMETRYCOLLECTION {}
|
||||
| GET_FORMAT {}
|
||||
| GRANTS {}
|
||||
| GLOBAL_SYM {}
|
||||
@@ -14404,7 +14493,6 @@ keyword_sp:
|
||||
| LEAVES {}
|
||||
| LESS_SYM {}
|
||||
| LEVEL_SYM {}
|
||||
| LINESTRING {}
|
||||
| LIST_SYM {}
|
||||
| LOCAL_SYM {}
|
||||
| LOCKS_SYM {}
|
||||
@@ -14438,7 +14526,6 @@ keyword_sp:
|
||||
| MAX_STATEMENT_TIME_SYM {}
|
||||
| MAX_UPDATES_PER_HOUR {}
|
||||
| MAX_USER_CONNECTIONS_SYM {}
|
||||
| MEDIUM_SYM {}
|
||||
| MEMORY_SYM {}
|
||||
| MERGE_SYM {}
|
||||
| MESSAGE_TEXT_SYM {}
|
||||
@@ -14449,24 +14536,17 @@ keyword_sp:
|
||||
| MODIFY_SYM {}
|
||||
| MODE_SYM {}
|
||||
| MONTH_SYM {}
|
||||
| MULTILINESTRING {}
|
||||
| MULTIPOINT {}
|
||||
| MULTIPOLYGON {}
|
||||
| MUTEX_SYM {}
|
||||
| MYSQL_SYM {}
|
||||
| MYSQL_ERRNO_SYM {}
|
||||
| NAME_SYM {}
|
||||
| NAMES_SYM {}
|
||||
| NATIONAL_SYM {}
|
||||
| NCHAR_SYM {}
|
||||
| NEXT_SYM {}
|
||||
| NEW_SYM {}
|
||||
| NO_WAIT_SYM {}
|
||||
| NODEGROUP_SYM {}
|
||||
| NONE_SYM {}
|
||||
| NOTFOUND_SYM {}
|
||||
| NUMBER_SYM {}
|
||||
| NVARCHAR_SYM {}
|
||||
| OFFSET_SYM {}
|
||||
| OLD_PASSWORD_SYM {}
|
||||
| ONE_SYM {}
|
||||
@@ -14482,8 +14562,6 @@ keyword_sp:
|
||||
| PHASE_SYM {}
|
||||
| PLUGIN_SYM {}
|
||||
| PLUGINS_SYM {}
|
||||
| POINT_SYM {}
|
||||
| POLYGON {}
|
||||
| PRESERVE_SYM {}
|
||||
| PREV_SYM {}
|
||||
| PRIVILEGES {}
|
||||
@@ -14495,7 +14573,6 @@ keyword_sp:
|
||||
| QUARTER_SYM {}
|
||||
| QUERY_SYM {}
|
||||
| QUICK {}
|
||||
| RAW {}
|
||||
| READ_ONLY_SYM {}
|
||||
| REBUILD_SYM {}
|
||||
| RECOVER_SYM {}
|
||||
@@ -14528,7 +14605,6 @@ keyword_sp:
|
||||
| SCHEDULE_SYM {}
|
||||
| SCHEMA_NAME_SYM {}
|
||||
| SECOND_SYM {}
|
||||
| SERIAL_SYM {}
|
||||
| SERIALIZABLE_SYM {}
|
||||
| SESSION_SYM {}
|
||||
| SIMPLE_SYM {}
|
||||
@@ -14563,15 +14639,12 @@ keyword_sp:
|
||||
| TABLESPACE {}
|
||||
| TEMPORARY {}
|
||||
| TEMPTABLE_SYM {}
|
||||
| TEXT_SYM {}
|
||||
| THAN_SYM {}
|
||||
| TRANSACTION_SYM {}
|
||||
| TRANSACTIONAL_SYM {}
|
||||
| TRIGGERS_SYM {}
|
||||
| TIMESTAMP {}
|
||||
| TIMESTAMP_ADD {}
|
||||
| TIMESTAMP_DIFF {}
|
||||
| TIME_SYM {}
|
||||
| TYPES_SYM {}
|
||||
| TYPE_SYM {}
|
||||
| UDF_RETURNS_SYM {}
|
||||
@@ -14584,7 +14657,6 @@ keyword_sp:
|
||||
| UNTIL_SYM {}
|
||||
| USER_SYM {}
|
||||
| USE_FRM {}
|
||||
| VARCHAR2 {}
|
||||
| VARIABLES {}
|
||||
| VIEW_SYM {}
|
||||
| VIRTUAL_SYM {}
|
||||
@@ -14596,7 +14668,6 @@ keyword_sp:
|
||||
| WORK_SYM {}
|
||||
| X509_SYM {}
|
||||
| XML_SYM {}
|
||||
| YEAR_SYM {}
|
||||
| VIA_SYM {}
|
||||
;
|
||||
|
||||
|
@@ -647,6 +647,11 @@ public:
|
||||
{
|
||||
vars= conds= hndlrs= curs= 0;
|
||||
}
|
||||
void init_using_vars(uint nvars)
|
||||
{
|
||||
vars= nvars;
|
||||
conds= hndlrs= curs= 0;
|
||||
}
|
||||
void join(const Lex_spblock_st &b1, const Lex_spblock_st &b2)
|
||||
{
|
||||
vars= b1.vars + b2.vars;
|
||||
|
11
sql/table.cc
11
sql/table.cc
@@ -8202,3 +8202,14 @@ LEX_CSTRING *fk_option_name(enum_fk_option opt)
|
||||
};
|
||||
return names + opt;
|
||||
}
|
||||
|
||||
|
||||
Field *TABLE::find_field_by_name(const char *str) const
|
||||
{
|
||||
for (Field **tmp= field; *tmp; tmp++)
|
||||
{
|
||||
if (!my_strcasecmp(system_charset_info, (*tmp)->field_name, str))
|
||||
return *tmp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@@ -1440,6 +1440,7 @@ public:
|
||||
TABLE *tmp_table,
|
||||
TMP_TABLE_PARAM *tmp_table_param,
|
||||
bool with_cleanup);
|
||||
Field *find_field_by_name(const char *str) const;
|
||||
};
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user