#include "row0ins.h"#include "dict0dict.h"#include "dict0boot.h"#include "trx0undo.h"#include "btr0btr.h"#include "btr0cur.h"#include "mach0data.h"#include "que0que.h"#include "row0upd.h"#include "row0sel.h"#include "row0row.h"#include "rem0cmp.h"#include "lock0lock.h"#include "log0log.h"#include "eval0eval.h"#include "data0data.h"#include "usr0sess.h"#include "buf0lru.h"Include dependency graph for row0ins.c:

Go to the source code of this file.
| #define ROW_INS_NEXT 2 |
| #define ROW_INS_PREV 1 |
| ibool innobase_query_is_update | ( | void | ) |
Referenced by row_ins_duplicate_error_in_clust(), and row_ins_scan_sec_index_for_duplicate().
Here is the caller graph for this function:

| ins_node_t* ins_node_create | ( | ulint | ins_type, | |
| dict_table_t * | table, | |||
| mem_heap_t * | heap | |||
| ) |
Definition at line 73 of file row0ins.c.
References ins_node_struct::common, ins_node_struct::entry, ins_node_struct::entry_sys_heap, ins_node_struct::index, INS_NODE_MAGIC_N, INS_NODE_SET_IX_LOCK, ins_node_struct::ins_type, ins_node_struct::magic_n, mem_heap_alloc(), mem_heap_create, NULL, QUE_NODE_INSERT, ins_node_struct::select, ins_node_struct::state, ins_node_struct::table, ins_node_struct::trx_id, que_common_struct::type, and ut_dulint_zero.
Referenced by ind_create_graph_create(), pars_insert_statement(), row_get_prebuilt_insert_row(), and tab_create_graph_create().
00075 : insert node struct */ 00076 ulint ins_type, /* in: INS_VALUES, ... */ 00077 dict_table_t* table, /* in: table where to insert */ 00078 mem_heap_t* heap) /* in: mem heap where created */ 00079 { 00080 ins_node_t* node; 00081 00082 node = mem_heap_alloc(heap, sizeof(ins_node_t)); 00083 00084 node->common.type = QUE_NODE_INSERT; 00085 00086 node->ins_type = ins_type; 00087 00088 node->state = INS_NODE_SET_IX_LOCK; 00089 node->table = table; 00090 node->index = NULL; 00091 node->entry = NULL; 00092 00093 node->select = NULL; 00094 00095 node->trx_id = ut_dulint_zero; 00096 00097 node->entry_sys_heap = mem_heap_create(128); 00098 00099 node->magic_n = INS_NODE_MAGIC_N; 00100 00101 return(node); 00102 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void ins_node_create_entry_list | ( | ins_node_t * | node | ) | [static] |
Definition at line 108 of file row0ins.c.
References dict_table_get_first_index(), dict_table_get_next_index(), ins_node_struct::entry_list, ins_node_struct::entry_sys_heap, index(), NULL, ins_node_struct::row, row_build_index_entry(), ins_node_struct::table, ut_ad, UT_LIST_ADD_LAST, and UT_LIST_INIT.
Referenced by ins_node_set_new_row().
00110 : row insert node */ 00111 { 00112 dict_index_t* index; 00113 dtuple_t* entry; 00114 00115 ut_ad(node->entry_sys_heap); 00116 00117 UT_LIST_INIT(node->entry_list); 00118 00119 index = dict_table_get_first_index(node->table); 00120 00121 while (index != NULL) { 00122 entry = row_build_index_entry(node->row, index, 00123 node->entry_sys_heap); 00124 UT_LIST_ADD_LAST(tuple_list, node->entry_list, entry); 00125 00126 index = dict_table_get_next_index(index); 00127 } 00128 }
Here is the call graph for this function:

Here is the caller graph for this function:

| void ins_node_set_new_row | ( | ins_node_t * | node, | |
| dtuple_t * | row | |||
| ) |
Definition at line 191 of file row0ins.c.
References ins_node_struct::entry, ins_node_struct::entry_sys_heap, ins_node_struct::index, ins_node_create_entry_list(), INS_NODE_SET_IX_LOCK, mem_heap_empty(), NULL, ins_node_struct::row, row_ins_alloc_sys_fields(), ins_node_struct::state, ins_node_struct::trx_id, and ut_dulint_zero.
Referenced by dict_build_col_def_step(), dict_build_field_def_step(), dict_build_index_def_step(), pars_insert_statement(), and row_get_prebuilt_insert_row().
00193 : insert node */ 00194 dtuple_t* row) /* in: new row (or first row) for the node */ 00195 { 00196 node->state = INS_NODE_SET_IX_LOCK; 00197 node->index = NULL; 00198 node->entry = NULL; 00199 00200 node->row = row; 00201 00202 mem_heap_empty(node->entry_sys_heap); 00203 00204 /* Create templates for index entries */ 00205 00206 ins_node_create_entry_list(node); 00207 00208 /* Allocate from entry_sys_heap buffers for sys fields */ 00209 00210 row_ins_alloc_sys_fields(node); 00211 00212 /* As we allocated a new trx id buf, the trx id should be written 00213 there again: */ 00214 00215 node->trx_id = ut_dulint_zero; 00216 }
Here is the call graph for this function:

Here is the caller graph for this function:

| ulint row_ins | ( | ins_node_t * | node, | |
| que_thr_t * | thr | |||
| ) |
Definition at line 2354 of file row0ins.c.
References DB_SUCCESS, dict_table_get_first_index(), dict_table_get_next_index(), ins_node_struct::entry, err, ins_node_struct::index, INS_NODE_ALLOC_ROW_ID, INS_NODE_INSERT_ENTRIES, INS_SEARCHED, INS_VALUES, NULL, row_ins_alloc_row_id_step(), row_ins_get_row_from_select(), row_ins_get_row_from_values(), row_ins_index_entry_step(), ins_node_struct::state, ut_ad, UT_LIST_GET_FIRST, and UT_LIST_GET_NEXT.
Referenced by row_ins_step().
02356 : DB_SUCCESS if operation successfully 02357 completed, else error code or DB_LOCK_WAIT */ 02358 ins_node_t* node, /* in: row insert node */ 02359 que_thr_t* thr) /* in: query thread */ 02360 { 02361 ulint err; 02362 02363 ut_ad(node && thr); 02364 02365 if (node->state == INS_NODE_ALLOC_ROW_ID) { 02366 02367 row_ins_alloc_row_id_step(node); 02368 02369 node->index = dict_table_get_first_index(node->table); 02370 node->entry = UT_LIST_GET_FIRST(node->entry_list); 02371 02372 if (node->ins_type == INS_SEARCHED) { 02373 02374 row_ins_get_row_from_select(node); 02375 02376 } else if (node->ins_type == INS_VALUES) { 02377 02378 row_ins_get_row_from_values(node); 02379 } 02380 02381 node->state = INS_NODE_INSERT_ENTRIES; 02382 } 02383 02384 ut_ad(node->state == INS_NODE_INSERT_ENTRIES); 02385 02386 while (node->index != NULL) { 02387 err = row_ins_index_entry_step(node, thr); 02388 02389 if (err != DB_SUCCESS) { 02390 02391 return(err); 02392 } 02393 02394 node->index = dict_table_get_next_index(node->index); 02395 node->entry = UT_LIST_GET_NEXT(tuple_list, node->entry); 02396 } 02397 02398 ut_ad(node->entry == NULL); 02399 02400 node->state = INS_NODE_ALLOC_ROW_ID; 02401 02402 return(DB_SUCCESS); 02403 }
Here is the call graph for this function:

Here is the caller graph for this function:

