Commit 76714a5c authored by Alexander Barkov's avatar Alexander Barkov

MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND

parent 4bb87996
......@@ -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;
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;
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 @@ class Item_int_func :public Item_func
};
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 @@ class sp_cursor : public Sql_alloc
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 @@ class sp_cursor : public Sql_alloc
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 {}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment