diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 38bd70b6951..631e640366d 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -802,6 +802,28 @@ use test| drop database sp_db3| select type,db,name from mysql.proc where db = 'sp_db3'| type db name +create procedure rc() +begin +delete from t1; +insert into t1 values ("a", 1), ("b", 2), ("c", 3); +end| +call rc()| +select row_count()| +row_count() +3 +update t1 set data=42 where id = "b"; +select row_count()| +row_count() +1 +delete from t1| +select row_count()| +row_count() +3 +delete from t1| +select row_count()| +row_count() +0 +drop procedure rc| create procedure bug822(a_id char(16), a_data int) begin declare n int; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index c86de916d16..f2bbf8d939c 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -931,6 +931,25 @@ drop database sp_db3| select type,db,name from mysql.proc where db = 'sp_db3'| +# ROW_COUNT() function after a CALL +# We test the other cases here too, although it's not strictly SP specific +create procedure rc() +begin + delete from t1; + insert into t1 values ("a", 1), ("b", 2), ("c", 3); +end| + +call rc()| +select row_count()| +update t1 set data=42 where id = "b"; +select row_count()| +delete from t1| +select row_count()| +delete from t1| +select row_count()| +drop procedure rc| + + # # Test cases for old bugs # diff --git a/sql/item_func.cc b/sql/item_func.cc index c648b34efae..47ca94238ab 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -3206,6 +3206,15 @@ longlong Item_func_is_used_lock::val_int() } +longlong Item_func_row_count::val_int() +{ + DBUG_ASSERT(fixed == 1); + THD *thd= current_thd; + + return thd->row_count_func; +} + + Item_func_sp::Item_func_sp(sp_name *name) :Item_func(), m_name(name), m_sp(NULL) { diff --git a/sql/item_func.h b/sql/item_func.h index 435615531b2..7becbeac8c5 100644 --- a/sql/item_func.h +++ b/sql/item_func.h @@ -1076,6 +1076,16 @@ enum Cast_target }; +class Item_func_row_count :public Item_int_func +{ +public: + Item_func_row_count() :Item_int_func() {} + longlong val_int(); + const char *func_name() const { return "row_count"; } + void fix_length_and_dec() { decimals= 0; maybe_null=0; } +}; + + /* * * Stored FUNCTIONs diff --git a/sql/lex.h b/sql/lex.h index 32552172a01..1102e070e6d 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -681,6 +681,7 @@ static SYMBOL sql_functions[] = { { "RELEASE_LOCK", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_release_lock)}, { "REVERSE", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_reverse)}, { "ROUND", SYM(ROUND)}, + { "ROW_COUNT", SYM(ROW_COUNT_SYM)}, { "RPAD", F_SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_rpad)}, { "RTRIM", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_rtrim)}, { "SEC_TO_TIME", F_SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_sec_to_time)}, diff --git a/sql/sql_class.h b/sql/sql_class.h index fd1ebca9d9e..14e4ce0044b 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -829,6 +829,7 @@ public: bool charset_is_system_charset, charset_is_collation_connection; bool slow_command; + ulong row_count_func; /* For the ROW_COUNT() function */ sp_rcontext *spcont; // SP runtime context sp_cache *sp_proc_cache; sp_cache *sp_func_cache; diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index ad6de901f56..3307f11a917 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -96,6 +96,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order, { delete select; free_underlaid_joins(thd, &thd->lex->select_lex); + thd->row_count_func= 0; send_ok(thd,0L); DBUG_RETURN(0); // Nothing to delete } @@ -245,6 +246,7 @@ cleanup: send_error(thd,thd->killed_errno()); else { + thd->row_count_func= deleted; send_ok(thd,deleted); DBUG_PRINT("info",("%d records deleted",deleted)); } @@ -550,7 +552,10 @@ bool multi_delete::send_eof() if (local_error) ::send_error(thd); else + { + thd->row_count_func= deleted; ::send_ok(thd, deleted); + } return 0; } diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 01e31b3e7a4..ced85159a53 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -419,7 +419,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, goto abort; if (values_list.elements == 1 && (!(thd->options & OPTION_WARNINGS) || !thd->cuted_fields)) - send_ok(thd,info.copied+info.deleted+info.updated,id); + { + thd->row_count_func= info.copied+info.deleted+info.updated; + send_ok(thd, thd->row_count_func, id); + } else { char buff[160]; @@ -430,7 +433,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, else sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, (ulong) info.deleted+info.updated, (ulong) thd->cuted_fields); - ::send_ok(thd,info.copied+info.deleted+info.updated,(ulonglong)id,buff); + thd->row_count_func= info.copied+info.deleted+info.updated; + ::send_ok(thd, thd->row_count_func, (ulonglong)id,buff); } free_underlaid_joins(thd, &thd->lex->select_lex); table->insert_values=0; @@ -1565,7 +1569,8 @@ bool select_insert::send_eof() else sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, (ulong) info.deleted+info.updated, (ulong) thd->cuted_fields); - ::send_ok(thd,info.copied+info.deleted+info.updated,last_insert_id,buff); + thd->row_count_func= info.copied+info.deleted+info.updated; + ::send_ok(thd, thd->row_count_func, last_insert_id, buff); DBUG_RETURN(0); } diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 5f52b8d6aac..63873bcb6b1 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3582,7 +3582,7 @@ unsent_create_error: } if (res == 0) - send_ok(thd); + send_ok(thd, thd->row_count_func); else goto error; // Substatement should already have sent error } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 277a6b3bf37..3e9bb0b753b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -399,8 +399,9 @@ int mysql_update(THD *thd, char buff[80]; sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, (ulong) thd->cuted_fields); - send_ok(thd, - (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, + thd->row_count_func= + (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; + send_ok(thd, thd->row_count_func, thd->insert_id_used ? thd->insert_id() : 0L,buff); DBUG_PRINT("info",("%d records updated",updated)); } @@ -1124,8 +1125,9 @@ bool multi_update::send_eof() sprintf(buff, ER(ER_UPDATE_INFO), (ulong) found, (ulong) updated, (ulong) thd->cuted_fields); - ::send_ok(thd, - (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated, + thd->row_count_func= + (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; + ::send_ok(thd, thd->row_count_func, thd->insert_id_used ? thd->insert_id() : 0L,buff); return 0; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 17236941ceb..f72d43ad298 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -436,6 +436,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token X509_SYM %token XOR %token COMPRESSED_SYM +%token ROW_COUNT_SYM %token ERRORS %token WARNINGS @@ -3936,6 +3937,11 @@ simple_expr: | ROUND '(' expr ')' { $$= new Item_func_round($3, new Item_int((char*)"0",0,1),0); } | ROUND '(' expr ',' expr ')' { $$= new Item_func_round($3,$5,0); } + | ROW_COUNT_SYM '(' ')' + { + $$= new Item_func_row_count(); + Lex->safe_to_cache_query= 0; + } | SUBDATE_SYM '(' expr ',' expr ')' { $$= new Item_date_add_interval($3, $5, INTERVAL_DAY, 1);} | SUBDATE_SYM '(' expr ',' INTERVAL_SYM expr interval ')'