| UNIV_INLINE void row_ins_alloc_row_id_step | ( | ins_node_t * | node | ) |
Definition at line 2264 of file row0ins.c.
References dict_sys_get_new_row_id(), dict_sys_write_row_id(), dict_table_get_first_index(), DICT_UNIQUE, INS_NODE_ALLOC_ROW_ID, ins_node_struct::row_id_buf, ins_node_struct::state, ins_node_struct::table, dict_index_struct::type, and ut_ad.
Referenced by row_ins().
02266 : row insert node */ 02267 { 02268 dulint row_id; 02269 02270 ut_ad(node->state == INS_NODE_ALLOC_ROW_ID); 02271 02272 if (dict_table_get_first_index(node->table)->type & DICT_UNIQUE) { 02273 02274 /* No row id is stored if the clustered index is unique */ 02275 02276 return; 02277 } 02278 02279 /* Fill in row id value to row */ 02280 02281 row_id = dict_sys_get_new_row_id(); 02282 02283 dict_sys_write_row_id(node->row_id_buf, row_id); 02284 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void row_ins_alloc_sys_fields | ( | ins_node_t * | node | ) | [static] |
Definition at line 134 of file row0ins.c.
References DATA_ROLL_PTR, DATA_ROLL_PTR_LEN, DATA_ROW_ID, DATA_ROW_ID_LEN, DATA_TRX_ID, DATA_TRX_ID_LEN, dfield_set_data(), dict_col_get_no(), dict_table_get_n_cols(), dict_table_get_sys_col(), dtuple_get_n_fields(), dtuple_get_nth_field(), ins_node_struct::entry_sys_heap, mem_heap_alloc(), ins_node_struct::row, ins_node_struct::row_id_buf, ins_node_struct::table, ins_node_struct::trx_id_buf, and ut_ad.
Referenced by ins_node_set_new_row().
00136 : insert node */ 00137 { 00138 dtuple_t* row; 00139 dict_table_t* table; 00140 mem_heap_t* heap; 00141 dict_col_t* col; 00142 dfield_t* dfield; 00143 byte* ptr; 00144 00145 row = node->row; 00146 table = node->table; 00147 heap = node->entry_sys_heap; 00148 00149 ut_ad(row && table && heap); 00150 ut_ad(dtuple_get_n_fields(row) == dict_table_get_n_cols(table)); 00151 00152 /* 1. Allocate buffer for row id */ 00153 00154 col = dict_table_get_sys_col(table, DATA_ROW_ID); 00155 00156 dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); 00157 00158 ptr = mem_heap_alloc(heap, DATA_ROW_ID_LEN); 00159 00160 dfield_set_data(dfield, ptr, DATA_ROW_ID_LEN); 00161 00162 node->row_id_buf = ptr; 00163 00164 /* 3. Allocate buffer for trx id */ 00165 00166 col = dict_table_get_sys_col(table, DATA_TRX_ID); 00167 00168 dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); 00169 ptr = mem_heap_alloc(heap, DATA_TRX_ID_LEN); 00170 00171 dfield_set_data(dfield, ptr, DATA_TRX_ID_LEN); 00172 00173 node->trx_id_buf = ptr; 00174 00175 /* 4. Allocate buffer for roll ptr */ 00176 00177 col = dict_table_get_sys_col(table, DATA_ROLL_PTR); 00178 00179 dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); 00180 ptr = mem_heap_alloc(heap, DATA_ROLL_PTR_LEN); 00181 00182 dfield_set_data(dfield, ptr, DATA_ROLL_PTR_LEN); 00183 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ibool row_ins_cascade_ancestor_updates_table | ( | que_node_t * | node, | |
| dict_table_t * | table | |||
| ) | [static] |
Definition at line 359 of file row0ins.c.
References FALSE, upd_node_struct::is_delete, que_node_get_parent(), que_node_get_type(), QUE_NODE_UPDATE, upd_node_struct::table, TRUE, and ut_a.
Referenced by row_ins_foreign_check_on_constraint().
00361 : TRUE if an ancestor updates table */ 00362 que_node_t* node, /* in: node in a query graph */ 00363 dict_table_t* table) /* in: table */ 00364 { 00365 que_node_t* parent; 00366 upd_node_t* upd_node; 00367 00368 parent = que_node_get_parent(node); 00369 00370 while (que_node_get_type(parent) == QUE_NODE_UPDATE) { 00371 00372 upd_node = parent; 00373 00374 if (upd_node->table == table && upd_node->is_delete == FALSE) { 00375 00376 return(TRUE); 00377 } 00378 00379 parent = que_node_get_parent(parent); 00380 00381 ut_a(parent); 00382 } 00383 00384 return(FALSE); 00385 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_cascade_calc_update_vec | ( | upd_node_t * | node, | |
| dict_foreign_t * | foreign, | |||
| mem_heap_t * | heap | |||
| ) | [static] |
Definition at line 418 of file row0ins.c.
References upd_node_struct::cascade_node, dfield_struct::data, DATA_MYSQL_BINARY_CHARSET_COLL, DATA_NOT_NULL, dict_index_get_nth_col_no(), dict_index_get_nth_type(), dict_table_get_nth_col_pos(), dtype_get_at_most_n_mbchars(), dtype_get_charset_coll(), dtype_get_len(), dtype_get_mbminlen(), dtype_get_min_size(), dtype_get_prtype(), upd_field_struct::exp, upd_field_struct::extern_storage, FALSE, upd_field_struct::field_no, upd_struct::fields, dict_foreign_struct::foreign_index, dict_foreign_struct::foreign_table, index(), dfield_struct::len, mem_heap_alloc(), memset, upd_struct::n_fields, dict_foreign_struct::n_fields, upd_field_struct::new_val, NULL, dtype_struct::prtype, dict_foreign_struct::referenced_index, dict_foreign_struct::referenced_table, upd_node_struct::table, upd_node_struct::update, update, ut_a, ut_error, and ut_memcpy().
Referenced by row_ins_foreign_check_on_constraint().
00420 : number of fields in the 00421 calculated update vector; the value 00422 can also be 0 if no foreign key 00423 fields changed; the returned value 00424 is ULINT_UNDEFINED if the column 00425 type in the child table is too short 00426 to fit the new value in the parent 00427 table: that means the update fails */ 00428 upd_node_t* node, /* in: update node of the parent 00429 table */ 00430 dict_foreign_t* foreign, /* in: foreign key constraint whose 00431 type is != 0 */ 00432 mem_heap_t* heap) /* in: memory heap to use as 00433 temporary storage */ 00434 { 00435 upd_node_t* cascade = node->cascade_node; 00436 dict_table_t* table = foreign->foreign_table; 00437 dict_index_t* index = foreign->foreign_index; 00438 upd_t* update; 00439 upd_field_t* ufield; 00440 dict_table_t* parent_table; 00441 dict_index_t* parent_index; 00442 upd_t* parent_update; 00443 upd_field_t* parent_ufield; 00444 ulint n_fields_updated; 00445 ulint parent_field_no; 00446 dtype_t* type; 00447 ulint i; 00448 ulint j; 00449 00450 ut_a(node && foreign && cascade && table && index); 00451 00452 /* Calculate the appropriate update vector which will set the fields 00453 in the child index record to the same value (possibly padded with 00454 spaces if the column is a fixed length CHAR or FIXBINARY column) as 00455 the referenced index record will get in the update. */ 00456 00457 parent_table = node->table; 00458 ut_a(parent_table == foreign->referenced_table); 00459 parent_index = foreign->referenced_index; 00460 parent_update = node->update; 00461 00462 update = cascade->update; 00463 00464 update->info_bits = 0; 00465 update->n_fields = foreign->n_fields; 00466 00467 n_fields_updated = 0; 00468 00469 for (i = 0; i < foreign->n_fields; i++) { 00470 00471 parent_field_no = dict_table_get_nth_col_pos( 00472 parent_table, 00473 dict_index_get_nth_col_no( 00474 parent_index, i)); 00475 00476 for (j = 0; j < parent_update->n_fields; j++) { 00477 parent_ufield = parent_update->fields + j; 00478 00479 if (parent_ufield->field_no == parent_field_no) { 00480 00481 ulint min_size; 00482 00483 /* A field in the parent index record is 00484 updated. Let us make the update vector 00485 field for the child table. */ 00486 00487 ufield = update->fields + n_fields_updated; 00488 00489 ufield->field_no = 00490 dict_table_get_nth_col_pos(table, 00491 dict_index_get_nth_col_no(index, i)); 00492 ufield->exp = NULL; 00493 00494 ufield->new_val = parent_ufield->new_val; 00495 00496 type = dict_index_get_nth_type(index, i); 00497 00498 /* Do not allow a NOT NULL column to be 00499 updated as NULL */ 00500 00501 if (ufield->new_val.len == UNIV_SQL_NULL 00502 && (type->prtype & DATA_NOT_NULL)) { 00503 00504 return(ULINT_UNDEFINED); 00505 } 00506 00507 /* If the new value would not fit in the 00508 column, do not allow the update */ 00509 00510 if (ufield->new_val.len != UNIV_SQL_NULL 00511 && dtype_get_at_most_n_mbchars( 00512 type, dtype_get_len(type), 00513 ufield->new_val.len, 00514 ufield->new_val.data) 00515 < ufield->new_val.len) { 00516 00517 return(ULINT_UNDEFINED); 00518 } 00519 00520 /* If the parent column type has a different 00521 length than the child column type, we may 00522 need to pad with spaces the new value of the 00523 child column */ 00524 00525 min_size = dtype_get_min_size(type); 00526 00527 if (min_size 00528 && ufield->new_val.len != UNIV_SQL_NULL 00529 && ufield->new_val.len < min_size) { 00530 00531 char* pad_start; 00532 const char* pad_end; 00533 ufield->new_val.data = 00534 mem_heap_alloc(heap, 00535 min_size); 00536 pad_start = 00537 ((char*) ufield->new_val.data) 00538 + ufield->new_val.len; 00539 pad_end = 00540 ((char*) ufield->new_val.data) 00541 + min_size; 00542 ufield->new_val.len = min_size; 00543 ut_memcpy(ufield->new_val.data, 00544 parent_ufield->new_val.data, 00545 parent_ufield->new_val.len); 00546 00547 switch (UNIV_EXPECT( 00548 dtype_get_mbminlen(type), 1)) { 00549 default: 00550 ut_error; 00551 case 1: 00552 if (UNIV_UNLIKELY( 00553 dtype_get_charset_coll( 00554 dtype_get_prtype(type)) 00555 == DATA_MYSQL_BINARY_CHARSET_COLL)) { 00556 /* Do not pad BINARY 00557 columns. */ 00558 return(ULINT_UNDEFINED); 00559 } 00560 00561 /* space=0x20 */ 00562 memset(pad_start, 0x20, 00563 pad_end - pad_start); 00564 break; 00565 case 2: 00566 /* space=0x0020 */ 00567 ut_a(!(ufield->new_val.len 00568 % 2)); 00569 ut_a(!(min_size % 2)); 00570 do { 00571 *pad_start++ = 0x00; 00572 *pad_start++ = 0x20; 00573 } while (pad_start < pad_end); 00574 break; 00575 } 00576 } 00577 00578 ufield->extern_storage = FALSE; 00579 00580 n_fields_updated++; 00581 } 00582 } 00583 } 00584 00585 update->n_fields = n_fields_updated; 00586 00587 return(n_fields_updated); 00588 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_cascade_n_ancestors | ( | que_node_t * | node | ) | [static] |
Definition at line 392 of file row0ins.c.
References que_node_get_parent(), que_node_get_type(), QUE_NODE_UPDATE, and ut_a.
Referenced by row_ins_foreign_check_on_constraint().
00394 : number of ancestors */ 00395 que_node_t* node) /* in: node in a query graph */ 00396 { 00397 que_node_t* parent; 00398 ulint n_ancestors = 0; 00399 00400 parent = que_node_get_parent(node); 00401 00402 while (que_node_get_type(parent) == QUE_NODE_UPDATE) { 00403 n_ancestors++; 00404 00405 parent = que_node_get_parent(parent); 00406 00407 ut_a(parent); 00408 } 00409 00410 return(n_ancestors); 00411 }
Here is the call graph for this function:

Here is the caller graph for this function:

