summaryrefslogtreecommitdiff
path: root/sql/sql_lex.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_lex.cc')
-rw-r--r--sql/sql_lex.cc387
1 files changed, 334 insertions, 53 deletions
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index f5c41b30659..7f395bb5811 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -1,5 +1,4 @@
-/*
- Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -12,20 +11,25 @@
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-*/
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* A lexical scanner on a temporary buffer with a yacc interface */
#define MYSQL_LEX 1
-#include "mysql_priv.h"
+#include "sql_priv.h"
+#include "unireg.h" // REQUIRED: for other includes
+#include "sql_class.h" // sql_lex.h: SQLCOM_END
+#include "sql_lex.h"
+#include "sql_parse.h" // add_to_list
#include "item_create.h"
#include <m_ctype.h>
#include <hash.h>
#include "sp.h"
#include "sp_head.h"
+static int lex_one_token(void *arg, void *yythd);
+
/*
We are using pointer to this variable for distinguishing between assignment
to NEW row field (when parsing trigger definition) and structured variable.
@@ -33,7 +37,33 @@
sys_var *trg_new_row_fake_var= (sys_var*) 0x01;
+/**
+ LEX_STRING constant for null-string to be used in parser and other places.
+*/
+const LEX_STRING null_lex_str= {NULL, 0};
+const LEX_STRING empty_lex_str= {(char *) "", 0};
+/**
+ @note The order of the elements of this array must correspond to
+ the order of elements in enum_binlog_stmt_unsafe.
+*/
+const int
+Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
+{
+ ER_BINLOG_UNSAFE_LIMIT,
+ ER_BINLOG_UNSAFE_INSERT_DELAYED,
+ ER_BINLOG_UNSAFE_SYSTEM_TABLE,
+ ER_BINLOG_UNSAFE_AUTOINC_COLUMNS,
+ ER_BINLOG_UNSAFE_UDF,
+ ER_BINLOG_UNSAFE_SYSTEM_VARIABLE,
+ ER_BINLOG_UNSAFE_SYSTEM_FUNCTION,
+ ER_BINLOG_UNSAFE_NONTRANS_AFTER_TRANS,
+ ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE,
+ ER_BINLOG_UNSAFE_MIXED_STATEMENT,
+};
+
+
/* Longest standard keyword name */
+
#define TOCK_NAME_LENGTH 24
/*
@@ -113,7 +143,18 @@ st_parsing_options::reset()
}
-bool Lex_input_stream::init(THD *thd, char *buff, unsigned int length)
+/**
+ Perform initialization of Lex_input_stream instance.
+
+ Basically, a buffer for pre-processed query. This buffer should be large
+ enough to keep multi-statement query. The allocation is done once in
+ Lex_input_stream::init() in order to prevent memory pollution when
+ the server is processing large multi-statement queries.
+*/
+
+bool Lex_input_stream::init(THD *thd,
+ char* buff,
+ unsigned int length)
{
DBUG_EXECUTE_IF("bug42064_simulate_oom",
DBUG_SET("+d,simulate_out_of_memory"););
@@ -126,19 +167,54 @@ bool Lex_input_stream::init(THD *thd, char *buff, unsigned int length)
if (m_cpp_buf == NULL)
return TRUE;
- m_cpp_ptr= m_cpp_buf;
m_thd= thd;
- m_ptr= buff;
- m_end_of_query= buff + length;
- m_buf= buff;
- m_buf_length= length;
- ignore_space= test(thd->variables.sql_mode & MODE_IGNORE_SPACE);
+ reset(buff, length);
return FALSE;
}
/**
+ Prepare Lex_input_stream instance state for use for handling next SQL statement.
+
+ It should be called between two statements in a multi-statement query.
+ The operation resets the input stream to the beginning-of-parse state,
+ but does not reallocate m_cpp_buf.
+*/
+
+void
+Lex_input_stream::reset(char *buffer, unsigned int length)
+{
+ yylineno= 1;
+ yytoklen= 0;
+ yylval= NULL;
+ lookahead_token= -1;
+ lookahead_yylval= NULL;
+ m_ptr= buffer;
+ m_tok_start= NULL;
+ m_tok_end= NULL;
+ m_end_of_query= buffer + length;
+ m_tok_start_prev= NULL;
+ m_buf= buffer;
+ m_buf_length= length;
+ m_echo= TRUE;
+ m_cpp_tok_start= NULL;
+ m_cpp_tok_start_prev= NULL;
+ m_cpp_tok_end= NULL;
+ m_body_utf8= NULL;
+ m_cpp_utf8_processed_ptr= NULL;
+ next_state= MY_LEX_START;
+ found_semicolon= NULL;
+ ignore_space= test(m_thd->variables.sql_mode & MODE_IGNORE_SPACE);
+ stmt_prepare_mode= FALSE;
+ multi_statements= TRUE;
+ in_comment=NO_COMMENT;
+ m_underscore_cs= NULL;
+ m_cpp_ptr= m_cpp_buf;
+}
+
+
+/**
The operation is called from the parser in order to
1) designate the intention to have utf8 body;
1) Indicate to the lexer that we will need a utf8 representation of this
@@ -309,7 +385,6 @@ void lex_start(THD *thd)
lex->subqueries= FALSE;
lex->context_analysis_only= 0;
lex->derived_tables= 0;
- lex->lock_option= TL_READ;
lex->safe_to_cache_query= 1;
lex->leaf_tables_insert= 0;
lex->parsing_options.reset();
@@ -322,12 +397,12 @@ void lex_start(THD *thd)
lex->select_lex.ftfunc_list= &lex->select_lex.ftfunc_list_alloc;
lex->select_lex.group_list.empty();
lex->select_lex.order_list.empty();
- lex->sql_command= SQLCOM_END;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
lex->spname= NULL;
lex->sphead= NULL;
lex->spcont= NULL;
+ lex->m_stmt= NULL;
lex->proc_list.first= 0;
lex->escape_used= FALSE;
lex->query_tables= 0;
@@ -342,7 +417,6 @@ void lex_start(THD *thd)
lex->nest_level=0 ;
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
- lex->protect_against_global_read_lock= FALSE;
/*
ok, there must be a better solution for this, long-term
I tried "bzero" in the sql_yacc.yy code, but that for
@@ -369,10 +443,16 @@ void lex_end(LEX *lex)
DBUG_PRINT("enter", ("lex: 0x%lx", (long) lex));
/* release used plugins */
- plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer,
- lex->plugins.elements);
+ if (lex->plugins.elements) /* No function call and no mutex if no plugins. */
+ {
+ plugin_unlock_list(0, (plugin_ref*)lex->plugins.buffer,
+ lex->plugins.elements);
+ }
reset_dynamic(&lex->plugins);
+ delete lex->sphead;
+ lex->sphead= NULL;
+
DBUG_VOID_RETURN;
}
@@ -380,8 +460,8 @@ Yacc_state::~Yacc_state()
{
if (yacc_yyss)
{
- my_free(yacc_yyss, MYF(0));
- my_free(yacc_yyvs, MYF(0));
+ my_free(yacc_yyss);
+ my_free(yacc_yyvs);
}
}
@@ -774,6 +854,60 @@ bool consume_comment(Lex_input_stream *lip, int remaining_recursions_permitted)
int MYSQLlex(void *arg, void *yythd)
{
+ THD *thd= (THD *)yythd;
+ Lex_input_stream *lip= & thd->m_parser_state->m_lip;
+ YYSTYPE *yylval=(YYSTYPE*) arg;
+ int token;
+
+ if (lip->lookahead_token >= 0)
+ {
+ /*
+ The next token was already parsed in advance,
+ return it.
+ */
+ token= lip->lookahead_token;
+ lip->lookahead_token= -1;
+ *yylval= *(lip->lookahead_yylval);
+ lip->lookahead_yylval= NULL;
+ return token;
+ }
+
+ token= lex_one_token(arg, yythd);
+
+ switch(token) {
+ case WITH:
+ /*
+ Parsing 'WITH' 'ROLLUP' or 'WITH' 'CUBE' requires 2 look ups,
+ which makes the grammar LALR(2).
+ Replace by a single 'WITH_ROLLUP' or 'WITH_CUBE' token,
+ to transform the grammar into a LALR(1) grammar,
+ which sql_yacc.yy can process.
+ */
+ token= lex_one_token(arg, yythd);
+ switch(token) {
+ case CUBE_SYM:
+ return WITH_CUBE_SYM;
+ case ROLLUP_SYM:
+ return WITH_ROLLUP_SYM;
+ default:
+ /*
+ Save the token following 'WITH'
+ */
+ lip->lookahead_yylval= lip->yylval;
+ lip->yylval= NULL;
+ lip->lookahead_token= token;
+ return WITH;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return token;
+}
+
+int lex_one_token(void *arg, void *yythd)
+{
reg1 uchar c= 0;
bool comment_closed;
int tokval, result_state;
@@ -1499,7 +1633,7 @@ Alter_info::Alter_info(const Alter_info &rhs, MEM_ROOT *mem_root)
keys_onoff(rhs.keys_onoff),
tablespace_op(rhs.tablespace_op),
partition_names(rhs.partition_names, mem_root),
- no_parts(rhs.no_parts),
+ num_parts(rhs.num_parts),
change_level(rhs.change_level),
datetime_field(rhs.datetime_field),
error_if_not_empty(rhs.error_if_not_empty)
@@ -1609,7 +1743,6 @@ void st_select_lex::init_query()
parent_lex->push_context(&context);
cond_count= between_count= with_wild= 0;
max_equal_elems= 0;
- conds_processed_with_permanent_arena= 0;
ref_pointer_array= 0;
select_n_where_fields= 0;
select_n_having_items= 0;
@@ -1622,7 +1755,6 @@ void st_select_lex::init_query()
exclude_from_table_unique_test= no_wrap_view_item= FALSE;
nest_level= 0;
link_next= 0;
- lock_option= TL_READ_DEFAULT;
}
void st_select_lex::init_select()
@@ -1868,6 +2000,7 @@ TABLE_LIST *st_select_lex_node::add_table_to_list (THD *thd, Table_ident *table,
LEX_STRING *alias,
ulong table_join_options,
thr_lock_type flags,
+ enum_mdl_type mdl_type,
List<Index_hint> *hints,
LEX_STRING *option)
{
@@ -2093,7 +2226,7 @@ void st_select_lex::print_limit(THD *thd,
to implement the clean up.
*/
-void st_lex::cleanup_lex_after_parse_error(THD *thd)
+void LEX::cleanup_lex_after_parse_error(THD *thd)
{
/*
Delete sphead for the side effect of restoring of the original
@@ -2133,6 +2266,7 @@ void st_lex::cleanup_lex_after_parse_error(THD *thd)
void Query_tables_list::reset_query_tables_list(bool init)
{
+ sql_command= SQLCOM_END;
if (!init && query_tables)
{
TABLE_LIST *table= query_tables;
@@ -2153,7 +2287,7 @@ void Query_tables_list::reset_query_tables_list(bool init)
We delay real initialization of hash (and therefore related
memory allocation) until first insertion into this hash.
*/
- hash_clear(&sroutines);
+ my_hash_clear(&sroutines);
}
else if (sroutines.records)
{
@@ -2164,6 +2298,7 @@ void Query_tables_list::reset_query_tables_list(bool init)
sroutines_list_own_last= sroutines_list.next;
sroutines_list_own_elements= 0;
binlog_stmt_flags= 0;
+ stmt_accessed_table_flag= 0;
}
@@ -2176,7 +2311,7 @@ void Query_tables_list::reset_query_tables_list(bool init)
void Query_tables_list::destroy_query_tables_list()
{
- hash_free(&sroutines);
+ my_hash_free(&sroutines);
}
@@ -2184,7 +2319,7 @@ void Query_tables_list::destroy_query_tables_list()
Initialize LEX object.
SYNOPSIS
- st_lex::st_lex()
+ LEX::LEX()
NOTE
LEX object initialized with this constructor can be used as part of
@@ -2194,9 +2329,8 @@ void Query_tables_list::destroy_query_tables_list()
for this.
*/
-st_lex::st_lex()
- :result(0),
- sql_command(SQLCOM_END), option_type(OPT_DEFAULT), is_lex_started(0)
+LEX::LEX()
+ :result(0), option_type(OPT_DEFAULT), is_lex_started(0)
{
my_init_dynamic_array2(&plugins, sizeof(plugin_ref),
@@ -2211,7 +2345,7 @@ st_lex::st_lex()
Check whether the merging algorithm can be used on this VIEW
SYNOPSIS
- st_lex::can_be_merged()
+ LEX::can_be_merged()
DESCRIPTION
We can apply merge algorithm if it is single SELECT view with
@@ -2225,7 +2359,7 @@ st_lex::st_lex()
TRUE - merge algorithm can be used
*/
-bool st_lex::can_be_merged()
+bool LEX::can_be_merged()
{
// TODO: do not forget implement case when select_lex.table_list.elements==0
@@ -2262,19 +2396,19 @@ bool st_lex::can_be_merged()
check if command can use VIEW with MERGE algorithm (for top VIEWs)
SYNOPSIS
- st_lex::can_use_merged()
+ LEX::can_use_merged()
DESCRIPTION
Only listed here commands can use merge algorithm in top level
SELECT_LEX (for subqueries will be used merge algorithm if
- st_lex::can_not_use_merged() is not TRUE).
+ LEX::can_not_use_merged() is not TRUE).
RETURN
FALSE - command can't use merged VIEWs
TRUE - VIEWs with MERGE algorithms can be used
*/
-bool st_lex::can_use_merged()
+bool LEX::can_use_merged()
{
switch (sql_command)
{
@@ -2299,18 +2433,18 @@ bool st_lex::can_use_merged()
Check if command can't use merged views in any part of command
SYNOPSIS
- st_lex::can_not_use_merged()
+ LEX::can_not_use_merged()
DESCRIPTION
Temporary table algorithm will be used on all SELECT levels for queries
- listed here (see also st_lex::can_use_merged()).
+ listed here (see also LEX::can_use_merged()).
RETURN
FALSE - command can't use merged VIEWs
TRUE - VIEWs with MERGE algorithms can be used
*/
-bool st_lex::can_not_use_merged()
+bool LEX::can_not_use_merged()
{
switch (sql_command)
{
@@ -2339,7 +2473,7 @@ bool st_lex::can_not_use_merged()
FALSE no, we need data
*/
-bool st_lex::only_view_structure()
+bool LEX::only_view_structure()
{
switch (sql_command) {
case SQLCOM_SHOW_CREATE:
@@ -2368,7 +2502,7 @@ bool st_lex::only_view_structure()
*/
-bool st_lex::need_correct_ident()
+bool LEX::need_correct_ident()
{
switch(sql_command)
{
@@ -2398,7 +2532,7 @@ bool st_lex::need_correct_ident()
VIEW_CHECK_CASCADED CHECK OPTION CASCADED
*/
-uint8 st_lex::get_effective_with_check(TABLE_LIST *view)
+uint8 LEX::get_effective_with_check(TABLE_LIST *view)
{
if (view->select_lex->master_unit() == &unit &&
which_check_option_applicable())
@@ -2427,7 +2561,7 @@ uint8 st_lex::get_effective_with_check(TABLE_LIST *view)
*/
bool
-st_lex::copy_db_to(char **p_db, size_t *p_db_length) const
+LEX::copy_db_to(char **p_db, size_t *p_db_length) const
{
if (sphead)
{
@@ -2504,7 +2638,7 @@ void st_select_lex_unit::set_limit(st_select_lex *sl)
clause.
*/
-void st_lex::set_trg_event_type_for_tables()
+void LEX::set_trg_event_type_for_tables()
{
uint8 new_trg_event_map= 0;
@@ -2647,7 +2781,7 @@ void st_lex::set_trg_event_type_for_tables()
In this case link_to_local is set.
*/
-TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
+TABLE_LIST *LEX::unlink_first_table(bool *link_to_local)
{
TABLE_LIST *first;
if ((first= query_tables))
@@ -2687,7 +2821,7 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
table list
SYNOPSYS
- st_lex::first_lists_tables_same()
+ LEX::first_lists_tables_same()
NOTES
In many cases (for example, usual INSERT/DELETE/...) the first table of
@@ -2698,7 +2832,7 @@ TABLE_LIST *st_lex::unlink_first_table(bool *link_to_local)
the global list first.
*/
-void st_lex::first_lists_tables_same()
+void LEX::first_lists_tables_same()
{
TABLE_LIST *first_table= select_lex.table_list.first;
if (query_tables != first_table && first_table != 0)
@@ -2734,7 +2868,7 @@ void st_lex::first_lists_tables_same()
global list
*/
-void st_lex::link_first_table_back(TABLE_LIST *first,
+void LEX::link_first_table_back(TABLE_LIST *first,
bool link_to_local)
{
if (first)
@@ -2761,7 +2895,7 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
cleanup lex for case when we open table by table for processing
SYNOPSIS
- st_lex::cleanup_after_one_table_open()
+ LEX::cleanup_after_one_table_open()
NOTE
This method is mostly responsible for cleaning up of selects lists and
@@ -2769,7 +2903,7 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
to call Query_tables_list::reset_query_tables_list(FALSE).
*/
-void st_lex::cleanup_after_one_table_open()
+void LEX::cleanup_after_one_table_open()
{
/*
thd->lex->derived_tables & additional units may be set if we open
@@ -2804,7 +2938,7 @@ void st_lex::cleanup_after_one_table_open()
backup Pointer to Query_tables_list instance to be used for backup
*/
-void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup)
+void LEX::reset_n_backup_query_tables_list(Query_tables_list *backup)
{
backup->set_query_tables_list(this);
/*
@@ -2823,7 +2957,7 @@ void st_lex::reset_n_backup_query_tables_list(Query_tables_list *backup)
backup Pointer to Query_tables_list instance used for backup
*/
-void st_lex::restore_backup_query_tables_list(Query_tables_list *backup)
+void LEX::restore_backup_query_tables_list(Query_tables_list *backup)
{
this->destroy_query_tables_list();
this->set_query_tables_list(backup);
@@ -2834,14 +2968,14 @@ void st_lex::restore_backup_query_tables_list(Query_tables_list *backup)
Checks for usage of routines and/or tables in a parsed statement
SYNOPSIS
- st_lex:table_or_sp_used()
+ LEX:table_or_sp_used()
RETURN
FALSE No routines and tables used
TRUE Either or both routines and tables are used.
*/
-bool st_lex::table_or_sp_used()
+bool LEX::table_or_sp_used()
{
DBUG_ENTER("table_or_sp_used");
@@ -3002,10 +3136,157 @@ bool st_select_lex::add_index_hint (THD *thd, char *str, uint length)
@retval FALSE No, not a management partition command
*/
-bool st_lex::is_partition_management() const
+bool LEX::is_partition_management() const
{
return (sql_command == SQLCOM_ALTER_TABLE &&
(alter_info.flags == ALTER_ADD_PARTITION ||
alter_info.flags == ALTER_REORGANIZE_PARTITION));
}
+
+#ifdef MYSQL_SERVER
+uint binlog_unsafe_map[256];
+
+#define UNSAFE(a, b, c) \
+ { \
+ DBUG_PRINT("unsafe_mixed_statement", ("SETTING BASE VALUES: %s, %s, %02X\n", \
+ LEX::stmt_accessed_table_string(a), \
+ LEX::stmt_accessed_table_string(b), \
+ c)); \
+ unsafe_mixed_statement(a, b, c); \
+ }
+
+/*
+ Sets the combination given by "a" and "b" and automatically combinations
+ given by other types of access, i.e. 2^(8 - 2), as unsafe.
+
+ It may happen a colision when automatically defining a combination as unsafe.
+ For that reason, a combination has its unsafe condition redefined only when
+ the new_condition is greater then the old. For instance,
+
+ . (BINLOG_DIRECT_ON & TRX_CACHE_NOT_EMPTY) is never overwritten by
+ . (BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF).
+*/
+void unsafe_mixed_statement(LEX::enum_stmt_accessed_table a,
+ LEX::enum_stmt_accessed_table b, uint condition)
+{
+ int type= 0;
+ int index= (1U << a) | (1U << b);
+
+
+ for (type= 0; type < 256; type++)
+ {
+ if ((type & index) == index)
+ {
+ binlog_unsafe_map[type] |= condition;
+ }
+ }
+}
+/*
+ The BINLOG_* AND TRX_CACHE_* values can be combined by using '&' or '|',
+ which means that both conditions need to be satisfied or any of them is
+ enough. For example,
+
+ . BINLOG_DIRECT_ON & TRX_CACHE_NOT_EMPTY means that the statment is
+ unsafe when the option is on and trx-cache is not empty;
+
+ . BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF means the statement is unsafe
+ in all cases.
+
+ . TRX_CACHE_EMPTY | TRX_CACHE_NOT_EMPTY means the statement is unsafe
+ in all cases. Similar as above.
+*/
+void binlog_unsafe_map_init()
+{
+ memset((void*) binlog_unsafe_map, 0, sizeof(uint) * 256);
+
+ /*
+ Classify a statement as unsafe when there is a mixed statement and an
+ on-going transaction at any point of the execution if:
+
+ 1. The mixed statement is about to update a transactional table and
+ a non-transactional table.
+
+ 2. The mixed statement is about to update a transactional table and
+ read from a non-transactional table.
+
+ 3. The mixed statement is about to update a non-transactional table
+ and temporary transactional table.
+
+ 4. The mixed statement is about to update a temporary transactional
+ table and read from a non-transactional table.
+
+ 5. The mixed statement is about to update a transactional table and
+ a temporary non-transactional table.
+
+ 6. The mixed statement is about to update a transactional table and
+ read from a temporary non-transactional table.
+
+ 7. The mixed statement is about to update a temporary transactional
+ table and temporary non-transactional table.
+
+ 8. The mixed statement is about to update a temporary transactional
+ table and read from a temporary non-transactional table.
+
+ After updating a transactional table if:
+
+ 9. The mixed statement is about to update a non-transactional table
+ and read from a transactional table.
+
+ 10. The mixed statement is about to update a non-transactional table
+ and read from a temporary transactional table.
+
+ 11. The mixed statement is about to update a temporary non-transactional
+ table and read from a transactional table.
+
+ 12. The mixed statement is about to update a temporary non-transactional
+ table and read from a temporary transactional table.
+
+ 13. The mixed statement is about to update a temporary non-transactional
+ table and read from a non-transactional table.
+
+ The reason for this is that locks acquired may not protected a concurrent
+ transaction of interfering in the current execution and by consequence in
+ the result.
+ */
+ /* Case 1. */
+ UNSAFE(LEX::STMT_WRITES_TRANS_TABLE, LEX::STMT_WRITES_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF);
+ /* Case 2. */
+ UNSAFE(LEX::STMT_WRITES_TRANS_TABLE, LEX::STMT_READS_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF);
+ /* Case 3. */
+ UNSAFE(LEX::STMT_WRITES_NON_TRANS_TABLE, LEX::STMT_WRITES_TEMP_TRANS_TABLE,
+ BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF);
+ /* Case 4. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_TRANS_TABLE, LEX::STMT_READS_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF);
+ /* Case 5. */
+ UNSAFE(LEX::STMT_WRITES_TRANS_TABLE, LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON);
+ /* Case 6. */
+ UNSAFE(LEX::STMT_WRITES_TRANS_TABLE, LEX::STMT_READS_TEMP_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON);
+ /* Case 7. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_TRANS_TABLE, LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON);
+ /* Case 8. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_TRANS_TABLE, LEX::STMT_READS_TEMP_NON_TRANS_TABLE,
+ BINLOG_DIRECT_ON);
+ /* Case 9. */
+ UNSAFE(LEX::STMT_WRITES_NON_TRANS_TABLE, LEX::STMT_READS_TRANS_TABLE,
+ (BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF) & TRX_CACHE_NOT_EMPTY);
+ /* Case 10 */
+ UNSAFE(LEX::STMT_WRITES_NON_TRANS_TABLE, LEX::STMT_READS_TEMP_TRANS_TABLE,
+ (BINLOG_DIRECT_ON | BINLOG_DIRECT_OFF) & TRX_CACHE_NOT_EMPTY);
+ /* Case 11. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE, LEX::STMT_READS_TRANS_TABLE,
+ BINLOG_DIRECT_ON & TRX_CACHE_NOT_EMPTY);
+ /* Case 12. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE, LEX::STMT_READS_TEMP_TRANS_TABLE,
+ BINLOG_DIRECT_ON & TRX_CACHE_NOT_EMPTY);
+ /* Case 13. */
+ UNSAFE(LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE, LEX::STMT_READS_NON_TRANS_TABLE,
+ BINLOG_DIRECT_OFF & TRX_CACHE_NOT_EMPTY);
+}
+#endif