mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-14593 human-readable XA RECOVER.
The 'data' field in the XA RECOVER resultset changed to be charset_bin. It seems to me right and also --binary-as-hex starts working. The XA RECOVER FORMAT='SQL' option implemented. It returns the XID string that fits to be an argument for the XA ... statements.
This commit is contained in:
@@ -115,3 +115,7 @@ c9: 0x000000000101000000000000000000F03F000000000000F03F
|
||||
#Print the table contents in html format
|
||||
|
||||
<TABLE BORDER=1><TR><TH>c1</TH><TH>c2</TH><TH>c3</TH><TH>c4</TH><TH>c5</TH><TH>c6</TH><TH>c7</TH><TH>c8</TH><TH>c9</TH></TR><TR><TD>0x74696E79626C6F622D74657874207265616461626C65</TD><TD>0x626C6F622D74657874207265616461626C65</TD><TD>0x6D656469756D626C6F622D74657874207265616461626C65</TD><TD>0x6C6F6E67626C6F622D74657874207265616461626C65</TD><TD>0x74657874207265616461626C65</TD><TD>0x01</TD><TD>0x63</TD><TD>0x7661726961626C65</TD><TD>0x000000000101000000000000000000F03F000000000000F03F</TD></TR></TABLE><TABLE BORDER=1><TR><TH>id</TH><TH>col1</TH><TH>col2</TH></TR><TR><TD>1</TD><TD>0xAB123400000000000000</TD><TD>0x123ABC</TD></TR><TR><TD>2</TD><TD>0xDE123400000000000000</TD><TD>0x123DEF</TD></TR></TABLE>DROP TABLE t1, t2;
|
||||
create table t1 (a int);
|
||||
formatID gtrid_length bqual_length data
|
||||
1 3 2 0x7472316271
|
||||
DROP TABLE t1;
|
||||
|
@@ -60,6 +60,59 @@ a
|
||||
20
|
||||
disconnect con1;
|
||||
connection default;
|
||||
xa start 'tr1';
|
||||
insert t1 values (40);
|
||||
xa end 'tr1';
|
||||
xa prepare 'tr1';
|
||||
xa recover format='SQL';
|
||||
formatID gtrid_length bqual_length data
|
||||
1 3 0 'tr1'
|
||||
xa rollback 'tr1';
|
||||
xa start 'tr1', 'bq';
|
||||
insert t1 values (40);
|
||||
xa end 'tr1', 'bq';
|
||||
xa prepare 'tr1', 'bq';
|
||||
xa recover format='SQL';
|
||||
formatID gtrid_length bqual_length data
|
||||
1 3 2 'tr1','bq'
|
||||
xa rollback 'tr1', 'bq';
|
||||
xa start 'tr1', 'bq', 3;
|
||||
insert t1 values (40);
|
||||
xa end 'tr1', 'bq', 3;
|
||||
xa prepare 'tr1', 'bq', 3;
|
||||
xa recover format='SQL';
|
||||
formatID gtrid_length bqual_length data
|
||||
3 3 2 'tr1','bq',3
|
||||
xa rollback 'tr1', 'bq', 3;
|
||||
xa start 'tr1#$';
|
||||
insert t1 values (40);
|
||||
xa end 'tr1#$';
|
||||
xa prepare 'tr1#$';
|
||||
xa recover format='SQL';
|
||||
formatID gtrid_length bqual_length data
|
||||
1 5 0 X'7472312324'
|
||||
xa rollback 'tr1#$';
|
||||
xa start 'tr1#$', 'bq';
|
||||
insert t1 values (40);
|
||||
xa end 'tr1#$', 'bq';
|
||||
xa prepare 'tr1#$', 'bq';
|
||||
xa recover format='SQL';
|
||||
formatID gtrid_length bqual_length data
|
||||
1 5 2 X'7472312324',X'6271'
|
||||
xa rollback 'tr1#$', 'bq';
|
||||
xa start 'tr1#$', 'bq', 3;
|
||||
insert t1 values (40);
|
||||
xa end 'tr1#$', 'bq', 3;
|
||||
xa prepare 'tr1#$', 'bq', 3;
|
||||
xa recover format='RAW';
|
||||
formatID gtrid_length bqual_length data
|
||||
3 5 2 tr1#$bq
|
||||
xa recover format='PLAIN';
|
||||
ERROR HY000: Unknown XA RECOVER format name: 'PLAIN'
|
||||
xa recover format='SQL';
|
||||
formatID gtrid_length bqual_length data
|
||||
3 5 2 X'7472312324',X'6271',3
|
||||
xa rollback 'tr1#$', 'bq', 3;
|
||||
drop table t1;
|
||||
drop table if exists t1;
|
||||
create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb;
|
||||
|
@@ -72,5 +72,25 @@ SELECT * FROM t2;
|
||||
#Cleanup
|
||||
DROP TABLE t1, t2;
|
||||
|
||||
# MDEV-14593 human-readable XA RECOVER
|
||||
|
||||
create table t1 (a int);
|
||||
|
||||
--write_file $MYSQLTEST_VARDIR/tmp/mdev-14593.sql
|
||||
DELIMITER /
|
||||
XA START 'tr1', 'bq'/
|
||||
INSERT INTO t1 VALUES (0)/
|
||||
XA END 'tr1', 'bq'/
|
||||
XA PREPARE 'tr1', 'bq'/
|
||||
XA RECOVER/
|
||||
XA ROLLBACK 'tr1', 'bq'/
|
||||
EOF
|
||||
--exec $MYSQL test --binary-as-hex < $MYSQLTEST_VARDIR/tmp/mdev-14593.sql 2>&1
|
||||
remove_file $MYSQLTEST_VARDIR/tmp/mdev-14593.sql;
|
||||
|
||||
|
||||
#Cleanup
|
||||
DROP TABLE t1;
|
||||
|
||||
# Wait till all disconnects are completed
|
||||
--source include/wait_until_count_sessions.inc
|
||||
|
@@ -83,6 +83,53 @@ select * from t1;
|
||||
|
||||
disconnect con1;
|
||||
connection default;
|
||||
|
||||
# MDEV-14593 human-readable XA RECOVER
|
||||
xa start 'tr1';
|
||||
insert t1 values (40);
|
||||
xa end 'tr1';
|
||||
xa prepare 'tr1';
|
||||
xa recover format='SQL';
|
||||
xa rollback 'tr1';
|
||||
|
||||
xa start 'tr1', 'bq';
|
||||
insert t1 values (40);
|
||||
xa end 'tr1', 'bq';
|
||||
xa prepare 'tr1', 'bq';
|
||||
xa recover format='SQL';
|
||||
xa rollback 'tr1', 'bq';
|
||||
|
||||
xa start 'tr1', 'bq', 3;
|
||||
insert t1 values (40);
|
||||
xa end 'tr1', 'bq', 3;
|
||||
xa prepare 'tr1', 'bq', 3;
|
||||
xa recover format='SQL';
|
||||
xa rollback 'tr1', 'bq', 3;
|
||||
|
||||
xa start 'tr1#$';
|
||||
insert t1 values (40);
|
||||
xa end 'tr1#$';
|
||||
xa prepare 'tr1#$';
|
||||
xa recover format='SQL';
|
||||
xa rollback 'tr1#$';
|
||||
|
||||
xa start 'tr1#$', 'bq';
|
||||
insert t1 values (40);
|
||||
xa end 'tr1#$', 'bq';
|
||||
xa prepare 'tr1#$', 'bq';
|
||||
xa recover format='SQL';
|
||||
xa rollback 'tr1#$', 'bq';
|
||||
|
||||
xa start 'tr1#$', 'bq', 3;
|
||||
insert t1 values (40);
|
||||
xa end 'tr1#$', 'bq', 3;
|
||||
xa prepare 'tr1#$', 'bq', 3;
|
||||
xa recover format='RAW';
|
||||
--error ER_UNKNOWN_EXPLAIN_FORMAT
|
||||
xa recover format='PLAIN';
|
||||
xa recover format='SQL';
|
||||
xa rollback 'tr1#$', 'bq', 3;
|
||||
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
@@ -379,7 +426,6 @@ connection default;
|
||||
DROP TABLE t1, t2;
|
||||
disconnect con2;
|
||||
|
||||
|
||||
# Wait till all disconnects are completed
|
||||
--source include/wait_until_count_sessions.inc
|
||||
|
||||
|
140
sql/handler.cc
140
sql/handler.cc
@@ -1981,6 +1981,97 @@ int ha_recover(HASH *commit_list)
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/**
|
||||
return the XID as it appears in the SQL function's arguments.
|
||||
So this string can be passed to XA START, XA PREPARE etc...
|
||||
|
||||
@note
|
||||
the 'buf' has to have space for at least SQL_XIDSIZE bytes.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
'a'..'z' 'A'..'Z', '0'..'9'
|
||||
and '-' '_' ' ' symbols don't have to be
|
||||
converted.
|
||||
*/
|
||||
|
||||
static const char xid_needs_conv[128]=
|
||||
{
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,
|
||||
0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
|
||||
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,0,
|
||||
1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1
|
||||
};
|
||||
|
||||
uint get_sql_xid(XID *xid, char *buf)
|
||||
{
|
||||
int tot_len= xid->gtrid_length + xid->bqual_length;
|
||||
int i;
|
||||
const char *orig_buf= buf;
|
||||
|
||||
for (i=0; i<tot_len; i++)
|
||||
{
|
||||
uchar c= ((uchar *) xid->data)[i];
|
||||
if (c >= 128 || xid_needs_conv[c])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= tot_len)
|
||||
{
|
||||
/* No need to convert characters to hexadecimals. */
|
||||
*buf++= '\'';
|
||||
memcpy(buf, xid->data, xid->gtrid_length);
|
||||
buf+= xid->gtrid_length;
|
||||
*buf++= '\'';
|
||||
if (xid->bqual_length > 0 || xid->formatID != 1)
|
||||
{
|
||||
*buf++= ',';
|
||||
*buf++= '\'';
|
||||
memcpy(buf, xid->data+xid->gtrid_length, xid->bqual_length);
|
||||
buf+= xid->bqual_length;
|
||||
*buf++= '\'';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*buf++= 'X';
|
||||
*buf++= '\'';
|
||||
for (i= 0; i < xid->gtrid_length; i++)
|
||||
{
|
||||
*buf++=_dig_vec_lower[((uchar*) xid->data)[i] >> 4];
|
||||
*buf++=_dig_vec_lower[((uchar*) xid->data)[i] & 0x0f];
|
||||
}
|
||||
*buf++= '\'';
|
||||
if (xid->bqual_length > 0 || xid->formatID != 1)
|
||||
{
|
||||
*buf++= ',';
|
||||
*buf++= 'X';
|
||||
*buf++= '\'';
|
||||
for (; i < tot_len; i++)
|
||||
{
|
||||
*buf++=_dig_vec_lower[((uchar*) xid->data)[i] >> 4];
|
||||
*buf++=_dig_vec_lower[((uchar*) xid->data)[i] & 0x0f];
|
||||
}
|
||||
*buf++= '\'';
|
||||
}
|
||||
}
|
||||
|
||||
if (xid->formatID != 1)
|
||||
{
|
||||
*buf++= ',';
|
||||
buf+= my_longlong10_to_str_8bit(&my_charset_bin, buf,
|
||||
MY_INT64_NUM_DECIMAL_DIGITS, -10, xid->formatID);
|
||||
}
|
||||
|
||||
return buf - orig_buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
return the list of XID's to a client, the same way SHOW commands do.
|
||||
|
||||
@@ -1990,7 +2081,8 @@ int ha_recover(HASH *commit_list)
|
||||
It can be easily fixed later, if necessary.
|
||||
*/
|
||||
|
||||
static my_bool xa_recover_callback(XID_STATE *xs, Protocol *protocol)
|
||||
static my_bool xa_recover_callback(XID_STATE *xs, Protocol *protocol,
|
||||
char *data, uint data_len, CHARSET_INFO *data_cs)
|
||||
{
|
||||
if (xs->xa_state == XA_PREPARED)
|
||||
{
|
||||
@@ -1998,8 +2090,7 @@ static my_bool xa_recover_callback(XID_STATE *xs, Protocol *protocol)
|
||||
protocol->store_longlong((longlong) xs->xid.formatID, FALSE);
|
||||
protocol->store_longlong((longlong) xs->xid.gtrid_length, FALSE);
|
||||
protocol->store_longlong((longlong) xs->xid.bqual_length, FALSE);
|
||||
protocol->store(xs->xid.data, xs->xid.gtrid_length + xs->xid.bqual_length,
|
||||
&my_charset_bin);
|
||||
protocol->store(data, data_len, data_cs);
|
||||
if (protocol->write())
|
||||
return TRUE;
|
||||
}
|
||||
@@ -2007,11 +2098,28 @@ static my_bool xa_recover_callback(XID_STATE *xs, Protocol *protocol)
|
||||
}
|
||||
|
||||
|
||||
static my_bool xa_recover_callback_short(XID_STATE *xs, Protocol *protocol)
|
||||
{
|
||||
return xa_recover_callback(xs, protocol, xs->xid.data,
|
||||
xs->xid.gtrid_length + xs->xid.bqual_length, &my_charset_bin);
|
||||
}
|
||||
|
||||
|
||||
static my_bool xa_recover_callback_verbose(XID_STATE *xs, Protocol *protocol)
|
||||
{
|
||||
char buf[SQL_XIDSIZE];
|
||||
uint len= get_sql_xid(&xs->xid, buf);
|
||||
return xa_recover_callback(xs, protocol, buf, len,
|
||||
&my_charset_utf8_general_ci);
|
||||
}
|
||||
|
||||
|
||||
bool mysql_xa_recover(THD *thd)
|
||||
{
|
||||
List<Item> field_list;
|
||||
Protocol *protocol= thd->protocol;
|
||||
MEM_ROOT *mem_root= thd->mem_root;
|
||||
my_hash_walk_action action;
|
||||
DBUG_ENTER("mysql_xa_recover");
|
||||
|
||||
field_list.push_back(new (mem_root)
|
||||
@@ -2023,16 +2131,32 @@ bool mysql_xa_recover(THD *thd)
|
||||
field_list.push_back(new (mem_root)
|
||||
Item_int(thd, "bqual_length", 0,
|
||||
MY_INT32_NUM_DECIMAL_DIGITS), mem_root);
|
||||
field_list.push_back(new (mem_root)
|
||||
Item_empty_string(thd, "data",
|
||||
XIDDATASIZE), mem_root);
|
||||
{
|
||||
uint len;
|
||||
CHARSET_INFO *cs;
|
||||
|
||||
if (thd->lex->verbose)
|
||||
{
|
||||
len= SQL_XIDSIZE;
|
||||
cs= &my_charset_utf8_general_ci;
|
||||
action= (my_hash_walk_action) xa_recover_callback_verbose;
|
||||
}
|
||||
else
|
||||
{
|
||||
len= XIDDATASIZE;
|
||||
cs= &my_charset_bin;
|
||||
action= (my_hash_walk_action) xa_recover_callback_short;
|
||||
}
|
||||
|
||||
field_list.push_back(new (mem_root)
|
||||
Item_empty_string(thd, "data", len, cs), mem_root);
|
||||
}
|
||||
|
||||
if (protocol->send_result_set_metadata(&field_list,
|
||||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (xid_cache_iterate(thd, (my_hash_walk_action) xa_recover_callback,
|
||||
protocol))
|
||||
if (xid_cache_iterate(thd, action, protocol))
|
||||
DBUG_RETURN(1);
|
||||
my_eof(thd);
|
||||
DBUG_RETURN(0);
|
||||
|
@@ -652,6 +652,15 @@ struct xid_t {
|
||||
};
|
||||
typedef struct xid_t XID;
|
||||
|
||||
/*
|
||||
The size of XID string representation in the form
|
||||
'gtrid', 'bqual', formatID
|
||||
see xid_t::get_sql_string() for details.
|
||||
*/
|
||||
#define SQL_XIDSIZE (XIDDATASIZE * 2 + 8 + MY_INT64_NUM_DECIMAL_DIGITS)
|
||||
/* The 'buf' has to have space for at least SQL_XIDSIZE bytes. */
|
||||
uint get_sql_xid(XID *xid, char *buf);
|
||||
|
||||
/* for recover() handlerton call */
|
||||
#define MIN_XID_LIST_SIZE 128
|
||||
#define MAX_XID_LIST_SIZE (1024*128)
|
||||
|
@@ -6850,8 +6850,8 @@ ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID
|
||||
eng "GTID_NEXT cannot be changed by a client that owns a GTID. The client owns %s. Ownership is released on COMMIT or ROLLBACK"
|
||||
|
||||
ER_UNKNOWN_EXPLAIN_FORMAT
|
||||
eng "Unknown EXPLAIN format name: '%s'"
|
||||
rus "Неизвестное имя формата команды EXPLAIN: '%s'"
|
||||
eng "Unknown %s format name: '%s'"
|
||||
rus "Неизвестное имя формата команды %s: '%s'"
|
||||
|
||||
ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION 25006
|
||||
eng "Cannot execute statement in a READ ONLY transaction"
|
||||
|
@@ -1682,7 +1682,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
|
||||
opt_default_time_precision
|
||||
case_stmt_body opt_bin_mod
|
||||
opt_if_exists_table_element opt_if_not_exists_table_element
|
||||
opt_recursive
|
||||
opt_recursive opt_format_xid
|
||||
|
||||
%type <object_ddl_options>
|
||||
create_or_replace
|
||||
@@ -16810,9 +16810,26 @@ xa:
|
||||
{
|
||||
Lex->sql_command = SQLCOM_XA_ROLLBACK;
|
||||
}
|
||||
| XA_SYM RECOVER_SYM
|
||||
| XA_SYM RECOVER_SYM opt_format_xid
|
||||
{
|
||||
Lex->sql_command = SQLCOM_XA_RECOVER;
|
||||
Lex->verbose= $3;
|
||||
}
|
||||
;
|
||||
|
||||
opt_format_xid:
|
||||
/* empty */ { $$= false; }
|
||||
| FORMAT_SYM '=' ident_or_text
|
||||
{
|
||||
if (!my_strcasecmp(system_charset_info, $3.str, "SQL"))
|
||||
$$= true;
|
||||
else if (!my_strcasecmp(system_charset_info, $3.str, "RAW"))
|
||||
$$= false;
|
||||
else
|
||||
{
|
||||
my_yyabort_error((ER_UNKNOWN_EXPLAIN_FORMAT, MYF(0), "XA RECOVER", $3.str));
|
||||
$$= false;
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
|
Reference in New Issue
Block a user