| ulint row_ins_check_foreign_constraint | ( | ibool | check_ref, | |
| dict_foreign_t * | foreign, | |||
| dict_table_t * | table, | |||
| dtuple_t * | entry, | |||
| que_thr_t * | thr | |||
| ) |
Definition at line 1178 of file row0ins.c.
References trx_struct::check_foreigns, cmp, DB_SUCCESS, dfield_get_len(), dict_operation_lock, dtuple_get_nth_field(), err, FALSE, upd_node_struct::foreign, upd_node_struct::is_delete, dict_foreign_struct::n_fields, NULL, que_node_get_type(), QUE_NODE_UPDATE, REC_OFFS_NORMAL_SIZE, que_thr_struct::run_node, RW_LOCK_SHARED, thr_get_trx(), and ut_ad.
Referenced by row_ins_check_foreign_constraints(), and row_upd_check_references_constraints().
01180 : DB_SUCCESS, 01181 DB_NO_REFERENCED_ROW, 01182 or DB_ROW_IS_REFERENCED */ 01183 ibool check_ref,/* in: TRUE if we want to check that 01184 the referenced table is ok, FALSE if we 01185 want to to check the foreign key table */ 01186 dict_foreign_t* foreign,/* in: foreign constraint; NOTE that the 01187 tables mentioned in it must be in the 01188 dictionary cache if they exist at all */ 01189 dict_table_t* table, /* in: if check_ref is TRUE, then the foreign 01190 table, else the referenced table */ 01191 dtuple_t* entry, /* in: index entry for index */ 01192 que_thr_t* thr) /* in: query thread */ 01193 { 01194 upd_node_t* upd_node; 01195 dict_table_t* check_table; 01196 dict_index_t* check_index; 01197 ulint n_fields_cmp; 01198 rec_t* rec; 01199 btr_pcur_t pcur; 01200 ibool moved; 01201 int cmp; 01202 ulint err; 01203 ulint i; 01204 mtr_t mtr; 01205 trx_t* trx = thr_get_trx(thr); 01206 mem_heap_t* heap = NULL; 01207 ulint offsets_[REC_OFFS_NORMAL_SIZE]; 01208 ulint* offsets = offsets_; 01209 *offsets_ = (sizeof offsets_) / sizeof *offsets_; 01210 01211 run_again: 01212 #ifdef UNIV_SYNC_DEBUG 01213 ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_SHARED)); 01214 #endif /* UNIV_SYNC_DEBUG */ 01215 01216 err = DB_SUCCESS; 01217 01218 if (trx->check_foreigns == FALSE) { 01219 /* The user has suppressed foreign key checks currently for 01220 this session */ 01221 goto exit_func; 01222 } 01223 01224 /* If any of the foreign key fields in entry is SQL NULL, we 01225 suppress the foreign key check: this is compatible with Oracle, 01226 for example */ 01227 01228 for (i = 0; i < foreign->n_fields; i++) { 01229 if (UNIV_SQL_NULL == dfield_get_len( 01230 dtuple_get_nth_field(entry, i))) { 01231 01232 goto exit_func; 01233 } 01234 } 01235 01236 if (que_node_get_type(thr->run_node) == QUE_NODE_UPDATE) { 01237 upd_node = thr->run_node; 01238 01239 if (!(upd_node->is_delete) && upd_node->foreign == foreign) { 01240 /* If a cascaded update is done as defined by a 01241 foreign key constraint, do not check that 01242 constraint for the child row. In ON UPDATE CASCADE 01243 the update of the parent row is only half done when 01244 we come here: if we would check the constraint here 01245 for the child row it would fail. 01246 01247 A QUESTION remains: if in the child table there are 01248 several constraints which refer to the same parent 01249 table, we should merge all updates to the child as 01250 one update? And the updates can be contradictory! 01251 Currently we just perform the update associated 01252 with each foreign key constraint, one after 01253 another, and the user has problems predicting in 01254 which order they are performed. */ 01255 01256 goto exit_func; 01257 } 01258 } 01259 01260 if (check_ref) { 01261 check_table = foreign->referenced_table; 01262 check_index = foreign->referenced_index; 01263 } else { 01264 check_table = foreign->foreign_table; 01265 check_index = foreign->foreign_index; 01266 } 01267 01268 if (check_table == NULL || check_table->ibd_file_missing) { 01269 if (check_ref) { 01270 FILE* ef = dict_foreign_err_file; 01271 01272 row_ins_set_detailed(trx, foreign); 01273 01274 mutex_enter(&dict_foreign_err_mutex); 01275 rewind(ef); 01276 ut_print_timestamp(ef); 01277 fputs(" Transaction:\n", ef); 01278 trx_print(ef, trx, 600); 01279 fputs("Foreign key constraint fails for table ", ef); 01280 ut_print_name(ef, trx, TRUE, 01281 foreign->foreign_table_name); 01282 fputs(":\n", ef); 01283 dict_print_info_on_foreign_key_in_create_format(ef, 01284 trx, foreign, TRUE); 01285 fputs("\nTrying to add to index ", ef); 01286 ut_print_name(ef, trx, FALSE, 01287 foreign->foreign_index->name); 01288 fputs(" tuple:\n", ef); 01289 dtuple_print(ef, entry); 01290 fputs("\nBut the parent table ", ef); 01291 ut_print_name(ef, trx, TRUE, 01292 foreign->referenced_table_name); 01293 fputs("\nor its .ibd file does not currently exist!\n", ef); 01294 mutex_exit(&dict_foreign_err_mutex); 01295 01296 err = DB_NO_REFERENCED_ROW; 01297 } 01298 01299 goto exit_func; 01300 } 01301 01302 ut_a(check_table && check_index); 01303 01304 if (check_table != table) { 01305 /* We already have a LOCK_IX on table, but not necessarily 01306 on check_table */ 01307 01308 err = lock_table(0, check_table, LOCK_IS, thr); 01309 01310 if (err != DB_SUCCESS) { 01311 01312 goto do_possible_lock_wait; 01313 } 01314 } 01315 01316 mtr_start(&mtr); 01317 01318 /* Store old value on n_fields_cmp */ 01319 01320 n_fields_cmp = dtuple_get_n_fields_cmp(entry); 01321 01322 dtuple_set_n_fields_cmp(entry, foreign->n_fields); 01323 01324 btr_pcur_open(check_index, entry, PAGE_CUR_GE, 01325 BTR_SEARCH_LEAF, &pcur, &mtr); 01326 01327 /* Scan index records and check if there is a matching record */ 01328 01329 for (;;) { 01330 page_t* page; 01331 rec = btr_pcur_get_rec(&pcur); 01332 page = buf_frame_align(rec); 01333 01334 if (rec == page_get_infimum_rec(page)) { 01335 01336 goto next_rec; 01337 } 01338 01339 offsets = rec_get_offsets(rec, check_index, 01340 offsets, ULINT_UNDEFINED, &heap); 01341 01342 if (rec == page_get_supremum_rec(page)) { 01343 01344 err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, rec, 01345 check_index, offsets, thr); 01346 if (err != DB_SUCCESS) { 01347 01348 break; 01349 } 01350 01351 goto next_rec; 01352 } 01353 01354 cmp = cmp_dtuple_rec(entry, rec, offsets); 01355 01356 if (cmp == 0) { 01357 if (rec_get_deleted_flag(rec, 01358 rec_offs_comp(offsets))) { 01359 err = row_ins_set_shared_rec_lock( 01360 LOCK_ORDINARY, rec, 01361 check_index, offsets, thr); 01362 if (err != DB_SUCCESS) { 01363 01364 break; 01365 } 01366 } else { 01367 /* Found a matching record. Lock only 01368 a record because we can allow inserts 01369 into gaps */ 01370 01371 err = row_ins_set_shared_rec_lock( 01372 LOCK_REC_NOT_GAP, rec, 01373 check_index, offsets, thr); 01374 01375 if (err != DB_SUCCESS) { 01376 01377 break; 01378 } 01379 01380 if (check_ref) { 01381 err = DB_SUCCESS; 01382 01383 break; 01384 } else if (foreign->type != 0) { 01385 /* There is an ON UPDATE or ON DELETE 01386 condition: check them in a separate 01387 function */ 01388 01389 err = 01390 row_ins_foreign_check_on_constraint( 01391 thr, foreign, &pcur, entry, 01392 &mtr); 01393 if (err != DB_SUCCESS) { 01394 /* Since reporting a plain 01395 "duplicate key" error 01396 message to the user in 01397 cases where a long CASCADE 01398 operation would lead to a 01399 duplicate key in some 01400 other table is very 01401 confusing, map duplicate 01402 key errors resulting from 01403 FK constraints to a 01404 separate error code. */ 01405 01406 if (err == DB_DUPLICATE_KEY) { 01407 err = DB_FOREIGN_DUPLICATE_KEY; 01408 } 01409 01410 break; 01411 } 01412 } else { 01413 row_ins_foreign_report_err( 01414 "Trying to delete or update", 01415 thr, foreign, rec, entry); 01416 01417 err = DB_ROW_IS_REFERENCED; 01418 break; 01419 } 01420 } 01421 } 01422 01423 if (cmp < 0) { 01424 err = row_ins_set_shared_rec_lock(LOCK_GAP, 01425 rec, check_index, offsets, thr); 01426 if (err != DB_SUCCESS) { 01427 01428 break; 01429 } 01430 01431 if (check_ref) { 01432 err = DB_NO_REFERENCED_ROW; 01433 row_ins_foreign_report_add_err( 01434 trx, foreign, rec, entry); 01435 } else { 01436 err = DB_SUCCESS; 01437 } 01438 01439 break; 01440 } 01441 01442 ut_a(cmp == 0); 01443 next_rec: 01444 moved = btr_pcur_move_to_next(&pcur, &mtr); 01445 01446 if (!moved) { 01447 if (check_ref) { 01448 rec = btr_pcur_get_rec(&pcur); 01449 row_ins_foreign_report_add_err( 01450 trx, foreign, rec, entry); 01451 err = DB_NO_REFERENCED_ROW; 01452 } else { 01453 err = DB_SUCCESS; 01454 } 01455 01456 break; 01457 } 01458 } 01459 01460 btr_pcur_close(&pcur); 01461 01462 mtr_commit(&mtr); 01463 01464 /* Restore old value */ 01465 dtuple_set_n_fields_cmp(entry, n_fields_cmp); 01466 01467 do_possible_lock_wait: 01468 if (err == DB_LOCK_WAIT) { 01469 trx->error_state = err; 01470 01471 que_thr_stop_for_mysql(thr); 01472 01473 srv_suspend_mysql_thread(thr); 01474 01475 if (trx->error_state == DB_SUCCESS) { 01476 01477 goto run_again; 01478 } 01479 01480 err = trx->error_state; 01481 } 01482 01483 exit_func: 01484 if (UNIV_LIKELY_NULL(heap)) { 01485 mem_heap_free(heap); 01486 } 01487 return(err); 01488 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_check_foreign_constraints | ( | dict_table_t * | table, | |
| dict_index_t * | index, | |||
| dtuple_t * | entry, | |||
| que_thr_t * | thr | |||
| ) | [static] |
Definition at line 1498 of file row0ins.c.
References DB_SUCCESS, trx_struct::dict_operation_lock_mode, dict_sys, dict_table_get(), err, FALSE, dict_foreign_struct::foreign_index, dict_table_struct::foreign_list, index(), dict_sys_struct::mutex, mutex_enter, mutex_exit(), dict_table_struct::n_foreign_key_checks_running, NULL, dict_foreign_struct::referenced_table, dict_foreign_struct::referenced_table_name, row_ins_check_foreign_constraint(), row_mysql_freeze_data_dictionary(), row_mysql_unfreeze_data_dictionary(), thr_get_trx(), TRUE, ut_a, UT_LIST_GET_FIRST, and UT_LIST_GET_NEXT.
Referenced by row_ins_index_entry().
01500 : DB_SUCCESS or error code */ 01501 dict_table_t* table, /* in: table */ 01502 dict_index_t* index, /* in: index */ 01503 dtuple_t* entry, /* in: index entry for index */ 01504 que_thr_t* thr) /* in: query thread */ 01505 { 01506 dict_foreign_t* foreign; 01507 ulint err; 01508 trx_t* trx; 01509 ibool got_s_lock = FALSE; 01510 01511 trx = thr_get_trx(thr); 01512 01513 foreign = UT_LIST_GET_FIRST(table->foreign_list); 01514 01515 while (foreign) { 01516 if (foreign->foreign_index == index) { 01517 01518 if (foreign->referenced_table == NULL) { 01519 dict_table_get(foreign->referenced_table_name); 01520 } 01521 01522 if (0 == trx->dict_operation_lock_mode) { 01523 got_s_lock = TRUE; 01524 01525 row_mysql_freeze_data_dictionary(trx); 01526 } 01527 01528 if (foreign->referenced_table) { 01529 mutex_enter(&(dict_sys->mutex)); 01530 01531 (foreign->referenced_table 01532 ->n_foreign_key_checks_running)++; 01533 01534 mutex_exit(&(dict_sys->mutex)); 01535 } 01536 01537 /* NOTE that if the thread ends up waiting for a lock 01538 we will release dict_operation_lock temporarily! 01539 But the counter on the table protects the referenced 01540 table from being dropped while the check is running. */ 01541 01542 err = row_ins_check_foreign_constraint(TRUE, foreign, 01543 table, entry, thr); 01544 01545 if (foreign->referenced_table) { 01546 mutex_enter(&(dict_sys->mutex)); 01547 01548 ut_a(foreign->referenced_table 01549 ->n_foreign_key_checks_running > 0); 01550 (foreign->referenced_table 01551 ->n_foreign_key_checks_running)--; 01552 01553 mutex_exit(&(dict_sys->mutex)); 01554 } 01555 01556 if (got_s_lock) { 01557 row_mysql_unfreeze_data_dictionary(trx); 01558 } 01559 01560 if (err != DB_SUCCESS) { 01561 return(err); 01562 } 01563 } 01564 01565 foreign = UT_LIST_GET_NEXT(foreign_list, foreign); 01566 } 01567 01568 return(DB_SUCCESS); 01569 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_clust_index_entry_by_modify | ( | ulint | mode, | |
| btr_cur_t * | cursor, | |||
| big_rec_t ** | big_rec, | |||
| dtuple_t * | entry, | |||
| ulint * | ext_vec, | |||
| ulint | n_ext_vec, | |||
| que_thr_t * | thr, | |||
| mtr_t * | mtr | |||
| ) | [static] |
Definition at line 289 of file row0ins.c.
References btr_cur_get_rec(), btr_cur_optimistic_update(), btr_cur_pessimistic_update(), BTR_MODIFY_LEAF, BTR_MODIFY_TREE, buf_LRU_buf_pool_running_out(), DB_FAIL, DB_LOCK_TABLE_FULL, DB_OVERFLOW, DB_UNDERFLOW, DICT_CLUSTERED, dict_table_is_comp(), err, btr_cur_struct::index, mem_heap_create, mem_heap_free, NULL, rec_get_deleted_flag(), row_upd_build_difference_binary(), dict_index_struct::table, thr_get_trx(), dict_index_struct::type, update, ut_a, and ut_ad.
Referenced by row_ins_index_entry_low().
00291 : DB_SUCCESS, DB_FAIL, or error code */ 00292 ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, 00293 depending on whether mtr holds just a leaf 00294 latch or also a tree latch */ 00295 btr_cur_t* cursor, /* in: B-tree cursor */ 00296 big_rec_t** big_rec,/* out: possible big rec vector of fields 00297 which have to be stored externally by the 00298 caller */ 00299 dtuple_t* entry, /* in: index entry to insert */ 00300 ulint* ext_vec,/* in: array containing field numbers of 00301 externally stored fields in entry, or NULL */ 00302 ulint n_ext_vec,/* in: number of fields in ext_vec */ 00303 que_thr_t* thr, /* in: query thread */ 00304 mtr_t* mtr) /* in: mtr */ 00305 { 00306 mem_heap_t* heap; 00307 rec_t* rec; 00308 upd_t* update; 00309 ulint err; 00310 00311 ut_ad(cursor->index->type & DICT_CLUSTERED); 00312 00313 *big_rec = NULL; 00314 00315 rec = btr_cur_get_rec(cursor); 00316 00317 ut_ad(rec_get_deleted_flag(rec, 00318 dict_table_is_comp(cursor->index->table))); 00319 00320 heap = mem_heap_create(1024); 00321 00322 /* Build an update vector containing all the fields to be modified; 00323 NOTE that this vector may NOT contain system columns trx_id or 00324 roll_ptr */ 00325 00326 update = row_upd_build_difference_binary(cursor->index, entry, ext_vec, 00327 n_ext_vec, rec, thr_get_trx(thr), heap); 00328 if (mode == BTR_MODIFY_LEAF) { 00329 /* Try optimistic updating of the record, keeping changes 00330 within the page */ 00331 00332 err = btr_cur_optimistic_update(0, cursor, update, 0, thr, 00333 mtr); 00334 if (err == DB_OVERFLOW || err == DB_UNDERFLOW) { 00335 err = DB_FAIL; 00336 } 00337 } else { 00338 ut_a(mode == BTR_MODIFY_TREE); 00339 if (buf_LRU_buf_pool_running_out()) { 00340 00341 err = DB_LOCK_TABLE_FULL; 00342 00343 goto func_exit; 00344 } 00345 err = btr_cur_pessimistic_update(0, cursor, big_rec, update, 00346 0, thr, mtr); 00347 } 00348 func_exit: 00349 mem_heap_free(heap); 00350 00351 return(err); 00352 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ibool row_ins_dupl_error_with_rec | ( | rec_t * | rec, | |
| dtuple_t * | entry, | |||
| dict_index_t * | index, | |||
| const ulint * | offsets | |||
| ) | [static] |
Definition at line 1577 of file row0ins.c.
References cmp_dtuple_rec_with_match(), dfield_get_len(), DICT_CLUSTERED, dict_index_get_n_unique(), dtuple_get_nth_field(), FALSE, index(), rec_get_deleted_flag(), rec_offs_comp(), rec_offs_validate(), and ut_ad.
Referenced by row_ins_duplicate_error_in_clust(), and row_ins_scan_sec_index_for_duplicate().
01579 : TRUE if error */ 01580 rec_t* rec, /* in: user record; NOTE that we assume 01581 that the caller already has a record lock on 01582 the record! */ 01583 dtuple_t* entry, /* in: entry to insert */ 01584 dict_index_t* index, /* in: index */ 01585 const ulint* offsets)/* in: rec_get_offsets(rec, index) */ 01586 { 01587 ulint matched_fields; 01588 ulint matched_bytes; 01589 ulint n_unique; 01590 ulint i; 01591 01592 ut_ad(rec_offs_validate(rec, index, offsets)); 01593 01594 n_unique = dict_index_get_n_unique(index); 01595 01596 matched_fields = 0; 01597 matched_bytes = 0; 01598 01599 cmp_dtuple_rec_with_match(entry, rec, offsets, 01600 &matched_fields, &matched_bytes); 01601 01602 if (matched_fields < n_unique) { 01603 01604 return(FALSE); 01605 } 01606 01607 /* In a unique secondary index we allow equal key values if they 01608 contain SQL NULLs */ 01609 01610 if (!(index->type & DICT_CLUSTERED)) { 01611 01612 for (i = 0; i < n_unique; i++) { 01613 if (UNIV_SQL_NULL == dfield_get_len( 01614 dtuple_get_nth_field(entry, i))) { 01615 01616 return(FALSE); 01617 } 01618 } 01619 } 01620 01621 return(!rec_get_deleted_flag(rec, rec_offs_comp(offsets))); 01622 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_duplicate_error_in_clust | ( | btr_cur_t * | cursor, | |
| dtuple_t * | entry, | |||
| que_thr_t * | thr, | |||
| mtr_t * | mtr | |||
| ) | [static] |
Definition at line 1766 of file row0ins.c.
References btr_cur_get_rec(), DB_DUPLICATE_KEY, DB_FAIL, DB_SUCCESS, DICT_CLUSTERED, dict_index_get_n_unique(), DICT_UNIQUE, err, trx_struct::error_info, btr_cur_struct::index, innobase_query_is_update(), LOCK_REC_NOT_GAP, btr_cur_struct::low_match, mem_heap_free, NULL, page_rec_get_next(), page_rec_is_infimum(), page_rec_is_supremum(), rec_get_offsets, REC_OFFS_NORMAL_SIZE, row_ins_dupl_error_with_rec(), row_ins_set_exclusive_rec_lock(), row_ins_set_shared_rec_lock(), thr_get_trx(), dict_index_struct::type, btr_cur_struct::up_match, ut_a, ut_ad, ut_error, and UT_NOT_USED.
Referenced by row_ins_index_entry_low().
01768 : DB_SUCCESS if no error, 01769 DB_DUPLICATE_KEY if error, DB_LOCK_WAIT if we 01770 have to wait for a lock on a possible 01771 duplicate record */ 01772 btr_cur_t* cursor, /* in: B-tree cursor */ 01773 dtuple_t* entry, /* in: entry to insert */ 01774 que_thr_t* thr, /* in: query thread */ 01775 mtr_t* mtr) /* in: mtr */ 01776 { 01777 #ifndef UNIV_HOTBACKUP 01778 ulint err; 01779 rec_t* rec; 01780 ulint n_unique; 01781 trx_t* trx = thr_get_trx(thr); 01782 mem_heap_t*heap = NULL; 01783 ulint offsets_[REC_OFFS_NORMAL_SIZE]; 01784 ulint* offsets = offsets_; 01785 *offsets_ = (sizeof offsets_) / sizeof *offsets_; 01786 01787 UT_NOT_USED(mtr); 01788 01789 ut_a(cursor->index->type & DICT_CLUSTERED); 01790 ut_ad(cursor->index->type & DICT_UNIQUE); 01791 01792 /* NOTE: For unique non-clustered indexes there may be any number 01793 of delete marked records with the same value for the non-clustered 01794 index key (remember multiversioning), and which differ only in 01795 the row refererence part of the index record, containing the 01796 clustered index key fields. For such a secondary index record, 01797 to avoid race condition, we must FIRST do the insertion and after 01798 that check that the uniqueness condition is not breached! */ 01799 01800 /* NOTE: A problem is that in the B-tree node pointers on an 01801 upper level may match more to the entry than the actual existing 01802 user records on the leaf level. So, even if low_match would suggest 01803 that a duplicate key violation may occur, this may not be the case. */ 01804 01805 n_unique = dict_index_get_n_unique(cursor->index); 01806 01807 if (cursor->low_match >= n_unique) { 01808 01809 rec = btr_cur_get_rec(cursor); 01810 01811 if (!page_rec_is_infimum(rec)) { 01812 offsets = rec_get_offsets(rec, cursor->index, offsets, 01813 ULINT_UNDEFINED, &heap); 01814 01815 /* We set a lock on the possible duplicate: this 01816 is needed in logical logging of MySQL to make 01817 sure that in roll-forward we get the same duplicate 01818 errors as in original execution */ 01819 01820 if (innobase_query_is_update()) { 01821 01822 /* If the SQL-query will update or replace 01823 duplicate key we will take X-lock for 01824 duplicates ( REPLACE, LOAD DATAFILE REPLACE, 01825 INSERT ON DUPLICATE KEY UPDATE). */ 01826 01827 err = row_ins_set_exclusive_rec_lock( 01828 LOCK_REC_NOT_GAP,rec,cursor->index, 01829 offsets, thr); 01830 } else { 01831 01832 err = row_ins_set_shared_rec_lock( 01833 LOCK_REC_NOT_GAP,rec, cursor->index, 01834 offsets, thr); 01835 } 01836 01837 if (err != DB_SUCCESS) { 01838 goto func_exit; 01839 } 01840 01841 if (row_ins_dupl_error_with_rec(rec, entry, 01842 cursor->index, offsets)) { 01843 trx->error_info = cursor->index; 01844 err = DB_DUPLICATE_KEY; 01845 goto func_exit; 01846 } 01847 } 01848 } 01849 01850 if (cursor->up_match >= n_unique) { 01851 01852 rec = page_rec_get_next(btr_cur_get_rec(cursor)); 01853 01854 if (!page_rec_is_supremum(rec)) { 01855 offsets = rec_get_offsets(rec, cursor->index, offsets, 01856 ULINT_UNDEFINED, &heap); 01857 01858 if (innobase_query_is_update()) { 01859 01860 /* If the SQL-query will update or replace 01861 duplicate key we will take X-lock for 01862 duplicates ( REPLACE, LOAD DATAFILE REPLACE, 01863 INSERT ON DUPLICATE KEY UPDATE). */ 01864 01865 err = row_ins_set_exclusive_rec_lock( 01866 LOCK_REC_NOT_GAP, rec, 01867 cursor->index, offsets, thr); 01868 } else { 01869 01870 err = row_ins_set_shared_rec_lock( 01871 LOCK_REC_NOT_GAP, rec, 01872 cursor->index, offsets, thr); 01873 } 01874 01875 if (err != DB_SUCCESS) { 01876 goto func_exit; 01877 } 01878 01879 if (row_ins_dupl_error_with_rec(rec, entry, 01880 cursor->index, offsets)) { 01881 trx->error_info = cursor->index; 01882 err = DB_DUPLICATE_KEY; 01883 goto func_exit; 01884 } 01885 } 01886 01887 ut_a(!(cursor->index->type & DICT_CLUSTERED)); 01888 /* This should never happen */ 01889 } 01890 01891 err = DB_SUCCESS; 01892 func_exit: 01893 if (UNIV_LIKELY_NULL(heap)) { 01894 mem_heap_free(heap); 01895 } 01896 return(err); 01897 #else /* UNIV_HOTBACKUP */ 01898 /* This function depends on MySQL code that is not included in 01899 InnoDB Hot Backup builds. Besides, this function should never 01900 be called in InnoDB Hot Backup. */ 01901 ut_error; 01902 return(DB_FAIL); 01903 #endif /* UNIV_HOTBACKUP */ 01904 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_foreign_check_on_constraint | ( | que_thr_t * | thr, | |
| dict_foreign_t * | foreign, | |||
| btr_pcur_t * | pcur, | |||
| dtuple_t * | entry, | |||
| mtr_t * | mtr | |||
| ) | [static] |
Definition at line 763 of file row0ins.c.
References btr_pcur_get_btr_cur(), btr_pcur_get_low_match(), btr_pcur_get_rec(), btr_pcur_open_with_no_init(), BTR_SEARCH_LEAF, upd_node_struct::cascade_heap, upd_node_struct::cascade_node, DB_ROW_IS_REFERENCED, DB_SUCCESS, DICT_CLUSTERED, DICT_FOREIGN_ON_DELETE_CASCADE, DICT_FOREIGN_ON_DELETE_SET_NULL, DICT_FOREIGN_ON_UPDATE_CASCADE, DICT_FOREIGN_ON_UPDATE_SET_NULL, dict_index_get_n_unique(), dict_index_get_nth_col_no(), dict_index_name_print(), dict_table_get_first_index(), dict_table_get_nth_col_pos(), dict_table_is_comp(), err, FALSE, upd_node_struct::foreign, dict_foreign_struct::foreign_index, dict_foreign_struct::foreign_table, btr_cur_struct::index, index(), upd_node_struct::is_delete, lock_clust_rec_read_check_and_lock_alt(), LOCK_IX, LOCK_REC_NOT_GAP, lock_table(), LOCK_X, mem_heap_create, upd_struct::n_fields, dict_foreign_struct::n_fields, dict_table_struct::name, NULL, PAGE_CUR_LE, page_rec_is_user_rec(), upd_node_struct::pcur, que_node_set_parent(), rec_get_deleted_flag(), rec_print(), row_build_row_ref(), ROW_COPY_POINTERS, row_create_update_node_for_mysql(), row_ins_cascade_ancestor_updates_table(), row_ins_cascade_calc_update_vec(), row_ins_cascade_n_ancestors(), row_ins_foreign_report_err(), row_ins_invalidate_query_cache(), que_thr_struct::run_node, upd_node_struct::table, thr_get_trx(), TRUE, dict_foreign_struct::type, upd_create(), upd_node_struct::update, update, upd_node_struct::update_n_fields, and ut_a.
00765 : DB_SUCCESS, DB_LOCK_WAIT, 00766 or error code */ 00767 que_thr_t* thr, /* in: query thread whose run_node 00768 is an update node */ 00769 dict_foreign_t* foreign, /* in: foreign key constraint whose 00770 type is != 0 */ 00771 btr_pcur_t* pcur, /* in: cursor placed on a matching 00772 index record in the child table */ 00773 dtuple_t* entry, /* in: index entry in the parent 00774 table */ 00775 mtr_t* mtr) /* in: mtr holding the latch of pcur 00776 page */ 00777 { 00778 upd_node_t* node; 00779 upd_node_t* cascade; 00780 dict_table_t* table = foreign->foreign_table; 00781 dict_index_t* index; 00782 dict_index_t* clust_index; 00783 dtuple_t* ref; 00784 mem_heap_t* upd_vec_heap = NULL; 00785 rec_t* rec; 00786 rec_t* clust_rec; 00787 upd_t* update; 00788 ulint n_to_update; 00789 ulint err; 00790 ulint i; 00791 trx_t* trx; 00792 mem_heap_t* tmp_heap = NULL; 00793 00794 ut_a(thr && foreign && pcur && mtr); 00795 00796 trx = thr_get_trx(thr); 00797 00798 /* Since we are going to delete or update a row, we have to invalidate 00799 the MySQL query cache for table. A deadlock of threads is not possible 00800 here because the caller of this function does not hold any latches with 00801 the sync0sync.h rank above the kernel mutex. The query cache mutex has 00802 a rank just above the kernel mutex. */ 00803 00804 row_ins_invalidate_query_cache(thr, table->name); 00805 00806 node = thr->run_node; 00807 00808 if (node->is_delete && 0 == (foreign->type & 00809 (DICT_FOREIGN_ON_DELETE_CASCADE 00810 | DICT_FOREIGN_ON_DELETE_SET_NULL))) { 00811 00812 row_ins_foreign_report_err("Trying to delete", 00813 thr, foreign, 00814 btr_pcur_get_rec(pcur), entry); 00815 00816 return(DB_ROW_IS_REFERENCED); 00817 } 00818 00819 if (!node->is_delete && 0 == (foreign->type & 00820 (DICT_FOREIGN_ON_UPDATE_CASCADE 00821 | DICT_FOREIGN_ON_UPDATE_SET_NULL))) { 00822 00823 /* This is an UPDATE */ 00824 00825 row_ins_foreign_report_err("Trying to update", 00826 thr, foreign, 00827 btr_pcur_get_rec(pcur), entry); 00828 00829 return(DB_ROW_IS_REFERENCED); 00830 } 00831 00832 if (node->cascade_node == NULL) { 00833 /* Extend our query graph by creating a child to current 00834 update node. The child is used in the cascade or set null 00835 operation. */ 00836 00837 node->cascade_heap = mem_heap_create(128); 00838 node->cascade_node = row_create_update_node_for_mysql( 00839 table, node->cascade_heap); 00840 que_node_set_parent(node->cascade_node, node); 00841 } 00842 00843 /* Initialize cascade_node to do the operation we want. Note that we 00844 use the SAME cascade node to do all foreign key operations of the 00845 SQL DELETE: the table of the cascade node may change if there are 00846 several child tables to the table where the delete is done! */ 00847 00848 cascade = node->cascade_node; 00849 00850 cascade->table = table; 00851 00852 cascade->foreign = foreign; 00853 00854 if (node->is_delete 00855 && (foreign->type & DICT_FOREIGN_ON_DELETE_CASCADE)) { 00856 cascade->is_delete = TRUE; 00857 } else { 00858 cascade->is_delete = FALSE; 00859 00860 if (foreign->n_fields > cascade->update_n_fields) { 00861 /* We have to make the update vector longer */ 00862 00863 cascade->update = upd_create(foreign->n_fields, 00864 node->cascade_heap); 00865 cascade->update_n_fields = foreign->n_fields; 00866 } 00867 } 00868 00869 /* We do not allow cyclic cascaded updating (DELETE is allowed, 00870 but not UPDATE) of the same table, as this can lead to an infinite 00871 cycle. Check that we are not updating the same table which is 00872 already being modified in this cascade chain. We have to check 00873 this also because the modification of the indexes of a 'parent' 00874 table may still be incomplete, and we must avoid seeing the indexes 00875 of the parent table in an inconsistent state! */ 00876 00877 if (!cascade->is_delete 00878 && row_ins_cascade_ancestor_updates_table(cascade, table)) { 00879 00880 /* We do not know if this would break foreign key 00881 constraints, but play safe and return an error */ 00882 00883 err = DB_ROW_IS_REFERENCED; 00884 00885 row_ins_foreign_report_err( 00886 "Trying an update, possibly causing a cyclic cascaded update\n" 00887 "in the child table,", thr, foreign, btr_pcur_get_rec(pcur), entry); 00888 00889 goto nonstandard_exit_func; 00890 } 00891 00892 if (row_ins_cascade_n_ancestors(cascade) >= 15) { 00893 err = DB_ROW_IS_REFERENCED; 00894 00895 row_ins_foreign_report_err( 00896 "Trying a too deep cascaded delete or update\n", 00897 thr, foreign, btr_pcur_get_rec(pcur), entry); 00898 00899 goto nonstandard_exit_func; 00900 } 00901 00902 index = btr_pcur_get_btr_cur(pcur)->index; 00903 00904 ut_a(index == foreign->foreign_index); 00905 00906 rec = btr_pcur_get_rec(pcur); 00907 00908 if (index->type & DICT_CLUSTERED) { 00909 /* pcur is already positioned in the clustered index of 00910 the child table */ 00911 00912 clust_index = index; 00913 clust_rec = rec; 00914 } else { 00915 /* We have to look for the record in the clustered index 00916 in the child table */ 00917 00918 clust_index = dict_table_get_first_index(table); 00919 00920 tmp_heap = mem_heap_create(256); 00921 00922 ref = row_build_row_ref(ROW_COPY_POINTERS, index, rec, 00923 tmp_heap); 00924 btr_pcur_open_with_no_init(clust_index, ref, 00925 PAGE_CUR_LE, BTR_SEARCH_LEAF, 00926 cascade->pcur, 0, mtr); 00927 00928 clust_rec = btr_pcur_get_rec(cascade->pcur); 00929 00930 if (!page_rec_is_user_rec(clust_rec) 00931 || btr_pcur_get_low_match(cascade->pcur) 00932 < dict_index_get_n_unique(clust_index)) { 00933 00934 fputs( 00935 "InnoDB: error in cascade of a foreign key op\n" 00936 "InnoDB: ", stderr); 00937 dict_index_name_print(stderr, trx, index); 00938 00939 fputs("\n" 00940 "InnoDB: record ", stderr); 00941 rec_print(stderr, rec, index); 00942 fputs("\n" 00943 "InnoDB: clustered record ", stderr); 00944 rec_print(stderr, clust_rec, clust_index); 00945 fputs("\n" 00946 "InnoDB: Submit a detailed bug report to http://bugs.mysql.com\n", stderr); 00947 00948 err = DB_SUCCESS; 00949 00950 goto nonstandard_exit_func; 00951 } 00952 } 00953 00954 /* Set an X-lock on the row to delete or update in the child table */ 00955 00956 err = lock_table(0, table, LOCK_IX, thr); 00957 00958 if (err == DB_SUCCESS) { 00959 /* Here it suffices to use a LOCK_REC_NOT_GAP type lock; 00960 we already have a normal shared lock on the appropriate 00961 gap if the search criterion was not unique */ 00962 00963 err = lock_clust_rec_read_check_and_lock_alt(0, clust_rec, 00964 clust_index, LOCK_X, LOCK_REC_NOT_GAP, thr); 00965 } 00966 00967 if (err != DB_SUCCESS) { 00968 00969 goto nonstandard_exit_func; 00970 } 00971 00972 if (rec_get_deleted_flag(clust_rec, dict_table_is_comp(table))) { 00973 /* This can happen if there is a circular reference of 00974 rows such that cascading delete comes to delete a row 00975 already in the process of being delete marked */ 00976 err = DB_SUCCESS; 00977 00978 goto nonstandard_exit_func; 00979 } 00980 00981 if ((node->is_delete 00982 && (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)) 00983 || (!node->is_delete 00984 && (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL))) { 00985 00986 /* Build the appropriate update vector which sets 00987 foreign->n_fields first fields in rec to SQL NULL */ 00988 00989 update = cascade->update; 00990 00991 update->info_bits = 0; 00992 update->n_fields = foreign->n_fields; 00993 00994 for (i = 0; i < foreign->n_fields; i++) { 00995 (update->fields + i)->field_no 00996 = dict_table_get_nth_col_pos(table, 00997 dict_index_get_nth_col_no(index, i)); 00998 (update->fields + i)->exp = NULL; 00999 (update->fields + i)->new_val.len = UNIV_SQL_NULL; 01000 (update->fields + i)->new_val.data = NULL; 01001 (update->fields + i)->extern_storage = FALSE; 01002 } 01003 } 01004 01005 if (!node->is_delete 01006 && (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) { 01007 01008 /* Build the appropriate update vector which sets changing 01009 foreign->n_fields first fields in rec to new values */ 01010 01011 upd_vec_heap = mem_heap_create(256); 01012 01013 n_to_update = row_ins_cascade_calc_update_vec(node, foreign, 01014 upd_vec_heap); 01015 if (n_to_update == ULINT_UNDEFINED) { 01016 err = DB_ROW_IS_REFERENCED; 01017 01018 row_ins_foreign_report_err( 01019 "Trying a cascaded update where the updated value in the child\n" 01020 "table would not fit in the length of the column, or the value would\n" 01021 "be NULL and the column is declared as not NULL in the child table,", 01022 thr, foreign, btr_pcur_get_rec(pcur), entry); 01023 01024 goto nonstandard_exit_func; 01025 } 01026 01027 if (cascade->update->n_fields == 0) { 01028 01029 /* The update does not change any columns referred 01030 to in this foreign key constraint: no need to do 01031 anything */ 01032 01033 err = DB_SUCCESS; 01034 01035 goto nonstandard_exit_func; 01036 } 01037 } 01038 01039 /* Store pcur position and initialize or store the cascade node 01040 pcur stored position */ 01041 01042 btr_pcur_store_position(pcur, mtr); 01043 01044 if (index == clust_index) { 01045 btr_pcur_copy_stored_position(cascade->pcur, pcur); 01046 } else { 01047 btr_pcur_store_position(cascade->pcur, mtr); 01048 } 01049 01050 mtr_commit(mtr); 01051 01052 ut_a(cascade->pcur->rel_pos == BTR_PCUR_ON); 01053 01054 cascade->state = UPD_NODE_UPDATE_CLUSTERED; 01055 01056 err = row_update_cascade_for_mysql(thr, cascade, 01057 foreign->foreign_table); 01058 01059 if (foreign->foreign_table->n_foreign_key_checks_running == 0) { 01060 fprintf(stderr, 01061 "InnoDB: error: table %s has the counter 0 though there is\n" 01062 "InnoDB: a FOREIGN KEY check running on it.\n", 01063 foreign->foreign_table->name); 01064 } 01065 01066 /* Release the data dictionary latch for a while, so that we do not 01067 starve other threads from doing CREATE TABLE etc. if we have a huge 01068 cascaded operation running. The counter n_foreign_key_checks_running 01069 will prevent other users from dropping or ALTERing the table when we 01070 release the latch. */ 01071 01072 row_mysql_unfreeze_data_dictionary(thr_get_trx(thr)); 01073 row_mysql_freeze_data_dictionary(thr_get_trx(thr)); 01074 01075 mtr_start(mtr); 01076 01077 /* Restore pcur position */ 01078 01079 btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr); 01080 01081 if (tmp_heap) { 01082 mem_heap_free(tmp_heap); 01083 } 01084 01085 if (upd_vec_heap) { 01086 mem_heap_free(upd_vec_heap); 01087 } 01088 01089 return(err); 01090 01091 nonstandard_exit_func: 01092 if (tmp_heap) { 01093 mem_heap_free(tmp_heap); 01094 } 01095 01096 if (upd_vec_heap) { 01097 mem_heap_free(upd_vec_heap); 01098 } 01099 01100 btr_pcur_store_position(pcur, mtr); 01101 01102 mtr_commit(mtr); 01103 mtr_start(mtr); 01104 01105 btr_pcur_restore_position(BTR_SEARCH_LEAF, pcur, mtr); 01106 01107 return(err); 01108 }
Here is the call graph for this function:

