Merge bk-internal.mysql.com:/home/bk/mysql-4.1
into bodhi.local:/opt/local/work/mysql-4.1-runtime
This commit is contained in:
commit
6a28c436f7
@ -104,3 +104,19 @@ SELECT `id1` FROM `t1` WHERE `id1` NOT IN (SELECT `id1` FROM `t2` WHERE `id2` =
|
||||
id1
|
||||
2
|
||||
DROP TABLE t1, t2;
|
||||
DROP TABLE IF EXISTS t2, t1;
|
||||
CREATE TABLE t1 (i INT NOT NULL PRIMARY KEY) ENGINE= InnoDB;
|
||||
CREATE TABLE t2 (
|
||||
i INT NOT NULL,
|
||||
FOREIGN KEY (i) REFERENCES t1 (i) ON DELETE NO ACTION
|
||||
) ENGINE= InnoDB;
|
||||
INSERT INTO t1 VALUES (1);
|
||||
INSERT INTO t2 VALUES (1);
|
||||
DELETE IGNORE FROM t1 WHERE i = 1;
|
||||
Warnings:
|
||||
Error 1217 Cannot delete or update a parent row: a foreign key constraint fails
|
||||
SELECT * FROM t1, t2;
|
||||
i i
|
||||
1 1
|
||||
DROP TABLE t2, t1;
|
||||
End of 4.1 tests.
|
||||
|
@ -936,3 +936,100 @@ GROUP_CONCAT(Track SEPARATOR ', ')
|
||||
CAD
|
||||
DEALLOCATE PREPARE STMT;
|
||||
DROP TABLE t1;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (i INT, INDEX(i));
|
||||
INSERT INTO t1 VALUES (1);
|
||||
PREPARE stmt FROM "SELECT (COUNT(i) = 1), COUNT(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(COUNT(i) = 1) COUNT(i)
|
||||
0 0
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(COUNT(i) = 1) COUNT(i)
|
||||
1 1
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(COUNT(i) = 1) COUNT(i)
|
||||
0 0
|
||||
PREPARE stmt FROM "SELECT (AVG(i) = 1), AVG(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(AVG(i) = 1) AVG(i)
|
||||
NULL NULL
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(AVG(i) = 1) AVG(i)
|
||||
1 1.0000
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(AVG(i) = 1) AVG(i)
|
||||
NULL NULL
|
||||
PREPARE stmt FROM "SELECT (VARIANCE(i) = 1), VARIANCE(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(VARIANCE(i) = 1) VARIANCE(i)
|
||||
NULL NULL
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(VARIANCE(i) = 1) VARIANCE(i)
|
||||
0 0.0000
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(VARIANCE(i) = 1) VARIANCE(i)
|
||||
NULL NULL
|
||||
PREPARE stmt FROM "SELECT (STDDEV(i) = 1), STDDEV(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(STDDEV(i) = 1) STDDEV(i)
|
||||
NULL NULL
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(STDDEV(i) = 1) STDDEV(i)
|
||||
0 0.0000
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(STDDEV(i) = 1) STDDEV(i)
|
||||
NULL NULL
|
||||
PREPARE stmt FROM "SELECT (BIT_OR(i) = 1), BIT_OR(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_OR(i) = 1) BIT_OR(i)
|
||||
0 0
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_OR(i) = 1) BIT_OR(i)
|
||||
1 1
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_OR(i) = 1) BIT_OR(i)
|
||||
0 0
|
||||
PREPARE stmt FROM "SELECT (BIT_AND(i) = 1), BIT_AND(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_AND(i) = 1) BIT_AND(i)
|
||||
0 18446744073709551615
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_AND(i) = 1) BIT_AND(i)
|
||||
1 1
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_AND(i) = 1) BIT_AND(i)
|
||||
0 18446744073709551615
|
||||
PREPARE stmt FROM "SELECT (BIT_XOR(i) = 1), BIT_XOR(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_XOR(i) = 1) BIT_XOR(i)
|
||||
0 0
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_XOR(i) = 1) BIT_XOR(i)
|
||||
1 1
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
(BIT_XOR(i) = 1) BIT_XOR(i)
|
||||
0 0
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
End of 4.1 tests.
|
||||
|
@ -108,6 +108,33 @@ a
|
||||
1
|
||||
drop table t1;
|
||||
drop table t2;
|
||||
DROP TABLE IF EXISTS t1;
|
||||
CREATE TABLE t1 (
|
||||
i INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
j INT DEFAULT 0
|
||||
);
|
||||
INSERT INTO t1 VALUES (NULL, -1);
|
||||
INSERT INTO t1 VALUES (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID(5)),
|
||||
(NULL, @@LAST_INSERT_ID);
|
||||
INSERT INTO t1 VALUES (NULL, 0), (NULL, LAST_INSERT_ID());
|
||||
UPDATE t1 SET j= -1 WHERE i IS NULL;
|
||||
SELECT * FROM t1;
|
||||
i j
|
||||
1 -1
|
||||
2 1
|
||||
3 5
|
||||
4 1
|
||||
5 -1
|
||||
6 2
|
||||
SELECT * FROM t1;
|
||||
i j
|
||||
1 -1
|
||||
2 1
|
||||
3 5
|
||||
4 1
|
||||
5 -1
|
||||
6 2
|
||||
DROP TABLE t1;
|
||||
#
|
||||
# End of 4.1 tests
|
||||
#
|
||||
|
@ -98,7 +98,7 @@ select ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'withou
|
||||
select distinct ifnull(group_concat(concat(t1.id, ':', t1.name)), 'shortname') as 'with distinct: cutoff at length of shortname' from t1;
|
||||
drop table t1;
|
||||
|
||||
# check zero rows
|
||||
# check zero rows (bug#836)
|
||||
create table t1(id int);
|
||||
create table t2(id int);
|
||||
insert into t1 values(0),(1);
|
||||
|
@ -117,3 +117,32 @@ INSERT INTO `t2`(`id1`,`id2`,`id3`,`id4`) VALUES
|
||||
|
||||
SELECT `id1` FROM `t1` WHERE `id1` NOT IN (SELECT `id1` FROM `t2` WHERE `id2` = 1 AND `id3` = 2);
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
|
||||
#
|
||||
# BUG#18819: DELETE IGNORE hangs on foreign key parent delete
|
||||
#
|
||||
# The bug itself does not relate to InnoDB, but we have to use foreign
|
||||
# keys to reproduce it.
|
||||
#
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t2, t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (i INT NOT NULL PRIMARY KEY) ENGINE= InnoDB;
|
||||
CREATE TABLE t2 (
|
||||
i INT NOT NULL,
|
||||
FOREIGN KEY (i) REFERENCES t1 (i) ON DELETE NO ACTION
|
||||
) ENGINE= InnoDB;
|
||||
|
||||
INSERT INTO t1 VALUES (1);
|
||||
INSERT INTO t2 VALUES (1);
|
||||
|
||||
DELETE IGNORE FROM t1 WHERE i = 1;
|
||||
|
||||
SELECT * FROM t1, t2;
|
||||
|
||||
DROP TABLE t2, t1;
|
||||
|
||||
|
||||
--echo End of 4.1 tests.
|
||||
|
@ -951,6 +951,7 @@ execute stmt;
|
||||
drop temporary table t1;
|
||||
deallocate prepare stmt;
|
||||
|
||||
|
||||
#
|
||||
# BUG#22085: Crash on the execution of a prepared statement that
|
||||
# uses an IN subquery with aggregate functions in HAVING
|
||||
@ -1003,4 +1004,76 @@ EXECUTE STMT USING @id,@id;
|
||||
DEALLOCATE PREPARE STMT;
|
||||
DROP TABLE t1;
|
||||
|
||||
# End of 4.1 tests
|
||||
|
||||
#
|
||||
# BUG#21354: (COUNT(*) = 1) not working in SELECT inside prepared
|
||||
# statement
|
||||
#
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (i INT, INDEX(i));
|
||||
INSERT INTO t1 VALUES (1);
|
||||
|
||||
PREPARE stmt FROM "SELECT (COUNT(i) = 1), COUNT(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (AVG(i) = 1), AVG(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (VARIANCE(i) = 1), VARIANCE(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (STDDEV(i) = 1), STDDEV(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (BIT_OR(i) = 1), BIT_OR(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (BIT_AND(i) = 1), BIT_AND(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
PREPARE stmt FROM "SELECT (BIT_XOR(i) = 1), BIT_XOR(i) FROM t1 WHERE i = ?";
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 1;
|
||||
EXECUTE stmt USING @a;
|
||||
SET @a = 0;
|
||||
EXECUTE stmt USING @a;
|
||||
|
||||
DEALLOCATE PREPARE stmt;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo End of 4.1 tests.
|
||||
|
@ -108,6 +108,38 @@ drop table t1;
|
||||
drop table t2;
|
||||
sync_slave_with_master;
|
||||
|
||||
|
||||
#
|
||||
# BUG#21726: Incorrect result with multiple invocations of
|
||||
# LAST_INSERT_ID
|
||||
#
|
||||
connection master;
|
||||
|
||||
--disable_warnings
|
||||
DROP TABLE IF EXISTS t1;
|
||||
--enable_warnings
|
||||
|
||||
CREATE TABLE t1 (
|
||||
i INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
j INT DEFAULT 0
|
||||
);
|
||||
|
||||
INSERT INTO t1 VALUES (NULL, -1);
|
||||
INSERT INTO t1 VALUES (NULL, LAST_INSERT_ID()), (NULL, LAST_INSERT_ID(5)),
|
||||
(NULL, @@LAST_INSERT_ID);
|
||||
# Test replication of substitution "IS NULL" -> "= LAST_INSERT_ID".
|
||||
INSERT INTO t1 VALUES (NULL, 0), (NULL, LAST_INSERT_ID());
|
||||
UPDATE t1 SET j= -1 WHERE i IS NULL;
|
||||
|
||||
SELECT * FROM t1;
|
||||
|
||||
sync_slave_with_master;
|
||||
SELECT * FROM t1;
|
||||
|
||||
connection master;
|
||||
DROP TABLE t1;
|
||||
|
||||
|
||||
--echo #
|
||||
--echo # End of 4.1 tests
|
||||
--echo #
|
||||
|
@ -2250,6 +2250,30 @@ longlong Item_func_release_lock::val_int()
|
||||
}
|
||||
|
||||
|
||||
bool Item_func_last_insert_id::fix_fields(THD *thd, TABLE_LIST *tables,
|
||||
Item **ref)
|
||||
{
|
||||
DBUG_ASSERT(fixed == 0);
|
||||
|
||||
if (Item_int_func::fix_fields(thd, tables, ref))
|
||||
return TRUE;
|
||||
|
||||
if (arg_count == 0)
|
||||
{
|
||||
/*
|
||||
As this statement calls LAST_INSERT_ID(), set
|
||||
THD::last_insert_id_used.
|
||||
*/
|
||||
thd->last_insert_id_used= TRUE;
|
||||
null_value= FALSE;
|
||||
}
|
||||
|
||||
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
longlong Item_func_last_insert_id::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
@ -2259,12 +2283,13 @@ longlong Item_func_last_insert_id::val_int()
|
||||
longlong value=args[0]->val_int();
|
||||
thd->insert_id(value);
|
||||
null_value=args[0]->null_value;
|
||||
return value;
|
||||
}
|
||||
else
|
||||
thd->lex->uncacheable(UNCACHEABLE_SIDEEFFECT);
|
||||
return thd->last_insert_id_used ? thd->current_insert_id : thd->insert_id();
|
||||
|
||||
return thd->current_insert_id;
|
||||
}
|
||||
|
||||
|
||||
/* This function is just used to test speed of different functions */
|
||||
|
||||
longlong Item_func_benchmark::val_int()
|
||||
|
@ -758,6 +758,7 @@ public:
|
||||
longlong val_int();
|
||||
const char *func_name() const { return "last_insert_id"; }
|
||||
void fix_length_and_dec() { if (arg_count) max_length= args[0]->max_length; }
|
||||
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
|
||||
};
|
||||
|
||||
class Item_func_benchmark :public Item_int_func
|
||||
|
@ -312,6 +312,7 @@ longlong Item_sum_count::val_int()
|
||||
void Item_sum_count::cleanup()
|
||||
{
|
||||
DBUG_ENTER("Item_sum_count::cleanup");
|
||||
clear();
|
||||
Item_sum_int::cleanup();
|
||||
used_table_cache= ~(table_map) 0;
|
||||
DBUG_VOID_RETURN;
|
||||
|
@ -58,9 +58,30 @@ public:
|
||||
Item_sum(THD *thd, Item_sum *item);
|
||||
enum Type type() const { return SUM_FUNC_ITEM; }
|
||||
virtual enum Sumfunctype sum_func () const=0;
|
||||
|
||||
/*
|
||||
This method is similar to add(), but it is called when the current
|
||||
aggregation group changes. Thus it performs a combination of
|
||||
clear() and add().
|
||||
*/
|
||||
inline bool reset() { clear(); return add(); };
|
||||
|
||||
/*
|
||||
Prepare this item for evaluation of an aggregate value. This is
|
||||
called by reset() when a group changes, or, for correlated
|
||||
subqueries, between subquery executions. E.g. for COUNT(), this
|
||||
method should set count= 0;
|
||||
*/
|
||||
virtual void clear()= 0;
|
||||
|
||||
/*
|
||||
This method is called for the next row in the same group. Its
|
||||
purpose is to aggregate the new value to the previous values in
|
||||
the group (i.e. since clear() was called last time). For example,
|
||||
for COUNT(), do count++.
|
||||
*/
|
||||
virtual bool add()=0;
|
||||
|
||||
/*
|
||||
Called when new group is started and results are being saved in
|
||||
a temporary table. Similar to reset(), but must also store value in
|
||||
@ -86,7 +107,17 @@ public:
|
||||
void make_field(Send_field *field);
|
||||
void print(String *str);
|
||||
void fix_num_length_and_dec();
|
||||
void no_rows_in_result() { reset(); }
|
||||
|
||||
/*
|
||||
This function is called by the execution engine to assign 'NO ROWS
|
||||
FOUND' value to an aggregate item, when the underlying result set
|
||||
has no rows. Such value, in a general case, may be different from
|
||||
the default value of the item after 'clear()': e.g. a numeric item
|
||||
may be initialized to 0 by clear() and to NULL by
|
||||
no_rows_in_result().
|
||||
*/
|
||||
void no_rows_in_result() { clear(); }
|
||||
|
||||
virtual bool setup(THD *thd) {return 0;}
|
||||
virtual void make_unique() {}
|
||||
Item *get_tmp_table_item(THD *thd);
|
||||
@ -304,6 +335,11 @@ class Item_sum_avg :public Item_sum_num
|
||||
void no_rows_in_result() {}
|
||||
const char *func_name() const { return "avg"; }
|
||||
Item *copy_or_same(THD* thd);
|
||||
void cleanup()
|
||||
{
|
||||
clear();
|
||||
Item_sum_num::cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
class Item_sum_variance;
|
||||
@ -361,6 +397,11 @@ class Item_sum_variance : public Item_sum_num
|
||||
void no_rows_in_result() {}
|
||||
const char *func_name() const { return "variance"; }
|
||||
Item *copy_or_same(THD* thd);
|
||||
void cleanup()
|
||||
{
|
||||
clear();
|
||||
Item_sum_num::cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
class Item_sum_std;
|
||||
@ -485,6 +526,11 @@ public:
|
||||
void update_field();
|
||||
void fix_length_and_dec()
|
||||
{ decimals=0; max_length=21; unsigned_flag=1; maybe_null=null_value=0; }
|
||||
void cleanup()
|
||||
{
|
||||
clear();
|
||||
Item_sum_int::cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -2255,7 +2255,6 @@ int Intvar_log_event::exec_event(struct st_relay_log_info* rli)
|
||||
{
|
||||
switch (type) {
|
||||
case LAST_INSERT_ID_EVENT:
|
||||
thd->last_insert_id_used = 1;
|
||||
thd->last_insert_id = val;
|
||||
break;
|
||||
case INSERT_ID_EVENT:
|
||||
|
@ -95,6 +95,8 @@ MY_LOCALE *my_locale_by_name(const char *name);
|
||||
#define MAX_ACCEPT_RETRY 10 // Test accept this many times
|
||||
#define MAX_FIELDS_BEFORE_HASH 32
|
||||
#define USER_VARS_HASH_SIZE 16
|
||||
#define TABLE_OPEN_CACHE_MIN 64
|
||||
#define TABLE_OPEN_CACHE_DEFAULT 64
|
||||
#define STACK_MIN_SIZE 8192 // Abort if less stack during eval.
|
||||
#define STACK_BUFF_ALLOC 64 // For stack overrun checks
|
||||
#ifndef MYSQLD_NET_RETRY_COUNT
|
||||
|
@ -2526,19 +2526,43 @@ static int init_common_variables(const char *conf_file_name, int argc,
|
||||
|
||||
/* connections and databases needs lots of files */
|
||||
{
|
||||
uint files, wanted_files;
|
||||
uint files, wanted_files, max_open_files;
|
||||
|
||||
wanted_files= 10+(uint) max(max_connections*5,
|
||||
max_connections+table_cache_size*2);
|
||||
set_if_bigger(wanted_files, open_files_limit);
|
||||
files= my_set_max_open_files(wanted_files);
|
||||
/* MyISAM requires two file handles per table. */
|
||||
wanted_files= 10+max_connections+table_cache_size*2;
|
||||
/*
|
||||
We are trying to allocate no less than max_connections*5 file
|
||||
handles (i.e. we are trying to set the limit so that they will
|
||||
be available). In addition, we allocate no less than how much
|
||||
was already allocated. However below we report a warning and
|
||||
recompute values only if we got less file handles than were
|
||||
explicitly requested. No warning and re-computation occur if we
|
||||
can't get max_connections*5 but still got no less than was
|
||||
requested (value of wanted_files).
|
||||
*/
|
||||
max_open_files= max(max(wanted_files, max_connections*5),
|
||||
open_files_limit);
|
||||
files= my_set_max_open_files(max_open_files);
|
||||
|
||||
if (files < wanted_files)
|
||||
{
|
||||
if (!open_files_limit)
|
||||
{
|
||||
max_connections= (ulong) min((files-10),max_connections);
|
||||
table_cache_size= (ulong) max((files-10-max_connections)/2,64);
|
||||
/*
|
||||
If we have requested too much file handles than we bring
|
||||
max_connections in supported bounds.
|
||||
*/
|
||||
max_connections= (ulong) min(files-10-TABLE_OPEN_CACHE_MIN*2,
|
||||
max_connections);
|
||||
/*
|
||||
Decrease table_cache_size according to max_connections, but
|
||||
not below TABLE_OPEN_CACHE_MIN. Outer min() ensures that we
|
||||
never increase table_cache_size automatically (that could
|
||||
happen if max_connections is decreased above).
|
||||
*/
|
||||
table_cache_size= (ulong) min(max((files-10-max_connections)/2,
|
||||
TABLE_OPEN_CACHE_MIN),
|
||||
table_cache_size);
|
||||
DBUG_PRINT("warning",
|
||||
("Changed limits: max_open_files: %u max_connections: %ld table_cache: %ld",
|
||||
files, max_connections, table_cache_size));
|
||||
@ -5511,8 +5535,8 @@ The minimum value for this variable is 4096.",
|
||||
0, 0, 0, 0},
|
||||
{"table_cache", OPT_TABLE_CACHE,
|
||||
"The number of open tables for all threads.", (gptr*) &table_cache_size,
|
||||
(gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L,
|
||||
0, 1, 0},
|
||||
(gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG,
|
||||
TABLE_OPEN_CACHE_DEFAULT, 1, 512*1024L, 0, 1, 0},
|
||||
{"thread_cache_size", OPT_THREAD_CACHE_SIZE,
|
||||
"How many threads we should keep in a cache for reuse.",
|
||||
(gptr*) &thread_cache_size, (gptr*) &thread_cache_size, 0, GET_ULONG,
|
||||
|
@ -2404,8 +2404,12 @@ bool sys_var_last_insert_id::update(THD *thd, set_var *var)
|
||||
byte *sys_var_last_insert_id::value_ptr(THD *thd, enum_var_type type,
|
||||
LEX_STRING *base)
|
||||
{
|
||||
thd->sys_var_tmp.long_value= (long) thd->insert_id();
|
||||
return (byte*) &thd->last_insert_id;
|
||||
/*
|
||||
As this statement reads @@LAST_INSERT_ID, set
|
||||
THD::last_insert_id_used.
|
||||
*/
|
||||
thd->last_insert_id_used= TRUE;
|
||||
return (byte*) &thd->current_insert_id;
|
||||
}
|
||||
|
||||
|
||||
|
@ -835,17 +835,29 @@ public:
|
||||
generated auto_increment value in handler.cc
|
||||
*/
|
||||
ulonglong next_insert_id;
|
||||
|
||||
/*
|
||||
The insert_id used for the last statement or set by SET LAST_INSERT_ID=#
|
||||
or SELECT LAST_INSERT_ID(#). Used for binary log and returned by
|
||||
LAST_INSERT_ID()
|
||||
At the beginning of the statement last_insert_id holds the first
|
||||
generated value of the previous statement. During statement
|
||||
execution it is updated to the value just generated, but then
|
||||
restored to the value that was generated first, so for the next
|
||||
statement it will again be "the first generated value of the
|
||||
previous statement".
|
||||
|
||||
It may also be set with "LAST_INSERT_ID(expr)" or
|
||||
"@@LAST_INSERT_ID= expr", but the effect of such setting will be
|
||||
seen only in the next statement.
|
||||
*/
|
||||
ulonglong last_insert_id;
|
||||
|
||||
/*
|
||||
Set to the first value that LAST_INSERT_ID() returned for the last
|
||||
statement. When this is set, last_insert_id_used is set to true.
|
||||
current_insert_id remembers the first generated value of the
|
||||
previous statement, and does not change during statement
|
||||
execution. Its value returned from LAST_INSERT_ID() and
|
||||
@@LAST_INSERT_ID.
|
||||
*/
|
||||
ulonglong current_insert_id;
|
||||
|
||||
ulonglong limit_found_rows;
|
||||
ha_rows cuted_fields,
|
||||
sent_row_count, examined_row_count;
|
||||
@ -896,7 +908,22 @@ public:
|
||||
bool locked, some_tables_deleted;
|
||||
bool last_cuted_field;
|
||||
bool no_errors, password, is_fatal_error;
|
||||
bool query_start_used,last_insert_id_used,insert_id_used,rand_used;
|
||||
bool query_start_used, rand_used;
|
||||
|
||||
/*
|
||||
last_insert_id_used is set when current statement calls
|
||||
LAST_INSERT_ID() or reads @@LAST_INSERT_ID, so that binary log
|
||||
LAST_INSERT_ID_EVENT be generated.
|
||||
*/
|
||||
bool last_insert_id_used;
|
||||
|
||||
/*
|
||||
insert_id_used is set when current statement updates
|
||||
THD::last_insert_id, so that binary log INSERT_ID_EVENT be
|
||||
generated.
|
||||
*/
|
||||
bool insert_id_used;
|
||||
|
||||
/* for IS NULL => = last_insert_id() fix in remove_eq_conds() */
|
||||
bool substitute_null_with_insert_id;
|
||||
bool time_zone_used;
|
||||
@ -996,15 +1023,6 @@ public:
|
||||
insert_id_used=1;
|
||||
substitute_null_with_insert_id= TRUE;
|
||||
}
|
||||
inline ulonglong insert_id(void)
|
||||
{
|
||||
if (!last_insert_id_used)
|
||||
{
|
||||
last_insert_id_used=1;
|
||||
current_insert_id=last_insert_id;
|
||||
}
|
||||
return last_insert_id;
|
||||
}
|
||||
inline ulonglong found_rows(void)
|
||||
{
|
||||
return limit_found_rows;
|
||||
|
@ -258,7 +258,8 @@ cleanup:
|
||||
mysql_unlock_tables(thd, thd->lock);
|
||||
thd->lock=0;
|
||||
}
|
||||
if (error >= 0 || thd->net.report_error)
|
||||
if ((error >= 0 || thd->net.report_error) &&
|
||||
(!thd->lex->ignore || thd->is_fatal_error))
|
||||
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0);
|
||||
else
|
||||
{
|
||||
|
@ -374,10 +374,8 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
if (error)
|
||||
break;
|
||||
/*
|
||||
If auto_increment values are used, save the first one
|
||||
for LAST_INSERT_ID() and for the update log.
|
||||
We can't use insert_id() as we don't want to touch the
|
||||
last_insert_id_used flag.
|
||||
If auto_increment values are used, save the first one for
|
||||
LAST_INSERT_ID() and for the update log.
|
||||
*/
|
||||
if (! id && thd->insert_id_used)
|
||||
{ // Get auto increment value
|
||||
@ -1687,7 +1685,7 @@ bool select_insert::send_data(List<Item> &values)
|
||||
{
|
||||
table->next_number_field->reset();
|
||||
if (! last_insert_id && thd->insert_id_used)
|
||||
last_insert_id=thd->insert_id();
|
||||
last_insert_id= thd->last_insert_id;
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(error);
|
||||
|
@ -466,10 +466,8 @@ read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
|
||||
if (write_record(table,&info))
|
||||
DBUG_RETURN(1);
|
||||
/*
|
||||
If auto_increment values are used, save the first one
|
||||
for LAST_INSERT_ID() and for the binary/update log.
|
||||
We can't use insert_id() as we don't want to touch the
|
||||
last_insert_id_used flag.
|
||||
If auto_increment values are used, save the first one for
|
||||
LAST_INSERT_ID() and for the binary/update log.
|
||||
*/
|
||||
if (!id && thd->insert_id_used)
|
||||
id= thd->last_insert_id;
|
||||
@ -572,10 +570,8 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
|
||||
if (write_record(table,&info))
|
||||
DBUG_RETURN(1);
|
||||
/*
|
||||
If auto_increment values are used, save the first one
|
||||
for LAST_INSERT_ID() and for the binary/update log.
|
||||
We can't use insert_id() as we don't want to touch the
|
||||
last_insert_id_used flag.
|
||||
If auto_increment values are used, save the first one for
|
||||
LAST_INSERT_ID() and for the binary/update log.
|
||||
*/
|
||||
if (!id && thd->insert_id_used)
|
||||
id= thd->last_insert_id;
|
||||
|
@ -1977,6 +1977,12 @@ mysql_execute_command(THD *thd)
|
||||
SELECT_LEX_UNIT *unit= &lex->unit;
|
||||
DBUG_ENTER("mysql_execute_command");
|
||||
|
||||
/*
|
||||
Remember first generated insert id value of the previous
|
||||
statement.
|
||||
*/
|
||||
thd->current_insert_id= thd->last_insert_id;
|
||||
|
||||
/*
|
||||
Reset warning count for each query that uses tables
|
||||
A better approach would be to reset this for any commands
|
||||
|
@ -4838,7 +4838,7 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
|
||||
Field *field=((Item_field*) args[0])->field;
|
||||
if (field->flags & AUTO_INCREMENT_FLAG && !field->table->maybe_null &&
|
||||
(thd->options & OPTION_AUTO_IS_NULL) &&
|
||||
thd->insert_id() && thd->substitute_null_with_insert_id)
|
||||
thd->current_insert_id && thd->substitute_null_with_insert_id)
|
||||
{
|
||||
#ifdef HAVE_QUERY_CACHE
|
||||
query_cache_abort(&thd->net);
|
||||
@ -4846,9 +4846,16 @@ remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
|
||||
COND *new_cond;
|
||||
if ((new_cond= new Item_func_eq(args[0],
|
||||
new Item_int("last_insert_id()",
|
||||
thd->insert_id(),
|
||||
thd->current_insert_id,
|
||||
21))))
|
||||
{
|
||||
/*
|
||||
Set THD::last_insert_id_used manually, as this statement
|
||||
uses LAST_INSERT_ID() in a sense, and should issue
|
||||
LAST_INSERT_ID_EVENT.
|
||||
*/
|
||||
thd->last_insert_id_used= TRUE;
|
||||
|
||||
cond=new_cond;
|
||||
cond->fix_fields(thd, 0, &cond);
|
||||
}
|
||||
|
@ -408,7 +408,7 @@ int mysql_update(THD *thd,
|
||||
(ulong) thd->cuted_fields);
|
||||
send_ok(thd,
|
||||
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
|
||||
thd->insert_id_used ? thd->insert_id() : 0L,buff);
|
||||
thd->insert_id_used ? thd->last_insert_id : 0L,buff);
|
||||
DBUG_PRINT("info",("%d records updated",updated));
|
||||
}
|
||||
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
|
||||
@ -1324,6 +1324,6 @@ bool multi_update::send_eof()
|
||||
(ulong) thd->cuted_fields);
|
||||
::send_ok(thd,
|
||||
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated,
|
||||
thd->insert_id_used ? thd->insert_id() : 0L,buff);
|
||||
thd->insert_id_used ? thd->last_insert_id : 0L,buff);
|
||||
return 0;
|
||||
}
|
||||
|
@ -11908,6 +11908,43 @@ static void test_bug20152()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Bug#21726: Incorrect result with multiple invocations of
|
||||
LAST_INSERT_ID
|
||||
|
||||
Test that client gets updated value of insert_id on UPDATE that uses
|
||||
LAST_INSERT_ID(expr).
|
||||
*/
|
||||
static void test_bug21726()
|
||||
{
|
||||
const char *update_query = "UPDATE t1 SET i= LAST_INSERT_ID(i + 1)";
|
||||
int rc;
|
||||
my_ulonglong insert_id;
|
||||
|
||||
DBUG_ENTER("test_bug21726");
|
||||
myheader("test_bug21726");
|
||||
|
||||
rc= mysql_query(mysql, "DROP TABLE IF EXISTS t1");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "CREATE TABLE t1 (i INT)");
|
||||
myquery(rc);
|
||||
rc= mysql_query(mysql, "INSERT INTO t1 VALUES (1)");
|
||||
myquery(rc);
|
||||
|
||||
rc= mysql_query(mysql, update_query);
|
||||
myquery(rc);
|
||||
insert_id= mysql_insert_id(mysql);
|
||||
DIE_UNLESS(insert_id == 2);
|
||||
|
||||
rc= mysql_query(mysql, update_query);
|
||||
myquery(rc);
|
||||
insert_id= mysql_insert_id(mysql);
|
||||
DIE_UNLESS(insert_id == 3);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read and parse arguments and MySQL options from my.cnf
|
||||
*/
|
||||
@ -12134,6 +12171,7 @@ static struct my_tests_st my_tests[]= {
|
||||
{ "test_bug12925", test_bug12925 },
|
||||
{ "test_bug15613", test_bug15613 },
|
||||
{ "test_bug20152", test_bug20152 },
|
||||
{ "test_bug21726", test_bug21726 },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user