diff options
author | Alexander Barkov <bar@mariadb.org> | 2016-09-27 10:13:08 +0400 |
---|---|---|
committer | Alexander Barkov <bar@mariadb.org> | 2017-04-05 15:02:51 +0400 |
commit | 76714a5c9a4c05fa7084f2c562a9eb50a0b7bd17 (patch) | |
tree | fc0e93ef9195d89d4079c8608e102012deb3b5e7 /sql | |
parent | 4bb87996b915a9383c7bf33c8683f128d3791014 (diff) | |
download | mariadb-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.cc | 48 | ||||
-rw-r--r-- | sql/item_func.h | 70 | ||||
-rw-r--r-- | sql/lex.h | 2 | ||||
-rw-r--r-- | sql/sp_pcontext.cc | 4 | ||||
-rw-r--r-- | sql/sp_rcontext.cc | 13 | ||||
-rw-r--r-- | sql/sp_rcontext.h | 14 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 4 | ||||
-rw-r--r-- | sql/sql_yacc_ora.yy | 58 |
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 {} |