| static void row_ins_foreign_report_add_err | ( | trx_t * | trx, | |
| dict_foreign_t * | foreign, | |||
| rec_t * | rec, | |||
| dtuple_t * | entry | |||
| ) | [static] |
Definition at line 679 of file row0ins.c.
References dict_foreign_err_file, dict_foreign_err_mutex, dict_print_info_on_foreign_key_in_create_format(), dtuple_print(), FALSE, dict_foreign_struct::foreign_index, dict_foreign_struct::foreign_table_name, mutex_enter, mutex_exit(), dict_index_struct::name, page_rec_get_prev(), page_rec_is_supremum(), rec_print(), dict_foreign_struct::referenced_index, dict_foreign_struct::referenced_table_name, row_ins_set_detailed(), TRUE, trx_print(), ut_print_name(), and ut_print_timestamp().
00681 : transaction */ 00682 dict_foreign_t* foreign, /* in: foreign key constraint */ 00683 rec_t* rec, /* in: a record in the parent table: 00684 it does not match entry because we 00685 have an error! */ 00686 dtuple_t* entry) /* in: index entry to insert in the 00687 child table */ 00688 { 00689 FILE* ef = dict_foreign_err_file; 00690 00691 row_ins_set_detailed(trx, foreign); 00692 00693 mutex_enter(&dict_foreign_err_mutex); 00694 rewind(ef); 00695 ut_print_timestamp(ef); 00696 fputs(" Transaction:\n", ef); 00697 trx_print(ef, trx, 600); 00698 fputs("Foreign key constraint fails for table ", ef); 00699 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name); 00700 fputs(":\n", ef); 00701 dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign, 00702 TRUE); 00703 fputs("\nTrying to add in child table, in index ", ef); 00704 ut_print_name(ef, trx, FALSE, foreign->foreign_index->name); 00705 if (entry) { 00706 fputs(" tuple:\n", ef); 00707 dtuple_print(ef, entry); 00708 } 00709 fputs("\nBut in parent table ", ef); 00710 ut_print_name(ef, trx, TRUE, foreign->referenced_table_name); 00711 fputs(", in index ", ef); 00712 ut_print_name(ef, trx, FALSE, foreign->referenced_index->name); 00713 fputs(",\nthe closest match we can find is record:\n", ef); 00714 if (rec && page_rec_is_supremum(rec)) { 00715 /* If the cursor ended on a supremum record, it is better 00716 to report the previous record in the error message, so that 00717 the user gets a more descriptive error message. */ 00718 rec = page_rec_get_prev(rec); 00719 } 00720 00721 if (rec) { 00722 rec_print(ef, rec, foreign->referenced_index); 00723 } 00724 putc('\n', ef); 00725 00726 mutex_exit(&dict_foreign_err_mutex); 00727 }
Here is the call graph for this function:

