byte* trx_undo_rec_get_partial_row( /*=========================*/ /* out: pointer to remaining part of undo record */ byte* ptr, /* in: remaining part in update undo log record of a suitable type, at the start of the stored index columns; NOTE that this copy of the undo log record must be preserved as long as the partial row is used, as we do NOT copy the data in the record! */ dict_index_t* index, /* in: clustered index */ dtuple_t** row, /* out, own: partial row */ mem_heap_t* heap) /* in: memory heap from which the memory needed is allocated */ { dfield_t* dfield; byte* field; ulint len; ulint field_no; ulint col_no; ulint row_len; ulint total_len; byte* start_ptr; ulint i; ut_ad(index && ptr && row && heap); row_len = dict_table_get_n_cols(index->table); *row = dtuple_create(heap, row_len); dict_table_copy_types(*row, index->table); start_ptr = ptr; total_len = mach_read_from_2(ptr); ptr += 2; for (i = 0;; i++) { if (ptr == start_ptr + total_len) { break; } ptr = trx_undo_update_rec_get_field_no(ptr, &field_no); col_no = dict_index_get_nth_col_no(index, field_no); ptr = trx_undo_rec_get_col_val(ptr, &field, &len); dfield = dtuple_get_nth_field(*row, col_no); dfield_set_data(dfield, field, len); } return(ptr); }
void row_upd_clust_index_replace_new_col_vals( /*=====================================*/ dtuple_t* entry, /* in/out: index entry where replaced */ upd_t* update) /* in: update vector */ { upd_field_t* upd_field; dfield_t* dfield; dfield_t* new_val; ulint field_no; ulint i; dtuple_set_info_bits(entry, update->info_bits); for (i = 0; i < upd_get_n_fields(update); i++) { upd_field = upd_get_nth_field(update, i); field_no = upd_field->field_no; dfield = dtuple_get_nth_field(entry, field_no); new_val = &(upd_field->new_val); dfield_set_data(dfield, new_val->data, new_val->len); } }
dtuple_t* row_rec_to_index_entry( /*===================*/ /* out, own: index entry built; see the NOTE below! */ ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS: the former copies also the data fields to heap as the latter only places pointers to data fields on the index page */ dict_index_t* index, /* in: index */ rec_t* rec, /* in: record in the index; NOTE: in the case ROW_COPY_POINTERS the data fields in the row will point directly into this record, therefore, the buffer page of this record must be at least s-latched and the latch held as long as the dtuple is used! */ mem_heap_t* heap) /* in: memory heap from which the memory needed is allocated */ { dtuple_t* entry; dfield_t* dfield; ulint i; byte* field; ulint len; ulint rec_len; byte* buf; ut_ad(rec && heap && index); if (type == ROW_COPY_DATA) { /* Take a copy of rec to heap */ buf = mem_heap_alloc(heap, rec_get_size(rec)); rec = rec_copy(buf, rec); } rec_len = rec_get_n_fields(rec); entry = dtuple_create(heap, rec_len); dtuple_set_n_fields_cmp(entry, dict_index_get_n_unique_in_tree(index)); ut_ad(rec_len == dict_index_get_n_fields(index)); dict_index_copy_types(entry, index, rec_len); dtuple_set_info_bits(entry, rec_get_info_bits(rec)); for (i = 0; i < rec_len; i++) { dfield = dtuple_get_nth_field(entry, i); field = rec_get_nth_field(rec, i, &len); dfield_set_data(dfield, field, len); } ut_ad(dtuple_check_typed(entry)); return(entry); }
void rec_copy_prefix_to_dtuple( /*======================*/ dtuple_t* tuple, /* in: data tuple */ rec_t* rec, /* in: physical record */ ulint n_fields, /* in: number of fields to copy */ mem_heap_t* heap) /* in: memory heap */ { dfield_t* field; byte* data; ulint len; byte* buf = NULL; ulint i; ut_ad(rec_validate(rec)); ut_ad(dtuple_check_typed(tuple)); dtuple_set_info_bits(tuple, rec_get_info_bits(rec)); for (i = 0; i < n_fields; i++) { field = dtuple_get_nth_field(tuple, i); data = rec_get_nth_field(rec, i, &len); if (len != UNIV_SQL_NULL) { buf = mem_heap_alloc(heap, len); ut_memcpy(buf, data, len); } dfield_set_data(field, buf, len); } }
/* Some non-inlined functions used in the MySQL interface: */ void dfield_set_data_noninline( dfield_t* field, /* in: field */ void* data, /* in: data */ ulint len) /* in: length or UNIV_SQL_NULL */ { dfield_set_data(field, data, len); }
/*******************************************************************//** Converts an index record to a typed data tuple. @return index entry built; does not set info_bits, and the data fields in the entry will point directly to rec */ UNIV_INTERN dtuple_t* row_rec_to_index_entry_low( /*=======================*/ const rec_t* rec, /*!< in: record in the index */ const dict_index_t* index, /*!< in: index */ const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */ ulint* n_ext, /*!< out: number of externally stored columns */ mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ { dtuple_t* entry; dfield_t* dfield; ulint i; const byte* field; ulint len; ulint rec_len; ut_ad(rec && heap && index); /* Because this function may be invoked by row0merge.c on a record whose header is in different format, the check rec_offs_validate(rec, index, offsets) must be avoided here. */ ut_ad(n_ext); *n_ext = 0; rec_len = rec_offs_n_fields(offsets); entry = dtuple_create(heap, rec_len); dtuple_set_n_fields_cmp(entry, dict_index_get_n_unique_in_tree(index)); ut_ad(rec_len == dict_index_get_n_fields(index)); dict_index_copy_types(entry, index, rec_len); for (i = 0; i < rec_len; i++) { dfield = dtuple_get_nth_field(entry, i); field = rec_get_nth_field(rec, offsets, i, &len); dfield_set_data(dfield, field, len); if (rec_offs_nth_extern(offsets, i)) { dfield_set_ext(dfield); (*n_ext)++; } } ut_ad(dtuple_check_typed(entry)); return(entry); }
void row_build_to_tuple( /*===============*/ dtuple_t* row, /* in/out: row built; see the NOTE below! */ dict_index_t* index, /* in: clustered index */ rec_t* rec) /* in: record in the clustered index; NOTE: the data fields in the row will point directly into this record, therefore, the buffer page of this record must be at least s-latched and the latch held as long as the row dtuple is used! NOTE 2: does not work with externally stored fields! */ { dict_table_t* table; ulint n_fields; ulint i; dfield_t* dfield; byte* field; ulint len; ulint row_len; dict_col_t* col; ut_ad(index && rec); ut_ad(index->type & DICT_CLUSTERED); table = index->table; row_len = dict_table_get_n_cols(table); dtuple_set_info_bits(row, rec_get_info_bits(rec)); n_fields = dict_index_get_n_fields(index); ut_ad(n_fields == rec_get_n_fields(rec)); dict_table_copy_types(row, table); for (i = 0; i < n_fields; i++) { col = dict_field_get_col(dict_index_get_nth_field(index, i)); dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); field = rec_get_nth_field(rec, i, &len); dfield_set_data(dfield, field, len); } ut_ad(dtuple_check_typed(row)); }
/******************************************************************//** Adds a string literal to a symbol table. @return symbol table node */ UNIV_INTERN sym_node_t* sym_tab_add_str_lit( /*================*/ sym_tab_t* sym_tab, /*!< in: symbol table */ byte* str, /*!< in: string with no quotes around it */ ulint len) /*!< in: string length */ { sym_node_t* node; byte* data; node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t)); node->common.type = QUE_NODE_SYMBOL; node->resolved = TRUE; node->token_type = SYM_LIT; node->indirection = NULL; dtype_set(dfield_get_type(&node->common.val), DATA_VARCHAR, DATA_ENGLISH, 0); if (len) { data = mem_heap_alloc(sym_tab->heap, len); ut_memcpy(data, str, len); } else { data = NULL; } dfield_set_data(&(node->common.val), data, len); node->common.val_buf_size = 0; node->prefetch_buf = NULL; node->cursor_def = NULL; UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node); node->sym_table = sym_tab; return(node); }
/*******************************************************************//** Builds a row reference from an undo log record. @return pointer to remaining part of undo record */ UNIV_INTERN byte* trx_undo_rec_get_row_ref( /*=====================*/ byte* ptr, /*!< in: remaining part of a copy of an undo log record, at the start of the row reference; NOTE that this copy of the undo log record must be preserved as long as the row reference is used, as we do NOT copy the data in the record! */ dict_index_t* index, /*!< in: clustered index */ dtuple_t** ref, /*!< out, own: row reference */ mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ { ulint ref_len; ulint i; ut_ad(index && ptr && ref && heap); ut_a(dict_index_is_clust(index)); ref_len = dict_index_get_n_unique(index); *ref = dtuple_create(heap, ref_len); dict_index_copy_types(*ref, index, ref_len); for (i = 0; i < ref_len; i++) { dfield_t* dfield; byte* field; ulint len; ulint orig_len; dfield = dtuple_get_nth_field(*ref, i); ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len); dfield_set_data(dfield, field, len); } return(ptr); }
void row_upd_index_replace_new_col_vals( /*===============================*/ dtuple_t* entry, /* in/out: index entry where replaced */ dict_index_t* index, /* in: index; NOTE that may also be a non-clustered index */ upd_t* update) /* in: update vector */ { upd_field_t* upd_field; dfield_t* dfield; dfield_t* new_val; ulint field_no; dict_index_t* clust_index; ulint i; ut_ad(index); clust_index = dict_table_get_first_index(index->table); dtuple_set_info_bits(entry, update->info_bits); for (i = 0; i < upd_get_n_fields(update); i++) { upd_field = upd_get_nth_field(update, i); field_no = dict_index_get_nth_col_pos(index, dict_index_get_nth_col_no(clust_index, upd_field->field_no)); if (field_no != ULINT_UNDEFINED) { dfield = dtuple_get_nth_field(entry, field_no); new_val = &(upd_field->new_val); dfield_set_data(dfield, new_val->data, new_val->len); } } }
/******************************************************************//** Adds an integer literal to a symbol table. @return symbol table node */ UNIV_INTERN sym_node_t* sym_tab_add_int_lit( /*================*/ sym_tab_t* sym_tab, /*!< in: symbol table */ ulint val) /*!< in: integer value */ { sym_node_t* node; byte* data; node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t)); node->common.type = QUE_NODE_SYMBOL; node->resolved = TRUE; node->token_type = SYM_LIT; node->indirection = NULL; dtype_set(dfield_get_type(&node->common.val), DATA_INT, 0, 4); data = mem_heap_alloc(sym_tab->heap, 4); mach_write_to_4(data, val); dfield_set_data(&(node->common.val), data, 4); node->common.val_buf_size = 0; node->prefetch_buf = NULL; node->cursor_def = NULL; UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node); node->sym_table = sym_tab; return(node); }
/*************************************************************************** Loads a foreign key constraint to the dictionary cache. */ static ulint dict_load_foreign( /*==============*/ /* out: DB_SUCCESS or error code */ char* id) /* in: foreign constraint id as a null-terminated string */ { dict_foreign_t* foreign; dict_table_t* sys_foreign; btr_pcur_t pcur; dict_index_t* sys_index; dtuple_t* tuple; mem_heap_t* heap2; dfield_t* dfield; rec_t* rec; byte* field; ulint len; ulint err; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); heap2 = mem_heap_create(1000); mtr_start(&mtr); sys_foreign = dict_table_get_low("SYS_FOREIGN"); sys_index = UT_LIST_GET_FIRST(sys_foreign->indexes); tuple = dtuple_create(heap2, 1); dfield = dtuple_get_nth_field(tuple, 0); dfield_set_data(dfield, id, ut_strlen(id)); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); rec = btr_pcur_get_rec(&pcur); if (!btr_pcur_is_on_user_rec(&pcur, &mtr) || rec_get_deleted_flag(rec)) { /* Not found */ fprintf(stderr, "InnoDB: Error A: cannot load foreign constraint %s\n", id); btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap2); return(DB_ERROR); } field = rec_get_nth_field(rec, 0, &len); /* Check if the id in record is the searched one */ if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) { fprintf(stderr, "InnoDB: Error B: cannot load foreign constraint %s\n", id); btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap2); return(DB_ERROR); } /* Read the table names and the number of columns associated with the constraint */ mem_heap_free(heap2); foreign = dict_mem_foreign_create(); foreign->n_fields = mach_read_from_4(rec_get_nth_field(rec, 5, &len)); ut_a(len == 4); foreign->id = mem_heap_alloc(foreign->heap, ut_strlen(id) + 1); ut_memcpy(foreign->id, id, ut_strlen(id) + 1); field = rec_get_nth_field(rec, 3, &len); foreign->foreign_table_name = mem_heap_alloc(foreign->heap, 1 + len); ut_memcpy(foreign->foreign_table_name, field, len); foreign->foreign_table_name[len] = '\0'; field = rec_get_nth_field(rec, 4, &len); foreign->referenced_table_name = mem_heap_alloc(foreign->heap, 1 + len); ut_memcpy(foreign->referenced_table_name, field, len); foreign->referenced_table_name[len] = '\0'; btr_pcur_close(&pcur); mtr_commit(&mtr); dict_load_foreign_cols(id, foreign); /* Note that there may already be a foreign constraint object in the dictionary cache for this constraint: then the following call only sets the pointers in it to point to the appropriate table and index objects and frees the newly created object foreign. */ err = dict_foreign_add_to_cache(foreign); return(err); }
/**************************************************************//** Moves parts of long fields in entry to the big record vector so that the size of tuple drops below the maximum record size allowed in the database. Moves data only from those fields which are not necessary to determine uniquely the insertion place of the tuple in the index. @return own: created big record vector, NULL if we are not able to shorten the entry enough, i.e., if there are too many fixed-length or short fields in entry or the index is clustered */ UNIV_INTERN big_rec_t* dtuple_convert_big_rec( /*===================*/ dict_index_t* index, /*!< in: index */ dtuple_t* entry, /*!< in/out: index entry */ ulint* n_ext) /*!< in/out: number of externally stored columns */ { mem_heap_t* heap; big_rec_t* vector; dfield_t* dfield; dict_field_t* ifield; ulint size; ulint n_fields; ulint local_len; ulint local_prefix_len; if (UNIV_UNLIKELY(!dict_index_is_clust(index))) { return(NULL); } if (dict_table_get_format(index->table) < DICT_TF_FORMAT_ZIP) { /* up to MySQL 5.1: store a 768-byte prefix locally */ local_len = BTR_EXTERN_FIELD_REF_SIZE + DICT_MAX_INDEX_COL_LEN; } else { /* new-format table: do not store any BLOB prefix locally */ local_len = BTR_EXTERN_FIELD_REF_SIZE; } ut_a(dtuple_check_typed_no_assert(entry)); size = rec_get_converted_size(index, entry, *n_ext); if (UNIV_UNLIKELY(size > 1000000000)) { fprintf(stderr, "InnoDB: Warning: tuple size very big: %lu\n", (ulong) size); fputs("InnoDB: Tuple contents: ", stderr); dtuple_print(stderr, entry); putc('\n', stderr); } heap = mem_heap_create(size + dtuple_get_n_fields(entry) * sizeof(big_rec_field_t) + 1000); vector = mem_heap_alloc(heap, sizeof(big_rec_t)); vector->heap = heap; vector->fields = mem_heap_alloc(heap, dtuple_get_n_fields(entry) * sizeof(big_rec_field_t)); /* Decide which fields to shorten: the algorithm is to look for a variable-length field that yields the biggest savings when stored externally */ n_fields = 0; while (page_zip_rec_needs_ext(rec_get_converted_size(index, entry, *n_ext), dict_table_is_comp(index->table), dict_index_get_n_fields(index), dict_table_zip_size(index->table))) { ulint i; ulint longest = 0; ulint longest_i = ULINT_MAX; byte* data; big_rec_field_t* b; for (i = dict_index_get_n_unique_in_tree(index); i < dtuple_get_n_fields(entry); i++) { ulint savings; dfield = dtuple_get_nth_field(entry, i); ifield = dict_index_get_nth_field(index, i); /* Skip fixed-length, NULL, externally stored, or short columns */ if (ifield->fixed_len || dfield_is_null(dfield) || dfield_is_ext(dfield) || dfield_get_len(dfield) <= local_len || dfield_get_len(dfield) <= BTR_EXTERN_FIELD_REF_SIZE * 2) { goto skip_field; } savings = dfield_get_len(dfield) - local_len; /* Check that there would be savings */ if (longest >= savings) { goto skip_field; } longest_i = i; longest = savings; skip_field: continue; } if (!longest) { /* Cannot shorten more */ mem_heap_free(heap); return(NULL); } /* Move data from field longest_i to big rec vector. We store the first bytes locally to the record. Then we can calculate all ordering fields in all indexes from locally stored data. */ dfield = dtuple_get_nth_field(entry, longest_i); ifield = dict_index_get_nth_field(index, longest_i); local_prefix_len = local_len - BTR_EXTERN_FIELD_REF_SIZE; b = &vector->fields[n_fields]; b->field_no = longest_i; b->len = dfield_get_len(dfield) - local_prefix_len; b->data = (char*) dfield_get_data(dfield) + local_prefix_len; /* Allocate the locally stored part of the column. */ data = mem_heap_alloc(heap, local_len); /* Copy the local prefix. */ memcpy(data, dfield_get_data(dfield), local_prefix_len); /* Clear the extern field reference (BLOB pointer). */ memset(data + local_prefix_len, 0, BTR_EXTERN_FIELD_REF_SIZE); #if 0 /* The following would fail the Valgrind checks in page_cur_insert_rec_low() and page_cur_insert_rec_zip(). The BLOB pointers in the record will be initialized after the record and the BLOBs have been written. */ UNIV_MEM_ALLOC(data + local_prefix_len, BTR_EXTERN_FIELD_REF_SIZE); #endif dfield_set_data(dfield, data, local_len); dfield_set_ext(dfield); n_fields++; (*n_ext)++; ut_ad(n_fields < dtuple_get_n_fields(entry)); } vector->n_fields = n_fields; return(vector); }
dtuple_t* row_build_row_ref( /*==============*/ /* out, own: row reference built; see the NOTE below! */ ulint type, /* in: ROW_COPY_DATA, or ROW_COPY_POINTERS: the former copies also the data fields to heap, whereas the latter only places pointers to data fields on the index page */ dict_index_t* index, /* in: index */ rec_t* rec, /* in: record in the index; NOTE: in the case ROW_COPY_POINTERS the data fields in the row will point directly into this record, therefore, the buffer page of this record must be at least s-latched and the latch held as long as the row reference is used! */ mem_heap_t* heap) /* in: memory heap from which the memory needed is allocated */ { dict_table_t* table; dict_index_t* clust_index; dfield_t* dfield; dtuple_t* ref; byte* field; ulint len; ulint ref_len; ulint pos; byte* buf; ulint i; ut_ad(index && rec && heap); if (type == ROW_COPY_DATA) { /* Take a copy of rec to heap */ buf = mem_heap_alloc(heap, rec_get_size(rec)); rec = rec_copy(buf, rec); } table = index->table; clust_index = dict_table_get_first_index(table); ref_len = dict_index_get_n_unique(clust_index); ref = dtuple_create(heap, ref_len); dict_index_copy_types(ref, clust_index, ref_len); for (i = 0; i < ref_len; i++) { dfield = dtuple_get_nth_field(ref, i); pos = dict_index_get_nth_field_pos(index, clust_index, i); ut_a(pos != ULINT_UNDEFINED); field = rec_get_nth_field(rec, pos, &len); dfield_set_data(dfield, field, len); } ut_ad(dtuple_check_typed(ref)); return(ref); }
/********************************************************************* Based on a table object, this function builds the entry to be inserted in the SYS_COLUMNS system table. */ static dtuple_t* dict_create_sys_columns_tuple( /*==========================*/ /* out: the tuple which should be inserted */ dict_table_t* table, /* in: table */ ulint i, /* in: column number */ mem_heap_t* heap) /* in: memory heap from which the memory for the built tuple is allocated */ { dict_table_t* sys_columns; dtuple_t* entry; const dict_col_t* column; dfield_t* dfield; byte* ptr; const char* col_name; ut_ad(table && heap); column = dict_table_get_nth_col(table, i); sys_columns = dict_sys->sys_columns; entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS); /* 0: TABLE_ID -----------------------*/ dfield = dtuple_get_nth_field(entry, 0); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, table->id); dfield_set_data(dfield, ptr, 8); /* 1: POS ----------------------------*/ dfield = dtuple_get_nth_field(entry, 1); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, i); dfield_set_data(dfield, ptr, 4); /* 4: NAME ---------------------------*/ dfield = dtuple_get_nth_field(entry, 2); col_name = dict_table_get_col_name(table, i); dfield_set_data(dfield, col_name, ut_strlen(col_name)); /* 5: MTYPE --------------------------*/ dfield = dtuple_get_nth_field(entry, 3); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, column->mtype); dfield_set_data(dfield, ptr, 4); /* 6: PRTYPE -------------------------*/ dfield = dtuple_get_nth_field(entry, 4); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, column->prtype); dfield_set_data(dfield, ptr, 4); /* 7: LEN ----------------------------*/ dfield = dtuple_get_nth_field(entry, 5); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, column->len); dfield_set_data(dfield, ptr, 4); /* 8: PREC ---------------------------*/ dfield = dtuple_get_nth_field(entry, 6); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, 0/* unused */); dfield_set_data(dfield, ptr, 4); /*---------------------------------*/ dict_table_copy_types(entry, sys_columns); return(entry); }
/********************************************************************* Based on a table object, this function builds the entry to be inserted in the SYS_TABLES system table. */ static dtuple_t* dict_create_sys_tables_tuple( /*=========================*/ /* out: the tuple which should be inserted */ dict_table_t* table, /* in: table */ mem_heap_t* heap) /* in: memory heap from which the memory for the built tuple is allocated */ { dict_table_t* sys_tables; dtuple_t* entry; dfield_t* dfield; byte* ptr; ut_ad(table && heap); sys_tables = dict_sys->sys_tables; entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS); /* 0: NAME -----------------------------*/ dfield = dtuple_get_nth_field(entry, 0); dfield_set_data(dfield, table->name, ut_strlen(table->name)); /* 3: ID -------------------------------*/ dfield = dtuple_get_nth_field(entry, 1); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, table->id); dfield_set_data(dfield, ptr, 8); /* 4: N_COLS ---------------------------*/ dfield = dtuple_get_nth_field(entry, 2); #if DICT_TF_COMPACT != 1 #error #endif ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, table->n_def | ((table->flags & DICT_TF_COMPACT) << 31)); dfield_set_data(dfield, ptr, 4); /* 5: TYPE -----------------------------*/ dfield = dtuple_get_nth_field(entry, 3); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, DICT_TABLE_ORDINARY); dfield_set_data(dfield, ptr, 4); /* 6: MIX_ID (obsolete) ---------------------------*/ dfield = dtuple_get_nth_field(entry, 4); ptr = mem_heap_alloc(heap, 8); memset(ptr, 0, 8); dfield_set_data(dfield, ptr, 8); /* 7: MIX_LEN (obsolete) --------------------------*/ dfield = dtuple_get_nth_field(entry, 5); ptr = mem_heap_alloc(heap, 4); memset(ptr, 0, 4); dfield_set_data(dfield, ptr, 4); /* 8: CLUSTER_NAME ---------------------*/ dfield = dtuple_get_nth_field(entry, 6); dfield_set_data(dfield, NULL, UNIV_SQL_NULL); /* not supported */ /* 9: SPACE ----------------------------*/ dfield = dtuple_get_nth_field(entry, 7); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, table->space); dfield_set_data(dfield, ptr, 4); /*----------------------------------*/ dict_table_copy_types(entry, sys_tables); return(entry); }
/*******************************************************************//** An inverse function to row_build_index_entry. Builds a row from a record in a clustered index. @return own: row built; see the NOTE below! */ UNIV_INTERN dtuple_t* row_build( /*======*/ ulint type, /*!< in: ROW_COPY_POINTERS or ROW_COPY_DATA; the latter copies also the data fields to heap while the first only places pointers to data fields on the index page, and thus is more efficient */ const dict_index_t* index, /*!< in: clustered index */ const rec_t* rec, /*!< in: record in the clustered index; NOTE: in the case ROW_COPY_POINTERS the data fields in the row will point directly into this record, therefore, the buffer page of this record must be at least s-latched and the latch held as long as the row dtuple is used! */ const ulint* offsets,/*!< in: rec_get_offsets(rec,index) or NULL, in which case this function will invoke rec_get_offsets() */ const dict_table_t* col_table, /*!< in: table, to check which externally stored columns occur in the ordering columns of an index, or NULL if index->table should be consulted instead */ row_ext_t** ext, /*!< out, own: cache of externally stored column prefixes, or NULL */ mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ { dtuple_t* row; const dict_table_t* table; ulint n_fields; ulint n_ext_cols; ulint* ext_cols = NULL; /* remove warning */ ulint len; ulint row_len; byte* buf; ulint i; ulint j; mem_heap_t* tmp_heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs_init(offsets_); ut_ad(index && rec && heap); ut_ad(dict_index_is_clust(index)); ut_ad(!mutex_own(&kernel_mutex)); if (!offsets) { offsets = rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &tmp_heap); } else { ut_ad(rec_offs_validate(rec, index, offsets)); } #if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG if (rec_offs_any_null_extern(rec, offsets)) { /* This condition can occur during crash recovery before trx_rollback_active() has completed execution, or when a concurrently executing row_ins_index_entry_low() has committed the B-tree mini-transaction but has not yet managed to restore the cursor position for writing the big_rec. */ ut_a(trx_undo_roll_ptr_is_insert( row_get_rec_roll_ptr(rec, index, offsets))); } #endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */ if (type != ROW_COPY_POINTERS) { /* Take a copy of rec to heap */ buf = mem_heap_alloc(heap, rec_offs_size(offsets)); rec = rec_copy(buf, rec, offsets); /* Avoid a debug assertion in rec_offs_validate(). */ rec_offs_make_valid(rec, index, (ulint*) offsets); } table = index->table; row_len = dict_table_get_n_cols(table); row = dtuple_create(heap, row_len); dict_table_copy_types(row, table); dtuple_set_info_bits(row, rec_get_info_bits( rec, dict_table_is_comp(table))); n_fields = rec_offs_n_fields(offsets); n_ext_cols = rec_offs_n_extern(offsets); if (n_ext_cols) { ext_cols = mem_heap_alloc(heap, n_ext_cols * sizeof *ext_cols); } for (i = j = 0; i < n_fields; i++) { dict_field_t* ind_field = dict_index_get_nth_field(index, i); const dict_col_t* col = dict_field_get_col(ind_field); ulint col_no = dict_col_get_no(col); dfield_t* dfield = dtuple_get_nth_field(row, col_no); if (ind_field->prefix_len == 0) { const byte* field = rec_get_nth_field( rec, offsets, i, &len); dfield_set_data(dfield, field, len); } if (rec_offs_nth_extern(offsets, i)) { dfield_set_ext(dfield); if (UNIV_LIKELY_NULL(col_table)) { ut_a(col_no < dict_table_get_n_cols(col_table)); col = dict_table_get_nth_col( col_table, col_no); } if (col->ord_part) { /* We will have to fetch prefixes of externally stored columns that are referenced by column prefixes. */ ext_cols[j++] = col_no; } } } ut_ad(dtuple_check_typed(row)); if (!ext) { /* REDUNDANT and COMPACT formats store a local 768-byte prefix of each externally stored column. No cache is needed. */ ut_ad(dict_table_get_format(index->table) < DICT_TF_FORMAT_ZIP); } else if (j) { *ext = row_ext_create(j, ext_cols, row, dict_table_zip_size(index->table), heap); } else { *ext = NULL; } if (tmp_heap) { mem_heap_free(tmp_heap); } return(row); }
ulint dict_load_foreigns( /*===============*/ /* out: DB_SUCCESS or error code */ char* table_name) /* in: table name */ { btr_pcur_t pcur; mem_heap_t* heap; dtuple_t* tuple; dfield_t* dfield; dict_index_t* sec_index; dict_table_t* sys_foreign; rec_t* rec; byte* field; ulint len; char* id ; ulint err; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); sys_foreign = dict_table_get_low("SYS_FOREIGN"); if (sys_foreign == NULL) { /* No foreign keys defined yet in this database */ fprintf(stderr, "InnoDB: Error: no foreign key system tables in the database\n"); return(DB_ERROR); } mtr_start(&mtr); /* Get the secondary index based on FOR_NAME from table SYS_FOREIGN */ sec_index = dict_table_get_next_index( dict_table_get_first_index(sys_foreign)); start_load: heap = mem_heap_create(256); tuple = dtuple_create(heap, 1); dfield = dtuple_get_nth_field(tuple, 0); dfield_set_data(dfield, table_name, ut_strlen(table_name)); dict_index_copy_types(tuple, sec_index, 1); btr_pcur_open_on_user_rec(sec_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); loop: rec = btr_pcur_get_rec(&pcur); if (!btr_pcur_is_on_user_rec(&pcur, &mtr)) { /* End of index */ goto load_next_index; } /* Now we have the record in the secondary index containing a table name and a foreign constraint ID */ rec = btr_pcur_get_rec(&pcur); field = rec_get_nth_field(rec, 0, &len); /* Check if the table name in record is the one searched for */ if (len != ut_strlen(table_name) || 0 != ut_memcmp(field, table_name, len)) { goto load_next_index; } if (rec_get_deleted_flag(rec)) { goto next_rec; } /* Now we get a foreign key constraint id */ field = rec_get_nth_field(rec, 1, &len); id = mem_heap_alloc(heap, len + 1); ut_memcpy(id, field, len); id[len] = '\0'; btr_pcur_store_position(&pcur, &mtr); mtr_commit(&mtr); /* Load the foreign constraint definition to the dictionary cache */ err = dict_load_foreign(id); if (err != DB_SUCCESS) { btr_pcur_close(&pcur); mem_heap_free(heap); return(err); } mtr_start(&mtr); btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr); next_rec: btr_pcur_move_to_next_user_rec(&pcur, &mtr); goto loop; load_next_index: btr_pcur_close(&pcur); mtr_commit(&mtr); mem_heap_free(heap); sec_index = dict_table_get_next_index(sec_index); if (sec_index != NULL) { mtr_start(&mtr); goto start_load; } return(DB_SUCCESS); }
/*****************************************************************//** Based on a table object, this function builds the entry to be inserted in the SYS_TABLES system table. @return the tuple which should be inserted */ static dtuple_t* dict_create_sys_tables_tuple( /*=========================*/ const dict_table_t* table, /*!< in: table */ mem_heap_t* heap) /*!< in: memory heap from which the memory for the built tuple is allocated */ { dict_table_t* sys_tables; dtuple_t* entry; dfield_t* dfield; byte* ptr; ut_ad(table); ut_ad(heap); sys_tables = dict_sys->sys_tables; entry = dtuple_create(heap, 8 + DATA_N_SYS_COLS); dict_table_copy_types(entry, sys_tables); /* 0: NAME -----------------------------*/ dfield = dtuple_get_nth_field(entry, 0/*NAME*/); dfield_set_data(dfield, table->name, ut_strlen(table->name)); /* 3: ID -------------------------------*/ dfield = dtuple_get_nth_field(entry, 1/*ID*/); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, table->id); dfield_set_data(dfield, ptr, 8); /* 4: N_COLS ---------------------------*/ dfield = dtuple_get_nth_field(entry, 2/*N_COLS*/); #if DICT_TF_COMPACT != 1 #error #endif ptr = mem_heap_alloc(heap, 4); if (dict_table_is_gcs(table)) /* ±í¶¨ÒåÐÞ¸Ä */ { ut_ad(dict_table_is_comp(table)); mach_write_to_4(ptr, table->n_def | (1 << 31) | (1 << 30)); } else { mach_write_to_4(ptr, table->n_def | ((table->flags & DICT_TF_COMPACT) << 31)); } dfield_set_data(dfield, ptr, 4); /* 5: TYPE -----------------------------*/ dfield = dtuple_get_nth_field(entry, 3/*TYPE*/); ptr = mem_heap_alloc(heap, 4); if (table->flags & (~DICT_TF_COMPACT & ~(~0 << DICT_TF_BITS))) { ut_a(table->flags & DICT_TF_COMPACT); ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP); ut_a((table->flags & DICT_TF_ZSSIZE_MASK) <= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT)); ut_a(!(table->flags & (~0 << DICT_TF2_BITS))); mach_write_to_4(ptr, table->flags & ~(~0 << DICT_TF_BITS)); } else { mach_write_to_4(ptr, DICT_TABLE_ORDINARY); } dfield_set_data(dfield, ptr, 4); /* 6: MIX_ID (obsolete) ---------------------------*/ dfield = dtuple_get_nth_field(entry, 4/*MIX_ID*/); ptr = mem_heap_zalloc(heap, 8); dfield_set_data(dfield, ptr, 8); /* 7: MIX_LEN (additional flags) --------------------------*/ dfield = dtuple_get_nth_field(entry, 5/*MIX_LEN*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, table->flags >> DICT_TF2_SHIFT); ut_ad(table->n_cols_before_alter_table == 0); dfield_set_data(dfield, ptr, 4); /* 8: CLUSTER_NAME ---------------------*/ dfield = dtuple_get_nth_field(entry, 6/*CLUSTER_NAME*/); dfield_set_null(dfield); /* not supported */ /* 9: SPACE ----------------------------*/ dfield = dtuple_get_nth_field(entry, 7/*SPACE*/); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, table->space); dfield_set_data(dfield, ptr, 4); /*----------------------------------*/ return(entry); }
dtuple_t* row_build( /*======*/ /* out, own: row built; see the NOTE below! */ ulint type, /* in: ROW_COPY_POINTERS, ROW_COPY_DATA, or ROW_COPY_ALSO_EXTERNALS, the two last copy also the data fields to heap as the first only places pointers to data fields on the index page, and thus is more efficient */ dict_index_t* index, /* in: clustered index */ rec_t* rec, /* in: record in the clustered index; NOTE: in the case ROW_COPY_POINTERS the data fields in the row will point directly into this record, therefore, the buffer page of this record must be at least s-latched and the latch held as long as the row dtuple is used! */ mem_heap_t* heap) /* in: memory heap from which the memory needed is allocated */ { dtuple_t* row; dict_table_t* table; dict_field_t* ind_field; dict_col_t* col; dfield_t* dfield; ulint n_fields; byte* field; ulint len; ulint row_len; byte* buf; ulint i; ut_ad(index && rec && heap); ut_ad(index->type & DICT_CLUSTERED); if (type != ROW_COPY_POINTERS) { /* Take a copy of rec to heap */ buf = mem_heap_alloc(heap, rec_get_size(rec)); rec = rec_copy(buf, rec); } table = index->table; row_len = dict_table_get_n_cols(table); row = dtuple_create(heap, row_len); dtuple_set_info_bits(row, rec_get_info_bits(rec)); n_fields = dict_index_get_n_fields(index); ut_ad(n_fields == rec_get_n_fields(rec)); dict_table_copy_types(row, table); for (i = 0; i < n_fields; i++) { ind_field = dict_index_get_nth_field(index, i); if (ind_field->prefix_len == 0) { col = dict_field_get_col(ind_field); dfield = dtuple_get_nth_field(row, dict_col_get_no(col)); field = rec_get_nth_field(rec, i, &len); if (type == ROW_COPY_ALSO_EXTERNALS && rec_get_nth_field_extern_bit(rec, i)) { field = btr_rec_copy_externally_stored_field( rec, i, &len, heap); } dfield_set_data(dfield, field, len); } } ut_ad(dtuple_check_typed(row)); return(row); }
void row_build_row_ref_in_tuple( /*=======================*/ dtuple_t* ref, /* in/out: row reference built; see the NOTE below! */ dict_index_t* index, /* in: index */ rec_t* rec) /* in: record in the index; NOTE: the data fields in ref will point directly into this record, therefore, the buffer page of this record must be at least s-latched and the latch held as long as the row reference is used! */ { dict_table_t* table; dict_index_t* clust_index; dfield_t* dfield; byte* field; ulint len; ulint ref_len; ulint pos; ulint i; ut_a(ref && index && rec); table = index->table; if (!table) { fprintf(stderr, "InnoDB: table %s for index %s not found\n", index->table_name, index->name); ut_a(0); } clust_index = dict_table_get_first_index(table); if (!clust_index) { fprintf(stderr, "InnoDB: clust index for table %s for index %s not found\n", index->table_name, index->name); ut_a(0); } ref_len = dict_index_get_n_unique(clust_index); ut_ad(ref_len == dtuple_get_n_fields(ref)); dict_index_copy_types(ref, clust_index, ref_len); for (i = 0; i < ref_len; i++) { dfield = dtuple_get_nth_field(ref, i); pos = dict_index_get_nth_field_pos(index, clust_index, i); ut_a(pos != ULINT_UNDEFINED); field = rec_get_nth_field(rec, pos, &len); dfield_set_data(dfield, field, len); } ut_ad(dtuple_check_typed(ref)); }
/******************************************************************//** Add a bound literal to a symbol table. @return symbol table node */ UNIV_INTERN sym_node_t* sym_tab_add_bound_lit( /*==================*/ sym_tab_t* sym_tab, /*!< in: symbol table */ const char* name, /*!< in: name of bound literal */ ulint* lit_type) /*!< out: type of literal (PARS_*_LIT) */ { sym_node_t* node; pars_bound_lit_t* blit; ulint len = 0; blit = pars_info_get_bound_lit(sym_tab->info, name); ut_a(blit); node = mem_heap_alloc(sym_tab->heap, sizeof(sym_node_t)); node->common.type = QUE_NODE_SYMBOL; node->resolved = TRUE; node->token_type = SYM_LIT; node->indirection = NULL; switch (blit->type) { case DATA_FIXBINARY: len = blit->length; *lit_type = PARS_FIXBINARY_LIT; break; case DATA_BLOB: *lit_type = PARS_BLOB_LIT; break; case DATA_VARCHAR: *lit_type = PARS_STR_LIT; break; case DATA_CHAR: ut_a(blit->length > 0); len = blit->length; *lit_type = PARS_STR_LIT; break; case DATA_INT: ut_a(blit->length > 0); ut_a(blit->length <= 8); len = blit->length; *lit_type = PARS_INT_LIT; break; default: ut_error; } dtype_set(dfield_get_type(&node->common.val), blit->type, blit->prtype, len); dfield_set_data(&(node->common.val), blit->address, blit->length); node->common.val_buf_size = 0; node->prefetch_buf = NULL; node->cursor_def = NULL; UT_LIST_ADD_LAST(sym_list, sym_tab->sym_list, node); node->sym_table = sym_tab; return(node); }
/*******************************************************************//** Builds a partial row from an update undo log record. It contains the columns which occur as ordering in any index of the table. @return pointer to remaining part of undo record */ UNIV_INTERN byte* trx_undo_rec_get_partial_row( /*=========================*/ byte* ptr, /*!< in: remaining part in update undo log record of a suitable type, at the start of the stored index columns; NOTE that this copy of the undo log record must be preserved as long as the partial row is used, as we do NOT copy the data in the record! */ dict_index_t* index, /*!< in: clustered index */ dtuple_t** row, /*!< out, own: partial row */ ibool ignore_prefix, /*!< in: flag to indicate if we expect blob prefixes in undo. Used only in the assertion. */ mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ { const byte* end_ptr; ulint row_len; ut_ad(index); ut_ad(ptr); ut_ad(row); ut_ad(heap); ut_ad(dict_index_is_clust(index)); row_len = dict_table_get_n_cols(index->table); *row = dtuple_create(heap, row_len); dict_table_copy_types(*row, index->table); end_ptr = ptr + mach_read_from_2(ptr); ptr += 2; while (ptr != end_ptr) { dfield_t* dfield; byte* field; ulint field_no; const dict_col_t* col; ulint col_no; ulint len; ulint orig_len; ptr = trx_undo_update_rec_get_field_no(ptr, &field_no); col = dict_index_get_nth_col(index, field_no); col_no = dict_col_get_no(col); ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len); dfield = dtuple_get_nth_field(*row, col_no); dfield_set_data(dfield, field, len); if (len != UNIV_SQL_NULL && len >= UNIV_EXTERN_STORAGE_FIELD) { dfield_set_len(dfield, len - UNIV_EXTERN_STORAGE_FIELD); dfield_set_ext(dfield); /* If the prefix of this column is indexed, ensure that enough prefix is stored in the undo log record. */ if (!ignore_prefix && col->ord_part) { ut_a(dfield_get_len(dfield) >= 2 * BTR_EXTERN_FIELD_REF_SIZE); ut_a(dict_table_get_format(index->table) >= DICT_TF_FORMAT_ZIP || dfield_get_len(dfield) >= REC_MAX_INDEX_COL_LEN + BTR_EXTERN_FIELD_REF_SIZE); } } } return(ptr); }
/************************************************************************ Loads foreign key constraint col names (also for the referenced table). */ static void dict_load_foreign_cols( /*===================*/ char* id, /* in: foreign constraint id as a null- terminated string */ dict_foreign_t* foreign)/* in: foreign constraint object */ { dict_table_t* sys_foreign_cols; dict_index_t* sys_index; btr_pcur_t pcur; dtuple_t* tuple; dfield_t* dfield; char* col_name; rec_t* rec; byte* field; ulint len; ulint i; mtr_t mtr; ut_ad(mutex_own(&(dict_sys->mutex))); foreign->foreign_col_names = mem_heap_alloc(foreign->heap, foreign->n_fields * sizeof(void*)); foreign->referenced_col_names = mem_heap_alloc(foreign->heap, foreign->n_fields * sizeof(void*)); mtr_start(&mtr); sys_foreign_cols = dict_table_get_low("SYS_FOREIGN_COLS"); sys_index = UT_LIST_GET_FIRST(sys_foreign_cols->indexes); tuple = dtuple_create(foreign->heap, 1); dfield = dtuple_get_nth_field(tuple, 0); dfield_set_data(dfield, id, ut_strlen(id)); dict_index_copy_types(tuple, sys_index, 1); btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); for (i = 0; i < foreign->n_fields; i++) { rec = btr_pcur_get_rec(&pcur); ut_a(btr_pcur_is_on_user_rec(&pcur, &mtr)); ut_a(!rec_get_deleted_flag(rec)); field = rec_get_nth_field(rec, 0, &len); ut_a(len == ut_strlen(id)); ut_a(ut_memcmp(id, field, len) == 0); field = rec_get_nth_field(rec, 1, &len); ut_a(len == 4); ut_a(i == mach_read_from_4(field)); field = rec_get_nth_field(rec, 4, &len); col_name = mem_heap_alloc(foreign->heap, len + 1); ut_memcpy(col_name, field, len); col_name[len] = '\0'; foreign->foreign_col_names[i] = col_name; field = rec_get_nth_field(rec, 5, &len); col_name = mem_heap_alloc(foreign->heap, len + 1); ut_memcpy(col_name, field, len); col_name[len] = '\0'; foreign->referenced_col_names[i] = col_name; btr_pcur_move_to_next_user_rec(&pcur, &mtr); } btr_pcur_close(&pcur); mtr_commit(&mtr); }
/*******************************************************************//** Builds an update vector based on a remaining part of an undo log record. @return remaining part of the record, NULL if an error detected, which means that the record is corrupted */ UNIV_INTERN byte* trx_undo_update_rec_get_update( /*===========================*/ byte* ptr, /*!< in: remaining part in update undo log record, after reading the row reference NOTE that this copy of the undo log record must be preserved as long as the update vector is used, as we do NOT copy the data in the record! */ dict_index_t* index, /*!< in: clustered index */ ulint type, /*!< in: TRX_UNDO_UPD_EXIST_REC, TRX_UNDO_UPD_DEL_REC, or TRX_UNDO_DEL_MARK_REC; in the last case, only trx id and roll ptr fields are added to the update vector */ trx_id_t trx_id, /*!< in: transaction id from this undo record */ roll_ptr_t roll_ptr,/*!< in: roll pointer from this undo record */ ulint info_bits,/*!< in: info bits from this undo record */ trx_t* trx, /*!< in: transaction */ mem_heap_t* heap, /*!< in: memory heap from which the memory needed is allocated */ upd_t** upd) /*!< out, own: update vector */ { upd_field_t* upd_field; upd_t* update; ulint n_fields; byte* buf; ulint i; ut_a(dict_index_is_clust(index)); if (type != TRX_UNDO_DEL_MARK_REC) { ptr = trx_undo_update_rec_get_n_upd_fields(ptr, &n_fields); } else { n_fields = 0; } update = upd_create(n_fields + 2, heap); update->info_bits = info_bits; /* Store first trx id and roll ptr to update vector */ upd_field = upd_get_nth_field(update, n_fields); buf = mem_heap_alloc(heap, DATA_TRX_ID_LEN); trx_write_trx_id(buf, trx_id); upd_field_set_field_no(upd_field, dict_index_get_sys_col_pos(index, DATA_TRX_ID), index, trx); dfield_set_data(&(upd_field->new_val), buf, DATA_TRX_ID_LEN); upd_field = upd_get_nth_field(update, n_fields + 1); buf = mem_heap_alloc(heap, DATA_ROLL_PTR_LEN); trx_write_roll_ptr(buf, roll_ptr); upd_field_set_field_no( upd_field, dict_index_get_sys_col_pos(index, DATA_ROLL_PTR), index, trx); dfield_set_data(&(upd_field->new_val), buf, DATA_ROLL_PTR_LEN); /* Store then the updated ordinary columns to the update vector */ for (i = 0; i < n_fields; i++) { byte* field; ulint len; ulint field_no; ulint orig_len; ptr = trx_undo_update_rec_get_field_no(ptr, &field_no); if (field_no >= dict_index_get_n_fields(index)) { fprintf(stderr, "InnoDB: Error: trying to access" " update undo rec field %lu in ", (ulong) field_no); dict_index_name_print(stderr, trx, index); fprintf(stderr, "\n" "InnoDB: but index has only %lu fields\n" "InnoDB: Submit a detailed bug report" " to http://bugs.mysql.com\n" "InnoDB: Run also CHECK TABLE ", (ulong) dict_index_get_n_fields(index)); ut_print_name(stderr, trx, TRUE, index->table_name); fprintf(stderr, "\n" "InnoDB: n_fields = %lu, i = %lu, ptr %p\n", (ulong) n_fields, (ulong) i, ptr); *upd = NULL; return(NULL); } upd_field = upd_get_nth_field(update, i); upd_field_set_field_no(upd_field, field_no, index, trx); ptr = trx_undo_rec_get_col_val(ptr, &field, &len, &orig_len); upd_field->orig_len = orig_len; if (len == UNIV_SQL_NULL) { dfield_set_null(&upd_field->new_val); } else if (len < UNIV_EXTERN_STORAGE_FIELD) { dfield_set_data(&upd_field->new_val, field, len); } else { len -= UNIV_EXTERN_STORAGE_FIELD; dfield_set_data(&upd_field->new_val, field, len); dfield_set_ext(&upd_field->new_val); } } *upd = update; return(ptr); }
/*****************************************************************//** When an insert or purge to a table is performed, this function builds the entry to be inserted into or purged from an index on the table. @return index entry which should be inserted or purged, or NULL if the externally stored columns in the clustered index record are unavailable and ext != NULL */ UNIV_INTERN dtuple_t* row_build_index_entry( /*==================*/ const dtuple_t* row, /*!< in: row which should be inserted or purged */ row_ext_t* ext, /*!< in: externally stored column prefixes, or NULL */ dict_index_t* index, /*!< in: index on the table */ mem_heap_t* heap) /*!< in: memory heap from which the memory for the index entry is allocated */ { dtuple_t* entry; ulint entry_len; ulint i; ut_ad(row && index && heap); ut_ad(dtuple_check_typed(row)); entry_len = dict_index_get_n_fields(index); entry = dtuple_create(heap, entry_len); if (UNIV_UNLIKELY(index->type & DICT_UNIVERSAL)) { dtuple_set_n_fields_cmp(entry, entry_len); /* There may only be externally stored columns in a clustered index B-tree of a user table. */ ut_a(!ext); } else { dtuple_set_n_fields_cmp( entry, dict_index_get_n_unique_in_tree(index)); } for (i = 0; i < entry_len; i++) { const dict_field_t* ind_field = dict_index_get_nth_field(index, i); const dict_col_t* col = ind_field->col; ulint col_no = dict_col_get_no(col); dfield_t* dfield = dtuple_get_nth_field(entry, i); const dfield_t* dfield2 = dtuple_get_nth_field(row, col_no); ulint len = dfield_get_len(dfield2); dfield_copy(dfield, dfield2); if (dfield_is_null(dfield)) { continue; } if (ind_field->prefix_len == 0 && (!dfield_is_ext(dfield) || dict_index_is_clust(index))) { /* The dfield_copy() above suffices for columns that are stored in-page, or for clustered index record columns that are not part of a column prefix in the PRIMARY KEY. */ continue; } /* If the column is stored externally (off-page) in the clustered index, it must be an ordering field in the secondary index. In the Antelope format, only prefix-indexed columns may be stored off-page in the clustered index record. In the Barracuda format, also fully indexed long CHAR or VARCHAR columns may be stored off-page. */ ut_ad(col->ord_part); if (UNIV_LIKELY_NULL(ext)) { /* See if the column is stored externally. */ const byte* buf = row_ext_lookup(ext, col_no, &len); if (UNIV_LIKELY_NULL(buf)) { if (UNIV_UNLIKELY(buf == field_ref_zero)) { return(NULL); } dfield_set_data(dfield, buf, len); } if (ind_field->prefix_len == 0) { /* In the Barracuda format (ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED), we can have a secondary index on an entire column that is stored off-page in the clustered index. As this is not a prefix index (prefix_len == 0), include the entire off-page column in the secondary index record. */ continue; } } else if (dfield_is_ext(dfield)) { /* This table is either in Antelope format (ROW_FORMAT=REDUNDANT or ROW_FORMAT=COMPACT) or a purge record where the ordered part of the field is not external. In Antelope, the maximum column prefix index length is 767 bytes, and the clustered index record contains a 768-byte prefix of each off-page column. */ ut_a(len >= BTR_EXTERN_FIELD_REF_SIZE); len -= BTR_EXTERN_FIELD_REF_SIZE; dfield_set_len(dfield, len); } /* If a column prefix index, take only the prefix. */ if (ind_field->prefix_len) { len = dtype_get_at_most_n_mbchars( col->prtype, col->mbminlen, col->mbmaxlen, ind_field->prefix_len, len, dfield_get_data(dfield)); dfield_set_len(dfield, len); } } ut_ad(dtuple_check_typed(entry)); return(entry); }
/********************************************************************* Based on an index object, this function builds the entry to be inserted in the SYS_INDEXES system table. */ static dtuple_t* dict_create_sys_indexes_tuple( /*==========================*/ /* out: the tuple which should be inserted */ dict_index_t* index, /* in: index */ mem_heap_t* heap) /* in: memory heap from which the memory for the built tuple is allocated */ { dict_table_t* sys_indexes; dict_table_t* table; dtuple_t* entry; dfield_t* dfield; byte* ptr; ut_ad(mutex_own(&(dict_sys->mutex))); ut_ad(index && heap); sys_indexes = dict_sys->sys_indexes; table = dict_table_get_low(index->table_name); entry = dtuple_create(heap, 7 + DATA_N_SYS_COLS); /* 0: TABLE_ID -----------------------*/ dfield = dtuple_get_nth_field(entry, 0); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, table->id); dfield_set_data(dfield, ptr, 8); /* 1: ID ----------------------------*/ dfield = dtuple_get_nth_field(entry, 1); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, index->id); dfield_set_data(dfield, ptr, 8); /* 4: NAME --------------------------*/ dfield = dtuple_get_nth_field(entry, 2); dfield_set_data(dfield, index->name, ut_strlen(index->name)); /* 5: N_FIELDS ----------------------*/ dfield = dtuple_get_nth_field(entry, 3); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, index->n_fields); dfield_set_data(dfield, ptr, 4); /* 6: TYPE --------------------------*/ dfield = dtuple_get_nth_field(entry, 4); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, index->type); dfield_set_data(dfield, ptr, 4); /* 7: SPACE --------------------------*/ #if DICT_SYS_INDEXES_SPACE_NO_FIELD != 7 #error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 7" #endif dfield = dtuple_get_nth_field(entry, 5); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, index->space); dfield_set_data(dfield, ptr, 4); /* 8: PAGE_NO --------------------------*/ #if DICT_SYS_INDEXES_PAGE_NO_FIELD != 8 #error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 8" #endif dfield = dtuple_get_nth_field(entry, 6); ptr = mem_heap_alloc(heap, 4); mach_write_to_4(ptr, FIL_NULL); dfield_set_data(dfield, ptr, 4); /*--------------------------------*/ dict_table_copy_types(entry, sys_indexes); return(entry); }
/*******************************************************************//** Builds from a secondary index record a row reference with which we can search the clustered index record. */ UNIV_INTERN void row_build_row_ref_in_tuple( /*=======================*/ dtuple_t* ref, /*!< in/out: row reference built; see the NOTE below! */ const rec_t* rec, /*!< in: record in the index; NOTE: the data fields in ref will point directly into this record, therefore, the buffer page of this record must be at least s-latched and the latch held as long as the row reference is used! */ const dict_index_t* index, /*!< in: secondary index */ ulint* offsets,/*!< in: rec_get_offsets(rec, index) or NULL */ trx_t* trx) /*!< in: transaction */ { const dict_index_t* clust_index; dfield_t* dfield; const byte* field; ulint len; ulint ref_len; ulint pos; ulint clust_col_prefix_len; ulint i; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; rec_offs_init(offsets_); ut_a(ref); ut_a(index); ut_a(rec); ut_ad(!dict_index_is_clust(index)); if (UNIV_UNLIKELY(!index->table)) { fputs("InnoDB: table ", stderr); notfound: ut_print_name(stderr, trx, TRUE, index->table_name); fputs(" for index ", stderr); ut_print_name(stderr, trx, FALSE, index->name); fputs(" not found\n", stderr); ut_error; } clust_index = dict_table_get_first_index(index->table); if (UNIV_UNLIKELY(!clust_index)) { fputs("InnoDB: clust index for table ", stderr); goto notfound; } if (!offsets) { offsets = rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap); } else { ut_ad(rec_offs_validate(rec, index, offsets)); } /* Secondary indexes must not contain externally stored columns. */ ut_ad(!rec_offs_any_extern(offsets)); ref_len = dict_index_get_n_unique(clust_index); ut_ad(ref_len == dtuple_get_n_fields(ref)); dict_index_copy_types(ref, clust_index, ref_len); for (i = 0; i < ref_len; i++) { dfield = dtuple_get_nth_field(ref, i); pos = dict_index_get_nth_field_pos(index, clust_index, i); ut_a(pos != ULINT_UNDEFINED); field = rec_get_nth_field(rec, offsets, pos, &len); dfield_set_data(dfield, field, len); /* If the primary key contains a column prefix, then the secondary index may contain a longer prefix of the same column, or the full column, and we must adjust the length accordingly. */ clust_col_prefix_len = dict_index_get_nth_field( clust_index, i)->prefix_len; if (clust_col_prefix_len > 0) { if (len != UNIV_SQL_NULL) { const dtype_t* dtype = dfield_get_type(dfield); dfield_set_len(dfield, dtype_get_at_most_n_mbchars( dtype->prtype, dtype->mbminlen, dtype->mbmaxlen, clust_col_prefix_len, len, (char*) field)); } } } ut_ad(dtuple_check_typed(ref)); if (UNIV_LIKELY_NULL(heap)) { mem_heap_free(heap); } }
/********************************************************************* Based on an index object, this function builds the entry to be inserted in the SYS_FIELDS system table. */ static dtuple_t* dict_create_sys_fields_tuple( /*=========================*/ /* out: the tuple which should be inserted */ dict_index_t* index, /* in: index */ ulint i, /* in: field number */ mem_heap_t* heap) /* in: memory heap from which the memory for the built tuple is allocated */ { dict_table_t* sys_fields; dtuple_t* entry; dict_field_t* field; dfield_t* dfield; byte* ptr; ibool index_contains_column_prefix_field = FALSE; ulint j; ut_ad(index && heap); for (j = 0; j < index->n_fields; j++) { if (dict_index_get_nth_field(index, j)->prefix_len > 0) { index_contains_column_prefix_field = TRUE; } } field = dict_index_get_nth_field(index, i); sys_fields = dict_sys->sys_fields; entry = dtuple_create(heap, 3 + DATA_N_SYS_COLS); /* 0: INDEX_ID -----------------------*/ dfield = dtuple_get_nth_field(entry, 0); ptr = mem_heap_alloc(heap, 8); mach_write_to_8(ptr, index->id); dfield_set_data(dfield, ptr, 8); /* 1: POS + PREFIX LENGTH ----------------------------*/ dfield = dtuple_get_nth_field(entry, 1); ptr = mem_heap_alloc(heap, 4); if (index_contains_column_prefix_field) { /* If there are column prefix fields in the index, then we store the number of the field to the 2 HIGH bytes and the prefix length to the 2 low bytes, */ mach_write_to_4(ptr, (i << 16) + field->prefix_len); } else { /* Else we store the number of the field to the 2 LOW bytes. This is to keep the storage format compatible with InnoDB versions < 4.0.14. */ mach_write_to_4(ptr, i); } dfield_set_data(dfield, ptr, 4); /* 4: COL_NAME -------------------------*/ dfield = dtuple_get_nth_field(entry, 2); dfield_set_data(dfield, field->name, ut_strlen(field->name)); /*---------------------------------*/ dict_table_copy_types(entry, sys_fields); return(entry); }
/*******************************************************************//** Builds from a secondary index record a row reference with which we can search the clustered index record. @return own: row reference built; see the NOTE below! */ UNIV_INTERN dtuple_t* row_build_row_ref( /*==============*/ ulint type, /*!< in: ROW_COPY_DATA, or ROW_COPY_POINTERS: the former copies also the data fields to heap, whereas the latter only places pointers to data fields on the index page */ dict_index_t* index, /*!< in: secondary index */ const rec_t* rec, /*!< in: record in the index; NOTE: in the case ROW_COPY_POINTERS the data fields in the row will point directly into this record, therefore, the buffer page of this record must be at least s-latched and the latch held as long as the row reference is used! */ mem_heap_t* heap) /*!< in: memory heap from which the memory needed is allocated */ { dict_table_t* table; dict_index_t* clust_index; dfield_t* dfield; dtuple_t* ref; const byte* field; ulint len; ulint ref_len; ulint pos; byte* buf; ulint clust_col_prefix_len; ulint i; mem_heap_t* tmp_heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; ulint* offsets = offsets_; rec_offs_init(offsets_); ut_ad(index && rec && heap); ut_ad(!dict_index_is_clust(index)); offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, &tmp_heap); /* Secondary indexes must not contain externally stored columns. */ ut_ad(!rec_offs_any_extern(offsets)); if (type == ROW_COPY_DATA) { /* Take a copy of rec to heap */ buf = mem_heap_alloc(heap, rec_offs_size(offsets)); rec = rec_copy(buf, rec, offsets); /* Avoid a debug assertion in rec_offs_validate(). */ rec_offs_make_valid(rec, index, offsets); } table = index->table; clust_index = dict_table_get_first_index(table); ref_len = dict_index_get_n_unique(clust_index); ref = dtuple_create(heap, ref_len); dict_index_copy_types(ref, clust_index, ref_len); for (i = 0; i < ref_len; i++) { dfield = dtuple_get_nth_field(ref, i); pos = dict_index_get_nth_field_pos(index, clust_index, i); ut_a(pos != ULINT_UNDEFINED); field = rec_get_nth_field(rec, offsets, pos, &len); dfield_set_data(dfield, field, len); /* If the primary key contains a column prefix, then the secondary index may contain a longer prefix of the same column, or the full column, and we must adjust the length accordingly. */ clust_col_prefix_len = dict_index_get_nth_field( clust_index, i)->prefix_len; if (clust_col_prefix_len > 0) { if (len != UNIV_SQL_NULL) { const dtype_t* dtype = dfield_get_type(dfield); dfield_set_len(dfield, dtype_get_at_most_n_mbchars( dtype->prtype, dtype->mbminlen, dtype->mbmaxlen, clust_col_prefix_len, len, (char*) field)); } } } ut_ad(dtuple_check_typed(ref)); if (tmp_heap) { mem_heap_free(tmp_heap); } return(ref); }