summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libmysql/libmysql.c16
-rw-r--r--libmysqld/lib_sql.cc17
-rw-r--r--mysql-test/r/func_in.result9
-rw-r--r--mysql-test/r/func_str.result13
-rw-r--r--mysql-test/r/rpl_trigger.result27
-rw-r--r--mysql-test/r/trigger.result22
-rw-r--r--mysql-test/t/func_in.test26
-rw-r--r--mysql-test/t/func_str.test15
-rw-r--r--mysql-test/t/rpl_trigger.test37
-rw-r--r--mysql-test/t/trigger.test28
-rw-r--r--sql/item_cmpfunc.cc1
-rw-r--r--sql/item_strfunc.cc14
-rw-r--r--sql/item_strfunc.h6
-rw-r--r--sql/sql_cache.cc42
-rw-r--r--sql/sql_trigger.cc104
-rw-r--r--sql/sql_yacc.yy5
-rw-r--r--tests/mysql_client_test.c78
17 files changed, 394 insertions, 66 deletions
diff --git a/libmysql/libmysql.c b/libmysql/libmysql.c
index 21fb84fb19a..276bdec18e7 100644
--- a/libmysql/libmysql.c
+++ b/libmysql/libmysql.c
@@ -2478,6 +2478,8 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
NET *net= &mysql->net;
char buff[4 /* size of stmt id */ +
5 /* execution flags */];
+ my_bool res;
+
DBUG_ENTER("execute");
DBUG_DUMP("packet", packet, length);
@@ -2485,16 +2487,18 @@ static my_bool execute(MYSQL_STMT *stmt, char *packet, ulong length)
int4store(buff, stmt->stmt_id); /* Send stmt id to server */
buff[4]= (char) stmt->flags;
int4store(buff+5, 1); /* iteration count */
- if (cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
- packet, length, 1, NULL) ||
- (*mysql->methods->read_query_result)(mysql))
+
+ res= test(cli_advanced_command(mysql, COM_STMT_EXECUTE, buff, sizeof(buff),
+ packet, length, 1, NULL) ||
+ (*mysql->methods->read_query_result)(mysql));
+ stmt->affected_rows= mysql->affected_rows;
+ stmt->server_status= mysql->server_status;
+ stmt->insert_id= mysql->insert_id;
+ if (res)
{
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
DBUG_RETURN(1);
}
- stmt->affected_rows= mysql->affected_rows;
- stmt->server_status= mysql->server_status;
- stmt->insert_id= mysql->insert_id;
DBUG_RETURN(0);
}
diff --git a/libmysqld/lib_sql.cc b/libmysqld/lib_sql.cc
index 98c75dfe719..93b1ed5c81d 100644
--- a/libmysqld/lib_sql.cc
+++ b/libmysqld/lib_sql.cc
@@ -277,26 +277,27 @@ static int emb_stmt_execute(MYSQL_STMT *stmt)
{
DBUG_ENTER("emb_stmt_execute");
char header[5];
- MYSQL_DATA *res;
THD *thd;
+ my_bool res;
int4store(header, stmt->stmt_id);
header[4]= stmt->flags;
thd= (THD*)stmt->mysql->thd;
thd->client_param_count= stmt->param_count;
thd->client_params= stmt->params;
- if (emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE,0,0,
- header, sizeof(header), 1, stmt) ||
- emb_read_query_result(stmt->mysql))
+
+ res= test(emb_advanced_command(stmt->mysql, COM_STMT_EXECUTE, 0, 0,
+ header, sizeof(header), 1, stmt) ||
+ emb_read_query_result(stmt->mysql));
+ stmt->affected_rows= stmt->mysql->affected_rows;
+ stmt->insert_id= stmt->mysql->insert_id;
+ stmt->server_status= stmt->mysql->server_status;
+ if (res)
{
NET *net= &stmt->mysql->net;
set_stmt_errmsg(stmt, net->last_error, net->last_errno, net->sqlstate);
DBUG_RETURN(1);
}
- stmt->affected_rows= stmt->mysql->affected_rows;
- stmt->insert_id= stmt->mysql->insert_id;
- stmt->server_status= stmt->mysql->server_status;
-
DBUG_RETURN(0);
}
diff --git a/mysql-test/r/func_in.result b/mysql-test/r/func_in.result
index e38e2624e19..a172d04d880 100644
--- a/mysql-test/r/func_in.result
+++ b/mysql-test/r/func_in.result
@@ -202,6 +202,14 @@ select count(*) from t1 where id not in (1,2);
count(*)
1
drop table t1;
+DROP TABLE IF EXISTS t1;
+CREATE TABLE t1 SELECT 1 IN (2, NULL);
+SELECT should return NULL.
+SELECT * FROM t1;
+1 IN (2, NULL)
+NULL
+DROP TABLE t1;
+End of 4.1 tests
CREATE TABLE t1 (a int PRIMARY KEY);
INSERT INTO t1 VALUES (44), (45), (46);
SELECT * FROM t1 WHERE a IN (45);
@@ -343,3 +351,4 @@ some_id
1
2
drop table t1;
+End of 5.0 tests
diff --git a/mysql-test/r/func_str.result b/mysql-test/r/func_str.result
index e5342eec54f..14c61a2dd93 100644
--- a/mysql-test/r/func_str.result
+++ b/mysql-test/r/func_str.result
@@ -1903,4 +1903,17 @@ Warnings:
Error 1292 Truncated incorrect DECIMAL value: ''
Error 1292 Truncated incorrect DECIMAL value: ''
Warning 1301 Result of lpad() was larger than max_allowed_packet (1048576) - truncated
+SET @orig_sql_mode = @@SQL_MODE;
+SET SQL_MODE=traditional;
+SELECT CHAR(0xff,0x8f USING utf8);
+CHAR(0xff,0x8f USING utf8)
+NULL
+Warnings:
+Error 1300 Invalid utf8 character string: 'FF8F'
+SELECT CHAR(0xff,0x8f USING utf8) IS NULL;
+CHAR(0xff,0x8f USING utf8) IS NULL
+1
+Warnings:
+Error 1300 Invalid utf8 character string: 'FF8F'
+SET SQL_MODE=@orig_sql_mode;
End of 5.0 tests
diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result
index 3c740bf8e64..f8573eec75f 100644
--- a/mysql-test/r/rpl_trigger.result
+++ b/mysql-test/r/rpl_trigger.result
@@ -941,3 +941,30 @@ c
---> Cleaning up...
DROP TABLE t1;
DROP TABLE t2;
+drop table if exists t1;
+create table t1(a int, b varchar(50));
+drop trigger not_a_trigger;
+ERROR HY000: Trigger does not exist
+drop trigger if exists not_a_trigger;
+Warnings:
+Note 1360 Trigger does not exist
+create trigger t1_bi before insert on t1
+for each row set NEW.b := "In trigger t1_bi";
+insert into t1 values (1, "a");
+drop trigger if exists t1_bi;
+insert into t1 values (2, "b");
+drop trigger if exists t1_bi;
+Warnings:
+Note 1360 Trigger does not exist
+insert into t1 values (3, "c");
+select * from t1;
+a b
+1 In trigger t1_bi
+2 b
+3 c
+select * from t1;
+a b
+1 In trigger t1_bi
+2 b
+3 c
+drop table t1;
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
index 9d3ab9b1d7d..9f34f60eb1a 100644
--- a/mysql-test/r/trigger.result
+++ b/mysql-test/r/trigger.result
@@ -1256,4 +1256,26 @@ select @a;
20
drop table t1;
drop function f1;
+drop table if exists t1;
+create table t1(a int, b varchar(50));
+drop trigger not_a_trigger;
+ERROR HY000: Trigger does not exist
+drop trigger if exists not_a_trigger;
+Warnings:
+Note 1360 Trigger does not exist
+create trigger t1_bi before insert on t1
+for each row set NEW.b := "In trigger t1_bi";
+insert into t1 values (1, "a");
+drop trigger if exists t1_bi;
+insert into t1 values (2, "b");
+drop trigger if exists t1_bi;
+Warnings:
+Note 1360 Trigger does not exist
+insert into t1 values (3, "c");
+select * from t1;
+a b
+1 In trigger t1_bi
+2 b
+3 c
+drop table t1;
End of 5.0 tests
diff --git a/mysql-test/t/func_in.test b/mysql-test/t/func_in.test
index 8ddf1fbe314..d48606ac6e6 100644
--- a/mysql-test/t/func_in.test
+++ b/mysql-test/t/func_in.test
@@ -109,7 +109,28 @@ select count(*) from t1 where id not in (1);
select count(*) from t1 where id not in (1,2);
drop table t1;
-# End of 4.1 tests
+
+#
+# BUG#17047: CHAR() and IN() can return NULL without signaling NULL
+# result
+#
+# The problem was in the IN() function that ignored maybe_null flags
+# of all arguments except the first (the one _before_ the IN
+# keyword, '1' in the test case below).
+#
+--disable_warnings
+DROP TABLE IF EXISTS t1;
+--enable_warnings
+
+CREATE TABLE t1 SELECT 1 IN (2, NULL);
+--echo SELECT should return NULL.
+SELECT * FROM t1;
+
+DROP TABLE t1;
+
+
+--echo End of 4.1 tests
+
#
# Bug #11885: WHERE condition with NOT IN (one element)
@@ -232,3 +253,6 @@ select some_id from t1 where some_id not in(2,-1);
select some_id from t1 where some_id not in(-4,-1,-4);
select some_id from t1 where some_id not in(-4,-1,3423534,2342342);
drop table t1;
+
+
+--echo End of 5.0 tests
diff --git a/mysql-test/t/func_str.test b/mysql-test/t/func_str.test
index 9622de96143..83a2c0a9029 100644
--- a/mysql-test/t/func_str.test
+++ b/mysql-test/t/func_str.test
@@ -780,6 +780,7 @@ SELECT * FROM t1 INNER JOIN t2 ON code=id
DROP TABLE t1,t2;
+
#
# Bug #10963
# 4294967296 18446744073709551616
@@ -969,4 +970,18 @@ select lpad('hello', 18446744073709551616, '1');
select lpad('hello', -18446744073709551617, '1');
select lpad('hello', 18446744073709551617, '1');
+
+#
+# BUG#17047: CHAR() and IN() can return NULL without signaling NULL
+# result
+#
+SET @orig_sql_mode = @@SQL_MODE;
+SET SQL_MODE=traditional;
+
+SELECT CHAR(0xff,0x8f USING utf8);
+SELECT CHAR(0xff,0x8f USING utf8) IS NULL;
+
+SET SQL_MODE=@orig_sql_mode;
+
+
--echo End of 5.0 tests
diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test
index d6e9410b1d3..faba89e7a73 100644
--- a/mysql-test/t/rpl_trigger.test
+++ b/mysql-test/t/rpl_trigger.test
@@ -423,6 +423,43 @@ DROP TABLE t2;
--sync_with_master
--connection master
+#
+# BUG#23703: DROP TRIGGER needs an IF EXISTS
+#
+
+connection master;
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1(a int, b varchar(50));
+
+-- error ER_TRG_DOES_NOT_EXIST
+drop trigger not_a_trigger;
+
+drop trigger if exists not_a_trigger;
+
+create trigger t1_bi before insert on t1
+for each row set NEW.b := "In trigger t1_bi";
+
+insert into t1 values (1, "a");
+drop trigger if exists t1_bi;
+insert into t1 values (2, "b");
+drop trigger if exists t1_bi;
+insert into t1 values (3, "c");
+
+select * from t1;
+
+save_master_pos;
+connection slave;
+sync_with_master;
+
+select * from t1;
+
+connection master;
+
+drop table t1;
#
# End of tests
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
index 81334f9b8ef..a9395c12a63 100644
--- a/mysql-test/t/trigger.test
+++ b/mysql-test/t/trigger.test
@@ -1519,4 +1519,32 @@ connection default;
drop table t1;
drop function f1;
+#
+# Bug#23703: DROP TRIGGER needs an IF EXISTS
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+create table t1(a int, b varchar(50));
+
+-- error ER_TRG_DOES_NOT_EXIST
+drop trigger not_a_trigger;
+
+drop trigger if exists not_a_trigger;
+
+create trigger t1_bi before insert on t1
+for each row set NEW.b := "In trigger t1_bi";
+
+insert into t1 values (1, "a");
+drop trigger if exists t1_bi;
+insert into t1 values (2, "b");
+drop trigger if exists t1_bi;
+insert into t1 values (3, "c");
+
+select * from t1;
+
+drop table t1;
+
--echo End of 5.0 tests
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 9a400d60ae6..70a8622af85 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2465,7 +2465,6 @@ void Item_func_in::fix_length_and_dec()
if (cmp_type == STRING_RESULT)
in_item->cmp_charset= cmp_collation.collation;
}
- maybe_null= args[0]->maybe_null;
max_length= 1;
}
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index c2f16ffac10..e8d46293065 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -80,6 +80,20 @@ String *Item_str_func::check_well_formed_result(String *str)
}
+bool Item_str_func::fix_fields(THD *thd, Item **ref)
+{
+ bool res= Item_func::fix_fields(thd, ref);
+ /*
+ In Item_str_func::check_well_formed_result() we may set null_value
+ flag on the same condition as in test() below.
+ */
+ maybe_null= (maybe_null ||
+ test(thd->variables.sql_mode &
+ (MODE_STRICT_TRANS_TABLES | MODE_STRICT_ALL_TABLES)));
+ return res;
+}
+
+
my_decimal *Item_str_func::val_decimal(my_decimal *decimal_value)
{
DBUG_ASSERT(fixed == 1);
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 528180b803d..fd2aaf19675 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -37,6 +37,7 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
void left_right_max_length();
String *check_well_formed_result(String *str);
+ bool fix_fields(THD *thd, Item **ref);
};
class Item_func_md5 :public Item_str_func
@@ -525,9 +526,8 @@ public:
{ collation.set(cs); }
String *val_str(String *);
void fix_length_and_dec()
- {
- maybe_null=0;
- max_length=arg_count * collation.collation->mbmaxlen;
+ {
+ max_length= arg_count * collation.collation->mbmaxlen;
}
const char *func_name() const { return "char"; }
};
diff --git a/sql/sql_cache.cc b/sql/sql_cache.cc
index ff033b69f98..1d8c79d0a1a 100644
--- a/sql/sql_cache.cc
+++ b/sql/sql_cache.cc
@@ -702,6 +702,7 @@ void query_cache_abort(NET *net)
void query_cache_end_of_result(THD *thd)
{
+ Query_cache_block *query_block;
DBUG_ENTER("query_cache_end_of_result");
/* See the comment on double-check locking usage above. */
@@ -717,13 +718,9 @@ void query_cache_end_of_result(THD *thd)
if (unlikely(query_cache.query_cache_size == 0 ||
query_cache.flush_in_progress))
- {
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
- DBUG_VOID_RETURN;
- }
+ goto end;
- Query_cache_block *query_block= ((Query_cache_block*)
- thd->net.query_cache_query);
+ query_block= ((Query_cache_block*) thd->net.query_cache_query);
if (query_block)
{
DUMP(&query_cache);
@@ -742,27 +739,25 @@ void query_cache_end_of_result(THD *thd)
header->query()));
query_cache.wreck(__LINE__, "");
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
-
- DBUG_VOID_RETURN;
+ /*
+ We do not need call of BLOCK_UNLOCK_WR(query_block); here because
+ query_cache.wreck() switched query cache off but left content
+ untouched for investigation (it is debugging method).
+ */
+ goto end;
}
#endif
header->found_rows(current_thd->limit_found_rows);
header->result()->type= Query_cache_block::RESULT;
header->writer(0);
thd->net.query_cache_query= 0;
+ BLOCK_UNLOCK_WR(query_block);
DBUG_EXECUTE("check_querycache",query_cache.check_integrity(1););
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
-
- BLOCK_UNLOCK_WR(query_block);
- }
- else
- {
- // Cache was flushed or resized and query was deleted => do nothing
- STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
}
+end:
+ STRUCT_UNLOCK(&query_cache.structure_guard_mutex);
DBUG_VOID_RETURN;
}
@@ -3529,7 +3524,7 @@ uint Query_cache::filename_2_table_key (char *key, const char *path,
#if defined(DBUG_OFF) && !defined(USE_QUERY_CACHE_INTEGRITY_CHECK)
-void wreck(uint line, const char *message) {}
+void wreck(uint line, const char *message) { query_cache_size = 0; }
void bins_dump() {}
void cache_dump() {}
void queries_dump() {}
@@ -3541,6 +3536,17 @@ my_bool in_blocks(Query_cache_block * point) { return 0; }
#else
+
+/*
+ Debug method which switch query cache off but left content for
+ investigation.
+
+ SYNOPSIS
+ Query_cache::wreck()
+ line line of the wreck() call
+ message message for logging
+*/
+
void Query_cache::wreck(uint line, const char *message)
{
THD *thd=current_thd;
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 95734d31411..3552fc596f3 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -107,7 +107,9 @@ const LEX_STRING trg_event_type_names[]=
};
-static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig);
+static int
+add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
+ TABLE_LIST ** table);
class Handle_old_incorrect_sql_modes_hook: public Unknown_key_hook
{
@@ -156,6 +158,13 @@ private:
*/
bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
{
+ /*
+ FIXME: The code below takes too many different paths depending on the
+ 'create' flag, so that the justification for a single function
+ 'mysql_create_or_drop_trigger', compared to two separate functions
+ 'mysql_create_trigger' and 'mysql_drop_trigger' is not apparent.
+ This is a good candidate for a minor refactoring.
+ */
TABLE *table;
bool result= TRUE;
String stmt_query;
@@ -181,10 +190,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
}
- if (!create &&
- !(tables= add_table_for_trigger(thd, thd->lex->spname)))
- DBUG_RETURN(TRUE);
-
/*
We don't allow creating triggers on tables in the 'mysql' schema
*/
@@ -194,9 +199,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
}
- /* We should have only one table in table list. */
- DBUG_ASSERT(tables->next_global == 0);
-
/*
TODO: We should check if user has TRIGGER privilege for table here.
Now we just require SUPER privilege for creating/dropping because
@@ -211,7 +213,7 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DROP for example) so we do the check for privileges. For now there is
already a stronger test right above; but when this stronger test will
be removed, the test below will hold. Because triggers have the same
- nature as functions regarding binlogging: their body is implicitely
+ nature as functions regarding binlogging: their body is implicitly
binlogged, so they share the same danger, so trust_function_creators
applies to them too.
*/
@@ -222,24 +224,52 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
DBUG_RETURN(TRUE);
}
- /* We do not allow creation of triggers on temporary tables. */
- if (create && find_temporary_table(thd, tables->db, tables->table_name))
- {
- my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
- DBUG_RETURN(TRUE);
- }
-
/*
We don't want perform our operations while global read lock is held
- so we have to wait until its end and then prevent it from occuring
+ so we have to wait until its end and then prevent it from occurring
again until we are done. (Acquiring LOCK_open is not enough because
- global read lock is held without helding LOCK_open).
+ global read lock is held without holding LOCK_open).
*/
if (wait_if_global_read_lock(thd, 0, 1))
DBUG_RETURN(TRUE);
VOID(pthread_mutex_lock(&LOCK_open));
+ if (!create)
+ {
+ bool if_exists= thd->lex->drop_if_exists;
+
+ if (add_table_for_trigger(thd, thd->lex->spname, if_exists, & tables))
+ goto end;
+
+ if (!tables)
+ {
+ DBUG_ASSERT(if_exists);
+ /*
+ Since the trigger does not exist, there is no associated table,
+ and therefore :
+ - no TRIGGER privileges to check,
+ - no trigger to drop,
+ - no table to lock/modify,
+ so the drop statement is successful.
+ */
+ result= FALSE;
+ /* Still, we need to log the query ... */
+ stmt_query.append(thd->query, thd->query_length);
+ goto end;
+ }
+ }
+
+ /* We should have only one table in table list. */
+ DBUG_ASSERT(tables->next_global == 0);
+
+ /* We do not allow creation of triggers on temporary tables. */
+ if (create && find_temporary_table(thd, tables->db, tables->table_name))
+ {
+ my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
+ goto end;
+ }
+
if (lock_table_names(thd, tables))
goto end;
@@ -1145,13 +1175,17 @@ bool Table_triggers_list::get_trigger_info(THD *thd, trg_event_type event,
mysql_table_for_trigger()
thd - current thread context
trig - identifier for trigger
+ if_exists - treat a not existing trigger as a warning if TRUE
+ table - pointer to TABLE_LIST object for the table trigger (output)
RETURN VALUE
- 0 - error
- # - pointer to TABLE_LIST object for the table
+ 0 Success
+ 1 Error
*/
-static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
+static int
+add_table_for_trigger(THD *thd, sp_name *trig, bool if_exists,
+ TABLE_LIST **table)
{
LEX *lex= thd->lex;
char path_buff[FN_REFLEN];
@@ -1162,6 +1196,7 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
path_buff, &trigname.trigger_table);
DBUG_ENTER("add_table_for_trigger");
+ DBUG_ASSERT(table != NULL);
strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", trig->m_db.str, "/",
trig->m_name.str, trigname_file_ext, NullS);
@@ -1170,30 +1205,45 @@ static TABLE_LIST *add_table_for_trigger(THD *thd, sp_name *trig)
if (access(path_buff, F_OK))
{
+ if (if_exists)
+ {
+ push_warning_printf(thd,
+ MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_TRG_DOES_NOT_EXIST,
+ ER(ER_TRG_DOES_NOT_EXIST));
+ *table= NULL;
+ DBUG_RETURN(0);
+ }
+
my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
}
if (!(parser= sql_parse_prepare(&path, thd->mem_root, 1)))
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
if (!is_equal(&trigname_file_type, parser->type()))
{
my_error(ER_WRONG_OBJECT, MYF(0), trig->m_name.str, trigname_file_ext+1,
"TRIGGERNAME");
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
}
if (parser->parse((gptr)&trigname, thd->mem_root,
trigname_file_parameters, 1,
&trigger_table_hook))
- DBUG_RETURN(0);
+ DBUG_RETURN(1);
/* We need to reset statement table list to be PS/SP friendly. */
lex->query_tables= 0;
lex->query_tables_last= &lex->query_tables;
- DBUG_RETURN(sp_add_to_query_tables(thd, lex, trig->m_db.str,
- trigname.trigger_table.str, TL_IGNORE));
+ *table= sp_add_to_query_tables(thd, lex, trig->m_db.str,
+ trigname.trigger_table.str, TL_IGNORE);
+
+ if (! *table)
+ DBUG_RETURN(1);
+
+ DBUG_RETURN(0);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 6f24a42c07c..21325123baa 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -6098,11 +6098,12 @@ drop:
lex->sql_command= SQLCOM_DROP_VIEW;
lex->drop_if_exists= $3;
}
- | DROP TRIGGER_SYM sp_name
+ | DROP TRIGGER_SYM if_exists sp_name
{
LEX *lex= Lex;
lex->sql_command= SQLCOM_DROP_TRIGGER;
- lex->spname= $3;
+ lex->drop_if_exists= $3;
+ lex->spname= $4;
}
;
diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c
index da7fde469ad..4f552af772f 100644
--- a/tests/mysql_client_test.c
+++ b/tests/mysql_client_test.c
@@ -15308,6 +15308,83 @@ static void test_bug21726()
/*
+ BUG#23383: mysql_affected_rows() returns different values than
+ mysql_stmt_affected_rows()
+
+ Test that both mysql_affected_rows() and mysql_stmt_affected_rows()
+ return -1 on error, 0 when no rows were affected, and (positive) row
+ count when some rows were affected.
+*/
+static void test_bug23383()
+{
+ const char *insert_query= "INSERT INTO t1 VALUES (1), (2)";
+ const char *update_query= "UPDATE t1 SET i= 4 WHERE i = 3";
+ MYSQL_STMT *stmt;
+ my_ulonglong row_count;
+ int rc;
+
+ DBUG_ENTER("test_bug23383");
+ myheader("test_bug23383");
+
+ rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
+ myquery(rc);
+
+ rc= mysql_query(mysql, "CREATE TABLE t1 (i INT UNIQUE)");
+ myquery(rc);
+
+ rc= mysql_query(mysql, insert_query);
+ myquery(rc);
+ row_count= mysql_affected_rows(mysql);
+ DIE_UNLESS(row_count == 2);
+
+ rc= mysql_query(mysql, insert_query);
+ DIE_UNLESS(rc != 0);
+ row_count= mysql_affected_rows(mysql);
+ DIE_UNLESS(row_count == (my_ulonglong)-1);
+
+ rc= mysql_query(mysql, update_query);
+ myquery(rc);
+ row_count= mysql_affected_rows(mysql);
+ DIE_UNLESS(row_count == 0);
+
+ rc= mysql_query(mysql, "DELETE FROM t1");
+ myquery(rc);
+
+ stmt= mysql_stmt_init(mysql);
+ DIE_UNLESS(stmt != 0);
+
+ rc= mysql_stmt_prepare(stmt, insert_query, strlen(insert_query));
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ row_count= mysql_stmt_affected_rows(stmt);
+ DIE_UNLESS(row_count == 2);
+
+ rc= mysql_stmt_execute(stmt);
+ DIE_UNLESS(rc != 0);
+ row_count= mysql_stmt_affected_rows(stmt);
+ DIE_UNLESS(row_count == (my_ulonglong)-1);
+
+ rc= mysql_stmt_prepare(stmt, update_query, strlen(update_query));
+ check_execute(stmt, rc);
+
+ rc= mysql_stmt_execute(stmt);
+ check_execute(stmt, rc);
+ row_count= mysql_stmt_affected_rows(stmt);
+ DIE_UNLESS(row_count == 0);
+
+ rc= mysql_stmt_close(stmt);
+ check_execute(stmt, rc);
+
+ rc= mysql_query(mysql, "DROP TABLE t1");
+ myquery(rc);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
Read and parse arguments and MySQL options from my.cnf
*/
@@ -15583,6 +15660,7 @@ static struct my_tests_st my_tests[]= {
{ "test_bug15752", test_bug15752 },
{ "test_bug21206", test_bug21206 },
{ "test_bug21726", test_bug21726 },
+ { "test_bug23383", test_bug23383 },
{ 0, 0 }
};