| static void row_ins_foreign_report_err | ( | const char * | errstr, | |
| que_thr_t * | thr, | |||
| dict_foreign_t * | foreign, | |||
| rec_t * | rec, | |||
| dtuple_t * | entry | |||
| ) | [static] |
Definition at line 622 of file row0ins.c.
References dict_foreign_err_file, dict_foreign_err_mutex, dict_print_info_on_foreign_key_in_create_format(), dtuple_print(), FALSE, dict_foreign_struct::foreign_index, dict_foreign_struct::foreign_table_name, mutex_enter, mutex_exit(), dict_index_struct::name, rec_print(), dict_foreign_struct::referenced_index, row_ins_set_detailed(), thr_get_trx(), TRUE, trx_print(), ut_print_name(), and ut_print_timestamp().
Referenced by row_ins_foreign_check_on_constraint().
00624 : error string from the viewpoint 00625 of the parent table */ 00626 que_thr_t* thr, /* in: query thread whose run_node 00627 is an update node */ 00628 dict_foreign_t* foreign, /* in: foreign key constraint */ 00629 rec_t* rec, /* in: a matching index record in the 00630 child table */ 00631 dtuple_t* entry) /* in: index entry in the parent 00632 table */ 00633 { 00634 FILE* ef = dict_foreign_err_file; 00635 trx_t* trx = thr_get_trx(thr); 00636 00637 row_ins_set_detailed(trx, foreign); 00638 00639 mutex_enter(&dict_foreign_err_mutex); 00640 rewind(ef); 00641 ut_print_timestamp(ef); 00642 fputs(" Transaction:\n", ef); 00643 trx_print(ef, trx, 600); 00644 00645 fputs("Foreign key constraint fails for table ", ef); 00646 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name); 00647 fputs(":\n", ef); 00648 dict_print_info_on_foreign_key_in_create_format(ef, trx, foreign, 00649 TRUE); 00650 putc('\n', ef); 00651 fputs(errstr, ef); 00652 fputs(" in parent table, in index ", ef); 00653 ut_print_name(ef, trx, FALSE, foreign->referenced_index->name); 00654 if (entry) { 00655 fputs(" tuple:\n", ef); 00656 dtuple_print(ef, entry); 00657 } 00658 fputs("\nBut in child table ", ef); 00659 ut_print_name(ef, trx, TRUE, foreign->foreign_table_name); 00660 fputs(", in index ", ef); 00661 ut_print_name(ef, trx, FALSE, foreign->foreign_index->name); 00662 if (rec) { 00663 fputs(", there is a record:\n", ef); 00664 rec_print(ef, rec, foreign->foreign_index); 00665 } else { 00666 fputs(", the record is not available\n", ef); 00667 } 00668 putc('\n', ef); 00669 00670 mutex_exit(&dict_foreign_err_mutex); 00671 }
Here is the call graph for this function:

