summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorAlexander Barkov <bar@mariadb.org>2016-09-27 10:13:08 +0400
committerAlexander Barkov <bar@mariadb.org>2017-04-05 15:02:51 +0400
commit76714a5c9a4c05fa7084f2c562a9eb50a0b7bd17 (patch)
treefc0e93ef9195d89d4079c8608e102012deb3b5e7 /sql
parent4bb87996b915a9383c7bf33c8683f128d3791014 (diff)
downloadmariadb-git-76714a5c9a4c05fa7084f2c562a9eb50a0b7bd17.tar.gz
MDEV-10582 sql_mode=ORACLE: explicit cursor attributes %ISOPEN, %ROWCOUNT, %FOUND, %NOTFOUND
Diffstat (limited to 'sql')
-rw-r--r--sql/item_func.cc48
-rw-r--r--sql/item_func.h70
-rw-r--r--sql/lex.h2
-rw-r--r--sql/sp_pcontext.cc4
-rw-r--r--sql/sp_rcontext.cc13
-rw-r--r--sql/sp_rcontext.h14
-rw-r--r--sql/sql_yacc.yy4
-rw-r--r--sql/sql_yacc_ora.yy58
8 files changed, 203 insertions, 10 deletions
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 4dd3a1e7da4..ad3a863fa57 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -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;
+}
diff --git a/sql/item_func.h b/sql/item_func.h
index 0fbf76c510d..28cdb78f6dd 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -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;
diff --git a/sql/lex.h b/sql/lex.h
index 38b0e2ab68c..08bcba3beee 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -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)},
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 6b796cb95e9..daf8a6febd0 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -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)
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 8873b87d989..ff5ecc5e6c6 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -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;
}
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 2640490fefa..b6b0d4de0c3 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -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
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index d93cbd7ed61..3a63b8467e9 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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 {}
diff --git a/sql/sql_yacc_ora.yy b/sql/sql_yacc_ora.yy
index d379991613b..7ab03be7617 100644
--- a/sql/sql_yacc_ora.yy
+++ b/sql/sql_yacc_ora.yy
@@ -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 {}