diff options
author | unknown <monty@mishka.local> | 2004-09-15 22:10:31 +0300 |
---|---|---|
committer | unknown <monty@mishka.local> | 2004-09-15 22:10:31 +0300 |
commit | ffc0d185da3c80f713b541cb52934712c24ce8cb (patch) | |
tree | d4323a7f81c07c98095c922e124755d6ac3253b8 /sql/handler.cc | |
parent | b15004a800770c3bdfc85f69c86629573669e1d0 (diff) | |
download | mariadb-git-ffc0d185da3c80f713b541cb52934712c24ce8cb.tar.gz |
Added options --auto-increment-increment and --auto-increment-offset.
This allows one to setup a master <-> master replication with non conflicting auto-increment series.
Cleaned up binary log code to make it easyer to add new state variables.
Added simpler 'upper level' logic for artificial events (events that should not cause cleanups on slave).
Simplified binary log handling.
Changed how auto_increment works together with to SET INSERT_ID=# to make it more predictable: Now the inserted rows in a multi-row statement are set independent of the existing rows in the table. (Before only InnoDB did this correctly)
mysql-test/r/mix_innodb_myisam_binlog.result:
Disable End_log_pos column from 'show binlog events' as this is now different from before
mysql-test/t/mix_innodb_myisam_binlog.test:
Disable End_log_pos column from 'show binlog events' as this is now different from before
sql/ha_berkeley.cc:
Changed prototype for get_auto_increment()
sql/ha_berkeley.h:
Changed prototype for get_auto_increment()
sql/ha_heap.cc:
Changed prototype for get_auto_increment()
sql/ha_heap.h:
Changed prototype for get_auto_increment()
sql/ha_innodb.cc:
Change how auto-increment is calculated.
Now the auto-increment logic is done in 'update_auto_increment()' to ensure that all handlers has the same auto-increment usage
sql/ha_innodb.h:
Changed prototype for get_auto_increment()
sql/ha_myisam.cc:
Changed prototype for get_auto_increment()
sql/ha_myisam.h:
Changed prototype for get_auto_increment()
sql/ha_ndbcluster.cc:
Changed prototype for get_auto_increment()
sql/ha_ndbcluster.h:
Changed prototype for get_auto_increment()
sql/handler.cc:
Remove some usage of current_thd
Changed how auto_increment works with SET INSERT_ID to make it more predictable
(Now we should generate same auto-increment serie on a slave, even if the table has rows that was not on the master.
Use auto_increment_increment and auto_increment_offset
sql/handler.h:
Changed prototype for get_auto_increment()
sql/log.cc:
Remove usage of 'set_log_pos()' to make code simpler. (Now log_pos is set in write_header())
Use 'data_written' instead of 'get_event_len()' to calculate how much data was written in the log
sql/log_event.cc:
Simple optimizations.
Remove cached_event_len (not used variable)
Made comments fit into 79 chars
Removed Log_event::set_log_pos(). Now we calculate log_pos in write_header().
Renamed write_data() to write() as the original write() function was not needed anymore.
Call writing of event header from event::write() functions. This made it easier to calculate the length of an event.
Simplified 'write_header' and remove 'switches' from it.
Changed all write() functions to return 'bool'. (The previous return values where not consistent)
Store auto_increment_increment and auto_increment_offset in binary log
Simplified how Query_log_event's where written and read. Now it's much easier to add now status variables for a query event to the binary log.
Removed some old MySQL 4.x code to make it easier to grep for functions used in 5.0
sql/log_event.h:
Changed return type of write() functions to bool. (Before we returned -1 or 1 for errors)
write_data() -> write()
Added 'data_written' member to make it easier to get length of written event.
Removed 'cached_event_len' and 'get_event_len()'
Added usage of auto_increment_increment and auto_increment_offset
Added 'artifical_event' to Start_log_event_v3, to hide logic that we in the binary log use log_pos=0 as a flag for an artifical event.
sql/mysqld.cc:
Added options --auto-increment-increment and --auto-increment-offset
sql/set_var.cc:
Added variables auto_increment_increment and auto_increment_offset
sql/slave.cc:
Changed errors -> warnings & information (in error log)
sql/sql_class.cc:
Added THD::cleanup_after_query(). This makes some code simpler and allows us to clean up 'next_insert_id' after query
sql/sql_class.h:
Added new auto_increment_xxx variables
Moved some functions/variables in THD class
sql/sql_help.cc:
Removed compiler warning
sql/sql_insert.cc:
Call 'restore_auto_increment()' if row was not inserted.
This makes it easier for handler to reuse the last generated auto-incrment value that was not used (for example in case of duplicate key)
sql/sql_parse.cc:
Use cleanup_after_query()
sql/sql_prepare.cc:
Use cleanup_after_query()
sql/sql_table.cc:
R
Diffstat (limited to 'sql/handler.cc')
-rw-r--r-- | sql/handler.cc | 164 |
1 files changed, 144 insertions, 20 deletions
diff --git a/sql/handler.cc b/sql/handler.cc index e7e1c807306..8a480b0f131 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -111,7 +111,7 @@ TYPELIB tx_isolation_typelib= {array_elements(tx_isolation_names)-1,"", enum db_type ha_resolve_by_name(const char *name, uint namelen) { - THD *thd=current_thd; + THD *thd= current_thd; if (thd && !my_strcasecmp(&my_charset_latin1, name, "DEFAULT")) { return (enum db_type) thd->variables.table_type; } @@ -142,6 +142,7 @@ const char *ha_get_storage_engine(enum db_type db_type) enum db_type ha_checktype(enum db_type database_type) { show_table_type_st *types; + THD *thd= current_thd; for (types= sys_table_types; types->type; types++) { if ((database_type == types->db_type) && @@ -161,8 +162,8 @@ enum db_type ha_checktype(enum db_type database_type) } return - DB_TYPE_UNKNOWN != (enum db_type) current_thd->variables.table_type ? - (enum db_type) current_thd->variables.table_type : + DB_TYPE_UNKNOWN != (enum db_type) thd->variables.table_type ? + (enum db_type) thd->variables.table_type : DB_TYPE_UNKNOWN != (enum db_type) global_system_variables.table_type ? (enum db_type) global_system_variables.table_type : DB_TYPE_MYISAM; @@ -946,7 +947,7 @@ int handler::read_first_row(byte * buf, uint primary_key) void handler::update_timestamp(byte *record) { - long skr= (long) current_thd->query_start(); + long skr= (long) table->in_use->query_start(); #ifdef WORDS_BIGENDIAN if (table->db_low_byte_first) { @@ -958,42 +959,165 @@ void handler::update_timestamp(byte *record) return; } + /* - Updates field with field_type NEXT_NUMBER according to following: - if field = 0 change field to the next free key in database. + Generate the next auto-increment number based on increment and offset + + In most cases increment= offset= 1, in which case we get: + 1,2,3,4,5,... + If increment=10 and offset=5 and previous number is 1, we get: + 1,5,15,25,35,... +*/ + +inline ulonglong +next_insert_id(ulonglong nr,struct system_variables *variables) +{ + nr= (((nr+ variables->auto_increment_increment - + variables->auto_increment_offset)) / + (ulonglong) variables->auto_increment_increment); + return (nr* (ulonglong) variables->auto_increment_increment + + variables->auto_increment_offset); +} + + +/* + Updates columns with type NEXT_NUMBER if: + + - If column value is set to NULL (in which case + auto_increment_field_not_null is 0) + - If column is set to 0 and (sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) is not + set. In the future we will only set NEXT_NUMBER fields if one sets them + to NULL (or they are not included in the insert list). + + + There are two different cases when the above is true: + + - thd->next_insert_id == 0 (This is the normal case) + In this case we set the set the column for the first row to the value + next_insert_id(get_auto_increment(column))) which is normally + max-used-column-value +1. + + We call get_auto_increment() only for the first row in a multi-row + statement. For the following rows we generate new numbers based on the + last used number. + + - thd->next_insert_id != 0. This happens when we have read a statement + from the binary log or when one has used SET LAST_INSERT_ID=#. + + In this case we will set the column to the value of next_insert_id. + The next row will be given the id + next_insert_id(next_insert_id) + + The idea is the generated auto_increment values are predicatable and + independent of the column values in the table. This is needed to be + able to replicate into a table that alread has rows with a higher + auto-increment value than the one that is inserted. + + After we have already generated an auto-increment number and the users + inserts a column with a higher value than the last used one, we will + start counting from the inserted value. + + thd->next_insert_id is cleared after it's been used for a statement. */ void handler::update_auto_increment() { - longlong nr; - THD *thd; + ulonglong nr; + THD *thd= table->in_use; + struct system_variables *variables= &thd->variables; DBUG_ENTER("handler::update_auto_increment"); - if (table->next_number_field->val_int() != 0 || + + /* + We must save the previous value to be able to restore it if the + row was not inserted + */ + thd->prev_insert_id= thd->next_insert_id; + + if ((nr= table->next_number_field->val_int()) != 0 || table->auto_increment_field_not_null && - current_thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) + thd->variables.sql_mode & MODE_NO_AUTO_VALUE_ON_ZERO) { + /* Clear flag for next row */ table->auto_increment_field_not_null= FALSE; + /* Mark that we didn't generated a new value **/ auto_increment_column_changed=0; + + /* Update next_insert_id if we have already generated a value */ + if (thd->clear_next_insert_id && nr >= thd->next_insert_id) + { + if (variables->auto_increment_increment != 1) + nr= next_insert_id(nr, variables); + else + nr++; + thd->next_insert_id= nr; + DBUG_PRINT("info",("next_insert_id: %lu", (ulong) nr)); + } DBUG_VOID_RETURN; } table->auto_increment_field_not_null= FALSE; - thd=current_thd; - if ((nr=thd->next_insert_id)) - thd->next_insert_id=0; // Clear after use - else - nr=get_auto_increment(); - if (!table->next_number_field->store(nr)) + if (!(nr= thd->next_insert_id)) + { + nr= get_auto_increment(); + if (variables->auto_increment_increment != 1) + nr= next_insert_id(nr-1, variables); + /* + Update next row based on the found value. This way we don't have to + call the handler for every generated auto-increment value on a + multi-row statement + */ + thd->next_insert_id= nr; + } + + DBUG_PRINT("info",("auto_increment: %lu", (ulong) nr)); + + /* Mark that we should clear next_insert_id before next stmt */ + thd->clear_next_insert_id= 1; + + if (!table->next_number_field->store((longlong) nr)) thd->insert_id((ulonglong) nr); else thd->insert_id(table->next_number_field->val_int()); + + /* + We can't set next_insert_id if the auto-increment key is not the + first key part, as there is no gurantee that the first parts will be in + sequence + */ + if (!table->next_number_key_offset) + { + /* + Set next insert id to point to next auto-increment value to be able to + handle multi-row statements + This works even if auto_increment_increment > 1 + */ + thd->next_insert_id= next_insert_id(nr, variables); + } + else + thd->next_insert_id= 0; + + /* Mark that we generated a new value */ auto_increment_column_changed=1; DBUG_VOID_RETURN; } +/* + restore_auto_increment + + In case of error on write, we restore the last used next_insert_id value + because the previous value was not used. +*/ + +void handler::restore_auto_increment() +{ + THD *thd= table->in_use; + if (thd->next_insert_id) + thd->next_insert_id= thd->prev_insert_id; +} + -longlong handler::get_auto_increment() +ulonglong handler::get_auto_increment() { - longlong nr; + ulonglong nr; int error; (void) extra(HA_EXTRA_KEYREAD); @@ -1014,8 +1138,8 @@ longlong handler::get_auto_increment() if (error) nr=1; else - nr=(longlong) table->next_number_field-> - val_int_offset(table->rec_buff_length)+1; + nr=((ulonglong) table->next_number_field-> + val_int_offset(table->rec_buff_length)+1); index_end(); (void) extra(HA_EXTRA_NO_KEYREAD); return nr; |