Commit a0f201b2 authored by joreland@mysql.com's avatar joreland@mysql.com

Merge joreland@bk-internal.mysql.com:/home/bk/mysql-5.0

into mysql.com:/home/jonas/src/mysql-5.0
parents 1839f740 9eca8dce
...@@ -279,7 +279,15 @@ rec_get_next_offs( ...@@ -279,7 +279,15 @@ rec_get_next_offs(
/* Note that for 64 KiB pages, field_value can 'wrap around' /* Note that for 64 KiB pages, field_value can 'wrap around'
and the debug assertion is not valid */ and the debug assertion is not valid */
ut_ad((int16_t)field_value /* In the following assertion, field_value is interpreted
as signed 16-bit integer in 2's complement arithmetics.
If all platforms defined int16_t in the standard headers,
the expression could be written simpler as
(int16_t) field_value + ut_align_offset(...) < UNIV_PAGE_SIZE
*/
ut_ad((field_value >= 32768
? field_value - 65536
: field_value)
+ ut_align_offset(rec, UNIV_PAGE_SIZE) + ut_align_offset(rec, UNIV_PAGE_SIZE)
< UNIV_PAGE_SIZE); < UNIV_PAGE_SIZE);
#endif #endif
......
...@@ -225,6 +225,21 @@ trx_savepoint_for_mysql( ...@@ -225,6 +225,21 @@ trx_savepoint_for_mysql(
position corresponding to this position corresponding to this
connection at the time of the connection at the time of the
savepoint */ savepoint */
/***********************************************************************
Releases a named savepoint. Savepoints which
were set after this savepoint are deleted. */
ulint
trx_release_savepoint_for_mysql(
/*================================*/
/* out: if no savepoint
of the name found then
DB_NO_SAVEPOINT,
otherwise DB_SUCCESS */
trx_t* trx, /* in: transaction handle */
const char* savepoint_name); /* in: savepoint name */
/*********************************************************************** /***********************************************************************
Frees savepoint structs. */ Frees savepoint structs. */
......
...@@ -316,6 +316,51 @@ trx_savepoint_for_mysql( ...@@ -316,6 +316,51 @@ trx_savepoint_for_mysql(
return(DB_SUCCESS); return(DB_SUCCESS);
} }
/***********************************************************************
Releases a named savepoint. Savepoints which
were set after this savepoint are deleted. */
ulint
trx_release_savepoint_for_mysql(
/*================================*/
/* out: if no savepoint
of the name found then
DB_NO_SAVEPOINT,
otherwise DB_SUCCESS */
trx_t* trx, /* in: transaction handle */
const char* savepoint_name) /* in: savepoint name */
{
trx_named_savept_t* savep;
savep = UT_LIST_GET_FIRST(trx->trx_savepoints);
while (savep != NULL) {
if (0 == ut_strcmp(savep->name, savepoint_name)) {
/* Found */
break;
}
savep = UT_LIST_GET_NEXT(trx_savepoints, savep);
}
if (savep == NULL) {
return(DB_NO_SAVEPOINT);
}
/* We can now free all savepoints strictly later than this one */
trx_roll_savepoints_free(trx, savep);
/* Now we can free this savepoint too */
UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep);
mem_free(savep->name);
mem_free(savep);
return(DB_SUCCESS);
}
/*********************************************************************** /***********************************************************************
Returns a transaction savepoint taken at this point in time. */ Returns a transaction savepoint taken at this point in time. */
......
...@@ -371,11 +371,11 @@ alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(20 ...@@ -371,11 +371,11 @@ alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(20
update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500;
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
from t0 as A, t0 as B from t0 as A, t0 as B
where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7or16 = 1 or A.key8=1)
and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1); and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7or16 = 1 or B.key8=1);
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7,i8 i2,i3,i4,i5,i6,i8 4,4,4,4,4,4 NULL 16 Using union(intersect(i2,i3,i4,i5,i6),i8); Using where 1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL 7or16 Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where
1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7,i8 i2,i3,i4,i5,i6,i8 4,4,4,4,4,4 NULL 16 Using union(intersect(i2,i3,i4,i5,i6),i8); Using where 1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7?,i8 i2,i3,i4,i5,i6,i7?,i8 X NULL 7or16 Using union(intersect(i2,i3,i4,i5,i6,i7?),i8); Using where
select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
from t0 as A, t0 as B from t0 as A, t0 as B
where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1)
......
...@@ -249,6 +249,30 @@ n ...@@ -249,6 +249,30 @@ n
4 4
5 5
6 6
set autocommit=0;
begin;
savepoint `my_savepoint`;
insert into t1 values (7);
savepoint `savept2`;
insert into t1 values (3);
select n from t1;
n
3
4
5
6
7
rollback to savepoint `savept2`;
release savepoint `my_savepoint`;
select n from t1;
n
4
5
6
7
rollback to savepoint `my_savepoint`;
ERROR HY000: Got error 153 during ROLLBACK
set autocommit=1;
rollback; rollback;
drop table t1; drop table t1;
create table t1 (n int not null primary key) engine=innodb; create table t1 (n int not null primary key) engine=innodb;
...@@ -1609,14 +1633,14 @@ t2 CREATE TABLE `t2` ( ...@@ -1609,14 +1633,14 @@ t2 CREATE TABLE `t2` (
drop table t2, t1; drop table t2, t1;
show status like "binlog_cache_use"; show status like "binlog_cache_use";
Variable_name Value Variable_name Value
Binlog_cache_use 24 Binlog_cache_use 25
show status like "binlog_cache_disk_use"; show status like "binlog_cache_disk_use";
Variable_name Value Variable_name Value
Binlog_cache_disk_use 0 Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb; create table t1 (a int) engine=innodb;
show status like "binlog_cache_use"; show status like "binlog_cache_use";
Variable_name Value Variable_name Value
Binlog_cache_use 25 Binlog_cache_use 26
show status like "binlog_cache_disk_use"; show status like "binlog_cache_disk_use";
Variable_name Value Variable_name Value
Binlog_cache_disk_use 1 Binlog_cache_disk_use 1
...@@ -1625,7 +1649,7 @@ delete from t1; ...@@ -1625,7 +1649,7 @@ delete from t1;
commit; commit;
show status like "binlog_cache_use"; show status like "binlog_cache_use";
Variable_name Value Variable_name Value
Binlog_cache_use 26 Binlog_cache_use 27
show status like "binlog_cache_disk_use"; show status like "binlog_cache_disk_use";
Variable_name Value Variable_name Value
Binlog_cache_disk_use 1 Binlog_cache_disk_use 1
...@@ -1693,10 +1717,10 @@ Variable_name Value ...@@ -1693,10 +1717,10 @@ Variable_name Value
Innodb_rows_deleted 2070 Innodb_rows_deleted 2070
show status like "Innodb_rows_inserted"; show status like "Innodb_rows_inserted";
Variable_name Value Variable_name Value
Innodb_rows_inserted 31706 Innodb_rows_inserted 31708
show status like "Innodb_rows_read"; show status like "Innodb_rows_read";
Variable_name Value Variable_name Value
Innodb_rows_read 80153 Innodb_rows_read 80162
show status like "Innodb_rows_updated"; show status like "Innodb_rows_updated";
Variable_name Value Variable_name Value
Innodb_rows_updated 29530 Innodb_rows_updated 29530
......
...@@ -306,6 +306,11 @@ select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 ...@@ -306,6 +306,11 @@ select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4
alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200); alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200);
update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500; update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500;
# The next query will not use index i7 in intersection if the OS doesn't
# support file sizes > 2GB. (ha_myisam::ref_length depends on this and index
# scan cost estimates depend on ha_myisam::ref_length)
--replace_result "4,4,4,4,4,4,4" X "4,4,4,4,4,4" X "i6,i7" "i6,i7?" "i6" "i6,i7?" 7 7or16 16 7or16
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5) explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
from t0 as A, t0 as B from t0 as A, t0 as B
where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1) where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1)
......
...@@ -129,6 +129,19 @@ insert into t1 values (6); ...@@ -129,6 +129,19 @@ insert into t1 values (6);
-- error 1062 -- error 1062
insert into t1 values (4); insert into t1 values (4);
select n from t1; select n from t1;
set autocommit=0;
begin;
savepoint `my_savepoint`;
insert into t1 values (7);
savepoint `savept2`;
insert into t1 values (3);
select n from t1;
rollback to savepoint `savept2`;
release savepoint `my_savepoint`;
select n from t1;
-- error 1181
rollback to savepoint `my_savepoint`;
set autocommit=1;
# nop # nop
rollback; rollback;
drop table t1; drop table t1;
......
...@@ -1612,6 +1612,31 @@ innobase_rollback_to_savepoint( ...@@ -1612,6 +1612,31 @@ innobase_rollback_to_savepoint(
DBUG_RETURN(convert_error_code_to_mysql(error, NULL)); DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
} }
/*********************************************************************
Release transaction savepoint name. */
int
innobase_release_savepoint_name(
/*===========================*/
/* out: 0 if success, HA_ERR_NO_SAVEPOINT if
no savepoint with the given name */
THD* thd, /* in: handle to the MySQL thread of the user
whose transaction should be rolled back */
char* savepoint_name) /* in: savepoint name */
{
ib_longlong mysql_binlog_cache_pos;
int error = 0;
trx_t* trx;
DBUG_ENTER("innobase_release_savepoint_name");
trx = check_trx_exists(thd);
error = trx_release_savepoint_for_mysql(trx, savepoint_name);
DBUG_RETURN(convert_error_code_to_mysql(error, NULL));
}
/********************************************************************* /*********************************************************************
Sets a transaction savepoint. */ Sets a transaction savepoint. */
......
...@@ -244,6 +244,9 @@ int innobase_savepoint( ...@@ -244,6 +244,9 @@ int innobase_savepoint(
THD* thd, THD* thd,
char* savepoint_name, char* savepoint_name,
my_off_t binlog_cache_pos); my_off_t binlog_cache_pos);
int innobase_release_savepoint_name(
THD* thd,
char* savepoint_name);
int innobase_close_connection(THD *thd); int innobase_close_connection(THD *thd);
int innobase_drop_database(char *path); int innobase_drop_database(char *path);
bool innodb_show_status(THD* thd); bool innodb_show_status(THD* thd);
......
...@@ -869,6 +869,35 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name) ...@@ -869,6 +869,35 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
DBUG_RETURN(error); DBUG_RETURN(error);
} }
int ha_release_savepoint_name(THD *thd, char *savepoint_name)
{
my_off_t binlog_cache_pos=0;
bool operation_done=0;
int error=0;
DBUG_ENTER("ha_release_savepoint_name");
#ifdef USING_TRANSACTIONS
if (opt_using_transactions)
{
#ifdef HAVE_INNOBASE_DB
if ((error=innobase_release_savepoint_name(thd, savepoint_name)))
{
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), error);
error=1;
}
else if (mysql_bin_log.is_open())
{
Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE, FALSE);
if (mysql_bin_log.write(&qinfo))
error= 1;
}
operation_done=1;
#endif
}
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
/* /*
Sets a transaction savepoint. Sets a transaction savepoint.
......
...@@ -653,6 +653,7 @@ int ha_commit_trans(THD *thd, THD_TRANS *trans); ...@@ -653,6 +653,7 @@ int ha_commit_trans(THD *thd, THD_TRANS *trans);
int ha_rollback_trans(THD *thd, THD_TRANS *trans); int ha_rollback_trans(THD *thd, THD_TRANS *trans);
int ha_rollback_to_savepoint(THD *thd, char *savepoint_name); int ha_rollback_to_savepoint(THD *thd, char *savepoint_name);
int ha_savepoint(THD *thd, char *savepoint_name); int ha_savepoint(THD *thd, char *savepoint_name);
int ha_release_savepoint_name(THD *thd, char *savepoint_name);
int ha_autocommit_or_rollback(THD *thd, int error); int ha_autocommit_or_rollback(THD *thd, int error);
void ha_set_spin_retries(uint retries); void ha_set_spin_retries(uint retries);
bool ha_flush_logs(void); bool ha_flush_logs(void);
......
...@@ -99,6 +99,7 @@ static SYMBOL symbols[] = { ...@@ -99,6 +99,7 @@ static SYMBOL symbols[] = {
{ "CASCADE", SYM(CASCADE)}, { "CASCADE", SYM(CASCADE)},
{ "CASCADED", SYM(CASCADED)}, { "CASCADED", SYM(CASCADED)},
{ "CASE", SYM(CASE_SYM)}, { "CASE", SYM(CASE_SYM)},
{ "CHAIN", SYM(CHAIN_SYM)},
{ "CHANGE", SYM(CHANGE)}, { "CHANGE", SYM(CHANGE)},
{ "CHANGED", SYM(CHANGED)}, { "CHANGED", SYM(CHANGED)},
{ "CHAR", SYM(CHAR_SYM)}, { "CHAR", SYM(CHAR_SYM)},
...@@ -385,6 +386,7 @@ static SYMBOL symbols[] = { ...@@ -385,6 +386,7 @@ static SYMBOL symbols[] = {
{ "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)}, { "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)},
{ "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM)}, { "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM)},
{ "RELAY_THREAD", SYM(RELAY_THREAD)}, { "RELAY_THREAD", SYM(RELAY_THREAD)},
{ "RELEASE", SYM(RELEASE_SYM)},
{ "RELOAD", SYM(RELOAD)}, { "RELOAD", SYM(RELOAD)},
{ "RENAME", SYM(RENAME)}, { "RENAME", SYM(RENAME)},
{ "REPAIR", SYM(REPAIR)}, { "REPAIR", SYM(REPAIR)},
......
...@@ -4176,7 +4176,7 @@ enum options_mysqld ...@@ -4176,7 +4176,7 @@ enum options_mysqld
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ, OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION, OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION,
OPT_SKIP_SAFEMALLOC, OPT_SKIP_SAFEMALLOC,
OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_TEMP_POOL, OPT_TX_ISOLATION, OPT_COMPLETION_TYPE,
OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS, OPT_SKIP_STACK_TRACE, OPT_SKIP_SYMLINKS,
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL, OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
OPT_SAFE_USER_CREATE, OPT_SQL_MODE, OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
...@@ -4363,6 +4363,10 @@ Disable with --skip-bdb (will save memory).", ...@@ -4363,6 +4363,10 @@ Disable with --skip-bdb (will save memory).",
{"collation-server", OPT_DEFAULT_COLLATION, "Set the default collation.", {"collation-server", OPT_DEFAULT_COLLATION, "Set the default collation.",
(gptr*) &default_collation_name, (gptr*) &default_collation_name, (gptr*) &default_collation_name, (gptr*) &default_collation_name,
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 }, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
{"completion-type", OPT_COMPLETION_TYPE, "Default completion type.",
(gptr*) &global_system_variables.completion_type,
(gptr*) &max_system_variables.completion_type, 0, GET_ULONG,
REQUIRED_ARG, 0, 0, 2, 0, 1, 0},
{"concurrent-insert", OPT_CONCURRENT_INSERT, {"concurrent-insert", OPT_CONCURRENT_INSERT,
"Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.", "Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.",
(gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert,
......
...@@ -100,6 +100,8 @@ static int check_pseudo_thread_id(THD *thd, set_var *var); ...@@ -100,6 +100,8 @@ static int check_pseudo_thread_id(THD *thd, set_var *var);
static bool set_log_bin(THD *thd, set_var *var); static bool set_log_bin(THD *thd, set_var *var);
static void fix_low_priority_updates(THD *thd, enum_var_type type); static void fix_low_priority_updates(THD *thd, enum_var_type type);
static void fix_tx_isolation(THD *thd, enum_var_type type); static void fix_tx_isolation(THD *thd, enum_var_type type);
static int check_completion_type(THD *thd, set_var *var);
static void fix_completion_type(THD *thd, enum_var_type type);
static void fix_net_read_timeout(THD *thd, enum_var_type type); static void fix_net_read_timeout(THD *thd, enum_var_type type);
static void fix_net_write_timeout(THD *thd, enum_var_type type); static void fix_net_write_timeout(THD *thd, enum_var_type type);
static void fix_net_retry_count(THD *thd, enum_var_type type); static void fix_net_retry_count(THD *thd, enum_var_type type);
...@@ -149,6 +151,10 @@ sys_var_character_set_database sys_character_set_database("character_set_databas ...@@ -149,6 +151,10 @@ sys_var_character_set_database sys_character_set_database("character_set_databas
sys_var_character_set_client sys_character_set_client("character_set_client"); sys_var_character_set_client sys_character_set_client("character_set_client");
sys_var_character_set_connection sys_character_set_connection("character_set_connection"); sys_var_character_set_connection sys_character_set_connection("character_set_connection");
sys_var_character_set_results sys_character_set_results("character_set_results"); sys_var_character_set_results sys_character_set_results("character_set_results");
sys_var_thd_ulong sys_completion_type("completion_type",
&SV::completion_type,
check_completion_type,
fix_completion_type);
sys_var_collation_connection sys_collation_connection("collation_connection"); sys_var_collation_connection sys_collation_connection("collation_connection");
sys_var_collation_database sys_collation_database("collation_database"); sys_var_collation_database sys_collation_database("collation_database");
sys_var_collation_server sys_collation_server("collation_server"); sys_var_collation_server sys_collation_server("collation_server");
...@@ -532,6 +538,7 @@ sys_var *sys_variables[]= ...@@ -532,6 +538,7 @@ sys_var *sys_variables[]=
&sys_collation_connection, &sys_collation_connection,
&sys_collation_database, &sys_collation_database,
&sys_collation_server, &sys_collation_server,
&sys_completion_type,
&sys_concurrent_insert, &sys_concurrent_insert,
&sys_connect_timeout, &sys_connect_timeout,
&sys_date_format, &sys_date_format,
...@@ -708,6 +715,7 @@ struct show_var_st init_vars[]= { ...@@ -708,6 +715,7 @@ struct show_var_st init_vars[]= {
{sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS}, {sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS},
{sys_collation_database.name,(char*) &sys_collation_database, SHOW_SYS}, {sys_collation_database.name,(char*) &sys_collation_database, SHOW_SYS},
{sys_collation_server.name,(char*) &sys_collation_server, SHOW_SYS}, {sys_collation_server.name,(char*) &sys_collation_server, SHOW_SYS},
{sys_completion_type.name, (char*) &sys_completion_type, SHOW_SYS},
{sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS}, {sys_concurrent_insert.name,(char*) &sys_concurrent_insert, SHOW_SYS},
{sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS}, {sys_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
{"datadir", mysql_real_data_home, SHOW_CHAR}, {"datadir", mysql_real_data_home, SHOW_CHAR},
...@@ -1122,6 +1130,21 @@ static void fix_tx_isolation(THD *thd, enum_var_type type) ...@@ -1122,6 +1130,21 @@ static void fix_tx_isolation(THD *thd, enum_var_type type)
thd->variables.tx_isolation); thd->variables.tx_isolation);
} }
static void fix_completion_type(THD *thd __attribute__(unused),
enum_var_type type __attribute__(unused)) {}
static int check_completion_type(THD *thd, set_var *var)
{
longlong val= var->value->val_int();
if (val < 0 || val > 2)
{
char buf[64];
my_error(ER_WRONG_VALUE_FOR_VAR, MYF(0), var->var->name, llstr(val, buf));
return 1;
}
return 0;
}
/* /*
If we are changing the thread variable, we have to copy it to NET too If we are changing the thread variable, we have to copy it to NET too
......
...@@ -408,6 +408,7 @@ struct system_variables ...@@ -408,6 +408,7 @@ struct system_variables
ulong table_type; ulong table_type;
ulong tmp_table_size; ulong tmp_table_size;
ulong tx_isolation; ulong tx_isolation;
ulong completion_type;
/* Determines which non-standard SQL behaviour should be enabled */ /* Determines which non-standard SQL behaviour should be enabled */
ulong sql_mode; ulong sql_mode;
/* check of key presence in updatable view */ /* check of key presence in updatable view */
......
...@@ -67,7 +67,7 @@ enum enum_sql_command { ...@@ -67,7 +67,7 @@ enum enum_sql_command {
SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS, SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS,
SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE, SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT, SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT,
SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT,
SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP, SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER, SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER,
SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE, SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
...@@ -718,6 +718,7 @@ typedef struct st_lex ...@@ -718,6 +718,7 @@ typedef struct st_lex
uint8 create_view_check; uint8 create_view_check;
bool drop_if_exists, drop_temporary, local_file, one_shot_set; bool drop_if_exists, drop_temporary, local_file, one_shot_set;
bool in_comment, ignore_space, verbose, no_write_to_binlog; bool in_comment, ignore_space, verbose, no_write_to_binlog;
bool tx_chain, tx_release;
/* special JOIN::prepare mode: changing of query is prohibited */ /* special JOIN::prepare mode: changing of query is prohibited */
bool view_prepare_mode; bool view_prepare_mode;
bool safe_to_cache_query; bool safe_to_cache_query;
......
...@@ -134,6 +134,28 @@ static bool end_active_trans(THD *thd) ...@@ -134,6 +134,28 @@ static bool end_active_trans(THD *thd)
DBUG_RETURN(error); DBUG_RETURN(error);
} }
static bool begin_trans(THD *thd)
{
int error=0;
if (thd->locked_tables)
{
thd->lock=thd->locked_tables;
thd->locked_tables=0; // Will be automatically closed
close_thread_tables(thd); // Free tables
}
if (end_active_trans(thd))
error= -1;
else
{
LEX *lex= thd->lex;
thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
if (lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT)
error= ha_start_consistent_snapshot(thd);
}
return error;
}
#ifdef HAVE_REPLICATION #ifdef HAVE_REPLICATION
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables) inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
...@@ -1262,6 +1284,127 @@ err: ...@@ -1262,6 +1284,127 @@ err:
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/*
Ends the current transaction and (maybe) begin the next
First uint4 in packet is completion type
Remainder is savepoint name (if required)
SYNOPSIS
mysql_endtrans()
thd Current thread
completion Completion type
savepoint_name Savepoint when doing ROLLBACK_SAVEPOINT_NAME
or RELEASE_SAVEPOINT_NAME
release (OUT) indicator for release operation
RETURN
0 - OK
*/
enum enum_mysql_completiontype {
ROLLBACK_RELEASE=-2,
COMMIT_RELEASE=-1,
COMMIT=0,
ROLLBACK=1,
SAVEPOINT_NAME_ROLLBACK=2,
SAVEPOINT_NAME_RELEASE=4,
COMMIT_AND_CHAIN=6,
ROLLBACK_AND_CHAIN=7,
};
int mysql_endtrans(THD *thd, enum enum_mysql_completiontype completion,
char *savepoint_name)
{
bool do_release= 0;
int res= 0;
LEX *lex= thd->lex;
DBUG_ENTER("mysql_endtrans");
switch (completion) {
case COMMIT:
/*
We don't use end_active_trans() here to ensure that this works
even if there is a problem with the OPTION_AUTO_COMMIT flag
(Which of course should never happen...)
*/
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!(res= ha_commit(thd)))
send_ok(thd);
break;
case COMMIT_RELEASE:
do_release= 1;
case COMMIT_AND_CHAIN:
res= end_active_trans(thd);
if (!res && completion == COMMIT_AND_CHAIN)
res= begin_trans(thd);
if (!res)
send_ok(thd);
break;
case ROLLBACK_RELEASE:
do_release= 1;
case ROLLBACK:
case ROLLBACK_AND_CHAIN:
{
bool warn= 0;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_rollback(thd))
{
/*
If a non-transactional table was updated, warn; don't warn if this is a
slave thread (because when a slave thread executes a ROLLBACK, it has
been read from the binary log, so it's 100% sure and normal to produce
error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
slave SQL thread, it would not stop the thread but just be printed in
the error log; but we don't want users to wonder why they have this
message in the error log, so we don't send it.
*/
warn= (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
!thd->slave_thread;
}
else
res= -1;
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
if (!res && (completion == ROLLBACK_AND_CHAIN))
res= begin_trans(thd);
if (!res)
{
if (warn)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
send_ok(thd);
}
break;
}
case SAVEPOINT_NAME_ROLLBACK:
if (!(res=ha_rollback_to_savepoint(thd, savepoint_name)))
{
if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
send_ok(thd);
}
break;
case SAVEPOINT_NAME_RELEASE:
if (!(res=ha_release_savepoint_name(thd, savepoint_name)))
send_ok(thd);
break;
default:
res= -1;
my_error(ER_UNKNOWN_COM_ERROR, MYF(0));
DBUG_RETURN(-1);
}
if (res < 0)
my_error(thd->killed_errno(), MYF(0));
else if ((res == 0) && do_release)
thd->killed= THD::KILL_CONNECTION;
DBUG_RETURN(res);
}
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
...@@ -3648,74 +3791,23 @@ unsent_create_error: ...@@ -3648,74 +3791,23 @@ unsent_create_error:
break; break;
case SQLCOM_BEGIN: case SQLCOM_BEGIN:
if (thd->locked_tables) if (begin_trans(thd))
{
thd->lock=thd->locked_tables;
thd->locked_tables=0; // Will be automatically closed
close_thread_tables(thd); // Free tables
}
if (end_active_trans(thd))
goto error; goto error;
else else
{
thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
if (!(lex->start_transaction_opt & MYSQL_START_TRANS_OPT_WITH_CONS_SNAPSHOT) ||
!(res= ha_start_consistent_snapshot(thd)))
send_ok(thd); send_ok(thd);
}
break; break;
case SQLCOM_COMMIT: case SQLCOM_COMMIT:
/* if (mysql_endtrans(thd, lex->tx_release ? COMMIT_RELEASE :
We don't use end_active_trans() here to ensure that this works lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT, 0))
even if there is a problem with the OPTION_AUTO_COMMIT flag
(Which of course should never happen...)
*/
{
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
if (!ha_commit(thd))
{
send_ok(thd);
}
else
goto error; goto error;
break; break;
}
case SQLCOM_ROLLBACK: case SQLCOM_ROLLBACK:
thd->server_status&= ~SERVER_STATUS_IN_TRANS; if (mysql_endtrans(thd, lex->tx_release ? ROLLBACK_RELEASE :
if (!ha_rollback(thd)) lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK, 0))
{ goto error;
/*
If a non-transactional table was updated, warn; don't warn if this is a
slave thread (because when a slave thread executes a ROLLBACK, it has
been read from the binary log, so it's 100% sure and normal to produce
error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
slave SQL thread, it would not stop the thread but just be printed in
the error log; but we don't want users to wonder why they have this
message in the error log, so we don't send it.
*/
if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
send_ok(thd);
}
else
res= TRUE;
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
break; break;
case SQLCOM_ROLLBACK_TO_SAVEPOINT: case SQLCOM_ROLLBACK_TO_SAVEPOINT:
if (!ha_rollback_to_savepoint(thd, lex->savepoint_name)) if (mysql_endtrans(thd, SAVEPOINT_NAME_ROLLBACK, lex->savepoint_name))
{
if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
send_ok(thd);
}
else
goto error; goto error;
break; break;
case SQLCOM_SAVEPOINT: case SQLCOM_SAVEPOINT:
...@@ -3724,6 +3816,10 @@ unsent_create_error: ...@@ -3724,6 +3816,10 @@ unsent_create_error:
else else
goto error; goto error;
break; break;
case SQLCOM_RELEASE_SAVEPOINT:
if (mysql_endtrans(thd, SAVEPOINT_NAME_RELEASE, lex->savepoint_name))
goto error;
break;
case SQLCOM_CREATE_PROCEDURE: case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SPFUNCTION: case SQLCOM_CREATE_SPFUNCTION:
{ {
......
...@@ -219,6 +219,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -219,6 +219,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CASCADE %token CASCADE
%token CASCADED %token CASCADED
%token CAST_SYM %token CAST_SYM
%token CHAIN_SYM
%token CHARSET %token CHARSET
%token CHECKSUM_SYM %token CHECKSUM_SYM
%token CHECK_SYM %token CHECK_SYM
...@@ -385,6 +386,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -385,6 +386,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token REDUNDANT_SYM %token REDUNDANT_SYM
%token REFERENCES %token REFERENCES
%token REGEXP %token REGEXP
%token RELEASE_SYM
%token RELOAD %token RELOAD
%token RENAME %token RENAME
%token REPEATABLE_SYM %token REPEATABLE_SYM
...@@ -690,7 +692,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -690,7 +692,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type table_option opt_if_not_exists opt_no_write_to_binlog opt_var_type
opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct
opt_ignore_leaves fulltext_options spatial_type union_option opt_ignore_leaves fulltext_options spatial_type union_option
start_transaction_opts start_transaction_opts opt_chain opt_work_and_chain opt_release
%type <ulong_num> %type <ulong_num>
ULONG_NUM raid_types merge_insert_types ULONG_NUM raid_types merge_insert_types
...@@ -777,7 +779,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -777,7 +779,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
query verb_clause create change select do drop insert replace insert2 query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename insert_values update delete truncate rename
show describe load alter optimize keycache preload flush show describe load alter optimize keycache preload flush
reset purge begin commit rollback savepoint reset purge begin commit rollback savepoint release
slave master_def master_defs master_file_def slave_until_opts slave master_def master_defs master_file_def slave_until_opts
repair restore backup analyze check start checksum repair restore backup analyze check start checksum
field_list field_list_item field_spec kill column_def key_def field_list field_list_item field_spec kill column_def key_def
...@@ -876,6 +878,7 @@ statement: ...@@ -876,6 +878,7 @@ statement:
| preload | preload
| prepare | prepare
| purge | purge
| release
| rename | rename
| repair | repair
| replace | replace
...@@ -6901,6 +6904,7 @@ keyword: ...@@ -6901,6 +6904,7 @@ keyword:
| BTREE_SYM {} | BTREE_SYM {}
| CACHE_SYM {} | CACHE_SYM {}
| CASCADED {} | CASCADED {}
| CHAIN_SYM {}
| CHANGED {} | CHANGED {}
| CHARSET {} | CHARSET {}
| CHECKSUM_SYM {} | CHECKSUM_SYM {}
...@@ -7854,25 +7858,66 @@ opt_work: ...@@ -7854,25 +7858,66 @@ opt_work:
| WORK_SYM {;} | WORK_SYM {;}
; ;
opt_chain:
/* empty */ { $$= (Lex->thd->variables.completion_type == 1); }
| AND_SYM NO_SYM CHAIN_SYM { $$=0; }
| AND_SYM CHAIN_SYM { $$=1; }
;
opt_release:
/* empty */ { $$= (Lex->thd->variables.completion_type == 2); }
| RELEASE_SYM { $$=1; }
| NO_SYM RELEASE_SYM { $$=0; }
;
opt_work_and_chain:
opt_work opt_chain { $$=$2; }
;
opt_savepoint:
/* empty */ {}
| SAVEPOINT_SYM {}
;
commit: commit:
COMMIT_SYM { Lex->sql_command = SQLCOM_COMMIT;}; COMMIT_SYM opt_work_and_chain opt_release
{
Lex->sql_command= SQLCOM_COMMIT;
Lex->tx_chain= $2;
Lex->tx_release= $3;
}
;
rollback: rollback:
ROLLBACK_SYM ROLLBACK_SYM opt_work_and_chain opt_release
{ {
Lex->sql_command = SQLCOM_ROLLBACK; Lex->sql_command= SQLCOM_ROLLBACK;
Lex->tx_chain= $2;
Lex->tx_release= $3;
} }
| ROLLBACK_SYM TO_SYM SAVEPOINT_SYM ident | ROLLBACK_SYM opt_work
TO_SYM opt_savepoint ident
{ {
Lex->sql_command = SQLCOM_ROLLBACK_TO_SAVEPOINT; Lex->sql_command = SQLCOM_ROLLBACK_TO_SAVEPOINT;
Lex->savepoint_name = $4.str; Lex->savepoint_name = $5.str;
}; }
;
savepoint: savepoint:
SAVEPOINT_SYM ident SAVEPOINT_SYM ident
{ {
Lex->sql_command = SQLCOM_SAVEPOINT; Lex->sql_command = SQLCOM_SAVEPOINT;
Lex->savepoint_name = $2.str; Lex->savepoint_name = $2.str;
}; }
;
release:
RELEASE_SYM SAVEPOINT_SYM ident
{
Lex->sql_command = SQLCOM_RELEASE_SAVEPOINT;
Lex->savepoint_name = $3.str;
}
;
/* /*
UNIONS : glue selects together UNIONS : glue selects together
......
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