Commit 6d4b3c58 authored by unknown's avatar unknown

Apply InnoDB snapshot innodb-5.1-ss1726.

Bug #16979: AUTO_INC lock in InnoDB works a table level lock
  - this is a major change in InnoDB auto-inc handling.
Bug #27950: Duplicate entry error in auto-inc after mysqld restart
  - Init AUTOINC from delete_row().
Bug #28781: InnoDB increments auto-increment value incorrectly with ON DUPLICATE KEY UPDATE
  - Use value specified by MySQL, in update_row().


mysql-test/r/innodb.result:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1655:
  Fix the innodb.test failure mentioned in r1654.
storage/innobase/dict/dict0dict.c:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
  
  
  Revision r1719:
  Merge r1264 from branches/zip: Avoid memory fragmentation when
  adding column definitions to tables.
  
  dict_mem_table_add_col(): Add the parameter "heap" for temporary memory
  allocation.  Allow it and "name" to be NULL.  These parameters are NULL
  when creating dummy indexes.
  
  dict_add_col_name(): Remove calls to ut_malloc() and ut_free().
  
  dict_table_get_col_name(): Allow table->col_names to be NULL.
  
  dict_table_add_system_columns(), dict_table_add_to_cache():
  Add the parameter "heap".
  ---
  Additional changes that had to be merged from branches/zip:
  
  dict_table_add_system_columns(): New function, factored out from
  dict_table_add_to_cache().
  
  mlog_parse_index(): Add some consistency checks, and make use of
  dict_table_add_system_columns().
storage/innobase/dict/dict0mem.c:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
  
  
  Revision r1719:
  Merge r1264 from branches/zip: Avoid memory fragmentation when
  adding column definitions to tables.
  
  dict_mem_table_add_col(): Add the parameter "heap" for temporary memory
  allocation.  Allow it and "name" to be NULL.  These parameters are NULL
  when creating dummy indexes.
  
  dict_add_col_name(): Remove calls to ut_malloc() and ut_free().
  
  dict_table_get_col_name(): Allow table->col_names to be NULL.
  
  dict_table_add_system_columns(), dict_table_add_to_cache():
  Add the parameter "heap".
  ---
  Additional changes that had to be merged from branches/zip:
  
  dict_table_add_system_columns(): New function, factored out from
  dict_table_add_to_cache().
  
  mlog_parse_index(): Add some consistency checks, and make use of
  dict_table_add_system_columns().
storage/innobase/handler/ha_innodb.cc:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
  
  
  Revision r1718:
  Replace mysql_byte with uchar and remove the #define mysql_byte from
  ha_innodb.cc.  This cleanup was made possible as of r1550:
  
  
  Revision r1658:
  check_trx_exists(): Remove a redundant function call and assignment that
  was added by someone at MySQL.
  
  
  Revision r1656:
  
  
  Revision r1719:
  Merge r1264 from branches/zip: Avoid memory fragmentation when
  adding column definitions to tables.
  
  dict_mem_table_add_col(): Add the parameter "heap" for temporary memory
  allocation.  Allow it and "name" to be NULL.  These parameters are NULL
  when creating dummy indexes.
  
  dict_add_col_name(): Remove calls to ut_malloc() and ut_free().
  
  dict_table_get_col_name(): Allow table->col_names to be NULL.
  
  dict_table_add_system_columns(), dict_table_add_to_cache():
  Add the parameter "heap".
  ---
  Additional changes that had to be merged from branches/zip:
  
  dict_table_add_system_columns(): New function, factored out from
  dict_table_add_to_cache().
  
  mlog_parse_index(): Add some consistency checks, and make use of
  dict_table_add_system_columns().
  
  
  Revision r1654:
  
  One test case in innodb.test fails because of auto-increment
  changes in r1562:1653:
  
  $diff innodb.result innodb.reject
  504c504
  < 3	test2		this will work
  ---
  > 4	test2		this will work
storage/innobase/handler/ha_innodb.h:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
  
  
  Revision r1654:
  
  One test case in innodb.test fails because of auto-increment
  changes in r1562:1653:
  
  $diff innodb.result innodb.reject
  504c504
  < 3	test2		this will work
  ---
  > 4	test2		this will work
storage/innobase/ibuf/ibuf0ibuf.c:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1715:
  ibuf0ibuf.c: Remove the unused prototype for dict_index_print_low()
  that was inadvertently added in r832.
  
  
  Revision r1719:
  Merge r1264 from branches/zip: Avoid memory fragmentation when
  adding column definitions to tables.
  
  dict_mem_table_add_col(): Add the parameter "heap" for temporary memory
  allocation.  Allow it and "name" to be NULL.  These parameters are NULL
  when creating dummy indexes.
  
  dict_add_col_name(): Remove calls to ut_malloc() and ut_free().
  
  dict_table_get_col_name(): Allow table->col_names to be NULL.
  
  dict_table_add_system_columns(), dict_table_add_to_cache():
  Add the parameter "heap".
  ---
  Additional changes that had to be merged from branches/zip:
  
  dict_table_add_system_columns(): New function, factored out from
  dict_table_add_to_cache().
  
  mlog_parse_index(): Add some consistency checks, and make use of
  dict_table_add_system_columns().
storage/innobase/include/dict0dict.h:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
  
  
  Revision r1719:
  Merge r1264 from branches/zip: Avoid memory fragmentation when
  adding column definitions to tables.
  
  dict_mem_table_add_col(): Add the parameter "heap" for temporary memory
  allocation.  Allow it and "name" to be NULL.  These parameters are NULL
  when creating dummy indexes.
  
  dict_add_col_name(): Remove calls to ut_malloc() and ut_free().
  
  dict_table_get_col_name(): Allow table->col_names to be NULL.
  
  dict_table_add_system_columns(), dict_table_add_to_cache():
  Add the parameter "heap".
  ---
  Additional changes that had to be merged from branches/zip:
  
  dict_table_add_system_columns(): New function, factored out from
  dict_table_add_to_cache().
  
  mlog_parse_index(): Add some consistency checks, and make use of
  dict_table_add_system_columns().
storage/innobase/include/dict0mem.h:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
  
  
  Revision r1719:
  Merge r1264 from branches/zip: Avoid memory fragmentation when
  adding column definitions to tables.
  
  dict_mem_table_add_col(): Add the parameter "heap" for temporary memory
  allocation.  Allow it and "name" to be NULL.  These parameters are NULL
  when creating dummy indexes.
  
  dict_add_col_name(): Remove calls to ut_malloc() and ut_free().
  
  dict_table_get_col_name(): Allow table->col_names to be NULL.
  
  dict_table_add_system_columns(), dict_table_add_to_cache():
  Add the parameter "heap".
  ---
  Additional changes that had to be merged from branches/zip:
  
  dict_table_add_system_columns(): New function, factored out from
  dict_table_add_to_cache().
  
  mlog_parse_index(): Add some consistency checks, and make use of
  dict_table_add_system_columns().
storage/innobase/include/lock0lock.h:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1664:
  lock_number_of_rows_locked(): Fix a typo in comment, and make the comments
  in lock0lock.c and lock0lock.h identical.  The typo was incorrectly fixed in
  r1623.
storage/innobase/include/row0mysql.h:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
storage/innobase/include/row0sel.h:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
storage/innobase/include/trx0trx.h:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
storage/innobase/include/ut0mem.h:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1713:
  Fix typo in comment.
storage/innobase/log/log0recv.c:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1657:
  recv_init_crash_recovery(): remove trailing white space
storage/innobase/row/row0mysql.c:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
storage/innobase/row/row0sel.c:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
storage/innobase/trx/trx0trx.c:
  Apply InnoDB snapshot innodb-5.1-ss1726.
  
  Revision r1645:
  Fix for bug# 16979, this is a major change in InnoDB auto-inc handling. There
  is one test that fails as of this commit. The updated test case should be
  part of the snapshot from MySQL shortly.
  
  Fix for bug# 27950 - Init AUTOINC from delete_row().
  
  Fix for bug# 28781 - Use value specified by MySQL, in update_row().
  
  Summary of structural changes:
  ==============================
  InnoDB needs to hold a table level lock for AUTOINC allocations to overcome
  the non-determinism inherent in MySQL SBR for INSERT ... SELECT. In this fix 
  for simple INSERT statements (including multi-value inserts), we try and avoid
  acquiring the special AUTOINC table level lock unless another transaction has
  already reserved the AUTOINC table level lock, in which case we fall back
  to the old behavior of acquiring the AUTOINC table level lock.
  
  The max AUTOINC value is now read directly using the low level interface
  of InnoDB.
