1
0
mirror of https://github.com/MariaDB/server.git synced 2026-01-06 05:22:24 +03:00
sql/item.cc:
  Auto merged
sql/item_func.cc:
  Auto merged
sql/protocol.cc:
  Auto merged
sql/sql_acl.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_select.cc:
  Auto merged
sql/table.cc:
  Auto merged
tests/mysql_client_test.c:
  Auto merged
BitKeeper/etc/logging_ok:
  Logging to logging@openlogging.org accepted
This commit is contained in:
unknown
2005-02-20 18:49:27 +02:00
247 changed files with 9330 additions and 4895 deletions

View File

@@ -83,6 +83,10 @@ const char *command_name[]={
"Error" // Last command number
};
const char *xa_state_names[]={
"NON-EXISTING", "ACTIVE", "IDLE", "PREPARED"
};
static char empty_c_string[1]= {0}; // Used for not defined 'db'
#ifdef __WIN__
@@ -152,7 +156,7 @@ static bool begin_trans(THD *thd)
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);
error= ha_start_consistent_snapshot(thd);
}
return error;
}
@@ -555,6 +559,12 @@ void free_max_user_conn(void)
sql_command is actually set to SQLCOM_END sometimes
so we need the +1 to include it in the array.
numbers are:
0 - read-only query
!= 0 - query that may change a table
2 - query that returns meaningful ROW_COUNT() -
a number of modified rows
*/
char uc_update_queries[SQLCOM_END+1];
@@ -566,23 +576,23 @@ void init_update_queries(void)
uc_update_queries[SQLCOM_CREATE_TABLE]=1;
uc_update_queries[SQLCOM_CREATE_INDEX]=1;
uc_update_queries[SQLCOM_ALTER_TABLE]=1;
uc_update_queries[SQLCOM_UPDATE]=1;
uc_update_queries[SQLCOM_INSERT]=1;
uc_update_queries[SQLCOM_INSERT_SELECT]=1;
uc_update_queries[SQLCOM_DELETE]=1;
uc_update_queries[SQLCOM_UPDATE]=2;
uc_update_queries[SQLCOM_UPDATE_MULTI]=2;
uc_update_queries[SQLCOM_INSERT]=2;
uc_update_queries[SQLCOM_INSERT_SELECT]=2;
uc_update_queries[SQLCOM_DELETE]=2;
uc_update_queries[SQLCOM_DELETE_MULTI]=2;
uc_update_queries[SQLCOM_TRUNCATE]=1;
uc_update_queries[SQLCOM_DROP_TABLE]=1;
uc_update_queries[SQLCOM_LOAD]=1;
uc_update_queries[SQLCOM_CREATE_DB]=1;
uc_update_queries[SQLCOM_DROP_DB]=1;
uc_update_queries[SQLCOM_REPLACE]=1;
uc_update_queries[SQLCOM_REPLACE_SELECT]=1;
uc_update_queries[SQLCOM_REPLACE]=2;
uc_update_queries[SQLCOM_REPLACE_SELECT]=2;
uc_update_queries[SQLCOM_RENAME_TABLE]=1;
uc_update_queries[SQLCOM_BACKUP_TABLE]=1;
uc_update_queries[SQLCOM_RESTORE_TABLE]=1;
uc_update_queries[SQLCOM_DELETE_MULTI]=1;
uc_update_queries[SQLCOM_DROP_INDEX]=1;
uc_update_queries[SQLCOM_UPDATE_MULTI]=1;
uc_update_queries[SQLCOM_CREATE_VIEW]=1;
uc_update_queries[SQLCOM_DROP_VIEW]=1;
}
@@ -708,12 +718,12 @@ static int check_connection(THD *thd)
{
uint connect_errors= 0;
NET *net= &thd->net;
ulong pkt_len= 0;
char *end;
DBUG_PRINT("info",
("New connection received on %s", vio_description(net->vio)));
vio_in_addr(net->vio,&thd->remote.sin_addr);
if (!thd->host) // If TCP/IP connection
{
char ip[30];
@@ -723,6 +733,7 @@ static int check_connection(THD *thd)
if (!(thd->ip= my_strdup(ip,MYF(0))))
return (ER_OUT_OF_RESOURCES);
thd->host_or_ip= thd->ip;
vio_in_addr(net->vio,&thd->remote.sin_addr);
#if !defined(HAVE_SYS_UN_H) || defined(HAVE_mit_thread)
/* Fast local hostname resolve for Win32 */
if (!strcmp(thd->ip,"127.0.0.1"))
@@ -758,10 +769,10 @@ static int check_connection(THD *thd)
DBUG_PRINT("info",("Host: %s",thd->host));
thd->host_or_ip= thd->host;
thd->ip= 0;
/* Reset sin_addr */
bzero((char*) &thd->remote, sizeof(thd->remote));
}
vio_keepalive(net->vio, TRUE);
ulong pkt_len= 0;
char *end;
{
/* buff[] needs to big enough to hold the server_version variable */
char buff[SERVER_VERSION_LENGTH + SCRAMBLE_LENGTH + 64];
@@ -823,17 +834,6 @@ static int check_connection(THD *thd)
return(ER_OUT_OF_RESOURCES);
thd->client_capabilities=uint2korr(net->read_pos);
#ifdef TO_BE_REMOVED_IN_4_1_RELEASE
/*
This is just a safety check against any client that would use the old
CLIENT_CHANGE_USER flag
*/
if ((thd->client_capabilities & CLIENT_PROTOCOL_41) &&
!(thd->client_capabilities & (CLIENT_RESERVED |
CLIENT_SECURE_CONNECTION |
CLIENT_MULTI_RESULTS)))
thd->client_capabilities&= ~CLIENT_PROTOCOL_41;
#endif
if (thd->client_capabilities & CLIENT_PROTOCOL_41)
{
thd->client_capabilities|= ((ulong) uint2korr(net->read_pos+2)) << 16;
@@ -1192,24 +1192,25 @@ extern "C" pthread_handler_decl(handle_bootstrap,arg)
We don't need to obtain LOCK_thread_count here because in bootstrap
mode we have only one thread.
*/
thd->query_id=query_id++;
if (mqh_used && thd->user_connect && check_mqh(thd, SQLCOM_END))
{
thd->net.error = 0;
close_thread_tables(thd); // Free tables
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
break;
}
thd->query_id=next_query_id();
mysql_parse(thd,thd->query,length);
close_thread_tables(thd); // Free tables
if (thd->is_fatal_error)
break;
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
#ifdef USING_TRANSACTIONS
free_root(&thd->transaction.mem_root,MYF(MY_KEEP_PREALLOC));
#endif
}
/* thd->fatal_error should be set in case something went wrong */
end:
bootstrap_error= thd->is_fatal_error;
net_end(&thd->net);
thd->cleanup();
delete thd;
#ifndef EMBEDDED_LIBRARY
(void) pthread_mutex_lock(&LOCK_thread_count);
thread_count--;
@@ -1218,7 +1219,7 @@ end:
my_thread_end();
pthread_exit(0);
#endif
DBUG_RETURN(0); // Never reached
DBUG_RETURN(0);
}
/* This works because items are allocated with sql_alloc() */
@@ -1284,45 +1285,27 @@ int mysql_table_dump(THD* thd, char* db, char* tbl_name, int fd)
my_error(ER_GET_ERRNO, MYF(0), error);
err:
close_thread_tables(thd);
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()
end_trans()
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)
int end_trans(THD *thd, enum enum_mysql_completiontype completion)
{
bool do_release= 0;
int res= 0;
LEX *lex= thd->lex;
DBUG_ENTER("mysql_endtrans");
DBUG_ENTER("end_trans");
switch (completion) {
case COMMIT:
@@ -1333,80 +1316,39 @@ int mysql_endtrans(THD *thd, enum enum_mysql_completiontype completion,
*/
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);
res= ha_commit(thd);
break;
case COMMIT_RELEASE:
do_release= 1;
do_release= 1; /* fall through */
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;
do_release= 1; /* fall through */
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
if (ha_rollback(thd))
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;
thd->killed= THD::KILL_CONNECTION;
DBUG_RETURN(res);
}
@@ -1621,7 +1563,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id=query_id;
if (command != COM_STATISTICS && command != COM_PING)
query_id++;
next_query_id();
thread_running++;
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
@@ -1773,13 +1715,14 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
if (alloc_query(thd, packet, packet_length))
break; // fatal error is set
char *packet_end= thd->query + thd->query_length;
mysql_log.write(thd,command,"%s",thd->query);
DBUG_PRINT("query",("%-.4096s",thd->query));
mysql_parse(thd,thd->query, thd->query_length);
while (!thd->killed && thd->lex->found_colon && !thd->net.report_error)
while (!thd->killed && thd->lex->found_semicolon && !thd->net.report_error)
{
char *packet= thd->lex->found_colon;
char *packet= thd->lex->found_semicolon;
/*
Multiple queries exits, execute them individually
in embedded server - just store them to be executed later
@@ -1788,7 +1731,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (thd->lock || thd->open_tables || thd->derived_tables)
close_thread_tables(thd);
#endif
ulong length= thd->query_length-(ulong)(packet-thd->query);
ulong length= (ulong)(packet_end-packet);
/* Remove garbage at start of query */
while (my_isspace(thd->charset(), *packet) && length > 0)
@@ -1799,7 +1742,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_length= length;
thd->query= packet;
thd->query_id= query_id++;
thd->query_id= next_query_id();
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
#ifndef EMBEDDED_LIBRARY
@@ -2104,7 +2047,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
statistic_increment(thd->status_var.com_other, &LOCK_status);
if (check_global_access(thd, SUPER_ACL))
break; /* purecov: inspected */
mysql_print_status(thd);
mysql_print_status();
mysql_log.write(thd,command,NullS);
send_eof(thd);
break;
@@ -2122,6 +2065,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->proc_info="closing tables";
close_thread_tables(thd); /* Free tables */
}
/*
assume handlers auto-commit (if some doesn't - transaction handling
in MySQL should be redesigned to support it; it's a big change,
and it's not worth it - better to commit explicitly only writing
transactions, read-only ones should better take care of themselves.
saves some work in 2pc too)
see also sql_base.cc - close_thread_tables()
*/
bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
if (!thd->active_transaction())
thd->transaction.xid.null();
/* report error issued during command execution */
if (thd->killed_errno() && !thd->net.report_error)
@@ -2413,9 +2367,14 @@ mysql_execute_command(THD *thd)
}
/*
Skip if we are in the slave thread, some table rules have been
given and the table list says the query should not be replicated
given and the table list says the query should not be replicated.
Exception is DROP TEMPORARY TABLE IF EXISTS: we always execute it
(otherwise we have stale files on slave caused by exclusion of one tmp
table).
*/
if (all_tables_not_ok(thd, all_tables))
if (!(lex->sql_command == SQLCOM_DROP_TABLE &&
lex->drop_temporary && lex->drop_if_exists) &&
all_tables_not_ok(thd, all_tables))
{
/* we warn the slave SQL thread */
my_message(ER_SLAVE_IGNORED_TABLE, ER(ER_SLAVE_IGNORED_TABLE), MYF(0));
@@ -2442,7 +2401,7 @@ mysql_execute_command(THD *thd)
*/
if (opt_readonly &&
!(thd->slave_thread || (thd->master_access & SUPER_ACL)) &&
(uc_update_queries[lex->sql_command] > 0))
uc_update_queries[lex->sql_command])
{
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
DBUG_RETURN(-1);
@@ -2708,7 +2667,7 @@ mysql_execute_command(THD *thd)
{
if (check_global_access(thd, REPL_SLAVE_ACL))
goto error;
res = show_binlog_events(thd);
res = mysql_show_binlog_events(thd);
break;
}
#endif
@@ -2743,7 +2702,7 @@ mysql_execute_command(THD *thd)
check_access(thd, INDEX_ACL, first_table->db,
&first_table->grant.privilege, 0, 0))
goto error;
res= mysql_assign_to_keycache(thd, first_table, &lex->name_and_length);
res= mysql_assign_to_keycache(thd, first_table, &lex->ident);
break;
}
case SQLCOM_PRELOAD_KEYS:
@@ -3364,7 +3323,7 @@ unsent_create_error:
first_table->ancestor && first_table->ancestor->next_local);
my_error(ER_VIEW_DELETE_MERGE_VIEW, MYF(0),
first_table->view_db.str, first_table->view_name.str);
res= -1;
res= FALSE;
break;
}
@@ -3389,7 +3348,6 @@ unsent_create_error:
}
else
res= TRUE;
close_thread_tables(thd);
break;
}
case SQLCOM_DROP_TABLE:
@@ -3912,7 +3870,7 @@ unsent_create_error:
*/
if (check_db_used(thd, all_tables))
goto error;
res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->backup_dir,
res= mysql_ha_read(thd, first_table, lex->ha_read_mode, lex->ident.str,
lex->insert_list, lex->ha_rkey_mode, select_lex->where,
select_lex->select_limit, select_lex->offset_limit);
break;
@@ -3920,32 +3878,121 @@ unsent_create_error:
case SQLCOM_BEGIN:
if (begin_trans(thd))
goto error;
else
send_ok(thd);
send_ok(thd);
break;
case SQLCOM_COMMIT:
if (mysql_endtrans(thd, lex->tx_release ? COMMIT_RELEASE :
lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT, 0))
if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
goto error;
send_ok(thd);
break;
case SQLCOM_ROLLBACK:
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 (mysql_endtrans(thd, SAVEPOINT_NAME_ROLLBACK, lex->savepoint_name))
goto error;
break;
case SQLCOM_SAVEPOINT:
if (!ha_savepoint(thd, lex->savepoint_name))
send_ok(thd);
else
if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
goto error;
send_ok(thd);
break;
case SQLCOM_RELEASE_SAVEPOINT:
if (mysql_endtrans(thd, SAVEPOINT_NAME_RELEASE, lex->savepoint_name))
goto error;
{
SAVEPOINT **sv;
for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
{
if (my_strnncoll(system_charset_info,
(uchar *)lex->ident.str, lex->ident.length,
(uchar *)(*sv)->name, (*sv)->length) == 0)
break;
}
if (*sv)
{
if (ha_release_savepoint(thd, *sv))
res= TRUE; // cannot happen
else
send_ok(thd);
*sv=(*sv)->prev;
}
else
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
res= TRUE;
}
break;
}
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
{
SAVEPOINT **sv;
for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
{
if (my_strnncoll(system_charset_info,
(uchar *)lex->ident.str, lex->ident.length,
(uchar *)(*sv)->name, (*sv)->length) == 0)
break;
}
if (*sv)
{
if (ha_rollback_to_savepoint(thd, *sv))
res= TRUE; // cannot happen
else
{
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);
}
*sv=(*sv)->prev;
}
else
{
my_error(ER_SP_DOES_NOT_EXIST, MYF(0), "SAVEPOINT", lex->ident.str);
res= TRUE;
}
break;
}
case SQLCOM_SAVEPOINT:
if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) ||
!opt_using_transactions)
send_ok(thd);
else
{
SAVEPOINT **sv, *newsv;
for (sv=&thd->transaction.savepoints; *sv; sv=&(*sv)->prev)
{
if (my_strnncoll(system_charset_info,
(uchar *)lex->ident.str, lex->ident.length,
(uchar *)(*sv)->name, (*sv)->length) == 0)
break;
}
if (*sv) /* old savepoint of the same name exists */
{
newsv=*sv;
ha_release_savepoint(thd, *sv); // it cannot fail
*sv=(*sv)->prev;
}
else if ((newsv=(SAVEPOINT *) alloc_root(&thd->transaction.mem_root,
savepoint_alloc_size)) == 0)
{
my_error(ER_OUT_OF_RESOURCES, MYF(0));
res= TRUE;
break;
}
newsv->name=strmake_root(&thd->transaction.mem_root,
lex->ident.str, lex->ident.length);
newsv->length=lex->ident.length;
/*
if we'll get an error here, don't add new savepoint to the list.
we'll lose a little bit of memory in transaction mem_root, but it'll
be free'd when transaction ends anyway
*/
if (ha_savepoint(thd, newsv))
res= TRUE;
else
{
newsv->prev=thd->transaction.savepoints;
thd->transaction.savepoints=newsv;
send_ok(thd);
}
}
break;
case SQLCOM_CREATE_PROCEDURE:
case SQLCOM_CREATE_SPFUNCTION:
@@ -3962,12 +4009,12 @@ unsent_create_error:
lex->sphead= 0;
goto error;
}
if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
{
lex->sphead->m_db.length= strlen(thd->db);
lex->sphead->m_db.str= strmake_root(thd->mem_root, thd->db,
lex->sphead->m_db.length);
lex->sphead->m_db.str= strmake_root(thd->mem_root, thd->db,
lex->sphead->m_db.length);
}
name= lex->sphead->name(&namelen);
@@ -4332,7 +4379,157 @@ unsent_create_error:
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
break;
}
default: /* Impossible */
case SQLCOM_XA_START:
if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_RESUME)
{
if (! thd->transaction.xid.eq(&thd->lex->ident))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
}
thd->transaction.xa_state=XA_ACTIVE;
send_ok(thd);
res=TRUE;
break;
}
if (thd->lex->ident.length > MAXGTRIDSIZE || thd->lex->xa_opt != XA_NONE)
{ // JOIN is not supported yet. TODO
my_error(ER_XAER_INVAL, MYF(0));
break;
}
if (thd->transaction.xa_state != XA_NOTR)
{
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
if (thd->active_transaction() || thd->locked_tables)
{
my_error(ER_XAER_OUTSIDE, MYF(0));
break;
}
DBUG_ASSERT(thd->transaction.xid.is_null());
thd->transaction.xa_state=XA_ACTIVE;
thd->transaction.xid.set(&thd->lex->ident);
thd->options= ((thd->options & (ulong) ~(OPTION_STATUS_NO_TRANS_UPDATE)) |
OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
send_ok(thd);
res=TRUE;
break;
case SQLCOM_XA_END:
/* fake it */
if (thd->lex->xa_opt != XA_NONE)
{ // SUSPEND and FOR MIGRATE are not supported yet. TODO
my_error(ER_XAER_INVAL, MYF(0));
break;
}
if (thd->transaction.xa_state != XA_ACTIVE)
{
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
if (!thd->transaction.xid.eq(&thd->lex->ident))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
}
thd->transaction.xa_state=XA_IDLE;
send_ok(thd);
res=TRUE;
break;
case SQLCOM_XA_PREPARE:
if (thd->transaction.xa_state != XA_IDLE)
{
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
if (!thd->transaction.xid.eq(&thd->lex->ident))
{
my_error(ER_XAER_NOTA, MYF(0));
break;
}
if (ha_prepare(thd))
{
my_error(ER_XA_RBROLLBACK, MYF(0));
thd->transaction.xa_state=XA_NOTR;
break;
}
res=TRUE;
thd->transaction.xa_state=XA_PREPARED;
send_ok(thd);
break;
case SQLCOM_XA_COMMIT:
if (!thd->transaction.xid.eq(&thd->lex->ident))
{
if (!(res= !ha_commit_or_rollback_by_xid(&thd->lex->ident, 1)))
my_error(ER_XAER_NOTA, MYF(0));
break;
}
if (thd->transaction.xa_state == XA_IDLE && thd->lex->xa_opt == XA_ONE_PHASE)
{
int r;
if ((r= ha_commit(thd)))
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
else
{
send_ok(thd);
res= TRUE;
}
}
else
if (thd->transaction.xa_state == XA_PREPARED && thd->lex->xa_opt == XA_NONE)
{
if (ha_commit_one_phase(thd, 1))
my_error(ER_XAER_RMERR, MYF(0));
else
{
send_ok(thd);
res= TRUE;
}
}
else
{
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
thd->transaction.xa_state=XA_NOTR;
break;
case SQLCOM_XA_ROLLBACK:
if (!thd->transaction.xid.eq(&thd->lex->ident))
{
if (!(res= !ha_commit_or_rollback_by_xid(&thd->lex->ident, 0)))
my_error(ER_XAER_NOTA, MYF(0));
break;
}
if (thd->transaction.xa_state != XA_IDLE &&
thd->transaction.xa_state != XA_PREPARED)
{
my_error(ER_XAER_RMFAIL, MYF(0),
xa_state_names[thd->transaction.xa_state]);
break;
}
if (ha_rollback(thd))
my_error(ER_XAER_RMERR, MYF(0));
else
{
send_ok(thd);
res= TRUE;
}
thd->options&= ~(ulong) (OPTION_BEGIN | OPTION_STATUS_NO_TRANS_UPDATE);
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
thd->transaction.xa_state=XA_NOTR;
break;
case SQLCOM_XA_RECOVER:
res= !mysql_xa_recover(thd);
break;
default:
DBUG_ASSERT(0); /* Impossible */
send_ok(thd);
break;
}
@@ -4367,22 +4564,10 @@ unsent_create_error:
the statement is not DELETE, INSERT or UPDATE (or a CALL executing
such a statement), but -1 is what JDBC and ODBC wants.
*/
switch (lex->sql_command) {
case SQLCOM_UPDATE:
case SQLCOM_UPDATE_MULTI:
case SQLCOM_REPLACE:
case SQLCOM_INSERT:
case SQLCOM_REPLACE_SELECT:
case SQLCOM_INSERT_SELECT:
case SQLCOM_DELETE:
case SQLCOM_DELETE_MULTI:
case SQLCOM_CALL:
break;
default:
if (lex->sql_command != SQLCOM_CALL && uc_update_queries[lex->sql_command]<2)
thd->row_count_func= -1;
}
goto cleanup;
error:
res= 1;
@@ -4997,6 +5182,20 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
}
else
{
/*
Binlog logs a string starting from thd->query and having length
thd->query_length; so we set thd->query_length correctly (to not
log several statements in one event, when we executed only first).
We set it to not see the ';' (otherwise it would get into binlog
and Query_log_event::print() would give ';;' output).
This also helps display only the current query in SHOW
PROCESSLIST.
Note that we don't need LOCK_thread_count to modify query_length.
*/
if (lex->found_semicolon &&
(thd->query_length= (ulong)(lex->found_semicolon - thd->query)))
thd->query_length--;
/* Actually execute the query */
mysql_execute_command(thd);
query_cache_end_of_result(thd);
}
@@ -5153,17 +5352,7 @@ bool add_field_to_list(THD *thd, char *field_name, enum_field_types type,
new_field->charset=cs;
new_field->geom_type= (Field::geometry_type) uint_geom_type;
if (!comment)
{
new_field->comment.str=0;
new_field->comment.length=0;
}
else
{
/* In this case comment is always of type Item_string */
new_field->comment.str= (char*) comment->str;
new_field->comment.length=comment->length;
}
new_field->comment=*comment;
/*
Set flag if this field doesn't have a default value
Enum values has always the first value as a default (set in