Here is the caller graph for this function:

| UNIV_INLINE void row_ins_get_row_from_select | ( | ins_node_t * | node | ) |
Definition at line 2323 of file row0ins.c.
References dfield_copy_data(), dtuple_get_nth_field(), que_node_get_next(), que_node_get_val(), ins_node_struct::row, ins_node_struct::select, and sel_node_struct::select_list.
Referenced by row_ins().
02325 : row insert node */ 02326 { 02327 que_node_t* list_node; 02328 dfield_t* dfield; 02329 dtuple_t* row; 02330 ulint i; 02331 02332 /* The field values are copied in the buffers of the select node and 02333 it is safe to use them until we fetch from select again: therefore 02334 we can just copy the pointers */ 02335 02336 row = node->row; 02337 02338 i = 0; 02339 list_node = node->select->select_list; 02340 02341 while (list_node) { 02342 dfield = dtuple_get_nth_field(row, i); 02343 dfield_copy_data(dfield, que_node_get_val(list_node)); 02344 02345 i++; 02346 list_node = que_node_get_next(list_node); 02347 } 02348 }
Here is the call graph for this function:

Here is the caller graph for this function:

| UNIV_INLINE void row_ins_get_row_from_values | ( | ins_node_t * | node | ) |
Definition at line 2290 of file row0ins.c.
References dfield_copy_data(), dtuple_get_nth_field(), eval_exp(), que_node_get_next(), que_node_get_val(), ins_node_struct::row, and ins_node_struct::values_list.
Referenced by row_ins().
02292 : row insert node */ 02293 { 02294 que_node_t* list_node; 02295 dfield_t* dfield; 02296 dtuple_t* row; 02297 ulint i; 02298 02299 /* The field values are copied in the buffers of the select node and 02300 it is safe to use them until we fetch from select again: therefore 02301 we can just copy the pointers */ 02302 02303 row = node->row; 02304 02305 i = 0; 02306 list_node = node->values_list; 02307 02308 while (list_node) { 02309 eval_exp(list_node); 02310 02311 dfield = dtuple_get_nth_field(row, i); 02312 dfield_copy_data(dfield, que_node_get_val(list_node)); 02313 02314 i++; 02315 list_node = que_node_get_next(list_node); 02316 } 02317 }
Here is the call graph for this function:

Here is the caller graph for this function:

| ulint row_ins_index_entry | ( | dict_index_t * | index, | |
| dtuple_t * | entry, | |||
| ulint * | ext_vec, | |||
| ulint | n_ext_vec, | |||
| que_thr_t * | thr | |||
| ) |
Definition at line 2152 of file row0ins.c.
References BTR_MODIFY_LEAF, BTR_MODIFY_TREE, DB_FAIL, DB_SUCCESS, err, index(), row_ins_check_foreign_constraints(), row_ins_index_entry_low(), and UT_LIST_GET_FIRST.
Referenced by row_ins_index_entry_step(), row_upd_clust_rec_by_insert(), and row_upd_sec_index_entry().
02154 : DB_SUCCESS, DB_LOCK_WAIT, 02155 DB_DUPLICATE_KEY, or some other error code */ 02156 dict_index_t* index, /* in: index */ 02157 dtuple_t* entry, /* in: index entry to insert */ 02158 ulint* ext_vec,/* in: array containing field numbers of 02159 externally stored fields in entry, or NULL */ 02160 ulint n_ext_vec,/* in: number of fields in ext_vec */ 02161 que_thr_t* thr) /* in: query thread */ 02162 { 02163 ulint err; 02164 02165 if (UT_LIST_GET_FIRST(index->table->foreign_list)) { 02166 err = row_ins_check_foreign_constraints(index->table, index, 02167 entry, thr); 02168 if (err != DB_SUCCESS) { 02169 02170 return(err); 02171 } 02172 } 02173 02174 /* Try first optimistic descent to the B-tree */ 02175 02176 err = row_ins_index_entry_low(BTR_MODIFY_LEAF, index, entry, 02177 ext_vec, n_ext_vec, thr); 02178 if (err != DB_FAIL) { 02179 02180 return(err); 02181 } 02182 02183 /* Try then pessimistic descent to the B-tree */ 02184 02185 err = row_ins_index_entry_low(BTR_MODIFY_TREE, index, entry, 02186 ext_vec, n_ext_vec, thr); 02187 return(err); 02188 }
Here is the call graph for this function:

Here is the caller graph for this function:

