summaryrefslogtreecommitdiff
path: root/sql/sql_class.h
diff options
context:
space:
mode:
authorunknown <mkindahl@dl145k.mysql.com>2006-07-11 12:17:19 +0200
committerunknown <mkindahl@dl145k.mysql.com>2006-07-11 12:17:19 +0200
commitc22a89819916b66753d266376650c53c1c991811 (patch)
treea7de1f862d3573e58eb4ee35c13d673028cafbf0 /sql/sql_class.h
parenta6edf110bcd6b393c801624181e5b20b6557b8c1 (diff)
parente8f1a99a7d27d4326541804b918cbdd4f70ebcd4 (diff)
downloadmariadb-git-c22a89819916b66753d266376650c53c1c991811.tar.gz
Merge dl145k.mysql.com:/data0/mkindahl/bkroot/mysql-5.1-new-rpl
into dl145k.mysql.com:/data0/mkindahl/bk/MERGE/mysql-5.1-merge include/my_sys.h: Auto merged mysql-test/mysql-test-run.pl: Auto merged mysql-test/r/rpl_row_create_table.result: Auto merged mysql-test/t/disabled.def: Auto merged mysql-test/t/rpl_row_create_table.test: Auto merged mysys/my_malloc.c: Auto merged server-tools/instance-manager/parse.h: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/handler.h: Auto merged sql/log.cc: Auto merged sql/log_event.cc: Auto merged sql/mysql_priv.h: Auto merged sql/set_var.h: Auto merged sql/sp.cc: Auto merged sql/sp_head.cc: Auto merged sql/sp_head.h: Auto merged sql/sql_base.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_parse.cc: Auto merged sql/sql_select.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_update.cc: Auto merged sql/sql_view.cc: Auto merged sql/sql_yacc.yy: Auto merged mysys/safemalloc.c: Merge of mysql-5.1-new-rpl into mysql-5.1 sql/ha_federated.cc: d Merge of mysql-5.1-new-rpl into mysql-5.1 sql/set_var.cc: Merge of mysql-5.1-new-rpl with mysql-5.1 sql/slave.cc: Merge of mysql-5.1-new-rpl into mysql-5.1 sql/sql_class.h: Merge of mysql-5.1-new-rpl into mysql-5.1
Diffstat (limited to 'sql/sql_class.h')
-rw-r--r--sql/sql_class.h205
1 files changed, 167 insertions, 38 deletions
diff --git a/sql/sql_class.h b/sql/sql_class.h
index b79f0753603..3255e4995b9 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -770,12 +770,14 @@ class Sub_statement_state
{
public:
ulonglong options;
- ulonglong last_insert_id, next_insert_id, current_insert_id;
+ ulonglong first_successful_insert_id_in_prev_stmt;
+ ulonglong first_successful_insert_id_in_cur_stmt, insert_id_for_cur_row;
+ Discrete_interval auto_inc_interval_for_cur_row;
ulonglong limit_found_rows;
ha_rows cuted_fields, sent_row_count, examined_row_count;
ulong client_capabilities;
uint in_sub_stmt;
- bool enable_slow_log, insert_id_used, clear_next_insert_id;
+ bool enable_slow_log;
bool last_insert_id_used;
my_bool no_send_ok;
SAVEPOINT *savepoints;
@@ -1071,24 +1073,137 @@ public:
Note: in the parser, stmt_arena == thd, even for PS/SP.
*/
Query_arena *stmt_arena;
+ /* Tells if LAST_INSERT_ID(#) was called for the current statement */
+ bool arg_of_last_insert_id_function;
/*
- next_insert_id is set on SET INSERT_ID= #. This is used as the next
- generated auto_increment value in handler.cc
+ ALL OVER THIS FILE, "insert_id" means "*automatically generated* value for
+ insertion into an auto_increment column".
*/
- ulonglong next_insert_id;
- /* Remember last next_insert_id to reset it if something went wrong */
- ulonglong prev_insert_id;
/*
- The insert_id used for the last statement or set by SET LAST_INSERT_ID=#
- or SELECT LAST_INSERT_ID(#). Used for binary log and returned by
- LAST_INSERT_ID()
+ This is the first autogenerated insert id which was *successfully*
+ inserted by the previous statement (exactly, if the previous statement
+ didn't successfully insert an autogenerated insert id, then it's the one
+ of the statement before, etc).
+ It can also be set by SET LAST_INSERT_ID=# or SELECT LAST_INSERT_ID(#).
+ It is returned by LAST_INSERT_ID().
*/
- ulonglong last_insert_id;
+ ulonglong first_successful_insert_id_in_prev_stmt;
/*
- Set to the first value that LAST_INSERT_ID() returned for the last
- statement. When this is set, last_insert_id_used is set to true.
+ Variant of the above, used for storing in statement-based binlog. The
+ difference is that the one above can change as the execution of a stored
+ function progresses, while the one below is set once and then does not
+ change (which is the value which statement-based binlog needs).
*/
- ulonglong current_insert_id;
+ ulonglong first_successful_insert_id_in_prev_stmt_for_binlog;
+ /*
+ This is the first autogenerated insert id which was *successfully*
+ inserted by the current statement. It is maintained only to set
+ first_successful_insert_id_in_prev_stmt when statement ends.
+ */
+ ulonglong first_successful_insert_id_in_cur_stmt;
+ /*
+ We follow this logic:
+ - when stmt starts, first_successful_insert_id_in_prev_stmt contains the
+ first insert id successfully inserted by the previous stmt.
+ - as stmt makes progress, handler::insert_id_for_cur_row changes; every
+ time get_auto_increment() is called, auto_inc_intervals_for_binlog is
+ augmented with the reserved interval (if statement-based binlogging).
+ - at first successful insertion of an autogenerated value,
+ first_successful_insert_id_in_cur_stmt is set to
+ handler::insert_id_for_cur_row.
+ - when stmt goes to binlog, auto_inc_intervals_for_binlog is
+ binlogged if non-empty.
+ - when stmt ends, first_successful_insert_id_in_prev_stmt is set to
+ first_successful_insert_id_in_cur_stmt.
+ */
+ /*
+ stmt_depends_on_first_successful_insert_id_in_prev_stmt is set when
+ LAST_INSERT_ID() is used by a statement.
+ If it is set, first_successful_insert_id_in_prev_stmt_for_binlog will be
+ stored in the statement-based binlog.
+ This variable is CUMULATIVE along the execution of a stored function or
+ trigger: if one substatement sets it to 1 it will stay 1 until the
+ function/trigger ends, thus making sure that
+ first_successful_insert_id_in_prev_stmt_for_binlog does not change anymore
+ and is propagated to the caller for binlogging.
+ */
+ bool stmt_depends_on_first_successful_insert_id_in_prev_stmt;
+ /*
+ List of auto_increment intervals reserved by the thread so far, for
+ storage in the statement-based binlog.
+ Note that its minimum is not first_successful_insert_id_in_cur_stmt:
+ assuming a table with an autoinc column, and this happens:
+ INSERT INTO ... VALUES(3);
+ SET INSERT_ID=3; INSERT IGNORE ... VALUES (NULL);
+ then the latter INSERT will insert no rows
+ (first_successful_insert_id_in_cur_stmt == 0), but storing "INSERT_ID=3"
+ in the binlog is still needed; the list's minimum will contain 3.
+ */
+ Discrete_intervals_list auto_inc_intervals_in_cur_stmt_for_binlog;
+ /* Used by replication and SET INSERT_ID */
+ Discrete_intervals_list auto_inc_intervals_forced;
+ /*
+ There is BUG#19630 where statement-based replication of stored
+ functions/triggers with two auto_increment columns breaks.
+ We however ensure that it works when there is 0 or 1 auto_increment
+ column; our rules are
+ a) on master, while executing a top statement involving substatements,
+ first top- or sub- statement to generate auto_increment values wins the
+ exclusive right to see its values be written to binlog (the write
+ will be done by the statement or its caller), and the losers won't see
+ their values be written to binlog.
+ b) on slave, while replicating a top statement involving substatements,
+ first top- or sub- statement to need to read auto_increment values from
+ the master's binlog wins the exclusive right to read them (so the losers
+ won't read their values from binlog but instead generate on their own).
+ a) implies that we mustn't backup/restore
+ auto_inc_intervals_in_cur_stmt_for_binlog.
+ b) implies that we mustn't backup/restore auto_inc_intervals_forced.
+
+ If there are more than 1 auto_increment columns, then intervals for
+ different columns may mix into the
+ auto_inc_intervals_in_cur_stmt_for_binlog list, which is logically wrong,
+ but there is no point in preventing this mixing by preventing intervals
+ from the secondly inserted column to come into the list, as such
+ prevention would be wrong too.
+ What will happen in the case of
+ INSERT INTO t1 (auto_inc) VALUES(NULL);
+ where t1 has a trigger which inserts into an auto_inc column of t2, is
+ that in binlog we'll store the interval of t1 and the interval of t2 (when
+ we store intervals, soon), then in slave, t1 will use both intervals, t2
+ will use none; if t1 inserts the same number of rows as on master,
+ normally the 2nd interval will not be used by t1, which is fine. t2's
+ values will be wrong if t2's internal auto_increment counter is different
+ from what it was on master (which is likely). In 5.1, in mixed binlogging
+ mode, row-based binlogging is used for such cases where two
+ auto_increment columns are inserted.
+ */
+ inline void record_first_successful_insert_id_in_cur_stmt(ulonglong id)
+ {
+ if (first_successful_insert_id_in_cur_stmt == 0)
+ first_successful_insert_id_in_cur_stmt= id;
+ }
+ inline ulonglong read_first_successful_insert_id_in_prev_stmt(void)
+ {
+ if (!stmt_depends_on_first_successful_insert_id_in_prev_stmt)
+ {
+ /* It's the first time we read it */
+ first_successful_insert_id_in_prev_stmt_for_binlog=
+ first_successful_insert_id_in_prev_stmt;
+ stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
+ }
+ return first_successful_insert_id_in_prev_stmt;
+ }
+ /*
+ Used by Intvar_log_event::exec_event() and by "SET INSERT_ID=#"
+ (mysqlbinlog). We'll soon add a variant which can take many intervals in
+ argument.
+ */
+ inline void force_one_auto_inc_interval(ulonglong next_id)
+ {
+ auto_inc_intervals_forced.append(next_id, ULONGLONG_MAX, 0);
+ }
+
ulonglong limit_found_rows;
ulonglong options; /* Bitmap of states */
longlong row_count_func; /* For the ROW_COUNT() function */
@@ -1157,7 +1272,6 @@ public:
bool last_cuted_field;
bool no_errors, password, is_fatal_error;
bool query_start_used, rand_used, time_zone_used;
- bool last_insert_id_used,insert_id_used, clear_next_insert_id;
bool in_lock_tables;
bool query_error, bootstrap, cleanup_done;
bool tmp_table_used;
@@ -1185,9 +1299,10 @@ public:
/* Used by the sys_var class to store temporary values */
union
{
- my_bool my_bool_value;
- long long_value;
- ulong ulong_value;
+ my_bool my_bool_value;
+ long long_value;
+ ulong ulong_value;
+ ulonglong ulonglong_value;
} sys_var_tmp;
struct {
@@ -1288,20 +1403,6 @@ public:
inline void end_time() { time(&start_time); }
inline void set_time(time_t t) { time_after_lock=start_time=user_time=t; }
inline void lock_time() { time(&time_after_lock); }
- inline void insert_id(ulonglong id_arg)
- {
- last_insert_id= id_arg;
- insert_id_used=1;
- }
- inline ulonglong insert_id(void)
- {
- if (!last_insert_id_used)
- {
- last_insert_id_used=1;
- current_insert_id=last_insert_id;
- }
- return last_insert_id;
- }
inline ulonglong found_rows(void)
{
return limit_found_rows;
@@ -1418,7 +1519,17 @@ public:
inline void set_current_stmt_binlog_row_based_if_mixed()
{
#ifdef HAVE_ROW_BASED_REPLICATION
- if (variables.binlog_format == BINLOG_FORMAT_MIXED)
+ /*
+ If in a stored/function trigger, the caller should already have done the
+ change. We test in_sub_stmt to prevent introducing bugs where people
+ wouldn't ensure that, and would switch to row-based mode in the middle
+ of executing a stored function/trigger (which is too late, see also
+ reset_current_stmt_binlog_row_based()); this condition will make their
+ tests fail and so force them to propagate the
+ lex->binlog_row_based_if_mixed upwards to the caller.
+ */
+ if ((variables.binlog_format == BINLOG_FORMAT_MIXED) &&
+ (in_sub_stmt == 0))
current_stmt_binlog_row_based= TRUE;
#endif
}
@@ -1437,12 +1548,29 @@ public:
inline void reset_current_stmt_binlog_row_based()
{
#ifdef HAVE_ROW_BASED_REPLICATION
- current_stmt_binlog_row_based=
- test(variables.binlog_format == BINLOG_FORMAT_ROW);
+ /*
+ If there are temporary tables, don't reset back to
+ statement-based. Indeed it could be that:
+ CREATE TEMPORARY TABLE t SELECT UUID(); # row-based
+ # and row-based does not store updates to temp tables
+ # in the binlog.
+ INSERT INTO u SELECT * FROM t; # stmt-based
+ and then the INSERT will fail as data inserted into t was not logged.
+ So we continue with row-based until the temp table is dropped.
+ If we are in a stored function or trigger, we mustn't reset in the
+ middle of its execution (as the binary logging way of a stored function
+ or trigger is decided when it starts executing, depending for example on
+ the caller (for a stored function: if caller is SELECT or
+ INSERT/UPDATE/DELETE...).
+ */
+ if ((temporary_tables == NULL) && (in_sub_stmt == 0))
+ {
+ current_stmt_binlog_row_based=
+ test(variables.binlog_format == BINLOG_FORMAT_ROW);
+ }
#else
current_stmt_binlog_row_based= FALSE;
#endif
- }
/*
Initialize the current database from a NULL-terminated string with length
@@ -1630,7 +1758,7 @@ class select_insert :public select_result_interceptor {
TABLE_LIST *table_list;
TABLE *table;
List<Item> *fields;
- ulonglong last_insert_id;
+ ulonglong autoinc_value_of_last_inserted_row; // autogenerated or not
COPY_INFO info;
bool insert_into_view;
@@ -1678,7 +1806,8 @@ public:
virtual bool can_rollback_data() { return 1; }
// Needed for access from local class MY_HOOKS in prepare(), since thd is proteted.
- THD *get_thd(void) { return thd; }
+ const THD *get_thd(void) { return thd; }
+ const HA_CREATE_INFO *get_create_info() { return create_info; };
};
#include <myisam.h>