summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rwxr-xr-xsql/CMakeLists.txt4
-rw-r--r--sql/event_queue.cc38
-rw-r--r--sql/events.cc9
-rw-r--r--sql/filesort.cc7
-rw-r--r--sql/ha_ndbcluster.cc2
-rw-r--r--sql/ha_ndbcluster_binlog.cc3
-rw-r--r--sql/handler.cc619
-rw-r--r--sql/handler.h122
-rw-r--r--sql/item.cc117
-rw-r--r--sql/item.h187
-rw-r--r--sql/item_cmpfunc.cc56
-rw-r--r--sql/item_cmpfunc.h51
-rw-r--r--sql/item_func.cc67
-rw-r--r--sql/item_func.h54
-rw-r--r--sql/item_geofunc.h9
-rw-r--r--sql/item_row.cc4
-rw-r--r--sql/item_row.h2
-rw-r--r--sql/item_strfunc.cc32
-rw-r--r--sql/item_strfunc.h12
-rw-r--r--sql/item_subselect.cc49
-rw-r--r--sql/item_subselect.h20
-rw-r--r--sql/item_sum.cc14
-rw-r--r--sql/item_sum.h6
-rw-r--r--sql/item_timefunc.cc32
-rw-r--r--sql/item_timefunc.h14
-rw-r--r--sql/log.cc10
-rw-r--r--sql/log_event.cc5
-rw-r--r--sql/log_event_old.cc22
-rw-r--r--sql/mysql_priv.h24
-rw-r--r--sql/mysqld.cc226
-rw-r--r--sql/net_serv.cc24
-rw-r--r--sql/protocol.cc8
-rw-r--r--sql/repl_failsafe.cc8
-rw-r--r--sql/rpl_injector.cc20
-rw-r--r--sql/set_var.cc18
-rw-r--r--sql/slave.cc2
-rw-r--r--sql/sp.cc22
-rw-r--r--sql/sp_head.cc17
-rw-r--r--sql/sql_acl.cc8
-rw-r--r--sql/sql_base.cc58
-rw-r--r--sql/sql_binlog.cc2
-rw-r--r--sql/sql_class.cc26
-rw-r--r--sql/sql_class.h44
-rw-r--r--sql/sql_connect.cc23
-rw-r--r--sql/sql_cursor.cc103
-rw-r--r--sql/sql_db.cc10
-rw-r--r--sql/sql_delete.cc50
-rw-r--r--sql/sql_do.cc14
-rw-r--r--sql/sql_error.cc2
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_help.cc2
-rw-r--r--sql/sql_insert.cc48
-rw-r--r--sql/sql_lex.cc27
-rw-r--r--sql/sql_lex.h18
-rw-r--r--sql/sql_load.cc12
-rw-r--r--sql/sql_parse.cc208
-rw-r--r--sql/sql_partition.cc40
-rw-r--r--sql/sql_plugin.cc7
-rw-r--r--sql/sql_prepare.cc53
-rw-r--r--sql/sql_profile.cc2
-rw-r--r--sql/sql_rename.cc2
-rw-r--r--sql/sql_repl.cc20
-rw-r--r--sql/sql_select.cc81
-rw-r--r--sql/sql_show.cc20
-rw-r--r--sql/sql_table.cc66
-rw-r--r--sql/sql_test.cc6
-rw-r--r--sql/sql_trigger.cc2
-rw-r--r--sql/sql_udf.cc9
-rw-r--r--sql/sql_update.cc71
-rw-r--r--sql/sql_view.cc303
-rw-r--r--sql/sql_view.h3
-rw-r--r--sql/sql_yacc.yy88
-rw-r--r--sql/stacktrace.c275
-rw-r--r--sql/stacktrace.h22
-rw-r--r--sql/table.h2
75 files changed, 2593 insertions, 1076 deletions
diff --git a/sql/CMakeLists.txt b/sql/CMakeLists.txt
index 1dffb6ffb58..c5c8c27bc4e 100755
--- a/sql/CMakeLists.txt
+++ b/sql/CMakeLists.txt
@@ -43,7 +43,7 @@ ADD_DEFINITIONS(-DMYSQL_SERVER -D_CONSOLE -DHAVE_DLOPEN)
ADD_EXECUTABLE(mysqld
../sql-common/client.c derror.cc des_key_file.cc
- discover.cc ../libmysql/errmsg.c field.cc field_conv.cc
+ discover.cc ../libmysql/errmsg.c field.cc stacktrace.c stacktrace.h field_conv.cc
filesort.cc gstream.cc
ha_partition.cc
handler.cc hash_filo.cc hash_filo.h
@@ -168,5 +168,5 @@ SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES
"lex_hash.h;message.rc;message.h;sql_yacc.h;sql_yacc.cc")
ADD_LIBRARY(udf_example MODULE udf_example.c udf_example.def)
-ADD_DEPENDENCIES(udf_example strings)
+ADD_DEPENDENCIES(udf_example strings GenError)
TARGET_LINK_LIBRARIES(udf_example strings wsock32)
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 898fc206c34..719a837cbfb 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -60,8 +60,16 @@ extern "C" int event_queue_element_compare_q(void *, uchar *, uchar *);
int event_queue_element_compare_q(void *vptr, uchar* a, uchar *b)
{
- my_time_t lhs = ((Event_queue_element *)a)->execute_at;
- my_time_t rhs = ((Event_queue_element *)b)->execute_at;
+ Event_queue_element *left = (Event_queue_element *)a;
+ Event_queue_element *right = (Event_queue_element *)b;
+ my_time_t lhs = left->execute_at;
+ my_time_t rhs = right->execute_at;
+
+ if (left->status == Event_queue_element::DISABLED)
+ return right->status != Event_queue_element::DISABLED;
+
+ if (right->status == Event_queue_element::DISABLED)
+ return 1;
return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0));
}
@@ -434,8 +442,34 @@ Event_queue::recalculate_activation_times(THD *thd)
((Event_queue_element*)queue_element(&queue, i))->update_timing_fields(thd);
}
queue_fix(&queue);
+ /*
+ The disabled elements are moved to the end during the `fix`.
+ Start from the end and remove all of the elements which are
+ disabled. When we find the first non-disabled one we break, as we
+ have removed all. The queue has been ordered in a way the disabled
+ events are at the end.
+ */
+ for (i= queue.elements; i > 0; i--)
+ {
+ Event_queue_element *element = (Event_queue_element*)queue_element(&queue, i - 1);
+ if (element->status != Event_queue_element::DISABLED)
+ break;
+ /*
+ This won't cause queue re-order, because we remove
+ always the last element.
+ */
+ queue_remove(&queue, i - 1);
+ delete element;
+ }
UNLOCK_QUEUE_DATA();
+ /*
+ XXX: The events are dropped only from memory and not from disk
+ even if `drop_list[j]->dropped` is TRUE. There will be still on the
+ disk till next server restart.
+ Please add code here to do it.
+ */
+
DBUG_VOID_RETURN;
}
diff --git a/sql/events.cc b/sql/events.cc
index 87385082a82..4225ca055de 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -737,7 +737,7 @@ send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
if (protocol->write())
DBUG_RETURN(TRUE);
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -1185,7 +1185,12 @@ Events::load_events_from_db(THD *thd)
{
/*
If not created, a stale event - drop if immediately if
- ON COMPLETION NOT PRESERVE
+ ON COMPLETION NOT PRESERVE.
+ XXX: This won't be replicated, thus the drop won't appear in
+ in the slave. When the slave is restarted it will drop events.
+ However, as the slave will be "out of sync", it might happen that
+ an event created on the master, after master restart, won't be
+ replicated to the slave correctly, as the create will fail there.
*/
int rc= table->file->ha_delete_row(table->record[0]);
if (rc)
diff --git a/sql/filesort.cc b/sql/filesort.cc
index 3783aa2a06a..ac731616218 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -120,6 +120,13 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
FILESORT_INFO table_sort;
TABLE_LIST *tab= table->pos_in_table_list;
Item_subselect *subselect= tab ? tab->containing_subselect() : 0;
+
+ /*
+ Release InnoDB's adaptive hash index latch (if holding) before
+ running a sort.
+ */
+ ha_release_temporary_latches(thd);
+
/*
Don't use table->sort in filesort as it is also used by
QUICK_INDEX_MERGE_SELECT. Work with a copy and put it back at the end
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index fdee8f92331..1cfe403407e 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -9454,7 +9454,7 @@ ha_ndbcluster::cond_push(const COND *cond)
my_errno= HA_ERR_OUT_OF_MEM;
DBUG_RETURN(NULL);
}
- DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname););
+ DBUG_EXECUTE("where",print_where((COND *)cond, m_tabname, QT_ORDINARY););
DBUG_RETURN(m_cond->cond_push(cond, table, (NDBTAB *)m_table));
}
diff --git a/sql/ha_ndbcluster_binlog.cc b/sql/ha_ndbcluster_binlog.cc
index af185e97360..4fd5ee1b402 100644
--- a/sql/ha_ndbcluster_binlog.cc
+++ b/sql/ha_ndbcluster_binlog.cc
@@ -283,6 +283,7 @@ static void run_query(THD *thd, char *buf, char *end,
thd_ndb->m_error_code,
(int) thd->is_error(), thd->is_slave_error);
}
+ close_thread_tables(thd);
/*
XXX: this code is broken. mysql_parse()/mysql_reset_thd_for_next_command()
can not be called from within a statement, and
@@ -1015,7 +1016,7 @@ static void ndbcluster_get_schema(NDB_SHARE *share,
uint blob_len= field_blob->get_length((*field)->ptr);
uchar *blob_ptr= 0;
field_blob->get_ptr(&blob_ptr);
- assert(blob_len == 0 || blob_ptr != 0);
+ DBUG_ASSERT(blob_len == 0 || blob_ptr != 0);
s->query_length= blob_len;
s->query= sql_strmake((char*) blob_ptr, blob_len);
}
diff --git a/sql/handler.cc b/sql/handler.cc
index eba9b0dc5ea..0fb61895a61 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -576,6 +576,295 @@ void ha_close_connection(THD* thd)
======================= TRANSACTIONS ===================================*/
/**
+ Transaction handling in the server
+ ==================================
+
+ In each client connection, MySQL maintains two transactional
+ states:
+ - a statement transaction,
+ - a standard, also called normal transaction.
+
+ Historical note
+ ---------------
+ "Statement transaction" is a non-standard term that comes
+ from the times when MySQL supported BerkeleyDB storage engine.
+
+ First of all, it should be said that in BerkeleyDB auto-commit
+ mode auto-commits operations that are atomic to the storage
+ engine itself, such as a write of a record, and are too
+ high-granular to be atomic from the application perspective
+ (MySQL). One SQL statement could involve many BerkeleyDB
+ auto-committed operations and thus BerkeleyDB auto-commit was of
+ little use to MySQL.
+
+ Secondly, instead of SQL standard savepoints, BerkeleyDB
+ provided the concept of "nested transactions". In a nutshell,
+ transactions could be arbitrarily nested, but when the parent
+ transaction was committed or aborted, all its child (nested)
+ transactions were handled committed or aborted as well.
+ Commit of a nested transaction, in turn, made its changes
+ visible, but not durable: it destroyed the nested transaction,
+ all its changes would become available to the parent and
+ currently active nested transactions of this parent.
+
+ So the mechanism of nested transactions was employed to
+ provide "all or nothing" guarantee of SQL statements
+ required by the standard.
+ A nested transaction would be created at start of each SQL
+ statement, and destroyed (committed or aborted) at statement
+ end. Such nested transaction was internally referred to as
+ a "statement transaction" and gave birth to the term.
+
+ <Historical note ends>
+
+ Since then a statement transaction is started for each statement
+ that accesses transactional tables or uses the binary log. If
+ the statement succeeds, the statement transaction is committed.
+ If the statement fails, the transaction is rolled back. Commits
+ of statement transactions are not durable -- each such
+ transaction is nested in the normal transaction, and if the
+ normal transaction is rolled back, the effects of all enclosed
+ statement transactions are undone as well. Technically,
+ a statement transaction can be viewed as a savepoint which is
+ maintained automatically in order to make effects of one
+ statement atomic.
+
+ The normal transaction is started by the user and is ended
+ usually upon a user request as well. The normal transaction
+ encloses transactions of all statements issued between
+ its beginning and its end.
+ In autocommit mode, the normal transaction is equivalent
+ to the statement transaction.
+
+ Since MySQL supports PSEA (pluggable storage engine
+ architecture), more than one transactional engine can be
+ active at a time. Hence transactions, from the server
+ point of view, are always distributed. In particular,
+ transactional state is maintained independently for each
+ engine. In order to commit a transaction the two phase
+ commit protocol is employed.
+
+ Not all statements are executed in context of a transaction.
+ Administrative and status information statements do not modify
+ engine data, and thus do not start a statement transaction and
+ also have no effect on the normal transaction. Examples of such
+ statements are SHOW STATUS and RESET SLAVE.
+
+ Similarly DDL statements are not transactional,
+ and therefore a transaction is [almost] never started for a DDL
+ statement. The difference between a DDL statement and a purely
+ administrative statement though is that a DDL statement always
+ commits the current transaction before proceeding, if there is
+ any.
+
+ At last, SQL statements that work with non-transactional
+ engines also have no effect on the transaction state of the
+ connection. Even though they are written to the binary log,
+ and the binary log is, overall, transactional, the writes
+ are done in "write-through" mode, directly to the binlog
+ file, followed with a OS cache sync, in other words,
+ bypassing the binlog undo log (translog).
+ They do not commit the current normal transaction.
+ A failure of a statement that uses non-transactional tables
+ would cause a rollback of the statement transaction, but
+ in case there no non-transactional tables are used,
+ no statement transaction is started.
+
+ Data layout
+ -----------
+
+ The server stores its transaction-related data in
+ thd->transaction. This structure has two members of type
+ THD_TRANS. These members correspond to the statement and
+ normal transactions respectively:
+
+ - thd->transaction.stmt contains a list of engines
+ that are participating in the given statement
+ - thd->transaction.all contains a list of engines that
+ have participated in any of the statement transactions started
+ within the context of the normal transaction.
+ Each element of the list contains a pointer to the storage
+ engine, engine-specific transactional data, and engine-specific
+ transaction flags.
+
+ In autocommit mode thd->transaction.all is empty.
+ Instead, data of thd->transaction.stmt is
+ used to commit/rollback the normal transaction.
+
+ The list of registered engines has a few important properties:
+ - no engine is registered in the list twice
+ - engines are present in the list a reverse temporal order --
+ new participants are always added to the beginning of the list.
+
+ Transaction life cycle
+ ----------------------
+
+ When a new connection is established, thd->transaction
+ members are initialized to an empty state.
+ If a statement uses any tables, all affected engines
+ are registered in the statement engine list. In
+ non-autocommit mode, the same engines are registered in
+ the normal transaction list.
+ At the end of the statement, the server issues a commit
+ or a roll back for all engines in the statement list.
+ At this point transaction flags of an engine, if any, are
+ propagated from the statement list to the list of the normal
+ transaction.
+ When commit/rollback is finished, the statement list is
+ cleared. It will be filled in again by the next statement,
+ and emptied again at the next statement's end.
+
+ The normal transaction is committed in a similar way
+ (by going over all engines in thd->transaction.all list)
+ but at different times:
+ - upon COMMIT SQL statement is issued by the user
+ - implicitly, by the server, at the beginning of a DDL statement
+ or SET AUTOCOMMIT={0|1} statement.
+
+ The normal transaction can be rolled back as well:
+ - if the user has requested so, by issuing ROLLBACK SQL
+ statement
+ - if one of the storage engines requested a rollback
+ by setting thd->transaction_rollback_request. This may
+ happen in case, e.g., when the transaction in the engine was
+ chosen a victim of the internal deadlock resolution algorithm
+ and rolled back internally. When such a situation happens, there
+ is little the server can do and the only option is to rollback
+ transactions in all other participating engines. In this case
+ the rollback is accompanied by an error sent to the user.
+
+ As follows from the use cases above, the normal transaction
+ is never committed when there is an outstanding statement
+ transaction. In most cases there is no conflict, since
+ commits of the normal transaction are issued by a stand-alone
+ administrative or DDL statement, thus no outstanding statement
+ transaction of the previous statement exists. Besides,
+ all statements that manipulate with the normal transaction
+ are prohibited in stored functions and triggers, therefore
+ no conflicting situation can occur in a sub-statement either.
+ The remaining rare cases when the server explicitly has
+ to commit the statement transaction prior to committing the normal
+ one cover error-handling scenarios (see for example
+ SQLCOM_LOCK_TABLES).
+
+ When committing a statement or a normal transaction, the server
+ either uses the two-phase commit protocol, or issues a commit
+ in each engine independently. The two-phase commit protocol
+ is used only if:
+ - all participating engines support two-phase commit (provide
+ handlerton::prepare PSEA API call) and
+ - transactions in at least two engines modify data (i.e. are
+ not read-only).
+
+ Note that the two phase commit is used for
+ statement transactions, even though they are not durable anyway.
+ This is done to ensure logical consistency of data in a multiple-
+ engine transaction.
+ For example, imagine that some day MySQL supports unique
+ constraint checks deferred till the end of statement. In such
+ case a commit in one of the engines may yield ER_DUP_KEY,
+ and MySQL should be able to gracefully abort statement
+ transactions of other participants.
+
+ After the normal transaction has been committed,
+ thd->transaction.all list is cleared.
+
+ When a connection is closed, the current normal transaction, if
+ any, is rolled back.
+
+ Roles and responsibilities
+ --------------------------
+
+ The server has no way to know that an engine participates in
+ the statement and a transaction has been started
+ in it unless the engine says so. Thus, in order to be
+ a part of a transaction, the engine must "register" itself.
+ This is done by invoking trans_register_ha() server call.
+ Normally the engine registers itself whenever handler::external_lock()
+ is called. trans_register_ha() can be invoked many times: if
+ an engine is already registered, the call does nothing.
+ In case autocommit is not set, the engine must register itself
+ twice -- both in the statement list and in the normal transaction
+ list.
+ In which list to register is a parameter of trans_register_ha().
+
+ Note, that although the registration interface in itself is
+ fairly clear, the current usage practice often leads to undesired
+ effects. E.g. since a call to trans_register_ha() in most engines
+ is embedded into implementation of handler::external_lock(), some
+ DDL statements start a transaction (at least from the server
+ point of view) even though they are not expected to. E.g.
+ CREATE TABLE does not start a transaction, since
+ handler::external_lock() is never called during CREATE TABLE. But
+ CREATE TABLE ... SELECT does, since handler::external_lock() is
+ called for the table that is being selected from. This has no
+ practical effects currently, but must be kept in mind
+ nevertheless.
+
+ Once an engine is registered, the server will do the rest
+ of the work.
+
+ During statement execution, whenever any of data-modifying
+ PSEA API methods is used, e.g. handler::write_row() or
+ handler::update_row(), the read-write flag is raised in the
+ statement transaction for the involved engine.
+ Currently All PSEA calls are "traced", and the data can not be
+ changed in a way other than issuing a PSEA call. Important:
+ unless this invariant is preserved the server will not know that
+ a transaction in a given engine is read-write and will not
+ involve the two-phase commit protocol!
+
+ At the end of a statement, server call
+ ha_autocommit_or_rollback() is invoked. This call in turn
+ invokes handlerton::prepare() for every involved engine.
+ Prepare is followed by a call to handlerton::commit_one_phase()
+ If a one-phase commit will suffice, handlerton::prepare() is not
+ invoked and the server only calls handlerton::commit_one_phase().
+ At statement commit, the statement-related read-write engine
+ flag is propagated to the corresponding flag in the normal
+ transaction. When the commit is complete, the list of registered
+ engines is cleared.
+
+ Rollback is handled in a similar fashion.
+
+ Additional notes on DDL and the normal transaction.
+ ---------------------------------------------------
+
+ DDLs and operations with non-transactional engines
+ do not "register" in thd->transaction lists, and thus do not
+ modify the transaction state. Besides, each DDL in
+ MySQL is prefixed with an implicit normal transaction commit
+ (a call to end_active_trans()), and thus leaves nothing
+ to modify.
+ However, as it has been pointed out with CREATE TABLE .. SELECT,
+ some DDL statements can start a *new* transaction.
+
+ Behaviour of the server in this case is currently badly
+ defined.
+ DDL statements use a form of "semantic" logging
+ to maintain atomicity: if CREATE TABLE .. SELECT failed,
+ the newly created table is deleted.
+ In addition, some DDL statements issue interim transaction
+ commits: e.g. ALTER TABLE issues a commit after data is copied
+ from the original table to the internal temporary table. Other
+ statements, e.g. CREATE TABLE ... SELECT do not always commit
+ after itself.
+ And finally there is a group of DDL statements such as
+ RENAME/DROP TABLE that doesn't start a new transaction
+ and doesn't commit.
+
+ This diversity makes it hard to say what will happen if
+ by chance a stored function is invoked during a DDL --
+ whether any modifications it makes will be committed or not
+ is not clear. Fortunately, SQL grammar of few DDLs allows
+ invocation of a stored function.
+
+ A consistent behaviour is perhaps to always commit the normal
+ transaction after all DDLs, just like the statement transaction
+ is always committed at the end of all statements.
+*/
+
+/**
Register a storage engine for a transaction.
Every storage engine MUST call this function when it starts
@@ -592,7 +881,7 @@ void ha_close_connection(THD* thd)
void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
{
THD_TRANS *trans;
- handlerton **ht;
+ Ha_trx_info *ha_info;
DBUG_ENTER("trans_register_ha");
DBUG_PRINT("enter",("%s", all ? "all" : "stmt"));
@@ -604,12 +893,13 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
else
trans= &thd->transaction.stmt;
- for (ht=trans->ht; *ht; ht++)
- if (*ht == ht_arg)
- DBUG_VOID_RETURN; /* already registered, return */
+ ha_info= thd->ha_data[ht_arg->slot].ha_info + static_cast<unsigned>(all);
+
+ if (ha_info->is_started())
+ DBUG_VOID_RETURN; /* already registered, return */
+
+ ha_info->register_ha(trans, ht_arg);
- trans->ht[trans->nht++]=ht_arg;
- DBUG_ASSERT(*ht == ht_arg);
trans->no_2pc|=(ht_arg->prepare==0);
if (thd->transaction.xid_state.xid.is_null())
thd->transaction.xid_state.xid.set(thd->query_id);
@@ -626,18 +916,19 @@ int ha_prepare(THD *thd)
{
int error=0, all=1;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
- handlerton **ht=trans->ht;
+ Ha_trx_info *ha_info= trans->ha_list;
DBUG_ENTER("ha_prepare");
#ifdef USING_TRANSACTIONS
- if (trans->nht)
+ if (ha_info)
{
- for (; *ht; ht++)
+ for (; ha_info; ha_info= ha_info->next())
{
int err;
+ handlerton *ht= ha_info->ht();
status_var_increment(thd->status_var.ha_prepare_count);
- if ((*ht)->prepare)
+ if (ht->prepare)
{
- if ((err= (*(*ht)->prepare)(*ht, thd, all)))
+ if ((err= ht->prepare(ht, thd, all)))
{
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
ha_rollback_trans(thd, all);
@@ -649,7 +940,7 @@ int ha_prepare(THD *thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_ILLEGAL_HA, ER(ER_ILLEGAL_HA),
- ha_resolve_storage_engine_name(*ht));
+ ha_resolve_storage_engine_name(ht));
}
}
}
@@ -658,6 +949,62 @@ int ha_prepare(THD *thd)
}
/**
+ Check if we can skip the two-phase commit.
+
+ A helper function to evaluate if two-phase commit is mandatory.
+ As a side effect, propagates the read-only/read-write flags
+ of the statement transaction to its enclosing normal transaction.
+
+ @retval TRUE we must run a two-phase commit. Returned
+ if we have at least two engines with read-write changes.
+ @retval FALSE Don't need two-phase commit. Even if we have two
+ transactional engines, we can run two independent
+ commits if changes in one of the engines are read-only.
+*/
+
+static
+bool
+ha_check_and_coalesce_trx_read_only(THD *thd, Ha_trx_info *ha_list,
+ bool all)
+{
+ /* The number of storage engines that have actual changes. */
+ unsigned rw_ha_count= 0;
+ Ha_trx_info *ha_info;
+
+ for (ha_info= ha_list; ha_info; ha_info= ha_info->next())
+ {
+ if (ha_info->is_trx_read_write())
+ ++rw_ha_count;
+
+ if (! all)
+ {
+ Ha_trx_info *ha_info_all= &thd->ha_data[ha_info->ht()->slot].ha_info[1];
+ DBUG_ASSERT(ha_info != ha_info_all);
+ /*
+ Merge read-only/read-write information about statement
+ transaction to its enclosing normal transaction. Do this
+ only if in a real transaction -- that is, if we know
+ that ha_info_all is registered in thd->transaction.all.
+ Since otherwise we only clutter the normal transaction flags.
+ */
+ if (ha_info_all->is_started()) /* FALSE if autocommit. */
+ ha_info_all->coalesce_trx_with(ha_info);
+ }
+ else if (rw_ha_count > 1)
+ {
+ /*
+ It is a normal transaction, so we don't need to merge read/write
+ information up, and the need for two-phase commit has been
+ already established. Break the loop prematurely.
+ */
+ break;
+ }
+ }
+ return rw_ha_count > 1;
+}
+
+
+/**
@retval
0 ok
@retval
@@ -674,12 +1021,25 @@ int ha_prepare(THD *thd)
int ha_commit_trans(THD *thd, bool all)
{
int error= 0, cookie= 0;
+ /*
+ 'all' means that this is either an explicit commit issued by
+ user, or an implicit commit issued by a DDL.
+ */
THD_TRANS *trans= all ? &thd->transaction.all : &thd->transaction.stmt;
- bool is_real_trans= all || thd->transaction.all.nht == 0;
- handlerton **ht= trans->ht;
+ bool is_real_trans= all || thd->transaction.all.ha_list == 0;
+ Ha_trx_info *ha_info= trans->ha_list;
my_xid xid= thd->transaction.xid_state.xid.get_my_xid();
DBUG_ENTER("ha_commit_trans");
+ /*
+ We must not commit the normal transaction if a statement
+ transaction is pending. Otherwise statement transaction
+ flags will not get propagated to its normal transaction's
+ counterpart.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.ha_list == NULL ||
+ trans == &thd->transaction.stmt);
+
if (thd->in_sub_stmt)
{
/*
@@ -701,8 +1061,10 @@ int ha_commit_trans(THD *thd, bool all)
DBUG_RETURN(2);
}
#ifdef USING_TRANSACTIONS
- if (trans->nht)
+ if (ha_info)
{
+ bool must_2pc;
+
if (is_real_trans && wait_if_global_read_lock(thd, 0, 0))
{
ha_rollback_trans(thd, all);
@@ -727,12 +1089,26 @@ int ha_commit_trans(THD *thd, bool all)
if (is_real_trans) /* not a statement commit */
thd->stmt_map.close_transient_cursors();
- if (!trans->no_2pc && trans->nht > 1)
+ must_2pc= ha_check_and_coalesce_trx_read_only(thd, ha_info, all);
+
+ if (!trans->no_2pc && must_2pc)
{
- for (; *ht && !error; ht++)
+ for (; ha_info && !error; ha_info= ha_info->next())
{
int err;
- if ((err= (*(*ht)->prepare)(*ht, thd, all)))
+ handlerton *ht= ha_info->ht();
+ /*
+ Do not call two-phase commit if this particular
+ transaction is read-only. This allows for simpler
+ implementation in engines that are always read-only.
+ */
+ if (! ha_info->is_trx_read_write())
+ continue;
+ /*
+ Sic: we know that prepare() is not NULL since otherwise
+ trans->no_2pc would have been set.
+ */
+ if ((err= ht->prepare(ht, thd, all)))
{
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
error= 1;
@@ -770,24 +1146,26 @@ int ha_commit_one_phase(THD *thd, bool all)
{
int error=0;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
- bool is_real_trans=all || thd->transaction.all.nht == 0;
- handlerton **ht=trans->ht;
+ bool is_real_trans=all || thd->transaction.all.ha_list == 0;
+ Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
DBUG_ENTER("ha_commit_one_phase");
#ifdef USING_TRANSACTIONS
- if (trans->nht)
+ if (ha_info)
{
- for (ht=trans->ht; *ht; ht++)
+ for (; ha_info; ha_info= ha_info_next)
{
int err;
- if ((err= (*(*ht)->commit)(*ht, thd, all)))
+ handlerton *ht= ha_info->ht();
+ if ((err= ht->commit(ht, thd, all)))
{
my_error(ER_ERROR_DURING_COMMIT, MYF(0), err);
error=1;
}
status_var_increment(thd->status_var.ha_commit_count);
- *ht= 0;
+ ha_info_next= ha_info->next();
+ ha_info->reset(); /* keep it conveniently zero-filled */
}
- trans->nht=0;
+ trans->ha_list= 0;
trans->no_2pc=0;
if (is_real_trans)
thd->transaction.xid_state.xid.null();
@@ -810,8 +1188,17 @@ int ha_rollback_trans(THD *thd, bool all)
{
int error=0;
THD_TRANS *trans=all ? &thd->transaction.all : &thd->transaction.stmt;
- bool is_real_trans=all || thd->transaction.all.nht == 0;
+ Ha_trx_info *ha_info= trans->ha_list, *ha_info_next;
+ bool is_real_trans=all || thd->transaction.all.ha_list == 0;
DBUG_ENTER("ha_rollback_trans");
+
+ /*
+ We must not rollback the normal transaction if a statement
+ transaction is pending.
+ */
+ DBUG_ASSERT(thd->transaction.stmt.ha_list == NULL ||
+ trans == &thd->transaction.stmt);
+
if (thd->in_sub_stmt)
{
/*
@@ -826,24 +1213,26 @@ int ha_rollback_trans(THD *thd, bool all)
DBUG_RETURN(1);
}
#ifdef USING_TRANSACTIONS
- if (trans->nht)
+ if (ha_info)
{
/* Close all cursors that can not survive ROLLBACK */
if (is_real_trans) /* not a statement commit */
thd->stmt_map.close_transient_cursors();
- for (handlerton **ht=trans->ht; *ht; ht++)
+ for (; ha_info; ha_info= ha_info_next)
{
int err;
- if ((err= (*(*ht)->rollback)(*ht, thd, all)))
+ handlerton *ht= ha_info->ht();
+ if ((err= ht->rollback(ht, thd, all)))
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
}
status_var_increment(thd->status_var.ha_rollback_count);
- *ht= 0;
+ ha_info_next= ha_info->next();
+ ha_info->reset(); /* keep it conveniently zero-filled */
}
- trans->nht=0;
+ trans->ha_list= 0;
trans->no_2pc=0;
if (is_real_trans)
thd->transaction.xid_state.xid.null();
@@ -889,17 +1278,19 @@ int ha_autocommit_or_rollback(THD *thd, int error)
{
DBUG_ENTER("ha_autocommit_or_rollback");
#ifdef USING_TRANSACTIONS
- if (thd->transaction.stmt.nht)
+ if (thd->transaction.stmt.ha_list)
{
if (!error)
{
- if (ha_commit_stmt(thd))
+ if (ha_commit_trans(thd, 0))
error=1;
}
- else if (thd->transaction_rollback_request && !thd->in_sub_stmt)
- (void) ha_rollback(thd);
- else
- (void) ha_rollback_stmt(thd);
+ else
+ {
+ (void) ha_rollback_trans(thd, 0);
+ if (thd->transaction_rollback_request && !thd->in_sub_stmt)
+ (void) ha_rollback(thd);
+ }
thd->variables.tx_isolation=thd->session_tx_isolation;
}
@@ -1199,7 +1590,7 @@ bool mysql_xa_recover(THD *thd)
}
pthread_mutex_unlock(&LOCK_xid_cache);
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(0);
}
@@ -1246,43 +1637,49 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
int error=0;
THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
&thd->transaction.all);
- handlerton **ht=trans->ht, **end_ht;
+ Ha_trx_info *ha_info, *ha_info_next;
+
DBUG_ENTER("ha_rollback_to_savepoint");
- trans->nht=sv->nht;
trans->no_2pc=0;
- end_ht=ht+sv->nht;
/*
rolling back to savepoint in all storage engines that were part of the
transaction when the savepoint was set
*/
- for (; ht < end_ht; ht++)
+ for (ha_info= sv->ha_list; ha_info; ha_info= ha_info->next())
{
int err;
- DBUG_ASSERT((*ht)->savepoint_set != 0);
- if ((err= (*(*ht)->savepoint_rollback)(*ht, thd, (uchar *)(sv+1)+(*ht)->savepoint_offset)))
+ handlerton *ht= ha_info->ht();
+ DBUG_ASSERT(ht);
+ DBUG_ASSERT(ht->savepoint_set != 0);
+ if ((err= ht->savepoint_rollback(ht, thd,
+ (uchar *)(sv+1)+ht->savepoint_offset)))
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
}
status_var_increment(thd->status_var.ha_savepoint_rollback_count);
- trans->no_2pc|=(*ht)->prepare == 0;
+ trans->no_2pc|= ht->prepare == 0;
}
/*
rolling back the transaction in all storage engines that were not part of
the transaction when the savepoint was set
*/
- for (; *ht ; ht++)
+ for (ha_info= trans->ha_list; ha_info != sv->ha_list;
+ ha_info= ha_info_next)
{
int err;
- if ((err= (*(*ht)->rollback)(*ht, thd, !thd->in_sub_stmt)))
+ handlerton *ht= ha_info->ht();
+ if ((err= ht->rollback(ht, thd, !thd->in_sub_stmt)))
{ // cannot happen
my_error(ER_ERROR_DURING_ROLLBACK, MYF(0), err);
error=1;
}
status_var_increment(thd->status_var.ha_rollback_count);
- *ht=0; // keep it conveniently zero-filled
+ ha_info_next= ha_info->next();
+ ha_info->reset(); /* keep it conveniently zero-filled */
}
+ trans->ha_list= sv->ha_list;
DBUG_RETURN(error);
}
@@ -1297,26 +1694,32 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
int error=0;
THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
&thd->transaction.all);
- handlerton **ht=trans->ht;
+ Ha_trx_info *ha_info= trans->ha_list;
DBUG_ENTER("ha_savepoint");
#ifdef USING_TRANSACTIONS
- for (; *ht; ht++)
+ for (; ha_info; ha_info= ha_info->next())
{
int err;
- if (! (*ht)->savepoint_set)
+ handlerton *ht= ha_info->ht();
+ DBUG_ASSERT(ht);
+ if (! ht->savepoint_set)
{
my_error(ER_CHECK_NOT_IMPLEMENTED, MYF(0), "SAVEPOINT");
error=1;
break;
}
- if ((err= (*(*ht)->savepoint_set)(*ht, thd, (uchar *)(sv+1)+(*ht)->savepoint_offset)))
+ if ((err= ht->savepoint_set(ht, thd, (uchar *)(sv+1)+ht->savepoint_offset)))
{ // cannot happen
my_error(ER_GET_ERRNO, MYF(0), err);
error=1;
}
status_var_increment(thd->status_var.ha_savepoint_count);
}
- sv->nht=trans->nht;
+ /*
+ Remember the list of registered storage engines. All new
+ engines are prepended to the beginning of the list.
+ */
+ sv->ha_list= trans->ha_list;
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
}
@@ -1324,20 +1727,19 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
{
int error=0;
- THD_TRANS *trans= (thd->in_sub_stmt ? &thd->transaction.stmt :
- &thd->transaction.all);
- handlerton **ht=trans->ht, **end_ht;
+ Ha_trx_info *ha_info= sv->ha_list;
DBUG_ENTER("ha_release_savepoint");
- end_ht=ht+sv->nht;
- for (; ht < end_ht; ht++)
+ for (; ha_info; ha_info= ha_info->next())
{
int err;
- if (!(*ht)->savepoint_release)
+ handlerton *ht= ha_info->ht();
+ /* Savepoint life time is enclosed into transaction life time. */
+ DBUG_ASSERT(ht);
+ if (!ht->savepoint_release)
continue;
- if ((err= (*(*ht)->savepoint_release)(*ht, thd,
- (uchar *)(sv+1)+
- (*ht)->savepoint_offset)))
+ if ((err= ht->savepoint_release(ht, thd,
+ (uchar *)(sv+1) + ht->savepoint_offset)))
{ // cannot happen
my_error(ER_GET_ERRNO, MYF(0), err);
error=1;
@@ -2506,6 +2908,36 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
return update_frm_version(table);
}
+/**
+ A helper function to mark a transaction read-write,
+ if it is started.
+*/
+
+inline
+void
+handler::mark_trx_read_write()
+{
+ Ha_trx_info *ha_info= &ha_thd()->ha_data[ht->slot].ha_info[0];
+ /*
+ When a storage engine method is called, the transaction must
+ have been started, unless it's a DDL call, for which the
+ storage engine starts the transaction internally, and commits
+ it internally, without registering in the ha_list.
+ Unfortunately here we can't know know for sure if the engine
+ has registered the transaction or not, so we must check.
+ */
+ if (ha_info->is_started())
+ {
+ DBUG_ASSERT(has_transactions());
+ /*
+ table_share can be NULL in ha_delete_table(). See implementation
+ of standalone function ha_delete_table() in sql_base.cc.
+ */
+ if (table_share == NULL || table_share->tmp_table == NO_TMP_TABLE)
+ ha_info->set_trx_read_write();
+ }
+}
+
/**
Repair table: public interface.
@@ -2516,6 +2948,9 @@ int handler::ha_check(THD *thd, HA_CHECK_OPT *check_opt)
int handler::ha_repair(THD* thd, HA_CHECK_OPT* check_opt)
{
int result;
+
+ mark_trx_read_write();
+
if ((result= repair(thd, check_opt)))
return result;
return update_frm_version(table);
@@ -2532,6 +2967,8 @@ int
handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data,
uint *dup_key_found)
{
+ mark_trx_read_write();
+
return bulk_update_row(old_data, new_data, dup_key_found);
}
@@ -2545,6 +2982,8 @@ handler::ha_bulk_update_row(const uchar *old_data, uchar *new_data,
int
handler::ha_delete_all_rows()
{
+ mark_trx_read_write();
+
return delete_all_rows();
}
@@ -2558,6 +2997,8 @@ handler::ha_delete_all_rows()
int
handler::ha_reset_auto_increment(ulonglong value)
{
+ mark_trx_read_write();
+
return reset_auto_increment(value);
}
@@ -2571,6 +3012,8 @@ handler::ha_reset_auto_increment(ulonglong value)
int
handler::ha_backup(THD* thd, HA_CHECK_OPT* check_opt)
{
+ mark_trx_read_write();
+
return backup(thd, check_opt);
}
@@ -2584,6 +3027,8 @@ handler::ha_backup(THD* thd, HA_CHECK_OPT* check_opt)
int
handler::ha_restore(THD* thd, HA_CHECK_OPT* check_opt)
{
+ mark_trx_read_write();
+
return restore(thd, check_opt);
}
@@ -2597,6 +3042,8 @@ handler::ha_restore(THD* thd, HA_CHECK_OPT* check_opt)
int
handler::ha_optimize(THD* thd, HA_CHECK_OPT* check_opt)
{
+ mark_trx_read_write();
+
return optimize(thd, check_opt);
}
@@ -2610,6 +3057,8 @@ handler::ha_optimize(THD* thd, HA_CHECK_OPT* check_opt)
int
handler::ha_analyze(THD* thd, HA_CHECK_OPT* check_opt)
{
+ mark_trx_read_write();
+
return analyze(thd, check_opt);
}
@@ -2623,6 +3072,8 @@ handler::ha_analyze(THD* thd, HA_CHECK_OPT* check_opt)
bool
handler::ha_check_and_repair(THD *thd)
{
+ mark_trx_read_write();
+
return check_and_repair(thd);
}
@@ -2636,6 +3087,8 @@ handler::ha_check_and_repair(THD *thd)
int
handler::ha_disable_indexes(uint mode)
{
+ mark_trx_read_write();
+
return disable_indexes(mode);
}
@@ -2649,6 +3102,8 @@ handler::ha_disable_indexes(uint mode)
int
handler::ha_enable_indexes(uint mode)
{
+ mark_trx_read_write();
+
return enable_indexes(mode);
}
@@ -2662,6 +3117,8 @@ handler::ha_enable_indexes(uint mode)
int
handler::ha_discard_or_import_tablespace(my_bool discard)
{
+ mark_trx_read_write();
+
return discard_or_import_tablespace(discard);
}
@@ -2677,6 +3134,8 @@ handler::ha_discard_or_import_tablespace(my_bool discard)
void
handler::ha_prepare_for_alter()
{
+ mark_trx_read_write();
+
prepare_for_alter();
}
@@ -2690,6 +3149,8 @@ handler::ha_prepare_for_alter()
int
handler::ha_rename_table(const char *from, const char *to)
{
+ mark_trx_read_write();
+
return rename_table(from, to);
}
@@ -2703,6 +3164,8 @@ handler::ha_rename_table(const char *from, const char *to)
int
handler::ha_delete_table(const char *name)
{
+ mark_trx_read_write();
+
return delete_table(name);
}
@@ -2716,6 +3179,8 @@ handler::ha_delete_table(const char *name)
void
handler::ha_drop_table(const char *name)
{
+ mark_trx_read_write();
+
return drop_table(name);
}
@@ -2729,6 +3194,8 @@ handler::ha_drop_table(const char *name)
int
handler::ha_create(const char *name, TABLE *form, HA_CREATE_INFO *info)
{
+ mark_trx_read_write();
+
return create(name, form, info);
}
@@ -2743,6 +3210,8 @@ int
handler::ha_create_handler_files(const char *name, const char *old_name,
int action_flag, HA_CREATE_INFO *info)
{
+ mark_trx_read_write();
+
return create_handler_files(name, old_name, action_flag, info);
}
@@ -2761,6 +3230,8 @@ handler::ha_change_partitions(HA_CREATE_INFO *create_info,
const uchar *pack_frm_data,
size_t pack_frm_len)
{
+ mark_trx_read_write();
+
return change_partitions(create_info, path, copied, deleted,
pack_frm_data, pack_frm_len);
}
@@ -2775,6 +3246,8 @@ handler::ha_change_partitions(HA_CREATE_INFO *create_info,
int
handler::ha_drop_partitions(const char *path)
{
+ mark_trx_read_write();
+
return drop_partitions(path);
}
@@ -2788,6 +3261,8 @@ handler::ha_drop_partitions(const char *path)
int
handler::ha_rename_partitions(const char *path)
{
+ mark_trx_read_write();
+
return rename_partitions(path);
}
@@ -2801,6 +3276,8 @@ handler::ha_rename_partitions(const char *path)
int
handler::ha_optimize_partitions(THD *thd)
{
+ mark_trx_read_write();
+
return optimize_partitions(thd);
}
@@ -2814,6 +3291,8 @@ handler::ha_optimize_partitions(THD *thd)
int
handler::ha_analyze_partitions(THD *thd)
{
+ mark_trx_read_write();
+
return analyze_partitions(thd);
}
@@ -2827,6 +3306,8 @@ handler::ha_analyze_partitions(THD *thd)
int
handler::ha_check_partitions(THD *thd)
{
+ mark_trx_read_write();
+
return check_partitions(thd);
}
@@ -2840,6 +3321,8 @@ handler::ha_check_partitions(THD *thd)
int
handler::ha_repair_partitions(THD *thd)
{
+ mark_trx_read_write();
+
return repair_partitions(thd);
}
@@ -2866,7 +3349,7 @@ int ha_enable_transaction(THD *thd, bool on)
is an optimization hint that storage engine is free to ignore.
So, let's commit an open transaction (if any) now.
*/
- if (!(error= ha_commit_stmt(thd)))
+ if (!(error= ha_commit_trans(thd, 0)))
error= end_trans(thd, COMMIT);
}
DBUG_RETURN(error);
@@ -3826,7 +4309,7 @@ bool ha_show_status(THD *thd, handlerton *db_type, enum ha_stat_type stat)
}
if (!result)
- send_eof(thd);
+ my_eof(thd);
return result;
}
@@ -4044,6 +4527,9 @@ int handler::ha_write_row(uchar *buf)
{
int error;
DBUG_ENTER("handler::ha_write_row");
+
+ mark_trx_read_write();
+
if (unlikely(error= write_row(buf)))
DBUG_RETURN(error);
if (unlikely(error= binlog_log_row<Write_rows_log_event>(table, 0, buf)))
@@ -4062,6 +4548,8 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
*/
DBUG_ASSERT(new_data == table->record[0]);
+ mark_trx_read_write();
+
if (unlikely(error= update_row(old_data, new_data)))
return error;
if (unlikely(error= binlog_log_row<Update_rows_log_event>(table, old_data, new_data)))
@@ -4072,6 +4560,9 @@ int handler::ha_update_row(const uchar *old_data, uchar *new_data)
int handler::ha_delete_row(const uchar *buf)
{
int error;
+
+ mark_trx_read_write();
+
if (unlikely(error= delete_row(buf)))
return error;
if (unlikely(error= binlog_log_row<Delete_rows_log_event>(table, buf, 0)))
diff --git a/sql/handler.h b/sql/handler.h
index b3a4b408589..9800f4974c3 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -721,14 +721,14 @@ struct handlerton
#define HTON_SUPPORT_LOG_TABLES (1 << 7) //Engine supports log tables
#define HTON_NO_PARTITION (1 << 8) //You can not partition these tables
-typedef struct st_thd_trans
+class Ha_trx_info;
+
+struct THD_TRANS
{
- /* number of entries in the ht[] */
- uint nht;
/* true is not all entries in the ht[] support 2pc */
bool no_2pc;
- /* storage engines that registered themselves for this transaction */
- handlerton *ht[MAX_HA];
+ /* storage engines that registered in this transaction */
+ Ha_trx_info *ha_list;
/*
The purpose of this flag is to keep track of non-transactional
tables that were modified in scope of:
@@ -758,7 +758,106 @@ typedef struct st_thd_trans
saved value.
*/
bool modified_non_trans_table;
-} THD_TRANS;
+
+ void reset() { no_2pc= FALSE; modified_non_trans_table= FALSE; }
+};
+
+
+/**
+ Either statement transaction or normal transaction - related
+ thread-specific storage engine data.
+
+ If a storage engine participates in a statement/transaction,
+ an instance of this class is present in
+ thd->transaction.{stmt|all}.ha_list. The addition to
+ {stmt|all}.ha_list is made by trans_register_ha().
+
+ When it's time to commit or rollback, each element of ha_list
+ is used to access storage engine's prepare()/commit()/rollback()
+ methods, and also to evaluate if a full two phase commit is
+ necessary.
+
+ @sa General description of transaction handling in handler.cc.
+*/
+
+class Ha_trx_info
+{
+public:
+ /** Register this storage engine in the given transaction context. */
+ void register_ha(THD_TRANS *trans, handlerton *ht_arg)
+ {
+ DBUG_ASSERT(m_flags == 0);
+ DBUG_ASSERT(m_ht == NULL);
+ DBUG_ASSERT(m_next == NULL);
+
+ m_ht= ht_arg;
+ m_flags= (int) TRX_READ_ONLY; /* Assume read-only at start. */
+
+ m_next= trans->ha_list;
+ trans->ha_list= this;
+ }
+
+ /** Clear, prepare for reuse. */
+ void reset()
+ {
+ m_next= NULL;
+ m_ht= NULL;
+ m_flags= 0;
+ }
+
+ Ha_trx_info() { reset(); }
+
+ void set_trx_read_write()
+ {
+ DBUG_ASSERT(is_started());
+ m_flags|= (int) TRX_READ_WRITE;
+ }
+ bool is_trx_read_write() const
+ {
+ DBUG_ASSERT(is_started());
+ return m_flags & (int) TRX_READ_WRITE;
+ }
+ bool is_started() const { return m_ht != NULL; }
+ /** Mark this transaction read-write if the argument is read-write. */
+ void coalesce_trx_with(const Ha_trx_info *stmt_trx)
+ {
+ /*
+ Must be called only after the transaction has been started.
+ Can be called many times, e.g. when we have many
+ read-write statements in a transaction.
+ */
+ DBUG_ASSERT(is_started());
+ if (stmt_trx->is_trx_read_write())
+ set_trx_read_write();
+ }
+ Ha_trx_info *next() const
+ {
+ DBUG_ASSERT(is_started());
+ return m_next;
+ }
+ handlerton *ht() const
+ {
+ DBUG_ASSERT(is_started());
+ return m_ht;
+ }
+private:
+ enum { TRX_READ_ONLY= 0, TRX_READ_WRITE= 1 };
+ /** Auxiliary, used for ha_list management */
+ Ha_trx_info *m_next;
+ /**
+ Although a given Ha_trx_info instance is currently always used
+ for the same storage engine, 'ht' is not-NULL only when the
+ corresponding storage is a part of a transaction.
+ */
+ handlerton *m_ht;
+ /**
+ Transaction flags related to this engine.
+ Not-null only if this instance is a part of transaction.
+ May assume a combination of enum values above.
+ */
+ uchar m_flags;
+};
+
enum enum_tx_isolation { ISO_READ_UNCOMMITTED, ISO_READ_COMMITTED,
ISO_REPEATABLE_READ, ISO_SERIALIZABLE};
@@ -1640,8 +1739,15 @@ protected:
provide useful functionality.
*/
virtual int rename_table(const char *from, const char *to);
+ /**
+ Delete a table in the engine. Called for base as well as temporary
+ tables.
+ */
virtual int delete_table(const char *name);
private:
+ /* Private helpers */
+ inline void mark_trx_read_write();
+private:
/*
Low-level primitives for storage engines. These should be
overridden by the storage engine class. To call these methods, use
@@ -1821,9 +1927,7 @@ extern TYPELIB tx_isolation_typelib;
extern TYPELIB myisam_stats_method_typelib;
extern ulong total_ha, total_ha_2pc;
- /* Wrapper functions */
-#define ha_commit_stmt(thd) (ha_commit_trans((thd), FALSE))
-#define ha_rollback_stmt(thd) (ha_rollback_trans((thd), FALSE))
+ /* Wrapper functions */
#define ha_commit(thd) (ha_commit_trans((thd), TRUE))
#define ha_rollback(thd) (ha_rollback_trans((thd), TRUE))
diff --git a/sql/item.cc b/sql/item.cc
index f28ef8967af..bb93e08d54b 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -442,9 +442,10 @@ uint Item::decimal_precision() const
}
-void Item::print_item_w_name(String *str)
+void Item::print_item_w_name(String *str, enum_query_type query_type)
{
- print(str);
+ print(str, query_type);
+
if (name)
{
THD *thd= current_thd;
@@ -1128,7 +1129,7 @@ Item_splocal::this_item_addr(THD *thd, Item **)
}
-void Item_splocal::print(String *str)
+void Item_splocal::print(String *str, enum_query_type)
{
str->reserve(m_name.length+8);
str->append(m_name.str, m_name.length);
@@ -1182,7 +1183,7 @@ Item_case_expr::this_item_addr(THD *thd, Item **)
}
-void Item_case_expr::print(String *str)
+void Item_case_expr::print(String *str, enum_query_type)
{
if (str->reserve(MAX_INT_WIDTH + sizeof("case_expr@")))
return; /* purecov: inspected */
@@ -1277,12 +1278,12 @@ bool Item_name_const::fix_fields(THD *thd, Item **ref)
}
-void Item_name_const::print(String *str)
+void Item_name_const::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("NAME_CONST("));
- name_item->print(str);
+ name_item->print(str, query_type);
str->append(',');
- value_item->print(str);
+ value_item->print(str, query_type);
str->append(')');
}
@@ -1299,12 +1300,12 @@ public:
const char *table_name_arg, const char *field_name_arg)
:Item_ref(context_arg, item, table_name_arg, field_name_arg) {}
- void print (String *str)
+ virtual inline void print (String *str, enum_query_type query_type)
{
if (ref)
- (*ref)->print(str);
+ (*ref)->print(str, query_type);
else
- Item_ident::print(str);
+ Item_ident::print(str, query_type);
}
};
@@ -1456,7 +1457,9 @@ bool DTCollation::aggregate(DTCollation &dt, uint flags)
set(dt);
}
else
- ; // Do nothing
+ {
+ // Do nothing
+ }
}
else if ((flags & MY_COLL_ALLOW_SUPERSET_CONV) &&
left_is_superset(this, &dt))
@@ -1873,7 +1876,7 @@ const char *Item_ident::full_name() const
return tmp;
}
-void Item_ident::print(String *str)
+void Item_ident::print(String *str, enum_query_type query_type)
{
THD *thd= current_thd;
char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
@@ -2135,7 +2138,7 @@ String *Item_int::val_str(String *str)
return str;
}
-void Item_int::print(String *str)
+void Item_int::print(String *str, enum_query_type query_type)
{
// my_charset_bin is good enough for numbers
str_value.set(value, &my_charset_bin);
@@ -2166,7 +2169,7 @@ String *Item_uint::val_str(String *str)
}
-void Item_uint::print(String *str)
+void Item_uint::print(String *str, enum_query_type query_type)
{
// latin1 is good enough for numbers
str_value.set((ulonglong) value, default_charset());
@@ -2258,7 +2261,7 @@ String *Item_decimal::val_str(String *result)
return result;
}
-void Item_decimal::print(String *str)
+void Item_decimal::print(String *str, enum_query_type query_type)
{
my_decimal2string(E_DEC_FATAL_ERROR, &decimal_value, 0, 0, 0, &str_value);
str->append(str_value);
@@ -2311,12 +2314,39 @@ my_decimal *Item_float::val_decimal(my_decimal *decimal_value)
}
-void Item_string::print(String *str)
+void Item_string::print(String *str, enum_query_type query_type)
{
- str->append('_');
- str->append(collation.collation->csname);
+ if (query_type == QT_ORDINARY && is_cs_specified())
+ {
+ str->append('_');
+ str->append(collation.collation->csname);
+ }
+
str->append('\'');
- str_value.print(str);
+
+ if (query_type == QT_ORDINARY ||
+ my_charset_same(str_value.charset(), system_charset_info))
+ {
+ str_value.print(str);
+ }
+ else
+ {
+ THD *thd= current_thd;
+ LEX_STRING utf8_lex_str;
+
+ thd->convert_string(&utf8_lex_str,
+ system_charset_info,
+ str_value.c_ptr_safe(),
+ str_value.length(),
+ str_value.charset());
+
+ String utf8_str(utf8_lex_str.str,
+ utf8_lex_str.length,
+ system_charset_info);
+
+ utf8_str.print(str);
+ }
+
str->append('\'');
}
@@ -2439,14 +2469,14 @@ default_set_param_func(Item_param *param,
Item_param::Item_param(uint pos_in_query_arg) :
- strict_type(FALSE),
state(NO_VALUE),
item_result_type(STRING_RESULT),
/* Don't pretend to be a literal unless value for this item is set. */
item_type(PARAM_ITEM),
param_type(MYSQL_TYPE_VARCHAR),
pos_in_query(pos_in_query_arg),
- set_param_func(default_set_param_func)
+ set_param_func(default_set_param_func),
+ limit_clause_param(FALSE)
{
name= (char*) "?";
/*
@@ -2630,8 +2660,13 @@ bool Item_param::set_from_user_var(THD *thd, const user_var_entry *entry)
{
item_result_type= entry->type;
unsigned_flag= entry->unsigned_flag;
- if (strict_type && required_result_type != item_result_type)
- DBUG_RETURN(1);
+ if (limit_clause_param)
+ {
+ my_bool unused;
+ set_int(entry->val_int(&unused), MY_INT64_NUM_DECIMAL_DIGITS);
+ item_type= Item::INT_ITEM;
+ DBUG_RETURN(!unsigned_flag && value.integer < 0 ? 1 : 0);
+ }
switch (item_result_type) {
case REAL_RESULT:
set_double(*(double*)entry->value);
@@ -3083,7 +3118,7 @@ Item_param::eq(const Item *arg, bool binary_cmp) const
/* End of Item_param related */
-void Item_param::print(String *str)
+void Item_param::print(String *str, enum_query_type query_type)
{
if (state == NO_VALUE)
{
@@ -4796,7 +4831,7 @@ int Item_float::save_in_field(Field *field, bool no_conversions)
}
-void Item_float::print(String *str)
+void Item_float::print(String *str, enum_query_type query_type)
{
if (presentation)
{
@@ -4914,7 +4949,7 @@ warn:
}
-void Item_hex_string::print(String *str)
+void Item_hex_string::print(String *str, enum_query_type query_type)
{
char *end= (char*) str_value.ptr() + str_value.length(),
*ptr= end - min(str_value.length(), sizeof(longlong));
@@ -5176,7 +5211,7 @@ Item *Item_field::update_value_transformer(uchar *select_arg)
}
-void Item_field::print(String *str)
+void Item_field::print(String *str, enum_query_type query_type)
{
if (field && field->table->const_table)
{
@@ -5188,7 +5223,7 @@ void Item_field::print(String *str)
str->append('\'');
return;
}
- Item_ident::print(str);
+ Item_ident::print(str, query_type);
}
@@ -5528,7 +5563,7 @@ void Item_ref::cleanup()
}
-void Item_ref::print(String *str)
+void Item_ref::print(String *str, enum_query_type query_type)
{
if (ref)
{
@@ -5539,10 +5574,10 @@ void Item_ref::print(String *str)
append_identifier(thd, str, name, (uint) strlen(name));
}
else
- (*ref)->print(str);
+ (*ref)->print(str, query_type);
}
else
- Item_ident::print(str);
+ Item_ident::print(str, query_type);
}
@@ -5732,11 +5767,11 @@ Item *Item_ref::get_tmp_table_item(THD *thd)
}
-void Item_ref_null_helper::print(String *str)
+void Item_ref_null_helper::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("<ref_null_helper>("));
if (ref)
- (*ref)->print(str);
+ (*ref)->print(str, query_type);
else
str->append('?');
str->append(')');
@@ -5928,7 +5963,7 @@ error:
}
-void Item_default_value::print(String *str)
+void Item_default_value::print(String *str, enum_query_type query_type)
{
if (!arg)
{
@@ -5936,7 +5971,7 @@ void Item_default_value::print(String *str)
return;
}
str->append(STRING_WITH_LEN("default("));
- arg->print(str);
+ arg->print(str, query_type);
str->append(')');
}
@@ -6072,10 +6107,10 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
return FALSE;
}
-void Item_insert_value::print(String *str)
+void Item_insert_value::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("values("));
- arg->print(str);
+ arg->print(str, query_type);
str->append(')');
}
@@ -6196,7 +6231,7 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
}
-void Item_trigger_field::print(String *str)
+void Item_trigger_field::print(String *str, enum_query_type query_type)
{
str->append((row_version == NEW_ROW) ? "NEW" : "OLD", 3);
str->append('.');
@@ -6386,13 +6421,13 @@ Item_cache* Item_cache::get_cache(const Item *item)
}
-void Item_cache::print(String *str)
+void Item_cache::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("<cache>("));
if (example)
- example->print(str);
+ example->print(str, query_type);
else
- Item::print(str);
+ Item::print(str, query_type);
str->append(')');
}
diff --git a/sql/item.h b/sql/item.h
index b98389bc8d4..7cf0bafa9d9 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -113,7 +113,6 @@ public:
}
};
-
/*************************************************************************/
/*
A framework to easily handle different return types for hybrid items
@@ -769,20 +768,24 @@ public:
*/
virtual bool const_during_execution() const
{ return (used_tables() & ~PARAM_TABLE_BIT) == 0; }
- /*
- This is an essential method for correct functioning of VIEWS.
- To save a view in an .frm file we need its unequivocal
- definition in SQL that takes into account sql_mode and
- environmental settings. Currently such definition is restored
- by traversing through the parsed tree of a view and
- print()'ing SQL syntax of every node to a String buffer. This
- method is used to print the SQL definition of an item. The
- second use of this method is for EXPLAIN EXTENDED, to print
- the SQL of a query after all optimizations of the parsed tree
- have been done.
- */
- virtual void print(String *str_arg) { str_arg->append(full_name()); }
- void print_item_w_name(String *);
+
+ /**
+ This method is used for to:
+ - to generate a view definition query (SELECT-statement);
+ - to generate a SQL-query for EXPLAIN EXTENDED;
+ - to generate a SQL-query to be shown in INFORMATION_SCHEMA;
+ - debug.
+
+ For more information about view definition query, INFORMATION_SCHEMA
+ query and why they should be generated from the Item-tree, @see
+ mysql_register_view().
+ */
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ str->append(full_name());
+ }
+
+ void print_item_w_name(String *, enum_query_type query_type);
virtual void update_used_tables() {}
virtual void split_sum_func(THD *thd, Item **ref_pointer_array,
List<Item> &fields) {}
@@ -1010,6 +1013,23 @@ public:
class sp_head;
+class Item_basic_constant :public Item
+{
+public:
+ /* to prevent drop fixed flag (no need parent cleanup call) */
+ void cleanup()
+ {
+ /*
+ Restore the original field name as it might not have been allocated
+ in the statement memory. If the name is auto generated, it must be
+ done again between subsequent executions of a prepared statement.
+ */
+ if (orig_name)
+ name= orig_name;
+ }
+};
+
+
/*****************************************************************************
The class is a base class for representation of stored routine variables in
the Item-hierarchy. There are the following kinds of SP-vars:
@@ -1134,7 +1154,7 @@ public:
const Item *this_item() const;
Item **this_item_addr(THD *thd, Item **);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
public:
inline const LEX_STRING *my_name() const;
@@ -1203,7 +1223,7 @@ public:
Item_case_expr can not occur in views, so here it is only for debug
purposes.
*/
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
private:
uint m_case_expr_id;
@@ -1261,7 +1281,7 @@ public:
String *val_str(String *sp);
my_decimal *val_decimal(my_decimal *);
bool is_null();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
Item_result result_type() const
{
@@ -1292,7 +1312,7 @@ bool agg_item_charsets(DTCollation &c, const char *name,
Item **items, uint nitems, uint flags, int item_sep);
-class Item_num: public Item
+class Item_num: public Item_basic_constant
{
public:
Item_num() {} /* Remove gcc warning */
@@ -1343,7 +1363,7 @@ public:
const char *full_name() const;
void cleanup();
bool remove_dependence_processor(uchar * arg);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
virtual bool change_context_processor(uchar *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
friend bool insert_fields(THD *thd, Name_resolution_context *context,
@@ -1473,7 +1493,7 @@ public:
Item *safe_charset_converter(CHARSET_INFO *tocs);
int fix_outer_field(THD *thd, Field **field, Item **reference);
virtual Item *update_value_transformer(uchar *select_arg);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
Field::geometry_type get_geometry_type() const
{
DBUG_ASSERT(field_type() == MYSQL_TYPE_GEOMETRY);
@@ -1484,7 +1504,7 @@ public:
friend class st_select_lex_unit;
};
-class Item_null :public Item
+class Item_null :public Item_basic_constant
{
public:
Item_null(char *name_par=0)
@@ -1506,12 +1526,15 @@ public:
bool send(Protocol *protocol, String *str);
enum Item_result result_type () const { return STRING_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
- /* to prevent drop fixed flag (no need parent cleanup call) */
- void cleanup() {}
bool basic_const_item() const { return 1; }
Item *clone_item() { return new Item_null(name); }
bool is_null() { return 1; }
- void print(String *str) { str->append(STRING_WITH_LEN("NULL")); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ str->append(STRING_WITH_LEN("NULL"));
+ }
+
Item *safe_charset_converter(CHARSET_INFO *tocs);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -1536,8 +1559,6 @@ class Item_param :public Item
char cnvbuf[MAX_FIELD_WIDTH];
String cnvstr;
Item *cnvitem;
- bool strict_type;
- enum Item_result required_result_type;
public:
enum enum_item_param_state
@@ -1645,7 +1666,7 @@ public:
*/
virtual table_map used_tables() const
{ return state != NO_VALUE ? (table_map)0 : PARAM_TABLE_BIT; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool is_null()
{ DBUG_ASSERT(state != NO_VALUE); return state == NULL_VALUE; }
bool basic_const_item() const;
@@ -1667,11 +1688,8 @@ public:
Otherwise return FALSE.
*/
bool eq(const Item *item, bool binary_cmp) const;
- void set_strict_type(enum Item_result result_type_arg)
- {
- strict_type= TRUE;
- required_result_type= result_type_arg;
- }
+ /** Item is a argument to a limit clause. */
+ bool limit_clause_param;
};
@@ -1701,9 +1719,7 @@ public:
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
Item *clone_item() { return new Item_int(name,value,max_length); }
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
Item_num *neg() { value= -value; return this; }
uint decimal_precision() const
{ return (uint)(max_length - test(value < 0)); }
@@ -1723,7 +1739,7 @@ public:
String *val_str(String*);
Item *clone_item() { return new Item_uint(name, value, max_length); }
int save_in_field(Field *field, bool no_conversions);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
Item_num *neg ();
uint decimal_precision() const { return max_length; }
bool check_partition_func_processor(uchar *bool_arg) { return FALSE;}
@@ -1757,9 +1773,7 @@ public:
{
return new Item_decimal(name, &decimal_value, decimals, max_length);
}
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
Item_num *neg()
{
my_decimal_neg(&decimal_value);
@@ -1813,12 +1827,10 @@ public:
String *val_str(String*);
my_decimal *val_decimal(my_decimal *);
bool basic_const_item() const { return 1; }
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
Item *clone_item()
{ return new Item_float(name, value, decimals, max_length); }
Item_num *neg() { value= -value; return this; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool eq(const Item *, bool binary_cmp) const;
};
@@ -1831,17 +1843,23 @@ public:
uint length)
:Item_float(NullS, val_arg, decimal_par, length), func_name(str)
{}
- void print(String *str) { str->append(func_name); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ str->append(func_name);
+ }
+
Item *safe_charset_converter(CHARSET_INFO *tocs);
};
-class Item_string :public Item
+class Item_string :public Item_basic_constant
{
public:
Item_string(const char *str,uint length,
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE,
uint repertoire= MY_REPERTOIRE_UNICODE30)
+ : m_cs_specified(FALSE)
{
str_value.set_or_copy_aligned(str, length, cs);
collation.set(cs, dv, repertoire);
@@ -1860,6 +1878,7 @@ public:
}
/* Just create an item and do not fill string representation */
Item_string(CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE)
+ : m_cs_specified(FALSE)
{
collation.set(cs, dv);
max_length= 0;
@@ -1870,6 +1889,7 @@ public:
Item_string(const char *name_par, const char *str, uint length,
CHARSET_INFO *cs, Derivation dv= DERIVATION_COERCIBLE,
uint repertoire= MY_REPERTOIRE_UNICODE30)
+ : m_cs_specified(FALSE)
{
str_value.set_or_copy_aligned(str, length, cs);
collation.set(cs, dv, repertoire);
@@ -1919,10 +1939,50 @@ public:
str_value.append(str, length);
max_length= str_value.numchars() * collation.collation->mbmaxlen;
}
- void print(String *str);
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
+ virtual void print(String *str, enum_query_type query_type);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
+
+ /**
+ Return TRUE if character-set-introducer was explicitly specified in the
+ original query for this item (text literal).
+
+ This operation is to be called from Item_string::print(). The idea is
+ that when a query is generated (re-constructed) from the Item-tree,
+ character-set-introducers should appear only for those literals, where
+ they were explicitly specified by the user. Otherwise, that may lead to
+ loss collation information (character set introducers implies default
+ collation for the literal).
+
+ Basically, that makes sense only for views and hopefully will be gone
+ one day when we start using original query as a view definition.
+
+ @return This operation returns the value of m_cs_specified attribute.
+ @retval TRUE if character set introducer was explicitly specified in
+ the original query.
+ @retval FALSE otherwise.
+ */
+ inline bool is_cs_specified() const
+ {
+ return m_cs_specified;
+ }
+
+ /**
+ Set the value of m_cs_specified attribute.
+
+ m_cs_specified attribute shows whether character-set-introducer was
+ explicitly specified in the original query for this text literal or
+ not. The attribute makes sense (is used) only for views.
+
+ This operation is to be called from the parser during parsing an input
+ query.
+ */
+ inline void set_cs_specified(bool cs_specified)
+ {
+ m_cs_specified= cs_specified;
+ }
+
+private:
+ bool m_cs_specified;
};
@@ -1936,7 +1996,12 @@ public:
:Item_string(NullS, str, length, cs, dv), func_name(name_par)
{}
Item *safe_charset_converter(CHARSET_INFO *tocs);
- void print(String *str) { str->append(func_name); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ str->append(func_name);
+ }
+
bool check_partition_func_processor(uchar *int_arg) {return TRUE;}
};
@@ -2005,10 +2070,10 @@ public:
};
-class Item_hex_string: public Item
+class Item_hex_string: public Item_basic_constant
{
public:
- Item_hex_string(): Item() {}
+ Item_hex_string() {}
Item_hex_string(const char *str,uint str_length);
enum Type type() const { return VARBIN_ITEM; }
double val_real()
@@ -2024,9 +2089,7 @@ public:
enum Item_result result_type () const { return STRING_RESULT; }
enum Item_result cast_to_int_type() const { return INT_RESULT; }
enum_field_types field_type() const { return MYSQL_TYPE_VARCHAR; }
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool eq(const Item *item, bool binary_cmp) const;
virtual Item *safe_charset_converter(CHARSET_INFO *tocs);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
@@ -2147,7 +2210,7 @@ public:
}
bool walk(Item_processor processor, bool walk_subquery, uchar *arg)
{ return (*ref)->walk(processor, walk_subquery, arg); }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool result_as_longlong()
{
return (*ref)->result_as_longlong();
@@ -2294,7 +2357,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
bool get_date(MYSQL_TIME *ltime, uint fuzzydate);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
/*
we add RAND_TABLE_BIT to prevent moving this item from HAVING to WHERE
*/
@@ -2469,7 +2532,7 @@ public:
enum Type type() const { return DEFAULT_VALUE_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
int save_in_field(Field *field_arg, bool no_conversions);
table_map used_tables() const { return (table_map)0L; }
@@ -2502,7 +2565,7 @@ public:
arg(a) {}
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
int save_in_field(Field *field_arg, bool no_conversions)
{
return Item_field::save_in_field(field_arg, no_conversions);
@@ -2573,7 +2636,7 @@ public:
enum Type type() const { return TRIGGER_FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
bool fix_fields(THD *, Item **);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
table_map used_tables() const { return (table_map)0L; }
Field *get_tmp_table_field() { return 0; }
Item *copy_or_same(THD *thd) { return this; }
@@ -2617,7 +2680,7 @@ private:
};
-class Item_cache: public Item
+class Item_cache: public Item_basic_constant
{
protected:
Item *example;
@@ -2664,9 +2727,7 @@ public:
static Item_cache* get_cache(const Item *item);
table_map used_tables() const { return used_table_map; }
virtual void keep_array() {}
- // to prevent drop fixed flag (no need parent cleanup call)
- void cleanup() {}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool eq_def(Field *field)
{
return cached_field ? cached_field->eq_def (field) : FALSE;
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index dc868376796..ae7ea95707c 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -286,10 +286,10 @@ longlong Item_func_not::val_int()
higher than the precedence of NOT.
*/
-void Item_func_not::print(String *str)
+void Item_func_not::print(String *str, enum_query_type query_type)
{
str->append('(');
- Item_func::print(str);
+ Item_func::print(str, query_type);
str->append(')');
}
@@ -321,12 +321,12 @@ bool Item_func_not_all::empty_underlying_subquery()
(test_sub_item && !test_sub_item->any_value()));
}
-void Item_func_not_all::print(String *str)
+void Item_func_not_all::print(String *str, enum_query_type query_type)
{
if (show)
- Item_func::print(str);
+ Item_func::print(str, query_type);
else
- args[0]->print(str);
+ args[0]->print(str, query_type);
}
@@ -1422,10 +1422,10 @@ void Item_func_truth::fix_length_and_dec()
}
-void Item_func_truth::print(String *str)
+void Item_func_truth::print(String *str, enum_query_type query_type)
{
str->append('(');
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" is "));
if (! affirmative)
str->append(STRING_WITH_LEN("not "));
@@ -2109,16 +2109,16 @@ longlong Item_func_between::val_int()
}
-void Item_func_between::print(String *str)
+void Item_func_between::print(String *str, enum_query_type query_type)
{
str->append('(');
- args[0]->print(str);
+ args[0]->print(str, query_type);
if (negated)
str->append(STRING_WITH_LEN(" not"));
str->append(STRING_WITH_LEN(" between "));
- args[1]->print(str);
+ args[1]->print(str, query_type);
str->append(STRING_WITH_LEN(" and "));
- args[2]->print(str);
+ args[2]->print(str, query_type);
str->append(')');
}
@@ -2763,26 +2763,26 @@ uint Item_func_case::decimal_precision() const
Fix this so that it prints the whole CASE expression
*/
-void Item_func_case::print(String *str)
+void Item_func_case::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("(case "));
if (first_expr_num != -1)
{
- args[first_expr_num]->print(str);
+ args[first_expr_num]->print(str, query_type);
str->append(' ');
}
for (uint i=0 ; i < ncases ; i+=2)
{
str->append(STRING_WITH_LEN("when "));
- args[i]->print(str);
+ args[i]->print(str, query_type);
str->append(STRING_WITH_LEN(" then "));
- args[i+1]->print(str);
+ args[i+1]->print(str, query_type);
str->append(' ');
}
if (else_expr_num != -1)
{
str->append(STRING_WITH_LEN("else "));
- args[else_expr_num]->print(str);
+ args[else_expr_num]->print(str, query_type);
str->append(' ');
}
str->append(STRING_WITH_LEN("end)"));
@@ -3706,14 +3706,14 @@ void Item_func_in::fix_length_and_dec()
}
-void Item_func_in::print(String *str)
+void Item_func_in::print(String *str, enum_query_type query_type)
{
str->append('(');
- args[0]->print(str);
+ args[0]->print(str, query_type);
if (negated)
str->append(STRING_WITH_LEN(" not"));
str->append(STRING_WITH_LEN(" in ("));
- print_args(str, 1);
+ print_args(str, 1, query_type);
str->append(STRING_WITH_LEN("))"));
}
@@ -4084,19 +4084,19 @@ void Item_cond::update_used_tables()
}
-void Item_cond::print(String *str)
+void Item_cond::print(String *str, enum_query_type query_type)
{
str->append('(');
List_iterator_fast<Item> li(list);
Item *item;
if ((item=li++))
- item->print(str);
+ item->print(str, query_type);
while ((item=li++))
{
str->append(' ');
str->append(func_name());
str->append(' ');
- item->print(str);
+ item->print(str, query_type);
}
str->append(')');
}
@@ -4279,10 +4279,10 @@ longlong Item_func_isnotnull::val_int()
}
-void Item_func_isnotnull::print(String *str)
+void Item_func_isnotnull::print(String *str, enum_query_type query_type)
{
str->append('(');
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" is not null)"));
}
@@ -5276,24 +5276,24 @@ Item *Item_equal::transform(Item_transformer transformer, uchar *arg)
return Item_func::transform(transformer, arg);
}
-void Item_equal::print(String *str)
+void Item_equal::print(String *str, enum_query_type query_type)
{
str->append(func_name());
str->append('(');
List_iterator_fast<Item_field> it(fields);
Item *item;
if (const_item)
- const_item->print(str);
+ const_item->print(str, query_type);
else
{
item= it++;
- item->print(str);
+ item->print(str, query_type);
}
while ((item= it++))
{
str->append(',');
str->append(' ');
- item->print(str);
+ item->print(str, query_type);
}
str->append(')');
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 188d87a69ca..0166a18029d 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -123,7 +123,7 @@ public:
virtual bool val_bool();
virtual longlong val_int();
virtual void fix_length_and_dec();
- virtual void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
protected:
Item_func_truth(Item *a, bool a_value, bool a_affirmative)
@@ -338,7 +338,12 @@ public:
optimize_type select_optimize() const { return OPTIMIZE_OP; }
virtual enum Functype rev_functype() const { return UNKNOWN_FUNC; }
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
- void print(String *str) { Item_func::print_op(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ Item_func::print_op(str, query_type);
+ }
+
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
@@ -368,7 +373,7 @@ public:
enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; }
Item *neg_transformer(THD *thd);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
class Item_maxmin_subselect;
@@ -433,7 +438,7 @@ public:
longlong val_int();
enum Functype functype() const { return NOT_ALL_FUNC; }
const char *func_name() const { return "<not>"; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
void set_sum_test(Item_sum_hybrid *item) { test_sum_item= item; };
void set_sub_test(Item_maxmin_subselect *item) { test_sub_item= item; };
bool empty_underlying_subquery();
@@ -594,7 +599,7 @@ public:
const char *func_name() const { return "between"; }
bool fix_fields(THD *, Item **);
void fix_length_and_dec();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
uint decimal_precision() const { return 1; }
@@ -608,7 +613,11 @@ public:
longlong val_int();
optimize_type select_optimize() const { return OPTIMIZE_NONE; }
const char *func_name() const { return "strcmp"; }
- void print(String *str) { Item_func::print(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ Item_func::print(str, query_type);
+ }
};
@@ -711,7 +720,12 @@ public:
void fix_length_and_dec();
uint decimal_precision() const { return args[0]->decimal_precision(); }
const char *func_name() const { return "nullif"; }
- void print(String *str) { Item_func::print(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ Item_func::print(str, query_type);
+ }
+
table_map not_null_tables() const { return 0; }
bool is_null();
};
@@ -1141,7 +1155,7 @@ public:
enum Item_result result_type () const { return cached_result_type; }
enum_field_types field_type() const { return cached_field_type; }
const char *func_name() const { return "case"; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
Item *find_item(String *str);
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
void cleanup();
@@ -1208,7 +1222,7 @@ public:
}
optimize_type select_optimize() const
{ return OPTIMIZE_KEY; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
bool nulls_in_row();
@@ -1330,7 +1344,7 @@ public:
table_map not_null_tables() const
{ return abort_on_null ? not_null_tables_cache : 0; }
Item *neg_transformer(THD *thd);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
void top_level_item() { abort_on_null=1; }
};
@@ -1395,7 +1409,12 @@ public:
longlong val_int();
bool fix_fields(THD *thd, Item **ref);
const char *func_name() const { return "regexp"; }
- void print(String *str) { print_op(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ print_op(str, query_type);
+ }
+
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
};
@@ -1407,7 +1426,11 @@ public:
Item_func_regex(Item *a,Item *b) :Item_bool_func(a,b) {}
longlong val_int() { return 0;}
const char *func_name() const { return "regex"; }
- void print(String *str) { print_op(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ print_op(str, query_type);
+ }
};
#endif /* USE_REGEX */
@@ -1444,7 +1467,7 @@ public:
List<Item>* argument_list() { return &list; }
table_map used_tables() const;
void update_used_tables();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
friend int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves,
COND **conds);
@@ -1568,7 +1591,7 @@ public:
void update_used_tables();
bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
Item *transform(Item_transformer transformer, uchar *arg);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
CHARSET_INFO *compare_collation()
{ return fields.head()->collation.collation; }
};
diff --git a/sql/item_func.cc b/sql/item_func.cc
index b61f683ae9f..e07ddeeb802 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -374,37 +374,37 @@ table_map Item_func::not_null_tables() const
}
-void Item_func::print(String *str)
+void Item_func::print(String *str, enum_query_type query_type)
{
str->append(func_name());
str->append('(');
- print_args(str, 0);
+ print_args(str, 0, query_type);
str->append(')');
}
-void Item_func::print_args(String *str, uint from)
+void Item_func::print_args(String *str, uint from, enum_query_type query_type)
{
for (uint i=from ; i < arg_count ; i++)
{
if (i != from)
str->append(',');
- args[i]->print(str);
+ args[i]->print(str, query_type);
}
}
-void Item_func::print_op(String *str)
+void Item_func::print_op(String *str, enum_query_type query_type)
{
str->append('(');
for (uint i=0 ; i < arg_count-1 ; i++)
{
- args[i]->print(str);
+ args[i]->print(str, query_type);
str->append(' ');
str->append(func_name());
str->append(' ');
}
- args[arg_count-1]->print(str);
+ args[arg_count-1]->print(str, query_type);
str->append(')');
}
@@ -884,10 +884,10 @@ my_decimal *Item_func_numhybrid::val_decimal(my_decimal *decimal_value)
}
-void Item_func_signed::print(String *str)
+void Item_func_signed::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("cast("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as signed)"));
}
@@ -955,10 +955,10 @@ longlong Item_func_signed::val_int()
}
-void Item_func_unsigned::print(String *str)
+void Item_func_unsigned::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("cast("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as unsigned)"));
}
@@ -1064,7 +1064,7 @@ err:
}
-void Item_decimal_typecast::print(String *str)
+void Item_decimal_typecast::print(String *str, enum_query_type query_type)
{
char len_buf[20*3 + 1];
char *end;
@@ -1072,7 +1072,7 @@ void Item_decimal_typecast::print(String *str)
uint precision= my_decimal_length_to_precision(max_length, decimals,
unsigned_flag);
str->append(STRING_WITH_LEN("cast("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as decimal("));
end=int10_to_str(precision, len_buf,10);
@@ -2537,16 +2537,16 @@ longlong Item_func_locate::val_int()
}
-void Item_func_locate::print(String *str)
+void Item_func_locate::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("locate("));
- args[1]->print(str);
+ args[1]->print(str, query_type);
str->append(',');
- args[0]->print(str);
+ args[0]->print(str, query_type);
if (arg_count == 3)
{
str->append(',');
- args[2]->print(str);
+ args[2]->print(str, query_type);
}
str->append(')');
}
@@ -3095,7 +3095,7 @@ void Item_udf_func::cleanup()
}
-void Item_udf_func::print(String *str)
+void Item_udf_func::print(String *str, enum_query_type query_type)
{
str->append(func_name());
str->append('(');
@@ -3103,7 +3103,7 @@ void Item_udf_func::print(String *str)
{
if (i != 0)
str->append(',');
- args[i]->print_item_w_name(str);
+ args[i]->print_item_w_name(str, query_type);
}
str->append(')');
}
@@ -3683,12 +3683,12 @@ longlong Item_func_benchmark::val_int()
}
-void Item_func_benchmark::print(String *str)
+void Item_func_benchmark::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("benchmark("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(',');
- args[1]->print(str);
+ args[1]->print(str, query_type);
str->append(')');
}
@@ -3995,7 +3995,7 @@ double user_var_entry::val_real(my_bool *null_value)
/** Get the value of a variable as an integer. */
-longlong user_var_entry::val_int(my_bool *null_value)
+longlong user_var_entry::val_int(my_bool *null_value) const
{
if ((*null_value= (value == 0)))
return LL(0);
@@ -4278,22 +4278,23 @@ my_decimal *Item_func_set_user_var::val_decimal_result(my_decimal *val)
}
-void Item_func_set_user_var::print(String *str)
+void Item_func_set_user_var::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("(@"));
str->append(name.str, name.length);
str->append(STRING_WITH_LEN(":="));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(')');
}
-void Item_func_set_user_var::print_as_stmt(String *str)
+void Item_func_set_user_var::print_as_stmt(String *str,
+ enum_query_type query_type)
{
str->append(STRING_WITH_LEN("set @"));
str->append(name.str, name.length);
str->append(STRING_WITH_LEN(":="));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(')');
}
@@ -4666,7 +4667,7 @@ enum Item_result Item_func_get_user_var::result_type() const
}
-void Item_func_get_user_var::print(String *str)
+void Item_func_get_user_var::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("(@"));
str->append(name.str,name.length);
@@ -4764,7 +4765,7 @@ my_decimal* Item_user_var_as_out_param::val_decimal(my_decimal *decimal_buffer)
}
-void Item_user_var_as_out_param::print(String *str)
+void Item_user_var_as_out_param::print(String *str, enum_query_type query_type)
{
str->append('@');
str->append(name.str,name.length);
@@ -5103,12 +5104,12 @@ double Item_func_match::val_real()
table->record[0], 0));
}
-void Item_func_match::print(String *str)
+void Item_func_match::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("(match "));
- print_args(str, 1);
+ print_args(str, 1, query_type);
str->append(STRING_WITH_LEN(" against ("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
if (flags & FT_BOOL)
str->append(STRING_WITH_LEN(" in boolean mode"));
else if (flags & FT_EXPAND)
@@ -5519,7 +5520,7 @@ Item_result
Item_func_sp::result_type() const
{
DBUG_ENTER("Item_func_sp::result_type");
- DBUG_PRINT("info", ("m_sp = %p", m_sp));
+ DBUG_PRINT("info", ("m_sp = %p", (void *) m_sp));
DBUG_ASSERT(sp_result_field);
DBUG_RETURN(sp_result_field->result_type());
}
diff --git a/sql/item_func.h b/sql/item_func.h
index c73b46f21e6..4f86337e390 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -140,9 +140,9 @@ public:
inline uint argument_count() const { return arg_count; }
inline void remove_arguments() { arg_count=0; }
void split_sum_func(THD *thd, Item **ref_pointer_array, List<Item> &fields);
- void print(String *str);
- void print_op(String *str);
- void print_args(String *str, uint from);
+ virtual void print(String *str, enum_query_type query_type);
+ void print_op(String *str, enum_query_type query_type);
+ void print_args(String *str, uint from, enum_query_type query_type);
virtual void fix_num_length_and_dec();
void count_only_length();
void count_real_length();
@@ -293,7 +293,12 @@ class Item_num_op :public Item_func_numhybrid
public:
Item_num_op(Item *a,Item *b) :Item_func_numhybrid(a, b) {}
virtual void result_precision()= 0;
- void print(String *str) { print_op(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ print_op(str, query_type);
+ }
+
void find_num_type();
String *str_op(String *str) { DBUG_ASSERT(0); return 0; }
};
@@ -338,7 +343,7 @@ public:
longlong val_int_from_str(int *error);
void fix_length_and_dec()
{ max_length=args[0]->max_length; unsigned_flag=0; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
uint decimal_precision() const { return args[0]->decimal_precision(); }
};
@@ -351,7 +356,7 @@ public:
void fix_length_and_dec()
{ max_length=args[0]->max_length; unsigned_flag=1; }
longlong val_int();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -372,7 +377,7 @@ public:
enum_field_types field_type() const { return MYSQL_TYPE_NEWDECIMAL; }
void fix_length_and_dec() {};
const char *func_name() const { return "decimal_typecast"; }
- void print(String *);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -442,7 +447,12 @@ public:
longlong val_int();
const char *func_name() const { return "DIV"; }
void fix_length_and_dec();
- void print(String *str) { print_op(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ print_op(str, query_type);
+ }
+
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -845,7 +855,7 @@ public:
const char *func_name() const { return "locate"; }
longlong val_int();
void fix_length_and_dec();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -902,7 +912,11 @@ public:
Item_func_bit(Item *a, Item *b) :Item_int_func(a, b) {}
Item_func_bit(Item *a) :Item_int_func(a) {}
void fix_length_and_dec() { unsigned_flag= 1; }
- void print(String *str) { print_op(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ print_op(str, query_type);
+ }
};
class Item_func_bit_or :public Item_func_bit
@@ -952,7 +966,11 @@ public:
Item_func_bit_neg(Item *a) :Item_func_bit(a) {}
longlong val_int();
const char *func_name() const { return "~"; }
- void print(String *str) { Item_func::print(str); }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ Item_func::print(str, query_type);
+ }
};
@@ -981,7 +999,7 @@ public:
longlong val_int();
const char *func_name() const { return "benchmark"; }
void fix_length_and_dec() { max_length=1; maybe_null=0; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -1078,7 +1096,7 @@ public:
Item_result result_type () const { return udf.result_type(); }
table_map not_null_tables() const { return 0; }
bool is_expensive() { return 1; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -1315,8 +1333,8 @@ public:
enum Item_result result_type () const { return cached_result_type; }
bool fix_fields(THD *thd, Item **ref);
void fix_length_and_dec();
- void print(String *str);
- void print_as_stmt(String *str);
+ virtual void print(String *str, enum_query_type query_type);
+ void print_as_stmt(String *str, enum_query_type query_type);
const char *func_name() const { return "set_user_var"; }
int save_in_field(Field *field, bool no_conversions,
bool can_use_result_field);
@@ -1346,7 +1364,7 @@ public:
my_decimal *val_decimal(my_decimal*);
String *val_str(String* str);
void fix_length_and_dec();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
enum Item_result result_type() const;
/*
We must always return variables as strings to guard against selects of type
@@ -1391,7 +1409,7 @@ public:
my_decimal *val_decimal(my_decimal *decimal_buffer);
/* fix_fields() binds variable name with its entry structure */
bool fix_fields(THD *thd, Item **ref);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
void set_null_value(CHARSET_INFO* cs);
void set_value(const char *str, uint length, CHARSET_INFO* cs);
};
@@ -1469,7 +1487,7 @@ public:
/* The following should be safe, even if we compare doubles */
longlong val_int() { DBUG_ASSERT(fixed == 1); return val_real() != 0.0; }
double val_real();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool fix_index();
void init_search(bool no_order);
diff --git a/sql/item_geofunc.h b/sql/item_geofunc.h
index 62be78eee9e..edbe104e307 100644
--- a/sql/item_geofunc.h
+++ b/sql/item_geofunc.h
@@ -224,8 +224,13 @@ public:
DBUG_ASSERT(0); // Should never happened
return "sp_unknown";
}
- }
- void print(String *str) { Item_func::print(str); }
+ }
+
+ virtual inline void print(String *str, enum_query_type query_type)
+ {
+ Item_func::print(str, query_type);
+ }
+
void fix_length_and_dec() { maybe_null= 1; }
bool is_null() { (void) val_int(); return null_value; }
};
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 369aa04930e..28de03bf049 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -134,14 +134,14 @@ bool Item_row::check_cols(uint c)
return 0;
}
-void Item_row::print(String *str)
+void Item_row::print(String *str, enum_query_type query_type)
{
str->append('(');
for (uint i= 0; i < arg_count; i++)
{
if (i)
str->append(',');
- items[i]->print(str);
+ items[i]->print(str, query_type);
}
str->append(')');
}
diff --git a/sql/item_row.h b/sql/item_row.h
index dd7436888f0..67441f49603 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -65,7 +65,7 @@ public:
bool const_item() const { return const_item_cache; };
enum Item_result result_type() const { return ROW_RESULT; }
void update_used_tables();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool walk(Item_processor processor, bool walk_subquery, uchar *arg);
Item *transform(Item_transformer transformer, uchar *arg);
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index 42314872997..fe805d7672a 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -1594,20 +1594,20 @@ void Item_func_trim::fix_length_and_dec()
}
}
-void Item_func_trim::print(String *str)
+void Item_func_trim::print(String *str, enum_query_type query_type)
{
if (arg_count == 1)
{
- Item_func::print(str);
+ Item_func::print(str, query_type);
return;
}
str->append(Item_func_trim::func_name());
str->append('(');
str->append(mode_name());
str->append(' ');
- args[1]->print(str);
+ args[1]->print(str, query_type);
str->append(STRING_WITH_LEN(" from "));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(')');
}
@@ -2116,12 +2116,12 @@ String *Item_func_format::val_str(String *str)
}
-void Item_func_format::print(String *str)
+void Item_func_format::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("format("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(',');
- args[1]->print(str);
+ args[1]->print(str, query_type);
str->append(')');
}
@@ -2292,14 +2292,14 @@ Item *Item_func_make_set::transform(Item_transformer transformer, uchar *arg)
}
-void Item_func_make_set::print(String *str)
+void Item_func_make_set::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("make_set("));
- item->print(str);
+ item->print(str, query_type);
if (arg_count)
{
str->append(',');
- print_args(str, 0);
+ print_args(str, 0, query_type);
}
str->append(')');
}
@@ -2710,10 +2710,10 @@ void Item_func_conv_charset::fix_length_and_dec()
max_length = args[0]->max_length*conv_charset->mbmaxlen;
}
-void Item_func_conv_charset::print(String *str)
+void Item_func_conv_charset::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("convert("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" using "));
str->append(conv_charset->csname);
str->append(')');
@@ -2781,10 +2781,10 @@ bool Item_func_set_collation::eq(const Item *item, bool binary_cmp) const
}
-void Item_func_set_collation::print(String *str)
+void Item_func_set_collation::print(String *str, enum_query_type query_type)
{
str->append('(');
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" collate "));
DBUG_ASSERT(args[1]->basic_const_item() &&
args[1]->type() == Item::STRING_ITEM);
@@ -2903,10 +2903,10 @@ String *Item_func_unhex::val_str(String *str)
}
-void Item_func_binary::print(String *str)
+void Item_func_binary::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("cast("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as binary)"));
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 0d7cd66acff..81baf9a4c5f 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -225,7 +225,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "trim"; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
virtual const char *mode_name() const { return "both"; }
};
@@ -482,7 +482,7 @@ public:
Item_str_func::walk(processor, walk_subquery, arg);
}
Item *transform(Item_transformer transformer, uchar *arg);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -494,7 +494,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "format"; }
- void print(String *);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -617,7 +617,7 @@ public:
collation.set(&my_charset_bin);
max_length=args[0]->max_length;
}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
const char *func_name() const { return "cast_as_binary"; }
};
@@ -719,7 +719,7 @@ public:
String *val_str(String *);
void fix_length_and_dec();
const char *func_name() const { return "convert"; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
class Item_func_set_collation :public Item_str_func
@@ -731,7 +731,7 @@ public:
bool eq(const Item *item, bool binary_cmp) const;
const char *func_name() const { return "collate"; }
enum Functype functype() const { return COLLATE_FUNC; }
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
Item_field *filed_for_view_update()
{
/* this function is transparent for view updating */
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 46b8d2e46cc..7b68d258d29 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -306,10 +306,10 @@ void Item_subselect::update_used_tables()
}
-void Item_subselect::print(String *str)
+void Item_subselect::print(String *str, enum_query_type query_type)
{
str->append('(');
- engine->print(str);
+ engine->print(str, query_type);
str->append(')');
}
@@ -391,10 +391,10 @@ void Item_maxmin_subselect::cleanup()
}
-void Item_maxmin_subselect::print(String *str)
+void Item_maxmin_subselect::print(String *str, enum_query_type query_type)
{
str->append(max?"<max>":"<min>", 5);
- Item_singlerow_subselect::print(str);
+ Item_singlerow_subselect::print(str, query_type);
}
@@ -630,10 +630,10 @@ Item_exists_subselect::Item_exists_subselect(st_select_lex *select_lex):
}
-void Item_exists_subselect::print(String *str)
+void Item_exists_subselect::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("exists"));
- Item_subselect::print(str);
+ Item_subselect::print(str, query_type);
}
@@ -1553,16 +1553,16 @@ err:
}
-void Item_in_subselect::print(String *str)
+void Item_in_subselect::print(String *str, enum_query_type query_type)
{
if (transformed)
str->append(STRING_WITH_LEN("<exists>"));
else
{
- left_expr->print(str);
+ left_expr->print(str, query_type);
str->append(STRING_WITH_LEN(" in "));
}
- Item_subselect::print(str);
+ Item_subselect::print(str, query_type);
}
@@ -1587,18 +1587,18 @@ Item_allany_subselect::select_transformer(JOIN *join)
}
-void Item_allany_subselect::print(String *str)
+void Item_allany_subselect::print(String *str, enum_query_type query_type)
{
if (transformed)
str->append(STRING_WITH_LEN("<exists>"));
else
{
- left_expr->print(str);
+ left_expr->print(str, query_type);
str->append(' ');
str->append(func->symbol(all));
str->append(all ? " all " : " any ", 5);
}
- Item_subselect::print(str);
+ Item_subselect::print(str, query_type);
}
@@ -2384,22 +2384,24 @@ table_map subselect_union_engine::upper_select_const_tables()
}
-void subselect_single_select_engine::print(String *str)
+void subselect_single_select_engine::print(String *str,
+ enum_query_type query_type)
{
- select_lex->print(thd, str);
+ select_lex->print(thd, str, query_type);
}
-void subselect_union_engine::print(String *str)
+void subselect_union_engine::print(String *str, enum_query_type query_type)
{
- unit->print(str);
+ unit->print(str, query_type);
}
-void subselect_uniquesubquery_engine::print(String *str)
+void subselect_uniquesubquery_engine::print(String *str,
+ enum_query_type query_type)
{
str->append(STRING_WITH_LEN("<primary_index_lookup>("));
- tab->ref.items[0]->print(str);
+ tab->ref.items[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" in "));
str->append(tab->table->s->table_name.str, tab->table->s->table_name.length);
KEY *key_info= tab->table->key_info+ tab->ref.key;
@@ -2408,16 +2410,17 @@ void subselect_uniquesubquery_engine::print(String *str)
if (cond)
{
str->append(STRING_WITH_LEN(" where "));
- cond->print(str);
+ cond->print(str, query_type);
}
str->append(')');
}
-void subselect_indexsubquery_engine::print(String *str)
+void subselect_indexsubquery_engine::print(String *str,
+ enum_query_type query_type)
{
str->append(STRING_WITH_LEN("<index_lookup>("));
- tab->ref.items[0]->print(str);
+ tab->ref.items[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" in "));
str->append(tab->table->s->table_name.str, tab->table->s->table_name.length);
KEY *key_info= tab->table->key_info+ tab->ref.key;
@@ -2428,12 +2431,12 @@ void subselect_indexsubquery_engine::print(String *str)
if (cond)
{
str->append(STRING_WITH_LEN(" where "));
- cond->print(str);
+ cond->print(str, query_type);
}
if (having)
{
str->append(STRING_WITH_LEN(" having "));
- having->print(str);
+ having->print(str, query_type);
}
str->append(')');
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index de4b1cbdc06..d4aa621c083 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -103,7 +103,7 @@ public:
inline bool get_const_item_cache() { return const_item_cache; }
Item *get_tmp_table_item(THD *thd);
void update_used_tables();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
virtual bool have_guarded_conds() { return FALSE; }
bool change_engine(subselect_engine *eng)
{
@@ -203,7 +203,7 @@ protected:
public:
Item_maxmin_subselect(THD *thd, Item_subselect *parent,
st_select_lex *select_lex, bool max);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
void cleanup();
bool any_value() { return was_values; }
void register_value() { was_values= TRUE; }
@@ -234,7 +234,7 @@ public:
my_decimal *val_decimal(my_decimal *);
bool val_bool();
void fix_length_and_dec();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
friend class select_exists_subselect;
friend class subselect_uniquesubquery_engine;
@@ -312,7 +312,7 @@ public:
void top_level_item() { abort_on_null=1; }
inline bool is_top_level_item() { return abort_on_null; }
bool test_limit(st_select_lex_unit *unit);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool fix_fields(THD *thd, Item **ref);
friend class Item_ref_null_helper;
@@ -335,7 +335,7 @@ public:
// only ALL subquery has upper not
subs_type substype() { return all?ALL_SUBS:ANY_SUBS; }
trans_res select_transformer(JOIN *join);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -399,7 +399,7 @@ public:
virtual bool may_be_null() { return maybe_null; };
virtual table_map upper_select_const_tables()= 0;
static table_map calc_const_tables(TABLE_LIST *);
- virtual void print(String *str)= 0;
+ virtual void print(String *str, enum_query_type query_type)= 0;
virtual bool change_result(Item_subselect *si, select_subselect *result)= 0;
virtual bool no_tables()= 0;
virtual bool is_executed() const { return FALSE; }
@@ -430,7 +430,7 @@ public:
uint8 uncacheable();
void exclude();
table_map upper_select_const_tables();
- void print (String *str);
+ virtual void print (String *str, enum_query_type query_type);
bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
bool may_be_null();
@@ -454,7 +454,7 @@ public:
uint8 uncacheable();
void exclude();
table_map upper_select_const_tables();
- void print (String *str);
+ virtual void print (String *str, enum_query_type query_type);
bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
bool is_executed() const;
@@ -511,7 +511,7 @@ public:
uint8 uncacheable() { return UNCACHEABLE_DEPENDENT; }
void exclude();
table_map upper_select_const_tables() { return 0; }
- void print (String *str);
+ virtual void print (String *str, enum_query_type query_type);
bool change_result(Item_subselect *si, select_subselect *result);
bool no_tables();
int scan_table();
@@ -565,7 +565,7 @@ public:
having(having_arg)
{}
int exec();
- void print (String *str);
+ virtual void print (String *str, enum_query_type query_type);
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 27b964a9e15..f5a3956c1e4 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -359,14 +359,14 @@ void Item_sum::make_field(Send_field *tmp_field)
}
-void Item_sum::print(String *str)
+void Item_sum::print(String *str, enum_query_type query_type)
{
str->append(func_name());
for (uint i=0 ; i < arg_count ; i++)
{
if (i)
str->append(',');
- args[i]->print(str);
+ args[i]->print(str, query_type);
}
str->append(')');
}
@@ -2716,7 +2716,7 @@ void Item_udf_sum::cleanup()
}
-void Item_udf_sum::print(String *str)
+void Item_udf_sum::print(String *str, enum_query_type query_type)
{
str->append(func_name());
str->append('(');
@@ -2724,7 +2724,7 @@ void Item_udf_sum::print(String *str)
{
if (i)
str->append(',');
- args[i]->print(str);
+ args[i]->print(str, query_type);
}
str->append(')');
}
@@ -3460,7 +3460,7 @@ String* Item_func_group_concat::val_str(String* str)
}
-void Item_func_group_concat::print(String *str)
+void Item_func_group_concat::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("group_concat("));
if (distinct)
@@ -3469,7 +3469,7 @@ void Item_func_group_concat::print(String *str)
{
if (i)
str->append(',');
- args[i]->print(str);
+ args[i]->print(str, query_type);
}
if (arg_count_order)
{
@@ -3478,7 +3478,7 @@ void Item_func_group_concat::print(String *str)
{
if (i)
str->append(',');
- (*order[i]->item)->print(str);
+ (*order[i]->item)->print(str, query_type);
if (order[i]->asc)
str->append(STRING_WITH_LEN(" ASC"));
else
diff --git a/sql/item_sum.h b/sql/item_sum.h
index a3582967736..d1e6a74e85e 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -343,7 +343,7 @@ public:
}
virtual bool const_item() const { return forced_const; }
void make_field(Send_field *field);
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
void fix_num_length_and_dec();
/*
@@ -984,7 +984,7 @@ public:
void reset_field() {};
void update_field() {};
void cleanup();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -1257,7 +1257,7 @@ public:
String* val_str(String* str);
Item *copy_or_same(THD* thd);
void no_rows_in_result() {}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
virtual bool change_context_processor(uchar *cntx)
{ context= (Name_resolution_context *)cntx; return FALSE; }
};
diff --git a/sql/item_timefunc.cc b/sql/item_timefunc.cc
index a0beadcd481..390f94945aa 100644
--- a/sql/item_timefunc.cc
+++ b/sql/item_timefunc.cc
@@ -2217,23 +2217,23 @@ static const char *interval_names[]=
"second_microsecond"
};
-void Item_date_add_interval::print(String *str)
+void Item_date_add_interval::print(String *str, enum_query_type query_type)
{
str->append('(');
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(date_sub_interval?" - interval ":" + interval ");
- args[1]->print(str);
+ args[1]->print(str, query_type);
str->append(' ');
str->append(interval_names[int_type]);
str->append(')');
}
-void Item_extract::print(String *str)
+void Item_extract::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("extract("));
str->append(interval_names[int_type]);
str->append(STRING_WITH_LEN(" from "));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(')');
}
@@ -2374,20 +2374,20 @@ bool Item_char_typecast::eq(const Item *item, bool binary_cmp) const
return 1;
}
-void Item_typecast::print(String *str)
+void Item_typecast::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("cast("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as "));
str->append(cast_type());
str->append(')');
}
-void Item_char_typecast::print(String *str)
+void Item_char_typecast::print(String *str, enum_query_type query_type)
{
str->append(STRING_WITH_LEN("cast("));
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(STRING_WITH_LEN(" as char"));
if (cast_length >= 0)
{
@@ -2822,7 +2822,7 @@ null_date:
}
-void Item_func_add_time::print(String *str)
+void Item_func_add_time::print(String *str, enum_query_type query_type)
{
if (is_date)
{
@@ -2836,9 +2836,9 @@ void Item_func_add_time::print(String *str)
else
str->append(STRING_WITH_LEN("subtime("));
}
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(',');
- args[1]->print(str);
+ args[1]->print(str, query_type);
str->append(')');
}
@@ -3083,7 +3083,7 @@ null_date:
}
-void Item_func_timestamp_diff::print(String *str)
+void Item_func_timestamp_diff::print(String *str, enum_query_type query_type)
{
str->append(func_name());
str->append('(');
@@ -3123,7 +3123,7 @@ void Item_func_timestamp_diff::print(String *str)
for (uint i=0 ; i < 2 ; i++)
{
str->append(',');
- args[i]->print(str);
+ args[i]->print(str, query_type);
}
str->append(')');
}
@@ -3163,7 +3163,7 @@ String *Item_func_get_format::val_str(String *str)
}
-void Item_func_get_format::print(String *str)
+void Item_func_get_format::print(String *str, enum_query_type query_type)
{
str->append(func_name());
str->append('(');
@@ -3181,7 +3181,7 @@ void Item_func_get_format::print(String *str)
default:
DBUG_ASSERT(0);
}
- args[0]->print(str);
+ args[0]->print(str, query_type);
str->append(')');
}
diff --git a/sql/item_timefunc.h b/sql/item_timefunc.h
index 9be7e97db49..cfcf5fab080 100644
--- a/sql/item_timefunc.h
+++ b/sql/item_timefunc.h
@@ -694,7 +694,7 @@ public:
longlong val_int();
bool get_date(MYSQL_TIME *res, uint fuzzy_date);
bool eq(const Item *item, bool binary_cmp) const;
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -711,7 +711,7 @@ class Item_extract :public Item_int_func
const char *func_name() const { return "extract"; }
void fix_length_and_dec();
bool eq(const Item *item, bool binary_cmp) const;
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
bool check_partition_func_processor(uchar *int_arg) {return FALSE;}
};
@@ -735,7 +735,7 @@ public:
max_length=args[0]->max_length;
}
virtual const char* cast_type() const= 0;
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -767,7 +767,7 @@ public:
const char* cast_type() const { return "char"; };
String *val_str(String *a);
void fix_length_and_dec();
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -901,7 +901,7 @@ public:
{
return tmp_table_field_from_field_type(table, 0);
}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
const char *func_name() const { return "add_time"; }
double val_real() { return val_real_from_decimal(); }
my_decimal *val_decimal(my_decimal *decimal_value)
@@ -977,7 +977,7 @@ public:
decimals=0;
maybe_null=1;
}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
@@ -1001,7 +1001,7 @@ public:
decimals=0;
max_length=17*MY_CHARSET_BIN_MB_MAXLEN;
}
- void print(String *str);
+ virtual void print(String *str, enum_query_type query_type);
};
diff --git a/sql/log.cc b/sql/log.cc
index 328aaa45f3f..d000aa6e94e 100644
--- a/sql/log.cc
+++ b/sql/log.cc
@@ -3384,6 +3384,16 @@ THD::binlog_start_trans_and_stmt()
if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
trans_register_ha(this, TRUE, binlog_hton);
trans_register_ha(this, FALSE, binlog_hton);
+ /*
+ Mark statement transaction as read/write. We never start
+ a binary log transaction and keep it read-only,
+ therefore it's best to mark the transaction read/write just
+ at the same time we start it.
+ Not necessary to mark the normal transaction read/write
+ since the statement-level flag will be propagated automatically
+ inside ha_commit_trans.
+ */
+ ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
}
DBUG_VOID_RETURN;
}
diff --git a/sql/log_event.cc b/sql/log_event.cc
index 2b53199a43c..911d9ec8d88 100644
--- a/sql/log_event.cc
+++ b/sql/log_event.cc
@@ -137,7 +137,7 @@ static void inline slave_rows_error_report(enum loglevel level, int ha_error,
" %s, Error_code: %d;", err->msg, err->code);
}
- rli->report(level, thd->net.client_last_errno,
+ rli->report(level, thd->net.last_errno,
"Could not execute %s event on table %s.%s;"
"%s handler error %s; "
"the event's master log %s, end_log_pos %lu",
@@ -3117,7 +3117,7 @@ int Format_description_log_event::do_apply_event(Relay_log_info const *rli)
original place when it comes to us; we'll know this by checking
log_pos ("artificial" events have log_pos == 0).
*/
- if (!artificial_event && created && thd->transaction.all.nht)
+ if (!artificial_event && created && thd->transaction.all.ha_list)
{
/* This is not an error (XA is safe), just an information */
rli->report(INFORMATION_LEVEL, 0,
@@ -8268,6 +8268,7 @@ int Rows_log_event::find_row(const Relay_log_info *rli)
ok:
table->default_column_bitmaps();
DBUG_RETURN(0);
+
err:
table->default_column_bitmaps();
DBUG_RETURN(error);
diff --git a/sql/log_event_old.cc b/sql/log_event_old.cc
index 13f9763debe..808356a05c7 100644
--- a/sql/log_event_old.cc
+++ b/sql/log_event_old.cc
@@ -1529,10 +1529,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
- uint actual_error= thd->net.client_last_errno;
+ uint actual_error= thd->net.last_errno;
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' in %s event: when locking tables",
- (actual_error ? thd->net.client_last_error :
+ (actual_error ? thd->net.last_error :
"unexpected success or fatal error"),
get_type_str());
thd->is_fatal_error= 1;
@@ -1573,10 +1573,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
Error reporting borrowed from Query_log_event with many excessive
simplifications (we don't honour --slave-skip-errors)
*/
- uint actual_error= thd->net.client_last_errno;
+ uint actual_error= thd->net.last_errno;
rli->report(ERROR_LEVEL, actual_error,
"Error '%s' on reopening tables",
- (actual_error ? thd->net.client_last_error :
+ (actual_error ? thd->net.last_error :
"unexpected success or fatal error"));
thd->is_slave_error= 1;
}
@@ -1729,10 +1729,10 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
break;
default:
- rli->report(ERROR_LEVEL, thd->net.client_last_errno,
+ rli->report(ERROR_LEVEL, thd->net.last_errno,
"Error in %s event: row application failed. %s",
get_type_str(),
- thd->net.client_last_error ? thd->net.client_last_error : "");
+ thd->net.last_error ? thd->net.last_error : "");
thd->is_slave_error= 1;
break;
}
@@ -1779,12 +1779,12 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
if (error)
{ /* error has occured during the transaction */
- rli->report(ERROR_LEVEL, thd->net.client_last_errno,
+ rli->report(ERROR_LEVEL, thd->net.last_errno,
"Error in %s event: error during transaction execution "
"on table %s.%s. %s",
get_type_str(), table->s->db.str,
table->s->table_name.str,
- thd->net.client_last_error ? thd->net.client_last_error : "");
+ thd->net.last_error ? thd->net.last_error : "");
/*
If one day we honour --skip-slave-errors in row-based replication, and
@@ -1913,7 +1913,7 @@ Old_rows_log_event::do_update_pos(Relay_log_info *rli)
example "no key found" (as this is allowed). This is a safety
measure; apparently those errors (e.g. when executing a
Delete_rows_log_event_old of a non-existing row, like in
- rpl_row_mystery22.test, thd->net.client_last_error = "Can't
+ rpl_row_mystery22.test, thd->net.last_error = "Can't
find record in 't1'" and last_errno=1032) do not become
visible. We still prefer to wipe them out.
*/
@@ -2647,8 +2647,8 @@ Write_rows_log_event_old::do_exec_row(const Relay_log_info *const rli)
DBUG_ASSERT(m_table != NULL);
int error= write_row(rli, TRUE /* overwrite */);
- if (error && !thd->net.client_last_errno)
- thd->net.client_last_errno= error;
+ if (error && !thd->net.last_errno)
+ thd->net.last_errno= error;
return error;
}
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index ea7482ca067..b768db95092 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -44,6 +44,19 @@
#include "sql_plugin.h"
#include "scheduler.h"
+/**
+ Query type constants.
+
+ QT_ORDINARY -- ordinary SQL query.
+ QT_IS -- SQL query to be shown in INFORMATION_SCHEMA (in utf8 and without
+ character set introducers).
+*/
+enum enum_query_type
+{
+ QT_ORDINARY,
+ QT_IS
+};
+
/* TODO convert all these three maps to Bitmap classes */
typedef ulonglong table_map; /* Used for table bits in join */
#if MAX_INDEXES <= 64
@@ -1035,7 +1048,6 @@ bool check_access(THD *thd, ulong access, const char *db, ulong *save_priv,
bool no_grant, bool no_errors, bool schema_db);
bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
uint number, bool no_errors);
-bool check_global_access(THD *thd, ulong want_access);
#else
inline bool check_access(THD *thd, ulong access, const char *db,
ulong *save_priv, bool no_grant, bool no_errors,
@@ -1048,10 +1060,14 @@ inline bool check_access(THD *thd, ulong access, const char *db,
inline bool check_table_access(THD *thd, ulong want_access, TABLE_LIST *tables,
uint number, bool no_errors)
{ return false; }
-inline bool check_global_access(THD *thd, ulong want_access)
-{ return false; }
#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
+#endif /* MYSQL_SERVER */
+#if defined MYSQL_SERVER || defined INNODB_COMPATIBILITY_HOOKS
+bool check_global_access(THD *thd, ulong want_access);
+#endif /* MYSQL_SERVER || INNODB_COMPATIBILITY_HOOKS */
+#ifdef MYSQL_SERVER
+
/*
Support routine for SQL parser on partitioning syntax
*/
@@ -1709,7 +1725,7 @@ bool mysql_manager_submit(void (*action)());
/* sql_test.cc */
#ifndef DBUG_OFF
-void print_where(COND *cond,const char *info);
+void print_where(COND *cond,const char *info, enum_query_type query_type);
void print_cached_tables(void);
void TEST_filesort(SORT_FIELD *sortorder,uint s_length);
void print_plan(JOIN* join,uint idx, double record_count, double read_time,
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 9c4e6f9e2a2..cdd08be6573 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -121,6 +121,13 @@ extern "C" { // Because of SCO 3.2V4.2
#include <sys/mman.h>
#endif
+#ifdef __WIN__
+#include <crtdbg.h>
+#define SIGNAL_FMT "exception 0x%x"
+#else
+#define SIGNAL_FMT "signal %d"
+#endif
+
#ifdef __NETWARE__
#define zVOLSTATE_ACTIVE 6
#define zVOLSTATE_DEACTIVE 2
@@ -217,6 +224,7 @@ inline void set_proper_floating_point_mode()
extern "C" int gethostname(char *name, int namelen);
#endif
+extern "C" sig_handler handle_segfault(int sig);
/* Constants */
@@ -1085,9 +1093,6 @@ static void __cdecl kill_server(int sig_ptr)
close_connections();
if (sig != MYSQL_KILL_SIGNAL &&
-#ifdef __WIN__
- sig != SIGINT && /* Bug#18235 */
-#endif
sig != 0)
unireg_abort(1); /* purecov: inspected */
else
@@ -1656,8 +1661,7 @@ static void network_init(void)
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL );
- MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe",
- MB_OK|MB_ICONINFORMATION);
+ sql_perror((char *)lpMsgBuf);
LocalFree(lpMsgBuf);
unireg_abort(1);
}
@@ -1916,16 +1920,162 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused)))
******************************************************************************/
#if defined(__WIN__)
+
+
+/*
+ On Windows, we use native SetConsoleCtrlHandler for handle events like Ctrl-C
+ with graceful shutdown.
+ Also, we do not use signal(), but SetUnhandledExceptionFilter instead - as it
+ provides possibility to pass the exception to just-in-time debugger, collect
+ dumps and potentially also the exception and thread context used to output
+ callstack.
+*/
+
+static BOOL WINAPI console_event_handler( DWORD type )
+{
+ DBUG_ENTER("console_event_handler");
+ if(type == CTRL_C_EVENT)
+ {
+ /*
+ Do not shutdown before startup is finished and shutdown
+ thread is initialized. Otherwise there is a race condition
+ between main thread doing initialization and CTRL-C thread doing
+ cleanup, which can result into crash.
+ */
+ if(hEventShutdown)
+ kill_mysql();
+ else
+ sql_print_warning("CTRL-C ignored during startup");
+ DBUG_RETURN(TRUE);
+ }
+ DBUG_RETURN(FALSE);
+}
+
+
+/*
+ In Visual Studio 2005 and later, default SIGABRT handler will overwrite
+ any unhandled exception filter set by the application and will try to
+ call JIT debugger. This is not what we want, this we calling __debugbreak
+ to stop in debugger, if process is being debugged or to generate
+ EXCEPTION_BREAKPOINT and then handle_segfault will do its magic.
+*/
+
+#if (_MSC_VER >= 1400)
+static void my_sigabrt_handler(int sig)
+{
+ __debugbreak();
+}
+#endif /*_MSC_VER >=1400 */
+
+void win_install_sigabrt_handler(void)
+{
+#if (_MSC_VER >=1400)
+ /*abort() should not override our exception filter*/
+ _set_abort_behavior(0,_CALL_REPORTFAULT);
+ signal(SIGABRT,my_sigabrt_handler);
+#endif /* _MSC_VER >=1400 */
+}
+
+#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER
+#define DEBUGGER_ATTACH_TIMEOUT 120
+/*
+ Wait for debugger to attach and break into debugger. If debugger is not attached,
+ resume after timeout.
+*/
+static void wait_for_debugger(int timeout_sec)
+{
+ if(!IsDebuggerPresent())
+ {
+ int i;
+ printf("Waiting for debugger to attach, pid=%u\n",GetCurrentProcessId());
+ fflush(stdout);
+ for(i= 0; i < timeout_sec; i++)
+ {
+ Sleep(1000);
+ if(IsDebuggerPresent())
+ {
+ /* Break into debugger */
+ __debugbreak();
+ return;
+ }
+ }
+ printf("pid=%u, debugger not attached after %d seconds, resuming\n",GetCurrentProcessId(),
+ timeout_sec);
+ fflush(stdout);
+ }
+}
+#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */
+
+LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers)
+{
+ static BOOL first_time= TRUE;
+ if(!first_time)
+ {
+ /*
+ This routine can be called twice, typically
+ when detaching in JIT debugger.
+ Return EXCEPTION_EXECUTE_HANDLER to terminate process.
+ */
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+ first_time= FALSE;
+#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER
+ /*
+ Unfortunately there is no clean way to debug unhandled exception filters,
+ as debugger does not stop there(also documented in MSDN)
+ To overcome, one could put a MessageBox, but this will not work in service.
+ Better solution is to print error message and sleep some minutes
+ until debugger is attached
+ */
+ wait_for_debugger(DEBUGGER_ATTACH_TIMEOUT);
+#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */
+ __try
+ {
+ set_exception_pointers(ex_pointers);
+ handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ DWORD written;
+ const char msg[] = "Got exception in exception handler!\n";
+ WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg, sizeof(msg)-1,
+ &written,NULL);
+ }
+ /*
+ Return EXCEPTION_CONTINUE_SEARCH to give JIT debugger
+ (drwtsn32 or vsjitdebugger) possibility to attach,
+ if JIT debugger is configured.
+ Windows Error reporting might generate a dump here.
+ */
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+
static void init_signals(void)
{
- int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ;
- for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++)
- signal(signals[i], kill_server) ;
-#if defined(__WIN__)
- signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT
-#else
- signal(SIGBREAK, kill_server);
-#endif
+ win_install_sigabrt_handler();
+ if(opt_console)
+ SetConsoleCtrlHandler(console_event_handler,TRUE);
+ else
+ {
+ /* Avoid MessageBox()es*/
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+
+ /*
+ Do not use SEM_NOGPFAULTERRORBOX in the following SetErrorMode (),
+ because it would prevent JIT debugger and Windows error reporting
+ from working. We need WER or JIT-debugging, since our own unhandled
+ exception filter is not guaranteed to work in all situation
+ (like heap corruption or stack overflow)
+ */
+ SetErrorMode(SetErrorMode(0)|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX);
+ }
+ SetUnhandledExceptionFilter(my_unhandler_exception_filter);
}
@@ -2178,7 +2328,7 @@ static void check_data_home(const char *path)
{
}
-#else /* if ! __WIN__ */
+#endif /*__WIN__ || __NETWARE */
#ifdef HAVE_LINUXTHREADS
#define UNSAFE_DEFAULT_LINUX_THREADS 200
@@ -2208,7 +2358,7 @@ extern "C" sig_handler handle_segfault(int sig)
*/
if (segfaulted)
{
- fprintf(stderr, "Fatal signal %d while backtracing\n", sig);
+ fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig);
exit(1);
}
@@ -2218,7 +2368,7 @@ extern "C" sig_handler handle_segfault(int sig)
localtime_r(&curr_time, &tm);
fprintf(stderr,"\
-%02d%02d%02d %2d:%02d:%02d - mysqld got signal %d;\n\
+%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\
This could be because you hit a bug. It is also possible that this binary\n\
or one of the libraries it was linked against is corrupt, improperly built,\n\
or misconfigured. This error can also be caused by malfunctioning hardware.\n",
@@ -2260,8 +2410,12 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n",
if (!(test_flags & TEST_NO_STACKTRACE))
{
fprintf(stderr,"thd: 0x%lx\n",(long) thd);
+ fprintf(stderr,"\
+Attempting backtrace. You can use the following information to find out\n\
+where mysqld died. If you see no messages after this, something went\n\
+terribly wrong...\n");
print_stacktrace(thd ? (uchar*) thd->thread_stack : (uchar*) 0,
- thread_stack);
+ thread_stack);
}
if (thd)
{
@@ -2327,15 +2481,22 @@ of those buggy OS calls. You should consider whether you really need the\n\
bugs.\n");
}
+#ifdef HAVE_WRITE_CORE
if (test_flags & TEST_CORE_ON_SIGNAL)
{
fprintf(stderr, "Writing a core file\n");
fflush(stderr);
write_core(sig);
}
+#endif
+
+#ifndef __WIN__
+ /* On Windows, do not terminate, but pass control to exception filter */
exit(1);
+#endif
}
+#if !defined(__WIN__) && !defined(__NETWARE__)
#ifndef SA_RESETHAND
#define SA_RESETHAND 0
#endif
@@ -2573,8 +2734,18 @@ pthread_handler_t signal_hand(void *arg __attribute__((unused)))
(TABLE_LIST*) 0, &not_used); // Flush logs
}
/* reenable logs after the options were reloaded */
- logger.set_handlers(LOG_FILE, opt_slow_log ? LOG_TABLE:LOG_NONE,
- opt_log ? LOG_TABLE:LOG_NONE);
+ if (log_output_options & LOG_NONE)
+ {
+ logger.set_handlers(LOG_FILE,
+ opt_slow_log ? LOG_TABLE : LOG_NONE,
+ opt_log ? LOG_TABLE : LOG_NONE);
+ }
+ else
+ {
+ logger.set_handlers(LOG_FILE,
+ opt_slow_log ? log_output_options : LOG_NONE,
+ opt_log ? log_output_options : LOG_NONE);
+ }
break;
#ifdef USE_ONE_SIGNAL_HAND
case THR_SERVER_ALARM:
@@ -2716,18 +2887,6 @@ pthread_handler_t handle_shutdown(void *arg)
kill_server(MYSQL_KILL_SIGNAL);
return 0;
}
-
-
-int STDCALL handle_kill(ulong ctrl_type)
-{
- if (ctrl_type == CTRL_CLOSE_EVENT ||
- ctrl_type == CTRL_SHUTDOWN_EVENT)
- {
- kill_server(MYSQL_KILL_SIGNAL);
- return TRUE;
- }
- return FALSE;
-}
#endif
#if !defined(EMBEDDED_LIBRARY)
@@ -4091,11 +4250,6 @@ we force server id to 2, but this MySQL server will not act as a slave.");
freopen(log_error_file,"a+",stderr);
FreeConsole(); // Remove window
}
- else
- {
- /* Don't show error dialog box when on foreground: it stops the server */
- SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
- }
#endif
/*
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index ad653a2267d..1098e8e6832 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -127,10 +127,10 @@ my_bool my_net_init(NET *net, Vio* vio)
net->error=0; net->return_errno=0; net->return_status=0;
net->pkt_nr=net->compress_pkt_nr=0;
net->write_pos=net->read_pos = net->buff;
- net->client_last_error[0]=0;
+ net->last_error[0]=0;
net->compress=0; net->reading_or_writing=0;
net->where_b = net->remain_in_buf=0;
- net->client_last_errno=0;
+ net->last_errno=0;
#ifdef USE_QUERY_CACHE
query_cache_init_query(net);
#else
@@ -177,7 +177,7 @@ my_bool net_realloc(NET *net, size_t length)
net->max_packet_size));
/* @todo: 1 and 2 codes are identical. */
net->error= 1;
- net->client_last_errno= ER_NET_PACKET_TOO_LARGE;
+ net->last_errno= ER_NET_PACKET_TOO_LARGE;
#ifdef MYSQL_SERVER
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
#endif
@@ -194,7 +194,7 @@ my_bool net_realloc(NET *net, size_t length)
{
/* @todo: 1 and 2 codes are identical. */
net->error= 1;
- net->client_last_errno= ER_OUT_OF_RESOURCES;
+ net->last_errno= ER_OUT_OF_RESOURCES;
/* In the server the error is reported by MY_WME flag. */
DBUG_RETURN(1);
}
@@ -579,7 +579,7 @@ net_real_write(NET *net,const uchar *packet, size_t len)
COMP_HEADER_SIZE, MYF(MY_WME))))
{
net->error= 2;
- net->client_last_errno= ER_OUT_OF_RESOURCES;
+ net->last_errno= ER_OUT_OF_RESOURCES;
/* In the server, the error is reported by MY_WME flag. */
net->reading_or_writing= 0;
DBUG_RETURN(1);
@@ -632,7 +632,7 @@ net_real_write(NET *net,const uchar *packet, size_t len)
my_progname,vio_errno(net->vio));
#endif /* EXTRA_DEBUG */
net->error= 2; /* Close socket */
- net->client_last_errno= ER_NET_PACKET_TOO_LARGE;
+ net->last_errno= ER_NET_PACKET_TOO_LARGE;
#ifdef MYSQL_SERVER
my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
#endif
@@ -662,10 +662,10 @@ net_real_write(NET *net,const uchar *packet, size_t len)
}
#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
net->error= 2; /* Close socket */
- net->client_last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
+ net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
ER_NET_ERROR_ON_WRITE);
#ifdef MYSQL_SERVER
- my_error(net->client_last_errno, MYF(0));
+ my_error(net->last_errno, MYF(0));
#endif /* MYSQL_SERVER */
break;
}
@@ -844,7 +844,7 @@ my_real_read(NET *net, size_t *complen)
#endif /* EXTRA_DEBUG */
len= packet_error;
net->error= 2; /* Close socket */
- net->client_last_errno= ER_NET_FCNTL_ERROR;
+ net->last_errno= ER_NET_FCNTL_ERROR;
#ifdef MYSQL_SERVER
my_error(ER_NET_FCNTL_ERROR, MYF(0));
#endif
@@ -876,11 +876,11 @@ my_real_read(NET *net, size_t *complen)
remain, vio_errno(net->vio), (long) length));
len= packet_error;
net->error= 2; /* Close socket */
- net->client_last_errno= (vio_was_interrupted(net->vio) ?
+ net->last_errno= (vio_was_interrupted(net->vio) ?
ER_NET_READ_INTERRUPTED :
ER_NET_READ_ERROR);
#ifdef MYSQL_SERVER
- my_error(net->client_last_errno, MYF(0));
+ my_error(net->last_errno, MYF(0));
#endif
goto end;
}
@@ -1100,7 +1100,7 @@ my_net_read(NET *net)
&complen))
{
net->error= 2; /* caller will close socket */
- net->client_last_errno= ER_NET_UNCOMPRESS_ERROR;
+ net->last_errno= ER_NET_UNCOMPRESS_ERROR;
#ifdef MYSQL_SERVER
my_error(ER_NET_UNCOMPRESS_ERROR, MYF(0));
#endif
diff --git a/sql/protocol.cc b/sql/protocol.cc
index 9e1b3c65538..5fe56724d08 100644
--- a/sql/protocol.cc
+++ b/sql/protocol.cc
@@ -112,8 +112,6 @@ void net_send_error(THD *thd, uint sql_errno, const char *err)
- message : Stored as packed length (1-9 bytes) + message.
Is not stored if no message.
- If net->no_send_ok return without sending packet.
-
@param thd Thread handler
@param affected_rows Number of rows changed by statement
@param id Auto_increment id for first row (if used)
@@ -128,7 +126,7 @@ net_send_ok(THD *thd,
{
NET *net= &thd->net;
uchar buff[MYSQL_ERRMSG_SIZE+10],*pos;
- DBUG_ENTER("send_ok");
+ DBUG_ENTER("my_ok");
if (! net->vio) // hack for re-parsing queries
{
@@ -425,8 +423,8 @@ void net_end_statement(THD *thd)
/****************************************************************************
- Functions used by the protocol functions (like send_ok) to store strings
- and numbers in the header result packet.
+ Functions used by the protocol functions (like net_send_ok) to store
+ strings and numbers in the header result packet.
****************************************************************************/
/* The following will only be used for short strings < 65K */
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index b4f7ce36ee5..10f32aa5827 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -478,7 +478,7 @@ bool show_new_master(THD* thd)
protocol->store((ulonglong) lex_mi->pos);
if (protocol->write())
DBUG_RETURN(TRUE);
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
}
@@ -691,7 +691,7 @@ bool show_slave_hosts(THD* thd)
}
}
pthread_mutex_unlock(&LOCK_slave_list);
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -702,7 +702,7 @@ int connect_to_master(THD *thd, MYSQL* mysql, Master_info* mi)
if (!mi->host || !*mi->host) /* empty host */
{
- strmov(mysql->net.client_last_error, "Master is not configured");
+ strmov(mysql->net.last_error, "Master is not configured");
DBUG_RETURN(1);
}
mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (char *) &slave_net_timeout);
@@ -1014,7 +1014,7 @@ err:
mysql_close(&mysql); // safe to call since we always do mysql_init()
if (!error)
- send_ok(thd);
+ my_ok(thd);
return error;
}
diff --git a/sql/rpl_injector.cc b/sql/rpl_injector.cc
index aa3020c42be..684655d1c3b 100644
--- a/sql/rpl_injector.cc
+++ b/sql/rpl_injector.cc
@@ -62,6 +62,26 @@ int injector::transaction::commit()
{
DBUG_ENTER("injector::transaction::commit()");
m_thd->binlog_flush_pending_rows_event(true);
+ /*
+ Cluster replication does not preserve statement or
+ transaction boundaries of the master. Instead, a new
+ transaction on replication slave is started when a new GCI
+ (global checkpoint identifier) is issued, and is committed
+ when the last event of the check point has been received and
+ processed. This ensures consistency of each cluster in
+ cluster replication, and there is no requirement for stronger
+ consistency: MySQL replication is asynchronous with other
+ engines as well.
+
+ A practical consequence of that is that row level replication
+ stream passed through the injector thread never contains
+ COMMIT events.
+ Here we should preserve the server invariant that there is no
+ outstanding statement transaction when the normal transaction
+ is committed by committing the statement transaction
+ explicitly.
+ */
+ ha_autocommit_or_rollback(m_thd, 0);
end_trans(m_thd, COMMIT);
DBUG_RETURN(0);
}
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 4c77cbfff82..8b38ffede41 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1219,7 +1219,7 @@ static void throw_bounds_warning(THD *thd, const char *name, ulonglong num)
static ulonglong fix_unsigned(THD *thd, ulonglong num,
const struct my_option *option_limits)
{
- bool fixed= FALSE;
+ my_bool fixed= FALSE;
ulonglong out= getopt_ull_limit_value(num, option_limits, &fixed);
if (fixed)
@@ -1279,7 +1279,7 @@ bool sys_var_long_ptr_global::update(THD *thd, set_var *var)
void sys_var_long_ptr_global::set_default(THD *thd, enum_var_type type)
{
- bool not_used;
+ my_bool not_used;
pthread_mutex_lock(guard);
*value= (ulong) getopt_ull_limit_value((ulong) option_limits->def_value,
option_limits, &not_used);
@@ -1302,7 +1302,7 @@ bool sys_var_ulonglong_ptr::update(THD *thd, set_var *var)
void sys_var_ulonglong_ptr::set_default(THD *thd, enum_var_type type)
{
- bool not_used;
+ my_bool not_used;
pthread_mutex_lock(&LOCK_global_system_variables);
*value= getopt_ull_limit_value((ulonglong) option_limits->def_value,
option_limits, &not_used);
@@ -1382,7 +1382,7 @@ void sys_var_thd_ulong::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
{
- bool not_used;
+ my_bool not_used;
/* We will not come here if option_limits is not set */
global_system_variables.*offset=
(ulong) getopt_ull_limit_value((ulong) option_limits->def_value,
@@ -1429,7 +1429,7 @@ void sys_var_thd_ha_rows::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
{
- bool not_used;
+ my_bool not_used;
/* We will not come here if option_limits is not set */
pthread_mutex_lock(&LOCK_global_system_variables);
global_system_variables.*offset=
@@ -1481,7 +1481,7 @@ void sys_var_thd_ulonglong::set_default(THD *thd, enum_var_type type)
{
if (type == OPT_GLOBAL)
{
- bool not_used;
+ my_bool not_used;
pthread_mutex_lock(&LOCK_global_system_variables);
global_system_variables.*offset=
getopt_ull_limit_value((ulonglong) option_limits->def_value,
@@ -3926,10 +3926,8 @@ bool sys_var_thd_dbug::update(THD *thd, set_var *var)
if (var->type == OPT_GLOBAL)
DBUG_SET_INITIAL(var ? var->value->str_value.c_ptr() : "");
else
- {
- DBUG_POP();
- DBUG_PUSH(var ? var->value->str_value.c_ptr() : "");
- }
+ DBUG_SET(var ? var->value->str_value.c_ptr() : "");
+
return 0;
}
diff --git a/sql/slave.cc b/sql/slave.cc
index b8d1fdfbb6b..051912717dd 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -1451,7 +1451,7 @@ bool show_master_info(THD* thd, Master_info* mi)
if (my_net_write(&thd->net, (uchar*) thd->packet.ptr(), packet->length()))
DBUG_RETURN(TRUE);
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sp.cc b/sql/sp.cc
index 83995e9b753..b486e58883a 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -697,8 +697,16 @@ sp_returns_type(THD *thd, String &result, sp_head *sp)
(TYPE_ENUM_PROCEDURE or TYPE_ENUM_FUNCTION).
@param sp Stored routine object to store.
- @return Error code. SP_OK is returned on success. Other SP_ constants are
- used to indicate about errors.
+ @note Opens and closes the thread tables. Therefore assumes
+ that there are no locked tables in this thread at the time of
+ invocation.
+ Unlike some other DDL statements, *does* close the tables
+ in the end, since the call to this function is normally
+ followed by an implicit grant (sp_grant_privileges())
+ and this subsequent call opens and closes mysql.procs_priv.
+
+ @return Error code. SP_OK is returned on success. Other
+ SP_ constants are used to indicate about errors.
*/
int
@@ -1251,7 +1259,7 @@ sp_show_status_routine(THD *thd, int type, const char *name_pattern)
}
err_case1:
- send_eof(thd);
+ my_eof(thd);
err_case:
table->file->ha_index_end();
close_thread_tables(thd);
@@ -1260,7 +1268,13 @@ done:
}
-/* Drop all routines in database 'db' */
+/**
+ Drop all routines in database 'db'
+
+ @note Close the thread tables, the calling code might want to
+ delete from other system tables afterwards.
+*/
+
int
sp_drop_db_routines(THD *thd, char *db)
{
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 8e6f5a96640..8bd10e00f15 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -2419,7 +2419,7 @@ sp_head::show_create_routine(THD *thd, int type)
err_status= protocol->write();
if (!err_status)
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(err_status);
}
@@ -2611,7 +2611,7 @@ sp_head::show_routine_code(THD *thd)
}
if (!res)
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(res);
}
@@ -2700,6 +2700,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
m_lex->unit.cleanup();
thd_proc_info(thd, "closing tables");
+ /* Here we also commit or rollback the current statement. */
close_thread_tables(thd);
thd_proc_info(thd, 0);
@@ -2932,7 +2933,7 @@ sp_instr_set::print(String *str)
}
str->qs_append(m_offset);
str->qs_append(' ');
- m_value->print(str);
+ m_value->print(str, QT_ORDINARY);
}
@@ -2960,9 +2961,9 @@ void
sp_instr_set_trigger_field::print(String *str)
{
str->append(STRING_WITH_LEN("set_trigger_field "));
- trigger_field->print(str);
+ trigger_field->print(str, QT_ORDINARY);
str->append(STRING_WITH_LEN(":="));
- value->print(str);
+ value->print(str, QT_ORDINARY);
}
/*
@@ -3088,7 +3089,7 @@ sp_instr_jump_if_not::print(String *str)
str->qs_append('(');
str->qs_append(m_cont_dest);
str->qs_append(STRING_WITH_LEN(") "));
- m_expr->print(str);
+ m_expr->print(str, QT_ORDINARY);
}
@@ -3176,7 +3177,7 @@ sp_instr_freturn::print(String *str)
str->qs_append(STRING_WITH_LEN("freturn "));
str->qs_append((uint)m_type);
str->qs_append(' ');
- m_value->print(str);
+ m_value->print(str, QT_ORDINARY);
}
/*
@@ -3664,7 +3665,7 @@ sp_instr_set_case_expr::print(String *str)
str->qs_append(STRING_WITH_LEN(") "));
str->qs_append(m_case_expr_id);
str->qs_append(' ');
- m_case_expr->print(str);
+ m_case_expr->print(str, QT_ORDINARY);
}
uint
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index b04f624f746..3805d9fa8b6 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3176,7 +3176,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
rw_unlock(&LOCK_grant);
if (!result) /* success */
- send_ok(thd);
+ my_ok(thd);
/* Tables are automatically closed */
thd->lex->restore_backup_query_tables_list(&backup);
@@ -3344,7 +3344,7 @@ bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
rw_unlock(&LOCK_grant);
if (!result && !no_error)
- send_ok(thd);
+ my_ok(thd);
/* Tables are automatically closed */
DBUG_RETURN(result);
@@ -3460,7 +3460,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
close_thread_tables(thd);
if (!result)
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(result);
}
@@ -4815,7 +4815,7 @@ end:
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(error);
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e5a5b51fcf6..4a417dc05b1 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1324,29 +1324,45 @@ void close_thread_tables(THD *thd)
Mark all temporary tables used by this statement as free for reuse.
*/
mark_temp_tables_as_free_for_reuse(thd);
-
- if (thd->locked_tables || prelocked_mode)
+ /*
+ Let us commit transaction for statement. Since in 5.0 we only have
+ one statement transaction and don't allow several nested statement
+ transactions this call will do nothing if we are inside of stored
+ function or trigger (i.e. statement transaction is already active and
+ does not belong to statement for which we do close_thread_tables()).
+ TODO: This should be fixed in later releases.
+ */
+ if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
{
+ thd->main_da.can_overwrite_status= TRUE;
+ ha_autocommit_or_rollback(thd, thd->is_error());
+ thd->main_da.can_overwrite_status= FALSE;
+
/*
- Let us commit transaction for statement. Since in 5.0 we only have
- one statement transaction and don't allow several nested statement
- transactions this call will do nothing if we are inside of stored
- function or trigger (i.e. statement transaction is already active and
- does not belong to statement for which we do close_thread_tables()).
- TODO: This should be fixed in later releases.
+ Reset transaction state, but only if we're not inside a
+ sub-statement of a prelocked statement.
*/
- ha_commit_stmt(thd);
+ if (! prelocked_mode || thd->lex->requires_prelocking())
+ thd->transaction.stmt.reset();
+ }
+
+ if (thd->locked_tables || prelocked_mode)
+ {
/* Ensure we are calling ha_reset() for all used tables */
mark_used_tables_as_free_for_reuse(thd, thd->open_tables);
- /* We are under simple LOCK TABLES so should not do anything else. */
+ /*
+ We are under simple LOCK TABLES or we're inside a sub-statement
+ of a prelocked statement, so should not do anything else.
+ */
if (!prelocked_mode || !thd->lex->requires_prelocking())
DBUG_VOID_RETURN;
/*
- We are in prelocked mode, so we have to leave it now with doing
- implicit UNLOCK TABLES if need.
+ We are in the top-level statement of a prelocked statement,
+ so we have to leave the prelocked mode now with doing implicit
+ UNLOCK TABLES if needed.
*/
DBUG_PRINT("info",("thd->prelocked_mode= NON_PRELOCKED"));
thd->prelocked_mode= NON_PRELOCKED;
@@ -1375,19 +1391,6 @@ void close_thread_tables(THD *thd)
thd->lock=0;
}
/*
- 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_parse.cc - dispatch_command()
- */
- if (!(thd->state_flags & Open_tables_state::BACKUPS_AVAIL))
- bzero(&thd->transaction.stmt, sizeof(thd->transaction.stmt));
- if (!thd->active_transaction())
- thd->transaction.xid_state.xid.null();
-
- /*
Note that we need to hold LOCK_open while changing the
open_tables list. Another thread may work on it.
(See: remove_table_from_cache(), mysql_wait_completed_table())
@@ -5059,10 +5062,7 @@ int decide_logging_format(THD *thd, TABLE_LIST *tables)
DBUG_PRINT("info", ("error: %d", error));
if (error)
- {
- ha_rollback_stmt(thd);
return -1;
- }
/*
We switch to row-based format if we are in mixed mode and one of
@@ -5216,7 +5216,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
table->table->query_id= thd->query_id;
if (check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
- ha_rollback_stmt(thd);
mysql_unlock_tables(thd, thd->locked_tables);
thd->locked_tables= 0;
thd->options&= ~(OPTION_TABLE_LOCK);
@@ -5251,7 +5250,6 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
if (!table->placeholder() &&
check_lock_and_start_stmt(thd, table->table, table->lock_type))
{
- ha_rollback_stmt(thd);
DBUG_RETURN(-1);
}
}
diff --git a/sql/sql_binlog.cc b/sql/sql_binlog.cc
index 462806ab10d..a6d0c8c9e9b 100644
--- a/sql/sql_binlog.cc
+++ b/sql/sql_binlog.cc
@@ -231,7 +231,7 @@ void mysql_client_binlog_statement(THD* thd)
DBUG_PRINT("info",("binlog base64 execution finished successfully"));
- send_ok(thd);
+ my_ok(thd);
end:
thd->rli_fake->clear_tables_to_lock();
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 044ea70e994..376102c8bf9 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -264,7 +264,7 @@ const char *set_thd_proc_info(THD *thd, const char *info,
extern "C"
void **thd_ha_data(const THD *thd, const struct handlerton *hton)
{
- return (void **) thd->ha_data + hton->slot;
+ return (void **) &thd->ha_data[hton->slot].ha_ptr;
}
extern "C"
@@ -682,6 +682,7 @@ void *thd_memdup(MYSQL_THD thd, const void* str, unsigned int size)
return thd->memdup(str, size);
}
+extern "C"
void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
{
*xid = *(MYSQL_XID *) &thd->transaction.xid_state.xid;
@@ -769,6 +770,10 @@ void THD::init_for_queries()
void THD::change_user(void)
{
+ pthread_mutex_lock(&LOCK_status);
+ add_to_status(&global_status_var, &status_var);
+ pthread_mutex_unlock(&LOCK_status);
+
cleanup();
killed= NOT_KILLED;
cleanup_done= 0;
@@ -1544,7 +1549,7 @@ bool select_send::send_eof()
mysql_unlock_tables(thd, thd->lock);
thd->lock=0;
}
- ::send_eof(thd);
+ ::my_eof(thd);
is_result_set_started= 0;
return FALSE;
}
@@ -1579,7 +1584,7 @@ bool select_to_file::send_eof()
function, SELECT INTO has to have an own SQLCOM.
TODO: split from SQLCOM_SELECT
*/
- ::send_ok(thd,row_count);
+ ::my_ok(thd,row_count);
}
file= -1;
return error;
@@ -2516,7 +2521,7 @@ bool select_dumpvar::send_data(List<Item> &items)
suv->update();
}
}
- DBUG_RETURN(0);
+ DBUG_RETURN(thd->is_error());
}
bool select_dumpvar::send_eof()
@@ -2529,7 +2534,7 @@ bool select_dumpvar::send_eof()
function, SELECT INTO has to have an own SQLCOM.
TODO: split from SQLCOM_SELECT
*/
- ::send_ok(thd,row_count);
+ ::my_ok(thd,row_count);
return 0;
}
@@ -2763,6 +2768,17 @@ extern "C" int thd_killed(const MYSQL_THD thd)
return(thd->killed);
}
+/**
+ Return the thread id of a user thread
+ @param thd user thread
+ @return thread id
+*/
+extern "C" unsigned long thd_get_thread_id(const MYSQL_THD thd)
+{
+ return((unsigned long)thd->thread_id);
+}
+
+
#ifdef INNODB_COMPATIBILITY_HOOKS
extern "C" struct charset_info_st *thd_charset(MYSQL_THD thd)
{
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 5f2b50f48b8..78d25cb1894 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -689,7 +689,8 @@ private:
struct st_savepoint {
struct st_savepoint *prev;
char *name;
- uint length, nht;
+ uint length;
+ Ha_trx_info *ha_list;
};
enum xa_states {XA_NOTR=0, XA_ACTIVE, XA_IDLE, XA_PREPARED};
@@ -992,9 +993,9 @@ public:
{
/** The area is cleared at start of a statement. */
DA_EMPTY= 0,
- /** Set whenever one calls send_ok(). */
+ /** Set whenever one calls my_ok(). */
DA_OK,
- /** Set whenever one calls send_eof(). */
+ /** Set whenever one calls my_eof(). */
DA_EOF,
/** Set whenever one calls my_error() or my_message(). */
DA_ERROR,
@@ -1062,7 +1063,7 @@ private:
Copied from thd->server_status when the diagnostics area is assigned.
We need this member as some places in the code use the following pattern:
thd->server_status|= ...
- send_eof(thd);
+ my_eof(thd);
thd->server_status&= ~...
Assigned by OK, EOF or ERROR.
*/
@@ -1096,6 +1097,33 @@ private:
/**
+ Storage engine specific thread local data.
+*/
+
+struct Ha_data
+{
+ /**
+ Storage engine specific thread local data.
+ Lifetime: one user connection.
+ */
+ void *ha_ptr;
+ /**
+ 0: Life time: one statement within a transaction. If @@autocommit is
+ on, also represents the entire transaction.
+ @sa trans_register_ha()
+
+ 1: Life time: one transaction within a connection.
+ If the storage engine does not participate in a transaction,
+ this should not be used.
+ @sa trans_register_ha()
+ */
+ Ha_trx_info ha_info[2];
+
+ Ha_data() :ha_ptr(NULL) {}
+};
+
+
+/**
@class THD
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
@@ -1234,7 +1262,7 @@ public:
uint in_sub_stmt;
/* container for handler's private per-connection data */
- void *ha_data[MAX_HA];
+ Ha_data ha_data[MAX_HA];
#ifndef MYSQL_CLIENT
int binlog_setup_trx_data();
@@ -2113,7 +2141,7 @@ private:
/** A short cut for thd->main_da.set_ok_status(). */
inline void
-send_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0,
+my_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0,
const char *message= NULL)
{
thd->main_da.set_ok_status(thd, affected_rows, id, message);
@@ -2123,7 +2151,7 @@ send_ok(THD *thd, ha_rows affected_rows= 0, ulonglong id= 0,
/** A short cut for thd->main_da.set_eof_status(). */
inline void
-send_eof(THD *thd)
+my_eof(THD *thd)
{
thd->main_da.set_eof_status(thd);
}
@@ -2578,7 +2606,7 @@ class user_var_entry
bool unsigned_flag;
double val_real(my_bool *null_value);
- longlong val_int(my_bool *null_value);
+ longlong val_int(my_bool *null_value) const;
String *val_str(my_bool *null_value, String *str, uint decimals);
my_decimal *val_decimal(my_bool *null_value, my_decimal *result);
DTCollation collation;
diff --git a/sql/sql_connect.cc b/sql/sql_connect.cc
index 309a1c7ab5d..b22a33e3e92 100644
--- a/sql/sql_connect.cc
+++ b/sql/sql_connect.cc
@@ -39,22 +39,7 @@
#endif /* HAVE_OPENSSL */
#ifdef __WIN__
-static void test_signal(int sig_ptr)
-{
-#if !defined( DBUG_OFF)
- MessageBox(NULL,"Test signal","DBUG",MB_OK);
-#endif
-#if defined(OS2)
- fprintf(stderr, "Test signal %d\n", sig_ptr);
- fflush(stderr);
-#endif
-}
-static void init_signals(void)
-{
- int signals[7] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGBREAK,SIGABRT } ;
- for (int i=0 ; i < 7 ; i++)
- signal( signals[i], test_signal) ;
-}
+extern void win_install_sigabrt_handler();
#endif
/*
@@ -334,7 +319,7 @@ check_user(THD *thd, enum enum_server_command command,
if (mysql_change_db(thd, &db_str, FALSE))
DBUG_RETURN(1);
}
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(0);
#else
@@ -483,7 +468,7 @@ check_user(THD *thd, enum enum_server_command command,
DBUG_RETURN(1);
}
}
- send_ok(thd);
+ my_ok(thd);
thd->password= test(passwd_len); // remember for error messages
/* Ready to handle queries */
DBUG_RETURN(0);
@@ -626,7 +611,7 @@ bool init_new_connection_handler_thread()
{
pthread_detach_this_thread();
#if defined(__WIN__)
- init_signals();
+ win_install_sigabrt_handler();
#else
/* Win32 calls this in pthread_create */
if (my_thread_init())
diff --git a/sql/sql_cursor.cc b/sql/sql_cursor.cc
index 2301b561797..5c4e93d4c74 100644
--- a/sql/sql_cursor.cc
+++ b/sql/sql_cursor.cc
@@ -88,6 +88,7 @@ class Materialized_cursor: public Server_side_cursor
public:
Materialized_cursor(select_result *result, TABLE *table);
+ int fill_item_list(THD *thd, List<Item> &send_fields);
virtual bool is_open() const { return table != 0; }
virtual int open(JOIN *join __attribute__((unused)));
virtual void fetch(ulong num_rows);
@@ -109,6 +110,7 @@ class Select_materialize: public select_union
{
select_result *result; /**< the result object of the caller (PS or SP) */
public:
+ Materialized_cursor *materialized_cursor;
Select_materialize(select_result *result_arg) :result(result_arg) {}
virtual bool send_fields(List<Item> &list, uint flags);
};
@@ -151,7 +153,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
if (! (sensitive_cursor= new (thd->mem_root) Sensitive_cursor(thd, result)))
{
- delete result;
+ delete result_materialize;
return 1;
}
@@ -173,13 +175,13 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
/*
Possible options here:
- a sensitive cursor is open. In this case rc is 0 and
- result_materialize->table is NULL, or
+ result_materialize->materialized_cursor is NULL, or
- a materialized cursor is open. In this case rc is 0 and
- result_materialize->table is not NULL
- - an error occured during materializaton.
- result_materialize->table is not NULL, but rc != 0
+ result_materialize->materialized is not NULL
+ - an error occurred during materialization.
+ result_materialize->materialized_cursor is not NULL, but rc != 0
- successful completion of mysql_execute_command without
- a cursor: rc is 0, result_materialize->table is NULL,
+ a cursor: rc is 0, result_materialize->materialized_cursor is NULL,
sensitive_cursor is not open.
This is possible if some command writes directly to the
network, bypassing select_result mechanism. An example of
@@ -190,7 +192,7 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
if (sensitive_cursor->is_open())
{
- DBUG_ASSERT(!result_materialize->table);
+ DBUG_ASSERT(!result_materialize->materialized_cursor);
/*
It's safer if we grab THD state after mysql_execute_command
is finished and not in Sensitive_cursor::open(), because
@@ -201,18 +203,10 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
*pcursor= sensitive_cursor;
goto end;
}
- else if (result_materialize->table)
+ else if (result_materialize->materialized_cursor)
{
- Materialized_cursor *materialized_cursor;
- TABLE *table= result_materialize->table;
- MEM_ROOT *mem_root= &table->mem_root;
-
- if (!(materialized_cursor= new (mem_root)
- Materialized_cursor(result, table)))
- {
- rc= 1;
- goto err_open;
- }
+ Materialized_cursor *materialized_cursor=
+ result_materialize->materialized_cursor;
if ((rc= materialized_cursor->open(0)))
{
@@ -228,8 +222,6 @@ int mysql_open_cursor(THD *thd, uint flags, select_result *result,
err_open:
DBUG_ASSERT(! (sensitive_cursor && sensitive_cursor->is_open()));
delete sensitive_cursor;
- if (result_materialize->table)
- free_tmp_table(thd, result_materialize->table);
end:
delete result_materialize;
return rc;
@@ -322,9 +314,10 @@ Sensitive_cursor::post_open(THD *thd)
close_at_commit= FALSE; /* reset in case we're reusing the cursor */
info= &ht_info[0];
- for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++)
+ for (Ha_trx_info *ha_trx_info= thd->transaction.stmt.ha_list;
+ ha_trx_info; ha_trx_info= ha_trx_info->next())
{
- handlerton *ht= *pht;
+ handlerton *ht= ha_trx_info->ht();
close_at_commit|= test(ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
if (ht->create_cursor_read_view)
{
@@ -553,6 +546,51 @@ Materialized_cursor::Materialized_cursor(select_result *result_arg,
}
+/**
+ Preserve the original metadata that would be sent to the client.
+
+ @param thd Thread identifier.
+ @param send_fields List of fields that would be sent.
+*/
+
+int Materialized_cursor::fill_item_list(THD *thd, List<Item> &send_fields)
+{
+ Query_arena backup_arena;
+ int rc;
+ List_iterator_fast<Item> it_org(send_fields);
+ List_iterator_fast<Item> it_dst(item_list);
+ Item *item_org;
+ Item *item_dst;
+
+ thd->set_n_backup_active_arena(this, &backup_arena);
+
+ if ((rc= table->fill_item_list(&item_list)))
+ goto end;
+
+ DBUG_ASSERT(send_fields.elements == item_list.elements);
+
+ /*
+ Unless we preserve the original metadata, it will be lost,
+ since new fields describe columns of the temporary table.
+ Allocate a copy of the name for safety only. Currently
+ items with original names are always kept in memory,
+ but in case this changes a memory leak may be hard to notice.
+ */
+ while ((item_dst= it_dst++, item_org= it_org++))
+ {
+ Send_field send_field;
+ Item_ident *ident= static_cast<Item_ident *>(item_dst);
+ item_org->make_field(&send_field);
+
+ ident->db_name= thd->strdup(send_field.db_name);
+ ident->table_name= thd->strdup(send_field.table_name);
+ }
+end:
+ thd->restore_active_arena(this, &backup_arena);
+ /* Check for thd->is_error() in case of OOM */
+ return rc || thd->is_error();
+}
+
int Materialized_cursor::open(JOIN *join __attribute__((unused)))
{
THD *thd= fake_unit.thd;
@@ -561,8 +599,7 @@ int Materialized_cursor::open(JOIN *join __attribute__((unused)))
thd->set_n_backup_active_arena(this, &backup_arena);
/* Create a list of fields and start sequential scan */
- rc= (table->fill_item_list(&item_list) ||
- result->prepare(item_list, &fake_unit) ||
+ rc= (result->prepare(item_list, &fake_unit) ||
table->file->ha_rnd_init(TRUE));
thd->restore_active_arena(this, &backup_arena);
if (rc == 0)
@@ -668,6 +705,24 @@ bool Select_materialize::send_fields(List<Item> &list, uint flags)
if (create_result_table(unit->thd, unit->get_unit_column_types(),
FALSE, thd->options | TMP_TABLE_ALL_COLUMNS, ""))
return TRUE;
+
+ materialized_cursor= new (&table->mem_root)
+ Materialized_cursor(result, table);
+
+ if (! materialized_cursor)
+ {
+ free_tmp_table(table->in_use, table);
+ table= 0;
+ return TRUE;
+ }
+ if (materialized_cursor->fill_item_list(unit->thd, list))
+ {
+ delete materialized_cursor;
+ table= 0;
+ materialized_cursor= 0;
+ return TRUE;
+ }
+
return FALSE;
}
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index b5f49b97ec9..d03ac7921ac 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -595,7 +595,7 @@ CHARSET_INFO *get_default_db_collation(THD *thd, const char *db_name)
In this case the entry should not be logged.
SIDE-EFFECTS
- 1. Report back to client that command succeeded (send_ok)
+ 1. Report back to client that command succeeded (my_ok)
2. Report errors to client
3. Log event to binary log
(The 'silent' flags turns off 1 and 3.)
@@ -660,7 +660,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_DB_CREATE_EXISTS, ER(ER_DB_CREATE_EXISTS), db);
if (!silent)
- send_ok(thd);
+ my_ok(thd);
error= 0;
goto exit;
}
@@ -749,7 +749,7 @@ bool mysql_create_db(THD *thd, char *db, HA_CREATE_INFO *create_info,
/* These DDL methods and logging protected with LOCK_mysql_create_db */
mysql_bin_log.write(&qinfo);
}
- send_ok(thd, result);
+ my_ok(thd, result);
}
exit:
@@ -826,7 +826,7 @@ bool mysql_alter_db(THD *thd, const char *db, HA_CREATE_INFO *create_info)
/* These DDL methods and logging protected with LOCK_mysql_create_db */
mysql_bin_log.write(&qinfo);
}
- send_ok(thd, result);
+ my_ok(thd, result);
exit:
VOID(pthread_mutex_unlock(&LOCK_mysql_create_db));
@@ -960,7 +960,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
}
thd->clear_error();
thd->server_status|= SERVER_STATUS_DB_DROPPED;
- send_ok(thd, (ulong) deleted);
+ my_ok(thd, (ulong) deleted);
thd->server_status&= ~SERVER_STATUS_DB_DROPPED;
}
else if (mysql_bin_log.is_open())
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index c6435387f44..990f7713561 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -24,6 +24,14 @@
#include "sp_head.h"
#include "sql_trigger.h"
+/**
+ Implement DELETE SQL word.
+
+ @note Like implementations of other DDL/DML in MySQL, this function
+ relies on the caller to close the thread tables. This is done in the
+ end of dispatch_command().
+*/
+
bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
SQL_LIST *order, ha_rows limit, ulonglong options,
bool reset_auto_increment)
@@ -150,7 +158,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
{
free_underlaid_joins(thd, select_lex);
thd->row_count_func= 0;
- send_ok(thd, (ha_rows) thd->row_count_func); // No matching records
+ my_ok(thd, (ha_rows) thd->row_count_func); // No matching records
DBUG_RETURN(0);
}
#endif
@@ -167,7 +175,7 @@ bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds,
delete select;
free_underlaid_joins(thd, select_lex);
thd->row_count_func= 0;
- send_ok(thd, (ha_rows) thd->row_count_func);
+ my_ok(thd, (ha_rows) thd->row_count_func);
/*
We don't need to call reset_auto_increment in this case, because
mysql_truncate always gives a NULL conds argument, hence we never
@@ -380,21 +388,10 @@ cleanup:
}
DBUG_ASSERT(transactional_table || !deleted || thd->transaction.stmt.modified_non_trans_table);
free_underlaid_joins(thd, select_lex);
- if (transactional_table)
- {
- if (ha_autocommit_or_rollback(thd,error >= 0))
- error=1;
- }
-
- if (thd->lock)
- {
- mysql_unlock_tables(thd, thd->lock);
- thd->lock=0;
- }
if (error < 0 || (thd->lex->ignore && !thd->is_fatal_error))
{
thd->row_count_func= deleted;
- send_ok(thd, (ha_rows) thd->row_count_func);
+ my_ok(thd, (ha_rows) thd->row_count_func);
DBUG_PRINT("info",("%ld records deleted",(long) deleted));
}
DBUG_RETURN(error >= 0 || thd->is_error());
@@ -751,11 +748,9 @@ void multi_delete::abort()
The same if all tables are transactional, regardless of where we are.
In all other cases do attempt deletes ...
*/
- if ((table_being_deleted == delete_tables &&
- table_being_deleted->table->file->has_transactions()) ||
- !normal_tables)
- ha_rollback_stmt(thd);
- else if (do_delete)
+ if (do_delete && normal_tables &&
+ (table_being_deleted != delete_tables ||
+ !table_being_deleted->table->file->has_transactions()))
{
/*
We have to execute the recorded do_deletes() and write info into the
@@ -921,15 +916,10 @@ bool multi_delete::send_eof()
if (local_error != 0)
error_handled= TRUE; // to force early leave from ::send_error()
- /* Commit or rollback the current SQL statement */
- if (transactional_tables)
- if (ha_autocommit_or_rollback(thd,local_error > 0))
- local_error=1;
-
if (!local_error)
{
thd->row_count_func= deleted;
- ::send_ok(thd, (ha_rows) thd->row_count_func);
+ ::my_ok(thd, (ha_rows) thd->row_count_func);
}
return 0;
}
@@ -983,7 +973,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok)
my_free((char*) table,MYF(0));
/*
If we return here we will not have logged the truncation to the bin log
- and we will not send_ok() to the client.
+ and we will not my_ok() to the client.
*/
goto end;
}
@@ -1029,7 +1019,7 @@ end:
we don't test current_stmt_binlog_row_based.
*/
write_bin_log(thd, TRUE, thd->query, thd->query_length);
- send_ok(thd); // This should return record count
+ my_ok(thd); // This should return record count
}
VOID(pthread_mutex_lock(&LOCK_open));
unlock_table_name(thd, table_list);
@@ -1055,6 +1045,12 @@ trunc_by_del:
error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0,
HA_POS_ERROR, LL(0), TRUE);
ha_enable_transaction(thd, TRUE);
+ /*
+ Safety, in case the engine ignored ha_enable_transaction(FALSE)
+ above. Also clears thd->transaction.*.
+ */
+ error= ha_autocommit_or_rollback(thd, error);
+ ha_commit(thd);
thd->options= save_options;
thd->current_stmt_binlog_row_based= save_binlog_row_based;
DBUG_RETURN(error);
diff --git a/sql/sql_do.cc b/sql/sql_do.cc
index a3eb93f87da..8406a9eaf45 100644
--- a/sql/sql_do.cc
+++ b/sql/sql_do.cc
@@ -28,7 +28,17 @@ bool mysql_do(THD *thd, List<Item> &values)
while ((value = li++))
value->val_int();
free_underlaid_joins(thd, &thd->lex->select_lex);
- thd->clear_error(); // DO always is OK
- send_ok(thd);
+
+ if (thd->is_error())
+ {
+ /*
+ Rollback the effect of the statement, since next instruction
+ will clear the error and the rollback in the end of
+ dispatch_command() won't work.
+ */
+ ha_autocommit_or_rollback(thd, thd->is_error());
+ thd->clear_error(); // DO always is OK
+ }
+ my_ok(thd);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_error.cc b/sql/sql_error.cc
index 89cff73d153..0b74e3455eb 100644
--- a/sql/sql_error.cc
+++ b/sql/sql_error.cc
@@ -249,6 +249,6 @@ bool mysqld_show_warnings(THD *thd, ulong levels_to_show)
if (protocol->write())
DBUG_RETURN(TRUE);
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index a4ba6f1140b..28a9fb5c78e 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -298,7 +298,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
tables->table->open_by_handler= 1;
if (! reopen)
- send_ok(thd);
+ my_ok(thd);
DBUG_PRINT("exit",("OK"));
DBUG_RETURN(FALSE);
@@ -350,7 +350,7 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
DBUG_RETURN(TRUE);
}
- send_ok(thd);
+ my_ok(thd);
DBUG_PRINT("exit", ("OK"));
DBUG_RETURN(FALSE);
}
@@ -658,7 +658,7 @@ retry:
}
ok:
mysql_unlock_tables(thd,lock);
- send_eof(thd);
+ my_eof(thd);
DBUG_PRINT("exit",("OK"));
DBUG_RETURN(FALSE);
diff --git a/sql/sql_help.cc b/sql/sql_help.cc
index 0d633ce86ac..e424425272e 100644
--- a/sql/sql_help.cc
+++ b/sql/sql_help.cc
@@ -779,7 +779,7 @@ bool mysqld_help(THD *thd, const char *mask)
if (send_variant_2_list(mem_root,protocol, &categories_list, "Y", 0))
goto error;
}
- send_eof(thd);
+ my_eof(thd);
close_system_tables(thd, &open_tables_state_backup);
DBUG_RETURN(FALSE);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index c2b1990f6c7..2be932a6040 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -541,6 +541,10 @@ bool open_and_lock_for_insert_delayed(THD *thd, TABLE_LIST *table_list)
/**
INSERT statement implementation
+
+ @note Like implementations of other DDL/DML in MySQL, this function
+ relies on the caller to close the thread tables. This is done in the
+ end of dispatch_command().
*/
bool mysql_insert(THD *thd,TABLE_LIST *table_list,
@@ -893,12 +897,9 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
}
DBUG_ASSERT(transactional_table || !changed ||
thd->transaction.stmt.modified_non_trans_table);
- if (transactional_table)
- error=ha_autocommit_or_rollback(thd,error);
-
+
if (thd->lock)
{
- mysql_unlock_tables(thd, thd->lock);
/*
Invalidate the table in the query cache if something changed
after unlocking when changes become fisible.
@@ -909,7 +910,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
{
query_cache_invalidate3(thd, table_list, 1);
}
- thd->lock=0;
}
}
thd_proc_info(thd, "end");
@@ -946,7 +946,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->row_count_func= info.copied + info.deleted +
((thd->client_capabilities & CLIENT_FOUND_ROWS) ?
info.touched : info.updated);
- send_ok(thd, (ulong) thd->row_count_func, id);
+ my_ok(thd, (ulong) thd->row_count_func, id);
}
else
{
@@ -961,7 +961,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
sprintf(buff, ER(ER_INSERT_INFO), (ulong) info.records,
(ulong) (info.deleted + updated), (ulong) thd->cuted_fields);
thd->row_count_func= info.copied + info.deleted + updated;
- ::send_ok(thd, (ulong) thd->row_count_func, id, buff);
+ ::my_ok(thd, (ulong) thd->row_count_func, id, buff);
}
thd->abort_on_warning= 0;
DBUG_RETURN(FALSE);
@@ -2445,7 +2445,7 @@ err:
first call to ha_*_row() instead. Remove code that are used to
cover for the case outlined above.
*/
- ha_rollback_stmt(thd);
+ ha_autocommit_or_rollback(thd, 1);
#ifndef __WIN__
end:
@@ -3139,18 +3139,6 @@ bool select_insert::send_eof()
thd->query, thd->query_length,
trans_table, FALSE, killed_status);
}
- /*
- We will call ha_autocommit_or_rollback() also for
- non-transactional tables under row-based replication: there might
- be events in the binary logs transaction, and we need to write
- them to the binary log.
- */
- if (trans_table || thd->current_stmt_binlog_row_based)
- {
- int error2= ha_autocommit_or_rollback(thd, error);
- if (error2 && !error)
- error= error2;
- }
table->file->ha_release_auto_increment();
if (error)
@@ -3174,7 +3162,7 @@ bool select_insert::send_eof()
(thd->arg_of_last_insert_id_function ?
thd->first_successful_insert_id_in_prev_stmt :
(info.copied ? autoinc_value_of_last_inserted_row : 0));
- ::send_ok(thd, (ulong) thd->row_count_func, id, buff);
+ ::my_ok(thd, (ulong) thd->row_count_func, id, buff);
DBUG_RETURN(0);
}
@@ -3228,7 +3216,6 @@ void select_insert::abort() {
table->file->ha_release_auto_increment();
}
- ha_rollback_stmt(thd);
DBUG_VOID_RETURN;
}
@@ -3667,7 +3654,10 @@ bool select_create::send_eof()
nevertheless.
*/
if (!table->s->tmp_table)
- ha_commit(thd); // Can fail, but we proceed anyway
+ {
+ ha_autocommit_or_rollback(thd, 0);
+ end_active_trans(thd);
+ }
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
@@ -3691,12 +3681,9 @@ void select_create::abort()
by removing the table, even for non-transactional tables.
*/
tmp_disable_binlog(thd);
- select_insert::abort();
- reenable_binlog(thd);
-
/*
- We roll back the statement, including truncating the transaction
- cache of the binary log, if the statement failed.
+ In select_insert::abort() we roll back the statement, including
+ truncating the transaction cache of the binary log.
We roll back the statement prior to deleting the table and prior
to releasing the lock on the table, since there might be potential
@@ -3707,8 +3694,9 @@ void select_create::abort()
of the table succeeded or not, since we need to reset the binary
log state.
*/
- if (thd->current_stmt_binlog_row_based)
- ha_rollback_stmt(thd);
+ select_insert::abort();
+ reenable_binlog(thd);
+
if (m_plock)
{
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 5352f8efbbb..b07efc62a00 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1947,7 +1947,7 @@ bool st_select_lex::setup_ref_array(THD *thd, uint order_group_num)
}
-void st_select_lex_unit::print(String *str)
+void st_select_lex_unit::print(String *str, enum_query_type query_type)
{
bool union_all= !union_distinct;
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
@@ -1962,7 +1962,7 @@ void st_select_lex_unit::print(String *str)
}
if (sl->braces)
str->append('(');
- sl->print(thd, str);
+ sl->print(thd, str, query_type);
if (sl->braces)
str->append(')');
}
@@ -1971,16 +1971,19 @@ void st_select_lex_unit::print(String *str)
if (fake_select_lex->order_list.elements)
{
str->append(STRING_WITH_LEN(" order by "));
- fake_select_lex->print_order(str,
- (ORDER *) fake_select_lex->
- order_list.first);
+ fake_select_lex->print_order(
+ str,
+ (ORDER *) fake_select_lex->order_list.first,
+ query_type);
}
- fake_select_lex->print_limit(thd, str);
+ fake_select_lex->print_limit(thd, str, query_type);
}
}
-void st_select_lex::print_order(String *str, ORDER *order)
+void st_select_lex::print_order(String *str,
+ ORDER *order,
+ enum_query_type query_type)
{
for (; order; order= order->next)
{
@@ -1991,7 +1994,7 @@ void st_select_lex::print_order(String *str, ORDER *order)
str->append(buffer, length);
}
else
- (*order->item)->print(str);
+ (*order->item)->print(str, query_type);
if (!order->asc)
str->append(STRING_WITH_LEN(" desc"));
if (order->next)
@@ -2000,7 +2003,9 @@ void st_select_lex::print_order(String *str, ORDER *order)
}
-void st_select_lex::print_limit(THD *thd, String *str)
+void st_select_lex::print_limit(THD *thd,
+ String *str,
+ enum_query_type query_type)
{
SELECT_LEX_UNIT *unit= master_unit();
Item_subselect *item= unit->item;
@@ -2019,10 +2024,10 @@ void st_select_lex::print_limit(THD *thd, String *str)
str->append(STRING_WITH_LEN(" limit "));
if (offset_limit)
{
- offset_limit->print(str);
+ offset_limit->print(str, query_type);
str->append(',');
}
- select_limit->print(str);
+ select_limit->print(str, query_type);
}
}
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index ef0a9bb11ef..b1a0d506382 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -543,7 +543,7 @@ public:
inline void unclean() { cleaned= 0; }
void reinit_exec_mechanism();
- void print(String *str);
+ void print(String *str, enum_query_type query_type);
bool add_fake_select_lex(THD *thd);
void init_prepare_fake_select_lex(THD *thd);
@@ -762,9 +762,11 @@ public:
init_select();
}
bool setup_ref_array(THD *thd, uint order_group_num);
- void print(THD *thd, String *str);
- static void print_order(String *str, ORDER *order);
- void print_limit(THD *thd, String *str);
+ void print(THD *thd, String *str, enum_query_type query_type);
+ static void print_order(String *str,
+ ORDER *order,
+ enum_query_type query_type);
+ void print_limit(THD *thd, String *str, enum_query_type query_type);
void fix_prepare_information(THD *thd, Item **conds, Item **having_conds);
/*
Destroy the used execution plan (JOIN) of this subtree (this
@@ -1513,10 +1515,8 @@ typedef struct st_lex : public Query_tables_list
/* store original leaf_tables for INSERT SELECT and PS/SP */
TABLE_LIST *leaf_tables_insert;
- /** Start of SELECT of CREATE VIEW statement */
- const char* create_view_select_start;
- /** End of SELECT of CREATE VIEW statement */
- const char* create_view_select_end;
+ /** SELECT of CREATE VIEW statement */
+ LEX_STRING create_view_select;
/** Start of 'ON table', in trigger statements. */
const char* raw_trg_on_table_name_begin;
@@ -1710,8 +1710,6 @@ typedef struct st_lex : public Query_tables_list
*/
bool use_only_table_context;
- LEX_STRING view_body_utf8;
-
/*
Reference to a struct that contains information in various commands
to add/create/drop/change table spaces.
diff --git a/sql/sql_load.cc b/sql/sql_load.cc
index c96fbb80b0c..4d5dc8e6f06 100644
--- a/sql/sql_load.cc
+++ b/sql/sql_load.cc
@@ -470,9 +470,6 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
}
#endif /*!EMBEDDED_LIBRARY*/
- if (transactional_table)
- ha_autocommit_or_rollback(thd,error);
-
error= -1; // Error on read
goto err;
}
@@ -510,20 +507,13 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
}
}
#endif /*!EMBEDDED_LIBRARY*/
- if (transactional_table)
- error=ha_autocommit_or_rollback(thd,error);
/* ok to client sent only after binlog write and engine commit */
- send_ok(thd, info.copied + info.deleted, 0L, name);
+ my_ok(thd, info.copied + info.deleted, 0L, name);
err:
DBUG_ASSERT(transactional_table || !(info.copied || info.deleted) ||
thd->transaction.stmt.modified_non_trans_table);
table->file->ha_release_auto_increment();
- if (thd->lock)
- {
- mysql_unlock_tables(thd, thd->lock);
- thd->lock=0;
- }
table->auto_increment_field_not_null= FALSE;
thd->abort_on_warning= 0;
DBUG_RETURN(error);
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 031ceddde9a..c06491bbfa2 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -913,7 +913,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (!mysql_change_db(thd, &tmp, FALSE))
{
general_log_write(thd, command, thd->db, thd->db_length);
- send_ok(thd);
+ my_ok(thd);
}
break;
}
@@ -921,7 +921,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_REGISTER_SLAVE:
{
if (!register_slave(thd, (uchar*)packet, packet_length))
- send_ok(thd);
+ my_ok(thd);
break;
}
#endif
@@ -1322,7 +1322,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
general_log_print(thd, command, NullS);
if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, &not_used))
- send_ok(thd);
+ my_ok(thd);
break;
}
#ifndef EMBEDDED_LIBRARY
@@ -1348,7 +1348,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
DBUG_PRINT("quit",("Got shutdown command for level %u", level));
general_log_print(thd, command, NullS);
- send_eof(thd);
+ my_eof(thd);
close_thread_tables(thd); // Free before kill
kill_mysql();
error=TRUE;
@@ -1386,7 +1386,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
(uint) (queries_per_second1000 % 1000));
#ifdef EMBEDDED_LIBRARY
/* Store the buffer in permanent memory */
- send_ok(thd, 0, 0, buff);
+ my_ok(thd, 0, 0, buff);
#endif
#ifdef SAFEMALLOC
if (sf_malloc_cur_memory) // Using SAFEMALLOC
@@ -1407,7 +1407,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_PING:
status_var_increment(thd->status_var.com_other);
- send_ok(thd); // Tell client we are alive
+ my_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
status_var_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST]);
@@ -1434,11 +1434,11 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
switch (opt_command) {
case (int) MYSQL_OPTION_MULTI_STATEMENTS_ON:
thd->client_capabilities|= CLIENT_MULTI_STATEMENTS;
- send_eof(thd);
+ my_eof(thd);
break;
case (int) MYSQL_OPTION_MULTI_STATEMENTS_OFF:
thd->client_capabilities&= ~CLIENT_MULTI_STATEMENTS;
- send_eof(thd);
+ my_eof(thd);
break;
default:
my_message(ER_UNKNOWN_COM_ERROR, ER(ER_UNKNOWN_COM_ERROR), MYF(0));
@@ -1452,7 +1452,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break; /* purecov: inspected */
mysql_print_status();
general_log_print(thd, command, NullS);
- send_eof(thd);
+ my_eof(thd);
break;
case COM_SLEEP:
case COM_CONNECT: // Impossible here
@@ -1464,21 +1464,13 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
- thd_proc_info(thd, "closing tables");
- /* Free tables */
- close_thread_tables(thd);
+ /* If commit fails, we should be able to reset the OK status. */
+ thd->main_da.can_overwrite_status= TRUE;
+ ha_autocommit_or_rollback(thd, thd->is_error());
+ thd->main_da.can_overwrite_status= FALSE;
+
+ thd->transaction.stmt.reset();
- /*
- 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_state.xid.null();
/* report error issued during command execution */
if (thd->killed_errno())
@@ -1495,6 +1487,10 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
net_end_statement(thd);
query_cache_end_of_result(thd);
+ thd->proc_info= "closing tables";
+ /* Free tables */
+ close_thread_tables(thd);
+
log_slow_statement(thd);
thd_proc_info(thd, "cleaning up");
@@ -2079,7 +2075,7 @@ mysql_execute_command(THD *thd)
break;
case SQLCOM_EMPTY_QUERY:
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_HELP:
@@ -2246,7 +2242,7 @@ mysql_execute_command(THD *thd)
{
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, 0,
"the master info structure does not exist");
- send_ok(thd);
+ my_ok(thd);
}
pthread_mutex_unlock(&LOCK_active_mi);
break;
@@ -2304,7 +2300,7 @@ mysql_execute_command(THD *thd)
if (!fetch_master_table(thd, first_table->db, first_table->table_name,
active_mi, 0, 0))
{
- send_ok(thd);
+ my_ok(thd);
}
pthread_mutex_unlock(&LOCK_active_mi);
break;
@@ -2507,7 +2503,7 @@ mysql_execute_command(THD *thd)
&alter_info, 0, 0);
}
if (!res)
- send_ok(thd);
+ my_ok(thd);
}
/* put tables back for PS rexecuting */
@@ -3002,10 +2998,8 @@ end_with_restore_list:
/* INSERT ... SELECT should invalidate only the very first table */
TABLE_LIST *save_table= first_table->next_local;
first_table->next_local= 0;
- mysql_unlock_tables(thd, thd->lock);
query_cache_invalidate3(thd, first_table, 1);
first_table->next_local= save_table;
- thd->lock=0;
}
delete sel_result;
}
@@ -3192,7 +3186,7 @@ end_with_restore_list:
LEX_STRING db_str= { (char *) select_lex->db, strlen(select_lex->db) };
if (!mysql_change_db(thd, &db_str, FALSE))
- send_ok(thd);
+ my_ok(thd);
break;
}
@@ -3245,7 +3239,7 @@ end_with_restore_list:
about the ONE_SHOT property of that SET. So we use a |= instead of = .
*/
thd->one_shot_set|= lex->one_shot_set;
- send_ok(thd);
+ my_ok(thd);
}
break;
}
@@ -3265,7 +3259,7 @@ end_with_restore_list:
}
if (thd->global_read_lock)
unlock_global_read_lock(thd);
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_LOCK_TABLES:
unlock_locked_tables(thd);
@@ -3286,7 +3280,7 @@ end_with_restore_list:
#endif /*HAVE_QUERY_CACHE*/
thd->locked_tables=thd->lock;
thd->lock=0;
- send_ok(thd);
+ my_ok(thd);
}
else
{
@@ -3423,7 +3417,7 @@ end_with_restore_list:
res= mysql_upgrade_db(thd, db);
if (!res)
- send_ok(thd);
+ my_ok(thd);
break;
}
case SQLCOM_ALTER_DB:
@@ -3508,7 +3502,7 @@ end_with_restore_list:
}
DBUG_PRINT("info",("DDL error code=%d", res));
if (!res)
- send_ok(thd);
+ my_ok(thd);
} while (0);
/* Don't do it, if we are inside a SP */
@@ -3527,7 +3521,7 @@ end_with_restore_list:
if (!(res= Events::drop_event(thd,
lex->spname->m_db, lex->spname->m_name,
lex->drop_if_exists)))
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_CREATE_FUNCTION: // UDF function
{
@@ -3535,7 +3529,7 @@ end_with_restore_list:
break;
#ifdef HAVE_DLOPEN
if (!(res = mysql_create_function(thd, &lex->udf)))
- send_ok(thd);
+ my_ok(thd);
#else
my_error(ER_CANT_OPEN_LIBRARY, MYF(0), lex->udf.dl, 0, "feature disabled");
res= TRUE;
@@ -3552,7 +3546,7 @@ end_with_restore_list:
goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_create_user(thd, lex->users_list)))
- send_ok(thd);
+ my_ok(thd);
break;
}
case SQLCOM_DROP_USER:
@@ -3564,7 +3558,7 @@ end_with_restore_list:
goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_drop_user(thd, lex->users_list)))
- send_ok(thd);
+ my_ok(thd);
break;
}
case SQLCOM_RENAME_USER:
@@ -3576,7 +3570,7 @@ end_with_restore_list:
goto error;
/* Conditionally writes to binlog */
if (!(res= mysql_rename_user(thd, lex->users_list)))
- send_ok(thd);
+ my_ok(thd);
break;
}
case SQLCOM_REVOKE_ALL:
@@ -3588,7 +3582,7 @@ end_with_restore_list:
break;
/* Conditionally writes to binlog */
if (!(res = mysql_revoke_all(thd, lex->users_list)))
- send_ok(thd);
+ my_ok(thd);
break;
}
case SQLCOM_REVOKE:
@@ -3725,7 +3719,7 @@ end_with_restore_list:
{
write_bin_log(thd, FALSE, thd->query, thd->query_length);
}
- send_ok(thd);
+ my_ok(thd);
}
break;
@@ -3797,19 +3791,19 @@ end_with_restore_list:
}
if (begin_trans(thd))
goto error;
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_COMMIT:
if (end_trans(thd, lex->tx_release ? COMMIT_RELEASE :
lex->tx_chain ? COMMIT_AND_CHAIN : COMMIT))
goto error;
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_ROLLBACK:
if (end_trans(thd, lex->tx_release ? ROLLBACK_RELEASE :
lex->tx_chain ? ROLLBACK_AND_CHAIN : ROLLBACK))
goto error;
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_RELEASE_SAVEPOINT:
{
@@ -3826,7 +3820,7 @@ end_with_restore_list:
if (ha_release_savepoint(thd, sv))
res= TRUE; // cannot happen
else
- send_ok(thd);
+ my_ok(thd);
thd->transaction.savepoints=sv->prev;
}
else
@@ -3855,7 +3849,7 @@ end_with_restore_list:
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WARNING_NOT_COMPLETE_ROLLBACK,
ER(ER_WARNING_NOT_COMPLETE_ROLLBACK));
- send_ok(thd);
+ my_ok(thd);
}
thd->transaction.savepoints=sv;
}
@@ -3866,7 +3860,7 @@ end_with_restore_list:
case SQLCOM_SAVEPOINT:
if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN) ||
thd->in_sub_stmt) || !opt_using_transactions)
- send_ok(thd);
+ my_ok(thd);
else
{
SAVEPOINT **sv, *newsv;
@@ -3903,7 +3897,7 @@ end_with_restore_list:
{
newsv->prev=thd->transaction.savepoints;
thd->transaction.savepoints=newsv;
- send_ok(thd);
+ my_ok(thd);
}
}
break;
@@ -3976,7 +3970,6 @@ end_with_restore_list:
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_PROC_AUTO_GRANT_FAIL,
ER(ER_PROC_AUTO_GRANT_FAIL));
- close_thread_tables(thd);
}
#endif
break;
@@ -4004,7 +3997,7 @@ end_with_restore_list:
create_sp_error:
if (sp_result != SP_OK )
goto error;
- send_ok(thd);
+ my_ok(thd);
break; /* break super switch */
} /* end case group bracket */
case SQLCOM_CALL:
@@ -4097,8 +4090,8 @@ create_sp_error:
thd->server_status&= ~bits_to_be_cleared;
if (!res)
- send_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
- thd->row_count_func));
+ my_ok(thd, (ulong) (thd->row_count_func < 0 ? 0 :
+ thd->row_count_func));
else
{
DBUG_ASSERT(thd->is_error() || thd->killed);
@@ -4175,7 +4168,7 @@ create_sp_error:
switch (sp_result)
{
case SP_OK:
- send_ok(thd);
+ my_ok(thd);
break;
case SP_KEY_NOT_FOUND:
my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
@@ -4240,7 +4233,7 @@ create_sp_error:
if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
{
- send_ok(thd);
+ my_ok(thd);
break;
}
}
@@ -4257,7 +4250,7 @@ create_sp_error:
res= sp_result;
switch (sp_result) {
case SP_OK:
- send_ok(thd);
+ my_ok(thd);
break;
case SP_KEY_NOT_FOUND:
if (lex->drop_if_exists)
@@ -4266,7 +4259,7 @@ create_sp_error:
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
SP_COM_STRING(lex), lex->spname->m_name.str);
res= FALSE;
- send_ok(thd);
+ my_ok(thd);
break;
}
my_error(ER_SP_DOES_NOT_EXIST, MYF(0),
@@ -4398,7 +4391,7 @@ create_sp_error:
break;
}
thd->transaction.xid_state.xa_state=XA_ACTIVE;
- send_ok(thd);
+ my_ok(thd);
break;
}
if (thd->lex->xa_opt != XA_NONE)
@@ -4429,7 +4422,7 @@ create_sp_error:
thd->transaction.all.modified_non_trans_table= FALSE;
thd->options= ((thd->options & ~(OPTION_KEEP_LOG)) | OPTION_BEGIN);
thd->server_status|= SERVER_STATUS_IN_TRANS;
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_XA_END:
/* fake it */
@@ -4450,7 +4443,7 @@ create_sp_error:
break;
}
thd->transaction.xid_state.xa_state=XA_IDLE;
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_XA_PREPARE:
if (thd->transaction.xid_state.xa_state != XA_IDLE)
@@ -4472,7 +4465,7 @@ create_sp_error:
break;
}
thd->transaction.xid_state.xa_state=XA_PREPARED;
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_XA_COMMIT:
if (!thd->transaction.xid_state.xid.eq(thd->lex->xid))
@@ -4484,7 +4477,7 @@ create_sp_error:
{
ha_commit_or_rollback_by_xid(thd->lex->xid, 1);
xid_cache_delete(xs);
- send_ok(thd);
+ my_ok(thd);
}
break;
}
@@ -4495,7 +4488,7 @@ create_sp_error:
if ((r= ha_commit(thd)))
my_error(r == 1 ? ER_XA_RBROLLBACK : ER_XAER_RMERR, MYF(0));
else
- send_ok(thd);
+ my_ok(thd);
}
else if (thd->transaction.xid_state.xa_state == XA_PREPARED &&
thd->lex->xa_opt == XA_NONE)
@@ -4510,7 +4503,7 @@ create_sp_error:
if (ha_commit_one_phase(thd, 1))
my_error(ER_XAER_RMERR, MYF(0));
else
- send_ok(thd);
+ my_ok(thd);
start_waiting_global_read_lock(thd);
}
}
@@ -4536,7 +4529,7 @@ create_sp_error:
{
ha_commit_or_rollback_by_xid(thd->lex->xid, 0);
xid_cache_delete(xs);
- send_ok(thd);
+ my_ok(thd);
}
break;
}
@@ -4550,7 +4543,7 @@ create_sp_error:
if (ha_rollback(thd))
my_error(ER_XAER_RMERR, MYF(0));
else
- send_ok(thd);
+ my_ok(thd);
thd->options&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
@@ -4564,16 +4557,16 @@ create_sp_error:
if (check_access(thd, ALTER_ACL, thd->db, 0, 1, 0, thd->db ? is_schema_db(thd->db) : 0))
break;
if (!(res= mysql_alter_tablespace(thd, lex->alter_tablespace_info)))
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_INSTALL_PLUGIN:
if (! (res= mysql_install_plugin(thd, &thd->lex->comment,
&thd->lex->ident)))
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_UNINSTALL_PLUGIN:
if (! (res= mysql_uninstall_plugin(thd, &thd->lex->comment)))
- send_ok(thd);
+ my_ok(thd);
break;
case SQLCOM_BINLOG_BASE64_EVENT:
{
@@ -4600,7 +4593,7 @@ create_sp_error:
my_error(error, MYF(0), lex->server_options.server_name);
break;
}
- send_ok(thd, 1);
+ my_ok(thd, 1);
break;
}
case SQLCOM_ALTER_SERVER:
@@ -4619,7 +4612,7 @@ create_sp_error:
my_error(error, MYF(0), lex->server_options.server_name);
break;
}
- send_ok(thd, 1);
+ my_ok(thd, 1);
break;
}
case SQLCOM_DROP_SERVER:
@@ -4641,18 +4634,18 @@ create_sp_error:
}
else
{
- send_ok(thd, 0);
+ my_ok(thd, 0);
}
break;
}
- send_ok(thd, 1);
+ my_ok(thd, 1);
break;
}
default:
#ifndef EMBEDDED_LIBRARY
DBUG_ASSERT(0); /* Impossible */
#endif
- send_ok(thd);
+ my_ok(thd);
break;
}
thd_proc_info(thd, "query end");
@@ -4728,7 +4721,7 @@ static bool execute_sqlcom_select(THD *thd, TABLE_LIST *all_tables)
char buff[1024];
String str(buff,(uint32) sizeof(buff), system_charset_info);
str.length(0);
- thd->lex->unit.print(&str);
+ thd->lex->unit.print(&str, QT_ORDINARY);
str.append('\0');
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_YES, str.ptr());
@@ -4981,35 +4974,6 @@ check_access(THD *thd, ulong want_access, const char *db, ulong *save_priv,
}
-/**
- check for global access and give descriptive error message if it fails.
-
- @param thd Thread handler
- @param want_access Use should have any of these global rights
-
- @warning
- One gets access right if one has ANY of the rights in want_access.
- This is useful as one in most cases only need one global right,
- but in some case we want to check if the user has SUPER or
- REPL_CLIENT_ACL rights.
-
- @retval
- 0 ok
- @retval
- 1 Access denied. In this case an error is sent to the client
-*/
-
-bool check_global_access(THD *thd, ulong want_access)
-{
- char command[128];
- if ((thd->security_ctx->master_access & want_access))
- return 0;
- get_privilege_desc(command, sizeof(command), want_access);
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
- return 1;
-}
-
-
static bool check_show_access(THD *thd, TABLE_LIST *table)
{
switch (get_schema_table_idx(table->schema_table)) {
@@ -5252,6 +5216,39 @@ bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table)
#endif /*NO_EMBEDDED_ACCESS_CHECKS*/
+
+/**
+ check for global access and give descriptive error message if it fails.
+
+ @param thd Thread handler
+ @param want_access Use should have any of these global rights
+
+ @warning
+ One gets access right if one has ANY of the rights in want_access.
+ This is useful as one in most cases only need one global right,
+ but in some case we want to check if the user has SUPER or
+ REPL_CLIENT_ACL rights.
+
+ @retval
+ 0 ok
+ @retval
+ 1 Access denied. In this case an error is sent to the client
+*/
+
+bool check_global_access(THD *thd, ulong want_access)
+{
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ char command[128];
+ if ((thd->security_ctx->master_access & want_access))
+ return 0;
+ get_privilege_desc(command, sizeof(command), want_access);
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), command);
+ return 1;
+#else
+ return 0;
+#endif
+}
+
/****************************************************************************
Check stack size; Send error if there isn't enough stack to continue
****************************************************************************/
@@ -6447,6 +6444,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables,
{
thd->thread_stack= (char*) &tmp_thd;
thd->store_globals();
+ lex_start(thd);
}
if (thd)
{
@@ -6659,7 +6657,7 @@ void sql_kill(THD *thd, ulong id, bool only_kill_query)
{
uint error;
if (!(error= kill_one_thread(thd, id, only_kill_query)))
- send_ok(thd);
+ my_ok(thd);
else
my_error(error, MYF(0), id);
}
diff --git a/sql/sql_partition.cc b/sql/sql_partition.cc
index 7eab04b073a..037da87be7f 100644
--- a/sql/sql_partition.cc
+++ b/sql/sql_partition.cc
@@ -3970,31 +3970,35 @@ static int fast_end_partition(THD *thd, ulonglong copied,
bool written_bin_log)
{
int error;
+ char tmp_name[80];
DBUG_ENTER("fast_end_partition");
thd->proc_info="end";
+
if (!is_empty)
query_cache_invalidate3(thd, table_list, 0);
- error= ha_commit_stmt(thd);
- if (ha_commit(thd))
+
+ error= ha_autocommit_or_rollback(thd, 0);
+ if (end_active_trans(thd))
error= 1;
- if (!error || is_empty)
- {
- char tmp_name[80];
- if ((!is_empty) && (!written_bin_log) &&
- (!thd->lex->no_write_to_binlog))
- write_bin_log(thd, FALSE, thd->query, thd->query_length);
- close_thread_tables(thd);
- my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
- (ulong) (copied + deleted),
- (ulong) deleted,
- (ulong) 0);
- send_ok(thd, (ha_rows) (copied+deleted),0L,tmp_name);
- DBUG_RETURN(FALSE);
+
+ if (error)
+ {
+ /* If error during commit, no need to rollback, it's done. */
+ table->file->print_error(error, MYF(0));
+ DBUG_RETURN(TRUE);
}
- table->file->print_error(error, MYF(0));
- close_thread_tables(thd);
- DBUG_RETURN(TRUE);
+
+ if ((!is_empty) && (!written_bin_log) &&
+ (!thd->lex->no_write_to_binlog))
+ write_bin_log(thd, FALSE, thd->query, thd->query_length);
+
+ my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
+ (ulong) (copied + deleted),
+ (ulong) deleted,
+ (ulong) 0);
+ my_ok(thd, (ha_rows) (copied+deleted),0L, tmp_name);
+ DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_plugin.cc b/sql/sql_plugin.cc
index ccb1a3a8af0..e0eeac0aa9f 100644
--- a/sql/sql_plugin.cc
+++ b/sql/sql_plugin.cc
@@ -1895,7 +1895,7 @@ err:
static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
- bool fixed;
+ my_bool fixed;
long long tmp;
struct my_option options;
value->val_int(value, &tmp);
@@ -1923,7 +1923,7 @@ static int check_func_int(THD *thd, struct st_mysql_sys_var *var,
static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
- bool fixed;
+ my_bool fixed;
long long tmp;
struct my_option options;
value->val_int(value, &tmp);
@@ -1951,12 +1951,11 @@ static int check_func_long(THD *thd, struct st_mysql_sys_var *var,
static int check_func_longlong(THD *thd, struct st_mysql_sys_var *var,
void *save, st_mysql_value *value)
{
- bool fixed;
+ my_bool fixed;
long long tmp;
struct my_option options;
value->val_int(value, &tmp);
plugin_opt_set_limits(&options, var);
- *(ulonglong *)save= getopt_ull_limit_value(tmp, &options, &fixed);
if (var->flags & PLUGIN_VAR_UNSIGNED)
*(ulonglong *)save= getopt_ull_limit_value((ulonglong) tmp, &options,
diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc
index 5a903a4fe1c..a027ffe9daa 100644
--- a/sql/sql_prepare.cc
+++ b/sql/sql_prepare.cc
@@ -1524,6 +1524,44 @@ static bool mysql_test_create_table(Prepared_statement *stmt)
/**
+ @brief Validate and prepare for execution CREATE VIEW statement
+
+ @param stmt prepared statement
+
+ @note This function handles create view commands.
+
+ @retval FALSE Operation was a success.
+ @retval TRUE An error occured.
+*/
+
+static bool mysql_test_create_view(Prepared_statement *stmt)
+{
+ DBUG_ENTER("mysql_test_create_view");
+ THD *thd= stmt->thd;
+ LEX *lex= stmt->lex;
+ bool res= TRUE;
+ /* Skip first table, which is the view we are creating */
+ bool link_to_local;
+ TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
+ TABLE_LIST *tables= lex->query_tables;
+
+ if (create_view_precheck(thd, tables, view, lex->create_view_mode))
+ goto err;
+
+ if (open_normal_and_derived_tables(thd, tables, 0))
+ goto err;
+
+ lex->view_prepare_mode= 1;
+ res= select_like_stmt_test(stmt, 0, 0);
+
+err:
+ /* put view back for PS rexecuting */
+ lex->link_first_table_back(view, link_to_local);
+ DBUG_RETURN(res);
+}
+
+
+/*
Validate and prepare for execution a multi update statement.
@param stmt prepared statement
@@ -1735,6 +1773,7 @@ static bool check_prepared_statement(Prepared_statement *stmt,
my_message(ER_UNSUPPORTED_PS, ER(ER_UNSUPPORTED_PS), MYF(0));
goto error;
}
+ res= mysql_test_create_view(stmt);
break;
case SQLCOM_DO:
res= mysql_test_do_fields(stmt, tables, lex->insert_list);
@@ -2111,7 +2150,7 @@ void mysql_sql_stmt_prepare(THD *thd)
thd->stmt_map.erase(stmt);
}
else
- send_ok(thd, 0L, 0L, "Statement prepared");
+ my_ok(thd, 0L, 0L, "Statement prepared");
DBUG_VOID_RETURN;
}
@@ -2494,7 +2533,9 @@ void mysql_stmt_reset(THD *thd, char *packet)
stmt->state= Query_arena::PREPARED;
- send_ok(thd);
+ general_log_print(thd, thd->command, NullS);
+
+ my_ok(thd);
DBUG_VOID_RETURN;
}
@@ -2523,6 +2564,7 @@ void mysql_stmt_close(THD *thd, char *packet)
*/
DBUG_ASSERT(! (stmt->flags & (uint) Prepared_statement::IS_IN_USE));
(void) stmt->deallocate();
+ general_log_print(thd, thd->command, NullS);
thd->main_da.disable_status();
@@ -2557,7 +2599,7 @@ void mysql_sql_stmt_close(THD *thd)
}
if (stmt->deallocate() == 0)
- send_ok(thd);
+ my_ok(thd);
}
/**
@@ -2630,6 +2672,9 @@ void mysql_stmt_get_longdata(THD *thd, char *packet, ulong packet_length)
stmt->last_errno= ER_OUTOFMEMORY;
sprintf(stmt->last_error, ER(ER_OUTOFMEMORY), 0);
}
+
+ general_log_print(thd, thd->command, NullS);
+
DBUG_VOID_RETURN;
}
@@ -2662,7 +2707,7 @@ bool Select_fetch_protocol_binary::send_fields(List<Item> &list, uint flags)
bool Select_fetch_protocol_binary::send_eof()
{
- ::send_eof(thd);
+ ::my_eof(thd);
return FALSE;
}
diff --git a/sql/sql_profile.cc b/sql/sql_profile.cc
index 1922fa3bc2b..c62cf6401ba 100644
--- a/sql/sql_profile.cc
+++ b/sql/sql_profile.cc
@@ -456,7 +456,7 @@ bool PROFILING::show_profiles()
if (protocol->write())
DBUG_RETURN(TRUE);
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_rename.cc b/sql/sql_rename.cc
index 9dd8e1b70d4..fc87356e452 100644
--- a/sql/sql_rename.cc
+++ b/sql/sql_rename.cc
@@ -178,7 +178,7 @@ bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
if (!silent && !error)
{
write_bin_log(thd, TRUE, thd->query, thd->query_length);
- send_ok(thd);
+ my_ok(thd);
}
if (!error)
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index cdce2fa695b..932b7a67b4d 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -252,7 +252,7 @@ bool purge_error_message(THD* thd, int res)
my_message(errmsg, ER(errmsg), MYF(0));
return TRUE;
}
- send_ok(thd);
+ my_ok(thd);
return FALSE;
}
@@ -262,7 +262,7 @@ bool purge_master_logs(THD* thd, const char* to_log)
char search_file_name[FN_REFLEN];
if (!mysql_bin_log.is_open())
{
- send_ok(thd);
+ my_ok(thd);
return FALSE;
}
@@ -277,7 +277,7 @@ bool purge_master_logs_before_date(THD* thd, time_t purge_time)
{
if (!mysql_bin_log.is_open())
{
- send_ok(thd);
+ my_ok(thd);
return 0;
}
return purge_error_message(thd,
@@ -738,7 +738,7 @@ end:
end_io_cache(&log);
(void)my_close(file, MYF(MY_WME));
- send_eof(thd);
+ my_eof(thd);
thd_proc_info(thd, "Waiting to finalize termination");
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
@@ -884,7 +884,7 @@ int start_slave(THD* thd , Master_info* mi, bool net_report)
DBUG_RETURN(1);
}
else if (net_report)
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(0);
}
@@ -936,7 +936,7 @@ int stop_slave(THD* thd, Master_info* mi, bool net_report )
DBUG_RETURN(1);
}
else if (net_report)
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(0);
}
@@ -1279,7 +1279,7 @@ bool change_master(THD* thd, Master_info* mi)
unlock_slave_threads(mi);
thd_proc_info(thd, 0);
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(FALSE);
}
@@ -1453,7 +1453,7 @@ err:
my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
"SHOW BINLOG EVENTS", errmsg);
else
- send_eof(thd);
+ my_eof(thd);
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
@@ -1490,7 +1490,7 @@ bool show_binlog_info(THD* thd)
if (protocol->write())
DBUG_RETURN(TRUE);
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -1572,7 +1572,7 @@ bool show_binlogs(THD* thd)
goto err;
}
mysql_bin_log.unlock_index();
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
err:
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index d7e7be87d23..a520f9c57cf 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -945,7 +945,8 @@ JOIN::optimize()
make_cond_for_table(conds, PSEUDO_TABLE_BITS, 0);
DBUG_EXECUTE("where",
print_where(table_independent_conds,
- "where after opt_sum_query()"););
+ "where after opt_sum_query()",
+ QT_ORDINARY););
conds= table_independent_conds;
}
}
@@ -1025,7 +1026,10 @@ JOIN::optimize()
{
conds= substitute_for_best_equal_field(conds, cond_equal, map2table);
conds->update_used_tables();
- DBUG_EXECUTE("where", print_where(conds, "after substitute_best_equal"););
+ DBUG_EXECUTE("where",
+ print_where(conds,
+ "after substitute_best_equal",
+ QT_ORDINARY););
}
/*
@@ -2088,12 +2092,14 @@ JOIN::exec()
curr_table->select_cond= curr_table->select->cond;
curr_table->select_cond->top_level_item();
DBUG_EXECUTE("where",print_where(curr_table->select->cond,
- "select and having"););
+ "select and having",
+ QT_ORDINARY););
curr_join->tmp_having= make_cond_for_table(curr_join->tmp_having,
~ (table_map) 0,
~used_tables);
DBUG_EXECUTE("where",print_where(curr_join->tmp_having,
- "having after sort"););
+ "having after sort",
+ QT_ORDINARY););
}
}
{
@@ -5837,7 +5843,8 @@ static void add_not_null_conds(JOIN *join)
if (notnull->fix_fields(join->thd, &notnull))
DBUG_VOID_RETURN;
DBUG_EXECUTE("where",print_where(notnull,
- referred_tab->table->alias););
+ referred_tab->table->alias,
+ QT_ORDINARY););
add_cond_and_fix(&referred_tab->select_cond, notnull);
}
}
@@ -5995,7 +6002,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
make_cond_for_table(cond,
join->const_table_map,
(table_map) 0);
- DBUG_EXECUTE("where",print_where(const_cond,"constants"););
+ DBUG_EXECUTE("where",print_where(const_cond,"constants", QT_ORDINARY););
for (JOIN_TAB *tab= join->join_tab+join->const_tables;
tab < join->join_tab+join->tables ; tab++)
{
@@ -6096,7 +6103,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
}
if (tmp || !cond)
{
- DBUG_EXECUTE("where",print_where(tmp,tab->table->alias););
+ DBUG_EXECUTE("where",print_where(tmp,tab->table->alias, QT_ORDINARY););
SQL_SELECT *sel= tab->select= ((SQL_SELECT*)
thd->memdup((uchar*) select,
sizeof(*select)));
@@ -6136,7 +6143,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
tab->select_cond= sel->cond= NULL;
sel->head=tab->table;
- DBUG_EXECUTE("where",print_where(tmp,tab->table->alias););
+ DBUG_EXECUTE("where",print_where(tmp,tab->table->alias, QT_ORDINARY););
if (tab->quick)
{
/* Use quick key read if it's a constant and it's not used
@@ -6248,7 +6255,7 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond)
current_map,
current_map)))
{
- DBUG_EXECUTE("where",print_where(tmp,"cache"););
+ DBUG_EXECUTE("where",print_where(tmp,"cache", QT_ORDINARY););
tab->cache.select=(SQL_SELECT*)
thd->memdup((uchar*) sel, sizeof(SQL_SELECT));
tab->cache.select->cond=tmp;
@@ -8872,10 +8879,10 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
predicate. Substitute a constant instead of this field if the
multiple equality contains a constant.
*/
- DBUG_EXECUTE("where", print_where(conds, "original"););
+ DBUG_EXECUTE("where", print_where(conds, "original", QT_ORDINARY););
conds= build_equal_items(join->thd, conds, NULL, join_list,
&join->cond_equal);
- DBUG_EXECUTE("where",print_where(conds,"after equal_items"););
+ DBUG_EXECUTE("where",print_where(conds,"after equal_items", QT_ORDINARY););
/* change field = field to field = const for each found field = const */
propagate_cond_constants(thd, (I_List<COND_CMP> *) 0, conds, conds);
@@ -8883,9 +8890,9 @@ optimize_cond(JOIN *join, COND *conds, List<TABLE_LIST> *join_list,
Remove all instances of item == item
Remove all and-levels where CONST item != CONST item
*/
- DBUG_EXECUTE("where",print_where(conds,"after const change"););
+ DBUG_EXECUTE("where",print_where(conds,"after const change", QT_ORDINARY););
conds= remove_eq_conds(thd, conds, cond_value) ;
- DBUG_EXECUTE("info",print_where(conds,"after remove"););
+ DBUG_EXECUTE("info",print_where(conds,"after remove", QT_ORDINARY););
}
DBUG_RETURN(conds);
}
@@ -13357,7 +13364,7 @@ static bool fix_having(JOIN *join, Item **having)
JOIN_TAB *table=&join->join_tab[join->const_tables];
table_map used_tables= join->const_table_map | table->table->map;
- DBUG_EXECUTE("where",print_where(*having,"having"););
+ DBUG_EXECUTE("where",print_where(*having,"having", QT_ORDINARY););
Item* sort_table_cond=make_cond_for_table(*having,used_tables,used_tables);
if (sort_table_cond)
{
@@ -13374,9 +13381,11 @@ static bool fix_having(JOIN *join, Item **having)
table->select_cond=table->select->cond;
table->select_cond->top_level_item();
DBUG_EXECUTE("where",print_where(table->select_cond,
- "select and having"););
+ "select and having",
+ QT_ORDINARY););
*having=make_cond_for_table(*having,~ (table_map) 0,~used_tables);
- DBUG_EXECUTE("where",print_where(*having,"having after make_cond"););
+ DBUG_EXECUTE("where",
+ print_where(*having,"having after make_cond", QT_ORDINARY););
}
return 0;
}
@@ -15043,7 +15052,7 @@ change_to_use_tmp_fields(THD *thd, Item **ref_pointer_array,
char buff[256];
String str(buff,sizeof(buff),&my_charset_bin);
str.length(0);
- item->print(&str);
+ item->print(&str, QT_ORDINARY);
item_field->name= sql_strmake(str.ptr(),str.length());
}
#endif
@@ -16084,7 +16093,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order,
if (thd->lex->describe & DESCRIBE_EXTENDED)
{
extra.append(STRING_WITH_LEN(": "));
- ((COND *)pushed_cond)->print(&extra);
+ ((COND *)pushed_cond)->print(&extra, QT_ORDINARY);
}
}
else
@@ -16233,9 +16242,13 @@ bool mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit, select_result *result)
@param thd thread handler
@param str string where table should be printed
@param tables list of tables in join
+ @query_type type of the query is being generated
*/
-static void print_join(THD *thd, String *str, List<TABLE_LIST> *tables)
+static void print_join(THD *thd,
+ String *str,
+ List<TABLE_LIST> *tables,
+ enum_query_type query_type)
{
/* List is reversed => we should reverse it before using */
List_iterator_fast<TABLE_LIST> ti(*tables);
@@ -16248,7 +16261,7 @@ static void print_join(THD *thd, String *str, List<TABLE_LIST> *tables)
*t= ti++;
DBUG_ASSERT(tables->elements >= 1);
- (*table)->print(thd, str);
+ (*table)->print(thd, str, query_type);
TABLE_LIST **end= table + tables->elements;
for (TABLE_LIST **tbl= table + 1; tbl < end; tbl++)
@@ -16263,11 +16276,11 @@ static void print_join(THD *thd, String *str, List<TABLE_LIST> *tables)
str->append(STRING_WITH_LEN(" straight_join "));
else
str->append(STRING_WITH_LEN(" join "));
- curr->print(thd, str);
+ curr->print(thd, str, query_type);
if (curr->on_expr)
{
str->append(STRING_WITH_LEN(" on("));
- curr->on_expr->print(str);
+ curr->on_expr->print(str, query_type);
str->append(')');
}
}
@@ -16314,15 +16327,15 @@ Index_hint::print(THD *thd, String *str)
/**
Print table as it should be in join list.
- @param str string where table should bbe printed
+ @param str string where table should be printed
*/
-void TABLE_LIST::print(THD *thd, String *str)
+void TABLE_LIST::print(THD *thd, String *str, enum_query_type query_type)
{
if (nested_join)
{
str->append('(');
- print_join(thd, str, &nested_join->join_list);
+ print_join(thd, str, &nested_join->join_list, query_type);
str->append(')');
}
else
@@ -16345,7 +16358,7 @@ void TABLE_LIST::print(THD *thd, String *str)
{
// A derived table
str->append('(');
- derived->print(str);
+ derived->print(str, query_type);
str->append(')');
cmp_name= ""; // Force printing of alias
}
@@ -16405,7 +16418,7 @@ void TABLE_LIST::print(THD *thd, String *str)
}
-void st_select_lex::print(THD *thd, String *str)
+void st_select_lex::print(THD *thd, String *str, enum_query_type query_type)
{
/* QQ: thd may not be set for sub queries, but this should be fixed */
if (!thd)
@@ -16453,7 +16466,7 @@ void st_select_lex::print(THD *thd, String *str)
first= 0;
else
str->append(',');
- item->print_item_w_name(str);
+ item->print_item_w_name(str, query_type);
}
/*
@@ -16464,7 +16477,7 @@ void st_select_lex::print(THD *thd, String *str)
{
str->append(STRING_WITH_LEN(" from "));
/* go through join tree */
- print_join(thd, str, &top_join_list);
+ print_join(thd, str, &top_join_list, query_type);
}
// Where
@@ -16475,7 +16488,7 @@ void st_select_lex::print(THD *thd, String *str)
{
str->append(STRING_WITH_LEN(" where "));
if (cur_where)
- cur_where->print(str);
+ cur_where->print(str, query_type);
else
str->append(cond_value != Item::COND_FALSE ? "1" : "0");
}
@@ -16484,7 +16497,7 @@ void st_select_lex::print(THD *thd, String *str)
if (group_list.elements)
{
str->append(STRING_WITH_LEN(" group by "));
- print_order(str, (ORDER *) group_list.first);
+ print_order(str, (ORDER *) group_list.first, query_type);
switch (olap)
{
case CUBE_TYPE:
@@ -16507,7 +16520,7 @@ void st_select_lex::print(THD *thd, String *str)
{
str->append(STRING_WITH_LEN(" having "));
if (cur_having)
- cur_having->print(str);
+ cur_having->print(str, query_type);
else
str->append(having_value != Item::COND_FALSE ? "1" : "0");
}
@@ -16515,11 +16528,11 @@ void st_select_lex::print(THD *thd, String *str)
if (order_list.elements)
{
str->append(STRING_WITH_LEN(" order by "));
- print_order(str, (ORDER *) order_list.first);
+ print_order(str, (ORDER *) order_list.first, query_type);
}
// limit
- print_limit(thd, str);
+ print_limit(thd, str, query_type);
// PROCEDURE unsupported here
}
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index a6516d5bf46..09886d3e171 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -224,7 +224,7 @@ bool mysqld_show_authors(THD *thd)
if (protocol->write())
DBUG_RETURN(TRUE);
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -258,7 +258,7 @@ bool mysqld_show_contributors(THD *thd)
if (protocol->write())
DBUG_RETURN(TRUE);
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -331,7 +331,7 @@ bool mysqld_show_privileges(THD *thd)
if (protocol->write())
DBUG_RETURN(TRUE);
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -419,7 +419,7 @@ bool mysqld_show_column_types(THD *thd)
if (protocol->write())
DBUG_RETURN(TRUE);
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -666,7 +666,7 @@ mysqld_show_create(THD *thd, TABLE_LIST *table_list)
if (protocol->write())
DBUG_RETURN(TRUE);
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -747,7 +747,7 @@ bool mysqld_show_create_db(THD *thd, char *dbname,
if (protocol->write())
DBUG_RETURN(TRUE);
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
}
@@ -789,7 +789,7 @@ mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
table->use_all_columns();
if (thd->protocol->send_fields(&field_list, Protocol::SEND_DEFAULTS))
DBUG_VOID_RETURN;
- send_eof(thd);
+ my_eof(thd);
DBUG_VOID_RETURN;
}
@@ -1582,7 +1582,7 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
We can't just use table->query, because our SQL_MODE may trigger
a different syntax, like when ANSI_QUOTES is defined.
*/
- table->view->unit.print(buff);
+ table->view->unit.print(buff, QT_ORDINARY);
if (table->with_check != VIEW_CHECK_NONE)
{
@@ -1738,7 +1738,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
if (protocol->write())
break; /* purecov: inspected */
}
- send_eof(thd);
+ my_eof(thd);
DBUG_VOID_RETURN;
}
@@ -6761,7 +6761,7 @@ static bool show_create_trigger_impl(THD *thd,
ret_code= p->write();
if (!ret_code)
- send_eof(thd);
+ my_eof(thd);
return ret_code != 0;
}
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 5600abfdc87..18d8ae68008 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1501,7 +1501,7 @@ bool mysql_rm_table(THD *thd,TABLE_LIST *tables, my_bool if_exists,
if (error)
DBUG_RETURN(TRUE);
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(FALSE);
}
@@ -3005,6 +3005,37 @@ mysql_prepare_create_table(THD *thd, HA_CREATE_INFO *create_info,
(qsort_cmp) sort_keys);
create_info->null_bits= null_fields;
+ /* Check fields. */
+ it.rewind();
+ while ((sql_field=it++))
+ {
+ Field::utype type= (Field::utype) MTYP_TYPENR(sql_field->unireg_check);
+
+ if (thd->variables.sql_mode & MODE_NO_ZERO_DATE &&
+ !sql_field->def &&
+ sql_field->sql_type == MYSQL_TYPE_TIMESTAMP &&
+ (sql_field->flags & NOT_NULL_FLAG) &&
+ (type == Field::NONE || type == Field::TIMESTAMP_UN_FIELD))
+ {
+ /*
+ An error should be reported if:
+ - NO_ZERO_DATE SQL mode is active;
+ - there is no explicit DEFAULT clause (default column value);
+ - this is a TIMESTAMP column;
+ - the column is not NULL;
+ - this is not the DEFAULT CURRENT_TIMESTAMP column.
+
+ In other words, an error should be reported if
+ - NO_ZERO_DATE SQL mode is active;
+ - the column definition is equivalent to
+ 'column_name TIMESTAMP DEFAULT 0'.
+ */
+
+ my_error(ER_INVALID_DEFAULT, MYF(0), sql_field->field_name);
+ DBUG_RETURN(TRUE);
+ }
+ }
+
DBUG_RETURN(FALSE);
}
@@ -4146,6 +4177,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
switch ((*prepare_func)(thd, table, check_opt)) {
case 1: // error, message written to net
ha_autocommit_or_rollback(thd, 1);
+ end_trans(thd, ROLLBACK);
close_thread_tables(thd);
DBUG_PRINT("admin", ("simple error, admin next table"));
continue;
@@ -4204,6 +4236,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
table_name);
protocol->store(buff, length, system_charset_info);
ha_autocommit_or_rollback(thd, 0);
+ end_trans(thd, COMMIT);
close_thread_tables(thd);
lex->reset_query_tables_list(FALSE);
table->table=0; // For query cache
@@ -4476,17 +4509,19 @@ send_result_message:
}
}
ha_autocommit_or_rollback(thd, 0);
+ end_trans(thd, COMMIT);
close_thread_tables(thd);
table->table=0; // For query cache
if (protocol->write())
goto err;
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
- err:
+err:
ha_autocommit_or_rollback(thd, 1);
+ end_trans(thd, ROLLBACK);
close_thread_tables(thd); // Shouldn't be needed
if (table)
table->table=0;
@@ -5009,8 +5044,8 @@ mysql_discard_or_import_tablespace(THD *thd,
query_cache_invalidate3(thd, table_list, 0);
/* The ALTER TABLE is always in its own transaction */
- error = ha_commit_stmt(thd);
- if (ha_commit(thd))
+ error = ha_autocommit_or_rollback(thd, 0);
+ if (end_active_trans(thd))
error=1;
if (error)
goto err;
@@ -5018,12 +5053,11 @@ mysql_discard_or_import_tablespace(THD *thd,
err:
ha_autocommit_or_rollback(thd, error);
- close_thread_tables(thd);
thd->tablespace_op=FALSE;
if (error == 0)
{
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(0);
}
@@ -5987,7 +6021,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
mysql_bin_log.write(&qinfo);
}
- send_ok(thd);
+ my_ok(thd);
}
unlock_table_names(thd, table_list, (TABLE_LIST*) 0);
@@ -6225,7 +6259,7 @@ view_err:
if (!error)
{
write_bin_log(thd, TRUE, thd->query, thd->query_length);
- send_ok(thd);
+ my_ok(thd);
}
else if (error > 0)
{
@@ -6541,8 +6575,8 @@ view_err:
VOID(pthread_mutex_unlock(&LOCK_open));
alter_table_manage_keys(table, table->file->indexes_are_disabled(),
alter_info->keys_onoff);
- error= ha_commit_stmt(thd);
- if (ha_commit(thd))
+ error= ha_autocommit_or_rollback(thd, 0);
+ if (end_active_trans(thd))
error= 1;
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE;
@@ -6630,7 +6664,7 @@ view_err:
/* Need to commit before a table is unlocked (NDB requirement). */
DBUG_PRINT("info", ("Committing before unlocking table"));
- if (ha_commit_stmt(thd) || ha_commit(thd))
+ if (ha_autocommit_or_rollback(thd, 0) || end_active_trans(thd))
goto err1;
committed= 1;
}
@@ -6861,7 +6895,7 @@ end_temporary:
my_snprintf(tmp_name, sizeof(tmp_name), ER(ER_INSERT_INFO),
(ulong) (copied + deleted), (ulong) deleted,
(ulong) thd->cuted_fields);
- send_ok(thd, copied + deleted, 0L, tmp_name);
+ my_ok(thd, copied + deleted, 0L, tmp_name);
thd->some_tables_deleted=0;
DBUG_RETURN(FALSE);
@@ -7131,9 +7165,9 @@ copy_data_between_tables(TABLE *from,TABLE *to,
Ensure that the new table is saved properly to disk so that we
can do a rename
*/
- if (ha_commit_stmt(thd))
+ if (ha_autocommit_or_rollback(thd, 0))
error=1;
- if (ha_commit(thd))
+ if (end_active_trans(thd))
error=1;
err:
@@ -7292,7 +7326,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables,
goto err;
}
- send_eof(thd);
+ my_eof(thd);
DBUG_RETURN(FALSE);
err:
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 0fe299d4505..0bce4eb4a82 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -49,14 +49,14 @@ static const char *lock_descriptions[] =
#ifndef DBUG_OFF
void
-print_where(COND *cond,const char *info)
+print_where(COND *cond,const char *info, enum_query_type query_type)
{
if (cond)
{
char buff[256];
String str(buff,(uint32) sizeof(buff), system_charset_info);
str.length(0);
- cond->print(&str);
+ cond->print(&str, query_type);
str.append('\0');
DBUG_LOCK_FILE;
(void) fprintf(DBUG_FILE,"\nWHERE:(%s) ",info);
@@ -143,7 +143,7 @@ void TEST_filesort(SORT_FIELD *sortorder,uint s_length)
else
{
str.length(0);
- sortorder->item->print(&str);
+ sortorder->item->print(&str, QT_ORDINARY);
out.append(str);
}
}
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
index 4cd1d542375..d426904e4b2 100644
--- a/sql/sql_trigger.cc
+++ b/sql/sql_trigger.cc
@@ -516,7 +516,7 @@ end:
start_waiting_global_read_lock(thd);
if (!result)
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(result);
}
diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc
index 30e8829d764..ae3f43eba5b 100644
--- a/sql/sql_udf.cc
+++ b/sql/sql_udf.cc
@@ -382,6 +382,14 @@ static udf_func *add_udf(LEX_STRING *name, Item_result ret, char *dl,
}
+/**
+ Create a user defined function.
+
+ @note Like implementations of other DDL/DML in MySQL, this function
+ relies on the caller to close the thread tables. This is done in the
+ end of dispatch_command().
+*/
+
int mysql_create_function(THD *thd,udf_func *udf)
{
int error;
@@ -489,7 +497,6 @@ int mysql_create_function(THD *thd,udf_func *udf)
table->field[3]->store((longlong) u_d->type, TRUE);
error = table->file->ha_write_row(table->record[0]);
- close_thread_tables(thd);
if (error)
{
my_error(ER_ERROR_ON_WRITE, MYF(0), "mysql.func", error);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 4d075e3308d..7c9ead7591c 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -319,7 +319,7 @@ int mysql_update(THD *thd,
if (prune_partitions(thd, table, conds))
{
free_underlaid_joins(thd, select_lex);
- send_ok(thd); // No matching records
+ my_ok(thd); // No matching records
DBUG_RETURN(0);
}
#endif
@@ -336,7 +336,7 @@ int mysql_update(THD *thd,
{
DBUG_RETURN(1); // Error in where
}
- send_ok(thd); // No matching records
+ my_ok(thd); // No matching records
DBUG_RETURN(0);
}
if (!select && limit != HA_POS_ERROR)
@@ -643,14 +643,6 @@ int mysql_update(THD *thd,
updated++;
else
error= 0;
-
- if (table->triggers &&
- table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
- TRG_ACTION_AFTER, TRUE))
- {
- error= 1;
- break;
- }
}
else if (!ignore ||
table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
@@ -669,6 +661,14 @@ int mysql_update(THD *thd,
}
}
+ if (table->triggers &&
+ table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
+ TRG_ACTION_AFTER, TRUE))
+ {
+ error= 1;
+ break;
+ }
+
if (!--limit && using_limit)
{
/*
@@ -803,17 +803,6 @@ int mysql_update(THD *thd,
}
DBUG_ASSERT(transactional_table || !updated || thd->transaction.stmt.modified_non_trans_table);
free_underlaid_joins(thd, select_lex);
- if (transactional_table)
- {
- if (ha_autocommit_or_rollback(thd, error >= 0))
- error=1;
- }
-
- if (thd->lock)
- {
- mysql_unlock_tables(thd, thd->lock);
- thd->lock=0;
- }
/* If LAST_INSERT_ID(X) was used, report X */
id= thd->arg_of_last_insert_id_function ?
@@ -826,7 +815,7 @@ int mysql_update(THD *thd,
(ulong) thd->cuted_fields);
thd->row_count_func=
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
- send_ok(thd, (ulong) thd->row_count_func, id, buff);
+ my_ok(thd, (ulong) thd->row_count_func, id, buff);
DBUG_PRINT("info",("%ld records updated", (long) updated));
}
thd->count_cuted_fields= CHECK_FIELD_IGNORE; /* calc cuted fields */
@@ -1644,12 +1633,12 @@ bool multi_update::send_data(List<Item> &not_used_values)
trans_safe= 0;
thd->transaction.stmt.modified_non_trans_table= TRUE;
}
- if (table->triggers &&
- table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
- TRG_ACTION_AFTER, TRUE))
- DBUG_RETURN(1);
}
}
+ if (table->triggers &&
+ table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
+ TRG_ACTION_AFTER, TRUE))
+ DBUG_RETURN(1);
}
else
{
@@ -1716,13 +1705,8 @@ void multi_update::abort()
If not attempt to do remaining updates.
*/
- if (trans_safe)
+ if (! trans_safe)
{
- DBUG_ASSERT(transactional_tables);
- (void) ha_autocommit_or_rollback(thd, 1);
- }
- else
- {
DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table);
if (do_update && table_count > 1)
{
@@ -1754,11 +1738,6 @@ void multi_update::abort()
thd->transaction.all.modified_non_trans_table= TRUE;
}
DBUG_ASSERT(trans_safe || !updated || thd->transaction.stmt.modified_non_trans_table);
-
- if (transactional_tables)
- {
- (void) ha_autocommit_or_rollback(thd, 1);
- }
}
@@ -1881,12 +1860,12 @@ int multi_update::do_updates()
updated++;
else
local_error= 0;
-
- if (table->triggers &&
- table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
- TRG_ACTION_AFTER, TRUE))
- goto err2;
}
+
+ if (table->triggers &&
+ table->triggers->process_triggers(thd, TRG_EVENT_UPDATE,
+ TRG_ACTION_AFTER, TRUE))
+ goto err2;
}
if (updated != org_updated)
@@ -1996,12 +1975,6 @@ bool multi_update::send_eof()
if (local_error != 0)
error_handled= TRUE; // to force early leave from ::send_error()
- if (transactional_tables)
- {
- if (ha_autocommit_or_rollback(thd, local_error != 0))
- local_error=1;
- }
-
if (local_error > 0) // if the above log write did not fail ...
{
/* Safety: If we haven't got an error before (can happen in do_updates) */
@@ -2016,6 +1989,6 @@ bool multi_update::send_eof()
(ulong) thd->cuted_fields);
thd->row_count_func=
(thd->client_capabilities & CLIENT_FOUND_ROWS) ? found : updated;
- ::send_ok(thd, (ulong) thd->row_count_func, id, buff);
+ ::my_ok(thd, (ulong) thd->row_count_func, id, buff);
DBUG_RETURN(FALSE);
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 1a4d7d515a8..a654721de37 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -182,10 +182,33 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
TABLE_LIST decoy;
memcpy (&decoy, view, sizeof (TABLE_LIST));
- if (!open_table(thd, &decoy, thd->mem_root, &not_used, OPEN_VIEW_NO_PARSE) &&
- !decoy.view)
+
+ /*
+ Let's reset decoy.view before calling open_table(): when we start
+ supporting ALTER VIEW in PS/SP that may save us from a crash.
+ */
+
+ decoy.view= NULL;
+
+ /*
+ open_table() will return NULL if 'decoy' is idenitifying a view *and*
+ there is no TABLE object for that view in the table cache. However,
+ decoy.view will be set to 1.
+
+ If there is a TABLE-instance for the oject identified by 'decoy',
+ open_table() will return that instance no matter if it is a table or
+ a view.
+
+ Thus, there is no need to check for the return value of open_table(),
+ since the return value itself does not mean anything.
+ */
+
+ open_table(thd, &decoy, thd->mem_root, &not_used, OPEN_VIEW_NO_PARSE);
+
+ if (!decoy.view)
{
- /* It's a table */
+ /* It's a table. */
+ my_error(ER_WRONG_OBJECT, MYF(0), view->db, view->table_name, "VIEW");
return TRUE;
}
@@ -204,104 +227,31 @@ fill_defined_view_parts (THD *thd, TABLE_LIST *view)
return FALSE;
}
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
/**
- Creating/altering VIEW procedure
+ @brief CREATE VIEW privileges pre-check.
@param thd thread handler
+ @param tables tables used in the view
@param views views to create
@param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
- @note This function handles both create and alter view commands.
-
@retval FALSE Operation was a success.
@retval TRUE An error occured.
*/
-bool mysql_create_view(THD *thd, TABLE_LIST *views,
- enum_view_create_mode mode)
+bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
+ enum_view_create_mode mode)
{
LEX *lex= thd->lex;
- bool link_to_local;
/* first table in list is target VIEW name => cut off it */
- TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
- TABLE_LIST *tables= lex->query_tables;
TABLE_LIST *tbl;
SELECT_LEX *select_lex= &lex->select_lex;
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
SELECT_LEX *sl;
-#endif
- SELECT_LEX_UNIT *unit= &lex->unit;
- bool res= FALSE;
- DBUG_ENTER("mysql_create_view");
-
- /* This is ensured in the parser. */
- DBUG_ASSERT(!lex->proc_list.first && !lex->result &&
- !lex->param_list.elements && !lex->derived_tables);
-
- if (mode != VIEW_CREATE_NEW)
- {
- if (mode == VIEW_ALTER &&
- fill_defined_view_parts(thd, view))
- {
- res= TRUE;
- goto err;
- }
- sp_cache_invalidate();
- }
-
- if (!lex->definer)
- {
- /*
- DEFINER-clause is missing; we have to create default definer in
- persistent arena to be PS/SP friendly.
- If this is an ALTER VIEW then the current user should be set as
- the definer.
- */
- Query_arena original_arena;
- Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
-
- if (!(lex->definer= create_default_definer(thd)))
- res= TRUE;
-
- if (ps_arena)
- thd->restore_active_arena(ps_arena, &original_arena);
+ bool res= TRUE;
+ DBUG_ENTER("create_view_precheck");
- if (res)
- goto err;
- }
-
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
- /*
- check definer of view:
- - same as current user
- - current user has SUPER_ACL
- */
- if (lex->definer &&
- (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 ||
- my_strcasecmp(system_charset_info,
- lex->definer->host.str,
- thd->security_ctx->priv_host) != 0))
- {
- if (!(thd->security_ctx->master_access & SUPER_ACL))
- {
- my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
- res= TRUE;
- goto err;
- }
- else
- {
- if (!is_acl_user(lex->definer->host.str,
- lex->definer->user.str))
- {
- push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_NO_SUCH_USER,
- ER(ER_NO_SUCH_USER),
- lex->definer->user.str,
- lex->definer->host.str);
- }
- }
- }
/*
Privilege check for view creation:
- user has CREATE VIEW privilege on view table
@@ -323,10 +273,8 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
(check_access(thd, DROP_ACL, view->db, &view->grant.privilege,
0, 0, is_schema_db(view->db)) ||
check_grant(thd, DROP_ACL, view, 0, 1, 0))))
- {
- res= TRUE;
goto err;
- }
+
for (sl= select_lex; sl; sl= sl->next_select())
{
for (tbl= sl->get_table_list(); tbl; tbl= tbl->next_local)
@@ -340,7 +288,6 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
"ANY", thd->security_ctx->priv_user,
thd->security_ctx->priv_host, tbl->table_name);
- res= TRUE;
goto err;
}
/*
@@ -376,10 +323,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
if (check_access(thd, SELECT_ACL, tbl->db,
&tbl->grant.privilege, 0, 0, test(tbl->schema_table)) ||
check_grant(thd, SELECT_ACL, tbl, 0, 1, 0))
- {
- res= TRUE;
goto err;
- }
}
}
}
@@ -403,8 +347,126 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
}
}
}
+
+ res= FALSE;
+
+err:
+ DBUG_RETURN(res || thd->is_error());
+}
+
+#else
+
+bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
+ enum_view_create_mode mode)
+{
+ return FALSE;
+}
+
#endif
+
+/**
+ @brief Creating/altering VIEW procedure
+
+ @param thd thread handler
+ @param views views to create
+ @param mode VIEW_CREATE_NEW, VIEW_ALTER, VIEW_CREATE_OR_REPLACE
+
+ @note This function handles both create and alter view commands.
+
+ @retval FALSE Operation was a success.
+ @retval TRUE An error occured.
+*/
+
+bool mysql_create_view(THD *thd, TABLE_LIST *views,
+ enum_view_create_mode mode)
+{
+ LEX *lex= thd->lex;
+ bool link_to_local;
+ /* first table in list is target VIEW name => cut off it */
+ TABLE_LIST *view= lex->unlink_first_table(&link_to_local);
+ TABLE_LIST *tables= lex->query_tables;
+ TABLE_LIST *tbl;
+ SELECT_LEX *select_lex= &lex->select_lex;
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ SELECT_LEX *sl;
+#endif
+ SELECT_LEX_UNIT *unit= &lex->unit;
+ bool res= FALSE;
+ DBUG_ENTER("mysql_create_view");
+
+ /* This is ensured in the parser. */
+ DBUG_ASSERT(!lex->proc_list.first && !lex->result &&
+ !lex->param_list.elements);
+
+ if (mode != VIEW_CREATE_NEW)
+ {
+ if (mode == VIEW_ALTER &&
+ fill_defined_view_parts(thd, view))
+ {
+ res= TRUE;
+ goto err;
+ }
+ sp_cache_invalidate();
+ }
+
+ if (!lex->definer)
+ {
+ /*
+ DEFINER-clause is missing; we have to create default definer in
+ persistent arena to be PS/SP friendly.
+ If this is an ALTER VIEW then the current user should be set as
+ the definer.
+ */
+ Query_arena original_arena;
+ Query_arena *ps_arena = thd->activate_stmt_arena_if_needed(&original_arena);
+
+ if (!(lex->definer= create_default_definer(thd)))
+ res= TRUE;
+
+ if (ps_arena)
+ thd->restore_active_arena(ps_arena, &original_arena);
+
+ if (res)
+ goto err;
+ }
+
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+ /*
+ check definer of view:
+ - same as current user
+ - current user has SUPER_ACL
+ */
+ if (lex->definer &&
+ (strcmp(lex->definer->user.str, thd->security_ctx->priv_user) != 0 ||
+ my_strcasecmp(system_charset_info,
+ lex->definer->host.str,
+ thd->security_ctx->priv_host) != 0))
+ {
+ if (!(thd->security_ctx->master_access & SUPER_ACL))
+ {
+ my_error(ER_SPECIFIC_ACCESS_DENIED_ERROR, MYF(0), "SUPER");
+ res= TRUE;
+ goto err;
+ }
+ else
+ {
+ if (!is_acl_user(lex->definer->host.str,
+ lex->definer->user.str))
+ {
+ push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_NO_SUCH_USER,
+ ER(ER_NO_SUCH_USER),
+ lex->definer->user.str,
+ lex->definer->host.str);
+ }
+ }
+ }
+#endif
+
+ if ((res= create_view_precheck(thd, tables, view, mode)))
+ goto err;
+
if (open_and_lock_tables(thd, tables))
{
res= TRUE;
@@ -599,7 +661,7 @@ bool mysql_create_view(THD *thd, TABLE_LIST *views,
if (res)
goto err;
- send_ok(thd);
+ my_ok(thd);
lex->link_first_table_back(view, link_to_local);
DBUG_RETURN(0);
@@ -696,8 +758,42 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode)
{
LEX *lex= thd->lex;
- char buff[4096];
- String view_query(buff, sizeof (buff), thd->charset());
+
+ /*
+ View definition query -- a SELECT statement that fully defines view. It
+ is generated from the Item-tree built from the original (specified by
+ the user) query. The idea is that generated query should eliminates all
+ ambiguities and fix view structure at CREATE-time (once for all).
+ Item::print() virtual operation is used to generate view definition
+ query.
+
+ INFORMATION_SCHEMA query (IS query) -- a SQL statement describing a
+ view that is shown in INFORMATION_SCHEMA. Basically, it is 'view
+ definition query' with text literals converted to UTF8 and without
+ character set introducers.
+
+ For example:
+ Let's suppose we have:
+ CREATE TABLE t1(a INT, b INT);
+ User specified query:
+ CREATE VIEW v1(x, y) AS SELECT * FROM t1;
+ Generated query:
+ SELECT a AS x, b AS y FROM t1;
+ IS query:
+ SELECT a AS x, b AS y FROM t1;
+
+ View definition query is stored in the client character set.
+ */
+ char view_query_buff[4096];
+ String view_query(view_query_buff,
+ sizeof (view_query_buff),
+ thd->charset());
+
+ char is_query_buff[4096];
+ String is_query(is_query_buff,
+ sizeof (is_query_buff),
+ system_charset_info);
+
char md5[MD5_BUFF_LENGTH];
bool can_be_merged;
char dir_buff[FN_REFLEN], path_buff[FN_REFLEN];
@@ -705,12 +801,16 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
int error= 0;
DBUG_ENTER("mysql_register_view");
- /* print query */
+ /* Generate view definition and IS queries. */
view_query.length(0);
+ is_query.length(0);
{
ulong sql_mode= thd->variables.sql_mode & MODE_ANSI_QUOTES;
thd->variables.sql_mode&= ~MODE_ANSI_QUOTES;
- lex->unit.print(&view_query);
+
+ lex->unit.print(&view_query, QT_ORDINARY);
+ lex->unit.print(&is_query, QT_IS);
+
thd->variables.sql_mode|= sql_mode;
}
DBUG_PRINT("info", ("View: %s", view_query.ptr()));
@@ -718,11 +818,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
/* fill structure */
view->select_stmt.str= view_query.c_ptr_safe();
view->select_stmt.length= view_query.length();
-
- view->source.str= (char*) thd->lex->create_view_select_start;
- view->source.length= (thd->lex->create_view_select_end
- - thd->lex->create_view_select_start);
- trim_whitespace(thd->charset(), & view->source);
+ view->source= thd->lex->create_view_select;
view->file_version= 1;
view->calc_md5(md5);
@@ -853,7 +949,8 @@ loop_out:
lex_string_set(&view->view_connection_cl_name,
view->view_creation_ctx->get_connection_cl()->name);
- view->view_body_utf8= lex->view_body_utf8;
+ view->view_body_utf8.str= is_query.c_ptr_safe();
+ view->view_body_utf8.length= is_query.length();
/*
Check that table of main select do not used in subqueries.
@@ -1552,7 +1649,7 @@ bool mysql_drop_view(THD *thd, TABLE_LIST *views, enum_drop_mode drop_mode)
{
DBUG_RETURN(TRUE);
}
- send_ok(thd);
+ my_ok(thd);
DBUG_RETURN(FALSE);
}
@@ -1581,7 +1678,7 @@ frm_type_enum mysql_frm_type(THD *thd, char *path, enum legacy_db_type *dbt)
if ((file= my_open(path, O_RDONLY | O_SHARE, MYF(0))) < 0)
DBUG_RETURN(FRMTYPE_ERROR);
- error= my_read(file, (uchar*) header, sizeof(header), MYF(MY_WME | MY_NABP));
+ error= my_read(file, (uchar*) header, sizeof(header), MYF(MY_NABP));
my_close(file, MYF(MY_WME));
if (error)
diff --git a/sql/sql_view.h b/sql/sql_view.h
index d3c83c82f44..b8138663489 100644
--- a/sql/sql_view.h
+++ b/sql/sql_view.h
@@ -15,6 +15,9 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+bool create_view_precheck(THD *thd, TABLE_LIST *tables, TABLE_LIST *view,
+ enum_view_create_mode mode);
+
bool mysql_create_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index c98228424a5..1bd90e74f47 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -8219,10 +8219,10 @@ limit_options:
;
limit_option:
- param_marker
- {
- ((Item_param *) $1)->set_strict_type(INT_RESULT);
- }
+ param_marker
+ {
+ ((Item_param *) $1)->limit_clause_param= TRUE;
+ }
| ULONGLONG_NUM { $$= new Item_uint($1.str, $1.length); }
| LONG_NUM { $$= new Item_uint($1.str, $1.length); }
| NUM { $$= new Item_uint($1.str, $1.length); }
@@ -9823,8 +9823,11 @@ text_literal:
}
| UNDERSCORE_CHARSET TEXT_STRING
{
- $$= new Item_string($2.str, $2.length, $1);
- ((Item_string*) $$)->set_repertoire_from_value();
+ Item_string *str= new Item_string($2.str, $2.length, $1);
+ str->set_repertoire_from_value();
+ str->set_cs_specified(TRUE);
+
+ $$= str;
}
| text_literal TEXT_STRING_literal
{
@@ -9927,15 +9930,22 @@ literal:
String *str= tmp ?
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
(String*) 0;
- $$= new Item_string(NULL, /* name will be set in select_item */
- str ? str->ptr() : "",
- str ? str->length() : 0,
- $1);
- if (!$$ || !$$->check_well_formed_result(&$$->str_value, TRUE))
+
+ Item_string *item_str=
+ new Item_string(NULL, /* name will be set in select_item */
+ str ? str->ptr() : "",
+ str ? str->length() : 0,
+ $1);
+ if (!item_str ||
+ !item_str->check_well_formed_result(&item_str->str_value, TRUE))
{
MYSQL_YYABORT;
}
- ((Item_string *) $$)->set_repertoire_from_value();
+
+ item_str->set_repertoire_from_value();
+ item_str->set_cs_specified(TRUE);
+
+ $$= item_str;
}
| UNDERSCORE_CHARSET BIN_NUM
{
@@ -9947,14 +9957,21 @@ literal:
String *str= tmp ?
tmp->quick_fix_field(), tmp->val_str((String*) 0) :
(String*) 0;
- $$= new Item_string(NULL, /* name will be set in select_item */
- str ? str->ptr() : "",
- str ? str->length() : 0,
- $1);
- if (!$$ || !$$->check_well_formed_result(&$$->str_value, TRUE))
+
+ Item_string *item_str=
+ new Item_string(NULL, /* name will be set in select_item */
+ str ? str->ptr() : "",
+ str ? str->length() : 0,
+ $1);
+ if (!item_str ||
+ !item_str->check_well_formed_result(&item_str->str_value, TRUE))
{
MYSQL_YYABORT;
}
+
+ item_str->set_cs_specified(TRUE);
+
+ $$= item_str;
}
| DATE_SYM text_literal { $$ = $2; }
| TIME_SYM text_literal { $$ = $2; }
@@ -10295,12 +10312,6 @@ TEXT_STRING_filesystem:
ident:
IDENT_sys { $$=$1; }
- | READ_ONLY_SYM
- {
- THD *thd= YYTHD;
- $$.str= thd->strmake("read_only",9);
- $$.length= 9;
- }
| keyword
{
THD *thd= YYTHD;
@@ -10605,6 +10616,7 @@ keyword_sp:
| QUARTER_SYM {}
| QUERY_SYM {}
| QUICK {}
+ | READ_ONLY_SYM {}
| REBUILD_SYM {}
| RECOVER_SYM {}
| REDO_BUFFER_SIZE_SYM {}
@@ -11988,27 +12000,7 @@ view_tail:
if (!lex->select_lex.add_table_to_list(thd, $3, NULL, TL_OPTION_UPDATING))
MYSQL_YYABORT;
}
- view_list_opt AS
- {
- THD *thd= YYTHD;
- Lex_input_stream *lip= thd->m_lip;
-
- lip->body_utf8_start(thd, lip->get_cpp_ptr());
- }
- view_select
- {
- THD *thd= YYTHD;
- LEX *lex= thd->lex;
- Lex_input_stream *lip= thd->m_lip;
-
- lip->body_utf8_append(lip->get_cpp_ptr());
-
- lex->view_body_utf8.str= thd->strmake(lip->get_body_utf8_str(),
- lip->get_body_utf8_length());
- lex->view_body_utf8.length= lip->get_body_utf8_length();
-
- trim_whitespace(&my_charset_utf8_general_ci, &lex->view_body_utf8);
- }
+ view_list_opt AS view_select
;
view_list_opt:
@@ -12039,18 +12031,22 @@ view_select:
lex->parsing_options.allows_select_into= FALSE;
lex->parsing_options.allows_select_procedure= FALSE;
lex->parsing_options.allows_derived= FALSE;
- lex->create_view_select_start= lip->get_cpp_ptr();
+ lex->create_view_select.str= (char *) lip->get_cpp_ptr();
}
view_select_aux view_check_option
{
THD *thd= YYTHD;
LEX *lex= Lex;
Lex_input_stream *lip= thd->m_lip;
+ uint len= lip->get_cpp_ptr() - lex->create_view_select.str;
+ void *create_view_select= thd->memdup(lex->create_view_select.str, len);
+ lex->create_view_select.length= len;
+ lex->create_view_select.str= (char *) create_view_select;
+ trim_whitespace(thd->charset(), &lex->create_view_select);
lex->parsing_options.allows_variable= TRUE;
lex->parsing_options.allows_select_into= TRUE;
lex->parsing_options.allows_select_procedure= TRUE;
lex->parsing_options.allows_derived= TRUE;
- lex->create_view_select_end= lip->get_cpp_ptr();
}
;
diff --git a/sql/stacktrace.c b/sql/stacktrace.c
index 3d718dfd9d2..5c3411aa8b1 100644
--- a/sql/stacktrace.c
+++ b/sql/stacktrace.c
@@ -13,12 +13,16 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+/* Workaround for Bug#32082: VOID redefinition on Win results in compile errors*/
+#define DONT_DEFINE_VOID 1
+
#include <my_global.h>
#include "stacktrace.h"
+
+#ifndef __WIN__
#include <signal.h>
#include <my_pthread.h>
#include <m_string.h>
-
#ifdef HAVE_STACKTRACE
#include <unistd.h>
#include <strings.h>
@@ -167,10 +171,7 @@ void print_stacktrace(uchar* stack_bottom, ulong thread_stack)
#endif
LINT_INIT(fp);
- fprintf(stderr,"\
-Attempting backtrace. You can use the following information to find out\n\
-where mysqld died. If you see no messages after this, something went\n\
-terribly wrong...\n");
+
#ifdef __i386__
__asm __volatile__ ("movl %%ebp,%0"
:"=r"(fp)
@@ -308,3 +309,267 @@ void write_core(int sig)
#endif
}
#endif
+#else /* __WIN__*/
+
+#include <dbghelp.h>
+
+/*
+ Stack tracing on Windows is implemented using Debug Helper library(dbghelp.dll)
+ We do not redistribute dbghelp and the one comes with older OS (up to Windows 2000)
+ is missing some important functions like functions StackWalk64 or MinidumpWriteDump.
+ Hence, we have to load functions at runtime using LoadLibrary/GetProcAddress.
+*/
+
+typedef DWORD (WINAPI *SymSetOptions_FctType)(DWORD dwOptions);
+typedef BOOL (WINAPI *SymGetModuleInfo64_FctType)
+ (HANDLE,DWORD64,PIMAGEHLP_MODULE64) ;
+typedef BOOL (WINAPI *SymGetSymFromAddr64_FctType)
+ (HANDLE,DWORD64,PDWORD64,PIMAGEHLP_SYMBOL64) ;
+typedef BOOL (WINAPI *SymGetLineFromAddr64_FctType)
+ (HANDLE,DWORD64,PDWORD,PIMAGEHLP_LINE64);
+typedef BOOL (WINAPI *SymInitialize_FctType)
+ (HANDLE,PSTR,BOOL);
+typedef BOOL (WINAPI *StackWalk64_FctType)
+ (DWORD,HANDLE,HANDLE,LPSTACKFRAME64,PVOID,PREAD_PROCESS_MEMORY_ROUTINE64,
+ PFUNCTION_TABLE_ACCESS_ROUTINE64,PGET_MODULE_BASE_ROUTINE64 ,
+ PTRANSLATE_ADDRESS_ROUTINE64);
+typedef BOOL (WINAPI *MiniDumpWriteDump_FctType)(
+ IN HANDLE hProcess,
+ IN DWORD ProcessId,
+ IN HANDLE hFile,
+ IN MINIDUMP_TYPE DumpType,
+ IN CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, OPTIONAL
+ IN CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, OPTIONAL
+ IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL
+ );
+
+static SymSetOptions_FctType pSymSetOptions;
+static SymGetModuleInfo64_FctType pSymGetModuleInfo64;
+static SymGetSymFromAddr64_FctType pSymGetSymFromAddr64;
+static SymInitialize_FctType pSymInitialize;
+static StackWalk64_FctType pStackWalk64;
+static SymGetLineFromAddr64_FctType pSymGetLineFromAddr64;
+static MiniDumpWriteDump_FctType pMiniDumpWriteDump;
+
+static EXCEPTION_POINTERS *exception_ptrs;
+
+#define MODULE64_SIZE_WINXP 576
+#define STACKWALK_MAX_FRAMES 64
+
+/*
+ Dynamically load dbghelp functions
+*/
+BOOL init_dbghelp_functions()
+{
+ static BOOL first_time= TRUE;
+ static BOOL rc;
+ HMODULE hDbghlp;
+
+ if(first_time)
+ {
+ first_time= FALSE;
+ hDbghlp= LoadLibrary("dbghelp");
+ if(!hDbghlp)
+ {
+ rc= FALSE;
+ return rc;
+ }
+ pSymSetOptions= (SymSetOptions_FctType)
+ GetProcAddress(hDbghlp,"SymSetOptions");
+ pSymInitialize= (SymInitialize_FctType)
+ GetProcAddress(hDbghlp,"SymInitialize");
+ pSymGetModuleInfo64= (SymGetModuleInfo64_FctType)
+ GetProcAddress(hDbghlp,"SymGetModuleInfo64");
+ pSymGetLineFromAddr64= (SymGetLineFromAddr64_FctType)
+ GetProcAddress(hDbghlp,"SymGetLineFromAddr64");
+ pSymGetSymFromAddr64=(SymGetSymFromAddr64_FctType)
+ GetProcAddress(hDbghlp,"SymGetSymFromAddr64");
+ pStackWalk64= (StackWalk64_FctType)
+ GetProcAddress(hDbghlp,"StackWalk64");
+ pMiniDumpWriteDump = (MiniDumpWriteDump_FctType)
+ GetProcAddress(hDbghlp,"MiniDumpWriteDump");
+
+ rc = (BOOL)(pSymSetOptions && pSymInitialize && pSymGetModuleInfo64
+ && pSymGetLineFromAddr64 && pSymGetSymFromAddr64 && pStackWalk64);
+ }
+ return rc;
+}
+
+void set_exception_pointers(EXCEPTION_POINTERS *ep)
+{
+ exception_ptrs = ep;
+}
+
+/* Platform SDK in VS2003 does not have definition for SYMOPT_NO_PROMPTS*/
+#ifndef SYMOPT_NO_PROMPTS
+#define SYMOPT_NO_PROMPTS 0
+#endif
+
+void print_stacktrace(uchar* unused1, ulong unused2)
+{
+ HANDLE hProcess= GetCurrentProcess();
+ HANDLE hThread= GetCurrentThread();
+ static IMAGEHLP_MODULE64 module= {sizeof(module)};
+ static IMAGEHLP_SYMBOL64_PACKAGE package;
+ DWORD64 addr;
+ DWORD machine;
+ int i;
+ CONTEXT context;
+ STACKFRAME64 frame={0};
+
+ if(!exception_ptrs || !init_dbghelp_functions())
+ return;
+
+ /* Copy context, as stackwalking on original will unwind the stack */
+ context = *(exception_ptrs->ContextRecord);
+ /*Initialize symbols.*/
+ pSymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_NO_PROMPTS|SYMOPT_DEFERRED_LOADS|SYMOPT_DEBUG);
+ pSymInitialize(hProcess,NULL,TRUE);
+
+ /*Prepare stackframe for the first StackWalk64 call*/
+ frame.AddrFrame.Mode= frame.AddrPC.Mode= frame.AddrStack.Mode= AddrModeFlat;
+#if (defined _M_IX86)
+ machine= IMAGE_FILE_MACHINE_I386;
+ frame.AddrFrame.Offset= context.Ebp;
+ frame.AddrPC.Offset= context.Eip;
+ frame.AddrStack.Offset= context.Esp;
+#elif (defined _M_X64)
+ machine = IMAGE_FILE_MACHINE_AMD64;
+ frame.AddrFrame.Offset= context.Rbp;
+ frame.AddrPC.Offset= context.Rip;
+ frame.AddrStack.Offset= context.Rsp;
+#else
+ /*There is currently no need to support IA64*/
+#pragma error ("unsupported architecture")
+#endif
+
+ package.sym.SizeOfStruct= sizeof(package.sym);
+ package.sym.MaxNameLength= sizeof(package.name);
+
+ /*Walk the stack, output useful information*/
+ for(i= 0; i< STACKWALK_MAX_FRAMES;i++)
+ {
+ DWORD64 function_offset= 0;
+ DWORD line_offset= 0;
+ IMAGEHLP_LINE64 line= {sizeof(line)};
+ BOOL have_module= FALSE;
+ BOOL have_symbol= FALSE;
+ BOOL have_source= FALSE;
+
+ if(!pStackWalk64(machine, hProcess, hThread, &frame, &context, 0, 0, 0 ,0))
+ break;
+ addr= frame.AddrPC.Offset;
+
+ have_module= pSymGetModuleInfo64(hProcess,addr,&module);
+#ifdef _M_IX86
+ if(!have_module)
+ {
+ /*
+ ModuleInfo structure has been "compatibly" extended in releases after XP,
+ and its size was increased. To make XP dbghelp.dll function
+ happy, pretend passing the old structure.
+ */
+ module.SizeOfStruct= MODULE64_SIZE_WINXP;
+ have_module= pSymGetModuleInfo64(hProcess, addr, &module);
+ }
+#endif
+
+ have_symbol= pSymGetSymFromAddr64(hProcess, addr, &function_offset,
+ &(package.sym));
+ have_source= pSymGetLineFromAddr64(hProcess, addr, &line_offset, &line);
+
+ fprintf(stderr, "%p ", addr);
+ if(have_module)
+ {
+ char *base_image_name= strrchr(module.ImageName, '\\');
+ if(base_image_name)
+ base_image_name++;
+ else
+ base_image_name= module.ImageName;
+ fprintf(stderr, "%s!", base_image_name);
+ }
+ if(have_symbol)
+ fprintf(stderr, "%s()", package.sym.Name);
+ else if(have_module)
+ fprintf(stderr, "???");
+
+ if(have_source)
+ {
+ char *base_file_name= strrchr(line.FileName, '\\');
+ if(base_file_name)
+ base_file_name++;
+ else
+ base_file_name= line.FileName;
+ fprintf(stderr,"[%s:%u]", base_file_name, line.LineNumber);
+ }
+ fprintf(stderr, "\n");
+ }
+ fflush(stderr);
+}
+
+
+/*
+ Write dump. The dump is created in current directory,
+ file name is constructed from executable name plus
+ ".dmp" extension
+*/
+void write_core(int unused)
+{
+ char path[MAX_PATH];
+ char dump_fname[MAX_PATH]= "core.dmp";
+ MINIDUMP_EXCEPTION_INFORMATION info;
+ HANDLE hFile;
+
+ if(!exception_ptrs || !init_dbghelp_functions() || !pMiniDumpWriteDump)
+ return;
+
+ info.ExceptionPointers= exception_ptrs;
+ info.ClientPointers= FALSE;
+ info.ThreadId= GetCurrentThreadId();
+
+ if(GetModuleFileName(NULL, path, sizeof(path)))
+ {
+ _splitpath(path, NULL, NULL,dump_fname,NULL);
+ strncat(dump_fname, ".dmp", sizeof(dump_fname));
+ }
+
+ hFile= CreateFile(dump_fname, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ if(hFile)
+ {
+ /* Create minidump */
+ if(pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
+ hFile, MiniDumpNormal, &info, 0, 0))
+ {
+ fprintf(stderr, "Minidump written to %s\n",
+ _fullpath(path, dump_fname, sizeof(path)) ? path : dump_fname);
+ }
+ else
+ {
+ fprintf(stderr,"MiniDumpWriteDump() failed, last error %u\n",
+ GetLastError());
+ }
+ CloseHandle(hFile);
+ }
+ else
+ {
+ fprintf(stderr, "CreateFile(%s) failed, last error %u\n", dump_fname,
+ GetLastError());
+ }
+ fflush(stderr);
+}
+
+
+void safe_print_str(const char *name, const char *val, int len)
+{
+ fprintf(stderr,"%s at %p", name, val);
+ __try
+ {
+ fprintf(stderr,"=%.*s\n", len, val);
+ }
+ __except(EXCEPTION_EXECUTE_HANDLER)
+ {
+ fprintf(stderr,"is an invalid string pointer\n");
+ }
+}
+#endif /*__WIN__*/
diff --git a/sql/stacktrace.h b/sql/stacktrace.h
index 96c09a21ad6..498f4f197fc 100644
--- a/sql/stacktrace.h
+++ b/sql/stacktrace.h
@@ -36,19 +36,33 @@ extern char* heap_start;
#define init_stacktrace() do { \
heap_start = (char*) &__bss_start; \
} while(0);
+void check_thread_lib(void);
+#endif /* defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
+#elif defined (__WIN__)
+#define HAVE_STACKTRACE
+extern void set_exception_pointers(EXCEPTION_POINTERS *ep);
+#define init_stacktrace() {}
+#endif
+
+#ifdef HAVE_STACKTRACE
void print_stacktrace(uchar* stack_bottom, ulong thread_stack);
void safe_print_str(const char* name, const char* val, int max_len);
-#endif /* (defined (__i386__) || (defined(__alpha__) && defined(__GNUC__))) */
-#endif /* TARGET_OS_LINUX */
-
+#else
/* Define empty prototypes for functions that are not implemented */
-#ifndef HAVE_STACKTRACE
#define init_stacktrace() {}
#define print_stacktrace(A,B) {}
#define safe_print_str(A,B,C) {}
#endif /* HAVE_STACKTRACE */
+
+#if !defined(__NETWARE__)
+#define HAVE_WRITE_CORE
+#endif
+
+#ifdef HAVE_WRITE_CORE
void write_core(int sig);
+#endif
+
#ifdef __cplusplus
}
diff --git a/sql/table.h b/sql/table.h
index 284885658e0..941964ee24e 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -1148,7 +1148,7 @@ struct TABLE_LIST
return derived || view || schema_table || create && !table->db_stat ||
!table;
}
- void print(THD *thd, String *str);
+ void print(THD *thd, String *str, enum_query_type query_type);
bool check_single_table(TABLE_LIST **table, table_map map,
TABLE_LIST *view);
bool set_insert_values(MEM_ROOT *mem_root);