Commit 52770e86 authored by serg@serg.mylan's avatar serg@serg.mylan

XID SQL syntax

minor cleanups
XA tests
parent 45a79c90
...@@ -186,7 +186,7 @@ typedef struct my_charset_handler_st ...@@ -186,7 +186,7 @@ typedef struct my_charset_handler_st
int base, char **e, int *err); int base, char **e, int *err);
double (*strntod)(struct charset_info_st *, char *s, uint l, char **e, double (*strntod)(struct charset_info_st *, char *s, uint l, char **e,
int *err); int *err);
longlong (*my_strtoll10)(struct charset_info_st *cs, longlong (*strtoll10)(struct charset_info_st *cs,
const char *nptr, char **endptr, int *error); const char *nptr, char **endptr, int *error);
ulong (*scan)(struct charset_info_st *, const char *b, const char *e, ulong (*scan)(struct charset_info_st *, const char *b, const char *e,
int sq); int sq);
......
drop table if exists t1, t2;
create table t1 (a int) engine=innodb;
xa start 'test1';
insert t1 values (10);
xa end 'test1';
xa prepare 'test1';
xa rollback 'test1';
select * from t1;
a
xa start 'test2';
xa start 'test-bad';
ERROR XAE07: XAER_RMFAIL: The command cannot be executed in the ACTIVE state
insert t1 values (20);
xa prepare 'test2';
ERROR XAE07: XAER_RMFAIL: The command cannot be executed in the ACTIVE state
xa end 'test2';
xa prepare 'test2';
xa commit 'test2';
select * from t1;
a
20
xa start 'testa','testb';
insert t1 values (30);
xa end 'testa','testb';
xa start 0x7465737462, 0x2030405060, 0xb;
insert t1 values (40);
xa end 'testb',' 0@P`',11;
xa prepare 'testb',0x2030405060,11;
xa recover;
formatID gtrid_length bqual_length data
11 5 5 testb 0@P`
xa prepare 'testa','testb';
xa recover;
formatID gtrid_length bqual_length data
11 5 5 testb 0@P`
1 5 5 testatestb
xa commit 'testb',0x2030405060,11;
xa rollback 'testa','testb';
xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
ERROR 42000: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' at line 1
select * from t1;
a
20
40
drop table t1;
#
# WL#1756
#
-- source include/have_innodb.inc
--disable_warnings
drop table if exists t1, t2;
--enable_warnings
create table t1 (a int) engine=innodb;
xa start 'test1';
insert t1 values (10);
xa end 'test1';
xa prepare 'test1';
xa rollback 'test1';
select * from t1;
xa start 'test2';
--error 1399
xa start 'test-bad';
insert t1 values (20);
--error 1399
xa prepare 'test2';
xa end 'test2';
xa prepare 'test2';
xa commit 'test2';
select * from t1;
xa start 'testa','testb';
insert t1 values (30);
xa end 'testa','testb';
connect (con1,localhost,,,);
connection con1;
xa start 0x7465737462, 0x2030405060, 0xb;
insert t1 values (40);
xa end 'testb',' 0@P`',11;
xa prepare 'testb',0x2030405060,11;
xa recover;
# uncomment the line below when binlog will be able to prepare
#disconnect con1;
connection default;
xa prepare 'testa','testb';
xa recover;
xa commit 'testb',0x2030405060,11;
xa rollback 'testa','testb';
--error 1064
xa start 'zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz';
select * from t1;
drop table t1;
...@@ -3230,13 +3230,13 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs) ...@@ -3230,13 +3230,13 @@ int Field_long::store(const char *from,uint len,CHARSET_INFO *cs)
long store_tmp; long store_tmp;
int error; int error;
char *end; char *end;
tmp_scan= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES); tmp_scan= cs->cset->scan(cs, from, from+len, MY_SEQ_SPACES);
len-= tmp_scan; len-= tmp_scan;
from+= tmp_scan; from+= tmp_scan;
end= (char*) from+len; end= (char*) from+len;
tmp= cs->cset->my_strtoll10(cs, from, &end, &error); tmp= cs->cset->strtoll10(cs, from, &end, &error);
if (error != MY_ERRNO_EDOM) if (error != MY_ERRNO_EDOM)
{ {
......
...@@ -750,17 +750,15 @@ int ha_autocommit_or_rollback(THD *thd, int error) ...@@ -750,17 +750,15 @@ int ha_autocommit_or_rollback(THD *thd, int error)
DBUG_RETURN(error); DBUG_RETURN(error);
} }
int ha_commit_or_rollback_by_xid(LEX_STRING *ident, bool commit) int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
{ {
XID xid;
handlerton **ht= handlertons, **end_ht=ht+total_ha; handlerton **ht= handlertons, **end_ht=ht+total_ha;
int res= 1; int res= 1;
xid.set(ident);
for ( ; ht < end_ht ; ht++) for ( ; ht < end_ht ; ht++)
if ((*ht)->recover) if ((*ht)->recover)
res= res && res= res &&
(*(commit ? (*ht)->commit_by_xid : (*ht)->rollback_by_xid))(&xid); (*(commit ? (*ht)->commit_by_xid : (*ht)->rollback_by_xid))(xid);
return res; return res;
} }
...@@ -2366,9 +2364,8 @@ TYPELIB *ha_known_exts(void) ...@@ -2366,9 +2364,8 @@ TYPELIB *ha_known_exts(void)
const char **ext, *old_ext; const char **ext, *old_ext;
known_extensions_id= mysys_usage_id; known_extensions_id= mysys_usage_id;
found_exts.push_back((char*) ".db");
for (types= sys_table_types; types->type; types++) for (types= sys_table_types; types->type; types++)
{ {
if (*types->value == SHOW_OPTION_YES) if (*types->value == SHOW_OPTION_YES)
{ {
handler *file= get_new_handler(0,(enum db_type) types->db_type); handler *file= get_new_handler(0,(enum db_type) types->db_type);
......
...@@ -213,13 +213,22 @@ struct xid_t { ...@@ -213,13 +213,22 @@ struct xid_t {
long bqual_length; long bqual_length;
char data[XIDDATASIZE]; // not \0-terminated ! char data[XIDDATASIZE]; // not \0-terminated !
bool eq(LEX_STRING *l) { return eq(l->length, 0, l->str); } bool eq(struct xid_t *xid)
{ return !memcmp(this, xid, sizeof(long)*3+gtrid_length+bqual_length); }
bool eq(long g, long b, const char *d) bool eq(long g, long b, const char *d)
{ return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); } { return g == gtrid_length && b == bqual_length && !memcmp(d, data, g+b); }
void set(LEX_STRING *l) { set(l->length, 0, l->str); } void set(struct xid_t *xid)
{ memcpy(this, xid, sizeof(long)*3+xid->gtrid_length+xid->bqual_length); }
void set(long f, const char *g, long gl, const char *b, long bl)
{
formatID= f;
memcpy(data, g, gtrid_length= gl);
memcpy(data+gl, b, bqual_length= bl);
}
void set(ulonglong xid) void set(ulonglong xid)
{ {
my_xid tmp; my_xid tmp;
formatID= 1;
set(MYSQL_XID_PREFIX_LEN, 0, MYSQL_XID_PREFIX); set(MYSQL_XID_PREFIX_LEN, 0, MYSQL_XID_PREFIX);
memcpy(data+MYSQL_XID_PREFIX_LEN, &server_id, sizeof(server_id)); memcpy(data+MYSQL_XID_PREFIX_LEN, &server_id, sizeof(server_id));
tmp= xid; tmp= xid;
...@@ -228,7 +237,7 @@ struct xid_t { ...@@ -228,7 +237,7 @@ struct xid_t {
} }
void set(long g, long b, const char *d) void set(long g, long b, const char *d)
{ {
formatID=1; formatID= 1;
gtrid_length= g; gtrid_length= g;
bqual_length= b; bqual_length= b;
memcpy(data, d, g+b); memcpy(data, d, g+b);
...@@ -244,7 +253,7 @@ struct xid_t { ...@@ -244,7 +253,7 @@ struct xid_t {
my_xid get_my_xid() my_xid get_my_xid()
{ {
return gtrid_length == MYSQL_XID_GTRID_LEN && bqual_length == 0 && return gtrid_length == MYSQL_XID_GTRID_LEN && bqual_length == 0 &&
*(ulong*)(data+MYSQL_XID_PREFIX_LEN) == server_id && !memcmp(data+MYSQL_XID_PREFIX_LEN, &server_id, sizeof(server_id)) &&
!memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ? !memcmp(data, MYSQL_XID_PREFIX, MYSQL_XID_PREFIX_LEN) ?
quick_get_my_xid() : 0; quick_get_my_xid() : 0;
} }
...@@ -261,8 +270,8 @@ typedef struct xid_t XID; ...@@ -261,8 +270,8 @@ typedef struct xid_t XID;
/* /*
handlerton is a singleton structure - one instance per storage engine - handlerton is a singleton structure - one instance per storage engine -
to provide access to storage engine functionality that works on to provide access to storage engine functionality that works on the
"global" level (unlike handler class that works on per-table basis) "global" level (unlike handler class that works on a per-table basis)
usually handlerton instance is defined statically in ha_xxx.cc as usually handlerton instance is defined statically in ha_xxx.cc as
...@@ -826,7 +835,7 @@ int ha_release_temporary_latches(THD *thd); ...@@ -826,7 +835,7 @@ int ha_release_temporary_latches(THD *thd);
/* transactions: interface to handlerton functions */ /* transactions: interface to handlerton functions */
int ha_start_consistent_snapshot(THD *thd); int ha_start_consistent_snapshot(THD *thd);
int ha_commit_or_rollback_by_xid(LEX_STRING *ident, bool commit); int ha_commit_or_rollback_by_xid(XID *xid, bool commit);
int ha_commit_one_phase(THD *thd, bool all); int ha_commit_one_phase(THD *thd, bool all);
int ha_rollback_trans(THD *thd, bool all); int ha_rollback_trans(THD *thd, bool all);
int ha_prepare(THD *thd); int ha_prepare(THD *thd);
......
...@@ -734,7 +734,7 @@ class Item_sum_udf_str :public Item_udf_sum ...@@ -734,7 +734,7 @@ class Item_sum_udf_str :public Item_udf_sum
return 0; /* Null value */ return 0; /* Null value */
cs= res->charset(); cs= res->charset();
end= (char*) res->ptr()+res->length(); end= (char*) res->ptr()+res->length();
return cs->cset->my_strtoll10(cs, res->ptr(), &end, &err_not_used); return cs->cset->strtoll10(cs, res->ptr(), &end, &err_not_used);
} }
my_decimal *val_decimal(my_decimal *dec); my_decimal *val_decimal(my_decimal *dec);
enum Item_result result_type () const { return STRING_RESULT; } enum Item_result result_type () const { return STRING_RESULT; }
......
...@@ -736,6 +736,13 @@ static void print_lock_error(int error, const char *table) ...@@ -736,6 +736,13 @@ static void print_lock_error(int error, const char *table)
protect_against_global_read_lock protect_against_global_read_lock
count of threads which have set protection against global read lock. count of threads which have set protection against global read lock.
access to them is protected with a mutex LOCK_global_read_lock
(XXX: one should never take LOCK_open if LOCK_global_read_lock is taken,
otherwise a deadlock may occur - see mysql_rm_table. Other mutexes could
be a problem too - grep the code for global_read_lock if you want to use
any other mutex here)
How blocking of threads by global read lock is achieved: that's How blocking of threads by global read lock is achieved: that's
advisory. Any piece of code which should be blocked by global read lock must advisory. Any piece of code which should be blocked by global read lock must
be designed like this: be designed like this:
...@@ -773,7 +780,7 @@ static void print_lock_error(int error, const char *table) ...@@ -773,7 +780,7 @@ static void print_lock_error(int error, const char *table)
table instance of thd2 table instance of thd2
thd1: COMMIT; # blocked by thd3. thd1: COMMIT; # blocked by thd3.
thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock. thd1 blocks thd2 which blocks thd3 which blocks thd1: deadlock.
Note that we need to support that one thread does Note that we need to support that one thread does
FLUSH TABLES WITH READ LOCK; and then COMMIT; FLUSH TABLES WITH READ LOCK; and then COMMIT;
(that's what innobackup does, for some good reason). (that's what innobackup does, for some good reason).
...@@ -818,7 +825,7 @@ bool lock_global_read_lock(THD *thd) ...@@ -818,7 +825,7 @@ bool lock_global_read_lock(THD *thd)
} }
thd->global_read_lock= GOT_GLOBAL_READ_LOCK; thd->global_read_lock= GOT_GLOBAL_READ_LOCK;
global_read_lock++; global_read_lock++;
thd->exit_cond(old_message); thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
} }
/* /*
We DON'T set global_read_lock_blocks_commit now, it will be set after We DON'T set global_read_lock_blocks_commit now, it will be set after
...@@ -887,8 +894,8 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh, ...@@ -887,8 +894,8 @@ bool wait_if_global_read_lock(THD *thd, bool abort_on_refresh,
The following is only true in case of a global read locks (which is rare) The following is only true in case of a global read locks (which is rare)
and if old_message is set and if old_message is set
*/ */
if (unlikely(need_exit_cond)) if (unlikely(need_exit_cond))
thd->exit_cond(old_message); thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
else else
pthread_mutex_unlock(&LOCK_global_read_lock); pthread_mutex_unlock(&LOCK_global_read_lock);
DBUG_RETURN(result); DBUG_RETURN(result);
...@@ -938,7 +945,7 @@ bool make_global_read_lock_block_commit(THD *thd) ...@@ -938,7 +945,7 @@ bool make_global_read_lock_block_commit(THD *thd)
global_read_lock_blocks_commit--; // undo what we did global_read_lock_blocks_commit--; // undo what we did
else else
thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT; thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT;
thd->exit_cond(old_message); thd->exit_cond(old_message); // this unlocks LOCK_global_read_lock
DBUG_RETURN(error); DBUG_RETURN(error);
} }
...@@ -342,7 +342,9 @@ void THD::change_user(void) ...@@ -342,7 +342,9 @@ void THD::change_user(void)
void THD::cleanup(void) void THD::cleanup(void)
{ {
DBUG_ENTER("THD::cleanup"); DBUG_ENTER("THD::cleanup");
ha_rollback(this); /* TODO uncomment the line below when binlog will be able to prepare */
// if (transaction.xa_state != XA_PREPARED)
ha_rollback(this);
if (locked_tables) if (locked_tables)
{ {
lock=locked_tables; locked_tables=0; lock=locked_tables; locked_tables=0;
...@@ -384,17 +386,17 @@ THD::~THD() ...@@ -384,17 +386,17 @@ THD::~THD()
add_to_status(&global_status_var, &status_var); add_to_status(&global_status_var, &status_var);
/* Close connection */ /* Close connection */
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
if (net.vio) if (net.vio)
{ {
vio_delete(net.vio); vio_delete(net.vio);
net_end(&net); net_end(&net);
} }
#endif #endif
if (!cleanup_done) if (!cleanup_done)
cleanup(); cleanup();
ha_close_connection(this); ha_close_connection(this);
sp_cache_clear(&sp_proc_cache); sp_cache_clear(&sp_proc_cache);
sp_cache_clear(&sp_func_cache); sp_cache_clear(&sp_func_cache);
......
...@@ -696,6 +696,7 @@ typedef struct st_lex ...@@ -696,6 +696,7 @@ typedef struct st_lex
Item *default_value, *on_update_value; Item *default_value, *on_update_value;
LEX_STRING comment, ident; LEX_STRING comment, ident;
LEX_USER *grant_user; LEX_USER *grant_user;
XID *xid;
gptr yacc_yyss,yacc_yyvs; gptr yacc_yyss,yacc_yyvs;
THD *thd; THD *thd;
CHARSET_INFO *charset; CHARSET_INFO *charset;
...@@ -738,7 +739,7 @@ typedef struct st_lex ...@@ -738,7 +739,7 @@ typedef struct st_lex
enum enum_tx_isolation tx_isolation; enum enum_tx_isolation tx_isolation;
enum enum_ha_read_modes ha_read_mode; enum enum_ha_read_modes ha_read_mode;
union { union {
enum ha_rkey_function ha_rkey_mode; enum ha_rkey_function ha_rkey_mode;
enum xa_option_words xa_opt; enum xa_option_words xa_opt;
}; };
enum enum_var_type option_type; enum enum_var_type option_type;
...@@ -764,15 +765,15 @@ typedef struct st_lex ...@@ -764,15 +765,15 @@ typedef struct st_lex
ALTER_INFO alter_info; ALTER_INFO alter_info;
/* Prepared statements SQL syntax:*/ /* Prepared statements SQL syntax:*/
LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */ LEX_STRING prepared_stmt_name; /* Statement name (in all queries) */
/* /*
Prepared statement query text or name of variable that holds the Prepared statement query text or name of variable that holds the
prepared statement (in PREPARE ... queries) prepared statement (in PREPARE ... queries)
*/ */
LEX_STRING prepared_stmt_code; LEX_STRING prepared_stmt_code;
/* If true, prepared_stmt_code is a name of variable that holds the query */ /* If true, prepared_stmt_code is a name of variable that holds the query */
bool prepared_stmt_code_is_varref; bool prepared_stmt_code_is_varref;
/* Names of user variables holding parameters (in EXECUTE) */ /* Names of user variables holding parameters (in EXECUTE) */
List<LEX_STRING> prepared_stmt_params; List<LEX_STRING> prepared_stmt_params;
/* /*
Points to part of global table list which contains time zone tables Points to part of global table list which contains time zone tables
implicitly used by the statement. implicitly used by the statement.
......
...@@ -4323,7 +4323,7 @@ mysql_execute_command(THD *thd) ...@@ -4323,7 +4323,7 @@ mysql_execute_command(THD *thd)
case SQLCOM_XA_START: case SQLCOM_XA_START:
if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME) if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
{ {
if (! thd->transaction.xid.eq(&thd->lex->ident)) if (! thd->transaction.xid.eq(thd->lex->xid))
{ {
my_error(ER_XAER_NOTA, MYF(0)); my_error(ER_XAER_NOTA, MYF(0));
break; break;
...@@ -4332,7 +4332,7 @@ mysql_execute_command(THD *thd) ...@@ -4332,7 +4332,7 @@ mysql_execute_command(THD *thd)
send_ok(thd); send_ok(thd);
break; break;
} }
if (thd->lex->ident.length > MAXGTRIDSIZE || thd->lex->xa_opt != XA_NONE) if (thd->lex->xa_opt != XA_NONE)
{ // JOIN is not supported yet. TODO { // JOIN is not supported yet. TODO
my_error(ER_XAER_INVAL, MYF(0)); my_error(ER_XAER_INVAL, MYF(0));
break; break;
...@@ -4350,7 +4350,7 @@ mysql_execute_command(THD *thd) ...@@ -4350,7 +4350,7 @@ mysql_execute_command(THD *thd)
} }
DBUG_ASSERT(thd->transaction.xid.is_null()); DBUG_ASSERT(thd->transaction.xid.is_null());
thd->transaction.xa_state=XA_ACTIVE; thd->transaction.xa_state=XA_ACTIVE;
thd->transaction.xid.set(&thd->lex->ident); thd->transaction.xid.set(thd->lex->xid);
thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) | thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
OPTION_BEGIN); OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS; thd->server_status|= SERVER_STATUS_IN_TRANS;
...@@ -4369,7 +4369,7 @@ mysql_execute_command(THD *thd) ...@@ -4369,7 +4369,7 @@ mysql_execute_command(THD *thd)
xa_state_names[thd->transaction.xa_state]); xa_state_names[thd->transaction.xa_state]);
break; break;
} }
if (!thd->transaction.xid.eq(&thd->lex->ident)) if (!thd->transaction.xid.eq(thd->lex->xid))
{ {
my_error(ER_XAER_NOTA, MYF(0)); my_error(ER_XAER_NOTA, MYF(0));
break; break;
...@@ -4384,7 +4384,7 @@ mysql_execute_command(THD *thd) ...@@ -4384,7 +4384,7 @@ mysql_execute_command(THD *thd)
xa_state_names[thd->transaction.xa_state]); xa_state_names[thd->transaction.xa_state]);
break; break;
} }
if (!thd->transaction.xid.eq(&thd->lex->ident)) if (!thd->transaction.xid.eq(thd->lex->xid))
{ {
my_error(ER_XAER_NOTA, MYF(0)); my_error(ER_XAER_NOTA, MYF(0));
break; break;
...@@ -4399,9 +4399,9 @@ mysql_execute_command(THD *thd) ...@@ -4399,9 +4399,9 @@ mysql_execute_command(THD *thd)
send_ok(thd); send_ok(thd);
break; break;
case SQLCOM_XA_COMMIT: case SQLCOM_XA_COMMIT:
if (!thd->transaction.xid.eq(&thd->lex->ident)) if (!thd->transaction.xid.eq(thd->lex->xid))
{ {
if (!(res= !ha_commit_or_rollback_by_xid(&thd->lex->ident, 1))) if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 1)))
my_error(ER_XAER_NOTA, MYF(0)); my_error(ER_XAER_NOTA, MYF(0));
else else
send_ok(thd); send_ok(thd);
...@@ -4434,9 +4434,9 @@ mysql_execute_command(THD *thd) ...@@ -4434,9 +4434,9 @@ mysql_execute_command(THD *thd)
thd->transaction.xa_state=XA_NOTR; thd->transaction.xa_state=XA_NOTR;
break; break;
case SQLCOM_XA_ROLLBACK: case SQLCOM_XA_ROLLBACK:
if (!thd->transaction.xid.eq(&thd->lex->ident)) if (!thd->transaction.xid.eq(thd->lex->xid))
{ {
if (!(res= !ha_commit_or_rollback_by_xid(&thd->lex->ident, 0))) if (!(res= !ha_commit_or_rollback_by_xid(thd->lex->xid, 0)))
my_error(ER_XAER_NOTA, MYF(0)); my_error(ER_XAER_NOTA, MYF(0));
else else
send_ok(thd); send_ok(thd);
......
This diff is collapsed.
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