| ulint row_ins_index_entry_low | ( | ulint | mode, | |
| dict_index_t * | index, | |||
| dtuple_t * | entry, | |||
| ulint * | ext_vec, | |||
| ulint | n_ext_vec, | |||
| que_thr_t * | thr | |||
| ) |
Definition at line 1959 of file row0ins.c.
References btr_cur_get_page(), btr_cur_get_rec(), BTR_CUR_INSERT_TO_IBUF, btr_cur_optimistic_insert(), btr_cur_pessimistic_insert(), btr_cur_position(), btr_cur_search_to_nth_level(), BTR_IGNORE_SEC_UNIQUE, BTR_INSERT, BTR_MODIFY_LEAF, BTR_MODIFY_TREE, btr_store_big_rec_extern_fields(), buf_LRU_buf_pool_running_out(), DB_LOCK_TABLE_FULL, DB_SUCCESS, DICT_CLUSTERED, dict_index_get_n_unique(), DICT_UNIQUE, dtuple_big_rec_free(), dtuple_convert_back_big_rec(), dtuple_get_n_fields(), err, btr_cur_struct::flag, index(), log_free_check(), btr_cur_struct::low_match, mem_heap_free, mtr_commit(), mtr_start(), NULL, page, PAGE_CUR_LE, page_get_infimum_rec(), page_get_supremum_rec(), page_rec_get_next(), page_t, rec_get_n_fields(), rec_get_offsets, REC_OFFS_NORMAL_SIZE, rec_set_field_extern_bits(), row_ins_clust_index_entry_by_modify(), row_ins_duplicate_error_in_clust(), row_ins_must_modify(), ROW_INS_NEXT, row_ins_scan_sec_index_for_duplicate(), row_ins_sec_index_entry_by_modify(), btr_cur_struct::thr, thr_get_trx(), btr_cur_struct::up_match, and ut_a.
Referenced by row_ins_index_entry().
01961 : DB_SUCCESS, DB_LOCK_WAIT, DB_FAIL 01962 if pessimistic retry needed, or error code */ 01963 ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, 01964 depending on whether we wish optimistic or 01965 pessimistic descent down the index tree */ 01966 dict_index_t* index, /* in: index */ 01967 dtuple_t* entry, /* in: index entry to insert */ 01968 ulint* ext_vec,/* in: array containing field numbers of 01969 externally stored fields in entry, or NULL */ 01970 ulint n_ext_vec,/* in: number of fields in ext_vec */ 01971 que_thr_t* thr) /* in: query thread */ 01972 { 01973 btr_cur_t cursor; 01974 ulint ignore_sec_unique = 0; 01975 ulint modify = 0; /* remove warning */ 01976 rec_t* insert_rec; 01977 rec_t* rec; 01978 ulint err; 01979 ulint n_unique; 01980 big_rec_t* big_rec = NULL; 01981 mtr_t mtr; 01982 mem_heap_t* heap = NULL; 01983 ulint offsets_[REC_OFFS_NORMAL_SIZE]; 01984 ulint* offsets = offsets_; 01985 *offsets_ = (sizeof offsets_) / sizeof *offsets_; 01986 01987 log_free_check(); 01988 01989 mtr_start(&mtr); 01990 01991 cursor.thr = thr; 01992 01993 /* Note that we use PAGE_CUR_LE as the search mode, because then 01994 the function will return in both low_match and up_match of the 01995 cursor sensible values */ 01996 01997 if (!(thr_get_trx(thr)->check_unique_secondary)) { 01998 ignore_sec_unique = BTR_IGNORE_SEC_UNIQUE; 01999 } 02000 02001 btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, 02002 mode | BTR_INSERT | ignore_sec_unique, 02003 &cursor, 0, &mtr); 02004 02005 if (cursor.flag == BTR_CUR_INSERT_TO_IBUF) { 02006 /* The insertion was made to the insert buffer already during 02007 the search: we are done */ 02008 02009 err = DB_SUCCESS; 02010 02011 goto function_exit; 02012 } 02013 02014 #ifdef UNIV_DEBUG 02015 { 02016 page_t* page = btr_cur_get_page(&cursor); 02017 rec_t* first_rec = page_rec_get_next( 02018 page_get_infimum_rec(page)); 02019 02020 if (UNIV_LIKELY(first_rec != page_get_supremum_rec(page))) { 02021 ut_a(rec_get_n_fields(first_rec, index) 02022 == dtuple_get_n_fields(entry)); 02023 } 02024 } 02025 #endif 02026 02027 n_unique = dict_index_get_n_unique(index); 02028 02029 if (index->type & DICT_UNIQUE && (cursor.up_match >= n_unique 02030 || cursor.low_match >= n_unique)) { 02031 02032 if (index->type & DICT_CLUSTERED) { 02033 /* Note that the following may return also 02034 DB_LOCK_WAIT */ 02035 02036 err = row_ins_duplicate_error_in_clust(&cursor, 02037 entry, thr, &mtr); 02038 if (err != DB_SUCCESS) { 02039 02040 goto function_exit; 02041 } 02042 } else { 02043 mtr_commit(&mtr); 02044 err = row_ins_scan_sec_index_for_duplicate(index, 02045 entry, thr); 02046 mtr_start(&mtr); 02047 02048 if (err != DB_SUCCESS) { 02049 02050 goto function_exit; 02051 } 02052 02053 /* We did not find a duplicate and we have now 02054 locked with s-locks the necessary records to 02055 prevent any insertion of a duplicate by another 02056 transaction. Let us now reposition the cursor and 02057 continue the insertion. */ 02058 02059 btr_cur_search_to_nth_level(index, 0, entry, 02060 PAGE_CUR_LE, mode | BTR_INSERT, 02061 &cursor, 0, &mtr); 02062 } 02063 } 02064 02065 modify = row_ins_must_modify(&cursor); 02066 02067 if (modify != 0) { 02068 /* There is already an index entry with a long enough common 02069 prefix, we must convert the insert into a modify of an 02070 existing record */ 02071 02072 if (modify == ROW_INS_NEXT) { 02073 rec = page_rec_get_next(btr_cur_get_rec(&cursor)); 02074 02075 btr_cur_position(index, rec, &cursor); 02076 } 02077 02078 if (index->type & DICT_CLUSTERED) { 02079 err = row_ins_clust_index_entry_by_modify(mode, 02080 &cursor, &big_rec, 02081 entry, 02082 ext_vec, n_ext_vec, 02083 thr, &mtr); 02084 } else { 02085 err = row_ins_sec_index_entry_by_modify(mode, &cursor, 02086 entry, 02087 thr, &mtr); 02088 } 02089 02090 } else { 02091 if (mode == BTR_MODIFY_LEAF) { 02092 err = btr_cur_optimistic_insert(0, &cursor, entry, 02093 &insert_rec, &big_rec, thr, &mtr); 02094 } else { 02095 ut_a(mode == BTR_MODIFY_TREE); 02096 if (buf_LRU_buf_pool_running_out()) { 02097 02098 err = DB_LOCK_TABLE_FULL; 02099 02100 goto function_exit; 02101 } 02102 err = btr_cur_pessimistic_insert(0, &cursor, entry, 02103 &insert_rec, &big_rec, thr, &mtr); 02104 } 02105 02106 if (err == DB_SUCCESS) { 02107 if (ext_vec) { 02108 rec_set_field_extern_bits(insert_rec, index, 02109 ext_vec, n_ext_vec, &mtr); 02110 } 02111 } 02112 } 02113 02114 function_exit: 02115 mtr_commit(&mtr); 02116 02117 if (big_rec) { 02118 rec_t* rec; 02119 mtr_start(&mtr); 02120 02121 btr_cur_search_to_nth_level(index, 0, entry, PAGE_CUR_LE, 02122 BTR_MODIFY_TREE, &cursor, 0, &mtr); 02123 rec = btr_cur_get_rec(&cursor); 02124 offsets = rec_get_offsets(rec, index, offsets, 02125 ULINT_UNDEFINED, &heap); 02126 02127 err = btr_store_big_rec_extern_fields(index, rec, 02128 offsets, big_rec, &mtr); 02129 02130 if (modify) { 02131 dtuple_big_rec_free(big_rec); 02132 } else { 02133 dtuple_convert_back_big_rec(index, entry, big_rec); 02134 } 02135 02136 mtr_commit(&mtr); 02137 } 02138 02139 if (UNIV_LIKELY_NULL(heap)) { 02140 mem_heap_free(heap); 02141 } 02142 return(err); 02143 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void row_ins_index_entry_set_vals | ( | dict_index_t * | index, | |
| dtuple_t * | entry, | |||
| dtuple_t * | row | |||
| ) | [static] |
Definition at line 2195 of file row0ins.c.
References dict_field_struct::col, dfield_struct::data, dfield_get_len(), dict_col_get_type(), dict_field_get_col(), dict_index_get_nth_field(), dtuple_get_n_fields(), dtuple_get_nth_field(), dtype_get_at_most_n_mbchars(), dict_col_struct::ind, index(), dfield_struct::len, dict_field_struct::prefix_len, and ut_ad.
Referenced by row_ins_index_entry_step().
02197 : index */ 02198 dtuple_t* entry, /* in: index entry to make */ 02199 dtuple_t* row) /* in: row */ 02200 { 02201 dict_field_t* ind_field; 02202 dfield_t* field; 02203 dfield_t* row_field; 02204 ulint n_fields; 02205 ulint i; 02206 dtype_t* cur_type; 02207 02208 ut_ad(entry && row); 02209 02210 n_fields = dtuple_get_n_fields(entry); 02211 02212 for (i = 0; i < n_fields; i++) { 02213 field = dtuple_get_nth_field(entry, i); 02214 ind_field = dict_index_get_nth_field(index, i); 02215 02216 row_field = dtuple_get_nth_field(row, ind_field->col->ind); 02217 02218 /* Check column prefix indexes */ 02219 if (ind_field->prefix_len > 0 02220 && dfield_get_len(row_field) != UNIV_SQL_NULL) { 02221 02222 cur_type = dict_col_get_type( 02223 dict_field_get_col(ind_field)); 02224 02225 field->len = dtype_get_at_most_n_mbchars(cur_type, 02226 ind_field->prefix_len, 02227 dfield_get_len(row_field), row_field->data); 02228 } else { 02229 field->len = row_field->len; 02230 } 02231 02232 field->data = row_field->data; 02233 } 02234 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_index_entry_step | ( | ins_node_t * | node, | |
| que_thr_t * | thr | |||
| ) | [static] |
Definition at line 2240 of file row0ins.c.
References dtuple_check_typed(), ins_node_struct::entry, err, ins_node_struct::index, NULL, ins_node_struct::row, row_ins_index_entry(), row_ins_index_entry_set_vals(), and ut_ad.
Referenced by row_ins().
02242 : DB_SUCCESS if operation successfully 02243 completed, else error code or DB_LOCK_WAIT */ 02244 ins_node_t* node, /* in: row insert node */ 02245 que_thr_t* thr) /* in: query thread */ 02246 { 02247 ulint err; 02248 02249 ut_ad(dtuple_check_typed(node->row)); 02250 02251 row_ins_index_entry_set_vals(node->index, node->entry, node->row); 02252 02253 ut_ad(dtuple_check_typed(node->entry)); 02254 02255 err = row_ins_index_entry(node->index, node->entry, NULL, 0, thr); 02256 02257 return(err); 02258 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void row_ins_invalidate_query_cache | ( | que_thr_t * | thr, | |
| const char * | name | |||
| ) | [static] |
Definition at line 733 of file row0ins.c.
References buf, innobase_invalidate_query_cache(), mem_free, mem_strdupl(), strchr(), strlen(), thr_get_trx(), and ut_a.
Referenced by row_ins_foreign_check_on_constraint().
00735 : query thread whose run_node 00736 is an update node */ 00737 const char* name) /* in: table name prefixed with 00738 database name and a '/' character */ 00739 { 00740 char* buf; 00741 char* ptr; 00742 ulint len = strlen(name) + 1; 00743 00744 buf = mem_strdupl(name, len); 00745 00746 ptr = strchr(buf, '/'); 00747 ut_a(ptr); 00748 *ptr = '\0'; 00749 00750 /* We call a function in ha_innodb.cc */ 00751 #ifndef UNIV_HOTBACKUP 00752 innobase_invalidate_query_cache(thr_get_trx(thr), buf, len); 00753 #endif 00754 mem_free(buf); 00755 }
Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1914 of file row0ins.c.
References btr_cur_get_rec(), dict_index_get_n_unique_in_tree(), btr_cur_struct::index, btr_cur_struct::low_match, page_rec_is_infimum(), and ROW_INS_PREV.
Referenced by row_ins_index_entry_low().
01916 : 0 if no update, ROW_INS_PREV if 01917 previous should be updated; currently we 01918 do the search so that only the low_match 01919 record can match enough to the search tuple, 01920 not the next record */ 01921 btr_cur_t* cursor) /* in: B-tree cursor */ 01922 { 01923 ulint enough_match; 01924 rec_t* rec; 01925 01926 /* NOTE: (compare to the note in row_ins_duplicate_error) Because node 01927 pointers on upper levels of the B-tree may match more to entry than 01928 to actual user records on the leaf level, we have to check if the 01929 candidate record is actually a user record. In a clustered index 01930 node pointers contain index->n_unique first fields, and in the case 01931 of a secondary index, all fields of the index. */ 01932 01933 enough_match = dict_index_get_n_unique_in_tree(cursor->index); 01934 01935 if (cursor->low_match >= enough_match) { 01936 01937 rec = btr_cur_get_rec(cursor); 01938 01939 if (!page_rec_is_infimum(rec)) { 01940 01941 return(ROW_INS_PREV); 01942 } 01943 } 01944 01945 return(0); 01946 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_scan_sec_index_for_duplicate | ( | dict_index_t * | index, | |
| dtuple_t * | entry, | |||
| que_thr_t * | thr | |||
| ) | [static] |
Definition at line 1631 of file row0ins.c.
References btr_pcur_get_rec(), btr_pcur_move_to_next(), btr_pcur_open(), BTR_SEARCH_LEAF, buf_frame_align(), cmp, cmp_dtuple_rec(), DB_DUPLICATE_KEY, DB_FAIL, DB_SUCCESS, dfield_get_len(), dict_index_get_n_unique(), dtuple_get_n_fields_cmp(), dtuple_get_nth_field(), dtuple_set_n_fields_cmp(), err, trx_struct::error_info, index(), innobase_query_is_update(), LOCK_ORDINARY, mem_heap_free, mtr_commit(), mtr_start(), NULL, PAGE_CUR_GE, page_get_infimum_rec(), page_rec_is_supremum(), rec_get_offsets, REC_OFFS_NORMAL_SIZE, row_ins_dupl_error_with_rec(), row_ins_set_exclusive_rec_lock(), row_ins_set_shared_rec_lock(), thr_get_trx(), ut_a, and ut_error.
Referenced by row_ins_index_entry_low().
01633 : DB_SUCCESS, DB_DUPLICATE_KEY, or 01634 DB_LOCK_WAIT */ 01635 dict_index_t* index, /* in: non-clustered unique index */ 01636 dtuple_t* entry, /* in: index entry */ 01637 que_thr_t* thr) /* in: query thread */ 01638 { 01639 #ifndef UNIV_HOTBACKUP 01640 ulint n_unique; 01641 ulint i; 01642 int cmp; 01643 ulint n_fields_cmp; 01644 rec_t* rec; 01645 btr_pcur_t pcur; 01646 ulint err = DB_SUCCESS; 01647 ibool moved; 01648 mtr_t mtr; 01649 mem_heap_t* heap = NULL; 01650 ulint offsets_[REC_OFFS_NORMAL_SIZE]; 01651 ulint* offsets = offsets_; 01652 *offsets_ = (sizeof offsets_) / sizeof *offsets_; 01653 01654 n_unique = dict_index_get_n_unique(index); 01655 01656 /* If the secondary index is unique, but one of the fields in the 01657 n_unique first fields is NULL, a unique key violation cannot occur, 01658 since we define NULL != NULL in this case */ 01659 01660 for (i = 0; i < n_unique; i++) { 01661 if (UNIV_SQL_NULL == dfield_get_len( 01662 dtuple_get_nth_field(entry, i))) { 01663 01664 return(DB_SUCCESS); 01665 } 01666 } 01667 01668 mtr_start(&mtr); 01669 01670 /* Store old value on n_fields_cmp */ 01671 01672 n_fields_cmp = dtuple_get_n_fields_cmp(entry); 01673 01674 dtuple_set_n_fields_cmp(entry, dict_index_get_n_unique(index)); 01675 01676 btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); 01677 01678 /* Scan index records and check if there is a duplicate */ 01679 01680 for (;;) { 01681 rec = btr_pcur_get_rec(&pcur); 01682 01683 if (rec == page_get_infimum_rec(buf_frame_align(rec))) { 01684 01685 goto next_rec; 01686 } 01687 01688 offsets = rec_get_offsets(rec, index, offsets, 01689 ULINT_UNDEFINED, &heap); 01690 01691 if (innobase_query_is_update()) { 01692 01693 /* If the SQL-query will update or replace 01694 duplicate key we will take X-lock for 01695 duplicates ( REPLACE, LOAD DATAFILE REPLACE, 01696 INSERT ON DUPLICATE KEY UPDATE). */ 01697 01698 err = row_ins_set_exclusive_rec_lock(LOCK_ORDINARY, 01699 rec, index, offsets, thr); 01700 } else { 01701 01702 err = row_ins_set_shared_rec_lock(LOCK_ORDINARY, 01703 rec, index, offsets, thr); 01704 } 01705 01706 if (err != DB_SUCCESS) { 01707 01708 break; 01709 } 01710 01711 if (page_rec_is_supremum(rec)) { 01712 01713 goto next_rec; 01714 } 01715 01716 cmp = cmp_dtuple_rec(entry, rec, offsets); 01717 01718 if (cmp == 0) { 01719 if (row_ins_dupl_error_with_rec(rec, entry, 01720 index, offsets)) { 01721 err = DB_DUPLICATE_KEY; 01722 01723 thr_get_trx(thr)->error_info = index; 01724 01725 break; 01726 } 01727 } 01728 01729 if (cmp < 0) { 01730 break; 01731 } 01732 01733 ut_a(cmp == 0); 01734 next_rec: 01735 moved = btr_pcur_move_to_next(&pcur, &mtr); 01736 01737 if (!moved) { 01738 break; 01739 } 01740 } 01741 01742 if (UNIV_LIKELY_NULL(heap)) { 01743 mem_heap_free(heap); 01744 } 01745 mtr_commit(&mtr); 01746 01747 /* Restore old value */ 01748 dtuple_set_n_fields_cmp(entry, n_fields_cmp); 01749 01750 return(err); 01751 #else /* UNIV_HOTBACKUP */ 01752 /* This function depends on MySQL code that is not included in 01753 InnoDB Hot Backup builds. Besides, this function should never 01754 be called in InnoDB Hot Backup. */ 01755 ut_error; 01756 return(DB_FAIL); 01757 #endif /* UNIV_HOTBACKUP */ 01758 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_sec_index_entry_by_modify | ( | ulint | mode, | |
| btr_cur_t * | cursor, | |||
| dtuple_t * | entry, | |||
| que_thr_t * | thr, | |||
| mtr_t * | mtr | |||
| ) | [static] |
Definition at line 224 of file row0ins.c.
References btr_cur_get_rec(), btr_cur_optimistic_update(), btr_cur_pessimistic_update(), BTR_KEEP_SYS_FLAG, BTR_MODIFY_LEAF, BTR_MODIFY_TREE, buf_LRU_buf_pool_running_out(), DB_FAIL, DB_LOCK_TABLE_FULL, DB_OVERFLOW, DB_UNDERFLOW, DICT_CLUSTERED, dict_table_is_comp(), err, btr_cur_struct::index, mem_heap_create, mem_heap_free, rec_get_deleted_flag(), row_upd_build_sec_rec_difference_binary(), dict_index_struct::table, thr_get_trx(), dict_index_struct::type, update, ut_a, and ut_ad.
Referenced by row_ins_index_entry_low().
00226 : DB_SUCCESS or error code */ 00227 ulint mode, /* in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, 00228 depending on whether mtr holds just a leaf 00229 latch or also a tree latch */ 00230 btr_cur_t* cursor, /* in: B-tree cursor */ 00231 dtuple_t* entry, /* in: index entry to insert */ 00232 que_thr_t* thr, /* in: query thread */ 00233 mtr_t* mtr) /* in: mtr */ 00234 { 00235 big_rec_t* dummy_big_rec; 00236 mem_heap_t* heap; 00237 upd_t* update; 00238 rec_t* rec; 00239 ulint err; 00240 00241 rec = btr_cur_get_rec(cursor); 00242 00243 ut_ad((cursor->index->type & DICT_CLUSTERED) == 0); 00244 ut_ad(rec_get_deleted_flag(rec, 00245 dict_table_is_comp(cursor->index->table))); 00246 00247 /* We know that in the alphabetical ordering, entry and rec are 00248 identified. But in their binary form there may be differences if 00249 there are char fields in them. Therefore we have to calculate the 00250 difference. */ 00251 00252 heap = mem_heap_create(1024); 00253 00254 update = row_upd_build_sec_rec_difference_binary(cursor->index, 00255 entry, rec, thr_get_trx(thr), heap); 00256 if (mode == BTR_MODIFY_LEAF) { 00257 /* Try an optimistic updating of the record, keeping changes 00258 within the page */ 00259 00260 err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG, cursor, 00261 update, 0, thr, mtr); 00262 if (err == DB_OVERFLOW || err == DB_UNDERFLOW) { 00263 err = DB_FAIL; 00264 } 00265 } else { 00266 ut_a(mode == BTR_MODIFY_TREE); 00267 if (buf_LRU_buf_pool_running_out()) { 00268 00269 err = DB_LOCK_TABLE_FULL; 00270 00271 goto func_exit; 00272 } 00273 00274 err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG, cursor, 00275 &dummy_big_rec, update, 0, thr, mtr); 00276 } 00277 func_exit: 00278 mem_heap_free(heap); 00279 00280 return(err); 00281 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static void row_ins_set_detailed | ( | trx_t * | trx, | |
| dict_foreign_t * | foreign | |||
| ) | [static] |
Definition at line 595 of file row0ins.c.
References dict_print_info_on_foreign_key_in_create_format(), FALSE, dict_foreign_struct::foreign_table_name, mutex_enter, mutex_exit(), os_file_set_eof(), srv_misc_tmpfile, srv_misc_tmpfile_mutex, TRUE, trx_set_detailed_error(), trx_set_detailed_error_from_file(), and ut_print_name().
Referenced by row_ins_foreign_report_add_err(), and row_ins_foreign_report_err().
00597 : transaction */ 00598 dict_foreign_t* foreign) /* in: foreign key constraint */ 00599 { 00600 mutex_enter(&srv_misc_tmpfile_mutex); 00601 rewind(srv_misc_tmpfile); 00602 00603 if (os_file_set_eof(srv_misc_tmpfile)) { 00604 ut_print_name(srv_misc_tmpfile, trx, TRUE, 00605 foreign->foreign_table_name); 00606 dict_print_info_on_foreign_key_in_create_format( 00607 srv_misc_tmpfile, 00608 trx, foreign, FALSE); 00609 trx_set_detailed_error_from_file(trx, srv_misc_tmpfile); 00610 } else { 00611 trx_set_detailed_error(trx, "temp file operation failed"); 00612 } 00613 00614 mutex_exit(&srv_misc_tmpfile_mutex); 00615 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_set_exclusive_rec_lock | ( | ulint | type, | |
| rec_t * | rec, | |||
| dict_index_t * | index, | |||
| const ulint * | offsets, | |||
| que_thr_t * | thr | |||
| ) | [static] |
Definition at line 1146 of file row0ins.c.
References DICT_CLUSTERED, err, index(), lock_clust_rec_read_check_and_lock(), lock_sec_rec_read_check_and_lock(), LOCK_X, rec_offs_validate(), and ut_ad.
Referenced by row_ins_duplicate_error_in_clust(), and row_ins_scan_sec_index_for_duplicate().
01148 : DB_SUCCESS or error code */ 01149 ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or 01150 LOCK_REC_NOT_GAP type lock */ 01151 rec_t* rec, /* in: record */ 01152 dict_index_t* index, /* in: index */ 01153 const ulint* offsets,/* in: rec_get_offsets(rec, index) */ 01154 que_thr_t* thr) /* in: query thread */ 01155 { 01156 ulint err; 01157 01158 ut_ad(rec_offs_validate(rec, index, offsets)); 01159 01160 if (index->type & DICT_CLUSTERED) { 01161 err = lock_clust_rec_read_check_and_lock(0, 01162 rec, index, offsets, LOCK_X, type, thr); 01163 } else { 01164 err = lock_sec_rec_read_check_and_lock(0, 01165 rec, index, offsets, LOCK_X, type, thr); 01166 } 01167 01168 return(err); 01169 }
Here is the call graph for this function:

Here is the caller graph for this function:

| static ulint row_ins_set_shared_rec_lock | ( | ulint | type, | |
| rec_t * | rec, | |||
| dict_index_t * | index, | |||
| const ulint * | offsets, | |||
| que_thr_t * | thr | |||
| ) | [static] |
Definition at line 1115 of file row0ins.c.
References DICT_CLUSTERED, err, index(), lock_clust_rec_read_check_and_lock(), LOCK_S, lock_sec_rec_read_check_and_lock(), rec_offs_validate(), and ut_ad.
Referenced by row_ins_duplicate_error_in_clust(), and row_ins_scan_sec_index_for_duplicate().
01117 : DB_SUCCESS or error code */ 01118 ulint type, /* in: LOCK_ORDINARY, LOCK_GAP, or 01119 LOCK_REC_NOT_GAP type lock */ 01120 rec_t* rec, /* in: record */ 01121 dict_index_t* index, /* in: index */ 01122 const ulint* offsets,/* in: rec_get_offsets(rec, index) */ 01123 que_thr_t* thr) /* in: query thread */ 01124 { 01125 ulint err; 01126 01127 ut_ad(rec_offs_validate(rec, index, offsets)); 01128 01129 if (index->type & DICT_CLUSTERED) { 01130 err = lock_clust_rec_read_check_and_lock(0, 01131 rec, index, offsets, LOCK_S, type, thr); 01132 } else { 01133 err = lock_sec_rec_read_check_and_lock(0, 01134 rec, index, offsets, LOCK_S, type, thr); 01135 } 01136 01137 return(err); 01138 }
Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 2410 of file row0ins.c.
References DB_SUCCESS, err, trx_struct::error_state, trx_struct::id, INS_NODE_ALLOC_ROW_ID, INS_NODE_SET_IX_LOCK, INS_SEARCHED, ins_node_struct::ins_type, LOCK_IX, lock_table(), NULL, que_thr_struct::prev_node, que_node_get_parent(), que_node_get_type(), QUE_NODE_INSERT, row_ins(), que_thr_struct::run_node, SEL_NODE_FETCH, SEL_NODE_NO_MORE_ROWS, SEL_NODE_OPEN, ins_node_struct::select, sel_node_struct::state, ins_node_struct::state, ins_node_struct::table, thr_get_trx(), ins_node_struct::trx_id, ins_node_struct::trx_id_buf, trx_start_if_not_started(), trx_write_trx_id(), ut_ad, and UT_DULINT_EQ.
Referenced by que_thr_step(), and row_insert_for_mysql().
02412 : query thread to run next or NULL */ 02413 que_thr_t* thr) /* in: query thread */ 02414 { 02415 ins_node_t* node; 02416 que_node_t* parent; 02417 sel_node_t* sel_node; 02418 trx_t* trx; 02419 ulint err; 02420 02421 ut_ad(thr); 02422 02423 trx = thr_get_trx(thr); 02424 02425 trx_start_if_not_started(trx); 02426 02427 node = thr->run_node; 02428 02429 ut_ad(que_node_get_type(node) == QUE_NODE_INSERT); 02430 02431 parent = que_node_get_parent(node); 02432 sel_node = node->select; 02433 02434 if (thr->prev_node == parent) { 02435 node->state = INS_NODE_SET_IX_LOCK; 02436 } 02437 02438 /* If this is the first time this node is executed (or when 02439 execution resumes after wait for the table IX lock), set an 02440 IX lock on the table and reset the possible select node. MySQL's 02441 partitioned table code may also call an insert within the same 02442 SQL statement AFTER it has used this table handle to do a search. 02443 This happens, for example, when a row update moves it to another 02444 partition. In that case, we have already set the IX lock on the 02445 table during the search operation, and there is no need to set 02446 it again here. But we must write trx->id to node->trx_id_buf. */ 02447 02448 trx_write_trx_id(node->trx_id_buf, trx->id); 02449 02450 if (node->state == INS_NODE_SET_IX_LOCK) { 02451 02452 /* It may be that the current session has not yet started 02453 its transaction, or it has been committed: */ 02454 02455 if (UT_DULINT_EQ(trx->id, node->trx_id)) { 02456 /* No need to do IX-locking */ 02457 02458 goto same_trx; 02459 } 02460 02461 err = lock_table(0, node->table, LOCK_IX, thr); 02462 02463 if (err != DB_SUCCESS) { 02464 02465 goto error_handling; 02466 } 02467 02468 node->trx_id = trx->id; 02469 same_trx: 02470 node->state = INS_NODE_ALLOC_ROW_ID; 02471 02472 if (node->ins_type == INS_SEARCHED) { 02473 /* Reset the cursor */ 02474 sel_node->state = SEL_NODE_OPEN; 02475 02476 /* Fetch a row to insert */ 02477 02478 thr->run_node = sel_node; 02479 02480 return(thr); 02481 } 02482 } 02483 02484 if ((node->ins_type == INS_SEARCHED) 02485 && (sel_node->state != SEL_NODE_FETCH)) { 02486 02487 ut_ad(sel_node->state == SEL_NODE_NO_MORE_ROWS); 02488 02489 /* No more rows to insert */ 02490 thr->run_node = parent; 02491 02492 return(thr); 02493 } 02494 02495 /* DO THE CHECKS OF THE CONSISTENCY CONSTRAINTS HERE */ 02496 02497 err = row_ins(node, thr); 02498 02499 error_handling: 02500 trx->error_state = err; 02501 02502 if (err != DB_SUCCESS) { 02503 /* err == DB_LOCK_WAIT or SQL error detected */ 02504 return(NULL); 02505 } 02506 02507 /* DO THE TRIGGER ACTIONS HERE */ 02508 02509 if (node->ins_type == INS_SEARCHED) { 02510 /* Fetch a row to insert */ 02511 02512 thr->run_node = sel_node; 02513 } else { 02514 thr->run_node = que_node_get_parent(node); 02515 } 02516 02517 return(thr); 02518 }
Here is the call graph for this function:

Here is the caller graph for this function:

1.4.7

