Commit 4333980a authored by Alexander Nozdrin's avatar Alexander Nozdrin

Patch for Bug#21818 (Return value of ROW_COUNT() is incorrect

for ALTER TABLE, LOAD DATA).

ROW_COUNT is now assigned according to the following rules:

  - In my_ok():
    - for DML statements: to the number of affected rows;
    - for DDL statements: to 0.

  - In my_eof(): to -1 to indicate that there was a result set.

    We derive this semantics from the JDBC specification, where int
    java.sql.Statement.getUpdateCount() is defined to (sic) "return the
    current result as an update count; if the result is a ResultSet
    object or there are no more results, -1 is returned".

  - In my_error(): to -1 to be compatible with the MySQL C API and
    MySQL ODBC driver.

  - For SIGNAL statements: to 0 per WL#2110 specification. Zero is used
    since that's the "default" value of ROW_COUNT in the diagnostics area.

sql/protocol.cc:
  Fix a typo.
sql/sql_class.h:
  - Introduce THD::get_row_count_func() / THD::set_row_count_func();
  - Remove the CF_HAS_ROW_COUNT define
sql/sql_parse.cc:
  CF_HAS_ROW_COUNT was eliminated.
parent f9101d98
...@@ -457,6 +457,8 @@ select * from t1; ...@@ -457,6 +457,8 @@ select * from t1;
show create table t1; show create table t1;
drop table t1; drop table t1;
# Ensure that row_count() value is reset after drop table.
select 1;
select hex(concat(row_count())); select hex(concat(row_count()));
create table t1 as select concat(row_count()) as c1; create table t1 as select concat(row_count()) as c1;
show create table t1; show create table t1;
......
...@@ -772,6 +772,9 @@ t1 CREATE TABLE `t1` ( ...@@ -772,6 +772,9 @@ t1 CREATE TABLE `t1` (
`c1` varbinary(31) DEFAULT NULL `c1` varbinary(31) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
select 1;
1
1
select hex(concat(row_count())); select hex(concat(row_count()));
hex(concat(row_count())) hex(concat(row_count()))
2D31 2D31
......
...@@ -854,6 +854,9 @@ t1 CREATE TABLE `t1` ( ...@@ -854,6 +854,9 @@ t1 CREATE TABLE `t1` (
`c1` varchar(31) CHARACTER SET cp1251 DEFAULT NULL `c1` varchar(31) CHARACTER SET cp1251 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
select 1;
1
1
select hex(concat(row_count())); select hex(concat(row_count()));
hex(concat(row_count())) hex(concat(row_count()))
2D31 2D31
......
...@@ -1182,6 +1182,9 @@ t1 CREATE TABLE `t1` ( ...@@ -1182,6 +1182,9 @@ t1 CREATE TABLE `t1` (
`c1` varchar(31) DEFAULT NULL `c1` varchar(31) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
select 1;
1
1
select hex(concat(row_count())); select hex(concat(row_count()));
hex(concat(row_count())) hex(concat(row_count()))
2D31 2D31
......
...@@ -2006,6 +2006,9 @@ t1 CREATE TABLE `t1` ( ...@@ -2006,6 +2006,9 @@ t1 CREATE TABLE `t1` (
`c1` varchar(31) CHARACTER SET ucs2 DEFAULT NULL `c1` varchar(31) CHARACTER SET ucs2 DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 ) ENGINE=MyISAM DEFAULT CHARSET=latin1
drop table t1; drop table t1;
select 1;
1
1
select hex(concat(row_count())); select hex(concat(row_count()));
hex(concat(row_count())) hex(concat(row_count()))
002D0031 002D0031
......
...@@ -2590,11 +2590,11 @@ row_count() ...@@ -2590,11 +2590,11 @@ row_count()
call bug4905()| call bug4905()|
select row_count()| select row_count()|
row_count() row_count()
-1 0
call bug4905()| call bug4905()|
select row_count()| select row_count()|
row_count() row_count()
-1 0
select * from t3| select * from t3|
s1 s1
1 1
......
...@@ -375,7 +375,7 @@ row_count() after delete ...@@ -375,7 +375,7 @@ row_count() after delete
2 2
SELECT row_count(); SELECT row_count();
row_count() row_count()
-1 0
SELECT * FROM temp; SELECT * FROM temp;
f1 f2 f3 f4 f5 f6 f1 f2 f3 f4 f5 f6
qwe xyz 1998-03-26 100 uvw 1000 qwe xyz 1998-03-26 100 uvw 1000
......
...@@ -376,7 +376,7 @@ row_count() after delete ...@@ -376,7 +376,7 @@ row_count() after delete
2 2
SELECT row_count(); SELECT row_count();
row_count() row_count()
-1 0
SELECT * FROM temp; SELECT * FROM temp;
f1 f2 f3 f4 f5 f6 f1 f2 f3 f4 f5 f6
qwe xyz 1998-03-26 100 uvw 1000 qwe xyz 1998-03-26 100 uvw 1000
......
...@@ -376,7 +376,7 @@ row_count() after delete ...@@ -376,7 +376,7 @@ row_count() after delete
2 2
SELECT row_count(); SELECT row_count();
row_count() row_count()
-1 0
SELECT * FROM temp; SELECT * FROM temp;
f1 f2 f3 f4 f5 f6 f1 f2 f3 f4 f5 f6
qwe xyz 1998-03-26 100 uvw 1000 qwe xyz 1998-03-26 100 uvw 1000
......
...@@ -375,7 +375,7 @@ row_count() after delete ...@@ -375,7 +375,7 @@ row_count() after delete
2 2
SELECT row_count(); SELECT row_count();
row_count() row_count()
-1 0
SELECT * FROM temp; SELECT * FROM temp;
f1 f2 f3 f4 f5 f6 f1 f2 f3 f4 f5 f6
qwe xyz 1998-03-26 100 uvw 1000 qwe xyz 1998-03-26 100 uvw 1000
......
# --
# -- Test case for Bug#21818.
# --
DROP TABLE IF EXISTS t1;
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
# -- Check 1.
SELECT * FROM t1 INTO OUTFILE "MYSQL_TMP_DIR/bug21818.txt";
affected rows: 3
SELECT ROW_COUNT();
ROW_COUNT()
3
# -- Check 2.
SELECT a FROM t1 LIMIT 1 INTO @a;
affected rows: 1
SELECT ROW_COUNT();
ROW_COUNT()
1
# -- Check 3.
DROP DATABASE IF EXISTS mysqltest1;
CREATE DATABASE mysqltest1;
affected rows: 1
SELECT ROW_COUNT();
ROW_COUNT()
1
DROP DATABASE mysqltest1;
# -- Check 4.
DELETE FROM t1;
LOAD DATA INFILE 'MYSQL_TMP_DIR/bug21818.txt' INTO TABLE t1(a);
affected rows: 3
info: Records: 3 Deleted: 0 Skipped: 0 Warnings: 0
SELECT ROW_COUNT();
ROW_COUNT()
3
# -- Check 5.
ALTER TABLE t1 ADD COLUMN b VARCHAR(255);
affected rows: 3
info: Records: 3 Duplicates: 0 Warnings: 0
SELECT ROW_COUNT();
ROW_COUNT()
3
DROP TABLE t1;
# -- Check 6.
DROP TABLE IF EXISTS t2;
CREATE TABLE t1(a INT);
CREATE TABLE t2(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t2 VALUES (ROW_COUNT());
SELECT * FROM t2;
a
3
DROP TABLE t1;
DROP TABLE t2;
# -- Check 7 (check that SQL errors reset row_count to -1).
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
SELECT f1();
ERROR 42000: FUNCTION test.f1 does not exist
SELECT ROW_COUNT();
ROW_COUNT()
-1
DROP TABLE t1;
# -- End of test case for Bug#21818.
--echo
--echo # --
--echo # -- Test case for Bug#21818.
--echo # --
--echo
--disable_warnings
DROP TABLE IF EXISTS t1;
--enable_warnings
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
--echo
--echo # -- Check 1.
--enable_info
--echo SELECT * FROM t1 INTO OUTFILE "MYSQL_TMP_DIR/bug21818.txt";
--disable_query_log # to avoid $MYSQL_TMP_DIR in query log
--eval SELECT * FROM t1 INTO OUTFILE "$MYSQL_TMP_DIR/bug21818.txt"
--enable_query_log
--disable_info
--echo
SELECT ROW_COUNT();
--echo
--echo # -- Check 2.
--enable_info
SELECT a FROM t1 LIMIT 1 INTO @a;
--disable_info
--echo
SELECT ROW_COUNT();
--echo
--echo # -- Check 3.
--disable_warnings
DROP DATABASE IF EXISTS mysqltest1;
--enable_warnings
--enable_info
CREATE DATABASE mysqltest1;
--disable_info
--echo
SELECT ROW_COUNT();
DROP DATABASE mysqltest1;
--echo
--echo # -- Check 4.
DELETE FROM t1;
--enable_info
--echo LOAD DATA INFILE 'MYSQL_TMP_DIR/bug21818.txt' INTO TABLE t1(a);
--disable_query_log # to avoid $MYSQL_TMP_DIR in query log
--eval LOAD DATA INFILE '$MYSQL_TMP_DIR/bug21818.txt' INTO TABLE t1(a)
--enable_query_log
--disable_info
--echo
SELECT ROW_COUNT();
--remove_file $MYSQL_TMP_DIR/bug21818.txt
--echo
--echo # -- Check 5.
--enable_info
ALTER TABLE t1 ADD COLUMN b VARCHAR(255);
--disable_info
--echo
SELECT ROW_COUNT();
--echo
DROP TABLE t1;
--echo
--echo # -- Check 6.
--disable_warnings
DROP TABLE IF EXISTS t2;
--enable_warnings
CREATE TABLE t1(a INT);
CREATE TABLE t2(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
INSERT INTO t2 VALUES (ROW_COUNT());
SELECT * FROM t2;
DROP TABLE t1;
DROP TABLE t2;
--echo
--echo # -- Check 7 (check that SQL errors reset row_count to -1).
CREATE TABLE t1(a INT);
INSERT INTO t1 VALUES (1), (2), (3);
--error ER_SP_DOES_NOT_EXIST
SELECT f1();
SELECT ROW_COUNT();
DROP TABLE t1;
--echo
--echo # -- End of test case for Bug#21818.
...@@ -6030,7 +6030,7 @@ longlong Item_func_row_count::val_int() ...@@ -6030,7 +6030,7 @@ longlong Item_func_row_count::val_int()
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
THD *thd= current_thd; THD *thd= current_thd;
return thd->row_count_func; return thd->get_row_count_func();
} }
......
...@@ -210,7 +210,7 @@ net_send_ok(THD *thd, ...@@ -210,7 +210,7 @@ net_send_ok(THD *thd,
NET *net= &thd->net; NET *net= &thd->net;
uchar buff[MYSQL_ERRMSG_SIZE+10],*pos; uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
bool error= FALSE; bool error= FALSE;
DBUG_ENTER("my_ok"); DBUG_ENTER("net_send_ok");
if (! net->vio) // hack for re-parsing queries if (! net->vio) // hack for re-parsing queries
{ {
......
...@@ -512,7 +512,7 @@ THD::THD() ...@@ -512,7 +512,7 @@ THD::THD()
cuted_fields= 0L; cuted_fields= 0L;
sent_row_count= 0L; sent_row_count= 0L;
limit_found_rows= 0; limit_found_rows= 0;
row_count_func= -1; m_row_count_func= -1;
statement_id_counter= 0UL; statement_id_counter= 0UL;
// Must be reset to handle error with THD's created for init of mysqld // Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0; lex->current_select= 0;
...@@ -804,7 +804,10 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno, ...@@ -804,7 +804,10 @@ MYSQL_ERROR* THD::raise_condition(uint sql_errno,
else else
{ {
if (! stmt_da->is_error()) if (! stmt_da->is_error())
{
set_row_count_func(-1);
stmt_da->set_error_status(this, sql_errno, msg, sqlstate); stmt_da->set_error_status(this, sql_errno, msg, sqlstate);
}
} }
} }
...@@ -1805,11 +1808,6 @@ bool select_to_file::send_eof() ...@@ -1805,11 +1808,6 @@ bool select_to_file::send_eof()
error= 1; error= 1;
if (!error) if (!error)
{ {
/*
In order to remember the value of affected rows for ROW_COUNT()
function, SELECT INTO has to have an own SQLCOM.
TODO: split from SQLCOM_SELECT
*/
::my_ok(thd,row_count); ::my_ok(thd,row_count);
} }
file= -1; file= -1;
...@@ -2830,11 +2828,6 @@ bool select_dumpvar::send_eof() ...@@ -2830,11 +2828,6 @@ bool select_dumpvar::send_eof()
if (! row_count) if (! row_count)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA)); ER_SP_FETCH_NO_DATA, ER(ER_SP_FETCH_NO_DATA));
/*
In order to remember the value of affected rows for ROW_COUNT()
function, SELECT INTO has to have an own SQLCOM.
TODO: split from SQLCOM_SELECT
*/
::my_ok(thd,row_count); ::my_ok(thd,row_count);
return 0; return 0;
} }
......
...@@ -1994,7 +1994,50 @@ public: ...@@ -1994,7 +1994,50 @@ public:
} }
ulonglong limit_found_rows; ulonglong limit_found_rows;
longlong row_count_func; /* For the ROW_COUNT() function */
private:
/**
Stores the result of ROW_COUNT() function.
ROW_COUNT() function is a MySQL extention, but we try to keep it
similar to ROW_COUNT member of the GET DIAGNOSTICS stack of the SQL
standard (see SQL99, part 2, search for ROW_COUNT). It's value is
implementation defined for anything except INSERT, DELETE, UPDATE.
ROW_COUNT is assigned according to the following rules:
- In my_ok():
- for DML statements: to the number of affected rows;
- for DDL statements: to 0.
- In my_eof(): to -1 to indicate that there was a result set.
We derive this semantics from the JDBC specification, where int
java.sql.Statement.getUpdateCount() is defined to (sic) "return the
current result as an update count; if the result is a ResultSet
object or there are no more results, -1 is returned".
- In my_error(): to -1 to be compatible with the MySQL C API and
MySQL ODBC driver.
- For SIGNAL statements: to 0 per WL#2110 specification (see also
sql_signal.cc comment). Zero is used since that's the "default"
value of ROW_COUNT in the diagnostics area.
*/
longlong m_row_count_func; /* For the ROW_COUNT() function */
public:
inline longlong get_row_count_func() const
{
return m_row_count_func;
}
inline void set_row_count_func(longlong row_count_func)
{
m_row_count_func= row_count_func;
}
ha_rows cuted_fields; ha_rows cuted_fields;
/* /*
...@@ -2781,6 +2824,7 @@ inline void ...@@ -2781,6 +2824,7 @@ inline void
my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0, my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0,
const char *message= NULL) const char *message= NULL)
{ {
thd->set_row_count_func(affected_rows);
thd->stmt_da->set_ok_status(thd, affected_rows, id, message); thd->stmt_da->set_ok_status(thd, affected_rows, id, message);
} }
...@@ -2790,6 +2834,7 @@ my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0, ...@@ -2790,6 +2834,7 @@ my_ok(THD *thd, ulonglong affected_rows= 0, ulonglong id= 0,
inline void inline void
my_eof(THD *thd) my_eof(THD *thd)
{ {
thd->set_row_count_func(-1);
thd->stmt_da->set_eof_status(thd); thd->stmt_da->set_eof_status(thd);
} }
...@@ -3451,7 +3496,7 @@ public: ...@@ -3451,7 +3496,7 @@ public:
/* Bits in sql_command_flags */ /* Bits in sql_command_flags */
#define CF_CHANGES_DATA (1U << 0) #define CF_CHANGES_DATA (1U << 0)
#define CF_HAS_ROW_COUNT (1U << 1) /* The 2nd bit is unused -- it used to be CF_HAS_ROW_COUNT. */
#define CF_STATUS_COMMAND (1U << 2) #define CF_STATUS_COMMAND (1U << 2)
#define CF_SHOW_TABLE_COMMAND (1U << 3) #define CF_SHOW_TABLE_COMMAND (1U << 3)
#define CF_WRITE_LOGS_COMMAND (1U << 4) #define CF_WRITE_LOGS_COMMAND (1U << 4)
......
...@@ -187,8 +187,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -187,8 +187,8 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (prune_partitions(thd, table, conds)) if (prune_partitions(thd, table, conds))
{ {
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
thd->row_count_func= 0; // No matching record
my_ok(thd, (ha_rows) thd->row_count_func); // No matching records my_ok(thd, 0);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
#endif #endif
...@@ -204,7 +204,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -204,7 +204,6 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{ {
delete select; delete select;
free_underlaid_joins(thd, select_lex); free_underlaid_joins(thd, select_lex);
thd->row_count_func= 0;
/* /*
Error was already created by quick select evaluation (check_quick()). Error was already created by quick select evaluation (check_quick()).
TODO: Add error code output parameter to Item::val_xxx() methods. TODO: Add error code output parameter to Item::val_xxx() methods.
...@@ -213,7 +212,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ...@@ -213,7 +212,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
*/ */
if (thd->is_error()) if (thd->is_error())
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
my_ok(thd, (ha_rows) thd->row_count_func); my_ok(thd, 0);
/* /*
We don't need to call reset_auto_increment in this case, because We don't need to call reset_auto_increment in this case, because
mysql_truncate always gives a NULL conds argument, hence we never mysql_truncate always gives a NULL conds argument, hence we never
...@@ -460,8 +459,7 @@ cleanup: ...@@ -460,8 +459,7 @@ cleanup:
If a TRUNCATE TABLE was issued, the number of rows should be reported as If a TRUNCATE TABLE was issued, the number of rows should be reported as
zero since the exact number is unknown. zero since the exact number is unknown.
*/ */
thd->row_count_func= reset_auto_increment ? 0 : deleted; my_ok(thd, reset_auto_increment ? 0 : deleted);
my_ok(thd, (ha_rows) thd->row_count_func);
DBUG_PRINT("info",("%ld records deleted",(long) deleted)); DBUG_PRINT("info",("%ld records deleted",(long) deleted));
} }
DBUG_RETURN(error >= 0 || thd->is_error()); DBUG_RETURN(error >= 0 || thd->is_error());
...@@ -1058,8 +1056,7 @@ bool multi_delete::send_eof() ...@@ -1058,8 +1056,7 @@ bool multi_delete::send_eof()
if (!local_error) if (!local_error)
{ {
thd->row_count_func= deleted; ::my_ok(thd, deleted);
::my_ok(thd, (ha_rows) thd->row_count_func);
} }
return 0; return 0;
} }
......
...@@ -1005,10 +1005,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ...@@ -1005,10 +1005,10 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
if (values_list.elements == 1 && (!(thd->variables.option_bits & OPTION_WARNINGS) || if (values_list.elements == 1 && (!(thd->variables.option_bits & OPTION_WARNINGS) ||
!thd->cuted_fields)) !thd->cuted_fields))
{ {
thd->row_count_func= info.copied + info.deleted + my_ok(thd, info.copied + info.deleted +
((thd->client_capabilities & CLIENT_FOUND_ROWS) ? ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
info.touched : info.updated); info.touched : info.updated),
my_ok(thd, (ulong) thd->row_count_func, id); id);
} }
else else
{ {
...@@ -1024,8 +1024,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list, ...@@ -1024,8 +1024,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(ulong) (info.deleted + updated), (ulong) (info.deleted + updated),
(ulong) thd->warning_info->statement_warn_count()); (ulong) thd->warning_info->statement_warn_count());
thd->row_count_func= info.copied + info.deleted + updated; ::my_ok(thd, info.copied + info.deleted + updated, id, buff);
::my_ok(thd, (ulong) thd->row_count_func, id, buff);
} }
thd->abort_on_warning= 0; thd->abort_on_warning= 0;
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
...@@ -3337,7 +3336,7 @@ bool select_insert::send_eof() ...@@ -3337,7 +3336,7 @@ bool select_insert::send_eof()
{ {
int error; int error;
bool const trans_table= table->file->has_transactions(); bool const trans_table= table->file->has_transactions();
ulonglong id; ulonglong id, row_count;
bool changed; bool changed;
THD::killed_state killed_status= thd->killed; THD::killed_state killed_status= thd->killed;
DBUG_ENTER("select_insert::send_eof"); DBUG_ENTER("select_insert::send_eof");
...@@ -3403,16 +3402,15 @@ bool select_insert::send_eof() ...@@ -3403,16 +3402,15 @@ bool select_insert::send_eof()
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records, sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(ulong) (info.deleted+info.updated), (ulong) (info.deleted+info.updated),
(ulong) thd->warning_info->statement_warn_count()); (ulong) thd->warning_info->statement_warn_count());
thd->row_count_func= info.copied + info.deleted + row_count= info.copied + info.deleted +
((thd->client_capabilities & CLIENT_FOUND_ROWS) ? ((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
info.touched : info.updated); info.touched : info.updated);
id= (thd->first_successful_insert_id_in_cur_stmt > 0) ? id= (thd->first_successful_insert_id_in_cur_stmt > 0) ?
thd->first_successful_insert_id_in_cur_stmt : thd->first_successful_insert_id_in_cur_stmt :
(thd->arg_of_last_insert_id_function ? (thd->arg_of_last_insert_id_function ?
thd->first_successful_insert_id_in_prev_stmt : thd->first_successful_insert_id_in_prev_stmt :
(info.copied ? autoinc_value_of_last_inserted_row : 0)); (info.copied ? autoinc_value_of_last_inserted_row : 0));
::my_ok(thd, (ulong) thd->row_count_func, id, buff); ::my_ok(thd, row_count, id, buff);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
......
...@@ -274,22 +274,20 @@ void init_update_queries(void) ...@@ -274,22 +274,20 @@ void init_update_queries(void)
sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_CREATE_TRIGGER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_DROP_TRIGGER]= CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | sql_command_flags[SQLCOM_UPDATE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_REEXECUTION_FRAGILE | CF_PROTECT_AGAINST_GRL; CF_PROTECT_AGAINST_GRL;
sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | sql_command_flags[SQLCOM_UPDATE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_REEXECUTION_FRAGILE | CF_PROTECT_AGAINST_GRL; CF_PROTECT_AGAINST_GRL;
sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | sql_command_flags[SQLCOM_INSERT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_REEXECUTION_FRAGILE | CF_PROTECT_AGAINST_GRL; CF_PROTECT_AGAINST_GRL;
sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | sql_command_flags[SQLCOM_INSERT_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_REEXECUTION_FRAGILE | CF_PROTECT_AGAINST_GRL; CF_PROTECT_AGAINST_GRL;
sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | sql_command_flags[SQLCOM_DELETE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_REEXECUTION_FRAGILE | CF_PROTECT_AGAINST_GRL; CF_PROTECT_AGAINST_GRL;
sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | sql_command_flags[SQLCOM_DELETE_MULTI]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE |
CF_REEXECUTION_FRAGILE | CF_PROTECT_AGAINST_GRL; CF_PROTECT_AGAINST_GRL;
sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT | sql_command_flags[SQLCOM_REPLACE]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_REPLACE_SELECT]= CF_CHANGES_DATA | CF_HAS_ROW_COUNT |
CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_SELECT]= CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS; sql_command_flags[SQLCOM_SET_OPTION]= CF_REEXECUTION_FRAGILE | CF_AUTO_COMMIT_TRANS;
sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_DO]= CF_REEXECUTION_FRAGILE;
...@@ -367,8 +365,7 @@ void init_update_queries(void) ...@@ -367,8 +365,7 @@ void init_update_queries(void)
last called (or executed) statement is preserved. last called (or executed) statement is preserved.
See mysql_execute_command() for how CF_ROW_COUNT is used. See mysql_execute_command() for how CF_ROW_COUNT is used.
*/ */
sql_command_flags[SQLCOM_CALL]= CF_HAS_ROW_COUNT | CF_REEXECUTION_FRAGILE; sql_command_flags[SQLCOM_CALL]= CF_REEXECUTION_FRAGILE;
sql_command_flags[SQLCOM_EXECUTE]= CF_HAS_ROW_COUNT;
/* /*
The following admin table operations are allowed The following admin table operations are allowed
...@@ -3184,7 +3181,7 @@ end_with_restore_list: ...@@ -3184,7 +3181,7 @@ end_with_restore_list:
res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values, res= mysql_insert(thd, all_tables, lex->field_list, lex->many_values,
lex->update_list, lex->value_list, lex->update_list, lex->value_list,
lex->duplicates, lex->ignore); lex->duplicates, lex->ignore);
MYSQL_INSERT_DONE(res, (ulong) thd->row_count_func); MYSQL_INSERT_DONE(res, (ulong) thd->get_row_count_func());
/* /*
If we have inserted into a VIEW, and the base table has If we have inserted into a VIEW, and the base table has
AUTO_INCREMENT column, but this column is not accessible through AUTO_INCREMENT column, but this column is not accessible through
...@@ -3250,7 +3247,7 @@ end_with_restore_list: ...@@ -3250,7 +3247,7 @@ end_with_restore_list:
delete sel_result; delete sel_result;
} }
/* revert changes for SP */ /* revert changes for SP */
MYSQL_INSERT_SELECT_DONE(res, (ulong) thd->row_count_func); MYSQL_INSERT_SELECT_DONE(res, (ulong) thd->get_row_count_func());
select_lex->table_list.first= (uchar*) first_table; select_lex->table_list.first= (uchar*) first_table;
} }
/* /*
...@@ -3296,7 +3293,7 @@ end_with_restore_list: ...@@ -3296,7 +3293,7 @@ end_with_restore_list:
&select_lex->order_list, &select_lex->order_list,
unit->select_limit_cnt, select_lex->options, unit->select_limit_cnt, select_lex->options,
FALSE); FALSE);
MYSQL_DELETE_DONE(res, (ulong) thd->row_count_func); MYSQL_DELETE_DONE(res, (ulong) thd->get_row_count_func());
break; break;
} }
case SQLCOM_DELETE_MULTI: case SQLCOM_DELETE_MULTI:
...@@ -4299,8 +4296,9 @@ create_sp_error: ...@@ -4299,8 +4296,9 @@ create_sp_error:
thd->server_status&= ~bits_to_be_cleared; thd->server_status&= ~bits_to_be_cleared;
if (!res) if (!res)
my_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 : {
thd->row_count_func)); my_ok(thd, (thd->get_row_count_func() < 0) ? 0 : thd->get_row_count_func());
}
else else
{ {
DBUG_ASSERT(thd->is_error() || thd->killed); DBUG_ASSERT(thd->is_error() || thd->killed);
...@@ -4687,15 +4685,6 @@ create_sp_error: ...@@ -4687,15 +4685,6 @@ create_sp_error:
if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION) if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
reset_one_shot_variables(thd); reset_one_shot_variables(thd);
/*
The return value for ROW_COUNT() is "implementation dependent" if the
statement is not DELETE, INSERT or UPDATE, but -1 is what JDBC and ODBC
wants. We also keep the last value in case of SQLCOM_CALL or
SQLCOM_EXECUTE.
*/
if (!(sql_command_flags[lex->sql_command] & CF_HAS_ROW_COUNT))
thd->row_count_func= -1;
goto finish; goto finish;
error: error:
......
...@@ -458,8 +458,20 @@ bool Signal_statement::execute(THD *thd) ...@@ -458,8 +458,20 @@ bool Signal_statement::execute(THD *thd)
DBUG_ENTER("Signal_statement::execute"); DBUG_ENTER("Signal_statement::execute");
/*
WL#2110 SIGNAL specification says:
When SIGNAL is executed, it has five effects, in the following order:
(1) First, the diagnostics area is completely cleared. So if the
SIGNAL is in a DECLARE HANDLER then any pending errors or warnings
are gone. So is 'row count'.
This has roots in the SQL standard specification for SIGNAL.
*/
thd->stmt_da->reset_diagnostics_area(); thd->stmt_da->reset_diagnostics_area();
thd->row_count_func= 0; thd->set_row_count_func(0);
thd->warning_info->clear_warning_info(thd->query_id); thd->warning_info->clear_warning_info(thd->query_id);
result= raise_condition(thd, &cond); result= raise_condition(thd, &cond);
......
...@@ -843,9 +843,8 @@ int mysql_update(THD *thd, ...@@ -843,9 +843,8 @@ int mysql_update(THD *thd,
my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found, my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), (ulong) found,
(ulong) updated, (ulong) updated,
(ulong) thd->warning_info->statement_warn_count()); (ulong) thd->warning_info->statement_warn_count());
thd->row_count_func= my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; id, buff);
my_ok(thd, (ulong) thd->row_count_func, id, buff);
DBUG_PRINT("info",("%ld records updated", (long) updated)); DBUG_PRINT("info",("%ld records updated", (long) updated));
} }
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */ thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
...@@ -2150,8 +2149,7 @@ bool multi_update::send_eof() ...@@ -2150,8 +2149,7 @@ bool multi_update::send_eof()
thd->first_successful_insert_id_in_prev_stmt : 0; thd->first_successful_insert_id_in_prev_stmt : 0;
my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO), my_snprintf(buff, sizeof(buff), ER(ER_UPDATE_INFO),
(ulong) found, (ulong) updated, (ulong) thd->cuted_fields); (ulong) found, (ulong) updated, (ulong) thd->cuted_fields);
thd->row_count_func= ::my_ok(thd, (thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated; id, buff);
::my_ok(thd, (ulong) thd->row_count_func, id, buff);
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
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