parent 2bdfe4d7
...@@ -501,7 +501,7 @@ ERROR 23000: Duplicate entry 'test2' for key 'ggid' ...@@ -501,7 +501,7 @@ ERROR 23000: Duplicate entry 'test2' for key 'ggid'
select * from t1; select * from t1;
id ggid email passwd id ggid email passwd
1 this will work 1 this will work
3 test2 this will work 4 test2 this will work
select * from t1 where id=1; select * from t1 where id=1;
id ggid email passwd id ggid email passwd
1 this will work 1 this will work
......
...@@ -410,14 +410,27 @@ dict_table_get_col_name( ...@@ -410,14 +410,27 @@ dict_table_get_col_name(
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
s = table->col_names; s = table->col_names;
if (s) {
for (i = 0; i < col_nr; i++) { for (i = 0; i < col_nr; i++) {
s += strlen(s) + 1; s += strlen(s) + 1;
}
} }
return(s); return(s);
} }
/************************************************************************
Acquire the autoinc lock.*/
void
dict_table_autoinc_lock(
/*====================*/
dict_table_t* table)
{
mutex_enter(&table->autoinc_mutex);
}
/************************************************************************ /************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */ initialized counter. */
...@@ -428,54 +441,8 @@ dict_table_autoinc_initialize( ...@@ -428,54 +441,8 @@ dict_table_autoinc_initialize(
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
ib_longlong value) /* in: next value to assign to a row */ ib_longlong value) /* in: next value to assign to a row */
{ {
mutex_enter(&(table->autoinc_mutex));
table->autoinc_inited = TRUE; table->autoinc_inited = TRUE;
table->autoinc = value; table->autoinc = value;
mutex_exit(&(table->autoinc_mutex));
}
/************************************************************************
Gets the next autoinc value (== autoinc counter value), 0 if not yet
initialized. If initialized, increments the counter by 1. */
ib_longlong
dict_table_autoinc_get(
/*===================*/
/* out: value for a new row, or 0 */
dict_table_t* table) /* in: table */
{
ib_longlong value;
mutex_enter(&(table->autoinc_mutex));
if (!table->autoinc_inited) {
value = 0;
} else {
value = table->autoinc;
table->autoinc = table->autoinc + 1;
}
mutex_exit(&(table->autoinc_mutex));
return(value);
}
/************************************************************************
Decrements the autoinc counter value by 1. */
void
dict_table_autoinc_decrement(
/*=========================*/
dict_table_t* table) /* in: table */
{
mutex_enter(&(table->autoinc_mutex));
table->autoinc = table->autoinc - 1;
mutex_exit(&(table->autoinc_mutex));
} }
/************************************************************************ /************************************************************************
...@@ -490,32 +457,6 @@ dict_table_autoinc_read( ...@@ -490,32 +457,6 @@ dict_table_autoinc_read(
{ {
ib_longlong value; ib_longlong value;
mutex_enter(&(table->autoinc_mutex));
if (!table->autoinc_inited) {
value = 0;
} else {
value = table->autoinc;
}
mutex_exit(&(table->autoinc_mutex));
return(value);
}
/************************************************************************
Peeks the autoinc counter value, 0 if not yet initialized. Does not
increment the counter. The read not protected by any mutex! */
ib_longlong
dict_table_autoinc_peek(
/*====================*/
/* out: value of the counter */
dict_table_t* table) /* in: table */
{
ib_longlong value;
if (!table->autoinc_inited) { if (!table->autoinc_inited) {
value = 0; value = 0;
...@@ -527,7 +468,7 @@ dict_table_autoinc_peek( ...@@ -527,7 +468,7 @@ dict_table_autoinc_peek(
} }
/************************************************************************ /************************************************************************
Updates the autoinc counter if the value supplied is equal or bigger than the Updates the autoinc counter if the value supplied is greater than the
current value. If not inited, does nothing. */ current value. If not inited, does nothing. */
void void
...@@ -537,15 +478,21 @@ dict_table_autoinc_update( ...@@ -537,15 +478,21 @@ dict_table_autoinc_update(
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
ib_longlong value) /* in: value which was assigned to a row */ ib_longlong value) /* in: value which was assigned to a row */
{ {
mutex_enter(&(table->autoinc_mutex)); if (table->autoinc_inited && value > table->autoinc) {
if (table->autoinc_inited) { table->autoinc = value;
if (value >= table->autoinc) {
table->autoinc = value + 1;
}
} }
}
mutex_exit(&(table->autoinc_mutex)); /************************************************************************
Release the autoinc lock.*/
void
dict_table_autoinc_unlock(
/*======================*/
dict_table_t* table) /* in: release autoinc lock for this table */
{
mutex_exit(&table->autoinc_mutex);
} }
/************************************************************************ /************************************************************************
...@@ -842,28 +789,18 @@ dict_table_get( ...@@ -842,28 +789,18 @@ dict_table_get(
} }
/************************************************************************** /**************************************************************************
Adds a table object to the dictionary cache. */ Adds system columns to a table object. */
void void
dict_table_add_to_cache( dict_table_add_system_columns(
/*====================*/ /*==========================*/
dict_table_t* table) /* in: table */ dict_table_t* table, /* in/out: table */
mem_heap_t* heap) /* in: temporary heap */
{ {
ulint fold;
ulint id_fold;
ulint i;
ulint row_len;
ut_ad(table); ut_ad(table);
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS); ut_ad(table->n_def == table->n_cols - DATA_N_SYS_COLS);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(table->cached == FALSE); ut_ad(!table->cached);
fold = ut_fold_string(table->name);
id_fold = ut_fold_dulint(table->id);
table->cached = TRUE;
/* NOTE: the system columns MUST be added in the following order /* NOTE: the system columns MUST be added in the following order
(so that they can be indexed by the numerical value of DATA_ROW_ID, (so that they can be indexed by the numerical value of DATA_ROW_ID,
...@@ -871,19 +808,19 @@ dict_table_add_to_cache( ...@@ -871,19 +808,19 @@ dict_table_add_to_cache(
The clustered index will not always physically contain all The clustered index will not always physically contain all
system columns. */ system columns. */
dict_mem_table_add_col(table, "DB_ROW_ID", DATA_SYS, dict_mem_table_add_col(table, heap, "DB_ROW_ID", DATA_SYS,
DATA_ROW_ID | DATA_NOT_NULL, DATA_ROW_ID | DATA_NOT_NULL,
DATA_ROW_ID_LEN); DATA_ROW_ID_LEN);
#if DATA_ROW_ID != 0 #if DATA_ROW_ID != 0
#error "DATA_ROW_ID != 0" #error "DATA_ROW_ID != 0"
#endif #endif
dict_mem_table_add_col(table, "DB_TRX_ID", DATA_SYS, dict_mem_table_add_col(table, heap, "DB_TRX_ID", DATA_SYS,
DATA_TRX_ID | DATA_NOT_NULL, DATA_TRX_ID | DATA_NOT_NULL,
DATA_TRX_ID_LEN); DATA_TRX_ID_LEN);
#if DATA_TRX_ID != 1 #if DATA_TRX_ID != 1
#error "DATA_TRX_ID != 1" #error "DATA_TRX_ID != 1"
#endif #endif
dict_mem_table_add_col(table, "DB_ROLL_PTR", DATA_SYS, dict_mem_table_add_col(table, heap, "DB_ROLL_PTR", DATA_SYS,
DATA_ROLL_PTR | DATA_NOT_NULL, DATA_ROLL_PTR | DATA_NOT_NULL,
DATA_ROLL_PTR_LEN); DATA_ROLL_PTR_LEN);
#if DATA_ROLL_PTR != 2 #if DATA_ROLL_PTR != 2
...@@ -895,10 +832,34 @@ dict_table_add_to_cache( ...@@ -895,10 +832,34 @@ dict_table_add_to_cache(
#if DATA_N_SYS_COLS != 3 #if DATA_N_SYS_COLS != 3
#error "DATA_N_SYS_COLS != 3" #error "DATA_N_SYS_COLS != 3"
#endif #endif
}
/**************************************************************************
Adds a table object to the dictionary cache. */
void
dict_table_add_to_cache(
/*====================*/
dict_table_t* table, /* in: table */
mem_heap_t* heap) /* in: temporary heap */
{
ulint fold;
ulint id_fold;
ulint i;
ulint row_len;
/* The lower limit for what we consider a "big" row */ /* The lower limit for what we consider a "big" row */
#define BIG_ROW_SIZE 1024 #define BIG_ROW_SIZE 1024
ut_ad(mutex_own(&(dict_sys->mutex)));
dict_table_add_system_columns(table, heap);
table->cached = TRUE;
fold = ut_fold_string(table->name);
id_fold = ut_fold_dulint(table->id);
row_len = 0; row_len = 0;
for (i = 0; i < table->n_def; i++) { for (i = 0; i < table->n_def; i++) {
ulint col_len = dict_col_get_max_size( ulint col_len = dict_col_get_max_size(
......
...@@ -90,6 +90,11 @@ dict_mem_table_create( ...@@ -90,6 +90,11 @@ dict_mem_table_create(
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX); mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
table->autoinc_inited = FALSE; table->autoinc_inited = FALSE;
/* The actual increment value will be set by MySQL, we simply
default to 1 here.*/
table->autoinc_increment = 1;
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
table->magic_n = DICT_TABLE_MAGIC_N; table->magic_n = DICT_TABLE_MAGIC_N;
#endif /* UNIV_DEBUG */ #endif /* UNIV_DEBUG */
...@@ -108,18 +113,11 @@ dict_mem_table_free( ...@@ -108,18 +113,11 @@ dict_mem_table_free(
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
mutex_free(&(table->autoinc_mutex)); mutex_free(&(table->autoinc_mutex));
if (table->col_names && (table->n_def < table->n_cols)) {
ut_free((void*)table->col_names);
}
mem_heap_free(table->heap); mem_heap_free(table->heap);
} }
/******************************************************************** /********************************************************************
Add 'name' to end of the col_names array (see dict_table_t::col_names). Call Append 'name' to 'col_names' (@see dict_table_t::col_names). */
ut_free on col_names (if not NULL), allocate new array (if heap, from it,
otherwise with ut_malloc), and copy col_names + name to it. */
static static
const char* const char*
dict_add_col_name( dict_add_col_name(
...@@ -129,21 +127,19 @@ dict_add_col_name( ...@@ -129,21 +127,19 @@ dict_add_col_name(
NULL */ NULL */
ulint cols, /* in: number of existing columns */ ulint cols, /* in: number of existing columns */
const char* name, /* in: new column name */ const char* name, /* in: new column name */
mem_heap_t* heap) /* in: heap, or NULL */ mem_heap_t* heap) /* in: heap */
{ {
ulint i; ulint old_len;
ulint old_len; ulint new_len;
ulint new_len; ulint total_len;
ulint total_len; char* res;
const char* s;
char* res;
ut_a(((cols == 0) && !col_names) || ((cols > 0) && col_names)); ut_ad(!cols == !col_names);
ut_a(*name);
/* Find out length of existing array. */ /* Find out length of existing array. */
if (col_names) { if (col_names) {
s = col_names; const char* s = col_names;
ulint i;
for (i = 0; i < cols; i++) { for (i = 0; i < cols; i++) {
s += strlen(s) + 1; s += strlen(s) + 1;
...@@ -157,11 +153,7 @@ dict_add_col_name( ...@@ -157,11 +153,7 @@ dict_add_col_name(
new_len = strlen(name) + 1; new_len = strlen(name) + 1;
total_len = old_len + new_len; total_len = old_len + new_len;
if (heap) { res = mem_heap_alloc(heap, total_len);
res = mem_heap_alloc(heap, total_len);
} else {
res = ut_malloc(total_len);
}
if (old_len > 0) { if (old_len > 0) {
memcpy(res, col_names, old_len); memcpy(res, col_names, old_len);
...@@ -169,10 +161,6 @@ dict_add_col_name( ...@@ -169,10 +161,6 @@ dict_add_col_name(
memcpy(res + old_len, name, new_len); memcpy(res + old_len, name, new_len);
if (col_names) {
ut_free((char*)col_names);
}
return(res); return(res);
} }
...@@ -183,7 +171,8 @@ void ...@@ -183,7 +171,8 @@ void
dict_mem_table_add_col( dict_mem_table_add_col(
/*===================*/ /*===================*/
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
const char* name, /* in: column name */ mem_heap_t* heap, /* in: temporary memory heap, or NULL */
const char* name, /* in: column name, or NULL */
ulint mtype, /* in: main datatype */ ulint mtype, /* in: main datatype */
ulint prtype, /* in: precise type */ ulint prtype, /* in: precise type */
ulint len) /* in: precision */ ulint len) /* in: precision */
...@@ -191,21 +180,32 @@ dict_mem_table_add_col( ...@@ -191,21 +180,32 @@ dict_mem_table_add_col(
dict_col_t* col; dict_col_t* col;
ulint mbminlen; ulint mbminlen;
ulint mbmaxlen; ulint mbmaxlen;
mem_heap_t* heap; ulint i;
ut_ad(table && name); ut_ad(table);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N); ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
ut_ad(!heap == !name);
table->n_def++; i = table->n_def++;
heap = table->n_def < table->n_cols ? NULL : table->heap; if (name) {
table->col_names = dict_add_col_name(table->col_names, if (UNIV_UNLIKELY(table->n_def == table->n_cols)) {
table->n_def - 1, heap = table->heap;
name, heap); }
if (UNIV_LIKELY(i) && UNIV_UNLIKELY(!table->col_names)) {
/* All preceding column names are empty. */
char* s = mem_heap_alloc(heap, table->n_def);
memset(s, 0, table->n_def);
table->col_names = s;
}
table->col_names = dict_add_col_name(table->col_names,
i, name, heap);
}
col = (dict_col_t*) dict_table_get_nth_col(table, table->n_def - 1); col = (dict_col_t*) dict_table_get_nth_col(table, i);
col->ind = table->n_def - 1; col->ind = i;
col->ord_part = 0; col->ord_part = 0;
col->mtype = (unsigned int) mtype; col->mtype = (unsigned int) mtype;
...@@ -318,7 +318,7 @@ dict_mem_index_add_field( ...@@ -318,7 +318,7 @@ dict_mem_index_add_field(
{ {
dict_field_t* field; dict_field_t* field;
ut_ad(index && name); ut_ad(index);
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N); ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
index->n_def++; index->n_def++;
......
...@@ -62,12 +62,6 @@ static bool innodb_inited = 0; ...@@ -62,12 +62,6 @@ static bool innodb_inited = 0;
*/ */
static handlerton *innodb_hton_ptr; static handlerton *innodb_hton_ptr;
/* Store MySQL definition of 'byte': in Linux it is char while InnoDB
uses unsigned char; the header univ.i which we include next defines
'byte' as a macro which expands to 'unsigned char' */
typedef uchar mysql_byte;
#define INSIDE_HA_INNOBASE_CC #define INSIDE_HA_INNOBASE_CC
/* Include necessary InnoDB headers */ /* Include necessary InnoDB headers */
...@@ -148,7 +142,7 @@ static HASH innobase_open_tables; ...@@ -148,7 +142,7 @@ static HASH innobase_open_tables;
bool nw_panic = FALSE; bool nw_panic = FALSE;
#endif #endif
static mysql_byte* innobase_get_key(INNOBASE_SHARE *share, size_t *length, static uchar* innobase_get_key(INNOBASE_SHARE *share, size_t *length,
my_bool not_used __attribute__((unused))); my_bool not_used __attribute__((unused)));
static INNOBASE_SHARE *get_share(const char *table_name); static INNOBASE_SHARE *get_share(const char *table_name);
static void free_share(INNOBASE_SHARE *share); static void free_share(INNOBASE_SHARE *share);
...@@ -1919,6 +1913,8 @@ innobase_commit( ...@@ -1919,6 +1913,8 @@ innobase_commit(
trx_mark_sql_stat_end(trx); trx_mark_sql_stat_end(trx);
} }
trx->n_autoinc_rows = 0; /* Reset the number AUTO-INC rows required */
if (trx->declared_to_be_inside_innodb) { if (trx->declared_to_be_inside_innodb) {
/* Release our possible ticket in the FIFO */ /* Release our possible ticket in the FIFO */
...@@ -2415,7 +2411,7 @@ ha_innobase::open( ...@@ -2415,7 +2411,7 @@ ha_innobase::open(
upd_and_key_val_buff_len = upd_and_key_val_buff_len =
table->s->reclength + table->s->max_key_length table->s->reclength + table->s->max_key_length
+ MAX_REF_PARTS * 3; + MAX_REF_PARTS * 3;
if (!(mysql_byte*) my_multi_malloc(MYF(MY_WME), if (!(uchar*) my_multi_malloc(MYF(MY_WME),
&upd_buff, upd_and_key_val_buff_len, &upd_buff, upd_and_key_val_buff_len,
&key_val_buff, upd_and_key_val_buff_len, &key_val_buff, upd_and_key_val_buff_len,
NullS)) { NullS)) {
...@@ -2849,8 +2845,8 @@ inline ...@@ -2849,8 +2845,8 @@ inline
uint uint
innobase_read_from_2_little_endian( innobase_read_from_2_little_endian(
/*===============================*/ /*===============================*/
/* out: value */ /* out: value */
const mysql_byte* buf) /* in: from where to read */ const uchar* buf) /* in: from where to read */
{ {
return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1]))); return (uint) ((ulint)(buf[0]) + 256 * ((ulint)(buf[1])));
} }
...@@ -2866,7 +2862,7 @@ ha_innobase::store_key_val_for_row( ...@@ -2866,7 +2862,7 @@ ha_innobase::store_key_val_for_row(
char* buff, /* in/out: buffer for the key value (in MySQL char* buff, /* in/out: buffer for the key value (in MySQL
format) */ format) */
uint buff_len,/* in: buffer length */ uint buff_len,/* in: buffer length */
const mysql_byte* record)/* in: row in MySQL format */ const uchar* record)/* in: row in MySQL format */
{ {
KEY* key_info = table->key_info + keynr; KEY* key_info = table->key_info + keynr;
KEY_PART_INFO* key_part = key_info->key_part; KEY_PART_INFO* key_part = key_info->key_part;
...@@ -3063,7 +3059,7 @@ ha_innobase::store_key_val_for_row( ...@@ -3063,7 +3059,7 @@ ha_innobase::store_key_val_for_row(
CHARSET_INFO* cs; CHARSET_INFO* cs;
ulint true_len; ulint true_len;
ulint key_len; ulint key_len;
const mysql_byte* src_start; const uchar* src_start;
int error=0; int error=0;
enum_field_types real_type; enum_field_types real_type;
...@@ -3342,6 +3338,93 @@ build_template( ...@@ -3342,6 +3338,93 @@ build_template(
} }
} }
/************************************************************************
This special handling is really to overcome the limitations of MySQL's
binlogging. We need to eliminate the non-determinism that will arise in
INSERT ... SELECT type of statements, since MySQL binlog only stores the
min value of the autoinc interval. Once that is fixed we can get rid of
the special lock handling.*/
ulong
ha_innobase::innobase_autoinc_lock(void)
/*====================================*/
/* out: DB_SUCCESS if all OK else
error code */
{
ulint error = DB_SUCCESS;
if (thd_sql_command(user_thd) == SQLCOM_INSERT) {
dict_table_autoinc_lock(prebuilt->table);
/* We peek at the dict_table_t::auto_inc_lock to check if
another statement has locked it */
if (prebuilt->trx->auto_inc_lock != NULL) {
/* Release the mutex to avoid deadlocks */
dict_table_autoinc_unlock(prebuilt->table);
goto acquire_auto_inc_lock;
}
} else {
acquire_auto_inc_lock:
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error == DB_SUCCESS) {
dict_table_autoinc_lock(prebuilt->table);
}
}
return(ulong(error));
}
/************************************************************************
Reset the autoinc value in the table.*/
ulong
ha_innobase::innobase_reset_autoinc(
/*================================*/
/* out: DB_SUCCESS if all went well
else error code */
ulonglong autoinc) /* in: value to store */
{
ulint error;
error = innobase_autoinc_lock();
if (error == DB_SUCCESS) {
dict_table_autoinc_initialize(prebuilt->table, autoinc);
dict_table_autoinc_unlock(prebuilt->table);
}
return(ulong(error));
}
/************************************************************************
Store the autoinc value in the table. The autoinc value is only set if
it's greater than the existing autoinc value in the table.*/
ulong
ha_innobase::innobase_set_max_autoinc(
/*==================================*/
/* out: DB_SUCCES if all went well
else error code */
ulonglong auto_inc) /* in: value to store */
{
ulint error;
error = innobase_autoinc_lock();
if (error == DB_SUCCESS) {
dict_table_autoinc_update(prebuilt->table, auto_inc);
dict_table_autoinc_unlock(prebuilt->table);
}
return(ulong(error));
}
/************************************************************************ /************************************************************************
Stores a row in an InnoDB database, to the table specified in this Stores a row in an InnoDB database, to the table specified in this
handle. */ handle. */
...@@ -3349,12 +3432,10 @@ handle. */ ...@@ -3349,12 +3432,10 @@ handle. */
int int
ha_innobase::write_row( ha_innobase::write_row(
/*===================*/ /*===================*/
/* out: error code */ /* out: error code */
mysql_byte* record) /* in: a row in MySQL format */ uchar* record) /* in: a row in MySQL format */
{ {
int error; int error = 0;
longlong auto_inc;
longlong dummy;
ibool auto_inc_used= FALSE; ibool auto_inc_used= FALSE;
ulint sql_command; ulint sql_command;
trx_t* trx = thd_to_trx(user_thd); trx_t* trx = thd_to_trx(user_thd);
...@@ -3453,62 +3534,20 @@ ha_innobase::write_row( ...@@ -3453,62 +3534,20 @@ ha_innobase::write_row(
num_write_row++; num_write_row++;
/* This is the case where the table has an auto-increment column */
if (table->next_number_field && record == table->record[0]) { if (table->next_number_field && record == table->record[0]) {
/* This is the case where the table has an
auto-increment column */
/* Initialize the auto-inc counter if it has not been
initialized yet */
if (0 == dict_table_autoinc_peek(prebuilt->table)) {
/* This call initializes the counter */
error = innobase_read_and_init_auto_inc(&dummy);
if (error) {
/* Deadlock or lock wait timeout */
goto func_exit;
}
/* We have to set sql_stat_start to TRUE because
the above call probably has called a select, and
has reset that flag; row_insert_for_mysql has to
know to set the IX intention lock on the table,
something it only does at the start of each
statement */
prebuilt->sql_stat_start = TRUE;
}
/* We have to use the transactional lock mechanism on the if ((error = update_auto_increment())) {
auto-inc counter of the table to ensure that replication and
roll-forward of the binlog exactly imitates also the given
auto-inc values. The lock is released at each SQL statement's
end. This lock also prevents a race where two threads would
call ::get_auto_increment() simultaneously. */
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error != DB_SUCCESS) {
/* Deadlock or lock wait timeout */
error = convert_error_code_to_mysql(error, user_thd);
goto func_exit; goto func_exit;
} }
/* We must use the handler code to update the auto-increment auto_inc_used = TRUE;
value to be sure that we increment it correctly. */
if ((error= update_auto_increment()))
goto func_exit;
auto_inc_used = 1;
} }
if (prebuilt->mysql_template == NULL if (prebuilt->mysql_template == NULL
|| prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) { || prebuilt->template_type != ROW_MYSQL_WHOLE_ROW) {
/* Build the template used in converting quickly between /* Build the template used in converting quickly between
the two database formats */ the two database formats */
...@@ -3519,40 +3558,63 @@ ha_innobase::write_row( ...@@ -3519,40 +3558,63 @@ ha_innobase::write_row(
error = row_insert_for_mysql((byte*) record, prebuilt); error = row_insert_for_mysql((byte*) record, prebuilt);
if (error == DB_SUCCESS && auto_inc_used) { /* Handle duplicate key errors */
if (auto_inc_used) {
ulonglong auto_inc;
/* Fetch the value that was set in the autoincrement field */ /* Note the number of rows processed for this statement, used
by get_auto_increment() to determine the number of AUTO-INC
values to reserve. This is only useful for a mult-value INSERT
and is a statement level counter.*/
if (trx->n_autoinc_rows > 0) {
--trx->n_autoinc_rows;
}
/* Get the value that MySQL attempted to store in the table.*/
auto_inc = table->next_number_field->val_int(); auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) { switch (error) {
/* This call will update the counter according to the case DB_DUPLICATE_KEY:
value that was inserted in the table */
dict_table_autoinc_update(prebuilt->table, auto_inc); /* A REPLACE command and LOAD DATA INFILE REPLACE
} handle a duplicate key error themselves, but we
} must update the autoinc counter if we are performing
those statements. */
switch (sql_command) {
case SQLCOM_LOAD:
if ((trx->duplicates
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) {
/* A REPLACE command and LOAD DATA INFILE REPLACE handle a duplicate goto set_max_autoinc;
key error themselves, and we must update the autoinc counter if we are }
performing those statements. */ break;
if (error == DB_DUPLICATE_KEY && auto_inc_used case SQLCOM_REPLACE:
&& (sql_command == SQLCOM_REPLACE case SQLCOM_INSERT_SELECT:
|| sql_command == SQLCOM_REPLACE_SELECT case SQLCOM_REPLACE_SELECT:
|| (sql_command == SQLCOM_INSERT goto set_max_autoinc;
&& ((trx->duplicates break;
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE))
|| (sql_command == SQLCOM_LOAD
&& ((trx->duplicates
& (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== (TRX_DUP_IGNORE | TRX_DUP_REPLACE))))) {
auto_inc = table->next_number_field->val_int(); default:
break;
}
if (auto_inc != 0) { break;
dict_table_autoinc_update(prebuilt->table, auto_inc);
case DB_SUCCESS:
/* If the actual value inserted is greater than
the upper limit of the interval, then we try and
update the table upper limit. Note: last_value
will be 0 if get_auto_increment() was not called.*/
if (auto_inc > prebuilt->last_value) {
set_max_autoinc:
auto_inc += prebuilt->table->autoinc_increment;
innobase_set_max_autoinc(auto_inc);
}
break;
} }
} }
...@@ -3560,8 +3622,6 @@ ha_innobase::write_row( ...@@ -3560,8 +3622,6 @@ ha_innobase::write_row(
error = convert_error_code_to_mysql(error, user_thd); error = convert_error_code_to_mysql(error, user_thd);
/* Tell InnoDB server that there might be work for
utility threads: */
func_exit: func_exit:
innobase_active_small(); innobase_active_small();
...@@ -3577,16 +3637,16 @@ calc_row_difference( ...@@ -3577,16 +3637,16 @@ calc_row_difference(
/*================*/ /*================*/
/* out: error number or 0 */ /* out: error number or 0 */
upd_t* uvect, /* in/out: update vector */ upd_t* uvect, /* in/out: update vector */
mysql_byte* old_row, /* in: old row in MySQL format */ uchar* old_row, /* in: old row in MySQL format */
mysql_byte* new_row, /* in: new row in MySQL format */ uchar* new_row, /* in: new row in MySQL format */
struct st_table* table, /* in: table in MySQL data struct st_table* table, /* in: table in MySQL data
dictionary */ dictionary */
mysql_byte* upd_buff, /* in: buffer to use */ uchar* upd_buff, /* in: buffer to use */
ulint buff_len, /* in: buffer length */ ulint buff_len, /* in: buffer length */
row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */ row_prebuilt_t* prebuilt, /* in: InnoDB prebuilt struct */
THD* thd) /* in: user thread */ THD* thd) /* in: user thread */
{ {
mysql_byte* original_upd_buff = upd_buff; uchar* original_upd_buff = upd_buff;
Field* field; Field* field;
enum_field_types field_mysql_type; enum_field_types field_mysql_type;
uint n_fields; uint n_fields;
...@@ -3730,8 +3790,8 @@ int ...@@ -3730,8 +3790,8 @@ int
ha_innobase::update_row( ha_innobase::update_row(
/*====================*/ /*====================*/
/* out: error number or 0 */ /* out: error number or 0 */
const mysql_byte* old_row,/* in: old row in MySQL format */ const uchar* old_row, /* in: old row in MySQL format */
mysql_byte* new_row)/* in: new row in MySQL format */ uchar* new_row) /* in: new row in MySQL format */
{ {
upd_t* uvect; upd_t* uvect;
int error = 0; int error = 0;
...@@ -3753,7 +3813,7 @@ ha_innobase::update_row( ...@@ -3753,7 +3813,7 @@ ha_innobase::update_row(
/* Build an update vector from the modified fields in the rows /* Build an update vector from the modified fields in the rows
(uses upd_buff of the handle) */ (uses upd_buff of the handle) */
calc_row_difference(uvect, (mysql_byte*) old_row, new_row, table, calc_row_difference(uvect, (uchar*) old_row, new_row, table,
upd_buff, (ulint)upd_and_key_val_buff_len, upd_buff, (ulint)upd_and_key_val_buff_len,
prebuilt, user_thd); prebuilt, user_thd);
...@@ -3766,6 +3826,32 @@ ha_innobase::update_row( ...@@ -3766,6 +3826,32 @@ ha_innobase::update_row(
error = row_update_for_mysql((byte*) old_row, prebuilt); error = row_update_for_mysql((byte*) old_row, prebuilt);
/* We need to do some special AUTOINC handling for the following case:
INSERT INTO t (c1,c2) VALUES(x,y) ON DUPLICATE KEY UPDATE ...
We need to use the AUTOINC counter that was actually used by
MySQL in the UPDATE statement, which can be different from the
value used in the INSERT statement.*/
if (error == DB_SUCCESS
&& table->next_number_field
&& new_row == table->record[0]
&& thd_sql_command(user_thd) == SQLCOM_INSERT
&& (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))
== TRX_DUP_IGNORE) {
longlong auto_inc;
auto_inc = table->next_number_field->val_int();
if (auto_inc != 0) {
auto_inc += prebuilt->table->autoinc_increment;
innobase_set_max_autoinc(auto_inc);
}
}
innodb_srv_conc_exit_innodb(trx); innodb_srv_conc_exit_innodb(trx);
error = convert_error_code_to_mysql(error, user_thd); error = convert_error_code_to_mysql(error, user_thd);
...@@ -3784,8 +3870,8 @@ Deletes a row given as the parameter. */ ...@@ -3784,8 +3870,8 @@ Deletes a row given as the parameter. */
int int
ha_innobase::delete_row( ha_innobase::delete_row(
/*====================*/ /*====================*/
/* out: error number or 0 */ /* out: error number or 0 */
const mysql_byte* record) /* in: a row in MySQL format */ const uchar* record) /* in: a row in MySQL format */
{ {
int error = 0; int error = 0;
trx_t* trx = thd_to_trx(user_thd); trx_t* trx = thd_to_trx(user_thd);
...@@ -3794,6 +3880,19 @@ ha_innobase::delete_row( ...@@ -3794,6 +3880,19 @@ ha_innobase::delete_row(
ut_a(prebuilt->trx == trx); ut_a(prebuilt->trx == trx);
/* Only if the table has an AUTOINC column */
if (table->found_next_number_field && record == table->record[0]) {
ulonglong dummy = 0;
error = innobase_get_auto_increment(&dummy);
if (error == DB_SUCCESS) {
dict_table_autoinc_unlock(prebuilt->table);
} else {
goto error_exit;
}
}
if (!prebuilt->upd_node) { if (!prebuilt->upd_node) {
row_get_prebuilt_update_vector(prebuilt); row_get_prebuilt_update_vector(prebuilt);
} }
...@@ -3808,6 +3907,7 @@ ha_innobase::delete_row( ...@@ -3808,6 +3907,7 @@ ha_innobase::delete_row(
innodb_srv_conc_exit_innodb(trx); innodb_srv_conc_exit_innodb(trx);
error_exit:
error = convert_error_code_to_mysql(error, user_thd); error = convert_error_code_to_mysql(error, user_thd);
/* Tell the InnoDB server that there might be work for /* Tell the InnoDB server that there might be work for
...@@ -4011,9 +4111,9 @@ ha_innobase::index_read( ...@@ -4011,9 +4111,9 @@ ha_innobase::index_read(
/*====================*/ /*====================*/
/* out: 0, HA_ERR_KEY_NOT_FOUND, /* out: 0, HA_ERR_KEY_NOT_FOUND,
or error number */ or error number */
mysql_byte* buf, /* in/out: buffer for the returned uchar* buf, /* in/out: buffer for the returned
row */ row */
const mysql_byte* key_ptr,/* in: key value; if this is NULL const uchar* key_ptr, /* in: key value; if this is NULL
we position the cursor at the we position the cursor at the
start or end of index; this can start or end of index; this can
also contain an InnoDB row id, in also contain an InnoDB row id, in
...@@ -4110,54 +4210,78 @@ row with the current key value or prefix. */ ...@@ -4110,54 +4210,78 @@ row with the current key value or prefix. */
int int
ha_innobase::index_read_last( ha_innobase::index_read_last(
/*=========================*/ /*=========================*/
/* out: 0, HA_ERR_KEY_NOT_FOUND, or an /* out: 0, HA_ERR_KEY_NOT_FOUND, or an
error code */ error code */
mysql_byte* buf, /* out: fetched row */ uchar* buf, /* out: fetched row */
const mysql_byte* key_ptr, /* in: key value, or a prefix of a full const uchar* key_ptr,/* in: key value, or a prefix of a full
key value */ key value */
uint key_len) /* in: length of the key val or prefix uint key_len)/* in: length of the key val or prefix
in bytes */ in bytes */
{ {
return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST)); return(index_read(buf, key_ptr, key_len, HA_READ_PREFIX_LAST));
} }
/************************************************************************ /************************************************************************
Changes the active index of a handle. */ Get the index for a handle. Does not change active index.*/
int dict_index_t*
ha_innobase::change_active_index( ha_innobase::innobase_get_index(
/*=============================*/ /*============================*/
/* out: 0 or error code */ /* out: NULL or index instance. */
uint keynr) /* in: use this index; MAX_KEY means always clustered uint keynr) /* in: use this index; MAX_KEY means always
index, even if it was internally generated by clustered index, even if it was internally
InnoDB */ generated by InnoDB */
{ {
KEY* key=0; KEY* key = 0;
DBUG_ENTER("change_active_index"); dict_index_t* index = 0;
DBUG_ENTER("innobase_get_index");
ha_statistic_increment(&SSV::ha_read_key_count); ha_statistic_increment(&SSV::ha_read_key_count);
ut_ad(user_thd == ha_thd()); ut_ad(user_thd == ha_thd());
ut_a(prebuilt->trx == thd_to_trx(user_thd)); ut_a(prebuilt->trx == thd_to_trx(user_thd));
active_index = keynr;
if (keynr != MAX_KEY && table->s->keys > 0) { if (keynr != MAX_KEY && table->s->keys > 0) {
key = table->key_info + active_index; key = table->key_info + keynr;
prebuilt->index = dict_table_get_index_noninline( index = dict_table_get_index_noninline(
prebuilt->table, key->name); prebuilt->table, key->name);
} else { } else {
prebuilt->index = dict_table_get_first_index_noninline( index = dict_table_get_first_index_noninline(prebuilt->table);
prebuilt->table);
} }
if (!prebuilt->index) { if (!index) {
sql_print_error( sql_print_error(
"Innodb could not find key n:o %u with name %s " "Innodb could not find key n:o %u with name %s "
"from dict cache for table %s", "from dict cache for table %s",
keynr, key ? key->name : "NULL", keynr, key ? key->name : "NULL",
prebuilt->table->name); prebuilt->table->name);
}
DBUG_RETURN(index);
}
/************************************************************************
Changes the active index of a handle. */
int
ha_innobase::change_active_index(
/*=============================*/
/* out: 0 or error code */
uint keynr) /* in: use this index; MAX_KEY means always clustered
index, even if it was internally generated by
InnoDB */
{
DBUG_ENTER("change_active_index");
ut_ad(user_thd == ha_thd());
ut_a(prebuilt->trx == thd_to_trx(user_thd));
active_index = keynr;
prebuilt->index = innobase_get_index(keynr);
if (!prebuilt->index) {
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -4188,10 +4312,10 @@ int ...@@ -4188,10 +4312,10 @@ int
ha_innobase::index_read_idx( ha_innobase::index_read_idx(
/*========================*/ /*========================*/
/* out: error number or 0 */ /* out: error number or 0 */
mysql_byte* buf, /* in/out: buffer for the returned uchar* buf, /* in/out: buffer for the returned
row */ row */
uint keynr, /* in: use this index */ uint keynr, /* in: use this index */
const mysql_byte* key, /* in: key value; if this is NULL const uchar* key, /* in: key value; if this is NULL
we position the cursor at the we position the cursor at the
start or end of index */ start or end of index */
uint key_len, /* in: key value length */ uint key_len, /* in: key value length */
...@@ -4214,7 +4338,7 @@ ha_innobase::general_fetch( ...@@ -4214,7 +4338,7 @@ ha_innobase::general_fetch(
/*=======================*/ /*=======================*/
/* out: 0, HA_ERR_END_OF_FILE, or error /* out: 0, HA_ERR_END_OF_FILE, or error
number */ number */
mysql_byte* buf, /* in/out: buffer for next row in MySQL uchar* buf, /* in/out: buffer for next row in MySQL
format */ format */
uint direction, /* in: ROW_SEL_NEXT or ROW_SEL_PREV */ uint direction, /* in: ROW_SEL_NEXT or ROW_SEL_PREV */
uint match_mode) /* in: 0, ROW_SEL_EXACT, or uint match_mode) /* in: 0, ROW_SEL_EXACT, or
...@@ -4261,7 +4385,7 @@ ha_innobase::index_next( ...@@ -4261,7 +4385,7 @@ ha_innobase::index_next(
/*====================*/ /*====================*/
/* out: 0, HA_ERR_END_OF_FILE, or error /* out: 0, HA_ERR_END_OF_FILE, or error
number */ number */
mysql_byte* buf) /* in/out: buffer for next row in MySQL uchar* buf) /* in/out: buffer for next row in MySQL
format */ format */
{ {
ha_statistic_increment(&SSV::ha_read_next_count); ha_statistic_increment(&SSV::ha_read_next_count);
...@@ -4277,8 +4401,8 @@ ha_innobase::index_next_same( ...@@ -4277,8 +4401,8 @@ ha_innobase::index_next_same(
/*=========================*/ /*=========================*/
/* out: 0, HA_ERR_END_OF_FILE, or error /* out: 0, HA_ERR_END_OF_FILE, or error
number */ number */
mysql_byte* buf, /* in/out: buffer for the row */ uchar* buf, /* in/out: buffer for the row */
const mysql_byte* key, /* in: key value */ const uchar* key, /* in: key value */
uint keylen) /* in: key value length */ uint keylen) /* in: key value length */
{ {
ha_statistic_increment(&SSV::ha_read_next_count); ha_statistic_increment(&SSV::ha_read_next_count);
...@@ -4293,10 +4417,8 @@ positioned using index_read. */ ...@@ -4293,10 +4417,8 @@ positioned using index_read. */
int int
ha_innobase::index_prev( ha_innobase::index_prev(
/*====================*/ /*====================*/
/* out: 0, HA_ERR_END_OF_FILE, or error /* out: 0, HA_ERR_END_OF_FILE, or error number */
number */ uchar* buf) /* in/out: buffer for previous row in MySQL format */
mysql_byte* buf) /* in/out: buffer for previous row in MySQL
format */
{ {
ha_statistic_increment(&SSV::ha_read_prev_count); ha_statistic_increment(&SSV::ha_read_prev_count);
...@@ -4310,9 +4432,8 @@ corresponding row to buf. */ ...@@ -4310,9 +4432,8 @@ corresponding row to buf. */
int int
ha_innobase::index_first( ha_innobase::index_first(
/*=====================*/ /*=====================*/
/* out: 0, HA_ERR_END_OF_FILE, /* out: 0, HA_ERR_END_OF_FILE, or error code */
or error code */ uchar* buf) /* in/out: buffer for the row */
mysql_byte* buf) /* in/out: buffer for the row */
{ {
int error; int error;
...@@ -4337,8 +4458,8 @@ corresponding row to buf. */ ...@@ -4337,8 +4458,8 @@ corresponding row to buf. */
int int
ha_innobase::index_last( ha_innobase::index_last(
/*====================*/ /*====================*/
/* out: 0, HA_ERR_END_OF_FILE, or error code */ /* out: 0, HA_ERR_END_OF_FILE, or error code */
mysql_byte* buf) /* in/out: buffer for the row */ uchar* buf) /* in/out: buffer for the row */
{ {
int error; int error;
...@@ -4407,7 +4528,7 @@ int ...@@ -4407,7 +4528,7 @@ int
ha_innobase::rnd_next( ha_innobase::rnd_next(
/*==================*/ /*==================*/
/* out: 0, HA_ERR_END_OF_FILE, or error number */ /* out: 0, HA_ERR_END_OF_FILE, or error number */
mysql_byte* buf)/* in/out: returns the row in this buffer, uchar* buf) /* in/out: returns the row in this buffer,
in MySQL format */ in MySQL format */
{ {
int error; int error;
...@@ -4434,14 +4555,12 @@ Fetches a row from the table based on a row reference. */ ...@@ -4434,14 +4555,12 @@ Fetches a row from the table based on a row reference. */
int int
ha_innobase::rnd_pos( ha_innobase::rnd_pos(
/*=================*/ /*=================*/
/* out: 0, HA_ERR_KEY_NOT_FOUND, /* out: 0, HA_ERR_KEY_NOT_FOUND, or error code */
or error code */ uchar* buf, /* in/out: buffer for the row */
mysql_byte* buf, /* in/out: buffer for the row */ uchar* pos) /* in: primary key value of the row in the
mysql_byte* pos) /* in: primary key value of the row in the MySQL format, or the row id if the clustered
MySQL format, or the row id if the clustered index was internally generated by InnoDB; the
index was internally generated by InnoDB; length of data in pos has to be ref_length */
the length of data in pos has to be
ref_length */
{ {
int error; int error;
uint keynr = active_index; uint keynr = active_index;
...@@ -4494,7 +4613,7 @@ was positioned the last time. */ ...@@ -4494,7 +4613,7 @@ was positioned the last time. */
void void
ha_innobase::position( ha_innobase::position(
/*==================*/ /*==================*/
const mysql_byte* record) /* in: row in MySQL format */ const uchar* record) /* in: row in MySQL format */
{ {
uint len; uint len;
...@@ -4636,7 +4755,7 @@ create_table_def( ...@@ -4636,7 +4755,7 @@ create_table_def(
} }
} }
dict_mem_table_add_col(table, dict_mem_table_add_col(table, table->heap,
(char*) field->field_name, (char*) field->field_name,
col_type, col_type,
dtype_form_prtype( dtype_form_prtype(
...@@ -5000,7 +5119,10 @@ ha_innobase::create( ...@@ -5000,7 +5119,10 @@ ha_innobase::create(
maximum value in the column. */ maximum value in the column. */
auto_inc_value = create_info->auto_increment_value; auto_inc_value = create_info->auto_increment_value;
dict_table_autoinc_lock(innobase_table);
dict_table_autoinc_initialize(innobase_table, auto_inc_value); dict_table_autoinc_initialize(innobase_table, auto_inc_value);
dict_table_autoinc_unlock(innobase_table);
} }
/* Tell the InnoDB server that there might be work for /* Tell the InnoDB server that there might be work for
...@@ -5351,7 +5473,7 @@ ha_innobase::records_in_range( ...@@ -5351,7 +5473,7 @@ ha_innobase::records_in_range(
{ {
KEY* key; KEY* key;
dict_index_t* index; dict_index_t* index;
mysql_byte* key_val_buff2 = (mysql_byte*) my_malloc( uchar* key_val_buff2 = (uchar*) my_malloc(
table->s->reclength table->s->reclength
+ table->s->max_key_length + 100, + table->s->max_key_length + 100,
MYF(MY_FAE)); MYF(MY_FAE));
...@@ -5393,7 +5515,7 @@ ha_innobase::records_in_range( ...@@ -5393,7 +5515,7 @@ ha_innobase::records_in_range(
(ulint)upd_and_key_val_buff_len, (ulint)upd_and_key_val_buff_len,
index, index,
(byte*) (min_key ? min_key->key : (byte*) (min_key ? min_key->key :
(const mysql_byte*) 0), (const uchar*) 0),
(ulint) (min_key ? min_key->length : 0), (ulint) (min_key ? min_key->length : 0),
prebuilt->trx); prebuilt->trx);
...@@ -5401,7 +5523,7 @@ ha_innobase::records_in_range( ...@@ -5401,7 +5523,7 @@ ha_innobase::records_in_range(
range_end, (byte*) key_val_buff2, range_end, (byte*) key_val_buff2,
buff2_len, index, buff2_len, index,
(byte*) (max_key ? max_key->key : (byte*) (max_key ? max_key->key :
(const mysql_byte*) 0), (const uchar*) 0),
(ulint) (max_key ? max_key->length : 0), (ulint) (max_key ? max_key->length : 0),
prebuilt->trx); prebuilt->trx);
...@@ -6801,12 +6923,12 @@ bool innobase_show_status(handlerton *hton, THD* thd, ...@@ -6801,12 +6923,12 @@ bool innobase_show_status(handlerton *hton, THD* thd,
locking. locking.
****************************************************************************/ ****************************************************************************/
static mysql_byte* innobase_get_key(INNOBASE_SHARE* share, size_t *length, static uchar* innobase_get_key(INNOBASE_SHARE* share, size_t *length,
my_bool not_used __attribute__((unused))) my_bool not_used __attribute__((unused)))
{ {
*length=share->table_name_length; *length=share->table_name_length;
return (mysql_byte*) share->table_name; return (uchar*) share->table_name;
} }
static INNOBASE_SHARE* get_share(const char* table_name) static INNOBASE_SHARE* get_share(const char* table_name)
...@@ -6816,7 +6938,7 @@ static INNOBASE_SHARE* get_share(const char* table_name) ...@@ -6816,7 +6938,7 @@ static INNOBASE_SHARE* get_share(const char* table_name)
uint length=(uint) strlen(table_name); uint length=(uint) strlen(table_name);
if (!(share=(INNOBASE_SHARE*) hash_search(&innobase_open_tables, if (!(share=(INNOBASE_SHARE*) hash_search(&innobase_open_tables,
(mysql_byte*) table_name, (uchar*) table_name,
length))) { length))) {
share = (INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1, share = (INNOBASE_SHARE *) my_malloc(sizeof(*share)+length+1,
...@@ -6827,7 +6949,7 @@ static INNOBASE_SHARE* get_share(const char* table_name) ...@@ -6827,7 +6949,7 @@ static INNOBASE_SHARE* get_share(const char* table_name)
strmov(share->table_name,table_name); strmov(share->table_name,table_name);
if (my_hash_insert(&innobase_open_tables, if (my_hash_insert(&innobase_open_tables,
(mysql_byte*) share)) { (uchar*) share)) {
pthread_mutex_unlock(&innobase_share_mutex); pthread_mutex_unlock(&innobase_share_mutex);
my_free(share,0); my_free(share,0);
...@@ -6849,7 +6971,7 @@ static void free_share(INNOBASE_SHARE* share) ...@@ -6849,7 +6971,7 @@ static void free_share(INNOBASE_SHARE* share)
pthread_mutex_lock(&innobase_share_mutex); pthread_mutex_lock(&innobase_share_mutex);
if (!--share->use_count) { if (!--share->use_count) {
hash_delete(&innobase_open_tables, (mysql_byte*) share); hash_delete(&innobase_open_tables, (uchar*) share);
thr_lock_delete(&share->lock); thr_lock_delete(&share->lock);
pthread_mutex_destroy(&share->mutex); pthread_mutex_destroy(&share->mutex);
my_free(share, MYF(0)); my_free(share, MYF(0));
...@@ -7070,15 +7192,15 @@ the value of the auto-inc counter. */ ...@@ -7070,15 +7192,15 @@ the value of the auto-inc counter. */
int int
ha_innobase::innobase_read_and_init_auto_inc( ha_innobase::innobase_read_and_init_auto_inc(
/*=========================================*/ /*=========================================*/
/* out: 0 or error code: deadlock or lock wait /* out: 0 or error code:
timeout */ deadlock or lock wait timeout */
longlong* ret) /* out: auto-inc value */ longlong* value) /* out: the autoinc value */
{ {
longlong auto_inc; longlong auto_inc;
ulint old_select_lock_type;
ibool trx_was_not_started = FALSE;
ibool stmt_start; ibool stmt_start;
int error; int mysql_error = 0;
dict_table_t* innodb_table = prebuilt->table;
ibool trx_was_not_started = FALSE;
ut_a(prebuilt); ut_a(prebuilt);
ut_a(prebuilt->table); ut_a(prebuilt->table);
...@@ -7099,103 +7221,47 @@ ha_innobase::innobase_read_and_init_auto_inc( ...@@ -7099,103 +7221,47 @@ ha_innobase::innobase_read_and_init_auto_inc(
trx_search_latch_release_if_reserved(prebuilt->trx); trx_search_latch_release_if_reserved(prebuilt->trx);
auto_inc = dict_table_autoinc_read(prebuilt->table); dict_table_autoinc_lock(prebuilt->table);
if (auto_inc != 0) {
/* Already initialized */
*ret = auto_inc;
error = 0;
goto func_exit_early;
}
error = row_lock_table_autoinc_for_mysql(prebuilt);
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error, user_thd);
goto func_exit_early;
}
/* Check again if someone has initialized the counter meanwhile */
auto_inc = dict_table_autoinc_read(prebuilt->table); auto_inc = dict_table_autoinc_read(prebuilt->table);
if (auto_inc != 0) { /* Was the AUTOINC counter reset during normal processing, if
*ret = auto_inc; so then we simply start count from 1. No need to go to the index.*/
if (auto_inc == 0 && innodb_table->autoinc_inited) {
error = 0; ++auto_inc;
dict_table_autoinc_initialize(innodb_table, auto_inc);
goto func_exit_early;
} }
(void) extra(HA_EXTRA_KEYREAD); if (auto_inc == 0) {
index_init(table->s->next_number_index, 1); dict_index_t* index;
ulint error = DB_SUCCESS;
const char* autoinc_col_name;
/* Starting from 5.0.9, we use a consistent read to read the auto-inc ut_a(!innodb_table->autoinc_inited);
column maximum value. This eliminates the spurious deadlocks caused
by the row X-lock that we previously used. Note the following flaw
in our algorithm: if some other user meanwhile UPDATEs the auto-inc
column, our consistent read will not return the largest value. We
accept this flaw, since the deadlocks were a bigger trouble. */
/* Fetch all the columns in the key */ index = innobase_get_index(table->s->next_number_index);
prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS; autoinc_col_name = table->found_next_number_field->field_name;
old_select_lock_type = prebuilt->select_lock_type;
prebuilt->select_lock_type = LOCK_NONE;
/* Eliminate an InnoDB error print that happens when we try to SELECT error = row_search_max_autoinc(
from a table when no table has been locked in ::external_lock(). */ index, autoinc_col_name, &auto_inc);
prebuilt->trx->n_mysql_tables_in_use++;
error = index_last(table->record[1]); if (error == DB_SUCCESS) {
++auto_inc;
prebuilt->trx->n_mysql_tables_in_use--; dict_table_autoinc_initialize(innodb_table, auto_inc);
prebuilt->select_lock_type = old_select_lock_type;
if (error) {
if (error == HA_ERR_END_OF_FILE) {
/* The table was empty, initialize to 1 */
auto_inc = 1;
error = 0;
} else { } else {
/* This should not happen in a consistent read */ fprintf(stderr, " InnoDB error: Couldn't read the "
sql_print_error("Consistent read of auto-inc column " "max AUTOINC value from index (%s).\n",
"returned %lu", (ulong) error); index->name);
auto_inc = -1;
goto func_exit; mysql_error = 1;
} }
} else {
/* Initialize to max(col) + 1; we use
'found_next_number_field' below because MySQL in SHOW TABLE
STATUS does not seem to set 'next_number_field'. The comment
in table.h says that 'next_number_field' is set when it is
'active'.
Since 5.1 MySQL enforces that we announce fields which we will
read; as we only do a val_*() call, dbug_tmp_use_all_columns()
with read_set is sufficient. */
my_bitmap_map *old_map;
old_map= dbug_tmp_use_all_columns(table, table->read_set);
auto_inc = (longlong) table->found_next_number_field->
val_int_offset(table->s->rec_buff_length) + 1;
dbug_tmp_restore_column_map(table->read_set, old_map);
} }
dict_table_autoinc_initialize(prebuilt->table, auto_inc); *value = auto_inc;
func_exit: dict_table_autoinc_unlock(prebuilt->table);
(void) extra(HA_EXTRA_NO_KEYREAD);
index_end();
*ret = auto_inc;
func_exit_early:
/* Since MySQL does not seem to call autocommit after SHOW TABLE /* Since MySQL does not seem to call autocommit after SHOW TABLE
STATUS (even if we would register the trx here), we commit our STATUS (even if we would register the trx here), we commit our
transaction here if it was started here. This is to eliminate a transaction here if it was started here. This is to eliminate a
...@@ -7210,6 +7276,63 @@ ha_innobase::innobase_read_and_init_auto_inc( ...@@ -7210,6 +7276,63 @@ ha_innobase::innobase_read_and_init_auto_inc(
prebuilt->sql_stat_start = stmt_start; prebuilt->sql_stat_start = stmt_start;
return(mysql_error);
}
/*******************************************************************************
Read the next autoinc value, initialize the table if it's not initialized.
On return if there is no error then the tables AUTOINC lock is locked.*/
ulong
ha_innobase::innobase_get_auto_increment(
ulonglong* value) /* out: autoinc value */
{
ulint error;
do {
error = innobase_autoinc_lock();
if (error == DB_SUCCESS) {
ib_longlong autoinc;
/* Determine the first value of the interval */
autoinc = dict_table_autoinc_read(prebuilt->table);
/* We need to initialize the AUTO-INC value, for
that we release all locks.*/
if (autoinc <= 0) {
trx_t* trx;
trx = prebuilt->trx;
dict_table_autoinc_unlock(prebuilt->table);
if (trx->auto_inc_lock) {
/* If we had reserved the AUTO-INC
lock in this SQL statement we release
it before retrying.*/
row_unlock_table_autoinc_for_mysql(trx);
}
/* Just to make sure */
ut_a(!trx->auto_inc_lock);
int mysql_error;
mysql_error = innobase_read_and_init_auto_inc(
&autoinc);
if (!mysql_error) {
/* Should have read the proper value */
ut_a(autoinc > 0);
} else {
error = DB_ERROR;
}
} else {
*value = (ulonglong) autoinc;
}
}
} while (*value == 0 && error == DB_SUCCESS);
return(error); return(error);
} }
...@@ -7221,37 +7344,87 @@ auto-inc counter in *first_value, and ULONGLONG_MAX in *nb_reserved_values (as ...@@ -7221,37 +7344,87 @@ auto-inc counter in *first_value, and ULONGLONG_MAX in *nb_reserved_values (as
we have a table-level lock). offset, increment, nb_desired_values are ignored. we have a table-level lock). offset, increment, nb_desired_values are ignored.
*first_value is set to -1 if error (deadlock or lock wait timeout) */ *first_value is set to -1 if error (deadlock or lock wait timeout) */
void ha_innobase::get_auto_increment( void
ha_innobase::get_auto_increment(
/*=================================*/ /*=================================*/
ulonglong offset, /* in */ ulonglong offset, /* in: */
ulonglong increment, /* in */ ulonglong increment, /* in: table autoinc increment */
ulonglong nb_desired_values, /* in */ ulonglong nb_desired_values, /* in: number of values reqd */
ulonglong *first_value, /* out */ ulonglong *first_value, /* out: the autoinc value */
ulonglong *nb_reserved_values) /* out */ ulonglong *nb_reserved_values) /* out: count of reserved values */
{ {
longlong nr; ulint error;
int error; ulonglong autoinc = 0;
/* Prepare prebuilt->trx in the table handle */ /* Prepare prebuilt->trx in the table handle */
update_thd(ha_thd()); update_thd(ha_thd());
error = innobase_read_and_init_auto_inc(&nr); error = innobase_get_auto_increment(&autoinc);
if (error) { if (error != DB_SUCCESS) {
/* This should never happen in the current (5.0.6) code, since /* This should never happen in the code > ver 5.0.6,
we call this function only after the counter has been since we call this function only after the counter
initialized. */ has been initialized. */
ut_print_timestamp(stderr); ut_print_timestamp(stderr);
sql_print_error("Error %lu in ::get_auto_increment()", sql_print_error("Error %lu in ::get_auto_increment()", error);
(ulong) error);
*first_value= (~(ulonglong) 0); *first_value = (~(ulonglong) 0);
return; return;
} }
*first_value= (ulonglong) nr; /* This is a hack, since nb_desired_values seems to be accurate only
/* table-level autoinc lock reserves up to +inf */ for the first call to get_auto_increment() for multi-row INSERT and
*nb_reserved_values= ULONGLONG_MAX; meaningless for other statements e.g, LOAD etc. Subsequent calls to
this method for the same statement results in different values which
don't make sense. Therefore we store the value the first time we are
called and count down from that as rows are written (see write_row()).
We make one exception, if the *first_value is precomputed by MySQL
we use that value. And set the number of reserved values to 1 if
this is the first time we were called for the SQL statement, this
will force MySQL to call us for the next value. If we are in the
middle of a multi-row insert we preserve the existing counter.*/
if (*first_value == 0) {
/* Called for the first time ? */
if (prebuilt->trx->n_autoinc_rows == 0) {
prebuilt->trx->n_autoinc_rows = nb_desired_values;
/* It's possible for nb_desired_values to be 0:
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
if (nb_desired_values == 0) {
++prebuilt->trx->n_autoinc_rows;
}
}
*first_value = autoinc;
} else if (prebuilt->trx->n_autoinc_rows == 0) {
prebuilt->trx->n_autoinc_rows = 1;
}
ut_a(prebuilt->trx->n_autoinc_rows > 0);
*nb_reserved_values = prebuilt->trx->n_autoinc_rows;
/* Compute the last value in the interval */
prebuilt->last_value = *first_value + (*nb_reserved_values * increment);
ut_a(prebuilt->last_value >= *first_value);
/* Update the table autoinc variable */
dict_table_autoinc_update(prebuilt->table, prebuilt->last_value);
/* The increment to be used to increase the AUTOINC value, we use
this in write_row() and update_row() to increase the autoinc counter
for columns that are filled by the user.*/
prebuilt->table->autoinc_increment = increment;
dict_table_autoinc_unlock(prebuilt->table);
} }
/* See comment in handler.h */ /* See comment in handler.h */
...@@ -7272,7 +7445,7 @@ ha_innobase::reset_auto_increment(ulonglong value) ...@@ -7272,7 +7445,7 @@ ha_innobase::reset_auto_increment(ulonglong value)
DBUG_RETURN(error); DBUG_RETURN(error);
} }
dict_table_autoinc_initialize(prebuilt->table, value); innobase_reset_autoinc(value);
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -7299,9 +7472,9 @@ ha_innobase::cmp_ref( ...@@ -7299,9 +7472,9 @@ ha_innobase::cmp_ref(
/*=================*/ /*=================*/
/* out: < 0 if ref1 < ref2, 0 if equal, else /* out: < 0 if ref1 < ref2, 0 if equal, else
> 0 */ > 0 */
const mysql_byte* ref1, /* in: an (internal) primary key value in the const uchar* ref1, /* in: an (internal) primary key value in the
MySQL key value format */ MySQL key value format */
const mysql_byte* ref2) /* in: an (internal) primary key value in the const uchar* ref2) /* in: an (internal) primary key value in the
MySQL key value format */ MySQL key value format */
{ {
enum_field_types mysql_type; enum_field_types mysql_type;
...@@ -7558,6 +7731,7 @@ innobase_xa_prepare( ...@@ -7558,6 +7731,7 @@ innobase_xa_prepare(
row_unlock_table_autoinc_for_mysql(trx); row_unlock_table_autoinc_for_mysql(trx);
} }
/* Store the current undo_no of the transaction so that we /* Store the current undo_no of the transaction so that we
know where to roll back if we have to roll back the next know where to roll back if we have to roll back the next
SQL statement */ SQL statement */
......
...@@ -32,7 +32,10 @@ typedef struct st_innobase_share { ...@@ -32,7 +32,10 @@ typedef struct st_innobase_share {
} INNOBASE_SHARE; } INNOBASE_SHARE;
struct dict_index_struct;
struct row_prebuilt_struct; struct row_prebuilt_struct;
typedef struct dict_index_struct dict_index_t;
typedef struct row_prebuilt_struct row_prebuilt_t; typedef struct row_prebuilt_struct row_prebuilt_t;
/* The class defining a handle to an Innodb table */ /* The class defining a handle to an Innodb table */
...@@ -70,6 +73,11 @@ class ha_innobase: public handler ...@@ -70,6 +73,11 @@ class ha_innobase: public handler
int change_active_index(uint keynr); int change_active_index(uint keynr);
int general_fetch(uchar* buf, uint direction, uint match_mode); int general_fetch(uchar* buf, uint direction, uint match_mode);
int innobase_read_and_init_auto_inc(longlong* ret); int innobase_read_and_init_auto_inc(longlong* ret);
ulong innobase_autoinc_lock();
ulong innobase_set_max_autoinc(ulonglong auto_inc);
ulong innobase_reset_autoinc(ulonglong auto_inc);
ulong innobase_get_auto_increment(ulonglong* value);
dict_index_t* innobase_get_index(uint keynr);
/* Init values for the class: */ /* Init values for the class: */
public: public:
......
...@@ -462,7 +462,8 @@ ibuf_data_init_for_space( ...@@ -462,7 +462,8 @@ ibuf_data_init_for_space(
page_t* root; page_t* root;
page_t* header_page; page_t* header_page;
mtr_t mtr; mtr_t mtr;
char buf[50]; char* buf;
mem_heap_t* heap;
dict_table_t* table; dict_table_t* table;
dict_index_t* index; dict_index_t* index;
ulint n_used; ulint n_used;
...@@ -516,16 +517,20 @@ ibuf_data_init_for_space( ...@@ -516,16 +517,20 @@ ibuf_data_init_for_space(
ibuf_exit(); ibuf_exit();
heap = mem_heap_create(450);
buf = mem_heap_alloc(heap, 50);
sprintf(buf, "SYS_IBUF_TABLE_%lu", (ulong) space); sprintf(buf, "SYS_IBUF_TABLE_%lu", (ulong) space);
/* use old-style record format for the insert buffer */ /* use old-style record format for the insert buffer */
table = dict_mem_table_create(buf, space, 2, 0); table = dict_mem_table_create(buf, space, 2, 0);
dict_mem_table_add_col(table, "PAGE_NO", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, "TYPES", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "TYPES", DATA_BINARY, 0, 0);
table->id = ut_dulint_add(DICT_IBUF_ID_MIN, space); table->id = ut_dulint_add(DICT_IBUF_ID_MIN, space);
dict_table_add_to_cache(table); dict_table_add_to_cache(table, heap);
mem_heap_free(heap);
index = dict_mem_index_create( index = dict_mem_index_create(
buf, "CLUST_IND", space, buf, "CLUST_IND", space,
...@@ -1139,7 +1144,7 @@ ibuf_dummy_index_add_col( ...@@ -1139,7 +1144,7 @@ ibuf_dummy_index_add_col(
ulint len) /* in: length of the column */ ulint len) /* in: length of the column */
{ {
ulint i = index->table->n_def; ulint i = index->table->n_def;
dict_mem_table_add_col(index->table, "DUMMY", dict_mem_table_add_col(index->table, NULL, NULL,
dtype_get_mtype(type), dtype_get_mtype(type),
dtype_get_prtype(type), dtype_get_prtype(type),
dtype_get_len(type)); dtype_get_len(type));
...@@ -1161,11 +1166,6 @@ ibuf_dummy_index_free( ...@@ -1161,11 +1166,6 @@ ibuf_dummy_index_free(
dict_mem_table_free(table); dict_mem_table_free(table);
} }
void
dict_index_print_low(
/*=================*/
dict_index_t* index); /* in: index */
/************************************************************************* /*************************************************************************
Builds the entry to insert into a non-clustered index when we have the Builds the entry to insert into a non-clustered index when we have the
corresponding record in an ibuf index. */ corresponding record in an ibuf index. */
......
...@@ -171,6 +171,13 @@ dict_col_name_is_reserved( ...@@ -171,6 +171,13 @@ dict_col_name_is_reserved(
/* out: TRUE if name is reserved */ /* out: TRUE if name is reserved */
const char* name); /* in: column name */ const char* name); /* in: column name */
/************************************************************************ /************************************************************************
Acquire the autoinc lock.*/
void
dict_table_autoinc_lock(
/*====================*/
dict_table_t* table); /* in: table */
/************************************************************************
Initializes the autoinc counter. It is not an error to initialize an already Initializes the autoinc counter. It is not an error to initialize an already
initialized counter. */ initialized counter. */
...@@ -180,22 +187,6 @@ dict_table_autoinc_initialize( ...@@ -180,22 +187,6 @@ dict_table_autoinc_initialize(
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
ib_longlong value); /* in: next value to assign to a row */ ib_longlong value); /* in: next value to assign to a row */
/************************************************************************ /************************************************************************
Gets the next autoinc value (== autoinc counter value), 0 if not yet
initialized. If initialized, increments the counter by 1. */
ib_longlong
dict_table_autoinc_get(
/*===================*/
/* out: value for a new row, or 0 */
dict_table_t* table); /* in: table */
/************************************************************************
Decrements the autoinc counter value by 1. */
void
dict_table_autoinc_decrement(
/*=========================*/
dict_table_t* table); /* in: table */
/************************************************************************
Reads the next autoinc value (== autoinc counter value), 0 if not yet Reads the next autoinc value (== autoinc counter value), 0 if not yet
initialized. */ initialized. */
...@@ -205,15 +196,6 @@ dict_table_autoinc_read( ...@@ -205,15 +196,6 @@ dict_table_autoinc_read(
/* out: value for a new row, or 0 */ /* out: value for a new row, or 0 */
dict_table_t* table); /* in: table */ dict_table_t* table); /* in: table */
/************************************************************************ /************************************************************************
Peeks the autoinc counter value, 0 if not yet initialized. Does not
increment the counter. The read not protected by any mutex! */
ib_longlong
dict_table_autoinc_peek(
/*====================*/
/* out: value of the counter */
dict_table_t* table); /* in: table */
/************************************************************************
Updates the autoinc counter if the value supplied is equal or bigger than the Updates the autoinc counter if the value supplied is equal or bigger than the
current value. If not inited, does nothing. */ current value. If not inited, does nothing. */
...@@ -223,13 +205,29 @@ dict_table_autoinc_update( ...@@ -223,13 +205,29 @@ dict_table_autoinc_update(
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
ib_longlong value); /* in: value which was assigned to a row */ ib_longlong value); /* in: value which was assigned to a row */
/************************************************************************
Release the autoinc lock.*/
void
dict_table_autoinc_unlock(
/*======================*/
dict_table_t* table); /* in: table */
/**************************************************************************
Adds system columns to a table object. */
void
dict_table_add_system_columns(
/*==========================*/
dict_table_t* table, /* in/out: table */
mem_heap_t* heap); /* in: temporary heap */
/************************************************************************** /**************************************************************************
Adds a table object to the dictionary cache. */ Adds a table object to the dictionary cache. */
void void
dict_table_add_to_cache( dict_table_add_to_cache(
/*====================*/ /*====================*/
dict_table_t* table); /* in: table */ dict_table_t* table, /* in: table */
mem_heap_t* heap); /* in: temporary heap */
/************************************************************************** /**************************************************************************
Removes a table object from the dictionary cache. */ Removes a table object from the dictionary cache. */
......
...@@ -72,7 +72,8 @@ void ...@@ -72,7 +72,8 @@ void
dict_mem_table_add_col( dict_mem_table_add_col(
/*===================*/ /*===================*/
dict_table_t* table, /* in: table */ dict_table_t* table, /* in: table */
const char* name, /* in: column name */ mem_heap_t* heap, /* in: temporary memory heap, or NULL */
const char* name, /* in: column name, or NULL */
ulint mtype, /* in: main datatype */ ulint mtype, /* in: main datatype */
ulint prtype, /* in: precise type */ ulint prtype, /* in: precise type */
ulint len); /* in: precision */ ulint len); /* in: precision */
...@@ -410,6 +411,11 @@ struct dict_table_struct{ ...@@ -410,6 +411,11 @@ struct dict_table_struct{
SELECT MAX(auto inc column) */ SELECT MAX(auto inc column) */
ib_longlong autoinc;/* autoinc counter value to give to the ib_longlong autoinc;/* autoinc counter value to give to the
next inserted row */ next inserted row */
ib_longlong autoinc_increment;
/* The increment step of the auto increment
column. Value must be greater than or equal
to 1 */
#ifdef UNIV_DEBUG #ifdef UNIV_DEBUG
ulint magic_n;/* magic number */ ulint magic_n;/* magic number */
# define DICT_TABLE_MAGIC_N 76333786 # define DICT_TABLE_MAGIC_N 76333786
......
...@@ -609,7 +609,7 @@ lock_validate(void); ...@@ -609,7 +609,7 @@ lock_validate(void);
/* out: TRUE if ok */ /* out: TRUE if ok */
/************************************************************************* /*************************************************************************
Return approximate number or record locks (bits set in the bitmap) for Return approximate number or record locks (bits set in the bitmap) for
this transaction. Since delete-marked records maybe removed, the this transaction. Since delete-marked records may be removed, the
record count will not be precise. */ record count will not be precise. */
ulint ulint
......
...@@ -670,6 +670,7 @@ struct row_prebuilt_struct { ...@@ -670,6 +670,7 @@ struct row_prebuilt_struct {
to this heap */ to this heap */
mem_heap_t* old_vers_heap; /* memory heap where a previous mem_heap_t* old_vers_heap; /* memory heap where a previous
version is built in consistent read */ version is built in consistent read */
ulonglong last_value; /* last value of AUTO-INC interval */
ulint magic_n2; /* this should be the same as ulint magic_n2; /* this should be the same as
magic_n */ magic_n */
}; };
......
...@@ -171,7 +171,17 @@ row_search_check_if_query_cache_permitted( ...@@ -171,7 +171,17 @@ row_search_check_if_query_cache_permitted(
trx_t* trx, /* in: transaction object */ trx_t* trx, /* in: transaction object */
const char* norm_name); /* in: concatenation of database name, const char* norm_name); /* in: concatenation of database name,
'/' char, table name */ '/' char, table name */
/***********************************************************************
Read the max AUTOINC value from an index. */
ulint
row_search_max_autoinc(
/*===================*/
/* out: DB_SUCCESS if all OK else
error code */
dict_index_t* index, /* in: index to search */
const char* col_name, /* in: autoinc column name */
ib_longlong* value); /* out: AUTOINC value read */
/* A structure for caching column values for prefetched rows */ /* A structure for caching column values for prefetched rows */
struct sel_buf_struct{ struct sel_buf_struct{
......
...@@ -681,6 +681,9 @@ struct trx_struct{ ...@@ -681,6 +681,9 @@ struct trx_struct{
trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log trx_undo_arr_t* undo_no_arr; /* array of undo numbers of undo log
records which are currently processed records which are currently processed
by a rollback operation */ by a rollback operation */
ulint n_autoinc_rows; /* no. of AUTO-INC rows required for
an SQL statement. This is useful for
multi-row INSERTs */
/*------------------------------*/ /*------------------------------*/
char detailed_error[256]; /* detailed error message for last char detailed_error[256]; /* detailed error message for last
error, or empty. */ error, or empty. */
......
...@@ -63,7 +63,7 @@ ut_test_malloc( ...@@ -63,7 +63,7 @@ ut_test_malloc(
/* out: TRUE if succeeded */ /* out: TRUE if succeeded */
ulint n); /* in: try to allocate this many bytes */ ulint n); /* in: try to allocate this many bytes */
/************************************************************************** /**************************************************************************
Frees a memory bloock allocated with ut_malloc. */ Frees a memory block allocated with ut_malloc. */
void void
ut_free( ut_free(
......
...@@ -115,7 +115,7 @@ dulint recv_max_page_lsn; ...@@ -115,7 +115,7 @@ dulint recv_max_page_lsn;
Initialize crash recovery environment. Can be called iff Initialize crash recovery environment. Can be called iff
recv_needed_recovery == FALSE. */ recv_needed_recovery == FALSE. */
static static
void void
recv_init_crash_recovery(void); recv_init_crash_recovery(void);
/*===========================*/ /*===========================*/
...@@ -2450,7 +2450,7 @@ void ...@@ -2450,7 +2450,7 @@ void
recv_init_crash_recovery(void) recv_init_crash_recovery(void)
/*==========================*/ /*==========================*/
{ {
ut_a(!recv_needed_recovery); ut_a(!recv_needed_recovery);
recv_needed_recovery = TRUE; recv_needed_recovery = TRUE;
...@@ -2481,7 +2481,6 @@ recv_init_crash_recovery(void) ...@@ -2481,7 +2481,6 @@ recv_init_crash_recovery(void)
"InnoDB: buffer...\n"); "InnoDB: buffer...\n");
trx_sys_doublewrite_init_or_restore_pages(TRUE); trx_sys_doublewrite_init_or_restore_pages(TRUE);
} }
} }
/************************************************************ /************************************************************
...@@ -2805,7 +2804,7 @@ recv_recovery_from_checkpoint_start( ...@@ -2805,7 +2804,7 @@ recv_recovery_from_checkpoint_start(
recv_synchronize_groups(up_to_date_group); recv_synchronize_groups(up_to_date_group);
if (!recv_needed_recovery) { if (!recv_needed_recovery) {
ut_a(ut_dulint_cmp(checkpoint_lsn, ut_a(ut_dulint_cmp(checkpoint_lsn,
recv_sys->recovered_lsn) == 0); recv_sys->recovered_lsn) == 0);
} else { } else {
......
...@@ -655,6 +655,8 @@ row_create_prebuilt( ...@@ -655,6 +655,8 @@ row_create_prebuilt(
prebuilt->old_vers_heap = NULL; prebuilt->old_vers_heap = NULL;
prebuilt->last_value = 0;
return(prebuilt); return(prebuilt);
} }
...@@ -2894,6 +2896,8 @@ row_truncate_table_for_mysql( ...@@ -2894,6 +2896,8 @@ row_truncate_table_for_mysql(
dict_table_change_id_in_cache(table, new_id); dict_table_change_id_in_cache(table, new_id);
} }
/* MySQL calls ha_innobase::reset_auto_increment() which does
the same thing. */
dict_table_autoinc_initialize(table, 0); dict_table_autoinc_initialize(table, 0);
dict_update_statistics(table); dict_update_statistics(table);
......
...@@ -4519,3 +4519,169 @@ row_search_check_if_query_cache_permitted( ...@@ -4519,3 +4519,169 @@ row_search_check_if_query_cache_permitted(
return(ret); return(ret);
} }
/***********************************************************************
Read the AUTOINC column from the current row. */
static
ib_longlong
row_search_autoinc_read_column(
/*===========================*/
/* out: value read from the column */
dict_index_t* index, /* in: index to read from */
const rec_t* rec, /* in: current rec */
ulint col_no, /* in: column number */
ibool unsigned_type) /* in: signed or unsigned flag */
{
ulint len;
byte* ptr;
const byte* data;
ib_longlong value;
mem_heap_t* heap = NULL;
byte dest[sizeof(value)];
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
*offsets_ = sizeof offsets_ / sizeof *offsets_;
/* TODO: We have to cast away the const of rec for now. This needs
to be fixed later.*/
offsets = rec_get_offsets(
(rec_t*) rec, index, offsets, ULINT_UNDEFINED, &heap);
/* TODO: We have to cast away the const of rec for now. This needs
to be fixed later.*/
data = rec_get_nth_field((rec_t*)rec, offsets, col_no, &len);
ut_a(len != UNIV_SQL_NULL);
ut_a(len <= sizeof value);
/* Convert integer data from Innobase to a little-endian format,
sign bit restored to normal */
for (ptr = dest + len; ptr != dest; ++data) {
--ptr;
*ptr = *data;
}
if (!unsigned_type) {
dest[len - 1] ^= 128;
}
/* The assumption here is that the AUTOINC value can't be negative.*/
switch (len) {
case 8:
value = *(ib_longlong*) ptr;
break;
case 4:
value = *(ib_uint32_t*) ptr;
break;
case 2:
value = *(uint16 *) ptr;
break;
case 1:
value = *ptr;
break;
default:
ut_error;
}
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
}
ut_a(value >= 0);
return(value);
}
/***********************************************************************
Get the last row. */
static
const rec_t*
row_search_autoinc_get_rec(
/*=======================*/
/* out: current rec or NULL */
btr_pcur_t* pcur, /* in: the current cursor */
mtr_t* mtr) /* in: mini transaction */
{
do {
const rec_t* rec = btr_pcur_get_rec(pcur);
if (page_rec_is_user_rec(rec)) {
return(rec);
}
} while (btr_pcur_move_to_prev(pcur, mtr));
return(NULL);
}
/***********************************************************************
Read the max AUTOINC value from an index. */
ulint
row_search_max_autoinc(
/*===================*/
/* out: DB_SUCCESS if all OK else
error code, DB_RECORD_NOT_FOUND if
column name can't be found in index */
dict_index_t* index, /* in: index to search */
const char* col_name, /* in: name of autoinc column */
ib_longlong* value) /* out: AUTOINC value read */
{
ulint i;
ulint n_cols;
dict_field_t* dfield = NULL;
ulint error = DB_SUCCESS;
n_cols = dict_index_get_n_ordering_defined_by_user(index);
/* Search the index for the AUTOINC column name */
for (i = 0; i < n_cols; ++i) {
dfield = dict_index_get_nth_field(index, i);
if (strcmp(col_name, dfield->name) == 0) {
break;
}
}
*value = 0;
/* Must find the AUTOINC column name */
if (i < n_cols && dfield) {
mtr_t mtr;
btr_pcur_t pcur;
mtr_start(&mtr);
/* Open at the high/right end (FALSE), and INIT
cursor (TRUE) */
btr_pcur_open_at_index_side(
FALSE, index, BTR_SEARCH_LEAF, &pcur, TRUE, &mtr);
if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) {
const rec_t* rec;
rec = row_search_autoinc_get_rec(&pcur, &mtr);
if (rec != NULL) {
ibool unsigned_type = (
dfield->col->prtype & DATA_UNSIGNED);
*value = row_search_autoinc_read_column(
index, rec, i, unsigned_type);
}
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
} else {
error = DB_RECORD_NOT_FOUND;
}
return(error);
}
...@@ -195,6 +195,8 @@ trx_create( ...@@ -195,6 +195,8 @@ trx_create(
memset(&trx->xid, 0, sizeof(trx->xid)); memset(&trx->xid, 0, sizeof(trx->xid));
trx->xid.formatID = -1; trx->xid.formatID = -1;
trx->n_autoinc_rows = 0;
trx_reset_new_rec_lock_info(trx); trx_reset_new_rec_lock_info(trx);
return(trx); return(trx);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment