From 21347433cff264b04c61c4aa5392516e9a4c9354 Mon Sep 17 00:00:00 2001 From: "mronstrom@mysql.com" <> Date: Thu, 28 Apr 2005 14:45:27 +0200 Subject: [PATCH 1/7] WL 1682: Use bitvector instead of query_id to tell handler which fields to read and write Changed Server code, added new interface to handler and changed the NDB handler, InnoDB handler and Federated handler that previously used query_id Bug#10202 fix (one-liner fix for memory leak) --- mysys/my_bitmap.c | 8 +++ sql/field.cc | 1 + sql/field.h | 1 + sql/ha_federated.cc | 42 ++---------- sql/ha_innodb.cc | 3 +- sql/ha_ndbcluster.cc | 151 +++++++++---------------------------------- sql/ha_ndbcluster.h | 5 +- sql/handler.cc | 95 ++++++++++++++++++++++----- sql/handler.h | 82 ++++++++++++++++++++++- sql/item.cc | 17 +++-- sql/lock.cc | 2 +- sql/mysql_priv.h | 2 +- sql/opt_range.cc | 3 + sql/sql_acl.cc | 8 +++ sql/sql_base.cc | 8 ++- sql/sql_class.h | 9 ++- sql/sql_insert.cc | 19 +++++- sql/sql_load.cc | 12 +++- sql/sql_select.cc | 13 +++- sql/sql_table.cc | 5 +- sql/sql_udf.cc | 1 + sql/sql_update.cc | 7 +- sql/table.cc | 3 + sql/unireg.cc | 1 + 24 files changed, 299 insertions(+), 199 deletions(-) diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index c0eb6f15548..2f8faea68a8 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -102,6 +102,14 @@ void bitmap_free(MY_BITMAP *map) void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit) { + if (map->bitmap) + { + DBUG_PRINT("info", ("Bitmap not defined")); + } + if (bitmap_bit >= map->bitmap_size*8) + { + DBUG_PRINT("info", ("bit %d size in bytes %d", bitmap_bit, map->bitmap_size)); + } DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); bitmap_lock(map); bitmap_fast_set_bit(map, bitmap_bit); diff --git a/sql/field.cc b/sql/field.cc index 00f729d5b07..de28a98a86d 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -1198,6 +1198,7 @@ Field::Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg, flags=null_ptr ? 0: NOT_NULL_FLAG; comment.str= (char*) ""; comment.length=0; + fieldnr= 0; } uint Field::offset() diff --git a/sql/field.h b/sql/field.h index 22787850442..f7ed6592a6d 100644 --- a/sql/field.h +++ b/sql/field.h @@ -86,6 +86,7 @@ public: utype unireg_check; uint32 field_length; // Length of field uint16 flags; + uint16 fieldnr; // Field number uchar null_bit; // Bit used to test null bit Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uchar null_bit_arg, diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 33acc9cad0b..1854801f6a2 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1076,11 +1076,8 @@ inline uint field_in_record_is_null(TABLE *table, int ha_federated::write_row(byte *buf) { - uint x= 0, num_fields= 0; + uint x, num_fields; Field **field; - ulong current_query_id= 1; - ulong tmp_query_id= 1; - uint all_fields_have_same_query_id= 1; char insert_buffer[IO_SIZE]; char values_buffer[IO_SIZE], insert_field_value_buffer[IO_SIZE]; @@ -1105,14 +1102,6 @@ int ha_federated::write_row(byte *buf) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) table->timestamp_field->set_time(); - /* - get the current query id - the fields that we add to the insert - statement to send to the foreign will not be appended unless they match - this query id - */ - current_query_id= table->in_use->query_id; - DBUG_PRINT("info", ("current query id %d", current_query_id)); - /* start off our string */ insert_string.append("INSERT INTO `"); insert_string.append(share->table_base_name); @@ -1120,44 +1109,25 @@ int ha_federated::write_row(byte *buf) /* start both our field and field values strings */ insert_string.append(" ("); values_string.append(" VALUES ("); - - /* - Even if one field is different, all_fields_same_query_id can't remain - 0 if it remains 0, then that means no fields were specified in the query - such as in the case of INSERT INTO table VALUES (val1, val2, valN) - */ - for (field= table->field; *field; field++, x++) - { - if (x > 0 && tmp_query_id != (*field)->query_id) - all_fields_have_same_query_id= 0; - - tmp_query_id= (*field)->query_id; - } /* loop through the field pointer array, add any fields to both the values - list and the fields list that match the current query id + list and the fields list that is part of the write set */ - x=0; - for (field= table->field; *field; field++, x++) + for (x=0, num_fields= 0, field= table->field; *field; field++, x++) { /* if there is a query id and if it's equal to the current query id */ - if (((*field)->query_id && (*field)->query_id == current_query_id) - || all_fields_have_same_query_id) + if (ha_get_bit_in_write_set((*field)->fieldnr)) { num_fields++; if ((*field)->is_null()) { - DBUG_PRINT("info", - ("column %d current query id %d field is_null query id %d", - x, current_query_id, (*field)->query_id)); + DBUG_PRINT("info", ("column %d field is_null", x)); insert_field_value_string.append("NULL"); } else { - DBUG_PRINT("info", - ("column %d current query id %d field is not null query ID %d", - x, current_query_id, (*field)->query_id)); + DBUG_PRINT("info", ("column %d field is not null", x)); (*field)->val_str(&insert_field_value_string); /* quote these fields if they require it */ (*field)->quote_data(&insert_field_value_string); } diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 3f592e36219..e15e201bb32 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2684,7 +2684,8 @@ build_template( (!(fetch_all_in_key && index_contains_field) && !(fetch_primary_key_cols && dict_table_col_in_clustered_key(index->table, i)) && - thd->query_id != field->query_id))) { + !(ha_get_bit_in_read_set(i+1) || + ha_get_bit_in_write_set(i+1))))) { /* This field is not needed in the query, skip it */ diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index e2d954b1928..705fbf957b7 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -833,12 +833,10 @@ int ha_ndbcluster::get_ndb_value(NdbOperation *ndb_op, Field *field, /* Check if any set or get of blob value in current query. */ -bool ha_ndbcluster::uses_blob_value(bool all_fields) +bool ha_ndbcluster::uses_blob_value() { if (table->s->blob_fields == 0) return FALSE; - if (all_fields) - return TRUE; { uint no_fields= table->s->fields; int i; @@ -847,7 +845,8 @@ bool ha_ndbcluster::uses_blob_value(bool all_fields) for (i= no_fields - 1; i >= 0; i--) { Field *field= table->field[i]; - if (thd->query_id == field->query_id) + if ((m_write_op && ha_get_bit_in_write_set(i+1)) || + (!m_write_op && ha_get_bit_in_read_set(i+1))) { return TRUE; } @@ -1116,7 +1115,7 @@ int ha_ndbcluster::get_ndb_lock_type(enum thr_lock_type type) { if (type >= TL_WRITE_ALLOW_WRITE) return NdbOperation::LM_Exclusive; - else if (uses_blob_value(m_retrieve_all_fields)) + else if (uses_blob_value()) return NdbOperation::LM_Read; else return NdbOperation::LM_CommittedRead; @@ -1294,9 +1293,8 @@ int ha_ndbcluster::define_read_attrs(byte* buf, NdbOperation* op) for (i= 0; i < table->s->fields; i++) { Field *field= table->field[i]; - if ((thd->query_id == field->query_id) || - ((field->flags & PRI_KEY_FLAG)) || - m_retrieve_all_fields) + if (ha_get_bit_in_read_set(i+1) || + ((field->flags & PRI_KEY_FLAG))) { if (get_ndb_value(op, field, i, buf)) ERR_RETURN(op->getNdbError()); @@ -1337,6 +1335,7 @@ int ha_ndbcluster::pk_read(const byte *key, uint key_len, byte *buf) DBUG_ENTER("pk_read"); DBUG_PRINT("enter", ("key_len: %u", key_len)); DBUG_DUMP("key", (char*)key, key_len); + m_write_op= FALSE; NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -1388,10 +1387,13 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data) NdbOperation *op; THD *thd= current_thd; DBUG_ENTER("complemented_pk_read"); + m_write_op= FALSE; - if (m_retrieve_all_fields) + if (ha_get_all_bit_in_read_set()) + { // We have allready retrieved all fields, nothing to complement DBUG_RETURN(0); + } NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -1408,7 +1410,7 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data) { Field *field= table->field[i]; if (!((field->flags & PRI_KEY_FLAG) || - (thd->query_id == field->query_id))) + (ha_get_bit_in_read_set(i+1)))) { if (get_ndb_value(op, field, i, new_data)) ERR_RETURN(trans->getNdbError()); @@ -1432,7 +1434,7 @@ int ha_ndbcluster::complemented_pk_read(const byte *old_data, byte *new_data) { Field *field= table->field[i]; if (!((field->flags & PRI_KEY_FLAG) || - (thd->query_id == field->query_id))) + (ha_get_bit_in_read_set(i+1)))) { m_value[i].ptr= NULL; } @@ -1810,6 +1812,7 @@ int ha_ndbcluster::ordered_index_scan(const key_range *start_key, DBUG_PRINT("enter", ("index: %u, sorted: %d, descending: %d", active_index, sorted, descending)); DBUG_PRINT("enter", ("Starting new ordered scan on %s", m_tabname)); + m_write_op= FALSE; // Check that sorted seems to be initialised DBUG_ASSERT(sorted == 0 || sorted == 1); @@ -1869,6 +1872,7 @@ int ha_ndbcluster::full_table_scan(byte *buf) DBUG_ENTER("full_table_scan"); DBUG_PRINT("enter", ("Starting new scan on %s", m_tabname)); + m_write_op= FALSE; NdbOperation::LockMode lm= (NdbOperation::LockMode)get_ndb_lock_type(m_lock.type); @@ -1898,6 +1902,7 @@ int ha_ndbcluster::write_row(byte *record) NdbOperation *op; int res; THD *thd= current_thd; + m_write_op= TRUE; DBUG_ENTER("write_row"); @@ -1916,7 +1921,10 @@ int ha_ndbcluster::write_row(byte *record) statistic_increment(thd->status_var.ha_write_count, &LOCK_status); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) + { table->timestamp_field->set_time(); + ha_set_bit_in_write_set(table->timestamp_field->fieldnr); + } has_auto_increment= (table->next_number_field && record == table->record[0]); if (!(op= trans->getNdbOperation((const NDBTAB *) m_table))) @@ -1969,6 +1977,7 @@ int ha_ndbcluster::write_row(byte *record) { Field *field= table->field[i]; if (!(field->flags & PRI_KEY_FLAG) && + (ha_get_bit_in_write_set(i+1)) && set_ndb_value(op, field, i, &set_blob_value)) { m_skip_auto_increment= TRUE; @@ -2086,13 +2095,13 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) NdbOperation *op; uint i; DBUG_ENTER("update_row"); + m_write_op= TRUE; statistic_increment(thd->status_var.ha_update_count, &LOCK_status); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) { table->timestamp_field->set_time(); - // Set query_id so that field is really updated - table->timestamp_field->query_id= thd->query_id; + ha_set_bit_in_write_set(table->timestamp_field->fieldnr); } /* Check for update of primary key for special handling */ @@ -2152,7 +2161,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) if (!(op= cursor->updateCurrentTuple())) ERR_RETURN(trans->getNdbError()); m_ops_pending++; - if (uses_blob_value(FALSE)) + if (uses_blob_value()) m_blobs_pending= TRUE; } else @@ -2190,7 +2199,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data) for (i= 0; i < table->s->fields; i++) { Field *field= table->field[i]; - if (((thd->query_id == field->query_id) || m_retrieve_all_fields) && + if (ha_get_bit_in_write_set(i+1) && (!(field->flags & PRI_KEY_FLAG)) && set_ndb_value(op, field, i)) ERR_RETURN(op->getNdbError()); @@ -2217,6 +2226,7 @@ int ha_ndbcluster::delete_row(const byte *record) NdbScanOperation* cursor= m_active_cursor; NdbOperation *op; DBUG_ENTER("delete_row"); + m_write_op= TRUE; statistic_increment(thd->status_var.ha_delete_count,&LOCK_status); m_rows_changed++; @@ -2481,6 +2491,7 @@ int ha_ndbcluster::index_read(byte *buf, int error; ndb_index_type type= get_index_type(active_index); const KEY* key_info= table->key_info+active_index; + m_write_op= FALSE; switch (type){ case PRIMARY_KEY_ORDERED_INDEX: case PRIMARY_KEY_INDEX: @@ -2647,6 +2658,7 @@ int ha_ndbcluster::read_range_first(const key_range *start_key, { byte* buf= table->record[0]; DBUG_ENTER("ha_ndbcluster::read_range_first"); + m_write_op= FALSE; DBUG_RETURN(read_range_first_to_buf(start_key, end_key, @@ -2868,83 +2880,11 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) { DBUG_ENTER("extra"); switch (operation) { - case HA_EXTRA_NORMAL: /* Optimize for space (def) */ - DBUG_PRINT("info", ("HA_EXTRA_NORMAL")); - break; - case HA_EXTRA_QUICK: /* Optimize for speed */ - DBUG_PRINT("info", ("HA_EXTRA_QUICK")); - break; case HA_EXTRA_RESET: /* Reset database to after open */ DBUG_PRINT("info", ("HA_EXTRA_RESET")); DBUG_PRINT("info", ("Clearing condition stack")); cond_clear(); break; - case HA_EXTRA_CACHE: /* Cash record in HA_rrnd() */ - DBUG_PRINT("info", ("HA_EXTRA_CACHE")); - break; - case HA_EXTRA_NO_CACHE: /* End cacheing of records (def) */ - DBUG_PRINT("info", ("HA_EXTRA_NO_CACHE")); - break; - case HA_EXTRA_NO_READCHECK: /* No readcheck on update */ - DBUG_PRINT("info", ("HA_EXTRA_NO_READCHECK")); - break; - case HA_EXTRA_READCHECK: /* Use readcheck (def) */ - DBUG_PRINT("info", ("HA_EXTRA_READCHECK")); - break; - case HA_EXTRA_KEYREAD: /* Read only key to database */ - DBUG_PRINT("info", ("HA_EXTRA_KEYREAD")); - break; - case HA_EXTRA_NO_KEYREAD: /* Normal read of records (def) */ - DBUG_PRINT("info", ("HA_EXTRA_NO_KEYREAD")); - break; - case HA_EXTRA_NO_USER_CHANGE: /* No user is allowed to write */ - DBUG_PRINT("info", ("HA_EXTRA_NO_USER_CHANGE")); - break; - case HA_EXTRA_KEY_CACHE: - DBUG_PRINT("info", ("HA_EXTRA_KEY_CACHE")); - break; - case HA_EXTRA_NO_KEY_CACHE: - DBUG_PRINT("info", ("HA_EXTRA_NO_KEY_CACHE")); - break; - case HA_EXTRA_WAIT_LOCK: /* Wait until file is avalably (def) */ - DBUG_PRINT("info", ("HA_EXTRA_WAIT_LOCK")); - break; - case HA_EXTRA_NO_WAIT_LOCK: /* If file is locked, return quickly */ - DBUG_PRINT("info", ("HA_EXTRA_NO_WAIT_LOCK")); - break; - case HA_EXTRA_WRITE_CACHE: /* Use write cache in ha_write() */ - DBUG_PRINT("info", ("HA_EXTRA_WRITE_CACHE")); - break; - case HA_EXTRA_FLUSH_CACHE: /* flush write_record_cache */ - DBUG_PRINT("info", ("HA_EXTRA_FLUSH_CACHE")); - break; - case HA_EXTRA_NO_KEYS: /* Remove all update of keys */ - DBUG_PRINT("info", ("HA_EXTRA_NO_KEYS")); - break; - case HA_EXTRA_KEYREAD_CHANGE_POS: /* Keyread, but change pos */ - DBUG_PRINT("info", ("HA_EXTRA_KEYREAD_CHANGE_POS")); /* xxxxchk -r must be used */ - break; - case HA_EXTRA_REMEMBER_POS: /* Remember pos for next/prev */ - DBUG_PRINT("info", ("HA_EXTRA_REMEMBER_POS")); - break; - case HA_EXTRA_RESTORE_POS: - DBUG_PRINT("info", ("HA_EXTRA_RESTORE_POS")); - break; - case HA_EXTRA_REINIT_CACHE: /* init cache from current record */ - DBUG_PRINT("info", ("HA_EXTRA_REINIT_CACHE")); - break; - case HA_EXTRA_FORCE_REOPEN: /* Datafile have changed on disk */ - DBUG_PRINT("info", ("HA_EXTRA_FORCE_REOPEN")); - break; - case HA_EXTRA_FLUSH: /* Flush tables to disk */ - DBUG_PRINT("info", ("HA_EXTRA_FLUSH")); - break; - case HA_EXTRA_NO_ROWS: /* Don't write rows */ - DBUG_PRINT("info", ("HA_EXTRA_NO_ROWS")); - break; - case HA_EXTRA_RESET_STATE: /* Reset positions */ - DBUG_PRINT("info", ("HA_EXTRA_RESET_STATE")); - break; case HA_EXTRA_IGNORE_DUP_KEY: /* Dup keys don't rollback everything*/ DBUG_PRINT("info", ("HA_EXTRA_IGNORE_DUP_KEY")); if (current_thd->lex->sql_command == SQLCOM_REPLACE) @@ -2963,34 +2903,6 @@ int ha_ndbcluster::extra(enum ha_extra_function operation) m_use_write= FALSE; m_ignore_dup_key= FALSE; break; - case HA_EXTRA_RETRIEVE_ALL_COLS: /* Retrieve all columns, not just those - where field->query_id is the same as - the current query id */ - DBUG_PRINT("info", ("HA_EXTRA_RETRIEVE_ALL_COLS")); - m_retrieve_all_fields= TRUE; - break; - case HA_EXTRA_PREPARE_FOR_DELETE: - DBUG_PRINT("info", ("HA_EXTRA_PREPARE_FOR_DELETE")); - break; - case HA_EXTRA_PREPARE_FOR_UPDATE: /* Remove read cache if problems */ - DBUG_PRINT("info", ("HA_EXTRA_PREPARE_FOR_UPDATE")); - break; - case HA_EXTRA_PRELOAD_BUFFER_SIZE: - DBUG_PRINT("info", ("HA_EXTRA_PRELOAD_BUFFER_SIZE")); - break; - case HA_EXTRA_RETRIEVE_PRIMARY_KEY: - DBUG_PRINT("info", ("HA_EXTRA_RETRIEVE_PRIMARY_KEY")); - m_retrieve_primary_key= TRUE; - break; - case HA_EXTRA_CHANGE_KEY_TO_UNIQUE: - DBUG_PRINT("info", ("HA_EXTRA_CHANGE_KEY_TO_UNIQUE")); - break; - case HA_EXTRA_CHANGE_KEY_TO_DUP: - DBUG_PRINT("info", ("HA_EXTRA_CHANGE_KEY_TO_DUP")); - case HA_EXTRA_KEYREAD_PRESERVE_FIELDS: - DBUG_PRINT("info", ("HA_EXTRA_KEYREAD_PRESERVE_FIELDS")); - break; - } DBUG_RETURN(0); @@ -3255,8 +3167,6 @@ int ha_ndbcluster::external_lock(THD *thd, int lock_type) DBUG_ASSERT(m_active_trans); // Start of transaction m_rows_changed= 0; - m_retrieve_all_fields= FALSE; - m_retrieve_primary_key= FALSE; m_ops_pending= 0; { NDBDICT *dict= ndb->getDictionary(); @@ -3383,8 +3293,6 @@ int ha_ndbcluster::start_stmt(THD *thd) m_active_trans= trans; // Start of statement - m_retrieve_all_fields= FALSE; - m_retrieve_primary_key= FALSE; m_ops_pending= 0; DBUG_RETURN(error); @@ -4166,8 +4074,6 @@ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): m_use_write(FALSE), m_ignore_dup_key(FALSE), m_primary_key_update(FALSE), - m_retrieve_all_fields(FALSE), - m_retrieve_primary_key(FALSE), m_rows_to_insert((ha_rows) 1), m_rows_inserted((ha_rows) 0), m_bulk_insert_rows((ha_rows) 1024), @@ -5489,6 +5395,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, HANDLER_BUFFER *buffer) { DBUG_ENTER("ha_ndbcluster::read_multi_range_first"); + m_write_op= FALSE; int res; KEY* key_info= table->key_info + active_index; @@ -5496,7 +5403,7 @@ ha_ndbcluster::read_multi_range_first(KEY_MULTI_RANGE **found_range_p, ulong reclength= table->s->reclength; NdbOperation* op; - if (uses_blob_value(m_retrieve_all_fields)) + if (uses_blob_value()) { /** * blobs can't be batched currently diff --git a/sql/ha_ndbcluster.h b/sql/ha_ndbcluster.h index 4dbab18b828..abd75eedd08 100644 --- a/sql/ha_ndbcluster.h +++ b/sql/ha_ndbcluster.h @@ -560,7 +560,7 @@ private: ulonglong get_auto_increment(); void invalidateDictionaryCache(); int ndb_err(NdbTransaction*); - bool uses_blob_value(bool all_fields); + bool uses_blob_value(); char *update_table_comment(const char * comment); @@ -611,8 +611,7 @@ private: bool m_use_write; bool m_ignore_dup_key; bool m_primary_key_update; - bool m_retrieve_all_fields; - bool m_retrieve_primary_key; + bool m_write_op; ha_rows m_rows_to_insert; ha_rows m_rows_inserted; ha_rows m_bulk_insert_rows; diff --git a/sql/handler.cc b/sql/handler.cc index 542efaba2bf..5460dd6d48b 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -193,54 +193,67 @@ enum db_type ha_checktype(enum db_type database_type) handler *get_new_handler(TABLE *table, enum db_type db_type) { + handler *file; switch (db_type) { #ifndef NO_HASH case DB_TYPE_HASH: - return new ha_hash(table); + file= new ha_hash(table); #endif #ifdef HAVE_ISAM case DB_TYPE_MRG_ISAM: - return new ha_isammrg(table); + file= new ha_isammrg(table); + break; case DB_TYPE_ISAM: - return new ha_isam(table); + file= new ha_isam(table); + break; #else case DB_TYPE_MRG_ISAM: - return new ha_myisammrg(table); + file= new ha_myisammrg(table); + break; #endif #ifdef HAVE_BERKELEY_DB case DB_TYPE_BERKELEY_DB: - return new ha_berkeley(table); + file= new ha_berkeley(table); + break; #endif #ifdef HAVE_INNOBASE_DB case DB_TYPE_INNODB: - return new ha_innobase(table); + file= new ha_innobase(table); + break; #endif #ifdef HAVE_EXAMPLE_DB case DB_TYPE_EXAMPLE_DB: - return new ha_example(table); + file= new ha_example(table); + break; #endif #ifdef HAVE_ARCHIVE_DB case DB_TYPE_ARCHIVE_DB: - return new ha_archive(table); + file= new ha_archive(table); + break; #endif #ifdef HAVE_BLACKHOLE_DB case DB_TYPE_BLACKHOLE_DB: - return new ha_blackhole(table); + file= new ha_blackhole(table); + break; #endif #ifdef HAVE_FEDERATED_DB case DB_TYPE_FEDERATED_DB: - return new ha_federated(table); + file= new ha_federated(table); + break; #endif #ifdef HAVE_CSV_DB case DB_TYPE_CSV_DB: - return new ha_tina(table); + file= new ha_tina(table); + break; #endif #ifdef HAVE_NDBCLUSTER_DB case DB_TYPE_NDBCLUSTER: - return new ha_ndbcluster(table); + file= new ha_ndbcluster(table); + break; #endif case DB_TYPE_HEAP: - return new ha_heap(table); + file= new ha_heap(table); + break; default: // should never happen { enum db_type def=(enum db_type) current_thd->variables.table_type; @@ -250,10 +263,21 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) } /* Fall back to MyISAM */ case DB_TYPE_MYISAM: - return new ha_myisam(table); + file= new ha_myisam(table); + break; case DB_TYPE_MRG_MYISAM: - return new ha_myisammrg(table); + file= new ha_myisammrg(table); + break; } + if (file) + { + if (table && file->ha_allocate_read_write_set(table->s->fields)) + { + delete file; + file= 0; + } + } + return file; } /* @@ -1319,6 +1343,47 @@ int handler::ha_open(const char *name, int mode, int test_if_locked) DBUG_RETURN(error); } +int handler::ha_allocate_read_write_set(ulong no_fields) +{ + DBUG_ENTER("ha_allocate_read_write_set"); + uint map_size= ((no_fields + 8)/8)*8; + if (rw_set_allocated) + ha_deallocate_read_write_set(); + DBUG_PRINT("info", ("no_fields = %d, map_size = %d", no_fields, map_size)); + if (bitmap_init(&read_set, NULL, map_size, FALSE)) + { + DBUG_RETURN(TRUE); + } + if (bitmap_init(&write_set, NULL, map_size, FALSE)) + { + bitmap_free(&read_set); + DBUG_RETURN(TRUE); + } + ha_clear_all_set(); + rw_set_allocated= TRUE; + DBUG_RETURN(FALSE); +} + +void handler::ha_deallocate_read_write_set() +{ + if (!rw_set_allocated) + return; + bitmap_free(&read_set); + bitmap_free(&write_set); +} + +void handler::ha_set_primary_key_in_read_set() +{ + ulong prim_key= table->s->primary_key; + if (prim_key != MAX_KEY) + { + KEY_PART_INFO *key_part= table->key_info[prim_key].key_part; + KEY_PART_INFO *key_part_end= key_part + + table->key_info[prim_key].key_parts; + for (;key_part != key_part_end; ++key_part) + ha_set_bit_in_read_set(key_part->fieldnr); + } +} /* Read first row (only) from a table This is never called for InnoDB or BDB tables, as these table types diff --git a/sql/handler.h b/sql/handler.h index 4c06fe8299d..d64bc7e706e 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -483,6 +483,9 @@ public: bool auto_increment_column_changed; bool implicit_emptied; /* Can be !=0 only if HEAP */ const COND *pushed_cond; + MY_BITMAP read_set; + MY_BITMAP write_set; + bool rw_set_allocated; handler(TABLE *table_arg) :table(table_arg), ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0), @@ -492,9 +495,13 @@ public: key_used_on_scan(MAX_KEY), active_index(MAX_KEY), ref_length(sizeof(my_off_t)), block_size(0), raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0), - pushed_cond(NULL) + pushed_cond(NULL), rw_set_allocated(0) {} - virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ } + virtual ~handler(void) + { + ha_deallocate_read_write_set(); + /* TODO: DBUG_ASSERT(inited == NONE); */ + } int ha_open(const char *name, int mode, int test_if_locked); void update_auto_increment(); virtual void print_error(int error, myf errflag); @@ -559,6 +566,77 @@ public: { return inited == INDEX ? ha_index_end() : inited == RND ? ha_rnd_end() : 0; } + /* + These are a set of routines used to enable handlers to only read/write + partial lists of the fields in the table. The bit vector is maintained + by the server part and is used by the handler at calls to read/write + data in the table. + It replaces the use of query id's for this purpose. The benefit is that + the handler can also set bits in the read/write set if it has special + needs and it is also easy for other parts of the server to interact + with the handler (e.g. the replication part for row-level logging). + The routines are all part of the general handler and are not possible + to override by a handler. A handler can however set/reset bits by + calling these routines. + */ + void ha_set_all_bits_in_read_set() + { + bitmap_set_all(&read_set); + } + void ha_set_all_bits_in_write_set() + { + bitmap_set_all(&write_set); + } + void ha_set_bit_in_read_set(uint fieldnr) + { + bitmap_set_bit(&read_set, fieldnr); + } + void ha_clear_bit_in_read_set(uint fieldnr) + { + bitmap_clear_bit(&read_set, fieldnr); + } + void ha_set_bit_in_write_set(uint fieldnr) + { + bitmap_set_bit(&write_set, fieldnr); + } + void ha_clear_bit_in_write_set(uint fieldnr) + { + bitmap_clear_bit(&write_set, fieldnr); + } + void ha_set_bit_in_rw_set(uint fieldnr, bool write_set) + { + if (!write_set) + ha_set_bit_in_read_set(fieldnr); + else + ha_set_bit_in_write_set(fieldnr); + } + my_bool ha_get_bit_in_read_set(uint fieldnr) + { + return bitmap_is_set(&read_set, fieldnr); + } + my_bool ha_get_all_bit_in_read_set() + { + return bitmap_is_set_all(&read_set); + } + my_bool ha_get_all_bit_in_write_set() + { + return bitmap_is_set_all(&write_set); + } + my_bool ha_get_bit_in_write_set(uint fieldnr) + { + return bitmap_is_set(&write_set, fieldnr); + } + void ha_clear_all_set() + { + bitmap_clear_all(&read_set); + bitmap_clear_all(&write_set); + bitmap_set_bit(&read_set,0); + bitmap_set_bit(&write_set,0); + } + void ha_set_primary_key_in_read_set(); + int ha_allocate_read_write_set(ulong no_fields); + void ha_deallocate_read_write_set(); + uint get_index(void) const { return active_index; } virtual int open(const char *name, int mode, uint test_if_locked)=0; virtual int close(void)=0; diff --git a/sql/item.cc b/sql/item.cc index 541fbf7b178..dc2a43a911f 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -2825,13 +2825,18 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **reference) set_field(from_field); } - else if (thd->set_query_id && field->query_id != thd->query_id) + else if (thd->set_query_id) { - /* We only come here in unions */ - TABLE *table=field->table; - field->query_id=thd->query_id; - table->used_fields++; - table->used_keys.intersect(field->part_of_key); + TABLE *table= field->table; + table->file->ha_set_bit_in_rw_set(field->fieldnr, + (bool)(thd->set_query_id-1)); + if (field->query_id != thd->query_id) + { + /* We only come here in unions */ + field->query_id=thd->query_id; + table->used_fields++; + table->used_keys.intersect(field->part_of_key); + } } #ifndef NO_EMBEDDED_ACCESS_CHECKS if (any_privileges) diff --git a/sql/lock.cc b/sql/lock.cc index a8ccba32d4f..bb7d1f7163b 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -179,7 +179,7 @@ static int lock_external(THD *thd, TABLE **tables, uint count) ((*tables)->reginfo.lock_type >= TL_READ && (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT)) lock_type=F_RDLCK; - + (*tables)->file->ha_clear_all_set(); if ((error=(*tables)->file->external_lock(thd,lock_type))) { print_lock_error(error, (*tables)->file->table_type()); diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index ad9728dba84..04ebd9c99f6 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -881,7 +881,7 @@ bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds, int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, List *sum_func_list, uint wild_num); bool setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables, - List &item, bool set_query_id, + List &item, ulong set_query_id, List *sum_func_list, bool allow_sum_func); int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index ac25f15d460..0e89cd0026a 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -921,6 +921,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) { DBUG_RETURN(1); } + file->ha_set_primary_key_in_read_set(); DBUG_RETURN(0); } @@ -951,6 +952,7 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) file->close(); goto failure; } + file->ha_set_primary_key_in_read_set(); free_file= TRUE; last_rowid= file->ref; DBUG_RETURN(0); @@ -5627,6 +5629,7 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() */ if (head->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY)) DBUG_RETURN(1); + head->file->ha_set_primary_key_in_read_set(); cur_quick_it.rewind(); cur_quick= cur_quick_it++; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index e72d78a6ac8..9552e286b34 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1526,6 +1526,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user, key_copy((byte *) user_key, table->record[0], table->key_info, table->key_info->key_length); + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read_idx(table->record[0], 0, (byte *) user_key, table->key_info->key_length, @@ -1619,6 +1620,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read_idx(table->record[0], 0, user_key, table->key_info->key_length, @@ -1752,6 +1754,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, We should NEVER delete from the user table, as a uses can still use mysqld even if he doesn't have any privileges in the user table! */ + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (cmp_record(table,record[1]) && (error=table->file->update_row(table->record[1],table->record[0]))) @@ -1834,6 +1837,7 @@ static int replace_db_table(TABLE *table, const char *db, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read_idx(table->record[0],0, user_key, table->key_info->key_length, @@ -1870,6 +1874,7 @@ static int replace_db_table(TABLE *table, const char *db, /* update old existing row */ if (rights) { + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if ((error=table->file->update_row(table->record[1],table->record[0]))) goto table_error; /* purecov: deadcode */ @@ -2203,6 +2208,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read(table->record[0], user_key, table->key_info->key_length, @@ -2280,6 +2286,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_copy(user_key, table->record[0], table->key_info, key_prefix_length); + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read(table->record[0], user_key, key_prefix_length, @@ -2378,6 +2385,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (table->file->index_read_idx(table->record[0], 0, user_key, table->key_info->key_length, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d79811aa4e2..d885ab50371 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1954,6 +1954,7 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table, my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),table->alias); DBUG_RETURN(1); } + table->file->ha_clear_all_set(); if ((error=table->file->start_stmt(thd))) { table->file->print_error(error,MYF(0)); @@ -2588,6 +2589,8 @@ Field *find_field_in_real_table(THD *thd, TABLE *table, if (thd->set_query_id) { + table->file->ha_set_bit_in_rw_set(field->fieldnr, + (bool)(thd->set_query_id-1)); if (field->query_id != thd->query_id) { field->query_id=thd->query_id; @@ -3098,7 +3101,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List &fields, ****************************************************************************/ bool setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, - List &fields, bool set_query_id, + List &fields, ulong set_query_id, List *sum_func_list, bool allow_sum_func) { reg2 Item *item; @@ -3547,7 +3550,10 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name, fields marked in setup_tables during fix_fields of view columns */ if (table) + { table->used_fields= table->s->fields; + table->file->ha_set_all_bits_in_read_set(); + } } } if (found) diff --git a/sql/sql_class.h b/sql/sql_class.h index a97f2566a3e..31880d78926 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -760,8 +760,15 @@ public: /* - if set_query_id=1, we set field->query_id for all fields. In that case field list can not contain duplicates. + 0: Means query_id is not set and no indicator to handler of fields used + is set + 1: Means query_id is set for fields in list and bit in read set is set + to inform handler of that field is to be read + 2: Means query is set for fields in list and bit is set in update set + to inform handler that it needs to update this field in write_row + and update_row */ - bool set_query_id; + ulong set_query_id; /* This variable is used in post-parse stage to declare that sum-functions, or functions which have sense only if GROUP BY is present, are allowed. diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 9a7a3d64de5..9ecd02aed76 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -105,6 +105,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, #endif clear_timestamp_auto_bits(table->timestamp_field_type, TIMESTAMP_AUTO_SET_ON_INSERT); + /* + No fields are provided so all fields must be provided in the values. + Thus we set all bits in the write set. + */ + table->file->ha_set_all_bits_in_write_set(); } else { // Part field list @@ -120,7 +125,11 @@ static int check_insert_fields(THD *thd, TABLE_LIST *table_list, thd->lex->select_lex.no_wrap_view_item= 1; save_next= table_list->next_local; // fields only from first table table_list->next_local= 0; - res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); + /* + Indicate fields in list is to be updated by setting set_query_id + parameter to 2. This sets the bit in the write_set for each field. + */ + res= setup_fields(thd, 0, table_list, fields, 2, 0, 0); table_list->next_local= save_next; thd->lex->select_lex.no_wrap_view_item= 0; if (res) @@ -209,9 +218,10 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, /* Check the fields we are going to modify. This will set the query_id - of all used fields to the threads query_id. + of all used fields to the threads query_id. It will also set all + fields into the write set of this table. */ - if (setup_fields(thd, 0, insert_table_list, update_fields, 1, 0, 0)) + if (setup_fields(thd, 0, insert_table_list, update_fields, 2, 0, 0)) return -1; if (table->timestamp_field) @@ -788,7 +798,10 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, DBUG_RETURN(TRUE); } if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) + { + table->file->ha_set_primary_key_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); + } thd->lex->select_lex.first_execution= 0; DBUG_RETURN(FALSE); } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index c827bbace3e..71222b4d1c4 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -179,6 +179,10 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, Field **field; for (field=table->field; *field ; field++) fields_vars.push_back(new Item_field(*field)); + /* + Since all fields is be set we set all bits in the write set + */ + table->file->ha_set_all_bits_in_write_set(); table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; /* Let us also prepare SET clause, altough it is probably empty @@ -191,8 +195,12 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, else { // Part field list /* TODO: use this conds for 'WITH CHECK OPTIONS' */ - if (setup_fields(thd, 0, table_list, fields_vars, 1, 0, 0) || - setup_fields(thd, 0, table_list, set_fields, 1, 0, 0) || + /* + Indicate that both variables in field list and fields in update_list + is to be included in write set of table + */ + if (setup_fields(thd, 0, table_list, fields_vars, 2, 0, 0) || + setup_fields(thd, 0, table_list, set_fields, 2, 0, 0) || check_that_all_fields_are_given_values(thd, table)) DBUG_RETURN(TRUE); /* diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9b93a92c6aa..44354168518 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -935,6 +935,7 @@ JOIN::optimize() for (uint i_h = const_tables; i_h < tables; i_h++) { TABLE* table_h = join_tab[i_h].table; + table_h->file->set_primary_key_in_read_set(); table_h->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); } } @@ -7978,7 +7979,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, uint hidden_null_count, hidden_null_pack_length, hidden_field_count; uint blob_count,group_null_items, string_count; uint temp_pool_slot=MY_BIT_NONE; - ulong reclength, string_total_length; + ulong reclength, string_total_length, fieldnr= 0; bool using_unique_constraint= 0; bool use_packed_rows= 0; bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS); @@ -8162,6 +8163,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, (*argp)->maybe_null=1; } new_field->query_id= thd->query_id; + new_field->fieldnr= ++fieldnr; } } } @@ -8209,6 +8211,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, new_field->flags|= GROUP_FLAG; } new_field->query_id= thd->query_id; + new_field->fieldnr= ++fieldnr; *(reg_field++) =new_field; } if (!--hidden_field_count) @@ -8217,6 +8220,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, DBUG_ASSERT(field_count >= (uint) (reg_field - table->field)); field_count= (uint) (reg_field - table->field); *blob_field= 0; // End marker + table->s->fields= field_count; /* If result table is small; use a heap */ if (blob_count || using_unique_constraint || @@ -8233,7 +8237,11 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, { table->file=get_new_handler(table,table->s->db_type= DB_TYPE_HEAP); } - + if (table->s->fields) + { + table->file->ha_set_all_bits_in_read_set(); + table->file->ha_set_all_bits_in_write_set(); + } if (!using_unique_constraint) reclength+= group_null_items; // null flag is stored separately @@ -8259,7 +8267,6 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, string_total_length / string_count >= AVG_STRING_LENGTH_TO_PACK_ROWS)) use_packed_rows= 1; - table->s->fields= field_count; table->s->reclength= reclength; { uint alloc_length=ALIGN_SIZE(reclength+MI_UNIQUE_HASH_LENGTH+1); diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 18c90d549ec..a6b1560b86f 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3825,7 +3825,9 @@ copy_data_between_tables(TABLE *from,TABLE *to, this function does not set field->query_id in the columns to the current query id */ - from->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + to->file->ha_set_all_bits_in_write_set(); + from->file->ha_set_all_bits_in_read_set(); + from->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); //To be removed RONM init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1); if (ignore || handle_duplicates == DUP_REPLACE) @@ -3991,6 +3993,7 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) /* InnoDB must be told explicitly to retrieve all columns, because this function does not set field->query_id in the columns to the current query id */ + t->file->ha_set_all_bits_in_read_set(); t->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (t->file->ha_rnd_init(1)) diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index f5d64efb5e9..a552fa9c0e7 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -527,6 +527,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) goto err; table->field[0]->store(udf_name->str, udf_name->length, system_charset_info); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_set_all_bits_in_read_set(); if (!table->file->index_read_idx(table->record[0], 0, (byte*) table->field[0]->ptr, table->key_info[0].key_length, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 86aa0bf9890..e73ccaa7473 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -188,7 +188,11 @@ int mysql_update(THD *thd, { bool res; select_lex->no_wrap_view_item= 1; - res= setup_fields(thd, 0, table_list, fields, 1, 0, 0); + /* + Indicate that the set of fields is to be updated by passing 2 for + set_query_id. + */ + res= setup_fields(thd, 0, table_list, fields, 2, 0, 0); select_lex->no_wrap_view_item= 0; if (res) DBUG_RETURN(1); /* purecov: inspected */ @@ -268,6 +272,7 @@ int mysql_update(THD *thd, We can't update table directly; We must first search after all matching rows before updating the table! */ + table->file->ha_set_all_bits_in_read_set(); table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); if (used_index < MAX_KEY && old_used_keys.is_set(used_index)) { diff --git a/sql/table.cc b/sql/table.cc index 8e0f52e1910..1af8277a13b 100644 --- a/sql/table.cc +++ b/sql/table.cc @@ -567,6 +567,7 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, error= 4; goto err; /* purecov: inspected */ } + reg_field->fieldnr= i+1; //Set field number reg_field->comment=comment; if (field_type == FIELD_TYPE_BIT && !f_bit_as_char(pack_flag)) { @@ -796,6 +797,8 @@ int openfrm(THD *thd, const char *name, const char *alias, uint db_stat, (*save++)= i; } } + if (outparam->file->ha_allocate_read_write_set(share->fields)) + goto err; /* The table struct is now initialized; Open the table */ error=2; diff --git a/sql/unireg.cc b/sql/unireg.cc index 929ca5c672e..d614e7f6b6f 100644 --- a/sql/unireg.cc +++ b/sql/unireg.cc @@ -715,6 +715,7 @@ static bool make_empty_rec(THD *thd, File file,enum db_type table_type, { my_error(ER_INVALID_DEFAULT, MYF(0), regfield->field_name); error= 1; + delete regfield; //To avoid memory leak goto err; } } From f7cd6b8aa136626252849eb13daa9bcd8d098ef2 Mon Sep 17 00:00:00 2001 From: "mronstrom@mysql.com" <> Date: Mon, 2 May 2005 15:45:33 +0200 Subject: [PATCH 2/7] WL 1682: After review fixes + update bitvector class + bitvector test cases + bug fixes --- mysys/my_bitmap.c | 8 -- sql/bitvector.cc | 320 +++++++++++++++++++++++++++++++++++++++++++ sql/bitvector.h | 299 +++++++++++++++++++++++++++++++--------- sql/field.h | 5 +- sql/ha_federated.cc | 9 +- sql/ha_innodb.cc | 4 +- sql/ha_innodb.h | 10 ++ sql/ha_ndbcluster.cc | 4 - sql/handler.cc | 145 ++++++++++++++++++-- sql/handler.h | 87 ++++-------- sql/opt_range.cc | 9 +- sql/sql_acl.cc | 24 ++-- sql/sql_base.cc | 2 + sql/sql_insert.cc | 8 +- sql/sql_load.cc | 9 +- sql/sql_select.cc | 16 +-- sql/sql_table.cc | 13 +- sql/sql_udf.cc | 3 +- sql/sql_update.cc | 6 +- 19 files changed, 772 insertions(+), 209 deletions(-) create mode 100644 sql/bitvector.cc diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index 2f8faea68a8..c0eb6f15548 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -102,14 +102,6 @@ void bitmap_free(MY_BITMAP *map) void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit) { - if (map->bitmap) - { - DBUG_PRINT("info", ("Bitmap not defined")); - } - if (bitmap_bit >= map->bitmap_size*8) - { - DBUG_PRINT("info", ("bit %d size in bytes %d", bitmap_bit, map->bitmap_size)); - } DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); bitmap_lock(map); bitmap_fast_set_bit(map, bitmap_bit); diff --git a/sql/bitvector.cc b/sql/bitvector.cc new file mode 100644 index 00000000000..d50ad7df33b --- /dev/null +++ b/sql/bitvector.cc @@ -0,0 +1,320 @@ +/* -*- Mode: C++ -*- + + Copyright (C) 2005 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include + +void bitvector::create_last_word_mask() +{ + + /* Get the number of used bits (1..8) in the last byte */ + unsigned int const used= 1U + ((size()-1U) & 0x7U); + + /* + * Create a mask with the upper 'unused' bits set and the lower 'used' + * bits clear. The bits within each byte is stored in big-endian order. + */ + unsigned char const mask= (~((1 << used) - 1)) & 255; + last_word_ptr= (uint32*)(m_data+((bytes()-1U)>>2)); + + /* + The first bytes are to be set to zero since they represent real bits + in the bitvector. The last bytes are set to 0xFF since they represent + bytes not used by the bitvector. Finally the last byte contains bits + as set by the mask above. + */ + + unsigned char *ptr= (unsigned char*)&last_word_mask; + switch (bytes()&3) + { + case 1: + last_word_mask= ~0U; + ptr[0]= mask; + return; + case 2: + last_word_mask= ~0U; + ptr[0]= 0; + ptr[1]= mask; + return; + case 3: + last_word_mask= 0U; + ptr[2]= mask; + ptr[3]= 0xFFU; + return; + case 0: + last_word_mask= 0U; + ptr[3]= mask; + return; + } +} + +int bitvector::init(size_t size) +{ + DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); + m_size= size; + m_data= (uchar*)my_malloc(byte_size_word_aligned(size), MYF(0)); + if (m_data) + { + create_last_word_mask(); + clear_all(); + return FALSE; + } + return TRUE; +} + +uint bitvector::no_bits_set() +{ + uint no_bytes= bytes(), res=0, i; + uchar *ptr= m_data; + *last_word_ptr^=last_word_mask; //Reset last bits to zero + for (i=0; i< no_bytes; i++, ptr++) + res+=my_count_bits_ushort(*ptr); + *last_word_ptr^=last_word_mask; //Set last bits to one again + return res; +} + +uint bitvector::get_first_bit_set() +{ + uchar *byte_ptr; + uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k; + for (i=0; data_ptr <= last_word_ptr; data_ptr++, i++) + { + if (*data_ptr) + { + byte_ptr= (uchar*)data_ptr; + for (j=0; j < 4; j++, byte_ptr++) + { + if (*byte_ptr) + { + for (k=0; k < 8; k++) + { + if (*byte_ptr & (1 << k)) + { + bit_found= (i << 5) + (j << 3) + k; + if (bit_found == m_size) + return MYSQL_NO_BIT_FOUND; + else + return bit_found; + } + } + DBUG_ASSERT(1); + } + } + DBUG_ASSERT(1); + } + } + return MYSQL_NO_BIT_FOUND; +} + +uint bitvector::get_first_bit_unset() +{ + uchar *byte_ptr; + uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k; + for (i=0; data_ptr <= last_word_ptr; data_ptr++, i++) + { + if (*data_ptr != 0xFFFFFFFF) + { + byte_ptr= (uchar*)data_ptr; + for (j=0; j < 4; j++, byte_ptr++) + { + if (*byte_ptr != 0xFF) + { + for (k=0; k < 8; k++) + { + if (!(*byte_ptr & (1 << k))) + { + bit_found= (i << 5) + (j << 3) + k; + if (bit_found == m_size) + return MYSQL_NO_BIT_FOUND; + else + return bit_found; + } + } + DBUG_ASSERT(1); + } + } + DBUG_ASSERT(1); + } + } + return MYSQL_NO_BIT_FOUND; +} + +#ifdef TEST_BITVECTOR + +int main() +{ + int i; + for (i= 0; i < 4096; i++) + if (do_test(i)) + return -1; + return 0; +} + +bool do_test(uint bitsize) +{ + bitvector *bv; + bv = new bitvector; + bv->init(bitsize); + if (test_set_get_clear_bit(bv,bitsize)) + return TRUE; + if (test_flip_bit(bv,bitsize)) + return TRUE; + if (test_operators(bv,bitsize)) + return TRUE; + if (test_get_all_bits(bvbitsize)) + return TRUE; + if (test_compare_operators(bv,bitsize)) + return TRUE; + if (test_count_bits_set(bv,bitsize)) + return TRUE; + if (test_get_first_bit(bv,bitsize)) + return TRUE; + if (test_get_next_bit(bv,bitsize)) + return TRUE; + printf("OK"); + return FALSE; +} + +uint get_rand_bit(uint bitsize) +{ + return (rand() % bitsize); +} + +bool test_set_get_clear_bit(bitvector *bv, uint bitsize) +{ + uint i, test_bit; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit= get_rand_bit(bitsize); + bv->set_bit(test_bit) + if (!bv->get_bit(test_bit)) + goto error1; + bv->clear_bit(test_bit); + if (bv->get_bit(test_bit)) + goto error2; + } + return FALSE; +error1: + printf("Error in set bit, bit %u, bitsize = %u", test_bit, bitsize); + return TRUE; +error2: + printf("Error in clear bit, bit %u, bitsize = %u", test_bit, bitsize); + return TRUE; +} + +bool test_flip_bit(bitvector *bv, uint bitsize) +{ + uint i test_bit; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit= get_rand_bit(bitsize); + bv->flip_bit(test_bit) + if (!bv->get_bit(test_bit)) + goto error1; + bv->flip_bit(test_bit); + if (bv->get_bit(test_bit)) + goto error2; + } + return FALSE; +error1: + printf("Error in flip bit 1, bit %u, bitsize = %u", test_bit, bitsize); + return TRUE; +error2: + printf("Error in flip bit 2, bit %u, bitsize = %u", test_bit, bitsize); + return TRUE; +} + +bool test_operators(bitvector *bv, uint bitsize) +{ + return FALSE; +} + +bool test_get_all_bits(bitvector *bv, uint bitsize) +{ + uint i; + bv->set_all(); + if (!bv->get_all_bits_set()) + goto error1; + bv->clear_all(); + if (!bv->get_all_bits_clear()) + goto error2; + for (i=0; iset_bit(i); + if (!bv->get_all_bits_set()) + goto error3; + for (i=0; iclear_bit(i); + if (!bv->get_all_bits_clear()) + goto error4; + return FALSE; +error1: + printf("Error in set_all, bitsize = %u", bitsize); + return TRUE; +error2: + printf("Error in clear_all, bitsize = %u", bitsize); + return TRUE; +error3: + printf("Error in bitwise set all, bitsize = %u", bitsize); + return TRUE; +error4: + printf("Error in bitwise clear all, bitsize = %u", bitsize); + return TRUE; +} + +bool test_compare_operators(bitvector *bv, uint bitsize) +{ + return FALSE; +} + +bool test_count_bits_set(bitvector *bv, uint bitsize) +{ + uint i, bit_count=0; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit=get_rand_bit(bitsize); + if (!bv->get_bit(test_bit)) + { + bv->set_bit(test_bit); + bit_count++; + } + } + if (bit_count==0 && bitsize > 0) + error1; + if (bv->no_bits_set() != bit_count) + error2; + return FALSE; +error1: + printf("No bits set bitsize = %u", bitsize); + return TRUE; +error2: + printf("Wrong count of bits set, bitsize = %u", bitsize); + return TRUE; +} + +bool test_get_first_bit(bitvector *bv, uint bitsize) +{ + return FALSE; +} + +bool test_get_next_bit(bitvector *bv, uint bitsize) +{ + return FALSE; +} +#endif diff --git a/sql/bitvector.h b/sql/bitvector.h index 9c3229df482..78def21df64 100644 --- a/sql/bitvector.h +++ b/sql/bitvector.h @@ -68,64 +68,70 @@ namespace inlining code. */ +/* Number returned when no bit found */ +#define MYSQL_NO_BIT_FOUND 1 << 20 class bitvector { private: - /* Helper classes */ - struct flip_bit_op - { - void operator()(byte* p, byte m) { *p^= m; } - }; - - struct set_bit_op - { - void operator()(byte* p, byte m) { *p|= m; } - }; - - struct clear_bit_op - { - void operator()(byte* p, byte m) { *p&= ~m; } - }; - - struct test_bit_op - { - bool operator()(byte* p, byte m) { return *p & m; } - }; - /* Compute the number of bytes required to store 'bits' bits in an array. */ static inline size_t byte_size(size_t bits) { - int const byte_bits = sizeof(byte) * CHAR_BIT; + uint const byte_bits = sizeof(byte) * CHAR_BIT; return (bits + (byte_bits-1)) / byte_bits; } - /* Tidy the last byte (by clearing the unused bits) of the bitvector to make - * comparison easy. This code is assuming that we're working with 8-bit - * bytes. - */ - void tidy_last_byte() + static inline size_t byte_size_word_aligned(size_t bits) + { + return ((bits + 31) >> 5) << 2; + } + + void create_last_word_mask() { - byte* const last_byte= m_data + bytes() - 1; /* Get the number of used bits (1..8) in the last byte */ unsigned int const used= 1U + ((size()-1U) & 0x7U); - /* Create a mask with the upper 'unused' bits clear and the lower 'used' - * bits set. The bits within each byte is stored in big-endian order. + /* + * Create a mask with the upper 'unused' bits set and the lower 'used' + * bits clear. The bits within each byte is stored in big-endian order. */ - unsigned int const mask= ((1 << used) - 1); + unsigned char const mask= (~((1 << used) - 1)) & 255; + last_word_ptr= (uint32*)(m_data+((bytes()-1U)>>2)); - /* Mask the last byte */ - *last_byte&= mask; + /* + The first bytes are to be set to zero since they represent real bits + in the bitvector. The last bytes are set to 0xFF since they represent + bytes not used by the bitvector. Finally the last byte contains bits + as set by the mask above. + */ + + unsigned char *ptr= (unsigned char*)&last_word_mask; + switch (bytes()&3) + { + case 1: + last_word_mask= ~0U; + ptr[0]= mask; + return; + case 2: + last_word_mask= ~0U; + ptr[0]= 0; + ptr[1]= mask; + return; + case 3: + last_word_mask= 0U; + ptr[2]= mask; + ptr[3]= 0xFFU; + return; + case 0: + last_word_mask= 0U; + ptr[3]= mask; + return; + } } - template - inline ReturnType apply_to_byte(size_t const pos, Func op) const + inline void tidy_last_word() { - /* Here I'm assuming that we're working with 8-bit bytes. */ - ptrdiff_t const byte_pos= pos >> 3; - byte const mask= (1 << (pos & 0x7U)); - return op(&m_data[byte_pos], mask); + *last_word_ptr|= last_word_mask; } public: @@ -135,8 +141,11 @@ public: } explicit bitvector(size_t size, bool value= false) - : m_size(size), m_data(my_malloc(byte_size(size), MYF(0))) + : m_size(size), + m_data((uchar*)my_malloc(byte_size_word_aligned(size), MYF(0))) { + DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); + create_last_word_mask(); if (value) set_all(); else @@ -147,32 +156,43 @@ public: * number of *bits* in the bitvector. */ explicit bitvector(byte const* data, size_t size) - : m_size(size), m_data(my_malloc(byte_size(size), MYF(0))) + : m_size(size), + m_data((uchar*)my_malloc(byte_size_word_aligned(size), MYF(0))) { - /* std::copy(data, data + byte_size(size), m_data); */ + DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); + create_last_word_mask(); memcpy(m_data, data, byte_size(size)); - tidy_last_byte(); + tidy_last_word(); } bitvector(bitvector const& other) - : m_size(other.size()), m_data(my_malloc(other.bytes(), MYF(0))) + : m_size(other.size()), + m_data((uchar*)my_malloc(other.bytes(), MYF(0))) { - /* std::copy(other.m_data, other.m_data + other.bytes(), m_data); */ + DBUG_ASSERT(m_size < MYSQL_NO_BIT_FOUND); + create_last_word_mask(); memcpy(m_data, other.data(), other.bytes()); - tidy_last_byte(); /* Just a precaution */ - } - - /* Assignment operator */ - bitvector& operator=(bitvector other) - { - swap(other); - return *this; + tidy_last_word(); } ~bitvector() { if (m_data) - my_free(m_data, MYF(0)); + my_free((char*)m_data, MYF(0)); + } + + int init(size_t size) + { + DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); + m_size= size; + m_data= (uchar*)my_malloc(byte_size_word_aligned(size), MYF(0)); + if (m_data) + { + create_last_word_mask(); + clear_all(); + return FALSE; + } + return TRUE; } /* Swap the guts of this instance with another instance. */ @@ -182,8 +202,35 @@ public: my_swap(m_data, other.m_data); } + bitvector &operator=(const bitvector &rhs) + { + DBUG_ASSERT(rhs.size() == size()); + memcpy(m_data, rhs.data(), byte_size_word_aligned(m_size)); + return *this; + } + + bool get_all_bits_set() + { + uint32 *data_ptr= (uint32*)&m_data[0]; + for (; data_ptr <= last_word_ptr; data_ptr++) + if (*data_ptr != 0xFFFFFFFF) + return FALSE; + return TRUE; + } + + bool get_all_bits_clear() + { + uint32 *data_ptr= (uint32*)&m_data[0]; + if (*last_word_ptr ^ last_word_mask) + return FALSE; + for (; data_ptr < last_word_ptr; data_ptr++) + if (*data_ptr) + return FALSE; + return TRUE; + } + /* A pointer to the bytes representing the bits */ - byte const *data() const { return m_data; } + uchar const *data() const { return m_data; } /* The size of the data in *bytes* */ size_t bytes() const { return byte_size(m_size); } @@ -194,47 +241,44 @@ public: /* Set all bits in the vector */ void set_all() { - /* std::fill_n(m_data, bytes(), 255); */ - memset(m_data, 255, bytes()); - tidy_last_byte(); + memset(m_data, 255, byte_size_word_aligned(m_size)); } /* Set a bit to a value */ void set_bit(size_t pos) { - apply_to_byte(pos, set_bit_op()); + *(uchar*)(m_data + (pos >> 3)) |= (uchar)(1 << (pos & 0x7U)); } /* Reset (clear) all bits in the vector */ void clear_all() { - /* std::fill_n(m_data, bytes(), 0); */ memset(m_data, 0, bytes()); - tidy_last_byte(); + tidy_last_word(); } /* Reset one bit in the vector */ void clear_bit(size_t pos) { - apply_to_byte(pos, clear_bit_op()); + *(u_char*)(m_data + (pos >> 3)) &= (u_char)(~(1 << (pos & 0x7U))); } void flip_bit(size_t pos) { - apply_to_byte(pos, flip_bit_op()); + *(uchar*)(m_data + (pos >> 3)) ^= (uchar)(1 << (pos & 0x7U)); } bool get_bit(size_t pos) const { - return apply_to_byte(pos, test_bit_op()); + (bool)(*(uchar*)(m_data + (pos >> 3))) & (uchar)(1 << (pos & 0x7U)); }; bool operator==(bitvector const& rhs) const { if (size() != rhs.size()) return false; - /* This works since I have ensured that the last byte of the array contain - * sensible data. + /* This works since I have ensured that the last byte of the array + * contain sensible data. */ if (memcmp(data(), rhs.data(), bytes()) != 0) return false; @@ -246,9 +290,130 @@ public: return !(*this == rhs); } + bitvector &operator&=(bitvector const& rhs) + { + DBUG_ASSERT(size() == rhs.size()); + uint32 *data_ptr=(uint32*)data(), *rhs_data_ptr=(uint32*)rhs.data(); + uint32 *last_ptr= last_word_ptr; + for (; data_ptr <= last_ptr; data_ptr++, rhs_data_ptr++) + *data_ptr&=*rhs_data_ptr; + return *this; + } + + bitvector &operator|=(bitvector const& rhs) + { + DBUG_ASSERT(size() == rhs.size()); + uint32 *data_ptr=(uint32*)data(), *rhs_data_ptr=(uint32*)rhs.data(); + uint32 *last_ptr= last_word_ptr; + for (; data_ptr <= last_ptr; data_ptr++, rhs_data_ptr++) + *data_ptr|=*rhs_data_ptr; + return *this; + } + + bitvector &operator^=(bitvector const& rhs) + { + DBUG_ASSERT(size() == rhs.size()); + uint32 *data_ptr=(uint32*)data(), *rhs_data_ptr=(uint32*)rhs.data(); + uint32 *last_ptr= last_word_ptr; + for (; data_ptr <= last_ptr; data_ptr++, rhs_data_ptr++) + *data_ptr^=*rhs_data_ptr; + tidy_last_word(); + return *this; + } + + bitvector &operator~() + { + uint32 *data_ptr= (uint32*)data(); + uint32 *last_ptr= last_word_ptr; + for (; data_ptr <= last_ptr; data_ptr++) + *data_ptr^=0xFFFFFFFF; + tidy_last_word(); + return *this; + } + + uint no_bits_set() + { + uint no_bytes= bytes(), res=0, i; + uchar *ptr= m_data; + *last_word_ptr^=last_word_mask; //Reset last bits to zero + for (i=0; i< no_bytes; i++, ptr++) + res+=my_count_bits_ushort(*ptr); + *last_word_ptr^=last_word_mask; //Set last bits to one again + return res; + } + + uint get_first_bit_set() + { + uchar *byte_ptr; + uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k; + for (i=0; data_ptr <= last_word_ptr; data_ptr++, i++) + { + if (*data_ptr) + { + byte_ptr= (uchar*)data_ptr; + for (j=0; j < 4; j++, byte_ptr++) + { + if (*byte_ptr) + { + for (k=0; k < 8; k++) + { + if (*byte_ptr & (1 << k)) + { + bit_found= (i << 5) + (j << 3) + k; + if (bit_found == m_size) + return MYSQL_NO_BIT_FOUND; + else + return bit_found; + } + } + DBUG_ASSERT(1); + } + } + DBUG_ASSERT(1); + } + } + return MYSQL_NO_BIT_FOUND; + } + + uint get_first_bit_unset() + { + uchar *byte_ptr; + uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k; + for (i=0; data_ptr <= last_word_ptr; data_ptr++, i++) + { + if (*data_ptr != 0xFFFFFFFF) + { + byte_ptr= (uchar*)data_ptr; + for (j=0; j < 4; j++, byte_ptr++) + { + if (*byte_ptr != 0xFF) + { + for (k=0; k < 8; k++) + { + if (!(*byte_ptr & (1 << k))) + { + bit_found= (i << 5) + (j << 3) + k; + if (bit_found == m_size) + return MYSQL_NO_BIT_FOUND; + else + return bit_found; + } + } + DBUG_ASSERT(1); + } + } + DBUG_ASSERT(1); + } + } + return MYSQL_NO_BIT_FOUND; + } + + private: size_t m_size; - byte *m_data; + uint32 last_word_mask; + uchar *m_data; + uint32 *last_word_ptr; }; #endif /* BITVECTOR_H */ diff --git a/sql/field.h b/sql/field.h index f7ed6592a6d..38a8f4d0bd0 100644 --- a/sql/field.h +++ b/sql/field.h @@ -86,7 +86,10 @@ public: utype unireg_check; uint32 field_length; // Length of field uint16 flags; - uint16 fieldnr; // Field number + /* fieldnr is the id of the field (first field = 1) as is also + used in key_part. + */ + uint16 fieldnr; uchar null_bit; // Bit used to test null bit Field(char *ptr_arg,uint32 length_arg,uchar *null_ptr_arg,uchar null_bit_arg, diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 1854801f6a2..52fdeee4ed4 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -1113,7 +1113,7 @@ int ha_federated::write_row(byte *buf) loop through the field pointer array, add any fields to both the values list and the fields list that is part of the write set */ - for (x=0, num_fields= 0, field= table->field; *field; field++, x++) + for (num_fields= 0, field= table->field; *field; field++) { /* if there is a query id and if it's equal to the current query id */ if (ha_get_bit_in_write_set((*field)->fieldnr)) @@ -1122,15 +1122,16 @@ int ha_federated::write_row(byte *buf) if ((*field)->is_null()) { - DBUG_PRINT("info", ("column %d field is_null", x)); + DBUG_PRINT("info", ("column %d field is_null", num_fields-1)); insert_field_value_string.append("NULL"); } else { - DBUG_PRINT("info", ("column %d field is not null", x)); + DBUG_PRINT("info", ("column %d field is not null", num_fields-1)); (*field)->val_str(&insert_field_value_string); /* quote these fields if they require it */ - (*field)->quote_data(&insert_field_value_string); } + (*field)->quote_data(&insert_field_value_string); + } /* append the field name */ insert_string.append((*field)->field_name); diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index e15e201bb32..9da90c9cbb7 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -2684,8 +2684,8 @@ build_template( (!(fetch_all_in_key && index_contains_field) && !(fetch_primary_key_cols && dict_table_col_in_clustered_key(index->table, i)) && - !(ha_get_bit_in_read_set(i+1) || - ha_get_bit_in_write_set(i+1))))) { + (!(table->file->ha_get_bit_in_read_set(i+1) || + table->file->ha_get_bit_in_write_set(i+1)))))) { /* This field is not needed in the query, skip it */ diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 35f95ead757..f596ec35fe5 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -165,6 +165,16 @@ class ha_innobase: public handler int transactional_table_lock(THD *thd, int lock_type); int start_stmt(THD *thd); + int ha_retrieve_all_cols() + { + ha_set_all_bits_in_read_set(); + return extra(HA_EXTRA_RETRIEVE_ALL_COLS); + } + int ha_retrieve_all_pk() + { + ha_set_primary_key_in_read_set(); + return extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); + } void position(byte *record); ha_rows records_in_range(uint inx, key_range *min_key, key_range *max_key); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 705fbf957b7..722623c4f2f 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -1921,10 +1921,7 @@ int ha_ndbcluster::write_row(byte *record) statistic_increment(thd->status_var.ha_write_count, &LOCK_status); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) - { table->timestamp_field->set_time(); - ha_set_bit_in_write_set(table->timestamp_field->fieldnr); - } has_auto_increment= (table->next_number_field && record == table->record[0]); if (!(op= trans->getNdbOperation((const NDBTAB *) m_table))) @@ -1977,7 +1974,6 @@ int ha_ndbcluster::write_row(byte *record) { Field *field= table->field[i]; if (!(field->flags & PRI_KEY_FLAG) && - (ha_get_bit_in_write_set(i+1)) && set_ndb_value(op, field, i, &set_blob_value)) { m_skip_auto_increment= TRUE; diff --git a/sql/handler.cc b/sql/handler.cc index 5460dd6d48b..8bd89888071 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -271,10 +271,10 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) } if (file) { - if (table && file->ha_allocate_read_write_set(table->s->fields)) + if (file->ha_initialise()) { delete file; - file= 0; + file=0; } } return file; @@ -1343,38 +1343,154 @@ int handler::ha_open(const char *name, int mode, int test_if_locked) DBUG_RETURN(error); } +int handler::ha_initialise() +{ + if (table && table->s->fields && + ha_allocate_read_write_set(table->s->fields)) + { + return TRUE; + } + return FALSE; +} + int handler::ha_allocate_read_write_set(ulong no_fields) { DBUG_ENTER("ha_allocate_read_write_set"); - uint map_size= ((no_fields + 8)/8)*8; - if (rw_set_allocated) - ha_deallocate_read_write_set(); - DBUG_PRINT("info", ("no_fields = %d, map_size = %d", no_fields, map_size)); - if (bitmap_init(&read_set, NULL, map_size, FALSE)) + DBUG_PRINT("info", ("no_fields = %d", no_fields)); + read_set= new bitvector; + write_set= new bitvector; + if (!read_set || !write_set) { + ha_deallocate_read_write_set(); DBUG_RETURN(TRUE); } - if (bitmap_init(&write_set, NULL, map_size, FALSE)) + if (read_set->init(no_fields+1) || write_set->init(no_fields+1)) { - bitmap_free(&read_set); + ha_deallocate_read_write_set(); DBUG_RETURN(TRUE); } ha_clear_all_set(); - rw_set_allocated= TRUE; DBUG_RETURN(FALSE); } void handler::ha_deallocate_read_write_set() { - if (!rw_set_allocated) - return; - bitmap_free(&read_set); - bitmap_free(&write_set); + delete read_set; + delete write_set; + read_set=write_set=0; +} + +void handler::ha_clear_all_set() +{ + DBUG_ENTER("ha_clear_all_set"); + read_set->clear_all(); + write_set->clear_all(); + read_set->set_bit((uint)0); + write_set->set_bit((uint)0); + DBUG_VOID_RETURN; +} + +void handler::ha_set_all_bits_in_read_set() +{ + DBUG_ENTER("handler::ha_set_all_bits_in_read_set"); + read_set->set_all(); + DBUG_VOID_RETURN; +} + +void handler::ha_set_all_bits_in_write_set() +{ + DBUG_ENTER("handler::ha_set_all_bits_in_write_set"); + write_set->set_all(); + DBUG_VOID_RETURN; +} + +void handler::ha_set_bit_in_read_set(uint fieldnr) +{ + DBUG_ENTER("handler::ha_set_bit_in_read_set"); + DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); + read_set->set_bit((size_t)fieldnr); + DBUG_VOID_RETURN; +} + +void handler::ha_clear_bit_in_read_set(uint fieldnr) +{ + DBUG_ENTER("handler::ha_clear_bit_in_read_set"); + DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); + read_set->clear_bit((size_t)fieldnr); + DBUG_VOID_RETURN; +} + +void handler::ha_set_bit_in_write_set(uint fieldnr) +{ + DBUG_ENTER("handler::ha_set_bit_in_write_set"); + DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); + write_set->set_bit((size_t)fieldnr); + DBUG_VOID_RETURN; +} + +void handler::ha_clear_bit_in_write_set(uint fieldnr) +{ + DBUG_ENTER("handler::ha_clear_bit_in_write_set"); + DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); + write_set->clear_bit((size_t)fieldnr); + DBUG_VOID_RETURN; +} + +void handler::ha_set_bit_in_rw_set(uint fieldnr, bool write_op) +{ + if (!write_op) + read_set->set_bit((size_t)fieldnr); + else + write_set->set_bit((size_t)fieldnr); +} + +bool handler::ha_get_bit_in_read_set(uint fieldnr) +{ + read_set->get_bit((size_t)fieldnr); +} + +bool handler::ha_get_bit_in_write_set(uint fieldnr) +{ + write_set->get_bit((size_t)fieldnr); +} + +bool handler::ha_get_all_bit_in_read_set() +{ + return read_set->get_all_bits_set(); +} + +bool handler::ha_get_all_bit_in_read_clear() +{ + return read_set->get_all_bits_clear(); +} + +bool handler::ha_get_all_bit_in_write_set() +{ + return write_set->get_all_bits_set(); +} + +bool handler::ha_get_all_bit_in_write_clear() +{ + return write_set->get_all_bits_clear(); +} + +int handler::ha_retrieve_all_cols() +{ + read_set->set_all(); + return 0; +} + +int handler::ha_retrieve_all_pk() +{ + ha_set_primary_key_in_read_set(); + return 0; } void handler::ha_set_primary_key_in_read_set() { ulong prim_key= table->s->primary_key; + DBUG_ENTER("handler::ha_set_primary_key_in_read_set"); + DBUG_PRINT("info", ("Primary key = %d", prim_key)); if (prim_key != MAX_KEY) { KEY_PART_INFO *key_part= table->key_info[prim_key].key_part; @@ -1383,6 +1499,7 @@ void handler::ha_set_primary_key_in_read_set() for (;key_part != key_part_end; ++key_part) ha_set_bit_in_read_set(key_part->fieldnr); } + DBUG_VOID_RETURN; } /* Read first row (only) from a table diff --git a/sql/handler.h b/sql/handler.h index d64bc7e706e..31bd5978e1c 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -23,6 +23,7 @@ #include #include +#include #ifndef NO_HASH #define NO_HASH /* Not yet implemented */ @@ -483,9 +484,8 @@ public: bool auto_increment_column_changed; bool implicit_emptied; /* Can be !=0 only if HEAP */ const COND *pushed_cond; - MY_BITMAP read_set; - MY_BITMAP write_set; - bool rw_set_allocated; + bitvector *read_set; + bitvector *write_set; handler(TABLE *table_arg) :table(table_arg), ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0), @@ -495,13 +495,14 @@ public: key_used_on_scan(MAX_KEY), active_index(MAX_KEY), ref_length(sizeof(my_off_t)), block_size(0), raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0), - pushed_cond(NULL), rw_set_allocated(0) + pushed_cond(NULL), read_set(0), write_set(0) {} virtual ~handler(void) { - ha_deallocate_read_write_set(); + ha_deallocate_read_write_set(); /* TODO: DBUG_ASSERT(inited == NONE); */ } + virtual int ha_initialise(); int ha_open(const char *name, int mode, int test_if_locked); void update_auto_increment(); virtual void print_error(int error, myf errflag); @@ -578,64 +579,32 @@ public: The routines are all part of the general handler and are not possible to override by a handler. A handler can however set/reset bits by calling these routines. + + The methods ha_retrieve_all_cols and ha_retrieve_all_pk are made + virtual to handle InnoDB specifics. If InnoDB doesn't need the + extra parameters HA_EXTRA_RETRIEVE_ALL_COLS and + HA_EXTRA_RETRIEVE_PRIMARY_KEY anymore then these methods need not be + virtual anymore. */ - void ha_set_all_bits_in_read_set() - { - bitmap_set_all(&read_set); - } - void ha_set_all_bits_in_write_set() - { - bitmap_set_all(&write_set); - } - void ha_set_bit_in_read_set(uint fieldnr) - { - bitmap_set_bit(&read_set, fieldnr); - } - void ha_clear_bit_in_read_set(uint fieldnr) - { - bitmap_clear_bit(&read_set, fieldnr); - } - void ha_set_bit_in_write_set(uint fieldnr) - { - bitmap_set_bit(&write_set, fieldnr); - } - void ha_clear_bit_in_write_set(uint fieldnr) - { - bitmap_clear_bit(&write_set, fieldnr); - } - void ha_set_bit_in_rw_set(uint fieldnr, bool write_set) - { - if (!write_set) - ha_set_bit_in_read_set(fieldnr); - else - ha_set_bit_in_write_set(fieldnr); - } - my_bool ha_get_bit_in_read_set(uint fieldnr) - { - return bitmap_is_set(&read_set, fieldnr); - } - my_bool ha_get_all_bit_in_read_set() - { - return bitmap_is_set_all(&read_set); - } - my_bool ha_get_all_bit_in_write_set() - { - return bitmap_is_set_all(&write_set); - } - my_bool ha_get_bit_in_write_set(uint fieldnr) - { - return bitmap_is_set(&write_set, fieldnr); - } - void ha_clear_all_set() - { - bitmap_clear_all(&read_set); - bitmap_clear_all(&write_set); - bitmap_set_bit(&read_set,0); - bitmap_set_bit(&write_set,0); - } + virtual int ha_retrieve_all_cols(); + virtual int ha_retrieve_all_pk(); + void ha_set_all_bits_in_read_set(); + void ha_set_all_bits_in_write_set(); + void ha_set_bit_in_read_set(uint fieldnr); + void ha_clear_bit_in_read_set(uint fieldnr); + void ha_set_bit_in_write_set(uint fieldnr); + void ha_clear_bit_in_write_set(uint fieldnr); + void ha_set_bit_in_rw_set(uint fieldnr, bool write_set); + bool ha_get_bit_in_read_set(uint fieldnr); + bool ha_get_bit_in_write_set(uint fieldnr); + bool ha_get_all_bit_in_read_set(); + bool ha_get_all_bit_in_read_clear(); + bool ha_get_all_bit_in_write_set(); + bool ha_get_all_bit_in_write_clear(); void ha_set_primary_key_in_read_set(); int ha_allocate_read_write_set(ulong no_fields); void ha_deallocate_read_write_set(); + void ha_clear_all_set(); uint get_index(void) const { return active_index; } virtual int open(const char *name, int mode, uint test_if_locked)=0; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 0e89cd0026a..b83e4f369af 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -916,12 +916,11 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) { DBUG_PRINT("info", ("Reusing handler %p", file)); if (file->extra(HA_EXTRA_KEYREAD) || - file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) || + file->ha_retrieve_all_pk() || init() || reset()) { DBUG_RETURN(1); } - file->ha_set_primary_key_in_read_set(); DBUG_RETURN(0); } @@ -945,14 +944,13 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) goto failure; if (file->extra(HA_EXTRA_KEYREAD) || - file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) || + file->ha_retrieve_all_pk() || init() || reset()) { file->external_lock(thd, F_UNLCK); file->close(); goto failure; } - file->ha_set_primary_key_in_read_set(); free_file= TRUE; last_rowid= file->ref; DBUG_RETURN(0); @@ -5627,9 +5625,8 @@ int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge() (This also creates a deficiency - it is possible that we will retrieve parts of key that are not used by current query at all.) */ - if (head->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY)) + if (head->file->ha_retrieve_all_pk()) DBUG_RETURN(1); - head->file->ha_set_primary_key_in_read_set(); cur_quick_it.rewind(); cur_quick= cur_quick_it++; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 9552e286b34..63d3992c4c8 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1526,8 +1526,7 @@ static bool update_user_table(THD *thd, const char *host, const char *user, key_copy((byte *) user_key, table->record[0], table->key_info, table->key_info->key_length); - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if (table->file->index_read_idx(table->record[0], 0, (byte *) user_key, table->key_info->key_length, HA_READ_KEY_EXACT)) @@ -1620,8 +1619,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if (table->file->index_read_idx(table->record[0], 0, user_key, table->key_info->key_length, HA_READ_KEY_EXACT)) @@ -1754,8 +1752,7 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, We should NEVER delete from the user table, as a uses can still use mysqld even if he doesn't have any privileges in the user table! */ - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if (cmp_record(table,record[1]) && (error=table->file->update_row(table->record[1],table->record[0]))) { // This should never happen @@ -1837,8 +1834,7 @@ static int replace_db_table(TABLE *table, const char *db, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if (table->file->index_read_idx(table->record[0],0, user_key, table->key_info->key_length, HA_READ_KEY_EXACT)) @@ -1874,8 +1870,7 @@ static int replace_db_table(TABLE *table, const char *db, /* update old existing row */ if (rights) { - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if ((error=table->file->update_row(table->record[1],table->record[0]))) goto table_error; /* purecov: deadcode */ } @@ -2208,8 +2203,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if (table->file->index_read(table->record[0], user_key, table->key_info->key_length, HA_READ_KEY_EXACT)) @@ -2286,8 +2280,7 @@ static int replace_column_table(GRANT_TABLE *g_t, key_copy(user_key, table->record[0], table->key_info, key_prefix_length); - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if (table->file->index_read(table->record[0], user_key, key_prefix_length, HA_READ_KEY_EXACT)) @@ -2385,8 +2378,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, key_copy(user_key, table->record[0], table->key_info, table->key_info->key_length); - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if (table->file->index_read_idx(table->record[0], 0, user_key, table->key_info->key_length, HA_READ_KEY_EXACT)) diff --git a/sql/sql_base.cc b/sql/sql_base.cc index d885ab50371..63fcf2b70b3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -3705,12 +3705,14 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds) goto err; /* Mark field used for table cache */ t2_field->query_id= thd->query_id; + t2->file->ha_set_bit_in_read_set(t2_field->fieldnr); t2->used_keys.intersect(t2_field->part_of_key); } if ((t1_field= iterator->field())) { /* Mark field used for table cache */ t1_field->query_id= thd->query_id; + t1->file->ha_set_bit_in_read_set(t1_field->fieldnr); t1->used_keys.intersect(t1_field->part_of_key); } Item_func_eq *tmp= new Item_func_eq(iterator->item(thd), diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 9ecd02aed76..512fdb90ef9 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -231,7 +231,10 @@ static int check_update_fields(THD *thd, TABLE_LIST *insert_table_list, clear_timestamp_auto_bits(table->timestamp_field_type, TIMESTAMP_AUTO_SET_ON_UPDATE); else + { table->timestamp_field->query_id= timestamp_query_id; + table->file->ha_set_bit_in_write_set(table->timestamp_field->fieldnr); + } } return 0; @@ -798,10 +801,7 @@ bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, DBUG_RETURN(TRUE); } if (duplic == DUP_UPDATE || duplic == DUP_REPLACE) - { - table->file->ha_set_primary_key_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); - } + table->file->ha_retrieve_all_pk(); thd->lex->select_lex.first_execution= 0; DBUG_RETURN(FALSE); } diff --git a/sql/sql_load.cc b/sql/sql_load.cc index 71222b4d1c4..880fbb62c13 100644 --- a/sql/sql_load.cc +++ b/sql/sql_load.cc @@ -163,7 +163,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, The main thing to fix to remove this restriction is to ensure that the table is marked to be 'used for insert' in which case we should never - mark this table as as 'const table' (ie, one that has only one row). + mark this table as 'const table' (ie, one that has only one row). */ if (unique_table(table_list, table_list->next_global)) { @@ -180,7 +180,7 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, for (field=table->field; *field ; field++) fields_vars.push_back(new Item_field(*field)); /* - Since all fields is be set we set all bits in the write set + Since all fields are set we set all bits in the write set */ table->file->ha_set_all_bits_in_write_set(); table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; @@ -197,8 +197,11 @@ bool mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list, /* TODO: use this conds for 'WITH CHECK OPTIONS' */ /* Indicate that both variables in field list and fields in update_list - is to be included in write set of table + is to be included in write set of table. We do however set all bits + in write set anyways since it is not allowed to specify NULLs in + LOAD DATA */ + table->file->ha_set_all_bits_in_write_set(); if (setup_fields(thd, 0, table_list, fields_vars, 2, 0, 0) || setup_fields(thd, 0, table_list, set_fields, 2, 0, 0) || check_that_all_fields_are_given_values(thd, table)) diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 44354168518..0d5efb99ce6 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -922,24 +922,19 @@ JOIN::optimize() } /* - Need to tell Innobase that to play it safe, it should fetch all - columns of the tables: this is because MySQL may build row - pointers for the rows, and for all columns of the primary key the - field->query_id has not necessarily been set to thd->query_id by - MySQL. + Need to tell handlers that to play it safe, it should fetch all + columns of the primary key of the tables: this is because MySQL may + build row pointers for the rows, and for all columns of the primary key + the read set has not necessarily been set by the server code. */ - -#ifdef HAVE_INNOBASE_DB if (need_tmp || select_distinct || group_list || order) { for (uint i_h = const_tables; i_h < tables; i_h++) { TABLE* table_h = join_tab[i_h].table; - table_h->file->set_primary_key_in_read_set(); - table_h->file->extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY); + table_h->file->ha_retrieve_all_pk(); } } -#endif DBUG_EXECUTE("info",TEST_join(this);); /* @@ -8090,6 +8085,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, table->s->tmp_table= TMP_TABLE; table->s->db_low_byte_first=1; // True for HEAP and MyISAM table->s->table_charset= param->table_charset; + table->s->primary_key= MAX_KEY; //Indicate no primary key table->s->keys_for_keyread.init(); table->s->keys_in_use.init(); /* For easier error reporting */ diff --git a/sql/sql_table.cc b/sql/sql_table.cc index a6b1560b86f..cb98bba5e4d 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -3826,8 +3826,7 @@ copy_data_between_tables(TABLE *from,TABLE *to, current query id */ to->file->ha_set_all_bits_in_write_set(); - from->file->ha_set_all_bits_in_read_set(); - from->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); //To be removed RONM + from->file->ha_retrieve_all_cols(); init_read_record(&info, thd, from, (SQL_SELECT *) 0, 1,1); if (ignore || handle_duplicates == DUP_REPLACE) @@ -3990,11 +3989,11 @@ bool mysql_checksum_table(THD *thd, TABLE_LIST *tables, HA_CHECK_OPT *check_opt) /* calculating table's checksum */ ha_checksum crc= 0; - /* InnoDB must be told explicitly to retrieve all columns, because - this function does not set field->query_id in the columns to the - current query id */ - t->file->ha_set_all_bits_in_read_set(); - t->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + /* + Set all bits in read set and inform InnoDB that we are reading all + fields + */ + t->file->ha_retrieve_all_cols(); if (t->file->ha_rnd_init(1)) protocol->store_null(); diff --git a/sql/sql_udf.cc b/sql/sql_udf.cc index a552fa9c0e7..dc6e8380cfe 100644 --- a/sql/sql_udf.cc +++ b/sql/sql_udf.cc @@ -526,8 +526,7 @@ int mysql_drop_function(THD *thd,const LEX_STRING *udf_name) if (!(table = open_ltable(thd,&tables,TL_WRITE))) goto err; table->field[0]->store(udf_name->str, udf_name->length, system_charset_info); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); - table->file->ha_set_all_bits_in_read_set(); + table->file->ha_retrieve_all_cols(); if (!table->file->index_read_idx(table->record[0], 0, (byte*) table->field[0]->ptr, table->key_info[0].key_length, diff --git a/sql/sql_update.cc b/sql/sql_update.cc index e73ccaa7473..8cb2cbef684 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -212,7 +212,10 @@ int mysql_update(THD *thd, if (table->timestamp_field->query_id == thd->query_id) table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; else + { table->timestamp_field->query_id=timestamp_query_id; + table->file->ha_set_bit_in_write_set(table->timestamp_field->fieldnr); + } } #ifndef NO_EMBEDDED_ACCESS_CHECKS @@ -272,8 +275,7 @@ int mysql_update(THD *thd, We can't update table directly; We must first search after all matching rows before updating the table! */ - table->file->ha_set_all_bits_in_read_set(); - table->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS); + table->file->ha_retrieve_all_cols(); if (used_index < MAX_KEY && old_used_keys.is_set(used_index)) { table->key_read=1; From 0f40e05cbec2811f236268d526206deac4f67136 Mon Sep 17 00:00:00 2001 From: "mronstrom@mysql.com" <> Date: Wed, 4 May 2005 10:44:11 +0200 Subject: [PATCH 3/7] Silly mistake, forgot return :( --- sql/bitvector.h | 3 ++- sql/handler.cc | 63 ++++++++++++++++++++++++++++++++++++------------- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/sql/bitvector.h b/sql/bitvector.h index 78def21df64..4d3e8982007 100644 --- a/sql/bitvector.h +++ b/sql/bitvector.h @@ -270,7 +270,8 @@ public: bool get_bit(size_t pos) const { - (bool)(*(uchar*)(m_data + (pos >> 3))) & (uchar)(1 << (pos & 0x7U)); + return (bool)(*(uchar*)(m_data + (pos >> 3))) & + (uchar)(1 << (pos & 0x7U)); }; bool operator==(bitvector const& rhs) const diff --git a/sql/handler.cc b/sql/handler.cc index 8bd89888071..c00f79c2995 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1345,12 +1345,13 @@ int handler::ha_open(const char *name, int mode, int test_if_locked) int handler::ha_initialise() { + DBUG_ENTER("ha_initialise"); if (table && table->s->fields && ha_allocate_read_write_set(table->s->fields)) { - return TRUE; + DBUG_RETURN(TRUE); } - return FALSE; + DBUG_RETURN(FALSE); } int handler::ha_allocate_read_write_set(ulong no_fields) @@ -1375,9 +1376,11 @@ int handler::ha_allocate_read_write_set(ulong no_fields) void handler::ha_deallocate_read_write_set() { + DBUG_ENTER("ha_deallocate_read_write_set"); delete read_set; delete write_set; read_set=write_set=0; + DBUG_VOID_RETURN; } void handler::ha_clear_all_set() @@ -1392,21 +1395,21 @@ void handler::ha_clear_all_set() void handler::ha_set_all_bits_in_read_set() { - DBUG_ENTER("handler::ha_set_all_bits_in_read_set"); + DBUG_ENTER("ha_set_all_bits_in_read_set"); read_set->set_all(); DBUG_VOID_RETURN; } void handler::ha_set_all_bits_in_write_set() { - DBUG_ENTER("handler::ha_set_all_bits_in_write_set"); + DBUG_ENTER("ha_set_all_bits_in_write_set"); write_set->set_all(); DBUG_VOID_RETURN; } void handler::ha_set_bit_in_read_set(uint fieldnr) { - DBUG_ENTER("handler::ha_set_bit_in_read_set"); + DBUG_ENTER("ha_set_bit_in_read_set"); DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); read_set->set_bit((size_t)fieldnr); DBUG_VOID_RETURN; @@ -1414,7 +1417,7 @@ void handler::ha_set_bit_in_read_set(uint fieldnr) void handler::ha_clear_bit_in_read_set(uint fieldnr) { - DBUG_ENTER("handler::ha_clear_bit_in_read_set"); + DBUG_ENTER("ha_clear_bit_in_read_set"); DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); read_set->clear_bit((size_t)fieldnr); DBUG_VOID_RETURN; @@ -1422,7 +1425,7 @@ void handler::ha_clear_bit_in_read_set(uint fieldnr) void handler::ha_set_bit_in_write_set(uint fieldnr) { - DBUG_ENTER("handler::ha_set_bit_in_write_set"); + DBUG_ENTER("ha_set_bit_in_write_set"); DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); write_set->set_bit((size_t)fieldnr); DBUG_VOID_RETURN; @@ -1430,7 +1433,7 @@ void handler::ha_set_bit_in_write_set(uint fieldnr) void handler::ha_clear_bit_in_write_set(uint fieldnr) { - DBUG_ENTER("handler::ha_clear_bit_in_write_set"); + DBUG_ENTER("ha_clear_bit_in_write_set"); DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); write_set->clear_bit((size_t)fieldnr); DBUG_VOID_RETURN; @@ -1438,52 +1441,78 @@ void handler::ha_clear_bit_in_write_set(uint fieldnr) void handler::ha_set_bit_in_rw_set(uint fieldnr, bool write_op) { - if (!write_op) + DBUG_ENTER("ha_set_bit_in_rw_set"); + if (!write_op) { + DBUG_PRINT("info", ("Set bit in read set")); read_set->set_bit((size_t)fieldnr); + } else + { + DBUG_PRINT("info", ("Set bit in write set")); write_set->set_bit((size_t)fieldnr); + } } bool handler::ha_get_bit_in_read_set(uint fieldnr) { - read_set->get_bit((size_t)fieldnr); + bool bit_set=read_set->get_bit((size_t)fieldnr); + DBUG_ENTER("ha_get_bit_in_read_set"); + DBUG_PRINT("info", ("bit %u = %u", fieldnr, bit_set)); + DBUG_RETURN(bit_set); } bool handler::ha_get_bit_in_write_set(uint fieldnr) { - write_set->get_bit((size_t)fieldnr); + bool bit_set=write_set->get_bit((size_t)fieldnr); + DBUG_ENTER("ha_get_bit_in_write_set"); + DBUG_PRINT("info", ("bit %u = %u", fieldnr, bit_set)); + DBUG_RETURN(bit_set); } bool handler::ha_get_all_bit_in_read_set() { - return read_set->get_all_bits_set(); + bool bit_set=read_set->get_all_bits_set(); + DBUG_ENTER("ha_get_all_bit_in_read_set"); + DBUG_PRINT("info", ("all bits set = %u", bit_set)); + DBUG_RETURN(bit_set); } bool handler::ha_get_all_bit_in_read_clear() { - return read_set->get_all_bits_clear(); + bool bit_set=read_set->get_all_bits_clear(); + DBUG_ENTER("ha_get_all_bit_in_read_clear"); + DBUG_PRINT("info", ("all bits clear = %u", bit_set)); + DBUG_RETURN(bit_set); } bool handler::ha_get_all_bit_in_write_set() { - return write_set->get_all_bits_set(); + bool bit_set=write_set->get_all_bits_set(); + DBUG_ENTER("ha_get_all_bit_in_write_set"); + DBUG_PRINT("info", ("all bits set = %u", bit_set)); + DBUG_RETURN(bit_set); } bool handler::ha_get_all_bit_in_write_clear() { - return write_set->get_all_bits_clear(); + bool bit_set=write_set->get_all_bits_clear(); + DBUG_ENTER("ha_get_all_bit_in_write_clear"); + DBUG_PRINT("info", ("all bits clear = %u", bit_set)); + DBUG_RETURN(bit_set); } int handler::ha_retrieve_all_cols() { + DBUG_ENTER("handler::ha_retrieve_all_cols"); read_set->set_all(); - return 0; + DBUG_RETURN(0); } int handler::ha_retrieve_all_pk() { + DBUG_ENTER("ha_retrieve_all_pk"); ha_set_primary_key_in_read_set(); - return 0; + DBUG_RETURN(0); } void handler::ha_set_primary_key_in_read_set() From abec3ade2656cb346a335890f658034a11ed5c2f Mon Sep 17 00:00:00 2001 From: "mronstrom@mysql.com" <> Date: Thu, 5 May 2005 10:17:09 +0200 Subject: [PATCH 4/7] WL 1682: Divide bitvector into .cc and .h file --- sql/Makefile.am | 1 + sql/bitvector.cc | 84 +++++++++++++-------------- sql/bitvector.h | 147 +++++------------------------------------------ sql/handler.cc | 1 + 4 files changed, 57 insertions(+), 176 deletions(-) diff --git a/sql/Makefile.am b/sql/Makefile.am index aabe7c08f0f..50cd18b816e 100644 --- a/sql/Makefile.am +++ b/sql/Makefile.am @@ -91,6 +91,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \ sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \ slave.cc sql_repl.cc rpl_filter.cc \ sql_union.cc sql_derived.cc \ + bitvector.cc \ client.c sql_client.cc mini_client_errors.c pack.c\ stacktrace.c repl_failsafe.h repl_failsafe.cc \ sql_olap.cc sql_view.cc \ diff --git a/sql/bitvector.cc b/sql/bitvector.cc index d50ad7df33b..219d34c5920 100644 --- a/sql/bitvector.cc +++ b/sql/bitvector.cc @@ -120,7 +120,7 @@ uint bitvector::get_first_bit_set() return MYSQL_NO_BIT_FOUND; } -uint bitvector::get_first_bit_unset() +uint bitvector::get_first_bit_clear() { uchar *byte_ptr; uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k; @@ -154,41 +154,6 @@ uint bitvector::get_first_bit_unset() } #ifdef TEST_BITVECTOR - -int main() -{ - int i; - for (i= 0; i < 4096; i++) - if (do_test(i)) - return -1; - return 0; -} - -bool do_test(uint bitsize) -{ - bitvector *bv; - bv = new bitvector; - bv->init(bitsize); - if (test_set_get_clear_bit(bv,bitsize)) - return TRUE; - if (test_flip_bit(bv,bitsize)) - return TRUE; - if (test_operators(bv,bitsize)) - return TRUE; - if (test_get_all_bits(bvbitsize)) - return TRUE; - if (test_compare_operators(bv,bitsize)) - return TRUE; - if (test_count_bits_set(bv,bitsize)) - return TRUE; - if (test_get_first_bit(bv,bitsize)) - return TRUE; - if (test_get_next_bit(bv,bitsize)) - return TRUE; - printf("OK"); - return FALSE; -} - uint get_rand_bit(uint bitsize) { return (rand() % bitsize); @@ -201,7 +166,7 @@ bool test_set_get_clear_bit(bitvector *bv, uint bitsize) for (i=0; i < no_loops; i++) { test_bit= get_rand_bit(bitsize); - bv->set_bit(test_bit) + bv->set_bit(test_bit); if (!bv->get_bit(test_bit)) goto error1; bv->clear_bit(test_bit); @@ -219,12 +184,12 @@ error2: bool test_flip_bit(bitvector *bv, uint bitsize) { - uint i test_bit; + uint i, test_bit; uint no_loops= bitsize > 128 ? 128 : bitsize; for (i=0; i < no_loops; i++) { test_bit= get_rand_bit(bitsize); - bv->flip_bit(test_bit) + bv->flip_bit(test_bit); if (!bv->get_bit(test_bit)) goto error1; bv->flip_bit(test_bit); @@ -284,7 +249,7 @@ bool test_compare_operators(bitvector *bv, uint bitsize) bool test_count_bits_set(bitvector *bv, uint bitsize) { - uint i, bit_count=0; + uint i, bit_count=0, test_bit; uint no_loops= bitsize > 128 ? 128 : bitsize; for (i=0; i < no_loops; i++) { @@ -296,9 +261,9 @@ bool test_count_bits_set(bitvector *bv, uint bitsize) } } if (bit_count==0 && bitsize > 0) - error1; + goto error1; if (bv->no_bits_set() != bit_count) - error2; + goto error2; return FALSE; error1: printf("No bits set bitsize = %u", bitsize); @@ -317,4 +282,39 @@ bool test_get_next_bit(bitvector *bv, uint bitsize) { return FALSE; } + +bool do_test(uint bitsize) +{ + bitvector *bv; + bv = new bitvector; + bv->init(bitsize); + if (test_set_get_clear_bit(bv,bitsize)) + return TRUE; + if (test_flip_bit(bv,bitsize)) + return TRUE; + if (test_operators(bv,bitsize)) + return TRUE; + if (test_get_all_bits(bv, bitsize)) + return TRUE; + if (test_compare_operators(bv,bitsize)) + return TRUE; + if (test_count_bits_set(bv,bitsize)) + return TRUE; + if (test_get_first_bit(bv,bitsize)) + return TRUE; + if (test_get_next_bit(bv,bitsize)) + return TRUE; + printf("OK"); + return FALSE; +} + +int main() +{ + int i; + for (i= 0; i < 4096; i++) + if (do_test(i)) + return -1; + return 0; +} + #endif diff --git a/sql/bitvector.h b/sql/bitvector.h index 4d3e8982007..bb7a1d6c3b9 100644 --- a/sql/bitvector.h +++ b/sql/bitvector.h @@ -85,49 +85,7 @@ private: return ((bits + 31) >> 5) << 2; } - void create_last_word_mask() - { - - /* Get the number of used bits (1..8) in the last byte */ - unsigned int const used= 1U + ((size()-1U) & 0x7U); - - /* - * Create a mask with the upper 'unused' bits set and the lower 'used' - * bits clear. The bits within each byte is stored in big-endian order. - */ - unsigned char const mask= (~((1 << used) - 1)) & 255; - last_word_ptr= (uint32*)(m_data+((bytes()-1U)>>2)); - - /* - The first bytes are to be set to zero since they represent real bits - in the bitvector. The last bytes are set to 0xFF since they represent - bytes not used by the bitvector. Finally the last byte contains bits - as set by the mask above. - */ - - unsigned char *ptr= (unsigned char*)&last_word_mask; - switch (bytes()&3) - { - case 1: - last_word_mask= ~0U; - ptr[0]= mask; - return; - case 2: - last_word_mask= ~0U; - ptr[0]= 0; - ptr[1]= mask; - return; - case 3: - last_word_mask= 0U; - ptr[2]= mask; - ptr[3]= 0xFFU; - return; - case 0: - last_word_mask= 0U; - ptr[3]= mask; - return; - } - } + void create_last_word_mask(); inline void tidy_last_word() { @@ -181,19 +139,18 @@ public: my_free((char*)m_data, MYF(0)); } - int init(size_t size) - { - DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); - m_size= size; - m_data= (uchar*)my_malloc(byte_size_word_aligned(size), MYF(0)); - if (m_data) - { - create_last_word_mask(); - clear_all(); - return FALSE; - } - return TRUE; - } + /* + Allocate memory to the bitvector and create last word mask + and clear all bits in the bitvector. + */ + int init(size_t size); + + /* Get number of bits set in the bitvector */ + uint no_bits_set(); + /* Get first bit set/clear in bitvector */ + uint get_first_bit_set(); + uint get_first_bit_clear(); + /* Swap the guts of this instance with another instance. */ void swap(bitvector& other) @@ -332,84 +289,6 @@ public: return *this; } - uint no_bits_set() - { - uint no_bytes= bytes(), res=0, i; - uchar *ptr= m_data; - *last_word_ptr^=last_word_mask; //Reset last bits to zero - for (i=0; i< no_bytes; i++, ptr++) - res+=my_count_bits_ushort(*ptr); - *last_word_ptr^=last_word_mask; //Set last bits to one again - return res; - } - - uint get_first_bit_set() - { - uchar *byte_ptr; - uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k; - for (i=0; data_ptr <= last_word_ptr; data_ptr++, i++) - { - if (*data_ptr) - { - byte_ptr= (uchar*)data_ptr; - for (j=0; j < 4; j++, byte_ptr++) - { - if (*byte_ptr) - { - for (k=0; k < 8; k++) - { - if (*byte_ptr & (1 << k)) - { - bit_found= (i << 5) + (j << 3) + k; - if (bit_found == m_size) - return MYSQL_NO_BIT_FOUND; - else - return bit_found; - } - } - DBUG_ASSERT(1); - } - } - DBUG_ASSERT(1); - } - } - return MYSQL_NO_BIT_FOUND; - } - - uint get_first_bit_unset() - { - uchar *byte_ptr; - uint32 *data_ptr= (uint32*)data(), bit_found,i,j,k; - for (i=0; data_ptr <= last_word_ptr; data_ptr++, i++) - { - if (*data_ptr != 0xFFFFFFFF) - { - byte_ptr= (uchar*)data_ptr; - for (j=0; j < 4; j++, byte_ptr++) - { - if (*byte_ptr != 0xFF) - { - for (k=0; k < 8; k++) - { - if (!(*byte_ptr & (1 << k))) - { - bit_found= (i << 5) + (j << 3) + k; - if (bit_found == m_size) - return MYSQL_NO_BIT_FOUND; - else - return bit_found; - } - } - DBUG_ASSERT(1); - } - } - DBUG_ASSERT(1); - } - } - return MYSQL_NO_BIT_FOUND; - } - - private: size_t m_size; uint32 last_word_mask; diff --git a/sql/handler.cc b/sql/handler.cc index c00f79c2995..229fe4ccc18 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1451,6 +1451,7 @@ void handler::ha_set_bit_in_rw_set(uint fieldnr, bool write_op) DBUG_PRINT("info", ("Set bit in write set")); write_set->set_bit((size_t)fieldnr); } + DBUG_VOID_RETURN; } bool handler::ha_get_bit_in_read_set(uint fieldnr) From e39f328e443a9e2c54b2704aae8501635cf446f2 Mon Sep 17 00:00:00 2001 From: "mronstrom@mysql.com" <> Date: Thu, 5 May 2005 15:22:47 +0200 Subject: [PATCH 5/7] After test on Mac OS X fixes --- sql/bitvector.cc | 48 +++++++++++++++++++++++++++++++++++++----------- sql/bitvector.h | 24 +++++++++++++++++------- 2 files changed, 54 insertions(+), 18 deletions(-) diff --git a/sql/bitvector.cc b/sql/bitvector.cc index 219d34c5920..861cff2c9bb 100644 --- a/sql/bitvector.cc +++ b/sql/bitvector.cc @@ -29,7 +29,8 @@ void bitvector::create_last_word_mask() * bits clear. The bits within each byte is stored in big-endian order. */ unsigned char const mask= (~((1 << used) - 1)) & 255; - last_word_ptr= (uint32*)(m_data+((bytes()-1U)>>2)); + unsigned int byte_no= ((bytes()-1)) & ~3U; + last_word_ptr= (uint32*)&m_data[byte_no]; /* The first bytes are to be set to zero since they represent real bits @@ -65,6 +66,7 @@ void bitvector::create_last_word_mask() int bitvector::init(size_t size) { DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); + DBUG_ASSERT(size > 0); m_size= size; m_data= (uchar*)my_malloc(byte_size_word_aligned(size), MYF(0)); if (m_data) @@ -289,32 +291,56 @@ bool do_test(uint bitsize) bv = new bitvector; bv->init(bitsize); if (test_set_get_clear_bit(bv,bitsize)) - return TRUE; + goto error; + bv->clear_all(); if (test_flip_bit(bv,bitsize)) - return TRUE; + goto error; + bv->clear_all(); if (test_operators(bv,bitsize)) - return TRUE; + goto error; + bv->clear_all(); if (test_get_all_bits(bv, bitsize)) - return TRUE; + goto error; + bv->clear_all(); if (test_compare_operators(bv,bitsize)) - return TRUE; + goto error; + bv->clear_all(); if (test_count_bits_set(bv,bitsize)) - return TRUE; + goto error; + bv->clear_all(); if (test_get_first_bit(bv,bitsize)) - return TRUE; + goto error; + bv->clear_all(); if (test_get_next_bit(bv,bitsize)) - return TRUE; - printf("OK"); + goto error; + delete bv; return FALSE; +error: + delete bv; + printf("\n"); + return TRUE; } int main() { int i; - for (i= 0; i < 4096; i++) + for (i= 1; i < 4096; i++) if (do_test(i)) return -1; + printf("OK\n"); return 0; } +/* +Compile by using the below on a compiled clone +g++ -DHAVE_CONFIG_H -I. -I. -I.. -I../include -I../regex -I. -I../include +-g -fno-omit-frame-pointer -fno-common -felide-constructors -fno-exceptions +-fno-rtti -fno-implicit-templates -fno-exceptions -fno-rtti +-DUSE_MYSYS_NEW -DDEFINE_CXA_PURE_VIRTUAL -DHAVE_DARWIN_THREADS +-D_P1003_1B_VISIBLE -DTEST_BITVECTOR -DSIGNAL_WITH_VIO_CLOSE +-DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT -o bitvector.o +-c bitvector.cc +g++ -o bitvector bitvector.o -L../mysys -lmysys -L../dbug -L../strings +-lmystrings -ldbug +*/ #endif diff --git a/sql/bitvector.h b/sql/bitvector.h index bb7a1d6c3b9..2a33e1858f1 100644 --- a/sql/bitvector.h +++ b/sql/bitvector.h @@ -177,8 +177,8 @@ public: bool get_all_bits_clear() { - uint32 *data_ptr= (uint32*)&m_data[0]; - if (*last_word_ptr ^ last_word_mask) + uint32 *data_ptr= (uint32*)m_data; + if (*last_word_ptr != last_word_mask) return FALSE; for (; data_ptr < last_word_ptr; data_ptr++) if (*data_ptr) @@ -204,7 +204,8 @@ public: /* Set a bit to a value */ void set_bit(size_t pos) { - *(uchar*)(m_data + (pos >> 3)) |= (uchar)(1 << (pos & 0x7U)); + DBUG_ASSERT(pos < m_size); + m_data[pos>>3]|= (uchar)(1 << (pos & 0x7U)); } /* Reset (clear) all bits in the vector */ @@ -217,18 +218,27 @@ public: /* Reset one bit in the vector */ void clear_bit(size_t pos) { - *(u_char*)(m_data + (pos >> 3)) &= (u_char)(~(1 << (pos & 0x7U))); + DBUG_ASSERT(pos < m_size); + m_data[pos>>3]&= ~(uchar)(1 << (pos & 0x7U)); } void flip_bit(size_t pos) { - *(uchar*)(m_data + (pos >> 3)) ^= (uchar)(1 << (pos & 0x7U)); + DBUG_ASSERT(pos < m_size); + m_data[pos>>3]^= (uchar)(1 << (pos & 0x7U)); } bool get_bit(size_t pos) const { - return (bool)(*(uchar*)(m_data + (pos >> 3))) & - (uchar)(1 << (pos & 0x7U)); + DBUG_ASSERT(pos < m_size); + /* + !! provides the most effective implementation of conversion to + bool + */ + uchar *byte_word= m_data + (pos >> 3); + uchar mask= 1 << (pos & 0x7U); + bool ret_value= !!(*byte_word & mask); + return ret_value; }; bool operator==(bitvector const& rhs) const From b4ab00df62af55b5f308ad93db4ef3ebb11e4e2b Mon Sep 17 00:00:00 2001 From: "mronstrom@mysql.com" <> Date: Sat, 7 May 2005 10:00:25 +0200 Subject: [PATCH 6/7] WL 1682: Bitvector for updated/read fields in handler interface Fixed clear issues of bitvector and memory allocation issues --- sql/bitvector.cc | 3 ++- sql/bitvector.h | 14 +++++--------- sql/handler.cc | 5 +++-- sql/handler.h | 10 +++++++++- sql/lock.cc | 1 - sql/opt_range.cc | 5 ++++- sql/sql_base.cc | 3 +-- sql/sql_insert.cc | 2 +- sql/sql_select.cc | 2 +- sql/sql_table.cc | 1 + sql/sql_update.cc | 4 ++-- 11 files changed, 29 insertions(+), 21 deletions(-) diff --git a/sql/bitvector.cc b/sql/bitvector.cc index 861cff2c9bb..0fcae84abc2 100644 --- a/sql/bitvector.cc +++ b/sql/bitvector.cc @@ -16,6 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include "mysql_priv.h" #include void bitvector::create_last_word_mask() @@ -68,7 +69,7 @@ int bitvector::init(size_t size) DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); DBUG_ASSERT(size > 0); m_size= size; - m_data= (uchar*)my_malloc(byte_size_word_aligned(size), MYF(0)); + m_data= (uchar*)sql_alloc(byte_size_word_aligned(size)); if (m_data) { create_last_word_mask(); diff --git a/sql/bitvector.h b/sql/bitvector.h index 2a33e1858f1..f08f782879f 100644 --- a/sql/bitvector.h +++ b/sql/bitvector.h @@ -70,7 +70,7 @@ namespace /* Number returned when no bit found */ #define MYSQL_NO_BIT_FOUND 1 << 20 -class bitvector +class bitvector :public Sql_alloc { private: /* Compute the number of bytes required to store 'bits' bits in an array. */ @@ -100,7 +100,7 @@ public: explicit bitvector(size_t size, bool value= false) : m_size(size), - m_data((uchar*)my_malloc(byte_size_word_aligned(size), MYF(0))) + m_data((uchar*)sql_alloc(byte_size_word_aligned(size))) { DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); create_last_word_mask(); @@ -115,7 +115,7 @@ public: */ explicit bitvector(byte const* data, size_t size) : m_size(size), - m_data((uchar*)my_malloc(byte_size_word_aligned(size), MYF(0))) + m_data((uchar*)sql_alloc(byte_size_word_aligned(size))) { DBUG_ASSERT(size < MYSQL_NO_BIT_FOUND); create_last_word_mask(); @@ -125,7 +125,7 @@ public: bitvector(bitvector const& other) : m_size(other.size()), - m_data((uchar*)my_malloc(other.bytes(), MYF(0))) + m_data((uchar*)sql_alloc(other.bytes())) { DBUG_ASSERT(m_size < MYSQL_NO_BIT_FOUND); create_last_word_mask(); @@ -133,11 +133,7 @@ public: tidy_last_word(); } - ~bitvector() - { - if (m_data) - my_free((char*)m_data, MYF(0)); - } + ~bitvector() {} /* Allocate memory to the bitvector and create last word mask diff --git a/sql/handler.cc b/sql/handler.cc index 229fe4ccc18..97e2a790a2d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1443,12 +1443,13 @@ void handler::ha_set_bit_in_rw_set(uint fieldnr, bool write_op) { DBUG_ENTER("ha_set_bit_in_rw_set"); if (!write_op) { - DBUG_PRINT("info", ("Set bit in read set")); + DBUG_PRINT("info", ("Set bit %u in read set", fieldnr)); read_set->set_bit((size_t)fieldnr); } else { - DBUG_PRINT("info", ("Set bit in write set")); + DBUG_PRINT("info", ("Set bit %u in read and write set", fieldnr)); + read_set->set_bit((size_t)fieldnr); write_set->set_bit((size_t)fieldnr); } DBUG_VOID_RETURN; diff --git a/sql/handler.h b/sql/handler.h index 31bd5978e1c..b463e423e86 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -443,6 +443,8 @@ class handler :public Sql_alloc virtual int rnd_init(bool scan) =0; virtual int rnd_end() { return 0; } +private: + virtual int reset() { return extra(HA_EXTRA_RESET); } public: byte *ref; /* Pointer to current row */ byte *dupp_ref; /* Pointer to dupp row */ @@ -562,6 +564,13 @@ public: inited=NONE; DBUG_RETURN(rnd_end()); } + int ha_reset() + { + DBUG_ENTER("ha_reset"); + ha_clear_all_set(); + DBUG_RETURN(reset()); + } + /* this is necessary in many places, e.g. in HANDLER command */ int ha_index_or_rnd_end() { @@ -664,7 +673,6 @@ public: { return 0; } virtual int extra_opt(enum ha_extra_function operation, ulong cache_size) { return extra(operation); } - virtual int reset() { return extra(HA_EXTRA_RESET); } virtual int external_lock(THD *thd, int lock_type) { return 0; } virtual void unlock_row() {} virtual int start_stmt(THD *thd) {return 0;} diff --git a/sql/lock.cc b/sql/lock.cc index bb7d1f7163b..ac527ca84f8 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -179,7 +179,6 @@ static int lock_external(THD *thd, TABLE **tables, uint count) ((*tables)->reginfo.lock_type >= TL_READ && (*tables)->reginfo.lock_type <= TL_READ_NO_INSERT)) lock_type=F_RDLCK; - (*tables)->file->ha_clear_all_set(); if ((error=(*tables)->file->external_lock(thd,lock_type))) { print_lock_error(error, (*tables)->file->table_type()); diff --git a/sql/opt_range.cc b/sql/opt_range.cc index b83e4f369af..fbb7ac80c28 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -778,9 +778,10 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT() { DBUG_PRINT("info", ("Freeing separate handler %p (free=%d)", file, free_file)); - file->reset(); + file->ha_reset(); file->external_lock(current_thd, F_UNLCK); file->close(); + delete file; } } delete_dynamic(&ranges); /* ranges are allocated in alloc */ @@ -956,6 +957,8 @@ int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler) DBUG_RETURN(0); failure: + if (file) + delete file; file= save_file; DBUG_RETURN(1); } diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 63fcf2b70b3..7c94b6004be 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -563,7 +563,7 @@ bool close_thread_table(THD *thd, TABLE **table_ptr) else { // Free memory and reset for next loop - table->file->reset(); + table->file->ha_reset(); } table->in_use=0; if (unused_tables) @@ -1954,7 +1954,6 @@ static bool check_lock_and_start_stmt(THD *thd, TABLE *table, my_error(ER_TABLE_NOT_LOCKED_FOR_WRITE, MYF(0),table->alias); DBUG_RETURN(1); } - table->file->ha_clear_all_set(); if ((error=table->file->start_stmt(thd))) { table->file->print_error(error,MYF(0)); diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc index 512fdb90ef9..a3062582367 100644 --- a/sql/sql_insert.cc +++ b/sql/sql_insert.cc @@ -1959,7 +1959,7 @@ select_insert::~select_insert() if (table) { table->next_number_field=0; - table->file->reset(); + table->file->ha_reset(); } thd->count_cuted_fields= CHECK_FIELD_IGNORE; thd->abort_on_warning= 0; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0d5efb99ce6..a9916fbfcf7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8870,8 +8870,8 @@ bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param, (void) new_table.file->close(); err1: new_table.file->delete_table(new_table.s->table_name); - delete new_table.file; err2: + delete new_table.file; thd->proc_info=save_proc_info; DBUG_RETURN(1); } diff --git a/sql/sql_table.cc b/sql/sql_table.cc index cb98bba5e4d..37814782018 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -1633,6 +1633,7 @@ bool mysql_create_table(THD *thd,const char *db, const char *table_name, end: VOID(pthread_mutex_unlock(&LOCK_open)); start_waiting_global_read_lock(thd); + delete file; thd->proc_info="After create"; DBUG_RETURN(error); } diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 8cb2cbef684..bd9e230514b 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -652,7 +652,7 @@ bool mysql_multi_update_prepare(THD *thd) leaves= lex->select_lex.leaf_tables; if ((lex->select_lex.no_wrap_view_item= 1, - res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), + res= setup_fields(thd, 0, table_list, *fields, 2, 0, 0), lex->select_lex.no_wrap_view_item= 0, res)) DBUG_RETURN(TRUE); @@ -769,7 +769,7 @@ bool mysql_multi_update_prepare(THD *thd) if (setup_tables(thd, table_list, &lex->select_lex.where, &lex->select_lex.leaf_tables, FALSE, FALSE) || (lex->select_lex.no_wrap_view_item= 1, - res= setup_fields(thd, 0, table_list, *fields, 1, 0, 0), + res= setup_fields(thd, 0, table_list, *fields, 2, 0, 0), lex->select_lex.no_wrap_view_item= 0, res)) DBUG_RETURN(TRUE); From cf642995f6e054f1d47d1ed4115a93a01c458336 Mon Sep 17 00:00:00 2001 From: "mronstrom@mysql.com" <> Date: Thu, 12 May 2005 11:20:50 +0200 Subject: [PATCH 7/7] Many fixes --- include/my_bitmap.h | 55 ++- mysys/my_bitmap.c | 951 +++++++++++++++++++++++++++++++++++--------- sql/handler.cc | 139 +------ sql/handler.h | 117 +++++- sql/opt_range.cc | 11 +- sql/sql_bitmap.h | 11 +- sql/sql_select.cc | 10 +- 7 files changed, 950 insertions(+), 344 deletions(-) diff --git a/include/my_bitmap.h b/include/my_bitmap.h index 4caa3b85456..a5df6389488 100644 --- a/include/my_bitmap.h +++ b/include/my_bitmap.h @@ -21,10 +21,13 @@ #define MY_BIT_NONE (~(uint) 0) + typedef struct st_bitmap { uchar *bitmap; - uint bitmap_size; /* number of bytes occupied by the above */ + uint bitmap_size; /* number of bits occupied by the above */ + uint32 last_word_mask; + uint32 *last_word_ptr; /* mutex will be acquired for the duration of each bitmap operation if thread_safe flag in bitmap_init was set. Otherwise, we optimize by not @@ -38,30 +41,60 @@ typedef struct st_bitmap #ifdef __cplusplus extern "C" { #endif -extern my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2); extern my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread_safe); extern my_bool bitmap_is_clear_all(const MY_BITMAP *map); extern my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size); -extern my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit); extern my_bool bitmap_is_set_all(const MY_BITMAP *map); extern my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2); extern uint bitmap_set_next(MY_BITMAP *map); extern uint bitmap_get_first(const MY_BITMAP *map); +extern uint bitmap_get_first_set(const MY_BITMAP *map); extern uint bitmap_bits_set(const MY_BITMAP *map); -extern void bitmap_clear_all(MY_BITMAP *map); -extern void bitmap_clear_bit(MY_BITMAP *map, uint bitmap_bit); extern void bitmap_free(MY_BITMAP *map); -extern void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2); -extern void bitmap_set_all(MY_BITMAP *map); -extern void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit); extern void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size); +extern void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2); extern void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2); extern void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2); +extern uint bitmap_lock_set_next(MY_BITMAP *map); +extern void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit); +#ifdef NOT_USED +extern uint bitmap_lock_bits_set(const MY_BITMAP *map); +extern my_bool bitmap_lock_is_set_all(const MY_BITMAP *map); +extern uint bitmap_lock_get_first(const MY_BITMAP *map); +extern uint bitmap_lock_get_first_set(const MY_BITMAP *map); +extern my_bool bitmap_lock_is_subset(const MY_BITMAP *map1, + const MY_BITMAP *map2); +extern my_bool bitmap_lock_is_prefix(const MY_BITMAP *map, uint prefix_size); +extern my_bool bitmap_lock_is_set(const MY_BITMAP *map, uint bitmap_bit); +extern my_bool bitmap_lock_is_clear_all(const MY_BITMAP *map); +extern my_bool bitmap_lock_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2); +extern void bitmap_lock_set_all(MY_BITMAP *map); +extern void bitmap_lock_clear_all(MY_BITMAP *map); +extern void bitmap_lock_set_bit(MY_BITMAP *map, uint bitmap_bit); +extern void bitmap_lock_flip_bit(MY_BITMAP *map, uint bitmap_bit); +extern void bitmap_lock_set_prefix(MY_BITMAP *map, uint prefix_size); +extern void bitmap_lock_intersect(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_lock_subtract(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_lock_union(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_lock_xor(MY_BITMAP *map, const MY_BITMAP *map2); +extern void bitmap_lock_invert(MY_BITMAP *map); +#endif /* Fast, not thread safe, bitmap functions */ -#define bitmap_fast_set_bit(MAP, BIT) (MAP)->bitmap[(BIT) / 8] |= (1 << ((BIT) & 7)) -#define bitmap_fast_clear_bit(MAP, BIT) (MAP)->bitmap[(BIT) / 8] &= ~ (1 << ((BIT) & 7)) -#define bitmap_fast_is_set(MAP, BIT) (MAP)->bitmap[(BIT) / 8] & (1 << ((BIT) & 7)) +#define no_bytes_in_map(map) ((map->bitmap_size + 7)/8) +#define no_words_in_map(map) ((map->bitmap_size + 31)/32) +#define bytes_word_aligned(bytes) (4*((bytes + 3)/4)) +#define bitmap_set_bit(MAP, BIT) ((MAP)->bitmap[(BIT) / 8] |= (1 << ((BIT) & 7))) +#define bitmap_flip_bit(MAP, BIT) ((MAP)->bitmap[(BIT) / 8] ^= (1 << ((BIT) & 7))) +#define bitmap_clear_bit(MAP, BIT) ((MAP)->bitmap[(BIT) / 8] &= ~ (1 << ((BIT) & 7))) +#define bitmap_is_set(MAP, BIT) ((MAP)->bitmap[(BIT) / 8] & (1 << ((BIT) & 7))) +#define bitmap_cmp(MAP1, MAP2) \ + (memcmp((MAP1)->bitmap, (MAP2)->bitmap, 4*no_words_in_map((MAP1)))==0) +#define bitmap_clear_all(MAP) \ + memset((MAP)->bitmap, 0, 4*no_words_in_map((MAP))); \ + *(MAP)->last_word_ptr|= (MAP)->last_word_mask +#define bitmap_set_all(MAP) \ + (memset((MAP)->bitmap, 0xFF, 4*no_words_in_map((MAP)))) #ifdef __cplusplus } diff --git a/mysys/my_bitmap.c b/mysys/my_bitmap.c index c0eb6f15548..ca8964b81e5 100644 --- a/mysys/my_bitmap.c +++ b/mysys/my_bitmap.c @@ -40,6 +40,50 @@ #include #include +void create_last_word_mask(MY_BITMAP *map) +{ + /* Get the number of used bits (1..8) in the last byte */ + unsigned int const used= 1U + ((map->bitmap_size-1U) & 0x7U); + + /* + * Create a mask with the upper 'unused' bits set and the lower 'used' + * bits clear. The bits within each byte is stored in big-endian order. + */ + unsigned char const mask= (~((1 << used) - 1)) & 255; + unsigned int byte_no= ((no_bytes_in_map(map)-1)) & ~3U; + map->last_word_ptr= (uint32*)&map->bitmap[byte_no]; + + /* + The first bytes are to be set to zero since they represent real bits + in the bitvector. The last bytes are set to 0xFF since they represent + bytes not used by the bitvector. Finally the last byte contains bits + as set by the mask above. + */ + + unsigned char *ptr= (unsigned char*)&map->last_word_mask; + switch (no_bytes_in_map(map)&3) + { + case 1: + map->last_word_mask= ~0U; + ptr[0]= mask; + return; + case 2: + map->last_word_mask= ~0U; + ptr[0]= 0; + ptr[1]= mask; + return; + case 3: + map->last_word_mask= 0U; + ptr[2]= mask; + ptr[3]= 0xFFU; + return; + case 0: + map->last_word_mask= 0U; + ptr[3]= mask; + return; + } +} + static inline void bitmap_lock(MY_BITMAP *map) { #ifdef THREAD @@ -61,16 +105,15 @@ my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, my_bool thread_safe) { DBUG_ENTER("bitmap_init"); - - DBUG_ASSERT((bitmap_size & 7) == 0); - bitmap_size/=8; + DBUG_ASSERT(bitmap_size > 0); if (!(map->bitmap=buf) && !(map->bitmap= (uchar*) my_malloc(bitmap_size + (thread_safe ? sizeof(pthread_mutex_t) : 0), - MYF(MY_WME | MY_ZEROFILL)))) + MYF(MY_WME)))) return 1; map->bitmap_size=bitmap_size; + create_last_word_mask(map); #ifdef THREAD if (thread_safe) { @@ -80,6 +123,7 @@ my_bool bitmap_init(MY_BITMAP *map, uchar *buf, uint bitmap_size, else map->mutex=0; #endif + bitmap_clear_all(map); DBUG_RETURN(0); } @@ -100,184 +144,113 @@ void bitmap_free(MY_BITMAP *map) } -void bitmap_set_bit(MY_BITMAP *map, uint bitmap_bit) -{ - DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); - bitmap_lock(map); - bitmap_fast_set_bit(map, bitmap_bit); - bitmap_unlock(map); -} - - uint bitmap_set_next(MY_BITMAP *map) { - uchar *bitmap=map->bitmap; - uint bit_found = MY_BIT_NONE; - uint bitmap_size=map->bitmap_size*8; - uint i; - + uint bit_found; DBUG_ASSERT(map->bitmap); - bitmap_lock(map); - for (i=0; i < bitmap_size ; i++, bitmap++) - { - if (*bitmap != 0xff) - { /* Found slot with free bit */ - uint b; - for (b=0; ; b++) - { - if (!(*bitmap & (1 << b))) - { - *bitmap |= 1<bitmap && bitmap_bit < map->bitmap_size*8); - bitmap_lock(map); - bitmap_fast_clear_bit(map, bitmap_bit); - bitmap_unlock(map); -} - - void bitmap_set_prefix(MY_BITMAP *map, uint prefix_size) { uint prefix_bytes, prefix_bits; DBUG_ASSERT(map->bitmap && - (prefix_size <= map->bitmap_size*8 || prefix_size == (uint) ~0)); - bitmap_lock(map); - set_if_smaller(prefix_size, map->bitmap_size*8); + (prefix_size <= map->bitmap_size || prefix_size == (uint) ~0)); + set_if_smaller(prefix_size, map->bitmap_size); if ((prefix_bytes= prefix_size / 8)) memset(map->bitmap, 0xff, prefix_bytes); if ((prefix_bits= prefix_size & 7)) map->bitmap[prefix_bytes++]= (1 << prefix_bits)-1; - if (prefix_bytes < map->bitmap_size) - bzero(map->bitmap+prefix_bytes, map->bitmap_size-prefix_bytes); - bitmap_unlock(map); -} - - -void bitmap_clear_all(MY_BITMAP *map) -{ - bitmap_set_prefix(map, 0); -} - - -void bitmap_set_all(MY_BITMAP *map) -{ - bitmap_set_prefix(map, ~0); + if (prefix_bytes < no_bytes_in_map(map)) + bzero(map->bitmap+prefix_bytes, no_bytes_in_map(map)-prefix_bytes); + *map->last_word_ptr|= map->last_word_mask; //Set last bits } my_bool bitmap_is_prefix(const MY_BITMAP *map, uint prefix_size) { - uint prefix_bits= prefix_size & 7, res= 0; - uchar *m= map->bitmap, *end_prefix= map->bitmap+prefix_size/8, - *end= map->bitmap+map->bitmap_size; + uint prefix_bits= prefix_size & 0x7, res; + uchar *m= map->bitmap; + uchar *end_prefix= map->bitmap+prefix_size/8; + uchar *end; + DBUG_ASSERT(map->bitmap && prefix_size <= map->bitmap_size); + end= map->bitmap+no_bytes_in_map(map); - DBUG_ASSERT(map->bitmap && prefix_size <= map->bitmap_size*8); - - bitmap_lock((MY_BITMAP *)map); while (m < end_prefix) if (*m++ != 0xff) - goto ret; + return 0; + *map->last_word_ptr^= map->last_word_mask; //Clear bits + res= 0; if (prefix_bits && *m++ != (1 << prefix_bits)-1) goto ret; while (m < end) if (*m++ != 0) goto ret; - - res=1; + res= 1; ret: - bitmap_unlock((MY_BITMAP *)map); - return res; + *map->last_word_ptr|= map->last_word_mask; //Set bits again + return res; +} + + +my_bool bitmap_is_set_all(const MY_BITMAP *map) +{ + uint32 *data_ptr= (uint32*)map->bitmap; + uint32 *end= map->last_word_ptr; + for (; data_ptr <= end; data_ptr++) + if (*data_ptr != 0xFFFFFFFF) + return FALSE; + return TRUE; } my_bool bitmap_is_clear_all(const MY_BITMAP *map) { - return bitmap_is_prefix(map, 0); -} - -my_bool bitmap_is_set_all(const MY_BITMAP *map) -{ - return bitmap_is_prefix(map, map->bitmap_size*8); -} - - -my_bool bitmap_is_set(const MY_BITMAP *map, uint bitmap_bit) -{ - DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size*8); - return bitmap_fast_is_set(map, bitmap_bit); + uint32 *data_ptr= (uint32*)map->bitmap; + uint32 *end; + if (*map->last_word_ptr != map->last_word_mask) + return FALSE; + end= map->last_word_ptr; + for (; data_ptr < end; data_ptr++) + if (*data_ptr) + return FALSE; + return TRUE; } my_bool bitmap_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2) { - uint res=0; - uchar *m1=map1->bitmap, *m2=map2->bitmap, *end; + uint32 *m1= (uint32*)map1->bitmap, *m2= (uint32*)map2->bitmap, *end; DBUG_ASSERT(map1->bitmap && map2->bitmap && map1->bitmap_size==map2->bitmap_size); - bitmap_lock((MY_BITMAP *)map1); - bitmap_lock((MY_BITMAP *)map2); - end= m1+map1->bitmap_size; + end= map1->last_word_ptr; - while (m1 < end) + while (m1 <= end) { if ((*m1++) & ~(*m2++)) - goto ret; + return 0; } - - res=1; -ret: - bitmap_unlock((MY_BITMAP *)map2); - bitmap_unlock((MY_BITMAP *)map1); - return res; -} - - -my_bool bitmap_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2) -{ - uint res; - - DBUG_ASSERT(map1->bitmap && map2->bitmap && - map1->bitmap_size==map2->bitmap_size); - bitmap_lock((MY_BITMAP *)map1); - bitmap_lock((MY_BITMAP *)map2); - - res= memcmp(map1->bitmap, map2->bitmap, map1->bitmap_size)==0; - - bitmap_unlock((MY_BITMAP *)map2); - bitmap_unlock((MY_BITMAP *)map1); - return res; + return 1; } void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2) { - uchar *to=map->bitmap, *from=map2->bitmap, *end; - uint len=map->bitmap_size, len2=map2->bitmap_size; + uint32 *to= (uint32*)map->bitmap, *from= (uint32*)map2->bitmap, *end; + uint len= no_words_in_map(map), len2 = no_words_in_map(map2); DBUG_ASSERT(map->bitmap && map2->bitmap); - bitmap_lock(map); - bitmap_lock((MY_BITMAP *)map2); end= to+min(len,len2); - + *map2->last_word_ptr^= map2->last_word_mask; //Clear last bits in map2 while (to < end) *to++ &= *from++; @@ -287,45 +260,291 @@ void bitmap_intersect(MY_BITMAP *map, const MY_BITMAP *map2) while (to < end) *to++=0; } - - bitmap_unlock((MY_BITMAP *)map2); - bitmap_unlock(map); + *map2->last_word_ptr|= map2->last_word_mask; //Set last bits in map + *map->last_word_ptr|= map->last_word_mask; //Set last bits in map2 } void bitmap_subtract(MY_BITMAP *map, const MY_BITMAP *map2) { - uchar *to=map->bitmap, *from=map2->bitmap, *end; + uint32 *to= (uint32*)map->bitmap, *from= (uint32*)map2->bitmap, *end; DBUG_ASSERT(map->bitmap && map2->bitmap && map->bitmap_size==map2->bitmap_size); - bitmap_lock(map); - bitmap_lock((MY_BITMAP *)map2); - end= to+map->bitmap_size; + end= map->last_word_ptr; - while (to < end) + while (to <= end) *to++ &= ~(*from++); - - bitmap_unlock((MY_BITMAP *)map2); - bitmap_unlock(map); + *map->last_word_ptr|= map->last_word_mask; //Set last bits again } void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2) { - uchar *to=map->bitmap, *from=map2->bitmap, *end; + uint32 *to= (uint32*)map->bitmap, *from= (uint32*)map2->bitmap, *end; DBUG_ASSERT(map->bitmap && map2->bitmap && map->bitmap_size==map2->bitmap_size); + end= map->last_word_ptr; + + while (to <= end) + *to++ |= *from++; +} + + +void bitmap_xor(MY_BITMAP *map, const MY_BITMAP *map2) +{ + uint32 *to= (uint32*)map->bitmap, *from= (uint32*)map2->bitmap, *end; + + DBUG_ASSERT(map->bitmap && map2->bitmap && + map->bitmap_size==map2->bitmap_size); + end= map->last_word_ptr; + + while (to <= end) + *to++ ^= *from++; + *map->last_word_ptr|= map->last_word_mask; //Set last bits again +} + + +void bitmap_invert(MY_BITMAP *map) +{ + uint32 *to= (uint32*)map->bitmap, *end; + + DBUG_ASSERT(map->bitmap); + end= map->last_word_ptr; + + while (to <= end) + *to++ ^= 0xFFFFFFFF; + *map->last_word_ptr|= map->last_word_mask; //Set last bits again +} + + +uint bitmap_bits_set(const MY_BITMAP *map) +{ + uchar *m= map->bitmap; + uchar *end= m + no_bytes_in_map(map); + uint res= 0; + + DBUG_ASSERT(map->bitmap); + *map->last_word_ptr^=map->last_word_mask; //Reset last bits to zero + while (m < end) + res+= my_count_bits_ushort(*m++); + *map->last_word_ptr^=map->last_word_mask; //Set last bits to one again + return res; +} + +uint bitmap_get_first_set(const MY_BITMAP *map) +{ + uchar *byte_ptr; + uint bit_found,i,j,k; + uint32 *data_ptr, *end= map->last_word_ptr; + + DBUG_ASSERT(map->bitmap); + data_ptr= (uint32*)map->bitmap; + for (i=0; data_ptr <= end; data_ptr++, i++) + { + if (*data_ptr) + { + byte_ptr= (uchar*)data_ptr; + for (j=0; ; j++, byte_ptr++) + { + if (*byte_ptr) + { + for (k=0; ; k++) + { + if (*byte_ptr & (1 << k)) + { + bit_found= (i*32) + (j*8) + k; + if (bit_found == map->bitmap_size) + return MY_BIT_NONE; + return bit_found; + } + } + DBUG_ASSERT(1); + } + } + DBUG_ASSERT(1); + } + } + return MY_BIT_NONE; +} + + +uint bitmap_get_first(const MY_BITMAP *map) +{ + uchar *byte_ptr; + uint bit_found= MY_BIT_NONE, i,j,k; + uint32 *data_ptr, *end= map->last_word_ptr; + + DBUG_ASSERT(map->bitmap); + data_ptr= (uint32*)map->bitmap; + for (i=0; data_ptr <= end; data_ptr++, i++) + { + if (*data_ptr != 0xFFFFFFFF) + { + byte_ptr= (uchar*)data_ptr; + for (j=0; ; j++, byte_ptr++) + { + if (*byte_ptr != 0xFF) + { + for (k=0; ; k++) + { + if (!(*byte_ptr & (1 << k))) + { + bit_found= (i*32) + (j*8) + k; + if (bit_found == map->bitmap_size) + return MY_BIT_NONE; + return bit_found; + } + } + DBUG_ASSERT(1); + } + } + DBUG_ASSERT(1); + } + } + return MY_BIT_NONE; +} + + +uint bitmap_lock_set_next(MY_BITMAP *map) +{ + uint bit_found; + bitmap_lock(map); + bit_found= bitmap_set_next(map); + bitmap_unlock(map); + return bit_found; +} + + +void bitmap_lock_clear_bit(MY_BITMAP *map, uint bitmap_bit) +{ + bitmap_lock(map); + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size); + bitmap_clear_bit(map, bitmap_bit); + bitmap_unlock(map); +} + + +#ifdef NOT_USED +my_bool bitmap_lock_is_prefix(const MY_BITMAP *map, uint prefix_size) +{ + my_bool res; + bitmap_lock((MY_BITMAP *)map); + res= bitmap_is_prefix(map, prefix_size); + bitmap_unlock((MY_BITMAP *)map); + return res; +} + + +void bitmap_lock_set_all(MY_BITMAP *map) +{ + bitmap_lock(map); + bitmap_set_all(map); + bitmap_unlock(map); +} + + +void bitmap_lock_clear_all(MY_BITMAP *map) +{ + bitmap_lock(map); + bitmap_clear_all(map); + bitmap_unlock(map); +} + + +void bitmap_lock_set_prefix(MY_BITMAP *map, uint prefix_size) +{ + bitmap_lock(map); + bitmap_set_prefix(map, prefix_size); + bitmap_unlock(map); +} + + +my_bool bitmap_lock_is_clear_all(const MY_BITMAP *map) +{ + uint res; + bitmap_lock((MY_BITMAP *)map); + res= bitmap_is_clear_all(map); + bitmap_unlock((MY_BITMAP *)map); + return res; +} + + +my_bool bitmap_lock_is_set_all(const MY_BITMAP *map) +{ + uint res; + bitmap_lock((MY_BITMAP *)map); + res= bitmap_is_set_all(map); + bitmap_unlock((MY_BITMAP *)map); + return res; +} + + +my_bool bitmap_lock_is_set(const MY_BITMAP *map, uint bitmap_bit) +{ + my_bool res; + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size); + bitmap_lock((MY_BITMAP *)map); + res= bitmap_is_set(map, bitmap_bit); + bitmap_unlock((MY_BITMAP *)map); + return res; +} + + +my_bool bitmap_lock_is_subset(const MY_BITMAP *map1, const MY_BITMAP *map2) +{ + uint res; + bitmap_lock((MY_BITMAP *)map1); + bitmap_lock((MY_BITMAP *)map2); + res= bitmap_is_subset(map1, map2); + bitmap_unlock((MY_BITMAP *)map2); + bitmap_unlock((MY_BITMAP *)map1); + return res; +} + + +my_bool bitmap_lock_cmp(const MY_BITMAP *map1, const MY_BITMAP *map2) +{ + uint res; + + DBUG_ASSERT(map1->bitmap && map2->bitmap && + map1->bitmap_size==map2->bitmap_size); + bitmap_lock((MY_BITMAP *)map1); + bitmap_lock((MY_BITMAP *)map2); + res= bitmap_cmp(map1, map2); + bitmap_unlock((MY_BITMAP *)map2); + bitmap_unlock((MY_BITMAP *)map1); + return res; +} + + +void bitmap_lock_intersect(MY_BITMAP *map, const MY_BITMAP *map2) +{ bitmap_lock(map); bitmap_lock((MY_BITMAP *)map2); + bitmap_intersect(map, map2); + bitmap_unlock((MY_BITMAP *)map2); + bitmap_unlock(map); +} - end= to+map->bitmap_size; - while (to < end) - *to++ |= *from++; +void bitmap_lock_subtract(MY_BITMAP *map, const MY_BITMAP *map2) +{ + bitmap_lock(map); + bitmap_lock((MY_BITMAP *)map2); + bitmap_subtract(map, map2); + bitmap_unlock((MY_BITMAP *)map2); + bitmap_unlock(map); +} + +void bitmap_lock_union(MY_BITMAP *map, const MY_BITMAP *map2) +{ + bitmap_lock(map); + bitmap_lock((MY_BITMAP *)map2); + bitmap_union(map, map2); bitmap_unlock((MY_BITMAP *)map2); bitmap_unlock(map); } @@ -338,19 +557,12 @@ void bitmap_union(MY_BITMAP *map, const MY_BITMAP *map2) RETURN Number of set bits in the bitmap. */ - -uint bitmap_bits_set(const MY_BITMAP *map) -{ - uchar *m= map->bitmap; - uchar *end= m + map->bitmap_size; - uint res= 0; - - DBUG_ASSERT(map->bitmap); +uint bitmap_lock_bits_set(const MY_BITMAP *map) +{ + uint res; bitmap_lock((MY_BITMAP *)map); - while (m < end) - { - res+= my_count_bits_ushort(*m++); - } + DBUG_ASSERT(map->bitmap); + res= bitmap_bits_set(map); bitmap_unlock((MY_BITMAP *)map); return res; } @@ -363,33 +575,418 @@ uint bitmap_bits_set(const MY_BITMAP *map) RETURN Number of first unset bit in the bitmap or MY_BIT_NONE if all bits are set. */ - -uint bitmap_get_first(const MY_BITMAP *map) +uint bitmap_lock_get_first(const MY_BITMAP *map) { - uchar *bitmap=map->bitmap; - uint bit_found = MY_BIT_NONE; - uint bitmap_size=map->bitmap_size*8; - uint i; - - DBUG_ASSERT(map->bitmap); - bitmap_lock((MY_BITMAP *)map); - for (i=0; i < bitmap_size ; i++, bitmap++) - { - if (*bitmap != 0xff) - { /* Found slot with free bit */ - uint b; - for (b=0; ; b++) - { - if (!(*bitmap & (1 << b))) - { - bit_found = (i*8)+b; - break; - } - } - break; /* Found bit */ - } - } - bitmap_unlock((MY_BITMAP *)map); - return bit_found; + uint res; + bitmap_lock((MY_BITMAP*)map); + res= bitmap_get_first(map); + bitmap_unlock((MY_BITMAP*)map); + return res; } + +uint bitmap_lock_get_first_set(const MY_BITMAP *map) +{ + uint res; + bitmap_lock((MY_BITMAP*)map); + res= bitmap_get_first_set(map); + bitmap_unlock((MY_BITMAP*)map); + return res; +} + + +void bitmap_lock_set_bit(MY_BITMAP *map, uint bitmap_bit) +{ + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size); + bitmap_lock(map); + bitmap_set_bit(map, bitmap_bit); + bitmap_unlock(map); +} + + +void bitmap_lock_flip_bit(MY_BITMAP *map, uint bitmap_bit) +{ + DBUG_ASSERT(map->bitmap && bitmap_bit < map->bitmap_size); + bitmap_lock(map); + bitmap_flip_bit(map, bitmap_bit); + bitmap_unlock(map); +} +#endif +#ifdef TEST_BITMAP +uint get_rand_bit(uint bitsize) +{ + return (rand() % bitsize); +} + +bool test_set_get_clear_bit(MY_BITMAP *map, uint bitsize) +{ + uint i, test_bit; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit= get_rand_bit(bitsize); + bitmap_set_bit(map, test_bit); + if (!bitmap_is_set(map, test_bit)) + goto error1; + bitmap_clear_bit(map, test_bit); + if (bitmap_is_set(map, test_bit)) + goto error2; + } + return FALSE; +error1: + printf("Error in set bit, bit %u, bitsize = %u", test_bit, bitsize); + return TRUE; +error2: + printf("Error in clear bit, bit %u, bitsize = %u", test_bit, bitsize); + return TRUE; +} + +bool test_flip_bit(MY_BITMAP *map, uint bitsize) +{ + uint i, test_bit; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit= get_rand_bit(bitsize); + bitmap_flip_bit(map, test_bit); + if (!bitmap_is_set(map, test_bit)) + goto error1; + bitmap_flip_bit(map, test_bit); + if (bitmap_is_set(map, test_bit)) + goto error2; + } + return FALSE; +error1: + printf("Error in flip bit 1, bit %u, bitsize = %u", test_bit, bitsize); + return TRUE; +error2: + printf("Error in flip bit 2, bit %u, bitsize = %u", test_bit, bitsize); + return TRUE; +} + +bool test_operators(MY_BITMAP *map, uint bitsize) +{ + return FALSE; +} + +bool test_get_all_bits(MY_BITMAP *map, uint bitsize) +{ + uint i; + bitmap_set_all(map); + if (!bitmap_is_set_all(map)) + goto error1; + if (!bitmap_is_prefix(map, bitsize)) + goto error5; + bitmap_clear_all(map); + if (!bitmap_is_clear_all(map)) + goto error2; + if (!bitmap_is_prefix(map, 0)) + goto error6; + for (i=0; i 128 ? 128 : bitsize; + MY_BITMAP map2_obj, map3_obj; + MY_BITMAP *map2= &map2_obj, *map3= &map3_obj; + uint32 map2buf[1024]; + uint32 map3buf[1024]; + bitmap_init(&map2_obj, (uchar*)&map2buf, bitsize, FALSE); + bitmap_init(&map3_obj, (uchar*)&map3buf, bitsize, FALSE); + bitmap_clear_all(map2); + bitmap_clear_all(map3); + for (i=0; i < no_loops; i++) + { + test_bit1=get_rand_bit(bitsize); + bitmap_set_prefix(map, test_bit1); + test_bit2=get_rand_bit(bitsize); + bitmap_set_prefix(map2, test_bit2); + bitmap_intersect(map, map2); + test_bit3= test_bit2 < test_bit1 ? test_bit2 : test_bit1; + bitmap_set_prefix(map3, test_bit3); + if (!bitmap_cmp(map, map3)) + goto error1; + bitmap_clear_all(map); + bitmap_clear_all(map2); + bitmap_clear_all(map3); + test_bit1=get_rand_bit(bitsize); + test_bit2=get_rand_bit(bitsize); + test_bit3=get_rand_bit(bitsize); + bitmap_set_prefix(map, test_bit1); + bitmap_set_prefix(map2, test_bit2); + test_bit3= test_bit2 > test_bit1 ? test_bit2 : test_bit1; + bitmap_set_prefix(map3, test_bit3); + bitmap_union(map, map2); + if (!bitmap_cmp(map, map3)) + goto error2; + bitmap_clear_all(map); + bitmap_clear_all(map2); + bitmap_clear_all(map3); + test_bit1=get_rand_bit(bitsize); + test_bit2=get_rand_bit(bitsize); + test_bit3=get_rand_bit(bitsize); + bitmap_set_prefix(map, test_bit1); + bitmap_set_prefix(map2, test_bit2); + bitmap_xor(map, map2); + test_bit3= test_bit2 > test_bit1 ? test_bit2 : test_bit1; + test_bit4= test_bit2 < test_bit1 ? test_bit2 : test_bit1; + bitmap_set_prefix(map3, test_bit3); + for (j=0; j < test_bit4; j++) + bitmap_clear_bit(map3, j); + if (!bitmap_cmp(map, map3)) + goto error3; + bitmap_clear_all(map); + bitmap_clear_all(map2); + bitmap_clear_all(map3); + test_bit1=get_rand_bit(bitsize); + test_bit2=get_rand_bit(bitsize); + test_bit3=get_rand_bit(bitsize); + bitmap_set_prefix(map, test_bit1); + bitmap_set_prefix(map2, test_bit2); + bitmap_subtract(map, map2); + if (test_bit2 < test_bit1) + { + bitmap_set_prefix(map3, test_bit1); + for (j=0; j < test_bit2; j++) + bitmap_clear_bit(map3, j); + } + if (!bitmap_cmp(map, map3)) + goto error4; + bitmap_clear_all(map); + bitmap_clear_all(map2); + bitmap_clear_all(map3); + test_bit1=get_rand_bit(bitsize); + bitmap_set_prefix(map, test_bit1); + bitmap_invert(map); + bitmap_set_all(map3); + for (j=0; j < test_bit1; j++) + bitmap_clear_bit(map3, j); + if (!bitmap_cmp(map, map3)) + goto error5; + bitmap_clear_all(map); + bitmap_clear_all(map3); + } + return FALSE; +error1: + printf("intersect error bitsize=%u,size1=%u,size2=%u", bitsize, + test_bit1,test_bit2); + return TRUE; +error2: + printf("union error bitsize=%u,size1=%u,size2=%u", bitsize, + test_bit1,test_bit2); + return TRUE; +error3: + printf("xor error bitsize=%u,size1=%u,size2=%u", bitsize, + test_bit1,test_bit2); + return TRUE; +error4: + printf("subtract error bitsize=%u,size1=%u,size2=%u", bitsize, + test_bit1,test_bit2); + return TRUE; +error5: + printf("invert error bitsize=%u,size=%u", bitsize, + test_bit1); + return TRUE; +} + +bool test_count_bits_set(MY_BITMAP *map, uint bitsize) +{ + uint i, bit_count=0, test_bit; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit=get_rand_bit(bitsize); + if (!bitmap_is_set(map, test_bit)) + { + bitmap_set_bit(map, test_bit); + bit_count++; + } + } + if (bit_count==0 && bitsize > 0) + goto error1; + if (bitmap_bits_set(map) != bit_count) + goto error2; + return FALSE; +error1: + printf("No bits set bitsize = %u", bitsize); + return TRUE; +error2: + printf("Wrong count of bits set, bitsize = %u", bitsize); + return TRUE; +} + +bool test_get_first_bit(MY_BITMAP *map, uint bitsize) +{ + uint i, j, test_bit; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit=get_rand_bit(bitsize); + bitmap_set_bit(map, test_bit); + if (bitmap_get_first_set(map) != test_bit) + goto error1; + bitmap_set_all(map); + bitmap_clear_bit(map, test_bit); + if (bitmap_get_first(map) != test_bit) + goto error2; + bitmap_clear_all(map); + } + return FALSE; +error1: + printf("get_first_set error bitsize=%u,prefix_size=%u",bitsize,test_bit); + return TRUE; +error2: + printf("get_first error bitsize= %u, prefix_size= %u",bitsize,test_bit); + return TRUE; +} + +bool test_get_next_bit(MY_BITMAP *map, uint bitsize) +{ + uint i, j, test_bit; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit=get_rand_bit(bitsize); + for (j=0; j < test_bit; j++) + bitmap_set_next(map); + if (!bitmap_is_prefix(map, test_bit)) + goto error1; + bitmap_clear_all(map); + } + return FALSE; +error1: + printf("get_next error bitsize= %u, prefix_size= %u", bitsize,test_bit); + return TRUE; +} + +bool test_prefix(MY_BITMAP *map, uint bitsize) +{ + uint i, j, test_bit; + uint no_loops= bitsize > 128 ? 128 : bitsize; + for (i=0; i < no_loops; i++) + { + test_bit=get_rand_bit(bitsize); + bitmap_set_prefix(map, test_bit); + if (!bitmap_is_prefix(map, test_bit)) + goto error1; + bitmap_clear_all(map); + for (j=0; j < test_bit; j++) + bitmap_set_bit(map, j); + if (!bitmap_is_prefix(map, test_bit)) + goto error2; + bitmap_set_all(map); + for (j=bitsize - 1; ~(j-test_bit); j--) + bitmap_clear_bit(map, j); + if (!bitmap_is_prefix(map, test_bit)) + goto error3; + bitmap_clear_all(map); + } + return FALSE; +error1: + printf("prefix1 error bitsize = %u, prefix_size = %u", bitsize,test_bit); + return TRUE; +error2: + printf("prefix2 error bitsize = %u, prefix_size = %u", bitsize,test_bit); + return TRUE; +error3: + printf("prefix3 error bitsize = %u, prefix_size = %u", bitsize,test_bit); + return TRUE; +} + + +bool do_test(uint bitsize) +{ + MY_BITMAP map; + uint32 buf[1024]; + if (bitmap_init(&map, (uchar*)buf, bitsize, FALSE)) + { + printf("init error for bitsize %d", bitsize); + goto error; + } + if (test_set_get_clear_bit(&map,bitsize)) + goto error; + bitmap_clear_all(&map); + if (test_flip_bit(&map,bitsize)) + goto error; + bitmap_clear_all(&map); + if (test_operators(&map,bitsize)) + goto error; + bitmap_clear_all(&map); + if (test_get_all_bits(&map, bitsize)) + goto error; + bitmap_clear_all(&map); + if (test_compare_operators(&map,bitsize)) + goto error; + bitmap_clear_all(&map); + if (test_count_bits_set(&map,bitsize)) + goto error; + bitmap_clear_all(&map); + if (test_get_first_bit(&map,bitsize)) + goto error; + bitmap_clear_all(&map); + if (test_get_next_bit(&map,bitsize)) + goto error; + if (test_prefix(&map,bitsize)) + goto error; + return FALSE; +error: + printf("\n"); + return TRUE; +} + +int main() +{ + int i; + for (i= 1; i < 4096; i++) + { + printf("Start test for bitsize=%u\n",i); + if (do_test(i)) + return -1; + } + printf("OK\n"); + return 0; +} + +/* +This is the way the test part was compiled after a complete tree build with +debug. + +gcc -DHAVE_CONFIG_H -I. -I. -I.. -I../include -I. -g -O -DDBUG_ON +-DSAFE_MUTEX -fno-omit-frame-pointer -DHAVE_DARWIN_THREADS +-D_P1003_1B_VISIBLE -DSIGNAL_WITH_VIO_CLOSE -DTEST_BITMAP +-DSIGNALS_DONT_BREAK_READ -DIGNORE_SIGHUP_SIGQUIT -MT +my_bitmap.o -MD -MP -MF ".deps/my_bitmap.Tpo" -c -o my_bitmap.o my_bitmap.c + +gcc -o my_bitmap my_bitmap.o -L../mysys -lmysys -L../strings -lmystrings +-L../dbug -ldbug +*/ + +#endif diff --git a/sql/handler.cc b/sql/handler.cc index 7125cae062c..653fc07b34d 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -1357,16 +1357,17 @@ int handler::ha_initialise() int handler::ha_allocate_read_write_set(ulong no_fields) { + uint bitmap_size= 4*(((no_fields+1)+31)/32); + uchar *read_buf, *write_buf; DBUG_ENTER("ha_allocate_read_write_set"); DBUG_PRINT("info", ("no_fields = %d", no_fields)); - read_set= new bitvector; - write_set= new bitvector; - if (!read_set || !write_set) - { - ha_deallocate_read_write_set(); - DBUG_RETURN(TRUE); - } - if (read_set->init(no_fields+1) || write_set->init(no_fields+1)) + read_set= (MY_BITMAP*)sql_alloc(sizeof(MY_BITMAP)); + write_set= (MY_BITMAP*)sql_alloc(sizeof(MY_BITMAP)); + read_buf= (uchar*)sql_alloc(bitmap_size); + write_buf= (uchar*)sql_alloc(bitmap_size); + DBUG_ASSERT(!bitmap_init(read_set, read_buf, (no_fields+1), FALSE)); + DBUG_ASSERT(!bitmap_init(write_set, write_buf, (no_fields+1), FALSE)); + if (!read_set || !write_set || !read_buf || !write_buf) { ha_deallocate_read_write_set(); DBUG_RETURN(TRUE); @@ -1378,8 +1379,6 @@ int handler::ha_allocate_read_write_set(ulong no_fields) void handler::ha_deallocate_read_write_set() { DBUG_ENTER("ha_deallocate_read_write_set"); - delete read_set; - delete write_set; read_set=write_set=0; DBUG_VOID_RETURN; } @@ -1387,127 +1386,17 @@ void handler::ha_deallocate_read_write_set() void handler::ha_clear_all_set() { DBUG_ENTER("ha_clear_all_set"); - read_set->clear_all(); - write_set->clear_all(); - read_set->set_bit((uint)0); - write_set->set_bit((uint)0); + bitmap_clear_all(read_set); + bitmap_clear_all(write_set); + bitmap_set_bit(read_set, 0); + bitmap_set_bit(write_set, 0); DBUG_VOID_RETURN; } -void handler::ha_set_all_bits_in_read_set() -{ - DBUG_ENTER("ha_set_all_bits_in_read_set"); - read_set->set_all(); - DBUG_VOID_RETURN; -} - -void handler::ha_set_all_bits_in_write_set() -{ - DBUG_ENTER("ha_set_all_bits_in_write_set"); - write_set->set_all(); - DBUG_VOID_RETURN; -} - -void handler::ha_set_bit_in_read_set(uint fieldnr) -{ - DBUG_ENTER("ha_set_bit_in_read_set"); - DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); - read_set->set_bit((size_t)fieldnr); - DBUG_VOID_RETURN; -} - -void handler::ha_clear_bit_in_read_set(uint fieldnr) -{ - DBUG_ENTER("ha_clear_bit_in_read_set"); - DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); - read_set->clear_bit((size_t)fieldnr); - DBUG_VOID_RETURN; -} - -void handler::ha_set_bit_in_write_set(uint fieldnr) -{ - DBUG_ENTER("ha_set_bit_in_write_set"); - DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); - write_set->set_bit((size_t)fieldnr); - DBUG_VOID_RETURN; -} - -void handler::ha_clear_bit_in_write_set(uint fieldnr) -{ - DBUG_ENTER("ha_clear_bit_in_write_set"); - DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); - write_set->clear_bit((size_t)fieldnr); - DBUG_VOID_RETURN; -} - -void handler::ha_set_bit_in_rw_set(uint fieldnr, bool write_op) -{ - DBUG_ENTER("ha_set_bit_in_rw_set"); - if (!write_op) { - DBUG_PRINT("info", ("Set bit %u in read set", fieldnr)); - read_set->set_bit((size_t)fieldnr); - } - else - { - DBUG_PRINT("info", ("Set bit %u in read and write set", fieldnr)); - read_set->set_bit((size_t)fieldnr); - write_set->set_bit((size_t)fieldnr); - } - DBUG_VOID_RETURN; -} - -bool handler::ha_get_bit_in_read_set(uint fieldnr) -{ - bool bit_set=read_set->get_bit((size_t)fieldnr); - DBUG_ENTER("ha_get_bit_in_read_set"); - DBUG_PRINT("info", ("bit %u = %u", fieldnr, bit_set)); - DBUG_RETURN(bit_set); -} - -bool handler::ha_get_bit_in_write_set(uint fieldnr) -{ - bool bit_set=write_set->get_bit((size_t)fieldnr); - DBUG_ENTER("ha_get_bit_in_write_set"); - DBUG_PRINT("info", ("bit %u = %u", fieldnr, bit_set)); - DBUG_RETURN(bit_set); -} - -bool handler::ha_get_all_bit_in_read_set() -{ - bool bit_set=read_set->get_all_bits_set(); - DBUG_ENTER("ha_get_all_bit_in_read_set"); - DBUG_PRINT("info", ("all bits set = %u", bit_set)); - DBUG_RETURN(bit_set); -} - -bool handler::ha_get_all_bit_in_read_clear() -{ - bool bit_set=read_set->get_all_bits_clear(); - DBUG_ENTER("ha_get_all_bit_in_read_clear"); - DBUG_PRINT("info", ("all bits clear = %u", bit_set)); - DBUG_RETURN(bit_set); -} - -bool handler::ha_get_all_bit_in_write_set() -{ - bool bit_set=write_set->get_all_bits_set(); - DBUG_ENTER("ha_get_all_bit_in_write_set"); - DBUG_PRINT("info", ("all bits set = %u", bit_set)); - DBUG_RETURN(bit_set); -} - -bool handler::ha_get_all_bit_in_write_clear() -{ - bool bit_set=write_set->get_all_bits_clear(); - DBUG_ENTER("ha_get_all_bit_in_write_clear"); - DBUG_PRINT("info", ("all bits clear = %u", bit_set)); - DBUG_RETURN(bit_set); -} - int handler::ha_retrieve_all_cols() { DBUG_ENTER("handler::ha_retrieve_all_cols"); - read_set->set_all(); + bitmap_set_all(read_set); DBUG_RETURN(0); } diff --git a/sql/handler.h b/sql/handler.h index 16f9364a3d2..9818e2dc01d 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -486,8 +486,8 @@ public: bool auto_increment_column_changed; bool implicit_emptied; /* Can be !=0 only if HEAP */ const COND *pushed_cond; - bitvector *read_set; - bitvector *write_set; + MY_BITMAP *read_set; + MY_BITMAP *write_set; handler(TABLE *table_arg) :table(table_arg), ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0), @@ -497,7 +497,7 @@ public: key_used_on_scan(MAX_KEY), active_index(MAX_KEY), ref_length(sizeof(my_off_t)), block_size(0), raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0), - pushed_cond(NULL), read_set(0), write_set(0) + pushed_cond(NULL) {} virtual ~handler(void) { @@ -597,24 +597,107 @@ public: */ virtual int ha_retrieve_all_cols(); virtual int ha_retrieve_all_pk(); - void ha_set_all_bits_in_read_set(); - void ha_set_all_bits_in_write_set(); - void ha_set_bit_in_read_set(uint fieldnr); - void ha_clear_bit_in_read_set(uint fieldnr); - void ha_set_bit_in_write_set(uint fieldnr); - void ha_clear_bit_in_write_set(uint fieldnr); - void ha_set_bit_in_rw_set(uint fieldnr, bool write_set); - bool ha_get_bit_in_read_set(uint fieldnr); - bool ha_get_bit_in_write_set(uint fieldnr); - bool ha_get_all_bit_in_read_set(); - bool ha_get_all_bit_in_read_clear(); - bool ha_get_all_bit_in_write_set(); - bool ha_get_all_bit_in_write_clear(); + void ha_set_all_bits_in_read_set() + { + DBUG_ENTER("ha_set_all_bits_in_read_set"); + bitmap_set_all(read_set); + DBUG_VOID_RETURN; + } + void ha_set_all_bits_in_write_set() + { + DBUG_ENTER("ha_set_all_bits_in_write_set"); + bitmap_set_all(write_set); + DBUG_VOID_RETURN; + } + void ha_set_bit_in_read_set(uint fieldnr) + { + DBUG_ENTER("ha_set_bit_in_read_set"); + DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); + bitmap_set_bit(read_set, fieldnr); + DBUG_VOID_RETURN; + } + void ha_clear_bit_in_read_set(uint fieldnr) + { + DBUG_ENTER("ha_clear_bit_in_read_set"); + DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); + bitmap_clear_bit(read_set, fieldnr); + DBUG_VOID_RETURN; + } + void ha_set_bit_in_write_set(uint fieldnr) + { + DBUG_ENTER("ha_set_bit_in_write_set"); + DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); + bitmap_set_bit(write_set, fieldnr); + DBUG_VOID_RETURN; + } + void ha_clear_bit_in_write_set(uint fieldnr) + { + DBUG_ENTER("ha_clear_bit_in_write_set"); + DBUG_PRINT("info", ("fieldnr = %d", fieldnr)); + bitmap_clear_bit(write_set, fieldnr); + DBUG_VOID_RETURN; + } + void ha_set_bit_in_rw_set(uint fieldnr, bool write_op) + { + DBUG_ENTER("ha_set_bit_in_rw_set"); + DBUG_PRINT("info", ("Set bit %u in read set", fieldnr)); + bitmap_set_bit(read_set, fieldnr); + if (!write_op) { + DBUG_VOID_RETURN; + } + else + { + DBUG_PRINT("info", ("Set bit %u in read and write set", fieldnr)); + bitmap_set_bit(write_set, fieldnr); + } + DBUG_VOID_RETURN; + } + bool ha_get_bit_in_read_set(uint fieldnr) + { + bool bit_set=bitmap_is_set(read_set,fieldnr); + DBUG_ENTER("ha_get_bit_in_read_set"); + DBUG_PRINT("info", ("bit %u = %u", fieldnr, bit_set)); + DBUG_RETURN(bit_set); + } + bool ha_get_bit_in_write_set(uint fieldnr) + { + bool bit_set=bitmap_is_set(write_set,fieldnr); + DBUG_ENTER("ha_get_bit_in_write_set"); + DBUG_PRINT("info", ("bit %u = %u", fieldnr, bit_set)); + DBUG_RETURN(bit_set); + } + bool ha_get_all_bit_in_read_set() + { + bool all_bits_set= bitmap_is_set_all(read_set); + DBUG_ENTER("ha_get_all_bit_in_read_set"); + DBUG_PRINT("info", ("all bits set = %u", all_bits_set)); + DBUG_RETURN(all_bits_set); + } + bool ha_get_all_bit_in_read_clear() + { + bool all_bits_set= bitmap_is_clear_all(read_set); + DBUG_ENTER("ha_get_all_bit_in_read_clear"); + DBUG_PRINT("info", ("all bits clear = %u", all_bits_set)); + DBUG_RETURN(all_bits_set); + } + bool ha_get_all_bit_in_write_set() + { + bool all_bits_set= bitmap_is_set_all(write_set); + DBUG_ENTER("ha_get_all_bit_in_write_set"); + DBUG_PRINT("info", ("all bits set = %u", all_bits_set)); + DBUG_RETURN(all_bits_set); + } + bool ha_get_all_bit_in_write_clear() + { + bool all_bits_set= bitmap_is_clear_all(write_set); + DBUG_ENTER("ha_get_all_bit_in_write_clear"); + DBUG_PRINT("info", ("all bits clear = %u", all_bits_set)); + DBUG_RETURN(all_bits_set); + } void ha_set_primary_key_in_read_set(); int ha_allocate_read_write_set(ulong no_fields); void ha_deallocate_read_write_set(); void ha_clear_all_set(); - uint get_index(void) const { return active_index; } virtual int open(const char *name, int mode, uint test_if_locked)=0; virtual int close(void)=0; diff --git a/sql/opt_range.cc b/sql/opt_range.cc index 48f2e95c7a4..634c833e554 100644 --- a/sql/opt_range.cc +++ b/sql/opt_range.cc @@ -1566,7 +1566,8 @@ static int fill_used_fields_bitmap(PARAM *param) param->fields_bitmap_size= (table->s->fields/8 + 1); uchar *tmp; uint pk; - if (!(tmp= (uchar*)alloc_root(param->mem_root,param->fields_bitmap_size)) || + if (!(tmp= (uchar*)alloc_root(param->mem_root, + bytes_word_aligned(param->fields_bitmap_size))) || bitmap_init(¶m->needed_fields, tmp, param->fields_bitmap_size*8, FALSE)) return 1; @@ -2321,7 +2322,7 @@ ROR_SCAN_INFO *make_ror_scan(const PARAM *param, int idx, SEL_ARG *sel_arg) ror_scan->records= param->table->quick_rows[keynr]; if (!(bitmap_buf= (uchar*)alloc_root(param->mem_root, - param->fields_bitmap_size))) + bytes_word_aligned(param->fields_bitmap_size)))) DBUG_RETURN(NULL); if (bitmap_init(&ror_scan->covered_fields, bitmap_buf, @@ -2441,7 +2442,8 @@ ROR_INTERSECT_INFO* ror_intersect_init(const PARAM *param) sizeof(ROR_INTERSECT_INFO)))) return NULL; info->param= param; - if (!(buf= (uchar*)alloc_root(param->mem_root, param->fields_bitmap_size))) + if (!(buf= (uchar*)alloc_root(param->mem_root, + bytes_word_aligned(param->fields_bitmap_size)))) return NULL; if (bitmap_init(&info->covered_fields, buf, param->fields_bitmap_size*8, FALSE)) @@ -2998,7 +3000,8 @@ TRP_ROR_INTERSECT *get_best_covering_ror_intersect(PARAM *param, /*I=set of all covering indexes */ ror_scan_mark= tree->ror_scans; - uchar buf[MAX_KEY/8+1]; + uint32 int_buf[MAX_KEY/32+1]; + uchar *buf= (uchar*)&int_buf; MY_BITMAP covered_fields; if (bitmap_init(&covered_fields, buf, nbits, FALSE)) DBUG_RETURN(0); diff --git a/sql/sql_bitmap.h b/sql/sql_bitmap.h index 5c51f3ecb67..37c74b4ea91 100644 --- a/sql/sql_bitmap.h +++ b/sql/sql_bitmap.h @@ -25,7 +25,7 @@ template class Bitmap { MY_BITMAP map; - uchar buffer[(default_width+7)/8]; + uint32 buffer[(default_width+31)/32]; public: Bitmap() { init(); } Bitmap(Bitmap& from) { *this=from; } @@ -62,17 +62,18 @@ public: char *print(char *buf) const { char *s=buf; int i; + uchar *uchar_buffer= (uchar*)&buffer; for (i=sizeof(buffer)-1; i>=0 ; i--) { - if ((*s=_dig_vec_upper[buffer[i] >> 4]) != '0') + if ((*s=_dig_vec_upper[uchar_buffer[i] >> 4]) != '0') break; - if ((*s=_dig_vec_upper[buffer[i] & 15]) != '0') + if ((*s=_dig_vec_upper[uchar_buffer[i] & 15]) != '0') break; } for (s++, i-- ; i>=0 ; i--) { - *s++=_dig_vec_upper[buffer[i] >> 4]; - *s++=_dig_vec_upper[buffer[i] & 15]; + *s++=_dig_vec_upper[uchar_buffer[i] >> 4]; + *s++=_dig_vec_upper[uchar_buffer[i] & 15]; } *s=0; return buf; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 348d0b578a1..5555029f928 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -7946,7 +7946,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status); if (use_temp_pool) - temp_pool_slot = bitmap_set_next(&temp_pool); + temp_pool_slot = bitmap_lock_set_next(&temp_pool); if (temp_pool_slot != MY_BIT_NONE) // we got a slot sprintf(filename, "%s_%lx_%i", tmp_file_prefix, @@ -7998,12 +7998,12 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, param->group_length : 0, NullS)) { - bitmap_clear_bit(&temp_pool, temp_pool_slot); + bitmap_lock_clear_bit(&temp_pool, temp_pool_slot); DBUG_RETURN(NULL); /* purecov: inspected */ } if (!(param->copy_field=copy=new Copy_field[field_count])) { - bitmap_clear_bit(&temp_pool, temp_pool_slot); + bitmap_lock_clear_bit(&temp_pool, temp_pool_slot); my_free((gptr) table,MYF(0)); /* purecov: inspected */ DBUG_RETURN(NULL); /* purecov: inspected */ } @@ -8449,7 +8449,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, err: free_tmp_table(thd,table); /* purecov: inspected */ - bitmap_clear_bit(&temp_pool, temp_pool_slot); + bitmap_lock_clear_bit(&temp_pool, temp_pool_slot); DBUG_RETURN(NULL); /* purecov: inspected */ } @@ -8723,7 +8723,7 @@ free_tmp_table(THD *thd, TABLE *entry) my_free((gptr) entry->record[0],MYF(0)); free_io_cache(entry); - bitmap_clear_bit(&temp_pool, entry->temp_pool_slot); + bitmap_lock_clear_bit(&temp_pool, entry->temp_pool_slot); my_free((gptr) entry,MYF(0)); thd->proc_info=save_proc_info;