summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <acurtis@pcgem.rdg.cyberkinetica.com>2005-02-01 19:48:05 +0000
committerunknown <acurtis@pcgem.rdg.cyberkinetica.com>2005-02-01 19:48:05 +0000
commit0e50e32480920c29f2efacfcbfa35c9c93838840 (patch)
treebbf0adb98417062aa825a294e28389e8eed0ec43
parentf7606a335e44841e2cac79cc7256b6eb489c7b82 (diff)
downloadmariadb-git-0e50e32480920c29f2efacfcbfa35c9c93838840.tar.gz
WL#1967
Support for COMMIT/ROLLBACK optional arguments innobase/include/trx0roll.h: WL#1967 trx_release_savepoint_for_mysql() innobase/trx/trx0roll.c: WL#1967 trx_release_savepoint_for_mysql() mysql-test/r/innodb.result: WL#1967 Test for savepoint release mysql-test/t/innodb.test: WL#1967 Test for savepoint release sql/ha_innodb.cc: WL#1967 innobase_release_savepoint_name() sql/ha_innodb.h: WL#1967 innobase_release_savepoint_name() sql/handler.cc: WL#1967 ha_release_savepoint_name() sql/handler.h: WL#1967 ha_release_savepoint_name() sql/lex.h: WL#1967 New tokens: CHAIN, RELEASE sql/mysqld.cc: WL#1967 new option: completion-type sql/set_var.cc: WL#1967 new option: completion-type sql/sql_class.h: WL#1967 new option: completion-type sql/sql_lex.h: WL#1967 Support RELEASE SAVEPOINT additional flags to support COMMIT/ROLLBACK options sql/sql_parse.cc: WL#1967 Transaction operations in mysql_endtrans(), begin_trans() sql/sql_yacc.yy: WL#1967 Support COMMIT/ROLLBACK optional args
-rw-r--r--innobase/include/trx0roll.h15
-rw-r--r--innobase/trx/trx0roll.c45
-rw-r--r--mysql-test/r/innodb.result34
-rw-r--r--mysql-test/t/innodb.test13
-rw-r--r--sql/ha_innodb.cc25
-rw-r--r--sql/ha_innodb.h3
-rw-r--r--sql/handler.cc29
-rw-r--r--sql/handler.h1
-rw-r--r--sql/lex.h2
-rw-r--r--sql/mysqld.cc6
-rw-r--r--sql/set_var.cc23
-rw-r--r--sql/sql_class.h1
-rw-r--r--sql/sql_lex.h3
-rw-r--r--sql/sql_parse.cc213
-rw-r--r--sql/sql_yacc.yy65
15 files changed, 402 insertions, 76 deletions
diff --git a/innobase/include/trx0roll.h b/innobase/include/trx0roll.h
index 9d025da4a5f..944142a299d 100644
--- a/innobase/include/trx0roll.h
+++ b/innobase/include/trx0roll.h
@@ -225,6 +225,21 @@ trx_savepoint_for_mysql(
position corresponding to this
connection at the time of the
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. */
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index e5cffd2a4f3..cba3040fd0e 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -317,6 +317,51 @@ trx_savepoint_for_mysql(
}
/***********************************************************************
+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. */
trx_savept_t
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 8d1c4e3fc90..5928688ca81 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -249,6 +249,30 @@ n
4
5
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;
drop table t1;
create table t1 (n int not null primary key) engine=innodb;
@@ -1609,14 +1633,14 @@ t2 CREATE TABLE `t2` (
drop table t2, t1;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 24
+Binlog_cache_use 25
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 25
+Binlog_cache_use 26
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
@@ -1625,7 +1649,7 @@ delete from t1;
commit;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 26
+Binlog_cache_use 27
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
@@ -1693,10 +1717,10 @@ Variable_name Value
Innodb_rows_deleted 2070
show status like "Innodb_rows_inserted";
Variable_name Value
-Innodb_rows_inserted 31706
+Innodb_rows_inserted 31708
show status like "Innodb_rows_read";
Variable_name Value
-Innodb_rows_read 80153
+Innodb_rows_read 80162
show status like "Innodb_rows_updated";
Variable_name Value
Innodb_rows_updated 29530
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index 4fff24a61d5..da27fcfc734 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -129,6 +129,19 @@ insert into t1 values (6);
-- error 1062
insert into t1 values (4);
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
rollback;
drop table t1;
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index d6b6c140fbf..32b203f7ad6 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1613,6 +1613,31 @@ innobase_rollback_to_savepoint(
}
/*********************************************************************
+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. */
int
diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h
index 2154e238fd1..7a48de52422 100644
--- a/sql/ha_innodb.h
+++ b/sql/ha_innodb.h
@@ -244,6 +244,9 @@ int innobase_savepoint(
THD* thd,
char* savepoint_name,
my_off_t binlog_cache_pos);
+int innobase_release_savepoint_name(
+ THD* thd,
+ char* savepoint_name);
int innobase_close_connection(THD *thd);
int innobase_drop_database(char *path);
bool innodb_show_status(THD* thd);
diff --git a/sql/handler.cc b/sql/handler.cc
index 059d1feaed1..a9bb19158dd 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -869,6 +869,35 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
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.
diff --git a/sql/handler.h b/sql/handler.h
index e5a794ca1b2..2b5c66fd886 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -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_to_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);
void ha_set_spin_retries(uint retries);
bool ha_flush_logs(void);
diff --git a/sql/lex.h b/sql/lex.h
index 871d1d99750..7b03950b35a 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -99,6 +99,7 @@ static SYMBOL symbols[] = {
{ "CASCADE", SYM(CASCADE)},
{ "CASCADED", SYM(CASCADED)},
{ "CASE", SYM(CASE_SYM)},
+ { "CHAIN", SYM(CHAIN_SYM)},
{ "CHANGE", SYM(CHANGE)},
{ "CHANGED", SYM(CHANGED)},
{ "CHAR", SYM(CHAR_SYM)},
@@ -385,6 +386,7 @@ static SYMBOL symbols[] = {
{ "RELAY_LOG_FILE", SYM(RELAY_LOG_FILE_SYM)},
{ "RELAY_LOG_POS", SYM(RELAY_LOG_POS_SYM)},
{ "RELAY_THREAD", SYM(RELAY_THREAD)},
+ { "RELEASE", SYM(RELEASE_SYM)},
{ "RELOAD", SYM(RELOAD)},
{ "RENAME", SYM(RENAME)},
{ "REPAIR", SYM(REPAIR)},
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9b39f51fc5b..e4df359d35c 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -4176,7 +4176,7 @@ enum options_mysqld
OPT_NDB_FORCE_SEND, OPT_NDB_AUTOINCREMENT_PREFETCH_SZ,
OPT_NDB_SHM, OPT_NDB_OPTIMIZED_NODE_SELECTION,
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_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
@@ -4363,6 +4363,10 @@ Disable with --skip-bdb (will save memory).",
{"collation-server", OPT_DEFAULT_COLLATION, "Set the default collation.",
(gptr*) &default_collation_name, (gptr*) &default_collation_name,
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,
"Use concurrent insert with MyISAM. Disable with --skip-concurrent-insert.",
(gptr*) &myisam_concurrent_insert, (gptr*) &myisam_concurrent_insert,
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 7a528467e24..541bcf0ff7d 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -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 void fix_low_priority_updates(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_write_timeout(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
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_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_database sys_collation_database("collation_database");
sys_var_collation_server sys_collation_server("collation_server");
@@ -532,6 +538,7 @@ sys_var *sys_variables[]=
&sys_collation_connection,
&sys_collation_database,
&sys_collation_server,
+ &sys_completion_type,
&sys_concurrent_insert,
&sys_connect_timeout,
&sys_date_format,
@@ -708,6 +715,7 @@ struct show_var_st init_vars[]= {
{sys_collation_connection.name,(char*) &sys_collation_connection, SHOW_SYS},
{sys_collation_database.name,(char*) &sys_collation_database, 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_connect_timeout.name, (char*) &sys_connect_timeout, SHOW_SYS},
{"datadir", mysql_real_data_home, SHOW_CHAR},
@@ -1122,6 +1130,21 @@ static void fix_tx_isolation(THD *thd, enum_var_type type)
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
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 8e6204ab3a3..561cf099592 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -408,6 +408,7 @@ struct system_variables
ulong table_type;
ulong tmp_table_size;
ulong tx_isolation;
+ ulong completion_type;
/* Determines which non-standard SQL behaviour should be enabled */
ulong sql_mode;
/* check of key presence in updatable view */
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 6ed5fb247dc..b2c214bf1fa 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -67,7 +67,7 @@ enum enum_sql_command {
SQLCOM_ASSIGN_TO_KEYCACHE, SQLCOM_PRELOAD_KEYS,
SQLCOM_FLUSH, SQLCOM_KILL, SQLCOM_ANALYZE,
SQLCOM_ROLLBACK, SQLCOM_ROLLBACK_TO_SAVEPOINT,
- SQLCOM_COMMIT, SQLCOM_SAVEPOINT,
+ SQLCOM_COMMIT, SQLCOM_SAVEPOINT, SQLCOM_RELEASE_SAVEPOINT,
SQLCOM_SLAVE_START, SQLCOM_SLAVE_STOP,
SQLCOM_BEGIN, SQLCOM_LOAD_MASTER_TABLE, SQLCOM_CHANGE_MASTER,
SQLCOM_RENAME_TABLE, SQLCOM_BACKUP_TABLE, SQLCOM_RESTORE_TABLE,
@@ -718,6 +718,7 @@ typedef struct st_lex
uint8 create_view_check;
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
bool in_comment, ignore_space, verbose, no_write_to_binlog;
+ bool tx_chain, tx_release;
/* special JOIN::prepare mode: changing of query is prohibited */
bool view_prepare_mode;
bool safe_to_cache_query;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 820a4f732a3..8b5986a805b 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -134,6 +134,27 @@ static bool end_active_trans(THD *thd)
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
+ {
+ 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
inline bool all_tables_not_ok(THD *thd, TABLE_LIST *tables)
@@ -1262,6 +1283,127 @@ err:
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
@@ -3648,74 +3790,23 @@ unsent_create_error:
break;
case SQLCOM_BEGIN:
- 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))
+ if (begin_trans(thd))
goto error;
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;
case SQLCOM_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 (!ha_commit(thd))
- {
- send_ok(thd);
- }
- else
+ if (mysql_endtrans(thd, lex->tx_release ? COMMIT_RELEASE :
+ lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT, 0))
goto error;
break;
- }
case SQLCOM_ROLLBACK:
- 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.
- */
- 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);
+ if (mysql_endtrans(thd, lex->tx_release ? ROLLBACK_RELEASE :
+ lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK, 0))
+ goto error;
break;
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
- if (!ha_rollback_to_savepoint(thd, 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
+ if (mysql_endtrans(thd, SAVEPOINT_NAME_ROLLBACK, lex->savepoint_name))
goto error;
break;
case SQLCOM_SAVEPOINT:
@@ -3724,6 +3815,10 @@ unsent_create_error:
else
goto error;
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_SPFUNCTION:
{
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index cc2443bd41b..e1c7c26060a 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -219,6 +219,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token CASCADE
%token CASCADED
%token CAST_SYM
+%token CHAIN_SYM
%token CHARSET
%token CHECKSUM_SYM
%token CHECK_SYM
@@ -385,6 +386,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token REDUNDANT_SYM
%token REFERENCES
%token REGEXP
+%token RELEASE_SYM
%token RELOAD
%token RENAME
%token REPEATABLE_SYM
@@ -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
opt_var_ident_type delete_option opt_temporary all_or_any opt_distinct
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>
ULONG_NUM raid_types merge_insert_types
@@ -777,7 +779,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
query verb_clause create change select do drop insert replace insert2
insert_values update delete truncate rename
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
repair restore backup analyze check start checksum
field_list field_list_item field_spec kill column_def key_def
@@ -876,6 +878,7 @@ statement:
| preload
| prepare
| purge
+ | release
| rename
| repair
| replace
@@ -6901,6 +6904,7 @@ keyword:
| BTREE_SYM {}
| CACHE_SYM {}
| CASCADED {}
+ | CHAIN_SYM {}
| CHANGED {}
| CHARSET {}
| CHECKSUM_SYM {}
@@ -7854,25 +7858,66 @@ opt_work:
| 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_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_SYM
- {
- Lex->sql_command = SQLCOM_ROLLBACK;
+ ROLLBACK_SYM opt_work_and_chain opt_release
+ {
+ 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->savepoint_name = $4.str;
- };
+ Lex->savepoint_name = $5.str;
+ }
+ ;
+
savepoint:
SAVEPOINT_SYM ident
{
Lex->sql_command = SQLCOM_SAVEPOINT;
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