MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND
This commit is contained in:
parent
4bb87996b9
commit
76714a5c9a
@ -350,3 +350,7 @@ CREATE TABLE decode (decode int);
|
||||
DROP TABLE decode;
|
||||
CREATE TABLE rowcount (rowcount int);
|
||||
DROP TABLE rowcount;
|
||||
CREATE TABLE isopen (isopen int);
|
||||
DROP TABLE isopen;
|
||||
CREATE TABLE notfound (notfound int);
|
||||
DROP TABLE notfound;
|
||||
|
291
mysql-test/suite/compat/oracle/r/sp-cursor.result
Normal file
291
mysql-test/suite/compat/oracle/r/sp-cursor.result
Normal file
@ -0,0 +1,291 @@
|
||||
SET sql_mode=ORACLE;
|
||||
#
|
||||
# MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND
|
||||
#
|
||||
#
|
||||
# Cursor attributes outside of an SP context
|
||||
#
|
||||
SELECT c%ISOPEN;
|
||||
ERROR 42000: Undefined CURSOR: c
|
||||
SELECT c%FOUND;
|
||||
ERROR 42000: Undefined CURSOR: c
|
||||
SELECT c%NOTFOUND;
|
||||
ERROR 42000: Undefined CURSOR: c
|
||||
SELECT c%ROWCOUNT;
|
||||
ERROR 42000: Undefined CURSOR: c
|
||||
#
|
||||
# Undefinite cursor attributes
|
||||
#
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
SELECT c%ISOPEN;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: Undefined CURSOR: c
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
SELECT c%ROWCOUNT;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: Undefined CURSOR: c
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
SELECT c%FOUND;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: Undefined CURSOR: c
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
SELECT c%NOTFOUND;
|
||||
END;
|
||||
$$
|
||||
ERROR 42000: Undefined CURSOR: c
|
||||
#
|
||||
# Not opened cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT
|
||||
#
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%ROWCOUNT;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR 24000: Cursor is not open
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%FOUND;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR 24000: Cursor is not open
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%NOTFOUND;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
ERROR 24000: Cursor is not open
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# Not opened cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT with INVALID_CURSOR exception
|
||||
#
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%ROWCOUNT;
|
||||
EXCEPTION
|
||||
WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c%ROWCOUNT
|
||||
msg
|
||||
INVALID_CURSOR caught
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%FOUND;
|
||||
EXCEPTION
|
||||
WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c%FOUND
|
||||
msg
|
||||
INVALID_CURSOR caught
|
||||
DROP PROCEDURE p1;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%NOTFOUND;
|
||||
EXCEPTION
|
||||
WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
|
||||
END;
|
||||
$$
|
||||
CALL p1;
|
||||
c%NOTFOUND
|
||||
msg
|
||||
INVALID_CURSOR caught
|
||||
DROP PROCEDURE p1;
|
||||
#
|
||||
# print()
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
EXPLAIN EXTENDED SELECT c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||
Warnings:
|
||||
Note 1003 select "c"%ISOPEN AS "c%ISOPEN","c"%ROWCOUNT AS "c%ROWCOUNT","c"%FOUND AS "c%FOUND","c"%NOTFOUND AS "c%NOTFOUND"
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Declared data type of the attributes
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
OPEN c;
|
||||
CREATE TABLE t2 AS SELECT c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
Table Create Table
|
||||
t2 CREATE TABLE "t2" (
|
||||
"c%ISOPEN" int(1) NOT NULL,
|
||||
"c%ROWCOUNT" bigint(21) NOT NULL,
|
||||
"c%FOUND" int(1) DEFAULT NULL,
|
||||
"c%NOTFOUND" int(1) DEFAULT NULL
|
||||
)
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# Core functionality
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
INSERT INTO t1 VALUES (20);
|
||||
INSERT INTO t1 VALUES (30);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a INT:=0;
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
SELECT a, c%ISOPEN;
|
||||
OPEN c;
|
||||
/*
|
||||
After OPEN and before FETCH:
|
||||
- %ROWCOUNT returns 0
|
||||
- %FOUND and %NOTFOUND return NULL
|
||||
*/
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
CLOSE c;
|
||||
SELECT a, c%ISOPEN;
|
||||
/*
|
||||
After reopen and before FETCH:
|
||||
- %ROWCOUNT returns 0
|
||||
- %FOUND and %NOTFOUND return NULL
|
||||
*/
|
||||
OPEN c;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
a c%ISOPEN
|
||||
0 0
|
||||
a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
|
||||
0 1 0 NULL NULL
|
||||
a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
|
||||
10 1 1 1 0
|
||||
a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
|
||||
20 1 2 1 0
|
||||
a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
|
||||
30 1 3 1 0
|
||||
a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
|
||||
30 1 3 0 1
|
||||
a c%ISOPEN
|
||||
30 0
|
||||
a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
|
||||
30 1 0 NULL NULL
|
||||
a c%ISOPEN c%ROWCOUNT c%FOUND c%NOTFOUND
|
||||
10 1 1 1 0
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# %NOTFOUND as a loop exit condition
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
INSERT INTO t1 VALUES (20);
|
||||
INSERT INTO t1 VALUES (30);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a INT:=0;
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
OPEN c;
|
||||
LOOP
|
||||
FETCH c INTO a;
|
||||
EXIT WHEN c%NOTFOUND;
|
||||
SELECT a;
|
||||
END LOOP;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
a
|
||||
10
|
||||
a
|
||||
20
|
||||
a
|
||||
30
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# %FOUND as a loop exit condition
|
||||
#
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
INSERT INTO t1 VALUES (20);
|
||||
INSERT INTO t1 VALUES (30);
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a INT:=0;
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
OPEN c;
|
||||
LOOP
|
||||
FETCH c INTO a;
|
||||
EXIT WHEN NOT c%FOUND;
|
||||
SELECT a;
|
||||
END LOOP;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
CALL p1();
|
||||
a
|
||||
10
|
||||
a
|
||||
20
|
||||
a
|
||||
30
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
296
mysql-test/suite/compat/oracle/t/sp-cursor.test
Normal file
296
mysql-test/suite/compat/oracle/t/sp-cursor.test
Normal file
@ -0,0 +1,296 @@
|
||||
SET sql_mode=ORACLE;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND
|
||||
--echo #
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Cursor attributes outside of an SP context
|
||||
--echo #
|
||||
|
||||
--error ER_SP_CURSOR_MISMATCH
|
||||
SELECT c%ISOPEN;
|
||||
--error ER_SP_CURSOR_MISMATCH
|
||||
SELECT c%FOUND;
|
||||
--error ER_SP_CURSOR_MISMATCH
|
||||
SELECT c%NOTFOUND;
|
||||
--error ER_SP_CURSOR_MISMATCH
|
||||
SELECT c%ROWCOUNT;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Undefinite cursor attributes
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
--error ER_SP_CURSOR_MISMATCH
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
SELECT c%ISOPEN;
|
||||
END;
|
||||
$$
|
||||
--error ER_SP_CURSOR_MISMATCH
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
SELECT c%ROWCOUNT;
|
||||
END;
|
||||
$$
|
||||
--error ER_SP_CURSOR_MISMATCH
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
SELECT c%FOUND;
|
||||
END;
|
||||
$$
|
||||
--error ER_SP_CURSOR_MISMATCH
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
BEGIN
|
||||
SELECT c%NOTFOUND;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Not opened cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%ROWCOUNT;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_SP_CURSOR_NOT_OPEN
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%FOUND;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_SP_CURSOR_NOT_OPEN
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%NOTFOUND;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
--error ER_SP_CURSOR_NOT_OPEN
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Not opened cursor attributes %FOUND, %NOTFOUND, %ROWCOUNT with INVALID_CURSOR exception
|
||||
--echo #
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%ROWCOUNT;
|
||||
EXCEPTION
|
||||
WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%FOUND;
|
||||
EXCEPTION
|
||||
WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT 1 AS c FROM DUAL;
|
||||
BEGIN
|
||||
SELECT c%NOTFOUND;
|
||||
EXCEPTION
|
||||
WHEN INVALID_CURSOR THEN SELECT 'INVALID_CURSOR caught' AS msg;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1;
|
||||
DROP PROCEDURE p1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # print()
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
EXPLAIN EXTENDED SELECT c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Declared data type of the attributes
|
||||
--echo #
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
OPEN c;
|
||||
CREATE TABLE t2 AS SELECT c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
SHOW CREATE TABLE t2;
|
||||
DROP TABLE t2;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # Core functionality
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
INSERT INTO t1 VALUES (20);
|
||||
INSERT INTO t1 VALUES (30);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a INT:=0;
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
SELECT a, c%ISOPEN;
|
||||
OPEN c;
|
||||
/*
|
||||
After OPEN and before FETCH:
|
||||
- %ROWCOUNT returns 0
|
||||
- %FOUND and %NOTFOUND return NULL
|
||||
*/
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
CLOSE c;
|
||||
SELECT a, c%ISOPEN;
|
||||
/*
|
||||
After reopen and before FETCH:
|
||||
- %ROWCOUNT returns 0
|
||||
- %FOUND and %NOTFOUND return NULL
|
||||
*/
|
||||
OPEN c;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
FETCH c INTO a;
|
||||
SELECT a, c%ISOPEN, c%ROWCOUNT, c%FOUND, c%NOTFOUND;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %NOTFOUND as a loop exit condition
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
INSERT INTO t1 VALUES (20);
|
||||
INSERT INTO t1 VALUES (30);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a INT:=0;
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
OPEN c;
|
||||
LOOP
|
||||
FETCH c INTO a;
|
||||
EXIT WHEN c%NOTFOUND;
|
||||
SELECT a;
|
||||
END LOOP;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # %FOUND as a loop exit condition
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (a INT);
|
||||
INSERT INTO t1 VALUES (10);
|
||||
INSERT INTO t1 VALUES (20);
|
||||
INSERT INTO t1 VALUES (30);
|
||||
DELIMITER $$;
|
||||
CREATE PROCEDURE p1
|
||||
AS
|
||||
a INT:=0;
|
||||
CURSOR c IS SELECT * FROM t1 ORDER BY a;
|
||||
BEGIN
|
||||
OPEN c;
|
||||
LOOP
|
||||
FETCH c INTO a;
|
||||
EXIT WHEN NOT c%FOUND;
|
||||
SELECT a;
|
||||
END LOOP;
|
||||
CLOSE c;
|
||||
END;
|
||||
$$
|
||||
DELIMITER ;$$
|
||||
CALL p1();
|
||||
DROP PROCEDURE p1;
|
||||
DROP TABLE t1;
|
@ -247,3 +247,9 @@ DROP TABLE decode;
|
||||
|
||||
CREATE TABLE rowcount (rowcount int);
|
||||
DROP TABLE rowcount;
|
||||
|
||||
CREATE TABLE isopen (isopen int);
|
||||
DROP TABLE isopen;
|
||||
|
||||
CREATE TABLE notfound (notfound int);
|
||||
DROP TABLE notfound;
|
||||
|
@ -6862,4 +6862,52 @@ void Item_func_last_value::fix_length_and_dec()
|
||||
}
|
||||
|
||||
|
||||
void Item_func_cursor_int_attr::print(String *str, enum_query_type query_type)
|
||||
{
|
||||
append_identifier(current_thd, str, m_cursor_name.str, m_cursor_name.length);
|
||||
str->append(func_name());
|
||||
}
|
||||
|
||||
|
||||
sp_cursor *Item_func_cursor_int_attr::get_open_cursor_or_error()
|
||||
{
|
||||
THD *thd= current_thd;
|
||||
sp_cursor *c= thd->spcont->get_cursor(m_cursor_offset);
|
||||
DBUG_ASSERT(c);
|
||||
if (!c/*safety*/ || !c->is_open())
|
||||
{
|
||||
my_message(ER_SP_CURSOR_NOT_OPEN, ER_THD(thd, ER_SP_CURSOR_NOT_OPEN),
|
||||
MYF(0));
|
||||
return NULL;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
longlong Item_func_cursor_isopen::val_int()
|
||||
{
|
||||
sp_cursor *c= current_thd->spcont->get_cursor(m_cursor_offset);
|
||||
DBUG_ASSERT(c != NULL);
|
||||
return c ? c->is_open() : 0;
|
||||
}
|
||||
|
||||
|
||||
longlong Item_func_cursor_found::val_int()
|
||||
{
|
||||
sp_cursor *c= get_open_cursor_or_error();
|
||||
return !(null_value= (!c || c->fetch_count() == 0)) && c->found();
|
||||
}
|
||||
|
||||
|
||||
longlong Item_func_cursor_notfound::val_int()
|
||||
{
|
||||
sp_cursor *c= get_open_cursor_or_error();
|
||||
return !(null_value= (!c || c->fetch_count() == 0)) && !c->found();
|
||||
}
|
||||
|
||||
|
||||
longlong Item_func_cursor_rowcount::val_int()
|
||||
{
|
||||
sp_cursor *c= get_open_cursor_or_error();
|
||||
return !(null_value= !c) ? c->row_count() : 0;
|
||||
}
|
||||
|
@ -725,6 +725,76 @@ public:
|
||||
};
|
||||
|
||||
|
||||
class Item_func_cursor_int_attr: public Item_int_func
|
||||
{
|
||||
protected:
|
||||
LEX_STRING m_cursor_name;
|
||||
uint m_cursor_offset;
|
||||
class sp_cursor *get_open_cursor_or_error();
|
||||
public:
|
||||
Item_func_cursor_int_attr(THD *thd, const LEX_STRING name, uint offset)
|
||||
:Item_int_func(thd), m_cursor_name(name), m_cursor_offset(offset)
|
||||
{ }
|
||||
bool check_vcol_func_processor(void *arg)
|
||||
{
|
||||
return mark_unsupported_function(func_name(), arg, VCOL_SESSION_FUNC);
|
||||
}
|
||||
void print(String *str, enum_query_type query_type);
|
||||
};
|
||||
|
||||
|
||||
class Item_func_cursor_isopen: public Item_func_cursor_int_attr
|
||||
{
|
||||
public:
|
||||
Item_func_cursor_isopen(THD *thd, const LEX_STRING name, uint offset)
|
||||
:Item_func_cursor_int_attr(thd, name, offset) { }
|
||||
const char *func_name() const { return "%ISOPEN"; }
|
||||
void fix_length_and_dec() { max_length= 1; }
|
||||
longlong val_int();
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_func_cursor_isopen>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
class Item_func_cursor_found: public Item_func_cursor_int_attr
|
||||
{
|
||||
public:
|
||||
Item_func_cursor_found(THD *thd, const LEX_STRING name, uint offset)
|
||||
:Item_func_cursor_int_attr(thd, name, offset) { }
|
||||
const char *func_name() const { return "%FOUND"; }
|
||||
void fix_length_and_dec() { max_length= 1; maybe_null= true; }
|
||||
longlong val_int();
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_func_cursor_found>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
class Item_func_cursor_notfound: public Item_func_cursor_int_attr
|
||||
{
|
||||
public:
|
||||
Item_func_cursor_notfound(THD *thd, const LEX_STRING name, uint offset)
|
||||
:Item_func_cursor_int_attr(thd, name, offset) { }
|
||||
const char *func_name() const { return "%NOTFOUND"; }
|
||||
void fix_length_and_dec() { max_length= 1; maybe_null= true; }
|
||||
longlong val_int();
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_func_cursor_notfound>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
class Item_func_cursor_rowcount: public Item_func_cursor_int_attr
|
||||
{
|
||||
public:
|
||||
Item_func_cursor_rowcount(THD *thd, const LEX_STRING name, uint offset)
|
||||
:Item_func_cursor_int_attr(thd, name, offset) { }
|
||||
const char *func_name() const { return "%ROWCOUNT"; }
|
||||
longlong val_int();
|
||||
Item *get_copy(THD *thd, MEM_ROOT *mem_root)
|
||||
{ return get_item_copy<Item_func_cursor_rowcount>(thd, mem_root, this); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Item_func_connection_id :public Item_int_func
|
||||
{
|
||||
longlong value;
|
||||
|
@ -310,6 +310,7 @@ static SYMBOL symbols[] = {
|
||||
{ "IPC", SYM(IPC_SYM)},
|
||||
{ "IS", SYM(IS)},
|
||||
{ "ISOLATION", SYM(ISOLATION)},
|
||||
{ "ISOPEN", SYM(ISOPEN_SYM)},
|
||||
{ "ISSUER", SYM(ISSUER_SYM)},
|
||||
{ "ITERATE", SYM(ITERATE_SYM)},
|
||||
{ "INVOKER", SYM(INVOKER_SYM)},
|
||||
@ -415,6 +416,7 @@ static SYMBOL symbols[] = {
|
||||
{ "NODEGROUP", SYM(NODEGROUP_SYM)},
|
||||
{ "NONE", SYM(NONE_SYM)},
|
||||
{ "NOT", SYM(NOT_SYM)},
|
||||
{ "NOTFOUND", SYM(NOTFOUND_SYM)},
|
||||
{ "NO_WRITE_TO_BINLOG", SYM(NO_WRITE_TO_BINLOG)},
|
||||
{ "NULL", SYM(NULL_SYM)},
|
||||
{ "NUMBER", SYM(NUMBER_SYM)},
|
||||
|
@ -289,13 +289,15 @@ sp_condition_value *sp_pcontext::find_condition(const LEX_STRING name,
|
||||
|
||||
|
||||
static sp_condition_value
|
||||
cond_invalid_cursor(ER_SP_CURSOR_NOT_OPEN),
|
||||
cond_no_data_found(ER_SP_FETCH_NO_DATA),
|
||||
cond_dup_val_on_index(ER_DUP_ENTRY),
|
||||
cond_too_many_rows(ER_TOO_MANY_ROWS);
|
||||
|
||||
|
||||
static sp_condition sp_predefined_conditions[3]=
|
||||
static sp_condition sp_predefined_conditions[]=
|
||||
{
|
||||
sp_condition(C_STRING_WITH_LEN("INVALID_CURSOR"), &cond_invalid_cursor),
|
||||
sp_condition(C_STRING_WITH_LEN("NO_DATA_FOUND"), &cond_no_data_found),
|
||||
sp_condition(C_STRING_WITH_LEN("DUP_VAL_ON_INDEX"), &cond_dup_val_on_index),
|
||||
sp_condition(C_STRING_WITH_LEN("TOO_MANY_ROWS"), &cond_too_many_rows)
|
||||
|
@ -425,7 +425,10 @@ sp_cursor::sp_cursor(THD *thd_arg, sp_lex_keeper *lex_keeper, sp_instr_cpush *i)
|
||||
result(thd_arg),
|
||||
m_lex_keeper(lex_keeper),
|
||||
server_side_cursor(NULL),
|
||||
m_i(i)
|
||||
m_i(i),
|
||||
m_fetch_count(0),
|
||||
m_row_count(0),
|
||||
m_found(false)
|
||||
{
|
||||
/*
|
||||
currsor can't be stored in QC, so we should prevent opening QC for
|
||||
@ -470,6 +473,8 @@ int sp_cursor::close(THD *thd)
|
||||
MYF(0));
|
||||
return -1;
|
||||
}
|
||||
m_row_count= m_fetch_count= 0;
|
||||
m_found= false;
|
||||
destroy();
|
||||
return 0;
|
||||
}
|
||||
@ -497,6 +502,7 @@ int sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_fetch_count++;
|
||||
DBUG_EXECUTE_IF("bug23032_emit_warning",
|
||||
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_UNKNOWN_ERROR,
|
||||
@ -514,10 +520,15 @@ int sp_cursor::fetch(THD *thd, List<sp_variable> *vars)
|
||||
*/
|
||||
if (! server_side_cursor->is_open())
|
||||
{
|
||||
m_found= false;
|
||||
if (thd->variables.sql_mode & MODE_ORACLE)
|
||||
return 0;
|
||||
my_message(ER_SP_FETCH_NO_DATA, ER_THD(thd, ER_SP_FETCH_NO_DATA), MYF(0));
|
||||
return -1;
|
||||
}
|
||||
|
||||
m_found= true;
|
||||
m_row_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -452,6 +452,15 @@ public:
|
||||
my_bool is_open()
|
||||
{ return MY_TEST(server_side_cursor); }
|
||||
|
||||
bool found() const
|
||||
{ return m_found; }
|
||||
|
||||
ulonglong row_count() const
|
||||
{ return m_row_count; }
|
||||
|
||||
ulonglong fetch_count() const
|
||||
{ return m_fetch_count; }
|
||||
|
||||
int fetch(THD *, List<sp_variable> *vars);
|
||||
|
||||
sp_instr_cpush *get_instr()
|
||||
@ -461,7 +470,10 @@ private:
|
||||
Select_fetch_into_spvars result;
|
||||
sp_lex_keeper *m_lex_keeper;
|
||||
Server_side_cursor *server_side_cursor;
|
||||
sp_instr_cpush *m_i; // My push instruction
|
||||
sp_instr_cpush *m_i; // My push instruction
|
||||
ulonglong m_fetch_count; // Number of FETCH commands since last OPEN
|
||||
ulonglong m_row_count; // Number of successful FETCH since last OPEN
|
||||
bool m_found; // If last FETCH fetched a row
|
||||
void destroy();
|
||||
|
||||
}; // class sp_cursor : public Sql_alloc
|
||||
|
@ -1181,6 +1181,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%token IPC_SYM
|
||||
%token IS /* SQL-2003-R */
|
||||
%token ISOLATION /* SQL-2003-R */
|
||||
%token ISOPEN_SYM /* Oracle-N */
|
||||
%token ISSUER_SYM
|
||||
%token ITERATE_SYM
|
||||
%token JOIN_SYM /* SQL-2003-R */
|
||||
@ -1290,6 +1291,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%token NONE_SYM /* SQL-2003-R */
|
||||
%token NOT2_SYM
|
||||
%token NOT_SYM /* SQL-2003-R */
|
||||
%token NOTFOUND_SYM /* Oracle-R */
|
||||
%token NOW_SYM
|
||||
%token NO_SYM /* SQL-2003-R */
|
||||
%token NO_WAIT_SYM
|
||||
@ -14346,6 +14348,7 @@ keyword_sp:
|
||||
| IO_SYM {}
|
||||
| IPC_SYM {}
|
||||
| ISOLATION {}
|
||||
| ISOPEN_SYM {}
|
||||
| ISSUER_SYM {}
|
||||
| JSON_SYM {}
|
||||
| INSERT_METHOD {}
|
||||
@ -14415,6 +14418,7 @@ keyword_sp:
|
||||
| NO_WAIT_SYM {}
|
||||
| NODEGROUP_SYM {}
|
||||
| NONE_SYM {}
|
||||
| NOTFOUND_SYM {}
|
||||
| NUMBER_SYM {}
|
||||
| NVARCHAR_SYM {}
|
||||
| OFFSET_SYM {}
|
||||
|
@ -178,6 +178,11 @@ void ORAerror(THD *thd, const char *s)
|
||||
Lex_field_type_st Lex_field_type;
|
||||
Lex_dyncol_type_st Lex_dyncol_type;
|
||||
Lex_for_loop_st for_loop;
|
||||
struct
|
||||
{
|
||||
LEX_STRING name;
|
||||
uint offset;
|
||||
} sp_cursor_name_and_offset;
|
||||
|
||||
/* pointers */
|
||||
Create_field *create_field;
|
||||
@ -555,6 +560,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%token IPC_SYM
|
||||
%token IS /* SQL-2003-R */
|
||||
%token ISOLATION /* SQL-2003-R */
|
||||
%token ISOPEN_SYM /* Oracle-N */
|
||||
%token ISSUER_SYM
|
||||
%token ITERATE_SYM
|
||||
%token JOIN_SYM /* SQL-2003-R */
|
||||
@ -664,6 +670,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%token NONE_SYM /* SQL-2003-R */
|
||||
%token NOT2_SYM
|
||||
%token NOT_SYM /* SQL-2003-R */
|
||||
%token NOTFOUND_SYM /* Oracle-R */
|
||||
%token NOW_SYM
|
||||
%token NO_SYM /* SQL-2003-R */
|
||||
%token NO_WAIT_SYM
|
||||
@ -975,7 +982,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
%left '&'
|
||||
%left SHIFT_LEFT SHIFT_RIGHT
|
||||
%left '-' '+'
|
||||
%left '*' '/' '%' DIV_SYM MOD_SYM
|
||||
%left '*' '/' DIV_SYM MOD_SYM
|
||||
%left '^'
|
||||
%left NEG '~'
|
||||
%right NOT_SYM NOT2_SYM
|
||||
@ -1103,6 +1110,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
window_func_expr
|
||||
window_func
|
||||
simple_window_func
|
||||
explicit_cursor_attr
|
||||
function_call_keyword
|
||||
function_call_nonkeyword
|
||||
function_call_generic
|
||||
@ -1291,6 +1299,7 @@ END_OF_INPUT
|
||||
%type <spblock> sp_decl_body sp_decl_body_list opt_sp_decl_body_list
|
||||
%type <spblock_handlers> sp_block_statements_and_exceptions
|
||||
%type <sp_instr_addr> sp_instr_addr
|
||||
%type <sp_cursor_name_and_offset> sp_cursor_name_and_offset
|
||||
%type <num> opt_exception_clause exception_handlers
|
||||
%type <lex> sp_cursor_stmt
|
||||
%type <spname> sp_name
|
||||
@ -8598,12 +8607,6 @@ bit_expr:
|
||||
if ($$ == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| bit_expr '%' bit_expr %prec '%'
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_mod(thd, $1, $3);
|
||||
if ($$ == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| bit_expr DIV_SYM bit_expr %prec DIV_SYM
|
||||
{
|
||||
$$= new (thd->mem_root) Item_func_int_div(thd, $1, $3);
|
||||
@ -8740,6 +8743,44 @@ dyncall_create_list:
|
||||
}
|
||||
;
|
||||
|
||||
sp_cursor_name_and_offset:
|
||||
ident
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
$$.name= $1;
|
||||
if (!lex->spcont ||
|
||||
!lex->spcont->find_cursor($1, &$$.offset, false))
|
||||
my_yyabort_error((ER_SP_CURSOR_MISMATCH, MYF(0), $1.str));
|
||||
}
|
||||
;
|
||||
|
||||
explicit_cursor_attr:
|
||||
sp_cursor_name_and_offset '%' ISOPEN_SYM
|
||||
{
|
||||
if (!($$= new (thd->mem_root)
|
||||
Item_func_cursor_isopen(thd, $1.name, $1.offset)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| sp_cursor_name_and_offset '%' FOUND_SYM
|
||||
{
|
||||
if (!($$= new (thd->mem_root)
|
||||
Item_func_cursor_found(thd, $1.name, $1.offset)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| sp_cursor_name_and_offset '%' NOTFOUND_SYM
|
||||
{
|
||||
if (!($$= new (thd->mem_root)
|
||||
Item_func_cursor_notfound(thd, $1.name, $1.offset)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
| sp_cursor_name_and_offset '%' ROWCOUNT_SYM
|
||||
{
|
||||
if (!($$= new (thd->mem_root)
|
||||
Item_func_cursor_rowcount(thd, $1.name, $1.offset)))
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
Expressions that the parser allows in a column DEFAULT clause
|
||||
without parentheses. These expressions cannot end with a COLLATE clause.
|
||||
@ -8904,6 +8945,7 @@ column_default_non_parenthesized_expr:
|
||||
|
||||
simple_expr:
|
||||
column_default_non_parenthesized_expr
|
||||
| explicit_cursor_attr
|
||||
| simple_expr COLLATE_SYM ident_or_text %prec NEG
|
||||
{
|
||||
Item *i1= new (thd->mem_root) Item_string(thd, $3.str,
|
||||
@ -14306,6 +14348,7 @@ keyword_sp:
|
||||
| IO_SYM {}
|
||||
| IPC_SYM {}
|
||||
| ISOLATION {}
|
||||
| ISOPEN_SYM {}
|
||||
| ISSUER_SYM {}
|
||||
| JSON_SYM {}
|
||||
| INSERT_METHOD {}
|
||||
@ -14375,6 +14418,7 @@ keyword_sp:
|
||||
| NO_WAIT_SYM {}
|
||||
| NODEGROUP_SYM {}
|
||||
| NONE_SYM {}
|
||||
| NOTFOUND_SYM {}
|
||||
| NUMBER_SYM {}
|
||||
| NVARCHAR_SYM {}
|
||||
| OFFSET_SYM {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user