Commit 0acac4fe authored by Alexey Botchkov's avatar Alexey Botchkov

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.
parent 1b5f0cbd
...@@ -115,3 +115,7 @@ c9: 0x000000000101000000000000000000F03F000000000000F03F ...@@ -115,3 +115,7 @@ c9: 0x000000000101000000000000000000F03F000000000000F03F
#Print the table contents in html format #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; <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 ...@@ -60,6 +60,59 @@ a
20 20
disconnect con1; disconnect con1;
connection default; 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 t1;
drop table if exists t1; drop table if exists t1;
create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb; create table t1(a int, b int, c varchar(20), primary key(a)) engine = innodb;
......
...@@ -72,5 +72,25 @@ SELECT * FROM t2; ...@@ -72,5 +72,25 @@ SELECT * FROM t2;
#Cleanup #Cleanup
DROP TABLE t1, t2; 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 # Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc --source include/wait_until_count_sessions.inc
...@@ -83,6 +83,53 @@ select * from t1; ...@@ -83,6 +83,53 @@ select * from t1;
disconnect con1; disconnect con1;
connection default; 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; drop table t1;
# #
...@@ -379,7 +426,6 @@ connection default; ...@@ -379,7 +426,6 @@ connection default;
DROP TABLE t1, t2; DROP TABLE t1, t2;
disconnect con2; disconnect con2;
# Wait till all disconnects are completed # Wait till all disconnects are completed
--source include/wait_until_count_sessions.inc --source include/wait_until_count_sessions.inc
...@@ -1981,6 +1981,97 @@ int ha_recover(HASH *commit_list) ...@@ -1981,6 +1981,97 @@ int ha_recover(HASH *commit_list)
DBUG_RETURN(0); 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. 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) ...@@ -1990,7 +2081,8 @@ int ha_recover(HASH *commit_list)
It can be easily fixed later, if necessary. 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) if (xs->xa_state == XA_PREPARED)
{ {
...@@ -1998,8 +2090,7 @@ static my_bool xa_recover_callback(XID_STATE *xs, Protocol *protocol) ...@@ -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.formatID, FALSE);
protocol->store_longlong((longlong) xs->xid.gtrid_length, FALSE); protocol->store_longlong((longlong) xs->xid.gtrid_length, FALSE);
protocol->store_longlong((longlong) xs->xid.bqual_length, FALSE); protocol->store_longlong((longlong) xs->xid.bqual_length, FALSE);
protocol->store(xs->xid.data, xs->xid.gtrid_length + xs->xid.bqual_length, protocol->store(data, data_len, data_cs);
&my_charset_bin);
if (protocol->write()) if (protocol->write())
return TRUE; return TRUE;
} }
...@@ -2007,11 +2098,28 @@ static my_bool xa_recover_callback(XID_STATE *xs, Protocol *protocol) ...@@ -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) bool mysql_xa_recover(THD *thd)
{ {
List<Item> field_list; List<Item> field_list;
Protocol *protocol= thd->protocol; Protocol *protocol= thd->protocol;
MEM_ROOT *mem_root= thd->mem_root; MEM_ROOT *mem_root= thd->mem_root;
my_hash_walk_action action;
DBUG_ENTER("mysql_xa_recover"); DBUG_ENTER("mysql_xa_recover");
field_list.push_back(new (mem_root) field_list.push_back(new (mem_root)
...@@ -2023,16 +2131,32 @@ bool mysql_xa_recover(THD *thd) ...@@ -2023,16 +2131,32 @@ bool mysql_xa_recover(THD *thd)
field_list.push_back(new (mem_root) field_list.push_back(new (mem_root)
Item_int(thd, "bqual_length", 0, Item_int(thd, "bqual_length", 0,
MY_INT32_NUM_DECIMAL_DIGITS), mem_root); MY_INT32_NUM_DECIMAL_DIGITS), 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) field_list.push_back(new (mem_root)
Item_empty_string(thd, "data", Item_empty_string(thd, "data", len, cs), mem_root);
XIDDATASIZE), mem_root); }
if (protocol->send_result_set_metadata(&field_list, if (protocol->send_result_set_metadata(&field_list,
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF)) Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
DBUG_RETURN(1); DBUG_RETURN(1);
if (xid_cache_iterate(thd, (my_hash_walk_action) xa_recover_callback, if (xid_cache_iterate(thd, action, protocol))
protocol))
DBUG_RETURN(1); DBUG_RETURN(1);
my_eof(thd); my_eof(thd);
DBUG_RETURN(0); DBUG_RETURN(0);
......
...@@ -652,6 +652,15 @@ struct xid_t { ...@@ -652,6 +652,15 @@ struct xid_t {
}; };
typedef struct xid_t XID; 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 */ /* for recover() handlerton call */
#define MIN_XID_LIST_SIZE 128 #define MIN_XID_LIST_SIZE 128
#define MAX_XID_LIST_SIZE (1024*128) #define MAX_XID_LIST_SIZE (1024*128)
......
...@@ -6850,8 +6850,8 @@ ER_CANT_SET_GTID_NEXT_WHEN_OWNING_GTID ...@@ -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" 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 ER_UNKNOWN_EXPLAIN_FORMAT
eng "Unknown EXPLAIN format name: '%s'" eng "Unknown %s format name: '%s'"
rus "Неизвестное имя формата команды EXPLAIN: '%s'" rus "Неизвестное имя формата команды %s: '%s'"
ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION 25006 ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION 25006
eng "Cannot execute statement in a READ ONLY transaction" eng "Cannot execute statement in a READ ONLY transaction"
......
...@@ -1682,7 +1682,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -1682,7 +1682,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_default_time_precision opt_default_time_precision
case_stmt_body opt_bin_mod case_stmt_body opt_bin_mod
opt_if_exists_table_element opt_if_not_exists_table_element opt_if_exists_table_element opt_if_not_exists_table_element
opt_recursive opt_recursive opt_format_xid
%type <object_ddl_options> %type <object_ddl_options>
create_or_replace create_or_replace
...@@ -16810,9 +16810,26 @@ xa: ...@@ -16810,9 +16810,26 @@ xa:
{ {
Lex->sql_command = SQLCOM_XA_ROLLBACK; Lex->sql_command = SQLCOM_XA_ROLLBACK;
} }
| XA_SYM RECOVER_SYM | XA_SYM RECOVER_SYM opt_format_xid
{ {
Lex->sql_command = SQLCOM_XA_RECOVER; 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;
}
} }
; ;
......
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