summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <anozdrin/alik@quad.opbmk>2008-03-18 13:53:51 +0300
committerunknown <anozdrin/alik@quad.opbmk>2008-03-18 13:53:51 +0300
commitf77686df0d15757ee4003ec42e4d1268b1137dd5 (patch)
treeac3aa6164de2c626ea1a053059068240ca07a75e
parentf20fe94b55727fbc69b1cb86af5dc96f216bdd87 (diff)
parent23d567aa7cb01811294a24ecda100d2a90fe8acf (diff)
downloadmariadb-git-f77686df0d15757ee4003ec42e4d1268b1137dd5.tar.gz
Merge quad.opbmk:/mnt/raid/alik/MySQL/devel/5.0
into quad.opbmk:/mnt/raid/alik/MySQL/devel/5.0-rt-merged libmysql/libmysql.c: Auto merged sql-common/client.c: Auto merged tests/mysql_client_test.c: Manually merged.
-rw-r--r--libmysql/libmysql.c17
-rw-r--r--mysql-test/r/trigger-trans.result19
-rw-r--r--mysql-test/t/mysql_client_test.test4
-rw-r--r--mysql-test/t/trigger-trans.test32
-rw-r--r--sql-common/client.c10
-rw-r--r--sql/sql_delete.cc15
-rw-r--r--sql/sql_prepare.cc18
-rw-r--r--tests/mysql_client_test.c79
8 files changed, 94 insertions, 100 deletions
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 0320126a522..97e0835b99f 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -2456,7 +2456,7 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
int4store(buff+5, 1); /* iteration count */
res= test(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
- packet, length, 1, NULL) ||
+ packet, length, 1, stmt) ||
(*mysql->methods->read_query_result)(mysql));
stmt->affected_rows= mysql->affected_rows;
stmt->server_status= mysql->server_status;
@@ -2673,7 +2673,7 @@ stmt_read_row_from_cursor(MYSQL_STMT *stmt, unsigned char **row)
int4store(buff + 4, stmt->prefetch_rows); /* number of rows to fetch */
if ((*mysql->methods->advanced_command)(mysql, COM_STMT_FETCH,
buff, sizeof(buff), NullS, 0,
- 1, NULL))
+ 1, stmt))
{
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
return 1;
@@ -3340,7 +3340,7 @@ mysql_stmt_send_long_data(MYSQL_STMT *stmt, uint param_number,
*/
if ((*mysql->methods->advanced_command)(mysql, COM_STMT_SEND_LONG_DATA,
buff, sizeof(buff), data,
- length, 1, NULL))
+ length, 1, stmt))
{
set_stmt_errmsg(stmt, mysql->net.last_error,
mysql->net.last_errno, mysql->net.sqlstate);
@@ -4737,6 +4737,13 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
MYSQL_DATA *result= &stmt->result;
DBUG_ENTER("mysql_stmt_store_result");
+ if (!mysql)
+ {
+ /* mysql can be reset in mysql_close called from mysql_reconnect */
+ set_stmt_error(stmt, CR_SERVER_LOST, unknown_sqlstate);
+ DBUG_RETURN(1);
+ }
+
mysql= mysql->last_used_con;
if (!stmt->field_count)
@@ -4762,7 +4769,7 @@ int STDCALL mysql_stmt_store_result(MYSQL_STMT *stmt)
int4store(buff, stmt->stmt_id);
int4store(buff + 4, (int)~0); /* number of rows to fetch */
if (cli_advanced_command(mysql, COM_STMT_FETCH, buff, sizeof(buff),
- NullS, 0, 1, NULL))
+ NullS, 0, 1, stmt))
{
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
DBUG_RETURN(1);
@@ -4949,7 +4956,7 @@ static my_bool reset_stmt_handle(MYSQL_STMT *stmt, uint flags)
char buff[MYSQL_STMT_HEADER]; /* packet header: 4 bytes for stmt id */
int4store(buff, stmt->stmt_id);
if ((*mysql->methods->advanced_command)(mysql, COM_STMT_RESET, buff,
- sizeof(buff), 0, 0, 0, NULL))
+ sizeof(buff), 0, 0, 0, stmt))
{
set_stmt_errmsg(stmt, mysql->net.last_error, mysql->net.last_errno,
mysql->net.sqlstate);
diff --git a/mysql-test/r/trigger-trans.result b/mysql-test/r/trigger-trans.result
index cd5f629564f..dccaa27c5fd 100644
--- a/mysql-test/r/trigger-trans.result
+++ b/mysql-test/r/trigger-trans.result
@@ -140,4 +140,23 @@ select * from t3;
c
1
drop table t1, t2, t3;
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=innodb;
+CREATE TABLE t2(b INT, FOREIGN KEY(b) REFERENCES t1(a)) ENGINE=innodb;
+INSERT INTO t1 VALUES (1);
+CREATE TRIGGER t1_bd BEFORE DELETE ON t1 FOR EACH ROW SET @a = 1;
+CREATE TRIGGER t1_ad AFTER DELETE ON t1 FOR EACH ROW SET @b = 1;
+SET @a = 0;
+SET @b = 0;
+TRUNCATE t1;
+SELECT @a, @b;
+@a @b
+0 0
+INSERT INTO t1 VALUES (1);
+DELETE FROM t1;
+SELECT @a, @b;
+@a @b
+1 1
+DROP TABLE t2, t1;
End of 5.0 tests
diff --git a/mysql-test/t/mysql_client_test.test b/mysql-test/t/mysql_client_test.test
index 66a27abd61a..7667522feaf 100644
--- a/mysql-test/t/mysql_client_test.test
+++ b/mysql-test/t/mysql_client_test.test
@@ -8,8 +8,8 @@
# server or run mysql-test-run --debug mysql_client_test and check
# var/log/mysql_client_test.trace
---exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1
---exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.log 2>&1
+--exec echo "$MYSQL_CLIENT_TEST" > $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1
+--exec $MYSQL_CLIENT_TEST --getopt-ll-test=25600M >> $MYSQLTEST_VARDIR/log/mysql_client_test.out.log 2>&1
# End of 4.1 tests
echo ok;
diff --git a/mysql-test/t/trigger-trans.test b/mysql-test/t/trigger-trans.test
index 8103a1ba0b1..5db5b982773 100644
--- a/mysql-test/t/trigger-trans.test
+++ b/mysql-test/t/trigger-trans.test
@@ -128,5 +128,37 @@ drop table t1, t2, t3;
disconnect connection_update;
disconnect connection_aux;
+#
+# Bug#34643: TRUNCATE crash if trigger and foreign key.
+#
+
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+DROP TABLE IF EXISTS t2;
+--enable_warnings
+
+CREATE TABLE t1(a INT PRIMARY KEY) ENGINE=innodb;
+CREATE TABLE t2(b INT, FOREIGN KEY(b) REFERENCES t1(a)) ENGINE=innodb;
+
+INSERT INTO t1 VALUES (1);
+
+CREATE TRIGGER t1_bd BEFORE DELETE ON t1 FOR EACH ROW SET @a = 1;
+CREATE TRIGGER t1_ad AFTER DELETE ON t1 FOR EACH ROW SET @b = 1;
+
+SET @a = 0;
+SET @b = 0;
+
+TRUNCATE t1;
+
+SELECT @a, @b;
+
+INSERT INTO t1 VALUES (1);
+
+DELETE FROM t1;
+
+SELECT @a, @b;
+
+DROP TABLE t2, t1;
+
--echo End of 5.0 tests
diff --git a/sql-common/client.c b/sql-common/client.c
index d4aceffe227..88774ce61e1 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -669,11 +669,12 @@ my_bool
cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
const char *header, ulong header_length,
const char *arg, ulong arg_length, my_bool skip_check,
- MYSQL_STMT *stmt __attribute__((unused)))
+ MYSQL_STMT *stmt)
{
NET *net= &mysql->net;
my_bool result= 1;
init_sigpipe_variables
+ my_bool stmt_skip= stmt ? stmt->state != MYSQL_STMT_INIT_DONE : FALSE;
DBUG_ENTER("cli_advanced_command");
/* Don't give sigpipe errors if the client doesn't want them */
@@ -681,7 +682,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
if (mysql->net.vio == 0)
{ /* Do reconnect if possible */
- if (mysql_reconnect(mysql))
+ if (mysql_reconnect(mysql) || stmt_skip)
DBUG_RETURN(1);
}
if (mysql->status != MYSQL_STATUS_READY ||
@@ -712,7 +713,7 @@ cli_advanced_command(MYSQL *mysql, enum enum_server_command command,
goto end;
}
end_server(mysql);
- if (mysql_reconnect(mysql))
+ if (mysql_reconnect(mysql) || stmt_skip)
goto end;
if (net_write_command(net,(uchar) command, header, header_length,
arg, arg_length))
@@ -2518,6 +2519,9 @@ my_bool mysql_reconnect(MYSQL *mysql)
if (stmt->state != MYSQL_STMT_INIT_DONE)
{
stmt->mysql= 0;
+ stmt->last_errno= CR_SERVER_LOST;
+ strmov(stmt->last_error, ER(CR_SERVER_LOST));
+ strmov(stmt->sqlstate, unknown_sqlstate);
}
else
{
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index a28a39a769d..3019b68d6f1 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -35,6 +35,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
READ_RECORD info;
bool using_limit=limit != HA_POS_ERROR;
bool transactional_table, safe_update, const_cond;
+ bool triggers_applicable;
ha_rows deleted;
uint usable_index= MAX_KEY;
SELECT_LEX *select_lex= &thd->lex->select_lex;
@@ -93,6 +94,11 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
select_lex->no_error= thd->lex->ignore;
+ /* NOTE: TRUNCATE must not invoke triggers. */
+
+ triggers_applicable= table->triggers &&
+ thd->lex->sql_command != SQLCOM_TRUNCATE;
+
/*
Test if the user wants to delete all rows and deletion doesn't have
any side-effects (because of triggers), so we can use optimized
@@ -102,8 +108,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
*/
if (!using_limit && const_cond && (!conds || conds->val_int()) &&
!(specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) &&
- (thd->lex->sql_command == SQLCOM_TRUNCATE ||
- !(table->triggers && table->triggers->has_delete_triggers()))
+ !(triggers_applicable && table->triggers->has_delete_triggers())
)
{
deleted= table->file->records;
@@ -217,7 +222,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
init_ftfuncs(thd, select_lex, 1);
thd->proc_info="updating";
- if (table->triggers)
+ if (triggers_applicable)
{
table->triggers->mark_fields_used(thd, TRG_EVENT_DELETE);
if (table->triggers->has_triggers(TRG_EVENT_DELETE,
@@ -239,7 +244,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (!(select && select->skip_record())&& !thd->net.report_error )
{
- if (table->triggers &&
+ if (triggers_applicable &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_BEFORE, FALSE))
{
@@ -250,7 +255,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
if (!(error=table->file->delete_row(table->record[0])))
{
deleted++;
- if (table->triggers &&
+ if (triggers_applicable &&
table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
TRG_ACTION_AFTER, FALSE))
{
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 18cfd8d7dfc..b00606aba4a 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -2516,7 +2516,7 @@ void mysql_stmt_close(THD *thd, char *packet)
DBUG_ENTER("mysql_stmt_close");
if (!(stmt= find_prepared_statement(thd, stmt_id, "mysql_stmt_close")))
- DBUG_VOID_RETURN;
+ goto out;
/*
The only way currently a statement can be deallocated when it's
@@ -2525,6 +2525,9 @@ void mysql_stmt_close(THD *thd, char *packet)
DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE));
(void) stmt->deallocate();
+out:
+ /* clear errors, response packet is not expected */
+ thd->clear_error();
DBUG_VOID_RETURN;
}
@@ -2591,10 +2594,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
#ifndef EMBEDDED_LIBRARY
/* Minimal size of long data packet is 6 bytes */
if (packet_length <= MYSQL_LONG_DATA_HEADER)
- {
- my_error(ER_WRONG_ARGUMENTS, MYF(0), "mysql_stmt_send_long_data");
- DBUG_VOID_RETURN;
- }
+ goto out;
#endif
stmt_id= uint4korr(packet);
@@ -2602,7 +2602,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
if (!(stmt=find_prepared_statement(thd, stmt_id,
"mysql_stmt_send_long_data")))
- DBUG_VOID_RETURN;
+ goto out;
param_number= uint2korr(packet);
packet+= 2;
@@ -2614,7 +2614,7 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
stmt->last_errno= ER_WRONG_ARGUMENTS;
sprintf(stmt->last_error, ER(ER_WRONG_ARGUMENTS),
"mysql_stmt_send_long_data");
- DBUG_VOID_RETURN;
+ goto out;
}
#endif
@@ -2630,6 +2630,10 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
stmt->last_errno= ER_OUTOFMEMORY;
sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
}
+
+out:
+ /* clear errors, response packet is not expected */
+ thd->clear_error();
DBUG_VOID_RETURN;
}
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index dbe22f2a9e4..e3b76e79f6e 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -11746,6 +11746,7 @@ static void test_bug5194()
rc= mysql_stmt_execute(stmt);
check_execute(stmt, rc);
+ mysql_stmt_reset(stmt);
}
mysql_stmt_close(stmt);
@@ -15952,83 +15953,6 @@ static void test_bug27592()
DBUG_VOID_RETURN;
}
-#if 0
-
-static void test_bug29948()
-{
- MYSQL *dbc=NULL;
- MYSQL_STMT *stmt=NULL;
- MYSQL_BIND bind;
-
- int res=0;
- my_bool auto_reconnect=1, error=0, is_null=0;
- char kill_buf[20];
- const char *query;
- int buf;
- unsigned long length, cursor_type;
-
- dbc = mysql_init(NULL);
- DIE_UNLESS(dbc);
-
- mysql_options(dbc, MYSQL_OPT_RECONNECT, (char*)&auto_reconnect);
- if (!mysql_real_connect(dbc, opt_host, opt_user,
- opt_password, current_db, opt_port,
- opt_unix_socket,
- (CLIENT_FOUND_ROWS | CLIENT_MULTI_STATEMENTS |
- CLIENT_MULTI_RESULTS)))
- {
- printf("connection failed: %s (%d)", mysql_error(dbc),
- mysql_errno(dbc));
- exit(1);
- }
-
- bzero(&bind, sizeof(bind));
- bind.buffer_type= MYSQL_TYPE_LONG;
- bind.buffer= (char *)&buf;
- bind.is_null= &is_null;
- bind.error= &error;
- bind.length= &length;
-
- res= mysql_query(dbc, "DROP TABLE IF EXISTS t1");
- myquery(res);
- res= mysql_query(dbc, "CREATE TABLE t1 (a INT)");
- myquery(res);
- res= mysql_query(dbc, "INSERT INTO t1 VALUES(1)");
- myquery(res);
-
- stmt= mysql_stmt_init(dbc);
- check_stmt(stmt);
-
- cursor_type= CURSOR_TYPE_READ_ONLY;
- res= mysql_stmt_attr_set(stmt, STMT_ATTR_CURSOR_TYPE, (void *)&cursor_type);
- myquery(res);
-
- query= "SELECT * from t1 where a=?";
- res= mysql_stmt_prepare(stmt, query, strlen(query));
- myquery(res);
-
- res= mysql_stmt_bind_param(stmt, &bind);
- myquery(res);
-
- res= mysql_stmt_execute(stmt);
- check_execute(stmt, res);
-
- res= mysql_stmt_bind_result(stmt,&bind);
- check_execute(stmt, res);
-
- sprintf(kill_buf, "kill %ld", dbc->thread_id);
- mysql_query(dbc, kill_buf);
-
- res= mysql_stmt_store_result(stmt);
- DIE_UNLESS(res);
-
- mysql_stmt_free_result(stmt);
- mysql_stmt_close(stmt);
- mysql_query(dbc, "DROP TABLE t1");
- mysql_close(dbc);
-}
-
-#endif
/**
Bug#29306 Truncated data in MS Access with decimal (3,1) columns in a VIEW
@@ -16556,7 +16480,6 @@ static struct my_tests_st my_tests[]= {
{ "test_bug28505", test_bug28505 },
{ "test_bug28934", test_bug28934 },
{ "test_bug27592", test_bug27592 },
- /* { "test_bug29948", test_bug29948 }, Bug#35103 */
{ "test_bug29306", test_bug29306 },
{ "test_bug31669", test_bug31669 },
{ "test_bug32265", test_bug32265 },