You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7109 lines
206 KiB

26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Backport of revno ## 2617.31.1, 2617.31.3, 2617.31.4, 2617.31.5, 2617.31.12, 2617.31.15, 2617.31.15, 2617.31.16, 2617.43.1 - initial changeset that introduced the fix for Bug#989 and follow up fixes for all test suite failures introduced in the initial changeset. ------------------------------------------------------------ revno: 2617.31.1 committer: Davi Arnaut <Davi.Arnaut@Sun.COM> branch nick: 4284-6.0 timestamp: Fri 2009-03-06 19:17:00 -0300 message: Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order WL#4284: Transactional DDL locking Currently the MySQL server does not keep metadata locks on schema objects for the duration of a transaction, thus failing to guarantee the integrity of the schema objects being used during the transaction and to protect then from concurrent DDL operations. This also poses a problem for replication as a DDL operation might be replicated even thought there are active transactions using the object being modified. The solution is to defer the release of metadata locks until a active transaction is either committed or rolled back. This prevents other statements from modifying the table for the entire duration of the transaction. This provides commitment ordering for guaranteeing serializability across multiple transactions. - Incompatible change: If MySQL's metadata locking system encounters a lock conflict, the usual schema is to use the try and back-off technique to avoid deadlocks -- this schema consists in releasing all locks and trying to acquire them all in one go. But in a transactional context this algorithm can't be utilized as its not possible to release locks acquired during the course of the transaction without breaking the transaction commitments. To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be returned if a lock conflict is encountered during a transaction. Let's consider an example: A transaction has two statements that modify table t1, then table t2, and then commits. The first statement of the transaction will acquire a shared metadata lock on table t1, and it will be kept utill COMMIT to ensure serializability. At the moment when the second statement attempts to acquire a shared metadata lock on t2, a concurrent ALTER or DROP statement might have locked t2 exclusively. The prescription of the current locking protocol is that the acquirer of the shared lock backs off -- gives up all his current locks and retries. This implies that the entire multi-statement transaction has to be rolled back. - Incompatible change: FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ LOCK won't cause locked tables to be implicitly unlocked anymore.
16 years ago
26 years ago
WL#4738 streamline/simplify @@variable creation process Bug#16565 mysqld --help --verbose does not order variablesBug#20413 sql_slave_skip_counter is not shown in show variables Bug#20415 Output of mysqld --help --verbose is incomplete Bug#25430 variable not found in SELECT @@global.ft_max_word_len; Bug#32902 plugin variables don't know their names Bug#34599 MySQLD Option and Variable Reference need to be consistent in formatting! Bug#34829 No default value for variable and setting default does not raise error Bug#34834 ? Is accepted as a valid sql mode Bug#34878 Few variables have default value according to documentation but error occurs Bug#34883 ft_boolean_syntax cant be assigned from user variable to global var. Bug#37187 `INFORMATION_SCHEMA`.`GLOBAL_VARIABLES`: inconsistent status Bug#40988 log_output_basic.test succeeded though syntactically false. Bug#41010 enum-style command-line options are not honoured (maria.maria-recover fails) Bug#42103 Setting key_buffer_size to a negative value may lead to very large allocations Bug#44691 Some plugins configured as MYSQL_PLUGIN_MANDATORY in can be disabled Bug#44797 plugins w/o command-line options have no disabling option in --help Bug#46314 string system variables don't support expressions Bug#46470 sys_vars.max_binlog_cache_size_basic_32 is broken Bug#46586 When using the plugin interface the type "set" for options caused a crash. Bug#47212 Crash in DBUG_PRINT in mysqltest.cc when trying to print octal number Bug#48758 mysqltest crashes on sys_vars.collation_server_basic in gcov builds Bug#49417 some complaints about mysqld --help --verbose output Bug#49540 DEFAULT value of binlog_format isn't the default value Bug#49640 ambiguous option '--skip-skip-myisam' (double skip prefix) Bug#49644 init_connect and \0 Bug#49645 init_slave and multi-byte characters Bug#49646 mysql --show-warnings crashes when server dies
16 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
22 years ago
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
19 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
WL#4738 streamline/simplify @@variable creation process Bug#16565 mysqld --help --verbose does not order variablesBug#20413 sql_slave_skip_counter is not shown in show variables Bug#20415 Output of mysqld --help --verbose is incomplete Bug#25430 variable not found in SELECT @@global.ft_max_word_len; Bug#32902 plugin variables don't know their names Bug#34599 MySQLD Option and Variable Reference need to be consistent in formatting! Bug#34829 No default value for variable and setting default does not raise error Bug#34834 ? Is accepted as a valid sql mode Bug#34878 Few variables have default value according to documentation but error occurs Bug#34883 ft_boolean_syntax cant be assigned from user variable to global var. Bug#37187 `INFORMATION_SCHEMA`.`GLOBAL_VARIABLES`: inconsistent status Bug#40988 log_output_basic.test succeeded though syntactically false. Bug#41010 enum-style command-line options are not honoured (maria.maria-recover fails) Bug#42103 Setting key_buffer_size to a negative value may lead to very large allocations Bug#44691 Some plugins configured as MYSQL_PLUGIN_MANDATORY in can be disabled Bug#44797 plugins w/o command-line options have no disabling option in --help Bug#46314 string system variables don't support expressions Bug#46470 sys_vars.max_binlog_cache_size_basic_32 is broken Bug#46586 When using the plugin interface the type "set" for options caused a crash. Bug#47212 Crash in DBUG_PRINT in mysqltest.cc when trying to print octal number Bug#48758 mysqltest crashes on sys_vars.collation_server_basic in gcov builds Bug#49417 some complaints about mysqld --help --verbose output Bug#49540 DEFAULT value of binlog_format isn't the default value Bug#49640 ambiguous option '--skip-skip-myisam' (double skip prefix) Bug#49644 init_connect and \0 Bug#49645 init_slave and multi-byte characters Bug#49646 mysql --show-warnings crashes when server dies
16 years ago
WL#4738 streamline/simplify @@variable creation process Bug#16565 mysqld --help --verbose does not order variablesBug#20413 sql_slave_skip_counter is not shown in show variables Bug#20415 Output of mysqld --help --verbose is incomplete Bug#25430 variable not found in SELECT @@global.ft_max_word_len; Bug#32902 plugin variables don't know their names Bug#34599 MySQLD Option and Variable Reference need to be consistent in formatting! Bug#34829 No default value for variable and setting default does not raise error Bug#34834 ? Is accepted as a valid sql mode Bug#34878 Few variables have default value according to documentation but error occurs Bug#34883 ft_boolean_syntax cant be assigned from user variable to global var. Bug#37187 `INFORMATION_SCHEMA`.`GLOBAL_VARIABLES`: inconsistent status Bug#40988 log_output_basic.test succeeded though syntactically false. Bug#41010 enum-style command-line options are not honoured (maria.maria-recover fails) Bug#42103 Setting key_buffer_size to a negative value may lead to very large allocations Bug#44691 Some plugins configured as MYSQL_PLUGIN_MANDATORY in can be disabled Bug#44797 plugins w/o command-line options have no disabling option in --help Bug#46314 string system variables don't support expressions Bug#46470 sys_vars.max_binlog_cache_size_basic_32 is broken Bug#46586 When using the plugin interface the type "set" for options caused a crash. Bug#47212 Crash in DBUG_PRINT in mysqltest.cc when trying to print octal number Bug#48758 mysqltest crashes on sys_vars.collation_server_basic in gcov builds Bug#49417 some complaints about mysqld --help --verbose output Bug#49540 DEFAULT value of binlog_format isn't the default value Bug#49640 ambiguous option '--skip-skip-myisam' (double skip prefix) Bug#49644 init_connect and \0 Bug#49645 init_slave and multi-byte characters Bug#49646 mysql --show-warnings crashes when server dies
16 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Backport of revno ## 2617.31.1, 2617.31.3, 2617.31.4, 2617.31.5, 2617.31.12, 2617.31.15, 2617.31.15, 2617.31.16, 2617.43.1 - initial changeset that introduced the fix for Bug#989 and follow up fixes for all test suite failures introduced in the initial changeset. ------------------------------------------------------------ revno: 2617.31.1 committer: Davi Arnaut <Davi.Arnaut@Sun.COM> branch nick: 4284-6.0 timestamp: Fri 2009-03-06 19:17:00 -0300 message: Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order WL#4284: Transactional DDL locking Currently the MySQL server does not keep metadata locks on schema objects for the duration of a transaction, thus failing to guarantee the integrity of the schema objects being used during the transaction and to protect then from concurrent DDL operations. This also poses a problem for replication as a DDL operation might be replicated even thought there are active transactions using the object being modified. The solution is to defer the release of metadata locks until a active transaction is either committed or rolled back. This prevents other statements from modifying the table for the entire duration of the transaction. This provides commitment ordering for guaranteeing serializability across multiple transactions. - Incompatible change: If MySQL's metadata locking system encounters a lock conflict, the usual schema is to use the try and back-off technique to avoid deadlocks -- this schema consists in releasing all locks and trying to acquire them all in one go. But in a transactional context this algorithm can't be utilized as its not possible to release locks acquired during the course of the transaction without breaking the transaction commitments. To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be returned if a lock conflict is encountered during a transaction. Let's consider an example: A transaction has two statements that modify table t1, then table t2, and then commits. The first statement of the transaction will acquire a shared metadata lock on table t1, and it will be kept utill COMMIT to ensure serializability. At the moment when the second statement attempts to acquire a shared metadata lock on t2, a concurrent ALTER or DROP statement might have locked t2 exclusively. The prescription of the current locking protocol is that the acquirer of the shared lock backs off -- gives up all his current locks and retries. This implies that the entire multi-statement transaction has to be rolled back. - Incompatible change: FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ LOCK won't cause locked tables to be implicitly unlocked anymore.
16 years ago
A prerequisite patch for the fix for Bug#46224 "HANDLER statements within a transaction might lead to deadlocks". Introduce a notion of a sentinel to MDL_context. A sentinel is a ticket that separates all tickets in the context into two groups: before and after it. Currently we can have (and need) only one designated sentinel -- it separates all locks taken by LOCK TABLE or HANDLER statement, which must survive COMMIT and ROLLBACK and all other locks, which must be released at COMMIT or ROLLBACK. The tricky part is maintaining the sentinel up to date when someone release its corresponding ticket. This can happen, e.g. if someone issues DROP TABLE under LOCK TABLES (generally, see all calls to release_all_locks_for_name()). MDL_context::release_ticket() is modified to take care of it. ****** A fix and a test case for Bug#46224 "HANDLER statements within a transaction might lead to deadlocks". An attempt to mix HANDLER SQL statements, which are transaction- agnostic, an open multi-statement transaction, and DDL against the involved tables (in a concurrent connection) could lead to a deadlock. The deadlock would occur when HANDLER OPEN or HANDLER READ would have to wait on a conflicting metadata lock. If the connection that issued HANDLER statement also had other metadata locks (say, acquired in scope of a transaction), a classical deadlock situation of mutual wait could occur. Incompatible change: entering LOCK TABLES mode automatically closes all open HANDLERs in the current connection. Incompatible change: previously an attempt to wait on a lock in a connection that has an open HANDLER statement could wait indefinitely/deadlock. After this patch, an error ER_LOCK_DEADLOCK is produced. The idea of the fix is to merge thd->handler_mdl_context with the main mdl_context of the connection, used for transactional locks. This makes deadlock detection possible, since all waits with locks are "visible" and available to analysis in a single MDL context of the connection. Since HANDLER locks and transactional locks have a different life cycle -- HANDLERs are explicitly open and closed, and so are HANDLER locks, explicitly acquired and released, whereas transactional locks "accumulate" till the end of a transaction and are released only with COMMIT, ROLLBACK and ROLLBACK TO SAVEPOINT, a concept of "sentinel" was introduced to MDL_context. All locks, HANDLER and others, reside in the same linked list. However, a selected element of the list separates locks with different life cycle. HANDLER locks always reside at the end of the list, after the sentinel. Transactional locks are prepended to the beginning of the list, before the sentinel. Thus, ROLLBACK, COMMIT or ROLLBACK TO SAVEPOINT, only release those locks that reside before the sentinel. HANDLER locks must be released explicitly as part of HANDLER CLOSE statement, or an implicit close. The same approach with sentinel is also employed for LOCK TABLES locks. Since HANDLER and LOCK TABLES statement has never worked together, the implementation is made simple and only maintains one sentinel, which is used either for HANDLER locks, or for LOCK TABLES locks.
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
23 years ago
26 years ago
23 years ago
26 years ago
26 years ago
26 years ago
26 years ago
22 years ago
22 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
26 years ago
22 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
23 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
22 years ago
26 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
23 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
21 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
24 years ago
26 years ago
26 years ago
26 years ago
26 years ago
21 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
merge mysql-5.1-rep+2-delivery1 --> mysql-5.1-rpl-merge Conflicts: Text conflict in .bzr-mysql/default.conf Text conflict in mysql-test/extra/rpl_tests/rpl_loaddata.test Text conflict in mysql-test/r/mysqlbinlog2.result Text conflict in mysql-test/suite/binlog/r/binlog_stm_mix_innodb_myisam.result Text conflict in mysql-test/suite/binlog/r/binlog_unsafe.result Text conflict in mysql-test/suite/rpl/r/rpl_insert_id.result Text conflict in mysql-test/suite/rpl/r/rpl_loaddata.result Text conflict in mysql-test/suite/rpl/r/rpl_stm_auto_increment_bug33029.result Text conflict in mysql-test/suite/rpl/r/rpl_udf.result Text conflict in mysql-test/suite/rpl/t/rpl_slow_query_log.test Text conflict in sql/field.h Text conflict in sql/log.cc Text conflict in sql/log_event.cc Text conflict in sql/log_event_old.cc Text conflict in sql/mysql_priv.h Text conflict in sql/share/errmsg.txt Text conflict in sql/sp.cc Text conflict in sql/sql_acl.cc Text conflict in sql/sql_base.cc Text conflict in sql/sql_class.h Text conflict in sql/sql_db.cc Text conflict in sql/sql_delete.cc Text conflict in sql/sql_insert.cc Text conflict in sql/sql_lex.cc Text conflict in sql/sql_lex.h Text conflict in sql/sql_load.cc Text conflict in sql/sql_table.cc Text conflict in sql/sql_update.cc Text conflict in sql/sql_view.cc Conflict adding files to storage/innobase. Created directory. Conflict because storage/innobase is not versioned, but has versioned children. Versioned directory. Conflict adding file storage/innobase. Moved existing file to storage/innobase.moved. Conflict adding files to storage/innobase/handler. Created directory. Conflict because storage/innobase/handler is not versioned, but has versioned children. Versioned directory. Contents conflict in storage/innobase/handler/ha_innodb.cc
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
Backport of WL#798 (MySQL IPv6 support) from 6.0. The following 6.0 revisions were analyzed: - sp1r-brian@zim.(none)-20071228102738-21894 - sp1r-brian@zim.(none)-20071228121841-56447 - sp1r-brian@zim.(none)-20071228205403-56423 - sp1r-brian@zim.(none)-20071228221139-55341 - sp1r-brian@zim.(none)-20071228233443-55352 - sp1r-brian@zim.(none)-20071229094527-61763 - sp1r-brian@zim.(none)-20071230203739-61746 - sp1r-brian@zim.(none)-20080102213805-61741 - sp1r-brian@zim.(none)-20080103201041-61746 - sp1r-brian@zim.(none)-20080104234927-59875 - sp1r-brian@zim.(none)-20080105005827-59874 - sp1r-brian@zim.(none)-20080105012020-59865 - sp1r-brian@zim.(none)-20080106003858-59857 - sp1r-brian@zim.(none)-20080123195552-31680 - sp1r-brian@zim.(none)-20080124201848-29999 - sp1r-brian@zim.(none)-20080129075144-36991 - sp1r-cbell/Chuck@mysql_cab_desk.-20080215041806-21954 - sp1r-vvaintroub@wva.-20080212124547-06272 - sp1r-dfischer/mysqldev@mysql.com/production.mysql.com-20071223184258-15140 - sp1r-brian@zim.(none)-20080206122216-35774 - sp1r-baker@bk-internal.mysql.com-20080209005622-35947 - sp1r-baker@bk-internal.mysql.com-20080224215608-24613 - sp1r-baker@bk-internal.mysql.com-20080307170710-63543 - sp1r-baker@bk-internal.mysql.com-20080312233205-13069 - sp1r-Reggie@core.-20080402175211-28643 - kpettersson@mysql.com-20080901101150-4ne74r8v0492vv42 - alik@sun.com-20090805173811-9fzt0ymcp9tsvn7k - alik@sun.com-20090805173937-fcv1fdveodq5x9gb - alik@sun.com-20090805175009-g1od16i3t1xkw2qr - kostja@sun.com-20090805200643-j9i4fy7ii8ijho5c - alik@sun.com-20090807195303-j4fb5m4l1dgdahwo - alik@sun.com-20090808114848-3rkzr9kifrijzaqy - alik@sun.com-20090810041739-ugmx34h34uid8mox - alik@sun.com-20090810105306-rf43rfyzzblsy5e7 - alik@sun.com-20090810123113-ccdjwai68b5woqdm - alik@sun.com-20090811080423-gb7pibec1znaydzy - alik@sun.com-20090811082130-5uckar1vx3kdsw7g - alik@sun.com-20090812202051-uqkfwwxxcjvo5ean The following bugfixes are also backported within this patch: - Bug#34292: netdb.h missing in hostname.cc - Bug#39153: Failing to lookup a host name can lead to crash in current IPv6 implementation - Bug#38247: Server does not resolve connecting ip's - Bug#43006: main.skip_name_resolve fails on Windows in PB2 - Bug#45606: ACL requires IPv4-mapped addresses to be used - Bug#45584: Host name cache does not work as a cache
16 years ago
Backport of WL#798 (MySQL IPv6 support) from 6.0. The following 6.0 revisions were analyzed: - sp1r-brian@zim.(none)-20071228102738-21894 - sp1r-brian@zim.(none)-20071228121841-56447 - sp1r-brian@zim.(none)-20071228205403-56423 - sp1r-brian@zim.(none)-20071228221139-55341 - sp1r-brian@zim.(none)-20071228233443-55352 - sp1r-brian@zim.(none)-20071229094527-61763 - sp1r-brian@zim.(none)-20071230203739-61746 - sp1r-brian@zim.(none)-20080102213805-61741 - sp1r-brian@zim.(none)-20080103201041-61746 - sp1r-brian@zim.(none)-20080104234927-59875 - sp1r-brian@zim.(none)-20080105005827-59874 - sp1r-brian@zim.(none)-20080105012020-59865 - sp1r-brian@zim.(none)-20080106003858-59857 - sp1r-brian@zim.(none)-20080123195552-31680 - sp1r-brian@zim.(none)-20080124201848-29999 - sp1r-brian@zim.(none)-20080129075144-36991 - sp1r-cbell/Chuck@mysql_cab_desk.-20080215041806-21954 - sp1r-vvaintroub@wva.-20080212124547-06272 - sp1r-dfischer/mysqldev@mysql.com/production.mysql.com-20071223184258-15140 - sp1r-brian@zim.(none)-20080206122216-35774 - sp1r-baker@bk-internal.mysql.com-20080209005622-35947 - sp1r-baker@bk-internal.mysql.com-20080224215608-24613 - sp1r-baker@bk-internal.mysql.com-20080307170710-63543 - sp1r-baker@bk-internal.mysql.com-20080312233205-13069 - sp1r-Reggie@core.-20080402175211-28643 - kpettersson@mysql.com-20080901101150-4ne74r8v0492vv42 - alik@sun.com-20090805173811-9fzt0ymcp9tsvn7k - alik@sun.com-20090805173937-fcv1fdveodq5x9gb - alik@sun.com-20090805175009-g1od16i3t1xkw2qr - kostja@sun.com-20090805200643-j9i4fy7ii8ijho5c - alik@sun.com-20090807195303-j4fb5m4l1dgdahwo - alik@sun.com-20090808114848-3rkzr9kifrijzaqy - alik@sun.com-20090810041739-ugmx34h34uid8mox - alik@sun.com-20090810105306-rf43rfyzzblsy5e7 - alik@sun.com-20090810123113-ccdjwai68b5woqdm - alik@sun.com-20090811080423-gb7pibec1znaydzy - alik@sun.com-20090811082130-5uckar1vx3kdsw7g - alik@sun.com-20090812202051-uqkfwwxxcjvo5ean The following bugfixes are also backported within this patch: - Bug#34292: netdb.h missing in hostname.cc - Bug#39153: Failing to lookup a host name can lead to crash in current IPv6 implementation - Bug#38247: Server does not resolve connecting ip's - Bug#43006: main.skip_name_resolve fails on Windows in PB2 - Bug#45606: ACL requires IPv4-mapped addresses to be used - Bug#45584: Host name cache does not work as a cache
16 years ago
Backport of WL#798 (MySQL IPv6 support) from 6.0. The following 6.0 revisions were analyzed: - sp1r-brian@zim.(none)-20071228102738-21894 - sp1r-brian@zim.(none)-20071228121841-56447 - sp1r-brian@zim.(none)-20071228205403-56423 - sp1r-brian@zim.(none)-20071228221139-55341 - sp1r-brian@zim.(none)-20071228233443-55352 - sp1r-brian@zim.(none)-20071229094527-61763 - sp1r-brian@zim.(none)-20071230203739-61746 - sp1r-brian@zim.(none)-20080102213805-61741 - sp1r-brian@zim.(none)-20080103201041-61746 - sp1r-brian@zim.(none)-20080104234927-59875 - sp1r-brian@zim.(none)-20080105005827-59874 - sp1r-brian@zim.(none)-20080105012020-59865 - sp1r-brian@zim.(none)-20080106003858-59857 - sp1r-brian@zim.(none)-20080123195552-31680 - sp1r-brian@zim.(none)-20080124201848-29999 - sp1r-brian@zim.(none)-20080129075144-36991 - sp1r-cbell/Chuck@mysql_cab_desk.-20080215041806-21954 - sp1r-vvaintroub@wva.-20080212124547-06272 - sp1r-dfischer/mysqldev@mysql.com/production.mysql.com-20071223184258-15140 - sp1r-brian@zim.(none)-20080206122216-35774 - sp1r-baker@bk-internal.mysql.com-20080209005622-35947 - sp1r-baker@bk-internal.mysql.com-20080224215608-24613 - sp1r-baker@bk-internal.mysql.com-20080307170710-63543 - sp1r-baker@bk-internal.mysql.com-20080312233205-13069 - sp1r-Reggie@core.-20080402175211-28643 - kpettersson@mysql.com-20080901101150-4ne74r8v0492vv42 - alik@sun.com-20090805173811-9fzt0ymcp9tsvn7k - alik@sun.com-20090805173937-fcv1fdveodq5x9gb - alik@sun.com-20090805175009-g1od16i3t1xkw2qr - kostja@sun.com-20090805200643-j9i4fy7ii8ijho5c - alik@sun.com-20090807195303-j4fb5m4l1dgdahwo - alik@sun.com-20090808114848-3rkzr9kifrijzaqy - alik@sun.com-20090810041739-ugmx34h34uid8mox - alik@sun.com-20090810105306-rf43rfyzzblsy5e7 - alik@sun.com-20090810123113-ccdjwai68b5woqdm - alik@sun.com-20090811080423-gb7pibec1znaydzy - alik@sun.com-20090811082130-5uckar1vx3kdsw7g - alik@sun.com-20090812202051-uqkfwwxxcjvo5ean The following bugfixes are also backported within this patch: - Bug#34292: netdb.h missing in hostname.cc - Bug#39153: Failing to lookup a host name can lead to crash in current IPv6 implementation - Bug#38247: Server does not resolve connecting ip's - Bug#43006: main.skip_name_resolve fails on Windows in PB2 - Bug#45606: ACL requires IPv4-mapped addresses to be used - Bug#45584: Host name cache does not work as a cache
16 years ago
Backport of WL#798 (MySQL IPv6 support) from 6.0. The following 6.0 revisions were analyzed: - sp1r-brian@zim.(none)-20071228102738-21894 - sp1r-brian@zim.(none)-20071228121841-56447 - sp1r-brian@zim.(none)-20071228205403-56423 - sp1r-brian@zim.(none)-20071228221139-55341 - sp1r-brian@zim.(none)-20071228233443-55352 - sp1r-brian@zim.(none)-20071229094527-61763 - sp1r-brian@zim.(none)-20071230203739-61746 - sp1r-brian@zim.(none)-20080102213805-61741 - sp1r-brian@zim.(none)-20080103201041-61746 - sp1r-brian@zim.(none)-20080104234927-59875 - sp1r-brian@zim.(none)-20080105005827-59874 - sp1r-brian@zim.(none)-20080105012020-59865 - sp1r-brian@zim.(none)-20080106003858-59857 - sp1r-brian@zim.(none)-20080123195552-31680 - sp1r-brian@zim.(none)-20080124201848-29999 - sp1r-brian@zim.(none)-20080129075144-36991 - sp1r-cbell/Chuck@mysql_cab_desk.-20080215041806-21954 - sp1r-vvaintroub@wva.-20080212124547-06272 - sp1r-dfischer/mysqldev@mysql.com/production.mysql.com-20071223184258-15140 - sp1r-brian@zim.(none)-20080206122216-35774 - sp1r-baker@bk-internal.mysql.com-20080209005622-35947 - sp1r-baker@bk-internal.mysql.com-20080224215608-24613 - sp1r-baker@bk-internal.mysql.com-20080307170710-63543 - sp1r-baker@bk-internal.mysql.com-20080312233205-13069 - sp1r-Reggie@core.-20080402175211-28643 - kpettersson@mysql.com-20080901101150-4ne74r8v0492vv42 - alik@sun.com-20090805173811-9fzt0ymcp9tsvn7k - alik@sun.com-20090805173937-fcv1fdveodq5x9gb - alik@sun.com-20090805175009-g1od16i3t1xkw2qr - kostja@sun.com-20090805200643-j9i4fy7ii8ijho5c - alik@sun.com-20090807195303-j4fb5m4l1dgdahwo - alik@sun.com-20090808114848-3rkzr9kifrijzaqy - alik@sun.com-20090810041739-ugmx34h34uid8mox - alik@sun.com-20090810105306-rf43rfyzzblsy5e7 - alik@sun.com-20090810123113-ccdjwai68b5woqdm - alik@sun.com-20090811080423-gb7pibec1znaydzy - alik@sun.com-20090811082130-5uckar1vx3kdsw7g - alik@sun.com-20090812202051-uqkfwwxxcjvo5ean The following bugfixes are also backported within this patch: - Bug#34292: netdb.h missing in hostname.cc - Bug#39153: Failing to lookup a host name can lead to crash in current IPv6 implementation - Bug#38247: Server does not resolve connecting ip's - Bug#43006: main.skip_name_resolve fails on Windows in PB2 - Bug#45606: ACL requires IPv4-mapped addresses to be used - Bug#45584: Host name cache does not work as a cache
16 years ago
Backport of WL#798 (MySQL IPv6 support) from 6.0. The following 6.0 revisions were analyzed: - sp1r-brian@zim.(none)-20071228102738-21894 - sp1r-brian@zim.(none)-20071228121841-56447 - sp1r-brian@zim.(none)-20071228205403-56423 - sp1r-brian@zim.(none)-20071228221139-55341 - sp1r-brian@zim.(none)-20071228233443-55352 - sp1r-brian@zim.(none)-20071229094527-61763 - sp1r-brian@zim.(none)-20071230203739-61746 - sp1r-brian@zim.(none)-20080102213805-61741 - sp1r-brian@zim.(none)-20080103201041-61746 - sp1r-brian@zim.(none)-20080104234927-59875 - sp1r-brian@zim.(none)-20080105005827-59874 - sp1r-brian@zim.(none)-20080105012020-59865 - sp1r-brian@zim.(none)-20080106003858-59857 - sp1r-brian@zim.(none)-20080123195552-31680 - sp1r-brian@zim.(none)-20080124201848-29999 - sp1r-brian@zim.(none)-20080129075144-36991 - sp1r-cbell/Chuck@mysql_cab_desk.-20080215041806-21954 - sp1r-vvaintroub@wva.-20080212124547-06272 - sp1r-dfischer/mysqldev@mysql.com/production.mysql.com-20071223184258-15140 - sp1r-brian@zim.(none)-20080206122216-35774 - sp1r-baker@bk-internal.mysql.com-20080209005622-35947 - sp1r-baker@bk-internal.mysql.com-20080224215608-24613 - sp1r-baker@bk-internal.mysql.com-20080307170710-63543 - sp1r-baker@bk-internal.mysql.com-20080312233205-13069 - sp1r-Reggie@core.-20080402175211-28643 - kpettersson@mysql.com-20080901101150-4ne74r8v0492vv42 - alik@sun.com-20090805173811-9fzt0ymcp9tsvn7k - alik@sun.com-20090805173937-fcv1fdveodq5x9gb - alik@sun.com-20090805175009-g1od16i3t1xkw2qr - kostja@sun.com-20090805200643-j9i4fy7ii8ijho5c - alik@sun.com-20090807195303-j4fb5m4l1dgdahwo - alik@sun.com-20090808114848-3rkzr9kifrijzaqy - alik@sun.com-20090810041739-ugmx34h34uid8mox - alik@sun.com-20090810105306-rf43rfyzzblsy5e7 - alik@sun.com-20090810123113-ccdjwai68b5woqdm - alik@sun.com-20090811080423-gb7pibec1znaydzy - alik@sun.com-20090811082130-5uckar1vx3kdsw7g - alik@sun.com-20090812202051-uqkfwwxxcjvo5ean The following bugfixes are also backported within this patch: - Bug#34292: netdb.h missing in hostname.cc - Bug#39153: Failing to lookup a host name can lead to crash in current IPv6 implementation - Bug#38247: Server does not resolve connecting ip's - Bug#43006: main.skip_name_resolve fails on Windows in PB2 - Bug#45606: ACL requires IPv4-mapped addresses to be used - Bug#45584: Host name cache does not work as a cache
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
21 years ago
21 years ago
21 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
21 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
22 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
22 years ago
22 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
22 years ago
26 years ago
22 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
26 years ago
26 years ago
26 years ago
21 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
21 years ago
26 years ago
26 years ago
21 years ago
26 years ago
21 years ago
21 years ago
26 years ago
21 years ago
21 years ago
21 years ago
21 years ago
21 years ago
26 years ago
26 years ago
26 years ago
Bug#18775 - Temporary table from alter table visible to other threads Continued implementation of WL#1324 (table name to filename encoding) The intermediate (not temporary) files of the new table during ALTER TABLE was visible for SHOW TABLES. These intermediate files are copies of the original table with the changes done by ALTER TABLE. After all the data is copied over from the original table, these files are renamed to the original tables file names. So they are not temporary files. They persist after ALTER TABLE, but just with another name. In 5.0 the intermediate files are invisible for SHOW TABLES because all file names beginning with "#sql" were suppressed. This failed since 5.1.6 because even temporary table names were converted when making file names from them. The prefix became converted to "@0023sql". Converting the prefix during SHOW TABLES would suppress the listing of user tables that start with "#sql". The solution of the problem is to continue the implementation of the table name to file name conversion feature. One requirement is to suppress the conversion for temporary table names. This change is straightforward for real temporary tables as there is a function that creates temporary file names. But the generated path names are located in TMPDIR and have no relation to the internal table name. This cannot be used for ALTER TABLE. Its intermediate files need to be in the same directory as the old table files. And it is necessary to be able to deduce the same path from the same table name repeatedly. Consequently the intermediate table files must be handled like normal tables. Their internal names shall start with tmp_file_prefix (#sql) and they shall not be converted like normal table names. I added a flags parameter to all relevant functions that are called from ALTER TABLE. It is used to suppress the conversion for the intermediate table files. The outcome is that the suppression of #sql in SHOW TABLES works again. It does not suppress user tables as these are converted to @0023sql on file level. This patch does also fix ALTER TABLE ... RENAME, which could not rename a table with non-ASCII characters in its name. It does also fix the problem that a user could create a table like `#sql-xxxx-yyyy`, where xxxx is mysqld's pid and yyyy is the thread ID of some other thread, which prevented this thread from running ALTER TABLE. Some of the above problems are mentioned in Bug 1405, which can be closed with this patch. This patch does also contain some minor fixes for other forgotten conversions. Still known problems are reported as bugs 21370, 21373, and 21387.
20 years ago
21 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
23 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
21 years ago
16 years ago
26 years ago
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
23 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
19 years ago
23 years ago
23 years ago
23 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
21 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Initial import of WL#3726 "DDL locking for all metadata objects". Backport of: ------------------------------------------------------------ revno: 2630.4.1 committer: Dmitry Lenev <dlenev@mysql.com> branch nick: mysql-6.0-3726-w timestamp: Fri 2008-05-23 17:54:03 +0400 message: WL#3726 "DDL locking for all metadata objects". After review fixes in progress. ------------------------------------------------------------ This is the first patch in series. It transforms the metadata locking subsystem to use a dedicated module (mdl.h,cc). No significant changes in the locking protocol. The import passes the test suite with the exception of deprecated/removed 6.0 features, and MERGE tables. The latter are subject to a fix by WL#4144. Unfortunately, the original changeset comments got lost in a merge, thus this import has its own (largely insufficient) comments. This patch fixes Bug#25144 "replication / binlog with view breaks". Warning: this patch introduces an incompatible change: Under LOCK TABLES, it's no longer possible to FLUSH a table that was not locked for WRITE. Under LOCK TABLES, it's no longer possible to DROP a table or VIEW that was not locked for WRITE. ****** Backport of: ------------------------------------------------------------ revno: 2630.4.2 committer: Dmitry Lenev <dlenev@mysql.com> branch nick: mysql-6.0-3726-w timestamp: Sat 2008-05-24 14:03:45 +0400 message: WL#3726 "DDL locking for all metadata objects". After review fixes in progress. ****** Backport of: ------------------------------------------------------------ revno: 2630.4.3 committer: Dmitry Lenev <dlenev@mysql.com> branch nick: mysql-6.0-3726-w timestamp: Sat 2008-05-24 14:08:51 +0400 message: WL#3726 "DDL locking for all metadata objects" Fixed failing Windows builds by adding mdl.cc to the lists of files needed to build server/libmysqld on Windows. ****** Backport of: ------------------------------------------------------------ revno: 2630.4.4 committer: Dmitry Lenev <dlenev@mysql.com> branch nick: mysql-6.0-3726-w timestamp: Sat 2008-05-24 21:57:58 +0400 message: WL#3726 "DDL locking for all metadata objects". Fix for assert failures in kill.test which occured when one tried to kill ALTER TABLE statement on merge table while it was waiting in wait_while_table_is_used() for other connections to close this table. These assert failures stemmed from the fact that cleanup code in this case assumed that temporary table representing new version of table was open with adding to THD::temporary_tables list while code which were opening this temporary table wasn't always fulfilling this. This patch changes code that opens new version of table to always do this linking in. It also streamlines cleanup process for cases when error occurs while we have new version of table open. ****** WL#3726 "DDL locking for all metadata objects" Add libmysqld/mdl.cc to .bzrignore. ****** Backport of: ------------------------------------------------------------ revno: 2630.4.6 committer: Dmitry Lenev <dlenev@mysql.com> branch nick: mysql-6.0-3726-w timestamp: Sun 2008-05-25 00:33:22 +0400 message: WL#3726 "DDL locking for all metadata objects". Addition to the fix of assert failures in kill.test caused by changes for this worklog. Make sure we close the new table only once.
16 years ago
23 years ago
26 years ago
26 years ago
26 years ago
23 years ago
26 years ago
26 years ago
Backport of revno ## 2617.31.1, 2617.31.3, 2617.31.4, 2617.31.5, 2617.31.12, 2617.31.15, 2617.31.15, 2617.31.16, 2617.43.1 - initial changeset that introduced the fix for Bug#989 and follow up fixes for all test suite failures introduced in the initial changeset. ------------------------------------------------------------ revno: 2617.31.1 committer: Davi Arnaut <Davi.Arnaut@Sun.COM> branch nick: 4284-6.0 timestamp: Fri 2009-03-06 19:17:00 -0300 message: Bug#989: If DROP TABLE while there's an active transaction, wrong binlog order WL#4284: Transactional DDL locking Currently the MySQL server does not keep metadata locks on schema objects for the duration of a transaction, thus failing to guarantee the integrity of the schema objects being used during the transaction and to protect then from concurrent DDL operations. This also poses a problem for replication as a DDL operation might be replicated even thought there are active transactions using the object being modified. The solution is to defer the release of metadata locks until a active transaction is either committed or rolled back. This prevents other statements from modifying the table for the entire duration of the transaction. This provides commitment ordering for guaranteeing serializability across multiple transactions. - Incompatible change: If MySQL's metadata locking system encounters a lock conflict, the usual schema is to use the try and back-off technique to avoid deadlocks -- this schema consists in releasing all locks and trying to acquire them all in one go. But in a transactional context this algorithm can't be utilized as its not possible to release locks acquired during the course of the transaction without breaking the transaction commitments. To avoid deadlocks in this case, the ER_LOCK_DEADLOCK will be returned if a lock conflict is encountered during a transaction. Let's consider an example: A transaction has two statements that modify table t1, then table t2, and then commits. The first statement of the transaction will acquire a shared metadata lock on table t1, and it will be kept utill COMMIT to ensure serializability. At the moment when the second statement attempts to acquire a shared metadata lock on t2, a concurrent ALTER or DROP statement might have locked t2 exclusively. The prescription of the current locking protocol is that the acquirer of the shared lock backs off -- gives up all his current locks and retries. This implies that the entire multi-statement transaction has to be rolled back. - Incompatible change: FLUSH commands such as FLUSH PRIVILEGES and FLUSH TABLES WITH READ LOCK won't cause locked tables to be implicitly unlocked anymore.
16 years ago
A prerequisite patch for the fix for Bug#46224 "HANDLER statements within a transaction might lead to deadlocks". Introduce a notion of a sentinel to MDL_context. A sentinel is a ticket that separates all tickets in the context into two groups: before and after it. Currently we can have (and need) only one designated sentinel -- it separates all locks taken by LOCK TABLE or HANDLER statement, which must survive COMMIT and ROLLBACK and all other locks, which must be released at COMMIT or ROLLBACK. The tricky part is maintaining the sentinel up to date when someone release its corresponding ticket. This can happen, e.g. if someone issues DROP TABLE under LOCK TABLES (generally, see all calls to release_all_locks_for_name()). MDL_context::release_ticket() is modified to take care of it. ****** A fix and a test case for Bug#46224 "HANDLER statements within a transaction might lead to deadlocks". An attempt to mix HANDLER SQL statements, which are transaction- agnostic, an open multi-statement transaction, and DDL against the involved tables (in a concurrent connection) could lead to a deadlock. The deadlock would occur when HANDLER OPEN or HANDLER READ would have to wait on a conflicting metadata lock. If the connection that issued HANDLER statement also had other metadata locks (say, acquired in scope of a transaction), a classical deadlock situation of mutual wait could occur. Incompatible change: entering LOCK TABLES mode automatically closes all open HANDLERs in the current connection. Incompatible change: previously an attempt to wait on a lock in a connection that has an open HANDLER statement could wait indefinitely/deadlock. After this patch, an error ER_LOCK_DEADLOCK is produced. The idea of the fix is to merge thd->handler_mdl_context with the main mdl_context of the connection, used for transactional locks. This makes deadlock detection possible, since all waits with locks are "visible" and available to analysis in a single MDL context of the connection. Since HANDLER locks and transactional locks have a different life cycle -- HANDLERs are explicitly open and closed, and so are HANDLER locks, explicitly acquired and released, whereas transactional locks "accumulate" till the end of a transaction and are released only with COMMIT, ROLLBACK and ROLLBACK TO SAVEPOINT, a concept of "sentinel" was introduced to MDL_context. All locks, HANDLER and others, reside in the same linked list. However, a selected element of the list separates locks with different life cycle. HANDLER locks always reside at the end of the list, after the sentinel. Transactional locks are prepended to the beginning of the list, before the sentinel. Thus, ROLLBACK, COMMIT or ROLLBACK TO SAVEPOINT, only release those locks that reside before the sentinel. HANDLER locks must be released explicitly as part of HANDLER CLOSE statement, or an implicit close. The same approach with sentinel is also employed for LOCK TABLES locks. Since HANDLER and LOCK TABLES statement has never worked together, the implementation is made simple and only maintains one sentinel, which is used either for HANDLER locks, or for LOCK TABLES locks.
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
21 years ago
21 years ago
26 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
21 years ago
26 years ago
26 years ago
21 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
23 years ago
26 years ago
26 years ago
19 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
23 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
A backporting patch for WL#4300 (Define privileges for tablespaces). Original revision in 6.0: ------------------------------------------------------------ revno: 2630.13.11 committer: Alexander Nozdrin <alik@mysql.com> branch nick: 6.0-rt-wl4300 timestamp: Thu 2008-07-24 11:44:21 +0400 message: A patch for WL#4300: Define privileges for tablespaces. ------------------------------------------------------------ per-file messages: mysql-test/r/grant.result Update result file: new columm 'Create_tablespace_priv' has been added to mysql.user. mysql-test/r/ps.result Update result file: new columm 'Create_tablespace_priv' has been added to mysql.user. mysql-test/r/system_mysql_db.result Update result file: new columm 'Create_tablespace_priv' has been added to mysql.user. mysql-test/suite/falcon/r/falcon_tablespace_priv.result Test case for WL#4300. mysql-test/suite/falcon/t/falcon_tablespace_priv.test Test case for WL#4300. mysql-test/suite/ndb/r/ndb_dd_ddl.result Test case for WL#4300. mysql-test/suite/ndb/t/ndb_dd_ddl.test Test case for WL#4300. scripts/mysql_system_tables.sql New columm 'Create_tablespace_priv' has been added to mysql.user. scripts/mysql_system_tables_data.sql 'CREATE TABLESPACE' is granted by default to the root user. scripts/mysql_system_tables_fix.sql Grant 'CREATE TABLESPACE' privilege during system table upgrade if a user had SUPER privilege. sql/sql_acl.cc Added CREATE TABLESPACE privilege. sql/sql_acl.h Added CREATE TABLESPACE privilege. sql/sql_parse.cc Check global 'CREATE TABLESPACE' privilege for the following SQL statements: - CREATE | ALTER | DROP TABLESPACE - CREATE | ALTER | DROP LOGFILE GROUP sql/sql_show.cc Added CREATE TABLESPACE privilege. sql/sql_yacc.yy Added CREATE TABLESPACE privilege.
16 years ago
A backporting patch for WL#4300 (Define privileges for tablespaces). Original revision in 6.0: ------------------------------------------------------------ revno: 2630.13.11 committer: Alexander Nozdrin <alik@mysql.com> branch nick: 6.0-rt-wl4300 timestamp: Thu 2008-07-24 11:44:21 +0400 message: A patch for WL#4300: Define privileges for tablespaces. ------------------------------------------------------------ per-file messages: mysql-test/r/grant.result Update result file: new columm 'Create_tablespace_priv' has been added to mysql.user. mysql-test/r/ps.result Update result file: new columm 'Create_tablespace_priv' has been added to mysql.user. mysql-test/r/system_mysql_db.result Update result file: new columm 'Create_tablespace_priv' has been added to mysql.user. mysql-test/suite/falcon/r/falcon_tablespace_priv.result Test case for WL#4300. mysql-test/suite/falcon/t/falcon_tablespace_priv.test Test case for WL#4300. mysql-test/suite/ndb/r/ndb_dd_ddl.result Test case for WL#4300. mysql-test/suite/ndb/t/ndb_dd_ddl.test Test case for WL#4300. scripts/mysql_system_tables.sql New columm 'Create_tablespace_priv' has been added to mysql.user. scripts/mysql_system_tables_data.sql 'CREATE TABLESPACE' is granted by default to the root user. scripts/mysql_system_tables_fix.sql Grant 'CREATE TABLESPACE' privilege during system table upgrade if a user had SUPER privilege. sql/sql_acl.cc Added CREATE TABLESPACE privilege. sql/sql_acl.h Added CREATE TABLESPACE privilege. sql/sql_parse.cc Check global 'CREATE TABLESPACE' privilege for the following SQL statements: - CREATE | ALTER | DROP TABLESPACE - CREATE | ALTER | DROP LOGFILE GROUP sql/sql_show.cc Added CREATE TABLESPACE privilege. sql/sql_yacc.yy Added CREATE TABLESPACE privilege.
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
25 years ago
26 years ago
26 years ago
22 years ago
26 years ago
26 years ago
26 years ago
Backport of revno 2630.28.10, 2630.28.31, 2630.28.26, 2630.33.1, 2630.39.1, 2630.28.29, 2630.34.3, 2630.34.2, 2630.34.1, 2630.29.29, 2630.29.28, 2630.31.1, 2630.28.13, 2630.28.10, 2617.23.14 and some other minor revisions. This patch implements: WL#4264 "Backup: Stabilize Service Interface" -- all the server prerequisites except si_objects.{h,cc} themselves (they can be just copied over, when needed). WL#4435: Support OUT-parameters in prepared statements. (and all issues in the initial patches for these two tasks, that were discovered in pushbuild and during testing). Bug#39519: mysql_stmt_close() should flush all data associated with the statement. After execution of a prepared statement, send OUT parameters of the invoked stored procedure, if any, to the client. When using the binary protocol, send the parameters in an additional result set over the wire. When using the text protocol, assign out parameters to the user variables from the CALL(@var1, @var2, ...) specification. The following refactoring has been made: - Protocol::send_fields() was renamed to Protocol::send_result_set_metadata(); - A new Protocol::send_result_set_row() was introduced to incapsulate common functionality for sending row data. - Signature of Protocol::prepare_for_send() was changed: this operation does not need a list of items, the number of items is fully sufficient. The following backward incompatible changes have been made: - CLIENT_MULTI_RESULTS is now enabled by default in the client; - CLIENT_PS_MULTI_RESUTLS is now enabled by default in the client.
16 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
25 years ago
26 years ago
26 years ago
26 years ago
22 years ago
26 years ago
22 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
26 years ago
26 years ago
23 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
26 years ago
23 years ago
26 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
23 years ago
21 years ago
23 years ago
22 years ago
23 years ago
23 years ago
23 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
21 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Fixed compiler warnings Fixed compile-pentium64 scripts Fixed wrong estimate of update_with_key_prefix in sql-bench Merge bk-internal.mysql.com:/home/bk/mysql-5.1 into mysql.com:/home/my/mysql-5.1 Fixed unsafe define of uint4korr() Fixed that --extern works with mysql-test-run.pl Small trivial cleanups This also fixes a bug in counting number of rows that are updated when we have many simultanous queries Move all connection handling and command exectuion main loop from sql_parse.cc to sql_connection.cc Split handle_one_connection() into reusable sub functions. Split create_new_thread() into reusable sub functions. Added thread_scheduler; Preliminary interface code for future thread_handling code. Use 'my_thread_id' for internal thread id's Make thr_alarm_kill() to depend on thread_id instead of thread Make thr_abort_locks_for_thread() depend on thread_id instead of thread In store_globals(), set my_thread_var->id to be thd->thread_id. Use my_thread_var->id as basis for my_thread_name() The above changes makes the connection we have between THD and threads more soft. Added a lot of DBUG_PRINT() and DBUG_ASSERT() functions Fixed compiler warnings Fixed core dumps when running with --debug Removed setting of signal masks (was never used) Made event code call pthread_exit() (portability fix) Fixed that event code doesn't call DBUG_xxx functions before my_thread_init() is called. Made handling of thread_id and thd->variables.pseudo_thread_id uniform. Removed one common 'not freed memory' warning from mysqltest Fixed a couple of usage of not initialized warnings (unlikely cases) Suppress compiler warnings from bdb and (for the moment) warnings from ndb
19 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
20 years ago
23 years ago
This changeset is largely a handler cleanup changeset (WL#3281), but includes fixes and cleanups that was found necessary while testing the handler changes Changes that requires code changes in other code of other storage engines. (Note that all changes are very straightforward and one should find all issues by compiling a --debug build and fixing all compiler errors and all asserts in field.cc while running the test suite), - New optional handler function introduced: reset() This is called after every DML statement to make it easy for a handler to statement specific cleanups. (The only case it's not called is if force the file to be closed) - handler::extra(HA_EXTRA_RESET) is removed. Code that was there before should be moved to handler::reset() - table->read_set contains a bitmap over all columns that are needed in the query. read_row() and similar functions only needs to read these columns - table->write_set contains a bitmap over all columns that will be updated in the query. write_row() and update_row() only needs to update these columns. The above bitmaps should now be up to date in all context (including ALTER TABLE, filesort()). The handler is informed of any changes to the bitmap after fix_fields() by calling the virtual function handler::column_bitmaps_signal(). If the handler does caching of these bitmaps (instead of using table->read_set, table->write_set), it should redo the caching in this code. as the signal() may be sent several times, it's probably best to set a variable in the signal and redo the caching on read_row() / write_row() if the variable was set. - Removed the read_set and write_set bitmap objects from the handler class - Removed all column bit handling functions from the handler class. (Now one instead uses the normal bitmap functions in my_bitmap.c instead of handler dedicated bitmap functions) - field->query_id is removed. One should instead instead check table->read_set and table->write_set if a field is used in the query. - handler::extra(HA_EXTRA_RETRIVE_ALL_COLS) and handler::extra(HA_EXTRA_RETRIEVE_PRIMARY_KEY) are removed. One should now instead use table->read_set to check for which columns to retrieve. - If a handler needs to call Field->val() or Field->store() on columns that are not used in the query, one should install a temporary all-columns-used map while doing so. For this, we provide the following functions: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->read_set); field->val(); dbug_tmp_restore_column_map(table->read_set, old_map); and similar for the write map: my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set); field->val(); dbug_tmp_restore_column_map(table->write_set, old_map); If this is not done, you will sooner or later hit a DBUG_ASSERT in the field store() / val() functions. (For not DBUG binaries, the dbug_tmp_restore_column_map() and dbug_tmp_restore_column_map() are inline dummy functions and should be optimized away be the compiler). - If one needs to temporary set the column map for all binaries (and not just to avoid the DBUG_ASSERT() in the Field::store() / Field::val() methods) one should use the functions tmp_use_all_columns() and tmp_restore_column_map() instead of the above dbug_ variants. - All 'status' fields in the handler base class (like records, data_file_length etc) are now stored in a 'stats' struct. This makes it easier to know what status variables are provided by the base handler. This requires some trivial variable names in the extra() function. - New virtual function handler::records(). This is called to optimize COUNT(*) if (handler::table_flags() & HA_HAS_RECORDS()) is true. (stats.records is not supposed to be an exact value. It's only has to be 'reasonable enough' for the optimizer to be able to choose a good optimization path). - Non virtual handler::init() function added for caching of virtual constants from engine. - Removed has_transactions() virtual method. Now one should instead return HA_NO_TRANSACTIONS in table_flags() if the table handler DOES NOT support transactions. - The 'xxxx_create_handler()' function now has a MEM_ROOT_root argument that is to be used with 'new handler_name()' to allocate the handler in the right area. The xxxx_create_handler() function is also responsible for any initialization of the object before returning. For example, one should change: static handler *myisam_create_handler(TABLE_SHARE *table) { return new ha_myisam(table); } -> static handler *myisam_create_handler(TABLE_SHARE *table, MEM_ROOT *mem_root) { return new (mem_root) ha_myisam(table); } - New optional virtual function: use_hidden_primary_key(). This is called in case of an update/delete when (table_flags() and HA_PRIMARY_KEY_REQUIRED_FOR_DELETE) is defined but we don't have a primary key. This allows the handler to take precisions in remembering any hidden primary key to able to update/delete any found row. The default handler marks all columns to be read. - handler::table_flags() now returns a ulonglong (to allow for more flags). - New/changed table_flags() - HA_HAS_RECORDS Set if ::records() is supported - HA_NO_TRANSACTIONS Set if engine doesn't support transactions - HA_PRIMARY_KEY_REQUIRED_FOR_DELETE Set if we should mark all primary key columns for read when reading rows as part of a DELETE statement. If there is no primary key, all columns are marked for read. - HA_PARTIAL_COLUMN_READ Set if engine will not read all columns in some cases (based on table->read_set) - HA_PRIMARY_KEY_ALLOW_RANDOM_ACCESS Renamed to HA_PRIMARY_KEY_REQUIRED_FOR_POSITION. - HA_DUPP_POS Renamed to HA_DUPLICATE_POS - HA_REQUIRES_KEY_COLUMNS_FOR_DELETE Set this if we should mark ALL key columns for read when when reading rows as part of a DELETE statement. In case of an update we will mark all keys for read for which key part changed value. - HA_STATS_RECORDS_IS_EXACT Set this if stats.records is exact. (This saves us some extra records() calls when optimizing COUNT(*)) - Removed table_flags() - HA_NOT_EXACT_COUNT Now one should instead use HA_HAS_RECORDS if handler::records() gives an exact count() and HA_STATS_RECORDS_IS_EXACT if stats.records is exact. - HA_READ_RND_SAME Removed (no one supported this one) - Removed not needed functions ha_retrieve_all_cols() and ha_retrieve_all_pk() - Renamed handler::dupp_pos to handler::dup_pos - Removed not used variable handler::sortkey Upper level handler changes: - ha_reset() now does some overall checks and calls ::reset() - ha_table_flags() added. This is a cached version of table_flags(). The cache is updated on engine creation time and updated on open. MySQL level changes (not obvious from the above): - DBUG_ASSERT() added to check that column usage matches what is set in the column usage bit maps. (This found a LOT of bugs in current column marking code). - In 5.1 before, all used columns was marked in read_set and only updated columns was marked in write_set. Now we only mark columns for which we need a value in read_set. - Column bitmaps are created in open_binary_frm() and open_table_from_share(). (Before this was in table.cc) - handler::table_flags() calls are replaced with handler::ha_table_flags() - For calling field->val() you must have the corresponding bit set in table->read_set. For calling field->store() you must have the corresponding bit set in table->write_set. (There are asserts in all store()/val() functions to catch wrong usage) - thd->set_query_id is renamed to thd->mark_used_columns and instead of setting this to an integer value, this has now the values: MARK_COLUMNS_NONE, MARK_COLUMNS_READ, MARK_COLUMNS_WRITE Changed also all variables named 'set_query_id' to mark_used_columns. - In filesort() we now inform the handler of exactly which columns are needed doing the sort and choosing the rows. - The TABLE_SHARE object has a 'all_set' column bitmap one can use when one needs a column bitmap with all columns set. (This is used for table->use_all_columns() and other places) - The TABLE object has 3 column bitmaps: - def_read_set Default bitmap for columns to be read - def_write_set Default bitmap for columns to be written - tmp_set Can be used as a temporary bitmap when needed. The table object has also two pointer to bitmaps read_set and write_set that the handler should use to find out which columns are used in which way. - count() optimization now calls handler::records() instead of using handler->stats.records (if (table_flags() & HA_HAS_RECORDS) is true). - Added extra argument to Item::walk() to indicate if we should also traverse sub queries. - Added TABLE parameter to cp_buffer_from_ref() - Don't close tables created with CREATE ... SELECT but keep them in the table cache. (Faster usage of newly created tables). New interfaces: - table->clear_column_bitmaps() to initialize the bitmaps for tables at start of new statements. - table->column_bitmaps_set() to set up new column bitmaps and signal the handler about this. - table->column_bitmaps_set_no_signal() for some few cases where we need to setup new column bitmaps but don't signal the handler (as the handler has already been signaled about these before). Used for the momement only in opt_range.cc when doing ROR scans. - table->use_all_columns() to install a bitmap where all columns are marked as use in the read and the write set. - table->default_column_bitmaps() to install the normal read and write column bitmaps, but not signaling the handler about this. This is mainly used when creating TABLE instances. - table->mark_columns_needed_for_delete(), table->mark_columns_needed_for_delete() and table->mark_columns_needed_for_insert() to allow us to put additional columns in column usage maps if handler so requires. (The handler indicates what it neads in handler->table_flags()) - table->prepare_for_position() to allow us to tell handler that it needs to read primary key parts to be able to store them in future table->position() calls. (This replaces the table->file->ha_retrieve_all_pk function) - table->mark_auto_increment_column() to tell handler are going to update columns part of any auto_increment key. - table->mark_columns_used_by_index() to mark all columns that is part of an index. It will also send extra(HA_EXTRA_KEYREAD) to handler to allow it to quickly know that it only needs to read colums that are part of the key. (The handler can also use the column map for detecting this, but simpler/faster handler can just monitor the extra() call). - table->mark_columns_used_by_index_no_reset() to in addition to other columns, also mark all columns that is used by the given key. - table->restore_column_maps_after_mark_index() to restore to default column maps after a call to table->mark_columns_used_by_index(). - New item function register_field_in_read_map(), for marking used columns in table->read_map. Used by filesort() to mark all used columns - Maintain in TABLE->merge_keys set of all keys that are used in query. (Simplices some optimization loops) - Maintain Field->part_of_key_not_clustered which is like Field->part_of_key but the field in the clustered key is not assumed to be part of all index. (used in opt_range.cc for faster loops) - dbug_tmp_use_all_columns(), dbug_tmp_restore_column_map() tmp_use_all_columns() and tmp_restore_column_map() functions to temporally mark all columns as usable. The 'dbug_' version is primarily intended inside a handler when it wants to just call Field:store() & Field::val() functions, but don't need the column maps set for any other usage. (ie:: bitmap_is_set() is never called) - We can't use compare_records() to skip updates for handlers that returns a partial column set and the read_set doesn't cover all columns in the write set. The reason for this is that if we have a column marked only for write we can't in the MySQL level know if the value changed or not. The reason this worked before was that MySQL marked all to be written columns as also to be read. The new 'optimal' bitmaps exposed this 'hidden bug'. - open_table_from_share() does not anymore setup temporary MEM_ROOT object as a thread specific variable for the handler. Instead we send the to-be-used MEMROOT to get_new_handler(). (Simpler, faster code) Bugs fixed: - Column marking was not done correctly in a lot of cases. (ALTER TABLE, when using triggers, auto_increment fields etc) (Could potentially result in wrong values inserted in table handlers relying on that the old column maps or field->set_query_id was correct) Especially when it comes to triggers, there may be cases where the old code would cause lost/wrong values for NDB and/or InnoDB tables. - Split thd->options flag OPTION_STATUS_NO_TRANS_UPDATE to two flags: OPTION_STATUS_NO_TRANS_UPDATE and OPTION_KEEP_LOG. This allowed me to remove some wrong warnings about: "Some non-transactional changed tables couldn't be rolled back" - Fixed handling of INSERT .. SELECT and CREATE ... SELECT that wrongly reset (thd->options & OPTION_STATUS_NO_TRANS_UPDATE) which caused us to loose some warnings about "Some non-transactional changed tables couldn't be rolled back") - Fixed use of uninitialized memory in ha_ndbcluster.cc::delete_table() which could cause delete_table to report random failures. - Fixed core dumps for some tests when running with --debug - Added missing FN_LIBCHAR in mysql_rm_tmp_tables() (This has probably caused us to not properly remove temporary files after crash) - slow_logs was not properly initialized, which could maybe cause extra/lost entries in slow log. - If we get an duplicate row on insert, change column map to read and write all columns while retrying the operation. This is required by the definition of REPLACE and also ensures that fields that are only part of UPDATE are properly handled. This fixed a bug in NDB and REPLACE where REPLACE wrongly copied some column values from the replaced row. - For table handler that doesn't support NULL in keys, we would give an error when creating a primary key with NULL fields, even after the fields has been automaticly converted to NOT NULL. - Creating a primary key on a SPATIAL key, would fail if field was not declared as NOT NULL. Cleanups: - Removed not used condition argument to setup_tables - Removed not needed item function reset_query_id_processor(). - Field->add_index is removed. Now this is instead maintained in (field->flags & FIELD_IN_ADD_INDEX) - Field->fieldnr is removed (use field->field_index instead) - New argument to filesort() to indicate that it should return a set of row pointers (not used columns). This allowed me to remove some references to sql_command in filesort and should also enable us to return column results in some cases where we couldn't before. - Changed column bitmap handling in opt_range.cc to be aligned with TABLE bitmap, which allowed me to use bitmap functions instead of looping over all fields to create some needed bitmaps. (Faster and smaller code) - Broke up found too long lines - Moved some variable declaration at start of function for better code readability. - Removed some not used arguments from functions. (setup_fields(), mysql_prepare_insert_check_table()) - setup_fields() now takes an enum instead of an int for marking columns usage. - For internal temporary tables, use handler::write_row(), handler::delete_row() and handler::update_row() instead of handler::ha_xxxx() for faster execution. - Changed some constants to enum's and define's. - Using separate column read and write sets allows for easier checking of timestamp field was set by statement. - Remove calls to free_io_cache() as this is now done automaticly in ha_reset() - Don't build table->normalized_path as this is now identical to table->path (after bar's fixes to convert filenames) - Fixed some missed DBUG_PRINT(.."%lx") to use "0x%lx" to make it easier to do comparision with the 'convert-dbug-for-diff' tool. Things left to do in 5.1: - We wrongly log failed CREATE TABLE ... SELECT in some cases when using row based logging (as shown by testcase binlog_row_mix_innodb_myisam.result) Mats has promised to look into this. - Test that my fix for CREATE TABLE ... SELECT is indeed correct. (I added several test cases for this, but in this case it's better that someone else also tests this throughly). Lars has promosed to do this.
20 years ago
21 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
26 years ago
26 years ago
26 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
WL#3817: Simplify string / memory area types and make things more consistent (first part) The following type conversions was done: - Changed byte to uchar - Changed gptr to uchar* - Change my_string to char * - Change my_size_t to size_t - Change size_s to size_t Removed declaration of byte, gptr, my_string, my_size_t and size_s. Following function parameter changes was done: - All string functions in mysys/strings was changed to use size_t instead of uint for string lengths. - All read()/write() functions changed to use size_t (including vio). - All protocoll functions changed to use size_t instead of uint - Functions that used a pointer to a string length was changed to use size_t* - Changed malloc(), free() and related functions from using gptr to use void * as this requires fewer casts in the code and is more in line with how the standard functions work. - Added extra length argument to dirname_part() to return the length of the created string. - Changed (at least) following functions to take uchar* as argument: - db_dump() - my_net_write() - net_write_command() - net_store_data() - DBUG_DUMP() - decimal2bin() & bin2decimal() - Changed my_compress() and my_uncompress() to use size_t. Changed one argument to my_uncompress() from a pointer to a value as we only return one value (makes function easier to use). - Changed type of 'pack_data' argument to packfrm() to avoid casts. - Changed in readfrm() and writefrom(), ha_discover and handler::discover() the type for argument 'frmdata' to uchar** to avoid casts. - Changed most Field functions to use uchar* instead of char* (reduced a lot of casts). - Changed field->val_xxx(xxx, new_ptr) to take const pointers. Other changes: - Removed a lot of not needed casts - Added a few new cast required by other changes - Added some cast to my_multi_malloc() arguments for safety (as string lengths needs to be uint, not size_t). - Fixed all calls to hash-get-key functions to use size_t*. (Needed to be done explicitely as this conflict was often hided by casting the function to hash_get_key). - Changed some buffers to memory regions to uchar* to avoid casts. - Changed some string lengths from uint to size_t. - Changed field->ptr to be uchar* instead of char*. This allowed us to get rid of a lot of casts. - Some changes from true -> TRUE, false -> FALSE, unsigned char -> uchar - Include zlib.h in some files as we needed declaration of crc32() - Changed MY_FILE_ERROR to be (size_t) -1. - Changed many variables to hold the result of my_read() / my_write() to be size_t. This was needed to properly detect errors (which are returned as (size_t) -1). - Removed some very old VMS code - Changed packfrm()/unpackfrm() to not be depending on uint size (portability fix) - Removed windows specific code to restore cursor position as this causes slowdown on windows and we should not mix read() and pread() calls anyway as this is not thread safe. Updated function comment to reflect this. Changed function that depended on original behavior of my_pwrite() to itself restore the cursor position (one such case). - Added some missing checking of return value of malloc(). - Changed definition of MOD_PAD_CHAR_TO_FULL_LENGTH to avoid 'long' overflow. - Changed type of table_def::m_size from my_size_t to ulong to reflect that m_size is the number of elements in the array, not a string/memory length. - Moved THD::max_row_length() to table.cc (as it's not depending on THD). Inlined max_row_length_blob() into this function. - More function comments - Fixed some compiler warnings when compiled without partitions. - Removed setting of LEX_STRING() arguments in declaration (portability fix). - Some trivial indentation/variable name changes. - Some trivial code simplifications: - Replaced some calls to alloc_root + memcpy to use strmake_root()/strdup_root(). - Changed some calls from memdup() to strmake() (Safety fix) - Simpler loops in client-simple.c
19 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
Re-apply missing changeset, orignally pushed by elliot Add define YASSL_PREFIX when compiling yassl Import patch from yaSSL - avoid allocating memory for each call to 'EVP_md5' and 'EVP_des_ede3_cbc' which were not released until server was stopped - Those functions are used from the SQL function 'des_encrypt' and 'des_decrypt'. Add new define YASSL_PREFIX beforee including ssl.h to activate inclusion of prefix_*.h files Bug#20022 mysql-test-run can't be run with secure connections turned on for all testcases - Part 1, fixes rpl- and federated-tests where connection is made to 127.0.0.1 - Include prefix files that renames all public functions in yaSSLs OpenSSL API to ya<function_name>. They will otherwise conflict with OpenSSL functions if loaded by an application that uses OpenSSL as well as libmysqlclient with yaSSL support. Bug#18235: assertion/crash when windows mysqld is ended with ctrl-c Two threads both try a shutdown sequence which creates a race to the de-init/free of certain resources. This exists in similar form in the client as 17926: "mysql.exe crashes when ctrl-c is pressed in windows." Update after merge to 5.0 BUG#18669: Session COM_STATISTICS breaks mysqladmin status. Changed COM_STATISTICS to display the global status, instead of thead status, for slow queries and table opens. - In function 'handle_grant_struct' when searching the memory structures for an entry to modify, convert all entries here host.hostname is NULL to "" and compare that with the host passed in argument "user_from". - A user created with hostname "" is stored in "mysql.user" table as host="" but when loaded into memory it'll be stored as host.hostname NULL. Specifiying "" as hostname means that "any host" can connect. Thus is's correct to turn on allow_all_hosts when such a user is found. - Review and fix other places where host.hostname may be NULL. BUG#19394 OPT_INNODB_THREAD_CONCURRENCY duplicated Removed duplication (not a user-visible change)
20 years ago
  1. /* Copyright (C) 2000-2003 MySQL AB, 2008-2009 Sun Microsystems, Inc
  2. This program is free software; you can redistribute it and/or modify
  3. it under the terms of the GNU General Public License as published by
  4. the Free Software Foundation; version 2 of the License.
  5. This program is distributed in the hope that it will be useful,
  6. but WITHOUT ANY WARRANTY; without even the implied warranty of
  7. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  8. GNU General Public License for more details.
  9. You should have received a copy of the GNU General Public License
  10. along with this program; if not, write to the Free Software
  11. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
  12. /*
  13. The privileges are saved in the following tables:
  14. mysql/user ; super user who are allowed to do almost anything
  15. mysql/host ; host privileges. This is used if host is empty in mysql/db.
  16. mysql/db ; database privileges / user
  17. data in tables is sorted according to how many not-wild-cards there is
  18. in the relevant fields. Empty strings comes last.
  19. */
  20. #include "my_global.h" /* NO_EMBEDDED_ACCESS_CHECKS */
  21. #include "sql_priv.h"
  22. #include "sql_acl.h" // MYSQL_DB_FIELD_COUNT, ACL_ACCESS
  23. #include "sql_base.h" // close_thread_tables
  24. #include "key.h" // key_copy, key_cmp_if_same, key_restore
  25. #include "sql_show.h" // append_identifier
  26. #include "sql_table.h" // build_table_filename
  27. #include "hash_filo.h"
  28. #include "sql_parse.h" // check_access
  29. #include "sql_view.h" // VIEW_ANY_ACL
  30. #include "records.h" // READ_RECORD, read_record_info,
  31. // init_read_record, end_read_record
  32. #include "rpl_filter.h" // rpl_filter
  33. #include <m_ctype.h>
  34. #include <stdarg.h>
  35. #include "sp_head.h"
  36. #include "sp.h"
  37. #include "transaction.h"
  38. #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
  39. #include "records.h" // init_read_record, end_read_record
  40. bool mysql_user_table_is_in_short_password_format= false;
  41. static const
  42. TABLE_FIELD_TYPE mysql_db_table_fields[MYSQL_DB_FIELD_COUNT] = {
  43. {
  44. { C_STRING_WITH_LEN("Host") },
  45. { C_STRING_WITH_LEN("char(60)") },
  46. {NULL, 0}
  47. },
  48. {
  49. { C_STRING_WITH_LEN("Db") },
  50. { C_STRING_WITH_LEN("char(64)") },
  51. {NULL, 0}
  52. },
  53. {
  54. { C_STRING_WITH_LEN("User") },
  55. { C_STRING_WITH_LEN("char(16)") },
  56. {NULL, 0}
  57. },
  58. {
  59. { C_STRING_WITH_LEN("Select_priv") },
  60. { C_STRING_WITH_LEN("enum('N','Y')") },
  61. { C_STRING_WITH_LEN("utf8") }
  62. },
  63. {
  64. { C_STRING_WITH_LEN("Insert_priv") },
  65. { C_STRING_WITH_LEN("enum('N','Y')") },
  66. { C_STRING_WITH_LEN("utf8") }
  67. },
  68. {
  69. { C_STRING_WITH_LEN("Update_priv") },
  70. { C_STRING_WITH_LEN("enum('N','Y')") },
  71. { C_STRING_WITH_LEN("utf8") }
  72. },
  73. {
  74. { C_STRING_WITH_LEN("Delete_priv") },
  75. { C_STRING_WITH_LEN("enum('N','Y')") },
  76. { C_STRING_WITH_LEN("utf8") }
  77. },
  78. {
  79. { C_STRING_WITH_LEN("Create_priv") },
  80. { C_STRING_WITH_LEN("enum('N','Y')") },
  81. { C_STRING_WITH_LEN("utf8") }
  82. },
  83. {
  84. { C_STRING_WITH_LEN("Drop_priv") },
  85. { C_STRING_WITH_LEN("enum('N','Y')") },
  86. { C_STRING_WITH_LEN("utf8") }
  87. },
  88. {
  89. { C_STRING_WITH_LEN("Grant_priv") },
  90. { C_STRING_WITH_LEN("enum('N','Y')") },
  91. { C_STRING_WITH_LEN("utf8") }
  92. },
  93. {
  94. { C_STRING_WITH_LEN("References_priv") },
  95. { C_STRING_WITH_LEN("enum('N','Y')") },
  96. { C_STRING_WITH_LEN("utf8") }
  97. },
  98. {
  99. { C_STRING_WITH_LEN("Index_priv") },
  100. { C_STRING_WITH_LEN("enum('N','Y')") },
  101. { C_STRING_WITH_LEN("utf8") }
  102. },
  103. {
  104. { C_STRING_WITH_LEN("Alter_priv") },
  105. { C_STRING_WITH_LEN("enum('N','Y')") },
  106. { C_STRING_WITH_LEN("utf8") }
  107. },
  108. {
  109. { C_STRING_WITH_LEN("Create_tmp_table_priv") },
  110. { C_STRING_WITH_LEN("enum('N','Y')") },
  111. { C_STRING_WITH_LEN("utf8") }
  112. },
  113. {
  114. { C_STRING_WITH_LEN("Lock_tables_priv") },
  115. { C_STRING_WITH_LEN("enum('N','Y')") },
  116. { C_STRING_WITH_LEN("utf8") }
  117. },
  118. {
  119. { C_STRING_WITH_LEN("Create_view_priv") },
  120. { C_STRING_WITH_LEN("enum('N','Y')") },
  121. { C_STRING_WITH_LEN("utf8") }
  122. },
  123. {
  124. { C_STRING_WITH_LEN("Show_view_priv") },
  125. { C_STRING_WITH_LEN("enum('N','Y')") },
  126. { C_STRING_WITH_LEN("utf8") }
  127. },
  128. {
  129. { C_STRING_WITH_LEN("Create_routine_priv") },
  130. { C_STRING_WITH_LEN("enum('N','Y')") },
  131. { C_STRING_WITH_LEN("utf8") }
  132. },
  133. {
  134. { C_STRING_WITH_LEN("Alter_routine_priv") },
  135. { C_STRING_WITH_LEN("enum('N','Y')") },
  136. { C_STRING_WITH_LEN("utf8") }
  137. },
  138. {
  139. { C_STRING_WITH_LEN("Execute_priv") },
  140. { C_STRING_WITH_LEN("enum('N','Y')") },
  141. { C_STRING_WITH_LEN("utf8") }
  142. },
  143. {
  144. { C_STRING_WITH_LEN("Event_priv") },
  145. { C_STRING_WITH_LEN("enum('N','Y')") },
  146. { C_STRING_WITH_LEN("utf8") }
  147. },
  148. {
  149. { C_STRING_WITH_LEN("Trigger_priv") },
  150. { C_STRING_WITH_LEN("enum('N','Y')") },
  151. { C_STRING_WITH_LEN("utf8") }
  152. }
  153. };
  154. const TABLE_FIELD_DEF
  155. mysql_db_table_def= {MYSQL_DB_FIELD_COUNT, mysql_db_table_fields};
  156. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  157. #define FIRST_NON_YN_FIELD 26
  158. class acl_entry :public hash_filo_element
  159. {
  160. public:
  161. ulong access;
  162. uint16 length;
  163. char key[1]; // Key will be stored here
  164. };
  165. static uchar* acl_entry_get_key(acl_entry *entry, size_t *length,
  166. my_bool not_used __attribute__((unused)))
  167. {
  168. *length=(uint) entry->length;
  169. return (uchar*) entry->key;
  170. }
  171. #define IP_ADDR_STRLEN (3+1+3+1+3+1+3)
  172. #define ACL_KEY_LENGTH (IP_ADDR_STRLEN+1+NAME_LEN+1+USERNAME_LENGTH+1)
  173. static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
  174. static MEM_ROOT mem, memex;
  175. static bool initialized=0;
  176. static bool allow_all_hosts=1;
  177. static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash;
  178. static DYNAMIC_ARRAY acl_wild_hosts;
  179. static hash_filo *acl_cache;
  180. static uint grant_version=0; /* Version of priv tables. incremented by acl_load */
  181. static ulong get_access(TABLE *form,uint fieldnr, uint *next_field=0);
  182. static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b);
  183. static ulong get_sort(uint count,...);
  184. static void init_check_host(void);
  185. static void rebuild_check_host(void);
  186. static ACL_USER *find_acl_user(const char *host, const char *user,
  187. my_bool exact);
  188. static bool update_user_table(THD *thd, TABLE *table,
  189. const char *host, const char *user,
  190. const char *new_password, uint new_password_len);
  191. static void update_hostname(acl_host_and_ip *host, const char *hostname);
  192. static bool compare_hostname(const acl_host_and_ip *host,const char *hostname,
  193. const char *ip);
  194. static my_bool acl_load(THD *thd, TABLE_LIST *tables);
  195. static my_bool grant_load(THD *thd, TABLE_LIST *tables);
  196. /*
  197. Convert scrambled password to binary form, according to scramble type,
  198. Binary form is stored in user.salt.
  199. */
  200. static
  201. void
  202. set_user_salt(ACL_USER *acl_user, const char *password, uint password_len)
  203. {
  204. if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH)
  205. {
  206. get_salt_from_password(acl_user->salt, password);
  207. acl_user->salt_len= SCRAMBLE_LENGTH;
  208. }
  209. else if (password_len == SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
  210. {
  211. get_salt_from_password_323((ulong *) acl_user->salt, password);
  212. acl_user->salt_len= SCRAMBLE_LENGTH_323;
  213. }
  214. else
  215. acl_user->salt_len= 0;
  216. }
  217. /*
  218. Initialize structures responsible for user/db-level privilege checking and
  219. load privilege information for them from tables in the 'mysql' database.
  220. SYNOPSIS
  221. acl_init()
  222. dont_read_acl_tables TRUE if we want to skip loading data from
  223. privilege tables and disable privilege checking.
  224. NOTES
  225. This function is mostly responsible for preparatory steps, main work
  226. on initialization and grants loading is done in acl_reload().
  227. RETURN VALUES
  228. 0 ok
  229. 1 Could not initialize grant's
  230. */
  231. my_bool acl_init(bool dont_read_acl_tables)
  232. {
  233. THD *thd;
  234. my_bool return_val;
  235. DBUG_ENTER("acl_init");
  236. acl_cache= new hash_filo(ACL_CACHE_SIZE, 0, 0,
  237. (my_hash_get_key) acl_entry_get_key,
  238. (my_hash_free_key) free,
  239. &my_charset_utf8_bin);
  240. if (dont_read_acl_tables)
  241. {
  242. DBUG_RETURN(0); /* purecov: tested */
  243. }
  244. /*
  245. To be able to run this from boot, we allocate a temporary THD
  246. */
  247. if (!(thd=new THD))
  248. DBUG_RETURN(1); /* purecov: inspected */
  249. thd->thread_stack= (char*) &thd;
  250. thd->store_globals();
  251. /*
  252. It is safe to call acl_reload() since acl_* arrays and hashes which
  253. will be freed there are global static objects and thus are initialized
  254. by zeros at startup.
  255. */
  256. return_val= acl_reload(thd);
  257. delete thd;
  258. /* Remember that we don't have a THD */
  259. my_pthread_setspecific_ptr(THR_THD, 0);
  260. DBUG_RETURN(return_val);
  261. }
  262. /*
  263. Initialize structures responsible for user/db-level privilege checking
  264. and load information about grants from open privilege tables.
  265. SYNOPSIS
  266. acl_load()
  267. thd Current thread
  268. tables List containing open "mysql.host", "mysql.user" and
  269. "mysql.db" tables.
  270. RETURN VALUES
  271. FALSE Success
  272. TRUE Error
  273. */
  274. static my_bool acl_load(THD *thd, TABLE_LIST *tables)
  275. {
  276. TABLE *table;
  277. READ_RECORD read_record_info;
  278. my_bool return_val= TRUE;
  279. bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
  280. char tmp_name[NAME_LEN+1];
  281. int password_length;
  282. ulong old_sql_mode= thd->variables.sql_mode;
  283. DBUG_ENTER("acl_load");
  284. thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
  285. grant_version++; /* Privileges updated */
  286. acl_cache->clear(1); // Clear locked hostname cache
  287. init_sql_alloc(&mem, ACL_ALLOC_BLOCK_SIZE, 0);
  288. init_read_record(&read_record_info,thd,table= tables[0].table,NULL,1,0,
  289. FALSE);
  290. table->use_all_columns();
  291. (void) my_init_dynamic_array(&acl_hosts,sizeof(ACL_HOST),20,50);
  292. while (!(read_record_info.read_record(&read_record_info)))
  293. {
  294. ACL_HOST host;
  295. update_hostname(&host.host,get_field(&mem, table->field[0]));
  296. host.db= get_field(&mem, table->field[1]);
  297. if (lower_case_table_names && host.db)
  298. {
  299. /*
  300. convert db to lower case and give a warning if the db wasn't
  301. already in lower case
  302. */
  303. (void) strmov(tmp_name, host.db);
  304. my_casedn_str(files_charset_info, host.db);
  305. if (strcmp(host.db, tmp_name) != 0)
  306. sql_print_warning("'host' entry '%s|%s' had database in mixed "
  307. "case that has been forced to lowercase because "
  308. "lower_case_table_names is set. It will not be "
  309. "possible to remove this privilege using REVOKE.",
  310. host.host.hostname ? host.host.hostname : "",
  311. host.db ? host.db : "");
  312. }
  313. host.access= get_access(table,2);
  314. host.access= fix_rights_for_db(host.access);
  315. host.sort= get_sort(2,host.host.hostname,host.db);
  316. if (check_no_resolve && hostname_requires_resolving(host.host.hostname))
  317. {
  318. sql_print_warning("'host' entry '%s|%s' "
  319. "ignored in --skip-name-resolve mode.",
  320. host.host.hostname ? host.host.hostname : "",
  321. host.db ? host.db : "");
  322. continue;
  323. }
  324. #ifndef TO_BE_REMOVED
  325. if (table->s->fields == 8)
  326. { // Without grant
  327. if (host.access & CREATE_ACL)
  328. host.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL | CREATE_TMP_ACL;
  329. }
  330. #endif
  331. (void) push_dynamic(&acl_hosts,(uchar*) &host);
  332. }
  333. my_qsort((uchar*) dynamic_element(&acl_hosts,0,ACL_HOST*),acl_hosts.elements,
  334. sizeof(ACL_HOST),(qsort_cmp) acl_compare);
  335. end_read_record(&read_record_info);
  336. freeze_size(&acl_hosts);
  337. init_read_record(&read_record_info,thd,table=tables[1].table,NULL,1,0,FALSE);
  338. table->use_all_columns();
  339. (void) my_init_dynamic_array(&acl_users,sizeof(ACL_USER),50,100);
  340. password_length= table->field[2]->field_length /
  341. table->field[2]->charset()->mbmaxlen;
  342. if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
  343. {
  344. sql_print_error("Fatal error: mysql.user table is damaged or in "
  345. "unsupported 3.20 format.");
  346. goto end;
  347. }
  348. DBUG_PRINT("info",("user table fields: %d, password length: %d",
  349. table->s->fields, password_length));
  350. mysql_mutex_lock(&LOCK_global_system_variables);
  351. if (password_length < SCRAMBLED_PASSWORD_CHAR_LENGTH)
  352. {
  353. if (opt_secure_auth)
  354. {
  355. mysql_mutex_unlock(&LOCK_global_system_variables);
  356. sql_print_error("Fatal error: mysql.user table is in old format, "
  357. "but server started with --secure-auth option.");
  358. goto end;
  359. }
  360. mysql_user_table_is_in_short_password_format= true;
  361. if (global_system_variables.old_passwords)
  362. mysql_mutex_unlock(&LOCK_global_system_variables);
  363. else
  364. {
  365. global_system_variables.old_passwords= 1;
  366. mysql_mutex_unlock(&LOCK_global_system_variables);
  367. sql_print_warning("mysql.user table is not updated to new password format; "
  368. "Disabling new password usage until "
  369. "mysql_fix_privilege_tables is run");
  370. }
  371. thd->variables.old_passwords= 1;
  372. }
  373. else
  374. {
  375. mysql_user_table_is_in_short_password_format= false;
  376. mysql_mutex_unlock(&LOCK_global_system_variables);
  377. }
  378. allow_all_hosts=0;
  379. while (!(read_record_info.read_record(&read_record_info)))
  380. {
  381. ACL_USER user;
  382. update_hostname(&user.host, get_field(&mem, table->field[0]));
  383. user.user= get_field(&mem, table->field[1]);
  384. if (check_no_resolve && hostname_requires_resolving(user.host.hostname))
  385. {
  386. sql_print_warning("'user' entry '%s@%s' "
  387. "ignored in --skip-name-resolve mode.",
  388. user.user ? user.user : "",
  389. user.host.hostname ? user.host.hostname : "");
  390. continue;
  391. }
  392. const char *password= get_field(thd->mem_root, table->field[2]);
  393. uint password_len= password ? strlen(password) : 0;
  394. set_user_salt(&user, password, password_len);
  395. if (user.salt_len == 0 && password_len != 0)
  396. {
  397. switch (password_len) {
  398. case 45: /* 4.1: to be removed */
  399. sql_print_warning("Found 4.1 style password for user '%s@%s'. "
  400. "Ignoring user. "
  401. "You should change password for this user.",
  402. user.user ? user.user : "",
  403. user.host.hostname ? user.host.hostname : "");
  404. break;
  405. default:
  406. sql_print_warning("Found invalid password for user: '%s@%s'; "
  407. "Ignoring user", user.user ? user.user : "",
  408. user.host.hostname ? user.host.hostname : "");
  409. break;
  410. }
  411. }
  412. else // password is correct
  413. {
  414. uint next_field;
  415. user.access= get_access(table,3,&next_field) & GLOBAL_ACLS;
  416. /*
  417. if it is pre 5.0.1 privilege table then map CREATE privilege on
  418. CREATE VIEW & SHOW VIEW privileges
  419. */
  420. if (table->s->fields <= 31 && (user.access & CREATE_ACL))
  421. user.access|= (CREATE_VIEW_ACL | SHOW_VIEW_ACL);
  422. /*
  423. if it is pre 5.0.2 privilege table then map CREATE/ALTER privilege on
  424. CREATE PROCEDURE & ALTER PROCEDURE privileges
  425. */
  426. if (table->s->fields <= 33 && (user.access & CREATE_ACL))
  427. user.access|= CREATE_PROC_ACL;
  428. if (table->s->fields <= 33 && (user.access & ALTER_ACL))
  429. user.access|= ALTER_PROC_ACL;
  430. /*
  431. pre 5.0.3 did not have CREATE_USER_ACL
  432. */
  433. if (table->s->fields <= 36 && (user.access & GRANT_ACL))
  434. user.access|= CREATE_USER_ACL;
  435. /*
  436. if it is pre 5.1.6 privilege table then map CREATE privilege on
  437. CREATE|ALTER|DROP|EXECUTE EVENT
  438. */
  439. if (table->s->fields <= 37 && (user.access & SUPER_ACL))
  440. user.access|= EVENT_ACL;
  441. /*
  442. if it is pre 5.1.6 privilege then map TRIGGER privilege on CREATE.
  443. */
  444. if (table->s->fields <= 38 && (user.access & SUPER_ACL))
  445. user.access|= TRIGGER_ACL;
  446. user.sort= get_sort(2,user.host.hostname,user.user);
  447. user.hostname_length= (user.host.hostname ?
  448. (uint) strlen(user.host.hostname) : 0);
  449. /* Starting from 4.0.2 we have more fields */
  450. if (table->s->fields >= 31)
  451. {
  452. char *ssl_type=get_field(thd->mem_root, table->field[next_field++]);
  453. if (!ssl_type)
  454. user.ssl_type=SSL_TYPE_NONE;
  455. else if (!strcmp(ssl_type, "ANY"))
  456. user.ssl_type=SSL_TYPE_ANY;
  457. else if (!strcmp(ssl_type, "X509"))
  458. user.ssl_type=SSL_TYPE_X509;
  459. else /* !strcmp(ssl_type, "SPECIFIED") */
  460. user.ssl_type=SSL_TYPE_SPECIFIED;
  461. user.ssl_cipher= get_field(&mem, table->field[next_field++]);
  462. user.x509_issuer= get_field(&mem, table->field[next_field++]);
  463. user.x509_subject= get_field(&mem, table->field[next_field++]);
  464. char *ptr = get_field(thd->mem_root, table->field[next_field++]);
  465. user.user_resource.questions=ptr ? atoi(ptr) : 0;
  466. ptr = get_field(thd->mem_root, table->field[next_field++]);
  467. user.user_resource.updates=ptr ? atoi(ptr) : 0;
  468. ptr = get_field(thd->mem_root, table->field[next_field++]);
  469. user.user_resource.conn_per_hour= ptr ? atoi(ptr) : 0;
  470. if (user.user_resource.questions || user.user_resource.updates ||
  471. user.user_resource.conn_per_hour)
  472. mqh_used=1;
  473. if (table->s->fields >= 36)
  474. {
  475. /* Starting from 5.0.3 we have max_user_connections field */
  476. ptr= get_field(thd->mem_root, table->field[next_field++]);
  477. user.user_resource.user_conn= ptr ? atoi(ptr) : 0;
  478. }
  479. else
  480. user.user_resource.user_conn= 0;
  481. }
  482. else
  483. {
  484. user.ssl_type=SSL_TYPE_NONE;
  485. bzero((char *)&(user.user_resource),sizeof(user.user_resource));
  486. #ifndef TO_BE_REMOVED
  487. if (table->s->fields <= 13)
  488. { // Without grant
  489. if (user.access & CREATE_ACL)
  490. user.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
  491. }
  492. /* Convert old privileges */
  493. user.access|= LOCK_TABLES_ACL | CREATE_TMP_ACL | SHOW_DB_ACL;
  494. if (user.access & FILE_ACL)
  495. user.access|= REPL_CLIENT_ACL | REPL_SLAVE_ACL;
  496. if (user.access & PROCESS_ACL)
  497. user.access|= SUPER_ACL | EXECUTE_ACL;
  498. #endif
  499. }
  500. (void) push_dynamic(&acl_users,(uchar*) &user);
  501. if (!user.host.hostname ||
  502. (user.host.hostname[0] == wild_many && !user.host.hostname[1]))
  503. allow_all_hosts=1; // Anyone can connect
  504. }
  505. }
  506. my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
  507. sizeof(ACL_USER),(qsort_cmp) acl_compare);
  508. end_read_record(&read_record_info);
  509. freeze_size(&acl_users);
  510. init_read_record(&read_record_info,thd,table=tables[2].table,NULL,1,0,FALSE);
  511. table->use_all_columns();
  512. (void) my_init_dynamic_array(&acl_dbs,sizeof(ACL_DB),50,100);
  513. while (!(read_record_info.read_record(&read_record_info)))
  514. {
  515. ACL_DB db;
  516. update_hostname(&db.host,get_field(&mem, table->field[MYSQL_DB_FIELD_HOST]));
  517. db.db=get_field(&mem, table->field[MYSQL_DB_FIELD_DB]);
  518. if (!db.db)
  519. {
  520. sql_print_warning("Found an entry in the 'db' table with empty database name; Skipped");
  521. continue;
  522. }
  523. db.user=get_field(&mem, table->field[MYSQL_DB_FIELD_USER]);
  524. if (check_no_resolve && hostname_requires_resolving(db.host.hostname))
  525. {
  526. sql_print_warning("'db' entry '%s %s@%s' "
  527. "ignored in --skip-name-resolve mode.",
  528. db.db,
  529. db.user ? db.user : "",
  530. db.host.hostname ? db.host.hostname : "");
  531. continue;
  532. }
  533. db.access=get_access(table,3);
  534. db.access=fix_rights_for_db(db.access);
  535. if (lower_case_table_names)
  536. {
  537. /*
  538. convert db to lower case and give a warning if the db wasn't
  539. already in lower case
  540. */
  541. (void)strmov(tmp_name, db.db);
  542. my_casedn_str(files_charset_info, db.db);
  543. if (strcmp(db.db, tmp_name) != 0)
  544. {
  545. sql_print_warning("'db' entry '%s %s@%s' had database in mixed "
  546. "case that has been forced to lowercase because "
  547. "lower_case_table_names is set. It will not be "
  548. "possible to remove this privilege using REVOKE.",
  549. db.db,
  550. db.user ? db.user : "",
  551. db.host.hostname ? db.host.hostname : "");
  552. }
  553. }
  554. db.sort=get_sort(3,db.host.hostname,db.db,db.user);
  555. #ifndef TO_BE_REMOVED
  556. if (table->s->fields <= 9)
  557. { // Without grant
  558. if (db.access & CREATE_ACL)
  559. db.access|=REFERENCES_ACL | INDEX_ACL | ALTER_ACL;
  560. }
  561. #endif
  562. (void) push_dynamic(&acl_dbs,(uchar*) &db);
  563. }
  564. my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
  565. sizeof(ACL_DB),(qsort_cmp) acl_compare);
  566. end_read_record(&read_record_info);
  567. freeze_size(&acl_dbs);
  568. init_check_host();
  569. initialized=1;
  570. return_val= FALSE;
  571. end:
  572. thd->variables.sql_mode= old_sql_mode;
  573. DBUG_RETURN(return_val);
  574. }
  575. void acl_free(bool end)
  576. {
  577. free_root(&mem,MYF(0));
  578. delete_dynamic(&acl_hosts);
  579. delete_dynamic(&acl_users);
  580. delete_dynamic(&acl_dbs);
  581. delete_dynamic(&acl_wild_hosts);
  582. my_hash_free(&acl_check_hosts);
  583. if (!end)
  584. acl_cache->clear(1); /* purecov: inspected */
  585. else
  586. {
  587. delete acl_cache;
  588. acl_cache=0;
  589. }
  590. }
  591. /*
  592. Forget current user/db-level privileges and read new privileges
  593. from the privilege tables.
  594. SYNOPSIS
  595. acl_reload()
  596. thd Current thread
  597. NOTE
  598. All tables of calling thread which were open and locked by LOCK TABLES
  599. statement will be unlocked and closed.
  600. This function is also used for initialization of structures responsible
  601. for user/db-level privilege checking.
  602. RETURN VALUE
  603. FALSE Success
  604. TRUE Failure
  605. */
  606. my_bool acl_reload(THD *thd)
  607. {
  608. TABLE_LIST tables[3];
  609. DYNAMIC_ARRAY old_acl_hosts,old_acl_users,old_acl_dbs;
  610. MEM_ROOT old_mem;
  611. bool old_initialized;
  612. my_bool return_val= TRUE;
  613. DBUG_ENTER("acl_reload");
  614. /*
  615. To avoid deadlocks we should obtain table locks before
  616. obtaining acl_cache->lock mutex.
  617. */
  618. bzero((char*) tables, sizeof(tables));
  619. tables[0].alias= tables[0].table_name= (char*) "host";
  620. tables[1].alias= tables[1].table_name= (char*) "user";
  621. tables[2].alias= tables[2].table_name= (char*) "db";
  622. tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
  623. tables[0].next_local= tables[0].next_global= tables+1;
  624. tables[1].next_local= tables[1].next_global= tables+2;
  625. tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_READ;
  626. tables[0].open_type= tables[1].open_type= tables[2].open_type= OT_BASE_ONLY;
  627. init_mdl_requests(tables);
  628. if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
  629. {
  630. /*
  631. Execution might have been interrupted; only print the error message
  632. if an error condition has been raised.
  633. */
  634. if (thd->stmt_da->is_error())
  635. sql_print_error("Fatal error: Can't open and lock privilege tables: %s",
  636. thd->stmt_da->message());
  637. goto end;
  638. }
  639. if ((old_initialized=initialized))
  640. mysql_mutex_lock(&acl_cache->lock);
  641. old_acl_hosts=acl_hosts;
  642. old_acl_users=acl_users;
  643. old_acl_dbs=acl_dbs;
  644. old_mem=mem;
  645. delete_dynamic(&acl_wild_hosts);
  646. my_hash_free(&acl_check_hosts);
  647. if ((return_val= acl_load(thd, tables)))
  648. { // Error. Revert to old list
  649. DBUG_PRINT("error",("Reverting to old privileges"));
  650. acl_free(); /* purecov: inspected */
  651. acl_hosts=old_acl_hosts;
  652. acl_users=old_acl_users;
  653. acl_dbs=old_acl_dbs;
  654. mem=old_mem;
  655. init_check_host();
  656. }
  657. else
  658. {
  659. free_root(&old_mem,MYF(0));
  660. delete_dynamic(&old_acl_hosts);
  661. delete_dynamic(&old_acl_users);
  662. delete_dynamic(&old_acl_dbs);
  663. }
  664. if (old_initialized)
  665. mysql_mutex_unlock(&acl_cache->lock);
  666. end:
  667. trans_commit_implicit(thd);
  668. close_thread_tables(thd);
  669. thd->mdl_context.release_transactional_locks();
  670. DBUG_RETURN(return_val);
  671. }
  672. /*
  673. Get all access bits from table after fieldnr
  674. IMPLEMENTATION
  675. We know that the access privileges ends when there is no more fields
  676. or the field is not an enum with two elements.
  677. SYNOPSIS
  678. get_access()
  679. form an open table to read privileges from.
  680. The record should be already read in table->record[0]
  681. fieldnr number of the first privilege (that is ENUM('N','Y') field
  682. next_field on return - number of the field next to the last ENUM
  683. (unless next_field == 0)
  684. RETURN VALUE
  685. privilege mask
  686. */
  687. static ulong get_access(TABLE *form, uint fieldnr, uint *next_field)
  688. {
  689. ulong access_bits=0,bit;
  690. char buff[2];
  691. String res(buff,sizeof(buff),&my_charset_latin1);
  692. Field **pos;
  693. for (pos=form->field+fieldnr, bit=1;
  694. *pos && (*pos)->real_type() == MYSQL_TYPE_ENUM &&
  695. ((Field_enum*) (*pos))->typelib->count == 2 ;
  696. pos++, fieldnr++, bit<<=1)
  697. {
  698. (*pos)->val_str(&res);
  699. if (my_toupper(&my_charset_latin1, res[0]) == 'Y')
  700. access_bits|= bit;
  701. }
  702. if (next_field)
  703. *next_field=fieldnr;
  704. return access_bits;
  705. }
  706. /*
  707. Return a number which, if sorted 'desc', puts strings in this order:
  708. no wildcards
  709. wildcards
  710. empty string
  711. */
  712. static ulong get_sort(uint count,...)
  713. {
  714. va_list args;
  715. va_start(args,count);
  716. ulong sort=0;
  717. /* Should not use this function with more than 4 arguments for compare. */
  718. DBUG_ASSERT(count <= 4);
  719. while (count--)
  720. {
  721. char *start, *str= va_arg(args,char*);
  722. uint chars= 0;
  723. uint wild_pos= 0; /* first wildcard position */
  724. if ((start= str))
  725. {
  726. for (; *str ; str++)
  727. {
  728. if (*str == wild_prefix && str[1])
  729. str++;
  730. else if (*str == wild_many || *str == wild_one)
  731. {
  732. wild_pos= (uint) (str - start) + 1;
  733. break;
  734. }
  735. chars= 128; // Marker that chars existed
  736. }
  737. }
  738. sort= (sort << 8) + (wild_pos ? min(wild_pos, 127) : chars);
  739. }
  740. va_end(args);
  741. return sort;
  742. }
  743. static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
  744. {
  745. if (a->sort > b->sort)
  746. return -1;
  747. if (a->sort < b->sort)
  748. return 1;
  749. return 0;
  750. }
  751. /*
  752. Seek ACL entry for a user, check password, SSL cypher, and if
  753. everything is OK, update THD user data and USER_RESOURCES struct.
  754. IMPLEMENTATION
  755. This function does not check if the user has any sensible privileges:
  756. only user's existence and validity is checked.
  757. Note, that entire operation is protected by acl_cache_lock.
  758. SYNOPSIS
  759. acl_getroot()
  760. thd thread handle. If all checks are OK,
  761. thd->security_ctx->priv_user/master_access are updated.
  762. thd->security_ctx->host/ip/user are used for checks.
  763. mqh user resources; on success mqh is reset, else
  764. unchanged
  765. passwd scrambled & crypted password, received from client
  766. (to check): thd->scramble or thd->scramble_323 is
  767. used to decrypt passwd, so they must contain
  768. original random string,
  769. passwd_len length of passwd, must be one of 0, 8,
  770. SCRAMBLE_LENGTH_323, SCRAMBLE_LENGTH
  771. 'thd' and 'mqh' are updated on success; other params are IN.
  772. RETURN VALUE
  773. 0 success: thd->priv_user, thd->priv_host, thd->master_access, mqh are
  774. updated
  775. 1 user not found or authentication failure
  776. 2 user found, has long (4.1.1) salt, but passwd is in old (3.23) format.
  777. -1 user found, has short (3.23) salt, but passwd is in new (4.1.1) format.
  778. */
  779. int acl_getroot(THD *thd, USER_RESOURCES *mqh,
  780. const char *passwd, uint passwd_len)
  781. {
  782. ulong user_access= NO_ACCESS;
  783. int res= 1;
  784. ACL_USER *acl_user= 0;
  785. Security_context *sctx= thd->security_ctx;
  786. DBUG_ENTER("acl_getroot");
  787. if (!initialized)
  788. {
  789. /*
  790. here if mysqld's been started with --skip-grant-tables option.
  791. */
  792. sctx->skip_grants();
  793. bzero((char*) mqh, sizeof(*mqh));
  794. DBUG_RETURN(0);
  795. }
  796. mysql_mutex_lock(&acl_cache->lock);
  797. /*
  798. Find acl entry in user database. Note, that find_acl_user is not the same,
  799. because it doesn't take into account the case when user is not empty,
  800. but acl_user->user is empty
  801. */
  802. for (uint i=0 ; i < acl_users.elements ; i++)
  803. {
  804. ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
  805. if (!acl_user_tmp->user || !strcmp(sctx->user, acl_user_tmp->user))
  806. {
  807. if (compare_hostname(&acl_user_tmp->host, sctx->host, sctx->ip))
  808. {
  809. /* check password: it should be empty or valid */
  810. if (passwd_len == acl_user_tmp->salt_len)
  811. {
  812. if (acl_user_tmp->salt_len == 0 ||
  813. (acl_user_tmp->salt_len == SCRAMBLE_LENGTH ?
  814. check_scramble(passwd, thd->scramble, acl_user_tmp->salt) :
  815. check_scramble_323(passwd, thd->scramble,
  816. (ulong *) acl_user_tmp->salt)) == 0)
  817. {
  818. acl_user= acl_user_tmp;
  819. res= 0;
  820. }
  821. }
  822. else if (passwd_len == SCRAMBLE_LENGTH &&
  823. acl_user_tmp->salt_len == SCRAMBLE_LENGTH_323)
  824. res= -1;
  825. else if (passwd_len == SCRAMBLE_LENGTH_323 &&
  826. acl_user_tmp->salt_len == SCRAMBLE_LENGTH)
  827. res= 2;
  828. /* linear search complete: */
  829. break;
  830. }
  831. }
  832. }
  833. /*
  834. This was moved to separate tree because of heavy HAVE_OPENSSL case.
  835. If acl_user is not null, res is 0.
  836. */
  837. if (acl_user)
  838. {
  839. /* OK. User found and password checked continue validation */
  840. #ifdef HAVE_OPENSSL
  841. Vio *vio=thd->net.vio;
  842. SSL *ssl= (SSL*) vio->ssl_arg;
  843. X509 *cert;
  844. #endif
  845. /*
  846. At this point we know that user is allowed to connect
  847. from given host by given username/password pair. Now
  848. we check if SSL is required, if user is using SSL and
  849. if X509 certificate attributes are OK
  850. */
  851. switch (acl_user->ssl_type) {
  852. case SSL_TYPE_NOT_SPECIFIED: // Impossible
  853. case SSL_TYPE_NONE: // SSL is not required
  854. user_access= acl_user->access;
  855. break;
  856. #ifdef HAVE_OPENSSL
  857. case SSL_TYPE_ANY: // Any kind of SSL is ok
  858. if (vio_type(vio) == VIO_TYPE_SSL)
  859. user_access= acl_user->access;
  860. break;
  861. case SSL_TYPE_X509: /* Client should have any valid certificate. */
  862. /*
  863. Connections with non-valid certificates are dropped already
  864. in sslaccept() anyway, so we do not check validity here.
  865. We need to check for absence of SSL because without SSL
  866. we should reject connection.
  867. */
  868. if (vio_type(vio) == VIO_TYPE_SSL &&
  869. SSL_get_verify_result(ssl) == X509_V_OK &&
  870. (cert= SSL_get_peer_certificate(ssl)))
  871. {
  872. user_access= acl_user->access;
  873. X509_free(cert);
  874. }
  875. break;
  876. case SSL_TYPE_SPECIFIED: /* Client should have specified attrib */
  877. /*
  878. We do not check for absence of SSL because without SSL it does
  879. not pass all checks here anyway.
  880. If cipher name is specified, we compare it to actual cipher in
  881. use.
  882. */
  883. if (vio_type(vio) != VIO_TYPE_SSL ||
  884. SSL_get_verify_result(ssl) != X509_V_OK)
  885. break;
  886. if (acl_user->ssl_cipher)
  887. {
  888. DBUG_PRINT("info",("comparing ciphers: '%s' and '%s'",
  889. acl_user->ssl_cipher,SSL_get_cipher(ssl)));
  890. if (!strcmp(acl_user->ssl_cipher,SSL_get_cipher(ssl)))
  891. user_access= acl_user->access;
  892. else
  893. {
  894. if (global_system_variables.log_warnings)
  895. sql_print_information("X509 ciphers mismatch: should be '%s' but is '%s'",
  896. acl_user->ssl_cipher,
  897. SSL_get_cipher(ssl));
  898. break;
  899. }
  900. }
  901. /* Prepare certificate (if exists) */
  902. DBUG_PRINT("info",("checkpoint 1"));
  903. if (!(cert= SSL_get_peer_certificate(ssl)))
  904. {
  905. user_access=NO_ACCESS;
  906. break;
  907. }
  908. DBUG_PRINT("info",("checkpoint 2"));
  909. /* If X509 issuer is specified, we check it... */
  910. if (acl_user->x509_issuer)
  911. {
  912. DBUG_PRINT("info",("checkpoint 3"));
  913. char *ptr = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
  914. DBUG_PRINT("info",("comparing issuers: '%s' and '%s'",
  915. acl_user->x509_issuer, ptr));
  916. if (strcmp(acl_user->x509_issuer, ptr))
  917. {
  918. if (global_system_variables.log_warnings)
  919. sql_print_information("X509 issuer mismatch: should be '%s' "
  920. "but is '%s'", acl_user->x509_issuer, ptr);
  921. free(ptr);
  922. X509_free(cert);
  923. user_access=NO_ACCESS;
  924. break;
  925. }
  926. user_access= acl_user->access;
  927. free(ptr);
  928. }
  929. DBUG_PRINT("info",("checkpoint 4"));
  930. /* X509 subject is specified, we check it .. */
  931. if (acl_user->x509_subject)
  932. {
  933. char *ptr= X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
  934. DBUG_PRINT("info",("comparing subjects: '%s' and '%s'",
  935. acl_user->x509_subject, ptr));
  936. if (strcmp(acl_user->x509_subject,ptr))
  937. {
  938. if (global_system_variables.log_warnings)
  939. sql_print_information("X509 subject mismatch: should be '%s' but is '%s'",
  940. acl_user->x509_subject, ptr);
  941. free(ptr);
  942. X509_free(cert);
  943. user_access=NO_ACCESS;
  944. break;
  945. }
  946. user_access= acl_user->access;
  947. free(ptr);
  948. }
  949. /* Deallocate the X509 certificate. */
  950. X509_free(cert);
  951. break;
  952. #else /* HAVE_OPENSSL */
  953. default:
  954. /*
  955. If we don't have SSL but SSL is required for this user the
  956. authentication should fail.
  957. */
  958. break;
  959. #endif /* HAVE_OPENSSL */
  960. }
  961. sctx->master_access= user_access;
  962. sctx->priv_user= acl_user->user ? sctx->user : (char *) "";
  963. *mqh= acl_user->user_resource;
  964. if (acl_user->host.hostname)
  965. strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1);
  966. else
  967. *sctx->priv_host= 0;
  968. }
  969. mysql_mutex_unlock(&acl_cache->lock);
  970. DBUG_RETURN(res);
  971. }
  972. /*
  973. This is like acl_getroot() above, but it doesn't check password,
  974. and we don't care about the user resources.
  975. SYNOPSIS
  976. acl_getroot_no_password()
  977. sctx Context which should be initialized
  978. user user name
  979. host host name
  980. ip IP
  981. db current data base name
  982. RETURN
  983. FALSE OK
  984. TRUE Error
  985. */
  986. bool acl_getroot_no_password(Security_context *sctx, char *user, char *host,
  987. char *ip, char *db)
  988. {
  989. int res= 1;
  990. uint i;
  991. ACL_USER *acl_user= 0;
  992. DBUG_ENTER("acl_getroot_no_password");
  993. DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', db: '%s'",
  994. (host ? host : "(NULL)"), (ip ? ip : "(NULL)"),
  995. user, (db ? db : "(NULL)")));
  996. sctx->user= user;
  997. sctx->host= host;
  998. sctx->ip= ip;
  999. sctx->host_or_ip= host ? host : (ip ? ip : "");
  1000. if (!initialized)
  1001. {
  1002. /*
  1003. here if mysqld's been started with --skip-grant-tables option.
  1004. */
  1005. sctx->skip_grants();
  1006. DBUG_RETURN(FALSE);
  1007. }
  1008. mysql_mutex_lock(&acl_cache->lock);
  1009. sctx->master_access= 0;
  1010. sctx->db_access= 0;
  1011. sctx->priv_user= (char *) "";
  1012. *sctx->priv_host= 0;
  1013. /*
  1014. Find acl entry in user database.
  1015. This is specially tailored to suit the check we do for CALL of
  1016. a stored procedure; user is set to what is actually a
  1017. priv_user, which can be ''.
  1018. */
  1019. for (i=0 ; i < acl_users.elements ; i++)
  1020. {
  1021. ACL_USER *acl_user_tmp= dynamic_element(&acl_users,i,ACL_USER*);
  1022. if ((!acl_user_tmp->user && !user[0]) ||
  1023. (acl_user_tmp->user && strcmp(user, acl_user_tmp->user) == 0))
  1024. {
  1025. if (compare_hostname(&acl_user_tmp->host, host, ip))
  1026. {
  1027. acl_user= acl_user_tmp;
  1028. res= 0;
  1029. break;
  1030. }
  1031. }
  1032. }
  1033. if (acl_user)
  1034. {
  1035. for (i=0 ; i < acl_dbs.elements ; i++)
  1036. {
  1037. ACL_DB *acl_db= dynamic_element(&acl_dbs, i, ACL_DB*);
  1038. if (!acl_db->user ||
  1039. (user && user[0] && !strcmp(user, acl_db->user)))
  1040. {
  1041. if (compare_hostname(&acl_db->host, host, ip))
  1042. {
  1043. if (!acl_db->db || (db && !wild_compare(db, acl_db->db, 0)))
  1044. {
  1045. sctx->db_access= acl_db->access;
  1046. break;
  1047. }
  1048. }
  1049. }
  1050. }
  1051. sctx->master_access= acl_user->access;
  1052. sctx->priv_user= acl_user->user ? user : (char *) "";
  1053. if (acl_user->host.hostname)
  1054. strmake(sctx->priv_host, acl_user->host.hostname, MAX_HOSTNAME - 1);
  1055. else
  1056. *sctx->priv_host= 0;
  1057. }
  1058. mysql_mutex_unlock(&acl_cache->lock);
  1059. DBUG_RETURN(res);
  1060. }
  1061. static uchar* check_get_key(ACL_USER *buff, size_t *length,
  1062. my_bool not_used __attribute__((unused)))
  1063. {
  1064. *length=buff->hostname_length;
  1065. return (uchar*) buff->host.hostname;
  1066. }
  1067. static void acl_update_user(const char *user, const char *host,
  1068. const char *password, uint password_len,
  1069. enum SSL_type ssl_type,
  1070. const char *ssl_cipher,
  1071. const char *x509_issuer,
  1072. const char *x509_subject,
  1073. USER_RESOURCES *mqh,
  1074. ulong privileges)
  1075. {
  1076. mysql_mutex_assert_owner(&acl_cache->lock);
  1077. for (uint i=0 ; i < acl_users.elements ; i++)
  1078. {
  1079. ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  1080. if ((!acl_user->user && !user[0]) ||
  1081. (acl_user->user && !strcmp(user,acl_user->user)))
  1082. {
  1083. if ((!acl_user->host.hostname && !host[0]) ||
  1084. (acl_user->host.hostname &&
  1085. !my_strcasecmp(system_charset_info, host, acl_user->host.hostname)))
  1086. {
  1087. acl_user->access=privileges;
  1088. if (mqh->specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
  1089. acl_user->user_resource.questions=mqh->questions;
  1090. if (mqh->specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
  1091. acl_user->user_resource.updates=mqh->updates;
  1092. if (mqh->specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
  1093. acl_user->user_resource.conn_per_hour= mqh->conn_per_hour;
  1094. if (mqh->specified_limits & USER_RESOURCES::USER_CONNECTIONS)
  1095. acl_user->user_resource.user_conn= mqh->user_conn;
  1096. if (ssl_type != SSL_TYPE_NOT_SPECIFIED)
  1097. {
  1098. acl_user->ssl_type= ssl_type;
  1099. acl_user->ssl_cipher= (ssl_cipher ? strdup_root(&mem,ssl_cipher) :
  1100. 0);
  1101. acl_user->x509_issuer= (x509_issuer ? strdup_root(&mem,x509_issuer) :
  1102. 0);
  1103. acl_user->x509_subject= (x509_subject ?
  1104. strdup_root(&mem,x509_subject) : 0);
  1105. }
  1106. if (password)
  1107. set_user_salt(acl_user, password, password_len);
  1108. /* search complete: */
  1109. break;
  1110. }
  1111. }
  1112. }
  1113. }
  1114. static void acl_insert_user(const char *user, const char *host,
  1115. const char *password, uint password_len,
  1116. enum SSL_type ssl_type,
  1117. const char *ssl_cipher,
  1118. const char *x509_issuer,
  1119. const char *x509_subject,
  1120. USER_RESOURCES *mqh,
  1121. ulong privileges)
  1122. {
  1123. ACL_USER acl_user;
  1124. mysql_mutex_assert_owner(&acl_cache->lock);
  1125. acl_user.user=*user ? strdup_root(&mem,user) : 0;
  1126. update_hostname(&acl_user.host, *host ? strdup_root(&mem, host): 0);
  1127. acl_user.access=privileges;
  1128. acl_user.user_resource = *mqh;
  1129. acl_user.sort=get_sort(2,acl_user.host.hostname,acl_user.user);
  1130. acl_user.hostname_length=(uint) strlen(host);
  1131. acl_user.ssl_type= (ssl_type != SSL_TYPE_NOT_SPECIFIED ?
  1132. ssl_type : SSL_TYPE_NONE);
  1133. acl_user.ssl_cipher= ssl_cipher ? strdup_root(&mem,ssl_cipher) : 0;
  1134. acl_user.x509_issuer= x509_issuer ? strdup_root(&mem,x509_issuer) : 0;
  1135. acl_user.x509_subject=x509_subject ? strdup_root(&mem,x509_subject) : 0;
  1136. set_user_salt(&acl_user, password, password_len);
  1137. (void) push_dynamic(&acl_users,(uchar*) &acl_user);
  1138. if (!acl_user.host.hostname ||
  1139. (acl_user.host.hostname[0] == wild_many && !acl_user.host.hostname[1]))
  1140. allow_all_hosts=1; // Anyone can connect /* purecov: tested */
  1141. my_qsort((uchar*) dynamic_element(&acl_users,0,ACL_USER*),acl_users.elements,
  1142. sizeof(ACL_USER),(qsort_cmp) acl_compare);
  1143. /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
  1144. rebuild_check_host();
  1145. }
  1146. static void acl_update_db(const char *user, const char *host, const char *db,
  1147. ulong privileges)
  1148. {
  1149. mysql_mutex_assert_owner(&acl_cache->lock);
  1150. for (uint i=0 ; i < acl_dbs.elements ; i++)
  1151. {
  1152. ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
  1153. if ((!acl_db->user && !user[0]) ||
  1154. (acl_db->user &&
  1155. !strcmp(user,acl_db->user)))
  1156. {
  1157. if ((!acl_db->host.hostname && !host[0]) ||
  1158. (acl_db->host.hostname &&
  1159. !strcmp(host, acl_db->host.hostname)))
  1160. {
  1161. if ((!acl_db->db && !db[0]) ||
  1162. (acl_db->db && !strcmp(db,acl_db->db)))
  1163. {
  1164. if (privileges)
  1165. acl_db->access=privileges;
  1166. else
  1167. delete_dynamic_element(&acl_dbs,i);
  1168. }
  1169. }
  1170. }
  1171. }
  1172. }
  1173. /*
  1174. Insert a user/db/host combination into the global acl_cache
  1175. SYNOPSIS
  1176. acl_insert_db()
  1177. user User name
  1178. host Host name
  1179. db Database name
  1180. privileges Bitmap of privileges
  1181. NOTES
  1182. acl_cache->lock must be locked when calling this
  1183. */
  1184. static void acl_insert_db(const char *user, const char *host, const char *db,
  1185. ulong privileges)
  1186. {
  1187. ACL_DB acl_db;
  1188. mysql_mutex_assert_owner(&acl_cache->lock);
  1189. acl_db.user=strdup_root(&mem,user);
  1190. update_hostname(&acl_db.host, *host ? strdup_root(&mem,host) : 0);
  1191. acl_db.db=strdup_root(&mem,db);
  1192. acl_db.access=privileges;
  1193. acl_db.sort=get_sort(3,acl_db.host.hostname,acl_db.db,acl_db.user);
  1194. (void) push_dynamic(&acl_dbs,(uchar*) &acl_db);
  1195. my_qsort((uchar*) dynamic_element(&acl_dbs,0,ACL_DB*),acl_dbs.elements,
  1196. sizeof(ACL_DB),(qsort_cmp) acl_compare);
  1197. }
  1198. /*
  1199. Get privilege for a host, user and db combination
  1200. as db_is_pattern changes the semantics of comparison,
  1201. acl_cache is not used if db_is_pattern is set.
  1202. */
  1203. ulong acl_get(const char *host, const char *ip,
  1204. const char *user, const char *db, my_bool db_is_pattern)
  1205. {
  1206. ulong host_access= ~(ulong)0, db_access= 0;
  1207. uint i;
  1208. size_t key_length;
  1209. char key[ACL_KEY_LENGTH],*tmp_db,*end;
  1210. acl_entry *entry;
  1211. DBUG_ENTER("acl_get");
  1212. mysql_mutex_lock(&acl_cache->lock);
  1213. end=strmov((tmp_db=strmov(strmov(key, ip ? ip : "")+1,user)+1),db);
  1214. if (lower_case_table_names)
  1215. {
  1216. my_casedn_str(files_charset_info, tmp_db);
  1217. db=tmp_db;
  1218. }
  1219. key_length= (size_t) (end-key);
  1220. if (!db_is_pattern && (entry=(acl_entry*) acl_cache->search((uchar*) key,
  1221. key_length)))
  1222. {
  1223. db_access=entry->access;
  1224. mysql_mutex_unlock(&acl_cache->lock);
  1225. DBUG_PRINT("exit", ("access: 0x%lx", db_access));
  1226. DBUG_RETURN(db_access);
  1227. }
  1228. /*
  1229. Check if there are some access rights for database and user
  1230. */
  1231. for (i=0 ; i < acl_dbs.elements ; i++)
  1232. {
  1233. ACL_DB *acl_db=dynamic_element(&acl_dbs,i,ACL_DB*);
  1234. if (!acl_db->user || !strcmp(user,acl_db->user))
  1235. {
  1236. if (compare_hostname(&acl_db->host,host,ip))
  1237. {
  1238. if (!acl_db->db || !wild_compare(db,acl_db->db,db_is_pattern))
  1239. {
  1240. db_access=acl_db->access;
  1241. if (acl_db->host.hostname)
  1242. goto exit; // Fully specified. Take it
  1243. break; /* purecov: tested */
  1244. }
  1245. }
  1246. }
  1247. }
  1248. if (!db_access)
  1249. goto exit; // Can't be better
  1250. /*
  1251. No host specified for user. Get hostdata from host table
  1252. */
  1253. host_access=0; // Host must be found
  1254. for (i=0 ; i < acl_hosts.elements ; i++)
  1255. {
  1256. ACL_HOST *acl_host=dynamic_element(&acl_hosts,i,ACL_HOST*);
  1257. if (compare_hostname(&acl_host->host,host,ip))
  1258. {
  1259. if (!acl_host->db || !wild_compare(db,acl_host->db,db_is_pattern))
  1260. {
  1261. host_access=acl_host->access; // Fully specified. Take it
  1262. break;
  1263. }
  1264. }
  1265. }
  1266. exit:
  1267. /* Save entry in cache for quick retrieval */
  1268. if (!db_is_pattern &&
  1269. (entry= (acl_entry*) malloc(sizeof(acl_entry)+key_length)))
  1270. {
  1271. entry->access=(db_access & host_access);
  1272. entry->length=key_length;
  1273. memcpy((uchar*) entry->key,key,key_length);
  1274. acl_cache->add(entry);
  1275. }
  1276. mysql_mutex_unlock(&acl_cache->lock);
  1277. DBUG_PRINT("exit", ("access: 0x%lx", db_access & host_access));
  1278. DBUG_RETURN(db_access & host_access);
  1279. }
  1280. /*
  1281. Check if there are any possible matching entries for this host
  1282. NOTES
  1283. All host names without wild cards are stored in a hash table,
  1284. entries with wildcards are stored in a dynamic array
  1285. */
  1286. static void init_check_host(void)
  1287. {
  1288. DBUG_ENTER("init_check_host");
  1289. (void) my_init_dynamic_array(&acl_wild_hosts,sizeof(struct acl_host_and_ip),
  1290. acl_users.elements,1);
  1291. (void) my_hash_init(&acl_check_hosts,system_charset_info,
  1292. acl_users.elements, 0, 0,
  1293. (my_hash_get_key) check_get_key, 0, 0);
  1294. if (!allow_all_hosts)
  1295. {
  1296. for (uint i=0 ; i < acl_users.elements ; i++)
  1297. {
  1298. ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  1299. if (strchr(acl_user->host.hostname,wild_many) ||
  1300. strchr(acl_user->host.hostname,wild_one) ||
  1301. acl_user->host.ip_mask)
  1302. { // Has wildcard
  1303. uint j;
  1304. for (j=0 ; j < acl_wild_hosts.elements ; j++)
  1305. { // Check if host already exists
  1306. acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,j,
  1307. acl_host_and_ip *);
  1308. if (!my_strcasecmp(system_charset_info,
  1309. acl_user->host.hostname, acl->hostname))
  1310. break; // already stored
  1311. }
  1312. if (j == acl_wild_hosts.elements) // If new
  1313. (void) push_dynamic(&acl_wild_hosts,(uchar*) &acl_user->host);
  1314. }
  1315. else if (!my_hash_search(&acl_check_hosts,(uchar*)
  1316. acl_user->host.hostname,
  1317. strlen(acl_user->host.hostname)))
  1318. {
  1319. if (my_hash_insert(&acl_check_hosts,(uchar*) acl_user))
  1320. { // End of memory
  1321. allow_all_hosts=1; // Should never happen
  1322. DBUG_VOID_RETURN;
  1323. }
  1324. }
  1325. }
  1326. }
  1327. freeze_size(&acl_wild_hosts);
  1328. freeze_size(&acl_check_hosts.array);
  1329. DBUG_VOID_RETURN;
  1330. }
  1331. /*
  1332. Rebuild lists used for checking of allowed hosts
  1333. We need to rebuild 'acl_check_hosts' and 'acl_wild_hosts' after adding,
  1334. dropping or renaming user, since they contain pointers to elements of
  1335. 'acl_user' array, which are invalidated by drop operation, and use
  1336. ACL_USER::host::hostname as a key, which is changed by rename.
  1337. */
  1338. void rebuild_check_host(void)
  1339. {
  1340. delete_dynamic(&acl_wild_hosts);
  1341. my_hash_free(&acl_check_hosts);
  1342. init_check_host();
  1343. }
  1344. /* Return true if there is no users that can match the given host */
  1345. bool acl_check_host(const char *host, const char *ip)
  1346. {
  1347. if (allow_all_hosts)
  1348. return 0;
  1349. mysql_mutex_lock(&acl_cache->lock);
  1350. if ((host && my_hash_search(&acl_check_hosts,(uchar*) host,strlen(host))) ||
  1351. (ip && my_hash_search(&acl_check_hosts,(uchar*) ip, strlen(ip))))
  1352. {
  1353. mysql_mutex_unlock(&acl_cache->lock);
  1354. return 0; // Found host
  1355. }
  1356. for (uint i=0 ; i < acl_wild_hosts.elements ; i++)
  1357. {
  1358. acl_host_and_ip *acl=dynamic_element(&acl_wild_hosts,i,acl_host_and_ip*);
  1359. if (compare_hostname(acl, host, ip))
  1360. {
  1361. mysql_mutex_unlock(&acl_cache->lock);
  1362. return 0; // Host ok
  1363. }
  1364. }
  1365. mysql_mutex_unlock(&acl_cache->lock);
  1366. return 1; // Host is not allowed
  1367. }
  1368. /*
  1369. Check if the user is allowed to change password
  1370. SYNOPSIS:
  1371. check_change_password()
  1372. thd THD
  1373. host hostname for the user
  1374. user user name
  1375. new_password new password
  1376. NOTE:
  1377. new_password cannot be NULL
  1378. RETURN VALUE
  1379. 0 OK
  1380. 1 ERROR ; In this case the error is sent to the client.
  1381. */
  1382. int check_change_password(THD *thd, const char *host, const char *user,
  1383. char *new_password, uint new_password_len)
  1384. {
  1385. if (!initialized)
  1386. {
  1387. my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
  1388. return(1);
  1389. }
  1390. if (!thd->slave_thread &&
  1391. (strcmp(thd->security_ctx->user, user) ||
  1392. my_strcasecmp(system_charset_info, host,
  1393. thd->security_ctx->priv_host)))
  1394. {
  1395. if (check_access(thd, UPDATE_ACL, "mysql", NULL, NULL, 1, 0))
  1396. return(1);
  1397. }
  1398. if (!thd->slave_thread && !thd->security_ctx->user[0])
  1399. {
  1400. my_message(ER_PASSWORD_ANONYMOUS_USER, ER(ER_PASSWORD_ANONYMOUS_USER),
  1401. MYF(0));
  1402. return(1);
  1403. }
  1404. size_t len= strlen(new_password);
  1405. if (len && len != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
  1406. len != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
  1407. {
  1408. my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
  1409. return -1;
  1410. }
  1411. return(0);
  1412. }
  1413. /*
  1414. Change a password for a user
  1415. SYNOPSIS
  1416. change_password()
  1417. thd Thread handle
  1418. host Hostname
  1419. user User name
  1420. new_password New password for host@user
  1421. RETURN VALUES
  1422. 0 ok
  1423. 1 ERROR; In this case the error is sent to the client.
  1424. */
  1425. bool change_password(THD *thd, const char *host, const char *user,
  1426. char *new_password)
  1427. {
  1428. TABLE_LIST tables;
  1429. TABLE *table;
  1430. /* Buffer should be extended when password length is extended. */
  1431. char buff[512];
  1432. ulong query_length;
  1433. uint new_password_len= (uint) strlen(new_password);
  1434. bool result= 1;
  1435. DBUG_ENTER("change_password");
  1436. DBUG_PRINT("enter",("host: '%s' user: '%s' new_password: '%s'",
  1437. host,user,new_password));
  1438. DBUG_ASSERT(host != 0); // Ensured by parent
  1439. if (check_change_password(thd, host, user, new_password, new_password_len))
  1440. DBUG_RETURN(1);
  1441. tables.init_one_table("mysql", 5, "user", 4, "user", TL_WRITE);
  1442. #ifdef HAVE_REPLICATION
  1443. /*
  1444. GRANT and REVOKE are applied the slave in/exclusion rules as they are
  1445. some kind of updates to the mysql.% tables.
  1446. */
  1447. if (thd->slave_thread && rpl_filter->is_on())
  1448. {
  1449. /*
  1450. The tables must be marked "updating" so that tables_ok() takes them into
  1451. account in tests. It's ok to leave 'updating' set after tables_ok.
  1452. */
  1453. tables.updating= 1;
  1454. /* Thanks to bzero, tables.next==0 */
  1455. if (!(thd->spcont || rpl_filter->tables_ok(0, &tables)))
  1456. DBUG_RETURN(0);
  1457. }
  1458. #endif
  1459. if (!(table= open_ltable(thd, &tables, TL_WRITE, MYSQL_LOCK_IGNORE_TIMEOUT)))
  1460. DBUG_RETURN(1);
  1461. mysql_mutex_lock(&acl_cache->lock);
  1462. ACL_USER *acl_user;
  1463. if (!(acl_user= find_acl_user(host, user, TRUE)))
  1464. {
  1465. mysql_mutex_unlock(&acl_cache->lock);
  1466. my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
  1467. goto end;
  1468. }
  1469. /* update loaded acl entry: */
  1470. set_user_salt(acl_user, new_password, new_password_len);
  1471. if (update_user_table(thd, table,
  1472. acl_user->host.hostname ? acl_user->host.hostname : "",
  1473. acl_user->user ? acl_user->user : "",
  1474. new_password, new_password_len))
  1475. {
  1476. mysql_mutex_unlock(&acl_cache->lock); /* purecov: deadcode */
  1477. goto end;
  1478. }
  1479. acl_cache->clear(1); // Clear locked hostname cache
  1480. mysql_mutex_unlock(&acl_cache->lock);
  1481. result= 0;
  1482. if (mysql_bin_log.is_open())
  1483. {
  1484. query_length=
  1485. my_sprintf(buff,
  1486. (buff,"SET PASSWORD FOR '%-.120s'@'%-.120s'='%-.120s'",
  1487. acl_user->user ? acl_user->user : "",
  1488. acl_user->host.hostname ? acl_user->host.hostname : "",
  1489. new_password));
  1490. thd->clear_error();
  1491. result= thd->binlog_query(THD::STMT_QUERY_TYPE, buff, query_length,
  1492. FALSE, FALSE, FALSE, 0);
  1493. }
  1494. end:
  1495. close_thread_tables(thd);
  1496. DBUG_RETURN(result);
  1497. }
  1498. /*
  1499. Find user in ACL
  1500. SYNOPSIS
  1501. is_acl_user()
  1502. host host name
  1503. user user name
  1504. RETURN
  1505. FALSE user not fond
  1506. TRUE there are such user
  1507. */
  1508. bool is_acl_user(const char *host, const char *user)
  1509. {
  1510. bool res;
  1511. /* --skip-grants */
  1512. if (!initialized)
  1513. return TRUE;
  1514. mysql_mutex_lock(&acl_cache->lock);
  1515. res= find_acl_user(host, user, TRUE) != NULL;
  1516. mysql_mutex_unlock(&acl_cache->lock);
  1517. return res;
  1518. }
  1519. /*
  1520. Find first entry that matches the current user
  1521. */
  1522. static ACL_USER *
  1523. find_acl_user(const char *host, const char *user, my_bool exact)
  1524. {
  1525. DBUG_ENTER("find_acl_user");
  1526. DBUG_PRINT("enter",("host: '%s' user: '%s'",host,user));
  1527. mysql_mutex_assert_owner(&acl_cache->lock);
  1528. for (uint i=0 ; i < acl_users.elements ; i++)
  1529. {
  1530. ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
  1531. DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),",
  1532. user, acl_user->user ? acl_user->user : "",
  1533. host,
  1534. acl_user->host.hostname ? acl_user->host.hostname :
  1535. ""));
  1536. if ((!acl_user->user && !user[0]) ||
  1537. (acl_user->user && !strcmp(user,acl_user->user)))
  1538. {
  1539. if (exact ? !my_strcasecmp(system_charset_info, host,
  1540. acl_user->host.hostname ?
  1541. acl_user->host.hostname : "") :
  1542. compare_hostname(&acl_user->host,host,host))
  1543. {
  1544. DBUG_RETURN(acl_user);
  1545. }
  1546. }
  1547. }
  1548. DBUG_RETURN(0);
  1549. }
  1550. /*
  1551. Comparing of hostnames
  1552. NOTES
  1553. A hostname may be of type:
  1554. hostname (May include wildcards); monty.pp.sci.fi
  1555. ip (May include wildcards); 192.168.0.0
  1556. ip/netmask 192.168.0.0/255.255.255.0
  1557. A net mask of 0.0.0.0 is not allowed.
  1558. */
  1559. static const char *calc_ip(const char *ip, long *val, char end)
  1560. {
  1561. long ip_val,tmp;
  1562. if (!(ip=str2int(ip,10,0,255,&ip_val)) || *ip != '.')
  1563. return 0;
  1564. ip_val<<=24;
  1565. if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
  1566. return 0;
  1567. ip_val+=tmp<<16;
  1568. if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != '.')
  1569. return 0;
  1570. ip_val+=tmp<<8;
  1571. if (!(ip=str2int(ip+1,10,0,255,&tmp)) || *ip != end)
  1572. return 0;
  1573. *val=ip_val+tmp;
  1574. return ip;
  1575. }
  1576. static void update_hostname(acl_host_and_ip *host, const char *hostname)
  1577. {
  1578. host->hostname=(char*) hostname; // This will not be modified!
  1579. if (!hostname ||
  1580. (!(hostname=calc_ip(hostname,&host->ip,'/')) ||
  1581. !(hostname=calc_ip(hostname+1,&host->ip_mask,'\0'))))
  1582. {
  1583. host->ip= host->ip_mask=0; // Not a masked ip
  1584. }
  1585. }
  1586. static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
  1587. const char *ip)
  1588. {
  1589. long tmp;
  1590. if (host->ip_mask && ip && calc_ip(ip,&tmp,'\0'))
  1591. {
  1592. return (tmp & host->ip_mask) == host->ip;
  1593. }
  1594. return (!host->hostname ||
  1595. (hostname && !wild_case_compare(system_charset_info,
  1596. hostname, host->hostname)) ||
  1597. (ip && !wild_compare(ip, host->hostname, 0)));
  1598. }
  1599. /**
  1600. Check if the given host name needs to be resolved or not.
  1601. Host name has to be resolved if it actually contains *name*.
  1602. For example:
  1603. 192.168.1.1 --> FALSE
  1604. 192.168.1.0/255.255.255.0 --> FALSE
  1605. % --> FALSE
  1606. 192.168.1.% --> FALSE
  1607. AB% --> FALSE
  1608. AAAAFFFF --> TRUE (Hostname)
  1609. AAAA:FFFF:1234:5678 --> FALSE
  1610. ::1 --> FALSE
  1611. This function does not check if the given string is a valid host name or
  1612. not. It assumes that the argument is a valid host name.
  1613. @param hostname the string to check.
  1614. @return a flag telling if the argument needs to be resolved or not.
  1615. @retval TRUE the argument is a host name and needs to be resolved.
  1616. @retval FALSE the argument is either an IP address, or a patter and
  1617. should not be resolved.
  1618. */
  1619. bool hostname_requires_resolving(const char *hostname)
  1620. {
  1621. if (!hostname)
  1622. return FALSE;
  1623. /* Check if hostname is the localhost. */
  1624. size_t hostname_len= strlen(hostname);
  1625. size_t localhost_len= strlen(my_localhost);
  1626. if (hostname == my_localhost ||
  1627. (hostname_len == localhost_len &&
  1628. !my_strnncoll(system_charset_info,
  1629. (const uchar *) hostname, hostname_len,
  1630. (const uchar *) my_localhost, strlen(my_localhost))))
  1631. {
  1632. return FALSE;
  1633. }
  1634. /*
  1635. If the string contains any of {':', '%', '_', '/'}, it is definitely
  1636. not a host name:
  1637. - ':' means that the string is an IPv6 address;
  1638. - '%' or '_' means that the string is a pattern;
  1639. - '/' means that the string is an IPv4 network address;
  1640. */
  1641. for (const char *p= hostname; *p; ++p)
  1642. {
  1643. switch (*p) {
  1644. case ':':
  1645. case '%':
  1646. case '_':
  1647. case '/':
  1648. return FALSE;
  1649. }
  1650. }
  1651. /*
  1652. Now we have to tell a host name (ab.cd, 12.ab) from an IPv4 address
  1653. (12.34.56.78). The assumption is that if the string contains only
  1654. digits and dots, it is an IPv4 address. Otherwise -- a host name.
  1655. */
  1656. for (const char *p= hostname; *p; ++p)
  1657. {
  1658. if (*p != '.' && !my_isdigit(&my_charset_latin1, *p))
  1659. return TRUE; /* a "letter" has been found. */
  1660. }
  1661. return FALSE; /* all characters are either dots or digits. */
  1662. }
  1663. /*
  1664. Update record for user in mysql.user privilege table with new password.
  1665. SYNOPSIS
  1666. update_user_table()
  1667. thd Thread handle
  1668. table Pointer to TABLE object for open mysql.user table
  1669. host/user Hostname/username pair identifying user for which
  1670. new password should be set
  1671. new_password New password
  1672. new_password_len Length of new password
  1673. */
  1674. static bool update_user_table(THD *thd, TABLE *table,
  1675. const char *host, const char *user,
  1676. const char *new_password, uint new_password_len)
  1677. {
  1678. char user_key[MAX_KEY_LENGTH];
  1679. int error;
  1680. DBUG_ENTER("update_user_table");
  1681. DBUG_PRINT("enter",("user: %s host: %s",user,host));
  1682. table->use_all_columns();
  1683. table->field[0]->store(host,(uint) strlen(host), system_charset_info);
  1684. table->field[1]->store(user,(uint) strlen(user), system_charset_info);
  1685. key_copy((uchar *) user_key, table->record[0], table->key_info,
  1686. table->key_info->key_length);
  1687. if (table->file->index_read_idx_map(table->record[0], 0,
  1688. (uchar *) user_key, HA_WHOLE_KEY,
  1689. HA_READ_KEY_EXACT))
  1690. {
  1691. my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
  1692. MYF(0)); /* purecov: deadcode */
  1693. DBUG_RETURN(1); /* purecov: deadcode */
  1694. }
  1695. store_record(table,record[1]);
  1696. table->field[2]->store(new_password, new_password_len, system_charset_info);
  1697. if ((error=table->file->ha_update_row(table->record[1],table->record[0])) &&
  1698. error != HA_ERR_RECORD_IS_THE_SAME)
  1699. {
  1700. table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  1701. DBUG_RETURN(1);
  1702. }
  1703. DBUG_RETURN(0);
  1704. }
  1705. /*
  1706. Return 1 if we are allowed to create new users
  1707. the logic here is: INSERT_ACL is sufficient.
  1708. It's also a requirement in opt_safe_user_create,
  1709. otherwise CREATE_USER_ACL is enough.
  1710. */
  1711. static bool test_if_create_new_users(THD *thd)
  1712. {
  1713. Security_context *sctx= thd->security_ctx;
  1714. bool create_new_users= test(sctx->master_access & INSERT_ACL) ||
  1715. (!opt_safe_user_create &&
  1716. test(sctx->master_access & CREATE_USER_ACL));
  1717. if (!create_new_users)
  1718. {
  1719. TABLE_LIST tl;
  1720. ulong db_access;
  1721. bzero((char*) &tl,sizeof(tl));
  1722. tl.db= (char*) "mysql";
  1723. tl.table_name= (char*) "user";
  1724. create_new_users= 1;
  1725. db_access=acl_get(sctx->host, sctx->ip,
  1726. sctx->priv_user, tl.db, 0);
  1727. if (!(db_access & INSERT_ACL))
  1728. {
  1729. if (check_grant(thd, INSERT_ACL, &tl, FALSE, UINT_MAX, TRUE))
  1730. create_new_users=0;
  1731. }
  1732. }
  1733. return create_new_users;
  1734. }
  1735. /****************************************************************************
  1736. Handle GRANT commands
  1737. ****************************************************************************/
  1738. static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
  1739. ulong rights, bool revoke_grant,
  1740. bool can_create_user, bool no_auto_create)
  1741. {
  1742. int error = -1;
  1743. bool old_row_exists=0;
  1744. const char *password= "";
  1745. uint password_len= 0;
  1746. char what= (revoke_grant) ? 'N' : 'Y';
  1747. uchar user_key[MAX_KEY_LENGTH];
  1748. LEX *lex= thd->lex;
  1749. DBUG_ENTER("replace_user_table");
  1750. mysql_mutex_assert_owner(&acl_cache->lock);
  1751. if (combo.password.str && combo.password.str[0])
  1752. {
  1753. if (combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH &&
  1754. combo.password.length != SCRAMBLED_PASSWORD_CHAR_LENGTH_323)
  1755. {
  1756. my_error(ER_PASSWD_LENGTH, MYF(0), SCRAMBLED_PASSWORD_CHAR_LENGTH);
  1757. DBUG_RETURN(-1);
  1758. }
  1759. password_len= combo.password.length;
  1760. password=combo.password.str;
  1761. }
  1762. table->use_all_columns();
  1763. table->field[0]->store(combo.host.str,combo.host.length,
  1764. system_charset_info);
  1765. table->field[1]->store(combo.user.str,combo.user.length,
  1766. system_charset_info);
  1767. key_copy(user_key, table->record[0], table->key_info,
  1768. table->key_info->key_length);
  1769. if (table->file->index_read_idx_map(table->record[0], 0, user_key,
  1770. HA_WHOLE_KEY,
  1771. HA_READ_KEY_EXACT))
  1772. {
  1773. /* what == 'N' means revoke */
  1774. if (what == 'N')
  1775. {
  1776. my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
  1777. goto end;
  1778. }
  1779. /*
  1780. There are four options which affect the process of creation of
  1781. a new user (mysqld option --safe-create-user, 'insert' privilege
  1782. on 'mysql.user' table, using 'GRANT' with 'IDENTIFIED BY' and
  1783. SQL_MODE flag NO_AUTO_CREATE_USER). Below is the simplified rule
  1784. how it should work.
  1785. if (safe-user-create && ! INSERT_priv) => reject
  1786. else if (identified_by) => create
  1787. else if (no_auto_create_user) => reject
  1788. else create
  1789. see also test_if_create_new_users()
  1790. */
  1791. else if (!password_len && no_auto_create)
  1792. {
  1793. my_error(ER_PASSWORD_NO_MATCH, MYF(0), combo.user.str, combo.host.str);
  1794. goto end;
  1795. }
  1796. else if (!can_create_user)
  1797. {
  1798. my_error(ER_CANT_CREATE_USER_WITH_GRANT, MYF(0),
  1799. thd->security_ctx->user, thd->security_ctx->host_or_ip);
  1800. goto end;
  1801. }
  1802. old_row_exists = 0;
  1803. restore_record(table,s->default_values);
  1804. table->field[0]->store(combo.host.str,combo.host.length,
  1805. system_charset_info);
  1806. table->field[1]->store(combo.user.str,combo.user.length,
  1807. system_charset_info);
  1808. table->field[2]->store(password, password_len,
  1809. system_charset_info);
  1810. }
  1811. else
  1812. {
  1813. old_row_exists = 1;
  1814. store_record(table,record[1]); // Save copy for update
  1815. if (combo.password.str) // If password given
  1816. table->field[2]->store(password, password_len, system_charset_info);
  1817. else if (!rights && !revoke_grant &&
  1818. lex->ssl_type == SSL_TYPE_NOT_SPECIFIED &&
  1819. !lex->mqh.specified_limits)
  1820. {
  1821. DBUG_RETURN(0);
  1822. }
  1823. }
  1824. /* Update table columns with new privileges */
  1825. Field **tmp_field;
  1826. ulong priv;
  1827. uint next_field;
  1828. for (tmp_field= table->field+3, priv = SELECT_ACL;
  1829. *tmp_field && (*tmp_field)->real_type() == MYSQL_TYPE_ENUM &&
  1830. ((Field_enum*) (*tmp_field))->typelib->count == 2 ;
  1831. tmp_field++, priv <<= 1)
  1832. {
  1833. if (priv & rights) // set requested privileges
  1834. (*tmp_field)->store(&what, 1, &my_charset_latin1);
  1835. }
  1836. rights= get_access(table, 3, &next_field);
  1837. DBUG_PRINT("info",("table fields: %d",table->s->fields));
  1838. if (table->s->fields >= 31) /* From 4.0.0 we have more fields */
  1839. {
  1840. /* We write down SSL related ACL stuff */
  1841. switch (lex->ssl_type) {
  1842. case SSL_TYPE_ANY:
  1843. table->field[next_field]->store(STRING_WITH_LEN("ANY"),
  1844. &my_charset_latin1);
  1845. table->field[next_field+1]->store("", 0, &my_charset_latin1);
  1846. table->field[next_field+2]->store("", 0, &my_charset_latin1);
  1847. table->field[next_field+3]->store("", 0, &my_charset_latin1);
  1848. break;
  1849. case SSL_TYPE_X509:
  1850. table->field[next_field]->store(STRING_WITH_LEN("X509"),
  1851. &my_charset_latin1);
  1852. table->field[next_field+1]->store("", 0, &my_charset_latin1);
  1853. table->field[next_field+2]->store("", 0, &my_charset_latin1);
  1854. table->field[next_field+3]->store("", 0, &my_charset_latin1);
  1855. break;
  1856. case SSL_TYPE_SPECIFIED:
  1857. table->field[next_field]->store(STRING_WITH_LEN("SPECIFIED"),
  1858. &my_charset_latin1);
  1859. table->field[next_field+1]->store("", 0, &my_charset_latin1);
  1860. table->field[next_field+2]->store("", 0, &my_charset_latin1);
  1861. table->field[next_field+3]->store("", 0, &my_charset_latin1);
  1862. if (lex->ssl_cipher)
  1863. table->field[next_field+1]->store(lex->ssl_cipher,
  1864. strlen(lex->ssl_cipher), system_charset_info);
  1865. if (lex->x509_issuer)
  1866. table->field[next_field+2]->store(lex->x509_issuer,
  1867. strlen(lex->x509_issuer), system_charset_info);
  1868. if (lex->x509_subject)
  1869. table->field[next_field+3]->store(lex->x509_subject,
  1870. strlen(lex->x509_subject), system_charset_info);
  1871. break;
  1872. case SSL_TYPE_NOT_SPECIFIED:
  1873. break;
  1874. case SSL_TYPE_NONE:
  1875. table->field[next_field]->store("", 0, &my_charset_latin1);
  1876. table->field[next_field+1]->store("", 0, &my_charset_latin1);
  1877. table->field[next_field+2]->store("", 0, &my_charset_latin1);
  1878. table->field[next_field+3]->store("", 0, &my_charset_latin1);
  1879. break;
  1880. }
  1881. next_field+=4;
  1882. USER_RESOURCES mqh= lex->mqh;
  1883. if (mqh.specified_limits & USER_RESOURCES::QUERIES_PER_HOUR)
  1884. table->field[next_field]->store((longlong) mqh.questions, TRUE);
  1885. if (mqh.specified_limits & USER_RESOURCES::UPDATES_PER_HOUR)
  1886. table->field[next_field+1]->store((longlong) mqh.updates, TRUE);
  1887. if (mqh.specified_limits & USER_RESOURCES::CONNECTIONS_PER_HOUR)
  1888. table->field[next_field+2]->store((longlong) mqh.conn_per_hour, TRUE);
  1889. if (table->s->fields >= 36 &&
  1890. (mqh.specified_limits & USER_RESOURCES::USER_CONNECTIONS))
  1891. table->field[next_field+3]->store((longlong) mqh.user_conn, TRUE);
  1892. mqh_used= mqh_used || mqh.questions || mqh.updates || mqh.conn_per_hour;
  1893. }
  1894. if (old_row_exists)
  1895. {
  1896. /*
  1897. We should NEVER delete from the user table, as a uses can still
  1898. use mysqld even if he doesn't have any privileges in the user table!
  1899. */
  1900. if (cmp_record(table,record[1]))
  1901. {
  1902. if ((error=
  1903. table->file->ha_update_row(table->record[1],table->record[0])) &&
  1904. error != HA_ERR_RECORD_IS_THE_SAME)
  1905. { // This should never happen
  1906. table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  1907. error= -1; /* purecov: deadcode */
  1908. goto end; /* purecov: deadcode */
  1909. }
  1910. else
  1911. error= 0;
  1912. }
  1913. }
  1914. else if ((error=table->file->ha_write_row(table->record[0]))) // insert
  1915. { // This should never happen
  1916. if (table->file->is_fatal_error(error, HA_CHECK_DUP))
  1917. {
  1918. table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  1919. error= -1; /* purecov: deadcode */
  1920. goto end; /* purecov: deadcode */
  1921. }
  1922. }
  1923. error=0; // Privileges granted / revoked
  1924. end:
  1925. if (!error)
  1926. {
  1927. acl_cache->clear(1); // Clear privilege cache
  1928. if (old_row_exists)
  1929. acl_update_user(combo.user.str, combo.host.str,
  1930. combo.password.str, password_len,
  1931. lex->ssl_type,
  1932. lex->ssl_cipher,
  1933. lex->x509_issuer,
  1934. lex->x509_subject,
  1935. &lex->mqh,
  1936. rights);
  1937. else
  1938. acl_insert_user(combo.user.str, combo.host.str, password, password_len,
  1939. lex->ssl_type,
  1940. lex->ssl_cipher,
  1941. lex->x509_issuer,
  1942. lex->x509_subject,
  1943. &lex->mqh,
  1944. rights);
  1945. }
  1946. DBUG_RETURN(error);
  1947. }
  1948. /*
  1949. change grants in the mysql.db table
  1950. */
  1951. static int replace_db_table(TABLE *table, const char *db,
  1952. const LEX_USER &combo,
  1953. ulong rights, bool revoke_grant)
  1954. {
  1955. uint i;
  1956. ulong priv,store_rights;
  1957. bool old_row_exists=0;
  1958. int error;
  1959. char what= (revoke_grant) ? 'N' : 'Y';
  1960. uchar user_key[MAX_KEY_LENGTH];
  1961. DBUG_ENTER("replace_db_table");
  1962. if (!initialized)
  1963. {
  1964. my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
  1965. DBUG_RETURN(-1);
  1966. }
  1967. /* Check if there is such a user in user table in memory? */
  1968. if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
  1969. {
  1970. my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH), MYF(0));
  1971. DBUG_RETURN(-1);
  1972. }
  1973. table->use_all_columns();
  1974. table->field[0]->store(combo.host.str,combo.host.length,
  1975. system_charset_info);
  1976. table->field[1]->store(db,(uint) strlen(db), system_charset_info);
  1977. table->field[2]->store(combo.user.str,combo.user.length,
  1978. system_charset_info);
  1979. key_copy(user_key, table->record[0], table->key_info,
  1980. table->key_info->key_length);
  1981. if (table->file->index_read_idx_map(table->record[0],0, user_key,
  1982. HA_WHOLE_KEY,
  1983. HA_READ_KEY_EXACT))
  1984. {
  1985. if (what == 'N')
  1986. { // no row, no revoke
  1987. my_error(ER_NONEXISTING_GRANT, MYF(0), combo.user.str, combo.host.str);
  1988. goto abort;
  1989. }
  1990. old_row_exists = 0;
  1991. restore_record(table, s->default_values);
  1992. table->field[0]->store(combo.host.str,combo.host.length,
  1993. system_charset_info);
  1994. table->field[1]->store(db,(uint) strlen(db), system_charset_info);
  1995. table->field[2]->store(combo.user.str,combo.user.length,
  1996. system_charset_info);
  1997. }
  1998. else
  1999. {
  2000. old_row_exists = 1;
  2001. store_record(table,record[1]);
  2002. }
  2003. store_rights=get_rights_for_db(rights);
  2004. for (i= 3, priv= 1; i < table->s->fields; i++, priv <<= 1)
  2005. {
  2006. if (priv & store_rights) // do it if priv is chosen
  2007. table->field [i]->store(&what,1, &my_charset_latin1);// set requested privileges
  2008. }
  2009. rights=get_access(table,3);
  2010. rights=fix_rights_for_db(rights);
  2011. if (old_row_exists)
  2012. {
  2013. /* update old existing row */
  2014. if (rights)
  2015. {
  2016. if ((error= table->file->ha_update_row(table->record[1],
  2017. table->record[0])) &&
  2018. error != HA_ERR_RECORD_IS_THE_SAME)
  2019. goto table_error; /* purecov: deadcode */
  2020. }
  2021. else /* must have been a revoke of all privileges */
  2022. {
  2023. if ((error= table->file->ha_delete_row(table->record[1])))
  2024. goto table_error; /* purecov: deadcode */
  2025. }
  2026. }
  2027. else if (rights && (error= table->file->ha_write_row(table->record[0])))
  2028. {
  2029. if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
  2030. goto table_error; /* purecov: deadcode */
  2031. }
  2032. acl_cache->clear(1); // Clear privilege cache
  2033. if (old_row_exists)
  2034. acl_update_db(combo.user.str,combo.host.str,db,rights);
  2035. else
  2036. if (rights)
  2037. acl_insert_db(combo.user.str,combo.host.str,db,rights);
  2038. DBUG_RETURN(0);
  2039. /* This could only happen if the grant tables got corrupted */
  2040. table_error:
  2041. table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  2042. abort:
  2043. DBUG_RETURN(-1);
  2044. }
  2045. class GRANT_COLUMN :public Sql_alloc
  2046. {
  2047. public:
  2048. char *column;
  2049. ulong rights;
  2050. uint key_length;
  2051. GRANT_COLUMN(String &c, ulong y) :rights (y)
  2052. {
  2053. column= (char*) memdup_root(&memex,c.ptr(), key_length=c.length());
  2054. }
  2055. };
  2056. static uchar* get_key_column(GRANT_COLUMN *buff, size_t *length,
  2057. my_bool not_used __attribute__((unused)))
  2058. {
  2059. *length=buff->key_length;
  2060. return (uchar*) buff->column;
  2061. }
  2062. class GRANT_NAME :public Sql_alloc
  2063. {
  2064. public:
  2065. acl_host_and_ip host;
  2066. char *db, *user, *tname, *hash_key;
  2067. ulong privs;
  2068. ulong sort;
  2069. size_t key_length;
  2070. GRANT_NAME(const char *h, const char *d,const char *u,
  2071. const char *t, ulong p, bool is_routine);
  2072. GRANT_NAME (TABLE *form, bool is_routine);
  2073. virtual ~GRANT_NAME() {};
  2074. virtual bool ok() { return privs != 0; }
  2075. void set_user_details(const char *h, const char *d,
  2076. const char *u, const char *t,
  2077. bool is_routine);
  2078. };
  2079. class GRANT_TABLE :public GRANT_NAME
  2080. {
  2081. public:
  2082. ulong cols;
  2083. HASH hash_columns;
  2084. GRANT_TABLE(const char *h, const char *d,const char *u,
  2085. const char *t, ulong p, ulong c);
  2086. GRANT_TABLE (TABLE *form, TABLE *col_privs);
  2087. ~GRANT_TABLE();
  2088. bool ok() { return privs != 0 || cols != 0; }
  2089. };
  2090. void GRANT_NAME::set_user_details(const char *h, const char *d,
  2091. const char *u, const char *t,
  2092. bool is_routine)
  2093. {
  2094. /* Host given by user */
  2095. update_hostname(&host, strdup_root(&memex, h));
  2096. if (db != d)
  2097. {
  2098. db= strdup_root(&memex, d);
  2099. if (lower_case_table_names)
  2100. my_casedn_str(files_charset_info, db);
  2101. }
  2102. user = strdup_root(&memex,u);
  2103. sort= get_sort(3,host.hostname,db,user);
  2104. if (tname != t)
  2105. {
  2106. tname= strdup_root(&memex, t);
  2107. if (lower_case_table_names || is_routine)
  2108. my_casedn_str(files_charset_info, tname);
  2109. }
  2110. key_length= strlen(d) + strlen(u)+ strlen(t)+3;
  2111. hash_key= (char*) alloc_root(&memex,key_length);
  2112. strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
  2113. }
  2114. GRANT_NAME::GRANT_NAME(const char *h, const char *d,const char *u,
  2115. const char *t, ulong p, bool is_routine)
  2116. :db(0), tname(0), privs(p)
  2117. {
  2118. set_user_details(h, d, u, t, is_routine);
  2119. }
  2120. GRANT_TABLE::GRANT_TABLE(const char *h, const char *d,const char *u,
  2121. const char *t, ulong p, ulong c)
  2122. :GRANT_NAME(h,d,u,t,p, FALSE), cols(c)
  2123. {
  2124. (void) my_hash_init2(&hash_columns,4,system_charset_info,
  2125. 0,0,0, (my_hash_get_key) get_key_column,0,0);
  2126. }
  2127. GRANT_NAME::GRANT_NAME(TABLE *form, bool is_routine)
  2128. {
  2129. update_hostname(&host, get_field(&memex, form->field[0]));
  2130. db= get_field(&memex,form->field[1]);
  2131. user= get_field(&memex,form->field[2]);
  2132. if (!user)
  2133. user= (char*) "";
  2134. sort= get_sort(3, host.hostname, db, user);
  2135. tname= get_field(&memex,form->field[3]);
  2136. if (!db || !tname)
  2137. {
  2138. /* Wrong table row; Ignore it */
  2139. privs= 0;
  2140. return; /* purecov: inspected */
  2141. }
  2142. if (lower_case_table_names)
  2143. {
  2144. my_casedn_str(files_charset_info, db);
  2145. }
  2146. if (lower_case_table_names || is_routine)
  2147. {
  2148. my_casedn_str(files_charset_info, tname);
  2149. }
  2150. key_length= (strlen(db) + strlen(user) + strlen(tname) + 3);
  2151. hash_key= (char*) alloc_root(&memex, key_length);
  2152. strmov(strmov(strmov(hash_key,user)+1,db)+1,tname);
  2153. privs = (ulong) form->field[6]->val_int();
  2154. privs = fix_rights_for_table(privs);
  2155. }
  2156. GRANT_TABLE::GRANT_TABLE(TABLE *form, TABLE *col_privs)
  2157. :GRANT_NAME(form, FALSE)
  2158. {
  2159. uchar key[MAX_KEY_LENGTH];
  2160. if (!db || !tname)
  2161. {
  2162. /* Wrong table row; Ignore it */
  2163. my_hash_clear(&hash_columns); /* allow for destruction */
  2164. cols= 0;
  2165. return;
  2166. }
  2167. cols= (ulong) form->field[7]->val_int();
  2168. cols = fix_rights_for_column(cols);
  2169. (void) my_hash_init2(&hash_columns,4,system_charset_info,
  2170. 0,0,0, (my_hash_get_key) get_key_column,0,0);
  2171. if (cols)
  2172. {
  2173. uint key_prefix_len;
  2174. KEY_PART_INFO *key_part= col_privs->key_info->key_part;
  2175. col_privs->field[0]->store(host.hostname,
  2176. host.hostname ? (uint) strlen(host.hostname) :
  2177. 0,
  2178. system_charset_info);
  2179. col_privs->field[1]->store(db,(uint) strlen(db), system_charset_info);
  2180. col_privs->field[2]->store(user,(uint) strlen(user), system_charset_info);
  2181. col_privs->field[3]->store(tname,(uint) strlen(tname), system_charset_info);
  2182. key_prefix_len= (key_part[0].store_length +
  2183. key_part[1].store_length +
  2184. key_part[2].store_length +
  2185. key_part[3].store_length);
  2186. key_copy(key, col_privs->record[0], col_privs->key_info, key_prefix_len);
  2187. col_privs->field[4]->store("",0, &my_charset_latin1);
  2188. col_privs->file->ha_index_init(0, 1);
  2189. if (col_privs->file->index_read_map(col_privs->record[0], (uchar*) key,
  2190. (key_part_map)15, HA_READ_KEY_EXACT))
  2191. {
  2192. cols = 0; /* purecov: deadcode */
  2193. col_privs->file->ha_index_end();
  2194. return;
  2195. }
  2196. do
  2197. {
  2198. String *res,column_name;
  2199. GRANT_COLUMN *mem_check;
  2200. /* As column name is a string, we don't have to supply a buffer */
  2201. res=col_privs->field[4]->val_str(&column_name);
  2202. ulong priv= (ulong) col_privs->field[6]->val_int();
  2203. if (!(mem_check = new GRANT_COLUMN(*res,
  2204. fix_rights_for_column(priv))))
  2205. {
  2206. /* Don't use this entry */
  2207. privs = cols = 0; /* purecov: deadcode */
  2208. return; /* purecov: deadcode */
  2209. }
  2210. if (my_hash_insert(&hash_columns, (uchar *) mem_check))
  2211. {
  2212. /* Invalidate this entry */
  2213. privs= cols= 0;
  2214. return;
  2215. }
  2216. } while (!col_privs->file->index_next(col_privs->record[0]) &&
  2217. !key_cmp_if_same(col_privs,key,0,key_prefix_len));
  2218. col_privs->file->ha_index_end();
  2219. }
  2220. }
  2221. GRANT_TABLE::~GRANT_TABLE()
  2222. {
  2223. my_hash_free(&hash_columns);
  2224. }
  2225. static uchar* get_grant_table(GRANT_NAME *buff, size_t *length,
  2226. my_bool not_used __attribute__((unused)))
  2227. {
  2228. *length=buff->key_length;
  2229. return (uchar*) buff->hash_key;
  2230. }
  2231. void free_grant_table(GRANT_TABLE *grant_table)
  2232. {
  2233. my_hash_free(&grant_table->hash_columns);
  2234. }
  2235. /* Search after a matching grant. Prefer exact grants before not exact ones */
  2236. static GRANT_NAME *name_hash_search(HASH *name_hash,
  2237. const char *host,const char* ip,
  2238. const char *db,
  2239. const char *user, const char *tname,
  2240. bool exact, bool name_tolower)
  2241. {
  2242. char helping [NAME_LEN*2+USERNAME_LENGTH+3], *name_ptr;
  2243. uint len;
  2244. GRANT_NAME *grant_name,*found=0;
  2245. HASH_SEARCH_STATE state;
  2246. name_ptr= strmov(strmov(helping, user) + 1, db) + 1;
  2247. len = (uint) (strmov(name_ptr, tname) - helping) + 1;
  2248. if (name_tolower)
  2249. my_casedn_str(files_charset_info, name_ptr);
  2250. for (grant_name= (GRANT_NAME*) my_hash_first(name_hash, (uchar*) helping,
  2251. len, &state);
  2252. grant_name ;
  2253. grant_name= (GRANT_NAME*) my_hash_next(name_hash,(uchar*) helping,
  2254. len, &state))
  2255. {
  2256. if (exact)
  2257. {
  2258. if (!grant_name->host.hostname ||
  2259. (host &&
  2260. !my_strcasecmp(system_charset_info, host,
  2261. grant_name->host.hostname)) ||
  2262. (ip && !strcmp(ip, grant_name->host.hostname)))
  2263. return grant_name;
  2264. }
  2265. else
  2266. {
  2267. if (compare_hostname(&grant_name->host, host, ip) &&
  2268. (!found || found->sort < grant_name->sort))
  2269. found=grant_name; // Host ok
  2270. }
  2271. }
  2272. return found;
  2273. }
  2274. inline GRANT_NAME *
  2275. routine_hash_search(const char *host, const char *ip, const char *db,
  2276. const char *user, const char *tname, bool proc, bool exact)
  2277. {
  2278. return (GRANT_TABLE*)
  2279. name_hash_search(proc ? &proc_priv_hash : &func_priv_hash,
  2280. host, ip, db, user, tname, exact, TRUE);
  2281. }
  2282. inline GRANT_TABLE *
  2283. table_hash_search(const char *host, const char *ip, const char *db,
  2284. const char *user, const char *tname, bool exact)
  2285. {
  2286. return (GRANT_TABLE*) name_hash_search(&column_priv_hash, host, ip, db,
  2287. user, tname, exact, FALSE);
  2288. }
  2289. inline GRANT_COLUMN *
  2290. column_hash_search(GRANT_TABLE *t, const char *cname, uint length)
  2291. {
  2292. return (GRANT_COLUMN*) my_hash_search(&t->hash_columns,
  2293. (uchar*) cname, length);
  2294. }
  2295. static int replace_column_table(GRANT_TABLE *g_t,
  2296. TABLE *table, const LEX_USER &combo,
  2297. List <LEX_COLUMN> &columns,
  2298. const char *db, const char *table_name,
  2299. ulong rights, bool revoke_grant)
  2300. {
  2301. int error=0,result=0;
  2302. uchar key[MAX_KEY_LENGTH];
  2303. uint key_prefix_length;
  2304. KEY_PART_INFO *key_part= table->key_info->key_part;
  2305. DBUG_ENTER("replace_column_table");
  2306. table->use_all_columns();
  2307. table->field[0]->store(combo.host.str,combo.host.length,
  2308. system_charset_info);
  2309. table->field[1]->store(db,(uint) strlen(db),
  2310. system_charset_info);
  2311. table->field[2]->store(combo.user.str,combo.user.length,
  2312. system_charset_info);
  2313. table->field[3]->store(table_name,(uint) strlen(table_name),
  2314. system_charset_info);
  2315. /* Get length of 4 first key parts */
  2316. key_prefix_length= (key_part[0].store_length + key_part[1].store_length +
  2317. key_part[2].store_length + key_part[3].store_length);
  2318. key_copy(key, table->record[0], table->key_info, key_prefix_length);
  2319. rights&= COL_ACLS; // Only ACL for columns
  2320. /* first fix privileges for all columns in column list */
  2321. List_iterator <LEX_COLUMN> iter(columns);
  2322. class LEX_COLUMN *column;
  2323. table->file->ha_index_init(0, 1);
  2324. while ((column= iter++))
  2325. {
  2326. ulong privileges= column->rights;
  2327. bool old_row_exists=0;
  2328. uchar user_key[MAX_KEY_LENGTH];
  2329. key_restore(table->record[0],key,table->key_info,
  2330. key_prefix_length);
  2331. table->field[4]->store(column->column.ptr(), column->column.length(),
  2332. system_charset_info);
  2333. /* Get key for the first 4 columns */
  2334. key_copy(user_key, table->record[0], table->key_info,
  2335. table->key_info->key_length);
  2336. if (table->file->index_read_map(table->record[0], user_key, HA_WHOLE_KEY,
  2337. HA_READ_KEY_EXACT))
  2338. {
  2339. if (revoke_grant)
  2340. {
  2341. my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
  2342. combo.user.str, combo.host.str,
  2343. table_name); /* purecov: inspected */
  2344. result= -1; /* purecov: inspected */
  2345. continue; /* purecov: inspected */
  2346. }
  2347. old_row_exists = 0;
  2348. restore_record(table, s->default_values); // Get empty record
  2349. key_restore(table->record[0],key,table->key_info,
  2350. key_prefix_length);
  2351. table->field[4]->store(column->column.ptr(),column->column.length(),
  2352. system_charset_info);
  2353. }
  2354. else
  2355. {
  2356. ulong tmp= (ulong) table->field[6]->val_int();
  2357. tmp=fix_rights_for_column(tmp);
  2358. if (revoke_grant)
  2359. privileges = tmp & ~(privileges | rights);
  2360. else
  2361. privileges |= tmp;
  2362. old_row_exists = 1;
  2363. store_record(table,record[1]); // copy original row
  2364. }
  2365. table->field[6]->store((longlong) get_rights_for_column(privileges), TRUE);
  2366. if (old_row_exists)
  2367. {
  2368. GRANT_COLUMN *grant_column;
  2369. if (privileges)
  2370. error=table->file->ha_update_row(table->record[1],table->record[0]);
  2371. else
  2372. error=table->file->ha_delete_row(table->record[1]);
  2373. if (error && error != HA_ERR_RECORD_IS_THE_SAME)
  2374. {
  2375. table->file->print_error(error,MYF(0)); /* purecov: inspected */
  2376. result= -1; /* purecov: inspected */
  2377. goto end; /* purecov: inspected */
  2378. }
  2379. else
  2380. error= 0;
  2381. grant_column= column_hash_search(g_t, column->column.ptr(),
  2382. column->column.length());
  2383. if (grant_column) // Should always be true
  2384. grant_column->rights= privileges; // Update hash
  2385. }
  2386. else // new grant
  2387. {
  2388. GRANT_COLUMN *grant_column;
  2389. if ((error=table->file->ha_write_row(table->record[0])))
  2390. {
  2391. table->file->print_error(error,MYF(0)); /* purecov: inspected */
  2392. result= -1; /* purecov: inspected */
  2393. goto end; /* purecov: inspected */
  2394. }
  2395. grant_column= new GRANT_COLUMN(column->column,privileges);
  2396. if (my_hash_insert(&g_t->hash_columns,(uchar*) grant_column))
  2397. {
  2398. result= -1;
  2399. goto end;
  2400. }
  2401. }
  2402. }
  2403. /*
  2404. If revoke of privileges on the table level, remove all such privileges
  2405. for all columns
  2406. */
  2407. if (revoke_grant)
  2408. {
  2409. uchar user_key[MAX_KEY_LENGTH];
  2410. key_copy(user_key, table->record[0], table->key_info,
  2411. key_prefix_length);
  2412. if (table->file->index_read_map(table->record[0], user_key,
  2413. (key_part_map)15,
  2414. HA_READ_KEY_EXACT))
  2415. goto end;
  2416. /* Scan through all rows with the same host,db,user and table */
  2417. do
  2418. {
  2419. ulong privileges = (ulong) table->field[6]->val_int();
  2420. privileges=fix_rights_for_column(privileges);
  2421. store_record(table,record[1]);
  2422. if (privileges & rights) // is in this record the priv to be revoked ??
  2423. {
  2424. GRANT_COLUMN *grant_column = NULL;
  2425. char colum_name_buf[HOSTNAME_LENGTH+1];
  2426. String column_name(colum_name_buf,sizeof(colum_name_buf),
  2427. system_charset_info);
  2428. privileges&= ~rights;
  2429. table->field[6]->store((longlong)
  2430. get_rights_for_column(privileges), TRUE);
  2431. table->field[4]->val_str(&column_name);
  2432. grant_column = column_hash_search(g_t,
  2433. column_name.ptr(),
  2434. column_name.length());
  2435. if (privileges)
  2436. {
  2437. int tmp_error;
  2438. if ((tmp_error=table->file->ha_update_row(table->record[1],
  2439. table->record[0])) &&
  2440. tmp_error != HA_ERR_RECORD_IS_THE_SAME)
  2441. { /* purecov: deadcode */
  2442. table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
  2443. result= -1; /* purecov: deadcode */
  2444. goto end; /* purecov: deadcode */
  2445. }
  2446. if (grant_column)
  2447. grant_column->rights = privileges; // Update hash
  2448. }
  2449. else
  2450. {
  2451. int tmp_error;
  2452. if ((tmp_error = table->file->ha_delete_row(table->record[1])))
  2453. { /* purecov: deadcode */
  2454. table->file->print_error(tmp_error,MYF(0)); /* purecov: deadcode */
  2455. result= -1; /* purecov: deadcode */
  2456. goto end; /* purecov: deadcode */
  2457. }
  2458. if (grant_column)
  2459. my_hash_delete(&g_t->hash_columns,(uchar*) grant_column);
  2460. }
  2461. }
  2462. } while (!table->file->index_next(table->record[0]) &&
  2463. !key_cmp_if_same(table, key, 0, key_prefix_length));
  2464. }
  2465. end:
  2466. table->file->ha_index_end();
  2467. DBUG_RETURN(result);
  2468. }
  2469. static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
  2470. TABLE *table, const LEX_USER &combo,
  2471. const char *db, const char *table_name,
  2472. ulong rights, ulong col_rights,
  2473. bool revoke_grant)
  2474. {
  2475. char grantor[USER_HOST_BUFF_SIZE];
  2476. int old_row_exists = 1;
  2477. int error=0;
  2478. ulong store_table_rights, store_col_rights;
  2479. uchar user_key[MAX_KEY_LENGTH];
  2480. DBUG_ENTER("replace_table_table");
  2481. strxmov(grantor, thd->security_ctx->user, "@",
  2482. thd->security_ctx->host_or_ip, NullS);
  2483. /*
  2484. The following should always succeed as new users are created before
  2485. this function is called!
  2486. */
  2487. if (!find_acl_user(combo.host.str,combo.user.str, FALSE))
  2488. {
  2489. my_message(ER_PASSWORD_NO_MATCH, ER(ER_PASSWORD_NO_MATCH),
  2490. MYF(0)); /* purecov: deadcode */
  2491. DBUG_RETURN(-1); /* purecov: deadcode */
  2492. }
  2493. table->use_all_columns();
  2494. restore_record(table, s->default_values); // Get empty record
  2495. table->field[0]->store(combo.host.str,combo.host.length,
  2496. system_charset_info);
  2497. table->field[1]->store(db,(uint) strlen(db), system_charset_info);
  2498. table->field[2]->store(combo.user.str,combo.user.length,
  2499. system_charset_info);
  2500. table->field[3]->store(table_name,(uint) strlen(table_name),
  2501. system_charset_info);
  2502. store_record(table,record[1]); // store at pos 1
  2503. key_copy(user_key, table->record[0], table->key_info,
  2504. table->key_info->key_length);
  2505. if (table->file->index_read_idx_map(table->record[0], 0, user_key,
  2506. HA_WHOLE_KEY,
  2507. HA_READ_KEY_EXACT))
  2508. {
  2509. /*
  2510. The following should never happen as we first check the in memory
  2511. grant tables for the user. There is however always a small change that
  2512. the user has modified the grant tables directly.
  2513. */
  2514. if (revoke_grant)
  2515. { // no row, no revoke
  2516. my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
  2517. combo.user.str, combo.host.str,
  2518. table_name); /* purecov: deadcode */
  2519. DBUG_RETURN(-1); /* purecov: deadcode */
  2520. }
  2521. old_row_exists = 0;
  2522. restore_record(table,record[1]); // Get saved record
  2523. }
  2524. store_table_rights= get_rights_for_table(rights);
  2525. store_col_rights= get_rights_for_column(col_rights);
  2526. if (old_row_exists)
  2527. {
  2528. ulong j,k;
  2529. store_record(table,record[1]);
  2530. j = (ulong) table->field[6]->val_int();
  2531. k = (ulong) table->field[7]->val_int();
  2532. if (revoke_grant)
  2533. {
  2534. /* column rights are already fixed in mysql_table_grant */
  2535. store_table_rights=j & ~store_table_rights;
  2536. }
  2537. else
  2538. {
  2539. store_table_rights|= j;
  2540. store_col_rights|= k;
  2541. }
  2542. }
  2543. table->field[4]->store(grantor,(uint) strlen(grantor), system_charset_info);
  2544. table->field[6]->store((longlong) store_table_rights, TRUE);
  2545. table->field[7]->store((longlong) store_col_rights, TRUE);
  2546. rights=fix_rights_for_table(store_table_rights);
  2547. col_rights=fix_rights_for_column(store_col_rights);
  2548. if (old_row_exists)
  2549. {
  2550. if (store_table_rights || store_col_rights)
  2551. {
  2552. if ((error=table->file->ha_update_row(table->record[1],
  2553. table->record[0])) &&
  2554. error != HA_ERR_RECORD_IS_THE_SAME)
  2555. goto table_error; /* purecov: deadcode */
  2556. }
  2557. else if ((error = table->file->ha_delete_row(table->record[1])))
  2558. goto table_error; /* purecov: deadcode */
  2559. }
  2560. else
  2561. {
  2562. error=table->file->ha_write_row(table->record[0]);
  2563. if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
  2564. goto table_error; /* purecov: deadcode */
  2565. }
  2566. if (rights | col_rights)
  2567. {
  2568. grant_table->privs= rights;
  2569. grant_table->cols= col_rights;
  2570. }
  2571. else
  2572. {
  2573. my_hash_delete(&column_priv_hash,(uchar*) grant_table);
  2574. }
  2575. DBUG_RETURN(0);
  2576. /* This should never happen */
  2577. table_error:
  2578. table->file->print_error(error,MYF(0)); /* purecov: deadcode */
  2579. DBUG_RETURN(-1); /* purecov: deadcode */
  2580. }
  2581. /**
  2582. @retval 0 success
  2583. @retval -1 error
  2584. */
  2585. static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
  2586. TABLE *table, const LEX_USER &combo,
  2587. const char *db, const char *routine_name,
  2588. bool is_proc, ulong rights, bool revoke_grant)
  2589. {
  2590. char grantor[USER_HOST_BUFF_SIZE];
  2591. int old_row_exists= 1;
  2592. int error=0;
  2593. ulong store_proc_rights;
  2594. DBUG_ENTER("replace_routine_table");
  2595. if (!initialized)
  2596. {
  2597. my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
  2598. DBUG_RETURN(-1);
  2599. }
  2600. strxmov(grantor, thd->security_ctx->user, "@",
  2601. thd->security_ctx->host_or_ip, NullS);
  2602. /*
  2603. New users are created before this function is called.
  2604. There may be some cases where a routine's definer is removed but the
  2605. routine remains.
  2606. */
  2607. table->use_all_columns();
  2608. restore_record(table, s->default_values); // Get empty record
  2609. table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
  2610. table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
  2611. table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
  2612. table->field[3]->store(routine_name,(uint) strlen(routine_name),
  2613. &my_charset_latin1);
  2614. table->field[4]->store((longlong)(is_proc ?
  2615. TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION),
  2616. TRUE);
  2617. store_record(table,record[1]); // store at pos 1
  2618. if (table->file->index_read_idx_map(table->record[0], 0,
  2619. (uchar*) table->field[0]->ptr,
  2620. HA_WHOLE_KEY,
  2621. HA_READ_KEY_EXACT))
  2622. {
  2623. /*
  2624. The following should never happen as we first check the in memory
  2625. grant tables for the user. There is however always a small change that
  2626. the user has modified the grant tables directly.
  2627. */
  2628. if (revoke_grant)
  2629. { // no row, no revoke
  2630. my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
  2631. combo.user.str, combo.host.str, routine_name);
  2632. DBUG_RETURN(-1);
  2633. }
  2634. old_row_exists= 0;
  2635. restore_record(table,record[1]); // Get saved record
  2636. }
  2637. store_proc_rights= get_rights_for_procedure(rights);
  2638. if (old_row_exists)
  2639. {
  2640. ulong j;
  2641. store_record(table,record[1]);
  2642. j= (ulong) table->field[6]->val_int();
  2643. if (revoke_grant)
  2644. {
  2645. /* column rights are already fixed in mysql_table_grant */
  2646. store_proc_rights=j & ~store_proc_rights;
  2647. }
  2648. else
  2649. {
  2650. store_proc_rights|= j;
  2651. }
  2652. }
  2653. table->field[5]->store(grantor,(uint) strlen(grantor), &my_charset_latin1);
  2654. table->field[6]->store((longlong) store_proc_rights, TRUE);
  2655. rights=fix_rights_for_procedure(store_proc_rights);
  2656. if (old_row_exists)
  2657. {
  2658. if (store_proc_rights)
  2659. {
  2660. if ((error=table->file->ha_update_row(table->record[1],
  2661. table->record[0])) &&
  2662. error != HA_ERR_RECORD_IS_THE_SAME)
  2663. goto table_error;
  2664. }
  2665. else if ((error= table->file->ha_delete_row(table->record[1])))
  2666. goto table_error;
  2667. }
  2668. else
  2669. {
  2670. error=table->file->ha_write_row(table->record[0]);
  2671. if (table->file->is_fatal_error(error, HA_CHECK_DUP_KEY))
  2672. goto table_error;
  2673. }
  2674. if (rights)
  2675. {
  2676. grant_name->privs= rights;
  2677. }
  2678. else
  2679. {
  2680. my_hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(uchar*)
  2681. grant_name);
  2682. }
  2683. DBUG_RETURN(0);
  2684. /* This should never happen */
  2685. table_error:
  2686. table->file->print_error(error,MYF(0));
  2687. DBUG_RETURN(-1);
  2688. }
  2689. /*
  2690. Store table level and column level grants in the privilege tables
  2691. SYNOPSIS
  2692. mysql_table_grant()
  2693. thd Thread handle
  2694. table_list List of tables to give grant
  2695. user_list List of users to give grant
  2696. columns List of columns to give grant
  2697. rights Table level grant
  2698. revoke_grant Set to 1 if this is a REVOKE command
  2699. RETURN
  2700. FALSE ok
  2701. TRUE error
  2702. */
  2703. int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
  2704. List <LEX_USER> &user_list,
  2705. List <LEX_COLUMN> &columns, ulong rights,
  2706. bool revoke_grant)
  2707. {
  2708. ulong column_priv= 0;
  2709. List_iterator <LEX_USER> str_list (user_list);
  2710. LEX_USER *Str, *tmp_Str;
  2711. TABLE_LIST tables[3];
  2712. bool create_new_users=0;
  2713. char *db_name, *table_name;
  2714. bool save_binlog_row_based;
  2715. DBUG_ENTER("mysql_table_grant");
  2716. if (!initialized)
  2717. {
  2718. my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
  2719. "--skip-grant-tables"); /* purecov: inspected */
  2720. DBUG_RETURN(TRUE); /* purecov: inspected */
  2721. }
  2722. if (rights & ~TABLE_ACLS)
  2723. {
  2724. my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
  2725. MYF(0));
  2726. DBUG_RETURN(TRUE);
  2727. }
  2728. if (!revoke_grant)
  2729. {
  2730. if (columns.elements)
  2731. {
  2732. class LEX_COLUMN *column;
  2733. List_iterator <LEX_COLUMN> column_iter(columns);
  2734. if (open_and_lock_tables(thd, table_list, TRUE, 0))
  2735. DBUG_RETURN(TRUE);
  2736. while ((column = column_iter++))
  2737. {
  2738. uint unused_field_idx= NO_CACHED_FIELD_INDEX;
  2739. TABLE_LIST *dummy;
  2740. Field *f=find_field_in_table_ref(thd, table_list, column->column.ptr(),
  2741. column->column.length(),
  2742. column->column.ptr(), NULL, NULL,
  2743. NULL, TRUE, FALSE,
  2744. &unused_field_idx, FALSE, &dummy);
  2745. if (f == (Field*)0)
  2746. {
  2747. my_error(ER_BAD_FIELD_ERROR, MYF(0),
  2748. column->column.c_ptr(), table_list->alias);
  2749. DBUG_RETURN(TRUE);
  2750. }
  2751. if (f == (Field *)-1)
  2752. DBUG_RETURN(TRUE);
  2753. column_priv|= column->rights;
  2754. }
  2755. close_thread_tables(thd);
  2756. }
  2757. else
  2758. {
  2759. if (!(rights & CREATE_ACL))
  2760. {
  2761. char buf[FN_REFLEN + 1];
  2762. build_table_filename(buf, sizeof(buf) - 1, table_list->db,
  2763. table_list->table_name, reg_ext, 0);
  2764. fn_format(buf, buf, "", "", MY_UNPACK_FILENAME | MY_RESOLVE_SYMLINKS |
  2765. MY_RETURN_REAL_PATH | MY_APPEND_EXT);
  2766. if (access(buf,F_OK))
  2767. {
  2768. my_error(ER_NO_SUCH_TABLE, MYF(0), table_list->db, table_list->alias);
  2769. DBUG_RETURN(TRUE);
  2770. }
  2771. }
  2772. if (table_list->grant.want_privilege)
  2773. {
  2774. char command[128];
  2775. get_privilege_desc(command, sizeof(command),
  2776. table_list->grant.want_privilege);
  2777. my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
  2778. command, thd->security_ctx->priv_user,
  2779. thd->security_ctx->host_or_ip, table_list->alias);
  2780. DBUG_RETURN(-1);
  2781. }
  2782. }
  2783. }
  2784. /* open the mysql.tables_priv and mysql.columns_priv tables */
  2785. bzero((char*) &tables,sizeof(tables));
  2786. tables[0].alias=tables[0].table_name= (char*) "user";
  2787. tables[1].alias=tables[1].table_name= (char*) "tables_priv";
  2788. tables[2].alias=tables[2].table_name= (char*) "columns_priv";
  2789. tables[0].next_local= tables[0].next_global= tables+1;
  2790. /* Don't open column table if we don't need it ! */
  2791. tables[1].next_local=
  2792. tables[1].next_global= ((column_priv ||
  2793. (revoke_grant &&
  2794. ((rights & COL_ACLS) || columns.elements)))
  2795. ? tables+2 : 0);
  2796. tables[0].lock_type=tables[1].lock_type=tables[2].lock_type=TL_WRITE;
  2797. tables[0].db=tables[1].db=tables[2].db=(char*) "mysql";
  2798. init_mdl_requests(tables);
  2799. /*
  2800. This statement will be replicated as a statement, even when using
  2801. row-based replication. The flag will be reset at the end of the
  2802. statement.
  2803. */
  2804. if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
  2805. thd->clear_current_stmt_binlog_format_row();
  2806. #ifdef HAVE_REPLICATION
  2807. /*
  2808. GRANT and REVOKE are applied the slave in/exclusion rules as they are
  2809. some kind of updates to the mysql.% tables.
  2810. */
  2811. if (thd->slave_thread && rpl_filter->is_on())
  2812. {
  2813. /*
  2814. The tables must be marked "updating" so that tables_ok() takes them into
  2815. account in tests.
  2816. */
  2817. tables[0].updating= tables[1].updating= tables[2].updating= 1;
  2818. if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
  2819. {
  2820. /* Restore the state of binlog format */
  2821. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  2822. if (save_binlog_row_based)
  2823. thd->set_current_stmt_binlog_format_row();
  2824. DBUG_RETURN(FALSE);
  2825. }
  2826. }
  2827. #endif
  2828. /*
  2829. The lock api is depending on the thd->lex variable which needs to be
  2830. re-initialized.
  2831. */
  2832. Query_tables_list backup;
  2833. thd->lex->reset_n_backup_query_tables_list(&backup);
  2834. if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
  2835. { // Should never happen
  2836. close_thread_tables(thd); /* purecov: deadcode */
  2837. /* Restore the state of binlog format */
  2838. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  2839. if (save_binlog_row_based)
  2840. thd->set_current_stmt_binlog_format_row();
  2841. DBUG_RETURN(TRUE); /* purecov: deadcode */
  2842. }
  2843. if (!revoke_grant)
  2844. create_new_users= test_if_create_new_users(thd);
  2845. bool result= FALSE;
  2846. mysql_rwlock_wrlock(&LOCK_grant);
  2847. mysql_mutex_lock(&acl_cache->lock);
  2848. MEM_ROOT *old_root= thd->mem_root;
  2849. thd->mem_root= &memex;
  2850. grant_version++;
  2851. while ((tmp_Str = str_list++))
  2852. {
  2853. int error;
  2854. GRANT_TABLE *grant_table;
  2855. if (!(Str= get_current_user(thd, tmp_Str)))
  2856. {
  2857. result= TRUE;
  2858. continue;
  2859. }
  2860. /* Create user if needed */
  2861. error=replace_user_table(thd, tables[0].table, *Str,
  2862. 0, revoke_grant, create_new_users,
  2863. test(thd->variables.sql_mode &
  2864. MODE_NO_AUTO_CREATE_USER));
  2865. if (error)
  2866. {
  2867. result= TRUE; // Remember error
  2868. continue; // Add next user
  2869. }
  2870. db_name= table_list->get_db_name();
  2871. table_name= table_list->get_table_name();
  2872. /* Find/create cached table grant */
  2873. grant_table= table_hash_search(Str->host.str, NullS, db_name,
  2874. Str->user.str, table_name, 1);
  2875. if (!grant_table)
  2876. {
  2877. if (revoke_grant)
  2878. {
  2879. my_error(ER_NONEXISTING_TABLE_GRANT, MYF(0),
  2880. Str->user.str, Str->host.str, table_list->table_name);
  2881. result= TRUE;
  2882. continue;
  2883. }
  2884. grant_table = new GRANT_TABLE (Str->host.str, db_name,
  2885. Str->user.str, table_name,
  2886. rights,
  2887. column_priv);
  2888. if (!grant_table ||
  2889. my_hash_insert(&column_priv_hash,(uchar*) grant_table))
  2890. {
  2891. result= TRUE; /* purecov: deadcode */
  2892. continue; /* purecov: deadcode */
  2893. }
  2894. }
  2895. /* If revoke_grant, calculate the new column privilege for tables_priv */
  2896. if (revoke_grant)
  2897. {
  2898. class LEX_COLUMN *column;
  2899. List_iterator <LEX_COLUMN> column_iter(columns);
  2900. GRANT_COLUMN *grant_column;
  2901. /* Fix old grants */
  2902. while ((column = column_iter++))
  2903. {
  2904. grant_column = column_hash_search(grant_table,
  2905. column->column.ptr(),
  2906. column->column.length());
  2907. if (grant_column)
  2908. grant_column->rights&= ~(column->rights | rights);
  2909. }
  2910. /* scan trough all columns to get new column grant */
  2911. column_priv= 0;
  2912. for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
  2913. {
  2914. grant_column= (GRANT_COLUMN*)
  2915. my_hash_element(&grant_table->hash_columns, idx);
  2916. grant_column->rights&= ~rights; // Fix other columns
  2917. column_priv|= grant_column->rights;
  2918. }
  2919. }
  2920. else
  2921. {
  2922. column_priv|= grant_table->cols;
  2923. }
  2924. /* update table and columns */
  2925. if (replace_table_table(thd, grant_table, tables[1].table, *Str,
  2926. db_name, table_name,
  2927. rights, column_priv, revoke_grant))
  2928. {
  2929. /* Should only happen if table is crashed */
  2930. result= TRUE; /* purecov: deadcode */
  2931. }
  2932. else if (tables[2].table)
  2933. {
  2934. if ((replace_column_table(grant_table, tables[2].table, *Str,
  2935. columns,
  2936. db_name, table_name,
  2937. rights, revoke_grant)))
  2938. {
  2939. result= TRUE;
  2940. }
  2941. }
  2942. }
  2943. thd->mem_root= old_root;
  2944. mysql_mutex_unlock(&acl_cache->lock);
  2945. if (!result) /* success */
  2946. {
  2947. result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
  2948. }
  2949. mysql_rwlock_unlock(&LOCK_grant);
  2950. if (!result) /* success */
  2951. my_ok(thd);
  2952. /* Tables are automatically closed */
  2953. thd->lex->restore_backup_query_tables_list(&backup);
  2954. /* Restore the state of binlog format */
  2955. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  2956. if (save_binlog_row_based)
  2957. thd->set_current_stmt_binlog_format_row();
  2958. DBUG_RETURN(result);
  2959. }
  2960. /**
  2961. Store routine level grants in the privilege tables
  2962. @param thd Thread handle
  2963. @param table_list List of routines to give grant
  2964. @param is_proc Is this a list of procedures?
  2965. @param user_list List of users to give grant
  2966. @param rights Table level grant
  2967. @param revoke_grant Is this is a REVOKE command?
  2968. @return
  2969. @retval FALSE Success.
  2970. @retval TRUE An error occurred.
  2971. */
  2972. bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
  2973. List <LEX_USER> &user_list, ulong rights,
  2974. bool revoke_grant, bool write_to_binlog)
  2975. {
  2976. List_iterator <LEX_USER> str_list (user_list);
  2977. LEX_USER *Str, *tmp_Str;
  2978. TABLE_LIST tables[2];
  2979. bool create_new_users=0, result=0;
  2980. char *db_name, *table_name;
  2981. bool save_binlog_row_based;
  2982. DBUG_ENTER("mysql_routine_grant");
  2983. if (!initialized)
  2984. {
  2985. my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
  2986. "--skip-grant-tables");
  2987. DBUG_RETURN(TRUE);
  2988. }
  2989. if (rights & ~PROC_ACLS)
  2990. {
  2991. my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
  2992. MYF(0));
  2993. DBUG_RETURN(TRUE);
  2994. }
  2995. if (!revoke_grant)
  2996. {
  2997. if (sp_exist_routines(thd, table_list, is_proc))
  2998. DBUG_RETURN(TRUE);
  2999. }
  3000. /* open the mysql.user and mysql.procs_priv tables */
  3001. bzero((char*) &tables,sizeof(tables));
  3002. tables[0].alias=tables[0].table_name= (char*) "user";
  3003. tables[1].alias=tables[1].table_name= (char*) "procs_priv";
  3004. tables[0].next_local= tables[0].next_global= tables+1;
  3005. tables[0].lock_type=tables[1].lock_type=TL_WRITE;
  3006. tables[0].db=tables[1].db=(char*) "mysql";
  3007. init_mdl_requests(tables);
  3008. /*
  3009. This statement will be replicated as a statement, even when using
  3010. row-based replication. The flag will be reset at the end of the
  3011. statement.
  3012. */
  3013. if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
  3014. thd->clear_current_stmt_binlog_format_row();
  3015. #ifdef HAVE_REPLICATION
  3016. /*
  3017. GRANT and REVOKE are applied the slave in/exclusion rules as they are
  3018. some kind of updates to the mysql.% tables.
  3019. */
  3020. if (thd->slave_thread && rpl_filter->is_on())
  3021. {
  3022. /*
  3023. The tables must be marked "updating" so that tables_ok() takes them into
  3024. account in tests.
  3025. */
  3026. tables[0].updating= tables[1].updating= 1;
  3027. if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
  3028. {
  3029. /* Restore the state of binlog format */
  3030. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  3031. if (save_binlog_row_based)
  3032. thd->set_current_stmt_binlog_format_row();
  3033. DBUG_RETURN(FALSE);
  3034. }
  3035. }
  3036. #endif
  3037. if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
  3038. { // Should never happen
  3039. close_thread_tables(thd);
  3040. /* Restore the state of binlog format */
  3041. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  3042. if (save_binlog_row_based)
  3043. thd->set_current_stmt_binlog_format_row();
  3044. DBUG_RETURN(TRUE);
  3045. }
  3046. if (!revoke_grant)
  3047. create_new_users= test_if_create_new_users(thd);
  3048. mysql_rwlock_wrlock(&LOCK_grant);
  3049. mysql_mutex_lock(&acl_cache->lock);
  3050. MEM_ROOT *old_root= thd->mem_root;
  3051. thd->mem_root= &memex;
  3052. DBUG_PRINT("info",("now time to iterate and add users"));
  3053. while ((tmp_Str= str_list++))
  3054. {
  3055. int error;
  3056. GRANT_NAME *grant_name;
  3057. if (!(Str= get_current_user(thd, tmp_Str)))
  3058. {
  3059. result= TRUE;
  3060. continue;
  3061. }
  3062. /* Create user if needed */
  3063. error=replace_user_table(thd, tables[0].table, *Str,
  3064. 0, revoke_grant, create_new_users,
  3065. test(thd->variables.sql_mode &
  3066. MODE_NO_AUTO_CREATE_USER));
  3067. if (error)
  3068. {
  3069. result= TRUE; // Remember error
  3070. continue; // Add next user
  3071. }
  3072. db_name= table_list->db;
  3073. table_name= table_list->table_name;
  3074. grant_name= routine_hash_search(Str->host.str, NullS, db_name,
  3075. Str->user.str, table_name, is_proc, 1);
  3076. if (!grant_name)
  3077. {
  3078. if (revoke_grant)
  3079. {
  3080. my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
  3081. Str->user.str, Str->host.str, table_name);
  3082. result= TRUE;
  3083. continue;
  3084. }
  3085. grant_name= new GRANT_NAME(Str->host.str, db_name,
  3086. Str->user.str, table_name,
  3087. rights, TRUE);
  3088. if (!grant_name ||
  3089. my_hash_insert(is_proc ?
  3090. &proc_priv_hash : &func_priv_hash,(uchar*) grant_name))
  3091. {
  3092. result= TRUE;
  3093. continue;
  3094. }
  3095. }
  3096. if (replace_routine_table(thd, grant_name, tables[1].table, *Str,
  3097. db_name, table_name, is_proc, rights,
  3098. revoke_grant) != 0)
  3099. {
  3100. result= TRUE;
  3101. continue;
  3102. }
  3103. }
  3104. thd->mem_root= old_root;
  3105. mysql_mutex_unlock(&acl_cache->lock);
  3106. if (write_to_binlog)
  3107. {
  3108. if (write_bin_log(thd, FALSE, thd->query(), thd->query_length()))
  3109. result= TRUE;
  3110. }
  3111. mysql_rwlock_unlock(&LOCK_grant);
  3112. /* Restore the state of binlog format */
  3113. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  3114. if (save_binlog_row_based)
  3115. thd->set_current_stmt_binlog_format_row();
  3116. /* Tables are automatically closed */
  3117. DBUG_RETURN(result);
  3118. }
  3119. bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &list,
  3120. ulong rights, bool revoke_grant)
  3121. {
  3122. List_iterator <LEX_USER> str_list (list);
  3123. LEX_USER *Str, *tmp_Str;
  3124. char tmp_db[NAME_LEN+1];
  3125. bool create_new_users=0;
  3126. TABLE_LIST tables[2];
  3127. bool save_binlog_row_based;
  3128. DBUG_ENTER("mysql_grant");
  3129. if (!initialized)
  3130. {
  3131. my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0),
  3132. "--skip-grant-tables"); /* purecov: tested */
  3133. DBUG_RETURN(TRUE); /* purecov: tested */
  3134. }
  3135. if (lower_case_table_names && db)
  3136. {
  3137. strmov(tmp_db,db);
  3138. my_casedn_str(files_charset_info, tmp_db);
  3139. db=tmp_db;
  3140. }
  3141. /* open the mysql.user and mysql.db tables */
  3142. bzero((char*) &tables,sizeof(tables));
  3143. tables[0].alias=tables[0].table_name=(char*) "user";
  3144. tables[1].alias=tables[1].table_name=(char*) "db";
  3145. tables[0].next_local= tables[0].next_global= tables+1;
  3146. tables[0].lock_type=tables[1].lock_type=TL_WRITE;
  3147. tables[0].db=tables[1].db=(char*) "mysql";
  3148. init_mdl_requests(tables);
  3149. /*
  3150. This statement will be replicated as a statement, even when using
  3151. row-based replication. The flag will be reset at the end of the
  3152. statement.
  3153. */
  3154. if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
  3155. thd->clear_current_stmt_binlog_format_row();
  3156. #ifdef HAVE_REPLICATION
  3157. /*
  3158. GRANT and REVOKE are applied the slave in/exclusion rules as they are
  3159. some kind of updates to the mysql.% tables.
  3160. */
  3161. if (thd->slave_thread && rpl_filter->is_on())
  3162. {
  3163. /*
  3164. The tables must be marked "updating" so that tables_ok() takes them into
  3165. account in tests.
  3166. */
  3167. tables[0].updating= tables[1].updating= 1;
  3168. if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
  3169. {
  3170. /* Restore the state of binlog format */
  3171. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  3172. if (save_binlog_row_based)
  3173. thd->set_current_stmt_binlog_format_row();
  3174. DBUG_RETURN(FALSE);
  3175. }
  3176. }
  3177. #endif
  3178. if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
  3179. { // This should never happen
  3180. close_thread_tables(thd); /* purecov: deadcode */
  3181. /* Restore the state of binlog format */
  3182. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  3183. if (save_binlog_row_based)
  3184. thd->set_current_stmt_binlog_format_row();
  3185. DBUG_RETURN(TRUE); /* purecov: deadcode */
  3186. }
  3187. if (!revoke_grant)
  3188. create_new_users= test_if_create_new_users(thd);
  3189. /* go through users in user_list */
  3190. mysql_rwlock_wrlock(&LOCK_grant);
  3191. mysql_mutex_lock(&acl_cache->lock);
  3192. grant_version++;
  3193. int result=0;
  3194. while ((tmp_Str = str_list++))
  3195. {
  3196. if (!(Str= get_current_user(thd, tmp_Str)))
  3197. {
  3198. result= TRUE;
  3199. continue;
  3200. }
  3201. /*
  3202. No User, but a password?
  3203. They did GRANT ... TO CURRENT_USER() IDENTIFIED BY ... !
  3204. Get the current user, and shallow-copy the new password to them!
  3205. */
  3206. if (!tmp_Str->user.str && tmp_Str->password.str)
  3207. Str->password= tmp_Str->password;
  3208. if (replace_user_table(thd, tables[0].table, *Str,
  3209. (!db ? rights : 0), revoke_grant, create_new_users,
  3210. test(thd->variables.sql_mode &
  3211. MODE_NO_AUTO_CREATE_USER)))
  3212. result= -1;
  3213. else if (db)
  3214. {
  3215. ulong db_rights= rights & DB_ACLS;
  3216. if (db_rights == rights)
  3217. {
  3218. if (replace_db_table(tables[1].table, db, *Str, db_rights,
  3219. revoke_grant))
  3220. result= -1;
  3221. }
  3222. else
  3223. {
  3224. my_error(ER_WRONG_USAGE, MYF(0), "DB GRANT", "GLOBAL PRIVILEGES");
  3225. result= -1;
  3226. }
  3227. }
  3228. }
  3229. mysql_mutex_unlock(&acl_cache->lock);
  3230. if (!result)
  3231. {
  3232. result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
  3233. }
  3234. mysql_rwlock_unlock(&LOCK_grant);
  3235. close_thread_tables(thd);
  3236. if (!result)
  3237. my_ok(thd);
  3238. /* Restore the state of binlog format */
  3239. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  3240. if (save_binlog_row_based)
  3241. thd->set_current_stmt_binlog_format_row();
  3242. DBUG_RETURN(result);
  3243. }
  3244. /* Free grant array if possible */
  3245. void grant_free(void)
  3246. {
  3247. DBUG_ENTER("grant_free");
  3248. my_hash_free(&column_priv_hash);
  3249. my_hash_free(&proc_priv_hash);
  3250. my_hash_free(&func_priv_hash);
  3251. free_root(&memex,MYF(0));
  3252. DBUG_VOID_RETURN;
  3253. }
  3254. /**
  3255. @brief Initialize structures responsible for table/column-level privilege
  3256. checking and load information for them from tables in the 'mysql' database.
  3257. @return Error status
  3258. @retval 0 OK
  3259. @retval 1 Could not initialize grant subsystem.
  3260. */
  3261. my_bool grant_init()
  3262. {
  3263. THD *thd;
  3264. my_bool return_val;
  3265. DBUG_ENTER("grant_init");
  3266. if (!(thd= new THD))
  3267. DBUG_RETURN(1); /* purecov: deadcode */
  3268. thd->thread_stack= (char*) &thd;
  3269. thd->store_globals();
  3270. return_val= grant_reload(thd);
  3271. delete thd;
  3272. /* Remember that we don't have a THD */
  3273. my_pthread_setspecific_ptr(THR_THD, 0);
  3274. DBUG_RETURN(return_val);
  3275. }
  3276. /**
  3277. @brief Helper function to grant_reload_procs_priv
  3278. Reads the procs_priv table into memory hash.
  3279. @param table A pointer to the procs_priv table structure.
  3280. @see grant_reload
  3281. @see grant_reload_procs_priv
  3282. @return Error state
  3283. @retval TRUE An error occurred
  3284. @retval FALSE Success
  3285. */
  3286. static my_bool grant_load_procs_priv(TABLE *p_table)
  3287. {
  3288. MEM_ROOT *memex_ptr;
  3289. my_bool return_val= 1;
  3290. bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
  3291. MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
  3292. THR_MALLOC);
  3293. DBUG_ENTER("grant_load_procs_priv");
  3294. (void) my_hash_init(&proc_priv_hash, &my_charset_utf8_bin,
  3295. 0,0,0, (my_hash_get_key) get_grant_table,
  3296. 0,0);
  3297. (void) my_hash_init(&func_priv_hash, &my_charset_utf8_bin,
  3298. 0,0,0, (my_hash_get_key) get_grant_table,
  3299. 0,0);
  3300. p_table->file->ha_index_init(0, 1);
  3301. p_table->use_all_columns();
  3302. if (!p_table->file->index_first(p_table->record[0]))
  3303. {
  3304. memex_ptr= &memex;
  3305. my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
  3306. do
  3307. {
  3308. GRANT_NAME *mem_check;
  3309. HASH *hash;
  3310. if (!(mem_check=new (memex_ptr) GRANT_NAME(p_table, TRUE)))
  3311. {
  3312. /* This could only happen if we are out memory */
  3313. goto end_unlock;
  3314. }
  3315. if (check_no_resolve)
  3316. {
  3317. if (hostname_requires_resolving(mem_check->host.hostname))
  3318. {
  3319. sql_print_warning("'procs_priv' entry '%s %s@%s' "
  3320. "ignored in --skip-name-resolve mode.",
  3321. mem_check->tname, mem_check->user,
  3322. mem_check->host.hostname ?
  3323. mem_check->host.hostname : "");
  3324. continue;
  3325. }
  3326. }
  3327. if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE)
  3328. {
  3329. hash= &proc_priv_hash;
  3330. }
  3331. else
  3332. if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION)
  3333. {
  3334. hash= &func_priv_hash;
  3335. }
  3336. else
  3337. {
  3338. sql_print_warning("'procs_priv' entry '%s' "
  3339. "ignored, bad routine type",
  3340. mem_check->tname);
  3341. continue;
  3342. }
  3343. mem_check->privs= fix_rights_for_procedure(mem_check->privs);
  3344. if (! mem_check->ok())
  3345. delete mem_check;
  3346. else if (my_hash_insert(hash, (uchar*) mem_check))
  3347. {
  3348. delete mem_check;
  3349. goto end_unlock;
  3350. }
  3351. }
  3352. while (!p_table->file->index_next(p_table->record[0]));
  3353. }
  3354. /* Return ok */
  3355. return_val= 0;
  3356. end_unlock:
  3357. p_table->file->ha_index_end();
  3358. my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
  3359. DBUG_RETURN(return_val);
  3360. }
  3361. /**
  3362. @brief Initialize structures responsible for table/column-level privilege
  3363. checking and load information about grants from open privilege tables.
  3364. @param thd Current thread
  3365. @param tables List containing open "mysql.tables_priv" and
  3366. "mysql.columns_priv" tables.
  3367. @see grant_reload
  3368. @return Error state
  3369. @retval FALSE Success
  3370. @retval TRUE Error
  3371. */
  3372. static my_bool grant_load(THD *thd, TABLE_LIST *tables)
  3373. {
  3374. MEM_ROOT *memex_ptr;
  3375. my_bool return_val= 1;
  3376. TABLE *t_table= 0, *c_table= 0;
  3377. bool check_no_resolve= specialflag & SPECIAL_NO_RESOLVE;
  3378. MEM_ROOT **save_mem_root_ptr= my_pthread_getspecific_ptr(MEM_ROOT**,
  3379. THR_MALLOC);
  3380. ulong old_sql_mode= thd->variables.sql_mode;
  3381. DBUG_ENTER("grant_load");
  3382. thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
  3383. (void) my_hash_init(&column_priv_hash, &my_charset_utf8_bin,
  3384. 0,0,0, (my_hash_get_key) get_grant_table,
  3385. (my_hash_free_key) free_grant_table,0);
  3386. t_table = tables[0].table;
  3387. c_table = tables[1].table;
  3388. t_table->file->ha_index_init(0, 1);
  3389. t_table->use_all_columns();
  3390. c_table->use_all_columns();
  3391. if (!t_table->file->index_first(t_table->record[0]))
  3392. {
  3393. memex_ptr= &memex;
  3394. my_pthread_setspecific_ptr(THR_MALLOC, &memex_ptr);
  3395. do
  3396. {
  3397. GRANT_TABLE *mem_check;
  3398. if (!(mem_check=new (memex_ptr) GRANT_TABLE(t_table,c_table)))
  3399. {
  3400. /* This could only happen if we are out memory */
  3401. goto end_unlock;
  3402. }
  3403. if (check_no_resolve)
  3404. {
  3405. if (hostname_requires_resolving(mem_check->host.hostname))
  3406. {
  3407. sql_print_warning("'tables_priv' entry '%s %s@%s' "
  3408. "ignored in --skip-name-resolve mode.",
  3409. mem_check->tname,
  3410. mem_check->user ? mem_check->user : "",
  3411. mem_check->host.hostname ?
  3412. mem_check->host.hostname : "");
  3413. continue;
  3414. }
  3415. }
  3416. if (! mem_check->ok())
  3417. delete mem_check;
  3418. else if (my_hash_insert(&column_priv_hash,(uchar*) mem_check))
  3419. {
  3420. delete mem_check;
  3421. goto end_unlock;
  3422. }
  3423. }
  3424. while (!t_table->file->index_next(t_table->record[0]));
  3425. }
  3426. return_val=0; // Return ok
  3427. end_unlock:
  3428. thd->variables.sql_mode= old_sql_mode;
  3429. t_table->file->ha_index_end();
  3430. my_pthread_setspecific_ptr(THR_MALLOC, save_mem_root_ptr);
  3431. DBUG_RETURN(return_val);
  3432. }
  3433. /**
  3434. @brief Helper function to grant_reload. Reloads procs_priv table is it
  3435. exists.
  3436. @param thd A pointer to the thread handler object.
  3437. @see grant_reload
  3438. @return Error state
  3439. @retval FALSE Success
  3440. @retval TRUE An error has occurred.
  3441. */
  3442. static my_bool grant_reload_procs_priv(THD *thd)
  3443. {
  3444. HASH old_proc_priv_hash, old_func_priv_hash;
  3445. TABLE_LIST table;
  3446. my_bool return_val= FALSE;
  3447. DBUG_ENTER("grant_reload_procs_priv");
  3448. table.init_one_table("mysql", 5, "procs_priv",
  3449. strlen("procs_priv"), "procs_priv",
  3450. TL_READ);
  3451. table.open_type= OT_BASE_ONLY;
  3452. if (open_and_lock_tables(thd, &table, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
  3453. {
  3454. close_thread_tables(thd);
  3455. DBUG_RETURN(TRUE);
  3456. }
  3457. mysql_rwlock_wrlock(&LOCK_grant);
  3458. /* Save a copy of the current hash if we need to undo the grant load */
  3459. old_proc_priv_hash= proc_priv_hash;
  3460. old_func_priv_hash= func_priv_hash;
  3461. if ((return_val= grant_load_procs_priv(table.table)))
  3462. {
  3463. /* Error; Reverting to old hash */
  3464. DBUG_PRINT("error",("Reverting to old privileges"));
  3465. grant_free();
  3466. proc_priv_hash= old_proc_priv_hash;
  3467. func_priv_hash= old_func_priv_hash;
  3468. }
  3469. else
  3470. {
  3471. my_hash_free(&old_proc_priv_hash);
  3472. my_hash_free(&old_func_priv_hash);
  3473. }
  3474. mysql_rwlock_unlock(&LOCK_grant);
  3475. close_thread_tables(thd);
  3476. DBUG_RETURN(return_val);
  3477. }
  3478. /**
  3479. @brief Reload information about table and column level privileges if possible
  3480. @param thd Current thread
  3481. Locked tables are checked by acl_reload() and doesn't have to be checked
  3482. in this call.
  3483. This function is also used for initialization of structures responsible
  3484. for table/column-level privilege checking.
  3485. @return Error state
  3486. @retval FALSE Success
  3487. @retval TRUE Error
  3488. */
  3489. my_bool grant_reload(THD *thd)
  3490. {
  3491. TABLE_LIST tables[2];
  3492. HASH old_column_priv_hash;
  3493. MEM_ROOT old_mem;
  3494. my_bool return_val= 1;
  3495. DBUG_ENTER("grant_reload");
  3496. /* Don't do anything if running with --skip-grant-tables */
  3497. if (!initialized)
  3498. DBUG_RETURN(0);
  3499. bzero((char*) tables, sizeof(tables));
  3500. tables[0].alias= tables[0].table_name= (char*) "tables_priv";
  3501. tables[1].alias= tables[1].table_name= (char*) "columns_priv";
  3502. tables[0].db= tables[1].db= (char *) "mysql";
  3503. tables[0].next_local= tables[0].next_global= tables+1;
  3504. tables[0].lock_type= tables[1].lock_type= TL_READ;
  3505. tables[0].open_type= tables[1].open_type= OT_BASE_ONLY;
  3506. init_mdl_requests(tables);
  3507. /*
  3508. To avoid deadlocks we should obtain table locks before
  3509. obtaining LOCK_grant rwlock.
  3510. */
  3511. if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
  3512. goto end;
  3513. mysql_rwlock_wrlock(&LOCK_grant);
  3514. old_column_priv_hash= column_priv_hash;
  3515. /*
  3516. Create a new memory pool but save the current memory pool to make an undo
  3517. opertion possible in case of failure.
  3518. */
  3519. old_mem= memex;
  3520. init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
  3521. if ((return_val= grant_load(thd, tables)))
  3522. { // Error. Revert to old hash
  3523. DBUG_PRINT("error",("Reverting to old privileges"));
  3524. grant_free(); /* purecov: deadcode */
  3525. column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
  3526. memex= old_mem; /* purecov: deadcode */
  3527. }
  3528. else
  3529. {
  3530. my_hash_free(&old_column_priv_hash);
  3531. free_root(&old_mem,MYF(0));
  3532. }
  3533. mysql_rwlock_unlock(&LOCK_grant);
  3534. trans_commit_implicit(thd);
  3535. close_thread_tables(thd);
  3536. thd->mdl_context.release_transactional_locks();
  3537. /*
  3538. It is OK failing to load procs_priv table because we may be
  3539. working with 4.1 privilege tables.
  3540. */
  3541. if (grant_reload_procs_priv(thd))
  3542. return_val= 1;
  3543. mysql_rwlock_wrlock(&LOCK_grant);
  3544. grant_version++;
  3545. mysql_rwlock_unlock(&LOCK_grant);
  3546. end:
  3547. DBUG_RETURN(return_val);
  3548. }
  3549. /**
  3550. @brief Check table level grants
  3551. @param thd Thread handler
  3552. @param want_access Bits of privileges user needs to have.
  3553. @param tables List of tables to check. The user should have
  3554. 'want_access' to all tables in list.
  3555. @param any_combination_will_do TRUE if it's enough to have any privilege for
  3556. any combination of the table columns.
  3557. @param number Check at most this number of tables.
  3558. @param no_errors TRUE if no error should be sent directly to the client.
  3559. If table->grant.want_privilege != 0 then the requested privileges where
  3560. in the set of COL_ACLS but access was not granted on the table level. As
  3561. a consequence an extra check of column privileges is required.
  3562. Specifically if this function returns FALSE the user has some kind of
  3563. privilege on a combination of columns in each table.
  3564. This function is usually preceeded by check_access which establish the
  3565. User-, Db- and Host access rights.
  3566. @see check_access
  3567. @see check_table_access
  3568. @note This functions assumes that either number of tables to be inspected
  3569. by it is limited explicitly (i.e. is is not UINT_MAX) or table list
  3570. used and thd->lex->query_tables_own_last value correspond to each
  3571. other (the latter should be either 0 or point to next_global member
  3572. of one of elements of this table list).
  3573. @return Access status
  3574. @retval FALSE Access granted; But column privileges might need to be
  3575. checked.
  3576. @retval TRUE The user did not have the requested privileges on any of the
  3577. tables.
  3578. */
  3579. bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
  3580. bool any_combination_will_do, uint number, bool no_errors)
  3581. {
  3582. TABLE_LIST *table, *first_not_own_table= thd->lex->first_not_own_table();
  3583. Security_context *sctx= thd->security_ctx;
  3584. uint i;
  3585. ulong orig_want_access= want_access;
  3586. DBUG_ENTER("check_grant");
  3587. DBUG_ASSERT(number > 0);
  3588. /*
  3589. Walk through the list of tables that belong to the query and save the
  3590. requested access (orig_want_privilege) to be able to use it when
  3591. checking access rights to the underlying tables of a view. Our grant
  3592. system gradually eliminates checked bits from want_privilege and thus
  3593. after all checks are done we can no longer use it.
  3594. The check that first_not_own_table is not reached is for the case when
  3595. the given table list refers to the list for prelocking (contains tables
  3596. of other queries). For simple queries first_not_own_table is 0.
  3597. */
  3598. for (i= 0, table= tables;
  3599. i < number && table != first_not_own_table;
  3600. table= table->next_global, i++)
  3601. {
  3602. /*
  3603. Save a copy of the privileges without the SHOW_VIEW_ACL attribute.
  3604. It will be checked during making view.
  3605. */
  3606. table->grant.orig_want_privilege= (want_access & ~SHOW_VIEW_ACL);
  3607. }
  3608. mysql_rwlock_rdlock(&LOCK_grant);
  3609. for (table= tables;
  3610. table && number-- && table != first_not_own_table;
  3611. table= table->next_global)
  3612. {
  3613. GRANT_TABLE *grant_table;
  3614. sctx = test(table->security_ctx) ?
  3615. table->security_ctx : thd->security_ctx;
  3616. const ACL_internal_table_access *access;
  3617. access= get_cached_table_access(&table->grant.m_internal,
  3618. table->get_db_name(),
  3619. table->get_table_name());
  3620. if (access)
  3621. {
  3622. switch(access->check(orig_want_access, &table->grant.privilege))
  3623. {
  3624. case ACL_INTERNAL_ACCESS_GRANTED:
  3625. /*
  3626. Currently,
  3627. - the information_schema does not subclass ACL_internal_table_access,
  3628. there are no per table privilege checks for I_S,
  3629. - the performance schema does use per tables checks, but at most
  3630. returns 'CHECK_GRANT', and never 'ACCESS_GRANTED'.
  3631. so this branch is not used.
  3632. */
  3633. DBUG_ASSERT(0);
  3634. case ACL_INTERNAL_ACCESS_DENIED:
  3635. goto err;
  3636. case ACL_INTERNAL_ACCESS_CHECK_GRANT:
  3637. break;
  3638. }
  3639. }
  3640. want_access= orig_want_access;
  3641. want_access&= ~sctx->master_access;
  3642. if (!want_access)
  3643. continue; // ok
  3644. if (!(~table->grant.privilege & want_access) ||
  3645. table->is_anonymous_derived_table() || table->schema_table)
  3646. {
  3647. /*
  3648. It is subquery in the FROM clause. VIEW set table->derived after
  3649. table opening, but this function always called before table opening.
  3650. */
  3651. if (!table->referencing_view)
  3652. {
  3653. /*
  3654. If it's a temporary table created for a subquery in the FROM
  3655. clause, or an INFORMATION_SCHEMA table, drop the request for
  3656. a privilege.
  3657. */
  3658. table->grant.want_privilege= 0;
  3659. }
  3660. continue;
  3661. }
  3662. if (!(grant_table= table_hash_search(sctx->host, sctx->ip,
  3663. table->get_db_name(), sctx->priv_user,
  3664. table->get_table_name(), FALSE)))
  3665. {
  3666. want_access &= ~table->grant.privilege;
  3667. goto err; // No grants
  3668. }
  3669. /*
  3670. For SHOW COLUMNS, SHOW INDEX it is enough to have some
  3671. privileges on any column combination on the table.
  3672. */
  3673. if (any_combination_will_do)
  3674. continue;
  3675. table->grant.grant_table=grant_table; // Remember for column test
  3676. table->grant.version=grant_version;
  3677. table->grant.privilege|= grant_table->privs;
  3678. table->grant.want_privilege= ((want_access & COL_ACLS)
  3679. & ~table->grant.privilege);
  3680. if (!(~table->grant.privilege & want_access))
  3681. continue;
  3682. if (want_access & ~(grant_table->cols | table->grant.privilege))
  3683. {
  3684. want_access &= ~(grant_table->cols | table->grant.privilege);
  3685. goto err; // impossible
  3686. }
  3687. }
  3688. mysql_rwlock_unlock(&LOCK_grant);
  3689. DBUG_RETURN(FALSE);
  3690. err:
  3691. mysql_rwlock_unlock(&LOCK_grant);
  3692. if (!no_errors) // Not a silent skip of table
  3693. {
  3694. char command[128];
  3695. get_privilege_desc(command, sizeof(command), want_access);
  3696. my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
  3697. command,
  3698. sctx->priv_user,
  3699. sctx->host_or_ip,
  3700. table ? table->get_table_name() : "unknown");
  3701. }
  3702. DBUG_RETURN(TRUE);
  3703. }
  3704. /*
  3705. Check column rights in given security context
  3706. SYNOPSIS
  3707. check_grant_column()
  3708. thd thread handler
  3709. grant grant information structure
  3710. db_name db name
  3711. table_name table name
  3712. name column name
  3713. length column name length
  3714. sctx security context
  3715. RETURN
  3716. FALSE OK
  3717. TRUE access denied
  3718. */
  3719. bool check_grant_column(THD *thd, GRANT_INFO *grant,
  3720. const char *db_name, const char *table_name,
  3721. const char *name, uint length, Security_context *sctx)
  3722. {
  3723. GRANT_TABLE *grant_table;
  3724. GRANT_COLUMN *grant_column;
  3725. ulong want_access= grant->want_privilege & ~grant->privilege;
  3726. DBUG_ENTER("check_grant_column");
  3727. DBUG_PRINT("enter", ("table: %s want_access: %lu", table_name, want_access));
  3728. if (!want_access)
  3729. DBUG_RETURN(0); // Already checked
  3730. mysql_rwlock_rdlock(&LOCK_grant);
  3731. /* reload table if someone has modified any grants */
  3732. if (grant->version != grant_version)
  3733. {
  3734. grant->grant_table=
  3735. table_hash_search(sctx->host, sctx->ip, db_name,
  3736. sctx->priv_user,
  3737. table_name, 0); /* purecov: inspected */
  3738. grant->version= grant_version; /* purecov: inspected */
  3739. }
  3740. if (!(grant_table= grant->grant_table))
  3741. goto err; /* purecov: deadcode */
  3742. grant_column=column_hash_search(grant_table, name, length);
  3743. if (grant_column && !(~grant_column->rights & want_access))
  3744. {
  3745. mysql_rwlock_unlock(&LOCK_grant);
  3746. DBUG_RETURN(0);
  3747. }
  3748. err:
  3749. mysql_rwlock_unlock(&LOCK_grant);
  3750. char command[128];
  3751. get_privilege_desc(command, sizeof(command), want_access);
  3752. my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
  3753. command,
  3754. sctx->priv_user,
  3755. sctx->host_or_ip,
  3756. name,
  3757. table_name);
  3758. DBUG_RETURN(1);
  3759. }
  3760. /*
  3761. Check the access right to a column depending on the type of table.
  3762. SYNOPSIS
  3763. check_column_grant_in_table_ref()
  3764. thd thread handler
  3765. table_ref table reference where to check the field
  3766. name name of field to check
  3767. length length of name
  3768. DESCRIPTION
  3769. Check the access rights to a column depending on the type of table
  3770. reference where the column is checked. The function provides a
  3771. generic interface to check column access rights that hides the
  3772. heterogeneity of the column representation - whether it is a view
  3773. or a stored table colum.
  3774. RETURN
  3775. FALSE OK
  3776. TRUE access denied
  3777. */
  3778. bool check_column_grant_in_table_ref(THD *thd, TABLE_LIST * table_ref,
  3779. const char *name, uint length)
  3780. {
  3781. GRANT_INFO *grant;
  3782. const char *db_name;
  3783. const char *table_name;
  3784. Security_context *sctx= test(table_ref->security_ctx) ?
  3785. table_ref->security_ctx : thd->security_ctx;
  3786. if (table_ref->view || table_ref->field_translation)
  3787. {
  3788. /* View or derived information schema table. */
  3789. ulong view_privs;
  3790. grant= &(table_ref->grant);
  3791. db_name= table_ref->view_db.str;
  3792. table_name= table_ref->view_name.str;
  3793. if (table_ref->belong_to_view &&
  3794. thd->lex->sql_command == SQLCOM_SHOW_FIELDS)
  3795. {
  3796. view_privs= get_column_grant(thd, grant, db_name, table_name, name);
  3797. if (view_privs & VIEW_ANY_ACL)
  3798. {
  3799. table_ref->belong_to_view->allowed_show= TRUE;
  3800. return FALSE;
  3801. }
  3802. table_ref->belong_to_view->allowed_show= FALSE;
  3803. my_message(ER_VIEW_NO_EXPLAIN, ER(ER_VIEW_NO_EXPLAIN), MYF(0));
  3804. return TRUE;
  3805. }
  3806. }
  3807. else
  3808. {
  3809. /* Normal or temporary table. */
  3810. TABLE *table= table_ref->table;
  3811. grant= &(table->grant);
  3812. db_name= table->s->db.str;
  3813. table_name= table->s->table_name.str;
  3814. }
  3815. if (grant->want_privilege)
  3816. return check_grant_column(thd, grant, db_name, table_name, name,
  3817. length, sctx);
  3818. else
  3819. return FALSE;
  3820. }
  3821. /**
  3822. @brief check if a query can access a set of columns
  3823. @param thd the current thread
  3824. @param want_access_arg the privileges requested
  3825. @param fields an iterator over the fields of a table reference.
  3826. @return Operation status
  3827. @retval 0 Success
  3828. @retval 1 Falure
  3829. @details This function walks over the columns of a table reference
  3830. The columns may originate from different tables, depending on the kind of
  3831. table reference, e.g. join, view.
  3832. For each table it will retrieve the grant information and will use it
  3833. to check the required access privileges for the fields requested from it.
  3834. */
  3835. bool check_grant_all_columns(THD *thd, ulong want_access_arg,
  3836. Field_iterator_table_ref *fields)
  3837. {
  3838. Security_context *sctx= thd->security_ctx;
  3839. ulong want_access= want_access_arg;
  3840. const char *table_name= NULL;
  3841. const char* db_name;
  3842. GRANT_INFO *grant;
  3843. /* Initialized only to make gcc happy */
  3844. GRANT_TABLE *grant_table= NULL;
  3845. /*
  3846. Flag that gets set if privilege checking has to be performed on column
  3847. level.
  3848. */
  3849. bool using_column_privileges= FALSE;
  3850. mysql_rwlock_rdlock(&LOCK_grant);
  3851. for (; !fields->end_of_fields(); fields->next())
  3852. {
  3853. const char *field_name= fields->name();
  3854. if (table_name != fields->get_table_name())
  3855. {
  3856. table_name= fields->get_table_name();
  3857. db_name= fields->get_db_name();
  3858. grant= fields->grant();
  3859. /* get a fresh one for each table */
  3860. want_access= want_access_arg & ~grant->privilege;
  3861. if (want_access)
  3862. {
  3863. /* reload table if someone has modified any grants */
  3864. if (grant->version != grant_version)
  3865. {
  3866. grant->grant_table=
  3867. table_hash_search(sctx->host, sctx->ip, db_name,
  3868. sctx->priv_user,
  3869. table_name, 0); /* purecov: inspected */
  3870. grant->version= grant_version; /* purecov: inspected */
  3871. }
  3872. grant_table= grant->grant_table;
  3873. DBUG_ASSERT (grant_table);
  3874. }
  3875. }
  3876. if (want_access)
  3877. {
  3878. GRANT_COLUMN *grant_column=
  3879. column_hash_search(grant_table, field_name,
  3880. (uint) strlen(field_name));
  3881. if (grant_column)
  3882. using_column_privileges= TRUE;
  3883. if (!grant_column || (~grant_column->rights & want_access))
  3884. goto err;
  3885. }
  3886. }
  3887. mysql_rwlock_unlock(&LOCK_grant);
  3888. return 0;
  3889. err:
  3890. mysql_rwlock_unlock(&LOCK_grant);
  3891. char command[128];
  3892. get_privilege_desc(command, sizeof(command), want_access);
  3893. /*
  3894. Do not give an error message listing a column name unless the user has
  3895. privilege to see all columns.
  3896. */
  3897. if (using_column_privileges)
  3898. my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0),
  3899. command, sctx->priv_user,
  3900. sctx->host_or_ip, table_name);
  3901. else
  3902. my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0),
  3903. command,
  3904. sctx->priv_user,
  3905. sctx->host_or_ip,
  3906. fields->name(),
  3907. table_name);
  3908. return 1;
  3909. }
  3910. static bool check_grant_db_routine(THD *thd, const char *db, HASH *hash)
  3911. {
  3912. Security_context *sctx= thd->security_ctx;
  3913. for (uint idx= 0; idx < hash->records; ++idx)
  3914. {
  3915. GRANT_NAME *item= (GRANT_NAME*) my_hash_element(hash, idx);
  3916. if (strcmp(item->user, sctx->priv_user) == 0 &&
  3917. strcmp(item->db, db) == 0 &&
  3918. compare_hostname(&item->host, sctx->host, sctx->ip))
  3919. {
  3920. return FALSE;
  3921. }
  3922. }
  3923. return TRUE;
  3924. }
  3925. /*
  3926. Check if a user has the right to access a database
  3927. Access is accepted if he has a grant for any table/routine in the database
  3928. Return 1 if access is denied
  3929. */
  3930. bool check_grant_db(THD *thd,const char *db)
  3931. {
  3932. Security_context *sctx= thd->security_ctx;
  3933. char helping [NAME_LEN+USERNAME_LENGTH+2];
  3934. uint len;
  3935. bool error= TRUE;
  3936. len= (uint) (strmov(strmov(helping, sctx->priv_user) + 1, db) - helping) + 1;
  3937. mysql_rwlock_rdlock(&LOCK_grant);
  3938. for (uint idx=0 ; idx < column_priv_hash.records ; idx++)
  3939. {
  3940. GRANT_TABLE *grant_table= (GRANT_TABLE*)
  3941. my_hash_element(&column_priv_hash,
  3942. idx);
  3943. if (len < grant_table->key_length &&
  3944. !memcmp(grant_table->hash_key,helping,len) &&
  3945. compare_hostname(&grant_table->host, sctx->host, sctx->ip))
  3946. {
  3947. error= FALSE; /* Found match. */
  3948. break;
  3949. }
  3950. }
  3951. if (error)
  3952. error= check_grant_db_routine(thd, db, &proc_priv_hash) &&
  3953. check_grant_db_routine(thd, db, &func_priv_hash);
  3954. mysql_rwlock_unlock(&LOCK_grant);
  3955. return error;
  3956. }
  3957. /****************************************************************************
  3958. Check routine level grants
  3959. SYNPOSIS
  3960. bool check_grant_routine()
  3961. thd Thread handler
  3962. want_access Bits of privileges user needs to have
  3963. procs List of routines to check. The user should have 'want_access'
  3964. is_proc True if the list is all procedures, else functions
  3965. no_errors If 0 then we write an error. The error is sent directly to
  3966. the client
  3967. RETURN
  3968. 0 ok
  3969. 1 Error: User did not have the requested privielges
  3970. ****************************************************************************/
  3971. bool check_grant_routine(THD *thd, ulong want_access,
  3972. TABLE_LIST *procs, bool is_proc, bool no_errors)
  3973. {
  3974. TABLE_LIST *table;
  3975. Security_context *sctx= thd->security_ctx;
  3976. char *user= sctx->priv_user;
  3977. char *host= sctx->priv_host;
  3978. DBUG_ENTER("check_grant_routine");
  3979. want_access&= ~sctx->master_access;
  3980. if (!want_access)
  3981. DBUG_RETURN(0); // ok
  3982. mysql_rwlock_rdlock(&LOCK_grant);
  3983. for (table= procs; table; table= table->next_global)
  3984. {
  3985. GRANT_NAME *grant_proc;
  3986. if ((grant_proc= routine_hash_search(host, sctx->ip, table->db, user,
  3987. table->table_name, is_proc, 0)))
  3988. table->grant.privilege|= grant_proc->privs;
  3989. if (want_access & ~table->grant.privilege)
  3990. {
  3991. want_access &= ~table->grant.privilege;
  3992. goto err;
  3993. }
  3994. }
  3995. mysql_rwlock_unlock(&LOCK_grant);
  3996. DBUG_RETURN(0);
  3997. err:
  3998. mysql_rwlock_unlock(&LOCK_grant);
  3999. if (!no_errors)
  4000. {
  4001. char buff[1024];
  4002. const char *command="";
  4003. if (table)
  4004. strxmov(buff, table->db, ".", table->table_name, NullS);
  4005. if (want_access & EXECUTE_ACL)
  4006. command= "execute";
  4007. else if (want_access & ALTER_PROC_ACL)
  4008. command= "alter routine";
  4009. else if (want_access & GRANT_ACL)
  4010. command= "grant";
  4011. my_error(ER_PROCACCESS_DENIED_ERROR, MYF(0),
  4012. command, user, host, table ? buff : "unknown");
  4013. }
  4014. DBUG_RETURN(1);
  4015. }
  4016. /*
  4017. Check if routine has any of the
  4018. routine level grants
  4019. SYNPOSIS
  4020. bool check_routine_level_acl()
  4021. thd Thread handler
  4022. db Database name
  4023. name Routine name
  4024. RETURN
  4025. 0 Ok
  4026. 1 error
  4027. */
  4028. bool check_routine_level_acl(THD *thd, const char *db, const char *name,
  4029. bool is_proc)
  4030. {
  4031. bool no_routine_acl= 1;
  4032. GRANT_NAME *grant_proc;
  4033. Security_context *sctx= thd->security_ctx;
  4034. mysql_rwlock_rdlock(&LOCK_grant);
  4035. if ((grant_proc= routine_hash_search(sctx->priv_host,
  4036. sctx->ip, db,
  4037. sctx->priv_user,
  4038. name, is_proc, 0)))
  4039. no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
  4040. mysql_rwlock_unlock(&LOCK_grant);
  4041. return no_routine_acl;
  4042. }
  4043. /*****************************************************************************
  4044. Functions to retrieve the grant for a table/column (for SHOW functions)
  4045. *****************************************************************************/
  4046. ulong get_table_grant(THD *thd, TABLE_LIST *table)
  4047. {
  4048. ulong privilege;
  4049. Security_context *sctx= thd->security_ctx;
  4050. const char *db = table->db ? table->db : thd->db;
  4051. GRANT_TABLE *grant_table;
  4052. mysql_rwlock_rdlock(&LOCK_grant);
  4053. #ifdef EMBEDDED_LIBRARY
  4054. grant_table= NULL;
  4055. #else
  4056. grant_table= table_hash_search(sctx->host, sctx->ip, db, sctx->priv_user,
  4057. table->table_name, 0);
  4058. #endif
  4059. table->grant.grant_table=grant_table; // Remember for column test
  4060. table->grant.version=grant_version;
  4061. if (grant_table)
  4062. table->grant.privilege|= grant_table->privs;
  4063. privilege= table->grant.privilege;
  4064. mysql_rwlock_unlock(&LOCK_grant);
  4065. return privilege;
  4066. }
  4067. /*
  4068. Determine the access priviliges for a field.
  4069. SYNOPSIS
  4070. get_column_grant()
  4071. thd thread handler
  4072. grant grants table descriptor
  4073. db_name name of database that the field belongs to
  4074. table_name name of table that the field belongs to
  4075. field_name name of field
  4076. DESCRIPTION
  4077. The procedure may also modify: grant->grant_table and grant->version.
  4078. RETURN
  4079. The access priviliges for the field db_name.table_name.field_name
  4080. */
  4081. ulong get_column_grant(THD *thd, GRANT_INFO *grant,
  4082. const char *db_name, const char *table_name,
  4083. const char *field_name)
  4084. {
  4085. GRANT_TABLE *grant_table;
  4086. GRANT_COLUMN *grant_column;
  4087. ulong priv;
  4088. mysql_rwlock_rdlock(&LOCK_grant);
  4089. /* reload table if someone has modified any grants */
  4090. if (grant->version != grant_version)
  4091. {
  4092. Security_context *sctx= thd->security_ctx;
  4093. grant->grant_table=
  4094. table_hash_search(sctx->host, sctx->ip,
  4095. db_name, sctx->priv_user,
  4096. table_name, 0); /* purecov: inspected */
  4097. grant->version= grant_version; /* purecov: inspected */
  4098. }
  4099. if (!(grant_table= grant->grant_table))
  4100. priv= grant->privilege;
  4101. else
  4102. {
  4103. grant_column= column_hash_search(grant_table, field_name,
  4104. (uint) strlen(field_name));
  4105. if (!grant_column)
  4106. priv= (grant->privilege | grant_table->privs);
  4107. else
  4108. priv= (grant->privilege | grant_table->privs | grant_column->rights);
  4109. }
  4110. mysql_rwlock_unlock(&LOCK_grant);
  4111. return priv;
  4112. }
  4113. /* Help function for mysql_show_grants */
  4114. static void add_user_option(String *grant, ulong value, const char *name)
  4115. {
  4116. if (value)
  4117. {
  4118. char buff[22], *p; // just as in int2str
  4119. grant->append(' ');
  4120. grant->append(name, strlen(name));
  4121. grant->append(' ');
  4122. p=int10_to_str(value, buff, 10);
  4123. grant->append(buff,p-buff);
  4124. }
  4125. }
  4126. static const char *command_array[]=
  4127. {
  4128. "SELECT", "INSERT", "UPDATE", "DELETE", "CREATE", "DROP", "RELOAD",
  4129. "SHUTDOWN", "PROCESS","FILE", "GRANT", "REFERENCES", "INDEX",
  4130. "ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES",
  4131. "LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT",
  4132. "CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE",
  4133. "CREATE USER", "EVENT", "TRIGGER", "CREATE TABLESPACE"
  4134. };
  4135. static uint command_lengths[]=
  4136. {
  4137. 6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9,
  4138. 14, 13, 11, 5, 7, 17
  4139. };
  4140. static int show_routine_grants(THD *thd, LEX_USER *lex_user, HASH *hash,
  4141. const char *type, int typelen,
  4142. char *buff, int buffsize);
  4143. /*
  4144. SHOW GRANTS; Send grants for a user to the client
  4145. IMPLEMENTATION
  4146. Send to client grant-like strings depicting user@host privileges
  4147. */
  4148. bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
  4149. {
  4150. ulong want_access;
  4151. uint counter,index;
  4152. int error = 0;
  4153. ACL_USER *acl_user;
  4154. ACL_DB *acl_db;
  4155. char buff[1024];
  4156. Protocol *protocol= thd->protocol;
  4157. DBUG_ENTER("mysql_show_grants");
  4158. LINT_INIT(acl_user);
  4159. if (!initialized)
  4160. {
  4161. my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
  4162. DBUG_RETURN(TRUE);
  4163. }
  4164. mysql_rwlock_rdlock(&LOCK_grant);
  4165. mysql_mutex_lock(&acl_cache->lock);
  4166. acl_user= find_acl_user(lex_user->host.str, lex_user->user.str, TRUE);
  4167. if (!acl_user)
  4168. {
  4169. mysql_mutex_unlock(&acl_cache->lock);
  4170. mysql_rwlock_unlock(&LOCK_grant);
  4171. my_error(ER_NONEXISTING_GRANT, MYF(0),
  4172. lex_user->user.str, lex_user->host.str);
  4173. DBUG_RETURN(TRUE);
  4174. }
  4175. Item_string *field=new Item_string("",0,&my_charset_latin1);
  4176. List<Item> field_list;
  4177. field->name=buff;
  4178. field->max_length=1024;
  4179. strxmov(buff,"Grants for ",lex_user->user.str,"@",
  4180. lex_user->host.str,NullS);
  4181. field_list.push_back(field);
  4182. if (protocol->send_result_set_metadata(&field_list,
  4183. Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
  4184. {
  4185. mysql_mutex_unlock(&acl_cache->lock);
  4186. mysql_rwlock_unlock(&LOCK_grant);
  4187. DBUG_RETURN(TRUE);
  4188. }
  4189. /* Add first global access grants */
  4190. {
  4191. String global(buff,sizeof(buff),system_charset_info);
  4192. global.length(0);
  4193. global.append(STRING_WITH_LEN("GRANT "));
  4194. want_access= acl_user->access;
  4195. if (test_all_bits(want_access, (GLOBAL_ACLS & ~ GRANT_ACL)))
  4196. global.append(STRING_WITH_LEN("ALL PRIVILEGES"));
  4197. else if (!(want_access & ~GRANT_ACL))
  4198. global.append(STRING_WITH_LEN("USAGE"));
  4199. else
  4200. {
  4201. bool found=0;
  4202. ulong j,test_access= want_access & ~GRANT_ACL;
  4203. for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
  4204. {
  4205. if (test_access & j)
  4206. {
  4207. if (found)
  4208. global.append(STRING_WITH_LEN(", "));
  4209. found=1;
  4210. global.append(command_array[counter],command_lengths[counter]);
  4211. }
  4212. }
  4213. }
  4214. global.append (STRING_WITH_LEN(" ON *.* TO '"));
  4215. global.append(lex_user->user.str, lex_user->user.length,
  4216. system_charset_info);
  4217. global.append (STRING_WITH_LEN("'@'"));
  4218. global.append(lex_user->host.str,lex_user->host.length,
  4219. system_charset_info);
  4220. global.append ('\'');
  4221. if (acl_user->salt_len)
  4222. {
  4223. char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
  4224. if (acl_user->salt_len == SCRAMBLE_LENGTH)
  4225. make_password_from_salt(passwd_buff, acl_user->salt);
  4226. else
  4227. make_password_from_salt_323(passwd_buff, (ulong *) acl_user->salt);
  4228. global.append(STRING_WITH_LEN(" IDENTIFIED BY PASSWORD '"));
  4229. global.append(passwd_buff);
  4230. global.append('\'');
  4231. }
  4232. /* "show grants" SSL related stuff */
  4233. if (acl_user->ssl_type == SSL_TYPE_ANY)
  4234. global.append(STRING_WITH_LEN(" REQUIRE SSL"));
  4235. else if (acl_user->ssl_type == SSL_TYPE_X509)
  4236. global.append(STRING_WITH_LEN(" REQUIRE X509"));
  4237. else if (acl_user->ssl_type == SSL_TYPE_SPECIFIED)
  4238. {
  4239. int ssl_options = 0;
  4240. global.append(STRING_WITH_LEN(" REQUIRE "));
  4241. if (acl_user->x509_issuer)
  4242. {
  4243. ssl_options++;
  4244. global.append(STRING_WITH_LEN("ISSUER \'"));
  4245. global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
  4246. global.append('\'');
  4247. }
  4248. if (acl_user->x509_subject)
  4249. {
  4250. if (ssl_options++)
  4251. global.append(' ');
  4252. global.append(STRING_WITH_LEN("SUBJECT \'"));
  4253. global.append(acl_user->x509_subject,strlen(acl_user->x509_subject),
  4254. system_charset_info);
  4255. global.append('\'');
  4256. }
  4257. if (acl_user->ssl_cipher)
  4258. {
  4259. if (ssl_options++)
  4260. global.append(' ');
  4261. global.append(STRING_WITH_LEN("CIPHER '"));
  4262. global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher),
  4263. system_charset_info);
  4264. global.append('\'');
  4265. }
  4266. }
  4267. if ((want_access & GRANT_ACL) ||
  4268. (acl_user->user_resource.questions ||
  4269. acl_user->user_resource.updates ||
  4270. acl_user->user_resource.conn_per_hour ||
  4271. acl_user->user_resource.user_conn))
  4272. {
  4273. global.append(STRING_WITH_LEN(" WITH"));
  4274. if (want_access & GRANT_ACL)
  4275. global.append(STRING_WITH_LEN(" GRANT OPTION"));
  4276. add_user_option(&global, acl_user->user_resource.questions,
  4277. "MAX_QUERIES_PER_HOUR");
  4278. add_user_option(&global, acl_user->user_resource.updates,
  4279. "MAX_UPDATES_PER_HOUR");
  4280. add_user_option(&global, acl_user->user_resource.conn_per_hour,
  4281. "MAX_CONNECTIONS_PER_HOUR");
  4282. add_user_option(&global, acl_user->user_resource.user_conn,
  4283. "MAX_USER_CONNECTIONS");
  4284. }
  4285. protocol->prepare_for_resend();
  4286. protocol->store(global.ptr(),global.length(),global.charset());
  4287. if (protocol->write())
  4288. {
  4289. error= -1;
  4290. goto end;
  4291. }
  4292. }
  4293. /* Add database access */
  4294. for (counter=0 ; counter < acl_dbs.elements ; counter++)
  4295. {
  4296. const char *user, *host;
  4297. acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
  4298. if (!(user=acl_db->user))
  4299. user= "";
  4300. if (!(host=acl_db->host.hostname))
  4301. host= "";
  4302. /*
  4303. We do not make SHOW GRANTS case-sensitive here (like REVOKE),
  4304. but make it case-insensitive because that's the way they are
  4305. actually applied, and showing fewer privileges than are applied
  4306. would be wrong from a security point of view.
  4307. */
  4308. if (!strcmp(lex_user->user.str,user) &&
  4309. !my_strcasecmp(system_charset_info, lex_user->host.str, host))
  4310. {
  4311. want_access=acl_db->access;
  4312. if (want_access)
  4313. {
  4314. String db(buff,sizeof(buff),system_charset_info);
  4315. db.length(0);
  4316. db.append(STRING_WITH_LEN("GRANT "));
  4317. if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL)))
  4318. db.append(STRING_WITH_LEN("ALL PRIVILEGES"));
  4319. else if (!(want_access & ~GRANT_ACL))
  4320. db.append(STRING_WITH_LEN("USAGE"));
  4321. else
  4322. {
  4323. int found=0, cnt;
  4324. ulong j,test_access= want_access & ~GRANT_ACL;
  4325. for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
  4326. {
  4327. if (test_access & j)
  4328. {
  4329. if (found)
  4330. db.append(STRING_WITH_LEN(", "));
  4331. found = 1;
  4332. db.append(command_array[cnt],command_lengths[cnt]);
  4333. }
  4334. }
  4335. }
  4336. db.append (STRING_WITH_LEN(" ON "));
  4337. append_identifier(thd, &db, acl_db->db, strlen(acl_db->db));
  4338. db.append (STRING_WITH_LEN(".* TO '"));
  4339. db.append(lex_user->user.str, lex_user->user.length,
  4340. system_charset_info);
  4341. db.append (STRING_WITH_LEN("'@'"));
  4342. // host and lex_user->host are equal except for case
  4343. db.append(host, strlen(host), system_charset_info);
  4344. db.append ('\'');
  4345. if (want_access & GRANT_ACL)
  4346. db.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
  4347. protocol->prepare_for_resend();
  4348. protocol->store(db.ptr(),db.length(),db.charset());
  4349. if (protocol->write())
  4350. {
  4351. error= -1;
  4352. goto end;
  4353. }
  4354. }
  4355. }
  4356. }
  4357. /* Add table & column access */
  4358. for (index=0 ; index < column_priv_hash.records ; index++)
  4359. {
  4360. const char *user, *host;
  4361. GRANT_TABLE *grant_table= (GRANT_TABLE*)
  4362. my_hash_element(&column_priv_hash, index);
  4363. if (!(user=grant_table->user))
  4364. user= "";
  4365. if (!(host= grant_table->host.hostname))
  4366. host= "";
  4367. /*
  4368. We do not make SHOW GRANTS case-sensitive here (like REVOKE),
  4369. but make it case-insensitive because that's the way they are
  4370. actually applied, and showing fewer privileges than are applied
  4371. would be wrong from a security point of view.
  4372. */
  4373. if (!strcmp(lex_user->user.str,user) &&
  4374. !my_strcasecmp(system_charset_info, lex_user->host.str, host))
  4375. {
  4376. ulong table_access= grant_table->privs;
  4377. if ((table_access | grant_table->cols) != 0)
  4378. {
  4379. String global(buff, sizeof(buff), system_charset_info);
  4380. ulong test_access= (table_access | grant_table->cols) & ~GRANT_ACL;
  4381. global.length(0);
  4382. global.append(STRING_WITH_LEN("GRANT "));
  4383. if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL)))
  4384. global.append(STRING_WITH_LEN("ALL PRIVILEGES"));
  4385. else if (!test_access)
  4386. global.append(STRING_WITH_LEN("USAGE"));
  4387. else
  4388. {
  4389. /* Add specific column access */
  4390. int found= 0;
  4391. ulong j;
  4392. for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1)
  4393. {
  4394. if (test_access & j)
  4395. {
  4396. if (found)
  4397. global.append(STRING_WITH_LEN(", "));
  4398. found= 1;
  4399. global.append(command_array[counter],command_lengths[counter]);
  4400. if (grant_table->cols)
  4401. {
  4402. uint found_col= 0;
  4403. for (uint col_index=0 ;
  4404. col_index < grant_table->hash_columns.records ;
  4405. col_index++)
  4406. {
  4407. GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
  4408. my_hash_element(&grant_table->hash_columns,col_index);
  4409. if (grant_column->rights & j)
  4410. {
  4411. if (!found_col)
  4412. {
  4413. found_col= 1;
  4414. /*
  4415. If we have a duplicated table level privilege, we
  4416. must write the access privilege name again.
  4417. */
  4418. if (table_access & j)
  4419. {
  4420. global.append(STRING_WITH_LEN(", "));
  4421. global.append(command_array[counter],
  4422. command_lengths[counter]);
  4423. }
  4424. global.append(STRING_WITH_LEN(" ("));
  4425. }
  4426. else
  4427. global.append(STRING_WITH_LEN(", "));
  4428. global.append(grant_column->column,
  4429. grant_column->key_length,
  4430. system_charset_info);
  4431. }
  4432. }
  4433. if (found_col)
  4434. global.append(')');
  4435. }
  4436. }
  4437. }
  4438. }
  4439. global.append(STRING_WITH_LEN(" ON "));
  4440. append_identifier(thd, &global, grant_table->db,
  4441. strlen(grant_table->db));
  4442. global.append('.');
  4443. append_identifier(thd, &global, grant_table->tname,
  4444. strlen(grant_table->tname));
  4445. global.append(STRING_WITH_LEN(" TO '"));
  4446. global.append(lex_user->user.str, lex_user->user.length,
  4447. system_charset_info);
  4448. global.append(STRING_WITH_LEN("'@'"));
  4449. // host and lex_user->host are equal except for case
  4450. global.append(host, strlen(host), system_charset_info);
  4451. global.append('\'');
  4452. if (table_access & GRANT_ACL)
  4453. global.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
  4454. protocol->prepare_for_resend();
  4455. protocol->store(global.ptr(),global.length(),global.charset());
  4456. if (protocol->write())
  4457. {
  4458. error= -1;
  4459. break;
  4460. }
  4461. }
  4462. }
  4463. }
  4464. if (show_routine_grants(thd, lex_user, &proc_priv_hash,
  4465. STRING_WITH_LEN("PROCEDURE"), buff, sizeof(buff)))
  4466. {
  4467. error= -1;
  4468. goto end;
  4469. }
  4470. if (show_routine_grants(thd, lex_user, &func_priv_hash,
  4471. STRING_WITH_LEN("FUNCTION"), buff, sizeof(buff)))
  4472. {
  4473. error= -1;
  4474. goto end;
  4475. }
  4476. end:
  4477. mysql_mutex_unlock(&acl_cache->lock);
  4478. mysql_rwlock_unlock(&LOCK_grant);
  4479. my_eof(thd);
  4480. DBUG_RETURN(error);
  4481. }
  4482. static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
  4483. const char *type, int typelen,
  4484. char *buff, int buffsize)
  4485. {
  4486. uint counter, index;
  4487. int error= 0;
  4488. Protocol *protocol= thd->protocol;
  4489. /* Add routine access */
  4490. for (index=0 ; index < hash->records ; index++)
  4491. {
  4492. const char *user, *host;
  4493. GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, index);
  4494. if (!(user=grant_proc->user))
  4495. user= "";
  4496. if (!(host= grant_proc->host.hostname))
  4497. host= "";
  4498. /*
  4499. We do not make SHOW GRANTS case-sensitive here (like REVOKE),
  4500. but make it case-insensitive because that's the way they are
  4501. actually applied, and showing fewer privileges than are applied
  4502. would be wrong from a security point of view.
  4503. */
  4504. if (!strcmp(lex_user->user.str,user) &&
  4505. !my_strcasecmp(system_charset_info, lex_user->host.str, host))
  4506. {
  4507. ulong proc_access= grant_proc->privs;
  4508. if (proc_access != 0)
  4509. {
  4510. String global(buff, buffsize, system_charset_info);
  4511. ulong test_access= proc_access & ~GRANT_ACL;
  4512. global.length(0);
  4513. global.append(STRING_WITH_LEN("GRANT "));
  4514. if (!test_access)
  4515. global.append(STRING_WITH_LEN("USAGE"));
  4516. else
  4517. {
  4518. /* Add specific procedure access */
  4519. int found= 0;
  4520. ulong j;
  4521. for (counter= 0, j= SELECT_ACL; j <= PROC_ACLS; counter++, j<<= 1)
  4522. {
  4523. if (test_access & j)
  4524. {
  4525. if (found)
  4526. global.append(STRING_WITH_LEN(", "));
  4527. found= 1;
  4528. global.append(command_array[counter],command_lengths[counter]);
  4529. }
  4530. }
  4531. }
  4532. global.append(STRING_WITH_LEN(" ON "));
  4533. global.append(type,typelen);
  4534. global.append(' ');
  4535. append_identifier(thd, &global, grant_proc->db,
  4536. strlen(grant_proc->db));
  4537. global.append('.');
  4538. append_identifier(thd, &global, grant_proc->tname,
  4539. strlen(grant_proc->tname));
  4540. global.append(STRING_WITH_LEN(" TO '"));
  4541. global.append(lex_user->user.str, lex_user->user.length,
  4542. system_charset_info);
  4543. global.append(STRING_WITH_LEN("'@'"));
  4544. // host and lex_user->host are equal except for case
  4545. global.append(host, strlen(host), system_charset_info);
  4546. global.append('\'');
  4547. if (proc_access & GRANT_ACL)
  4548. global.append(STRING_WITH_LEN(" WITH GRANT OPTION"));
  4549. protocol->prepare_for_resend();
  4550. protocol->store(global.ptr(),global.length(),global.charset());
  4551. if (protocol->write())
  4552. {
  4553. error= -1;
  4554. break;
  4555. }
  4556. }
  4557. }
  4558. }
  4559. return error;
  4560. }
  4561. /*
  4562. Make a clear-text version of the requested privilege.
  4563. */
  4564. void get_privilege_desc(char *to, uint max_length, ulong access)
  4565. {
  4566. uint pos;
  4567. char *start=to;
  4568. DBUG_ASSERT(max_length >= 30); // For end ',' removal
  4569. if (access)
  4570. {
  4571. max_length--; // Reserve place for end-zero
  4572. for (pos=0 ; access ; pos++, access>>=1)
  4573. {
  4574. if ((access & 1) &&
  4575. command_lengths[pos] + (uint) (to-start) < max_length)
  4576. {
  4577. to= strmov(to, command_array[pos]);
  4578. *to++=',';
  4579. }
  4580. }
  4581. to--; // Remove end ','
  4582. }
  4583. *to=0;
  4584. }
  4585. void get_mqh(const char *user, const char *host, USER_CONN *uc)
  4586. {
  4587. ACL_USER *acl_user;
  4588. mysql_mutex_lock(&acl_cache->lock);
  4589. if (initialized && (acl_user= find_acl_user(host,user, FALSE)))
  4590. uc->user_resources= acl_user->user_resource;
  4591. else
  4592. bzero((char*) &uc->user_resources, sizeof(uc->user_resources));
  4593. mysql_mutex_unlock(&acl_cache->lock);
  4594. }
  4595. /*
  4596. Open the grant tables.
  4597. SYNOPSIS
  4598. open_grant_tables()
  4599. thd The current thread.
  4600. tables (out) The 4 elements array for the opened tables.
  4601. DESCRIPTION
  4602. Tables are numbered as follows:
  4603. 0 user
  4604. 1 db
  4605. 2 tables_priv
  4606. 3 columns_priv
  4607. RETURN
  4608. 1 Skip GRANT handling during replication.
  4609. 0 OK.
  4610. < 0 Error.
  4611. */
  4612. #define GRANT_TABLES 5
  4613. int open_grant_tables(THD *thd, TABLE_LIST *tables)
  4614. {
  4615. DBUG_ENTER("open_grant_tables");
  4616. if (!initialized)
  4617. {
  4618. my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--skip-grant-tables");
  4619. DBUG_RETURN(-1);
  4620. }
  4621. bzero((char*) tables, GRANT_TABLES*sizeof(*tables));
  4622. tables->alias= tables->table_name= (char*) "user";
  4623. (tables+1)->alias= (tables+1)->table_name= (char*) "db";
  4624. (tables+2)->alias= (tables+2)->table_name= (char*) "tables_priv";
  4625. (tables+3)->alias= (tables+3)->table_name= (char*) "columns_priv";
  4626. (tables+4)->alias= (tables+4)->table_name= (char*) "procs_priv";
  4627. tables->next_local= tables->next_global= tables+1;
  4628. (tables+1)->next_local= (tables+1)->next_global= tables+2;
  4629. (tables+2)->next_local= (tables+2)->next_global= tables+3;
  4630. (tables+3)->next_local= (tables+3)->next_global= tables+4;
  4631. tables->lock_type= (tables+1)->lock_type=
  4632. (tables+2)->lock_type= (tables+3)->lock_type=
  4633. (tables+4)->lock_type= TL_WRITE;
  4634. tables->db= (tables+1)->db= (tables+2)->db=
  4635. (tables+3)->db= (tables+4)->db= (char*) "mysql";
  4636. init_mdl_requests(tables);
  4637. #ifdef HAVE_REPLICATION
  4638. /*
  4639. GRANT and REVOKE are applied the slave in/exclusion rules as they are
  4640. some kind of updates to the mysql.% tables.
  4641. */
  4642. if (thd->slave_thread && rpl_filter->is_on())
  4643. {
  4644. /*
  4645. The tables must be marked "updating" so that tables_ok() takes them into
  4646. account in tests.
  4647. */
  4648. tables[0].updating=tables[1].updating=tables[2].updating=
  4649. tables[3].updating=tables[4].updating=1;
  4650. if (!(thd->spcont || rpl_filter->tables_ok(0, tables)))
  4651. DBUG_RETURN(1);
  4652. tables[0].updating=tables[1].updating=tables[2].updating=
  4653. tables[3].updating=tables[4].updating=0;;
  4654. }
  4655. #endif
  4656. if (open_and_lock_tables(thd, tables, FALSE, MYSQL_LOCK_IGNORE_TIMEOUT))
  4657. { // This should never happen
  4658. close_thread_tables(thd);
  4659. DBUG_RETURN(-1);
  4660. }
  4661. DBUG_RETURN(0);
  4662. }
  4663. ACL_USER *check_acl_user(LEX_USER *user_name,
  4664. uint *acl_acl_userdx)
  4665. {
  4666. ACL_USER *acl_user= 0;
  4667. uint counter;
  4668. mysql_mutex_assert_owner(&acl_cache->lock);
  4669. for (counter= 0 ; counter < acl_users.elements ; counter++)
  4670. {
  4671. const char *user,*host;
  4672. acl_user= dynamic_element(&acl_users, counter, ACL_USER*);
  4673. if (!(user=acl_user->user))
  4674. user= "";
  4675. if (!(host=acl_user->host.hostname))
  4676. host= "";
  4677. if (!strcmp(user_name->user.str,user) &&
  4678. !my_strcasecmp(system_charset_info, user_name->host.str, host))
  4679. break;
  4680. }
  4681. if (counter == acl_users.elements)
  4682. return 0;
  4683. *acl_acl_userdx= counter;
  4684. return acl_user;
  4685. }
  4686. /*
  4687. Modify a privilege table.
  4688. SYNOPSIS
  4689. modify_grant_table()
  4690. table The table to modify.
  4691. host_field The host name field.
  4692. user_field The user name field.
  4693. user_to The new name for the user if to be renamed,
  4694. NULL otherwise.
  4695. DESCRIPTION
  4696. Update user/host in the current record if user_to is not NULL.
  4697. Delete the current record if user_to is NULL.
  4698. RETURN
  4699. 0 OK.
  4700. != 0 Error.
  4701. */
  4702. static int modify_grant_table(TABLE *table, Field *host_field,
  4703. Field *user_field, LEX_USER *user_to)
  4704. {
  4705. int error;
  4706. DBUG_ENTER("modify_grant_table");
  4707. if (user_to)
  4708. {
  4709. /* rename */
  4710. store_record(table, record[1]);
  4711. host_field->store(user_to->host.str, user_to->host.length,
  4712. system_charset_info);
  4713. user_field->store(user_to->user.str, user_to->user.length,
  4714. system_charset_info);
  4715. if ((error= table->file->ha_update_row(table->record[1],
  4716. table->record[0])) &&
  4717. error != HA_ERR_RECORD_IS_THE_SAME)
  4718. table->file->print_error(error, MYF(0));
  4719. else
  4720. error= 0;
  4721. }
  4722. else
  4723. {
  4724. /* delete */
  4725. if ((error=table->file->ha_delete_row(table->record[0])))
  4726. table->file->print_error(error, MYF(0));
  4727. }
  4728. DBUG_RETURN(error);
  4729. }
  4730. /*
  4731. Handle a privilege table.
  4732. SYNOPSIS
  4733. handle_grant_table()
  4734. tables The array with the four open tables.
  4735. table_no The number of the table to handle (0..4).
  4736. drop If user_from is to be dropped.
  4737. user_from The the user to be searched/dropped/renamed.
  4738. user_to The new name for the user if to be renamed,
  4739. NULL otherwise.
  4740. DESCRIPTION
  4741. Scan through all records in a grant table and apply the requested
  4742. operation. For the "user" table, a single index access is sufficient,
  4743. since there is an unique index on (host, user).
  4744. Delete from grant table if drop is true.
  4745. Update in grant table if drop is false and user_to is not NULL.
  4746. Search in grant table if drop is false and user_to is NULL.
  4747. Tables are numbered as follows:
  4748. 0 user
  4749. 1 db
  4750. 2 tables_priv
  4751. 3 columns_priv
  4752. 4 procs_priv
  4753. RETURN
  4754. > 0 At least one record matched.
  4755. 0 OK, but no record matched.
  4756. < 0 Error.
  4757. */
  4758. static int handle_grant_table(TABLE_LIST *tables, uint table_no, bool drop,
  4759. LEX_USER *user_from, LEX_USER *user_to)
  4760. {
  4761. int result= 0;
  4762. int error;
  4763. TABLE *table= tables[table_no].table;
  4764. Field *host_field= table->field[0];
  4765. Field *user_field= table->field[table_no ? 2 : 1];
  4766. char *host_str= user_from->host.str;
  4767. char *user_str= user_from->user.str;
  4768. const char *host;
  4769. const char *user;
  4770. uchar user_key[MAX_KEY_LENGTH];
  4771. uint key_prefix_length;
  4772. DBUG_ENTER("handle_grant_table");
  4773. THD *thd= current_thd;
  4774. table->use_all_columns();
  4775. if (! table_no) // mysql.user table
  4776. {
  4777. /*
  4778. The 'user' table has an unique index on (host, user).
  4779. Thus, we can handle everything with a single index access.
  4780. The host- and user fields are consecutive in the user table records.
  4781. So we set host- and user fields of table->record[0] and use the
  4782. pointer to the host field as key.
  4783. index_read_idx() will replace table->record[0] (its first argument)
  4784. by the searched record, if it exists.
  4785. */
  4786. DBUG_PRINT("info",("read table: '%s' search: '%s'@'%s'",
  4787. table->s->table_name.str, user_str, host_str));
  4788. host_field->store(host_str, user_from->host.length, system_charset_info);
  4789. user_field->store(user_str, user_from->user.length, system_charset_info);
  4790. key_prefix_length= (table->key_info->key_part[0].store_length +
  4791. table->key_info->key_part[1].store_length);
  4792. key_copy(user_key, table->record[0], table->key_info, key_prefix_length);
  4793. if ((error= table->file->index_read_idx_map(table->record[0], 0,
  4794. user_key, (key_part_map)3,
  4795. HA_READ_KEY_EXACT)))
  4796. {
  4797. if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
  4798. {
  4799. table->file->print_error(error, MYF(0));
  4800. result= -1;
  4801. }
  4802. }
  4803. else
  4804. {
  4805. /* If requested, delete or update the record. */
  4806. result= ((drop || user_to) &&
  4807. modify_grant_table(table, host_field, user_field, user_to)) ?
  4808. -1 : 1; /* Error or found. */
  4809. }
  4810. DBUG_PRINT("info",("read result: %d", result));
  4811. }
  4812. else
  4813. {
  4814. /*
  4815. The non-'user' table do not have indexes on (host, user).
  4816. And their host- and user fields are not consecutive.
  4817. Thus, we need to do a table scan to find all matching records.
  4818. */
  4819. if ((error= table->file->ha_rnd_init(1)))
  4820. {
  4821. table->file->print_error(error, MYF(0));
  4822. result= -1;
  4823. }
  4824. else
  4825. {
  4826. #ifdef EXTRA_DEBUG
  4827. DBUG_PRINT("info",("scan table: '%s' search: '%s'@'%s'",
  4828. table->s->table_name.str, user_str, host_str));
  4829. #endif
  4830. while ((error= table->file->rnd_next(table->record[0])) !=
  4831. HA_ERR_END_OF_FILE)
  4832. {
  4833. if (error)
  4834. {
  4835. /* Most probable 'deleted record'. */
  4836. DBUG_PRINT("info",("scan error: %d", error));
  4837. continue;
  4838. }
  4839. if (! (host= get_field(thd->mem_root, host_field)))
  4840. host= "";
  4841. if (! (user= get_field(thd->mem_root, user_field)))
  4842. user= "";
  4843. #ifdef EXTRA_DEBUG
  4844. DBUG_PRINT("loop",("scan fields: '%s'@'%s' '%s' '%s' '%s'",
  4845. user, host,
  4846. get_field(thd->mem_root, table->field[1]) /*db*/,
  4847. get_field(thd->mem_root, table->field[3]) /*table*/,
  4848. get_field(thd->mem_root,
  4849. table->field[4]) /*column*/));
  4850. #endif
  4851. if (strcmp(user_str, user) ||
  4852. my_strcasecmp(system_charset_info, host_str, host))
  4853. continue;
  4854. /* If requested, delete or update the record. */
  4855. result= ((drop || user_to) &&
  4856. modify_grant_table(table, host_field, user_field, user_to)) ?
  4857. -1 : result ? result : 1; /* Error or keep result or found. */
  4858. /* If search is requested, we do not need to search further. */
  4859. if (! drop && ! user_to)
  4860. break ;
  4861. }
  4862. (void) table->file->ha_rnd_end();
  4863. DBUG_PRINT("info",("scan result: %d", result));
  4864. }
  4865. }
  4866. DBUG_RETURN(result);
  4867. }
  4868. /*
  4869. Handle an in-memory privilege structure.
  4870. SYNOPSIS
  4871. handle_grant_struct()
  4872. struct_no The number of the structure to handle (0..3).
  4873. drop If user_from is to be dropped.
  4874. user_from The the user to be searched/dropped/renamed.
  4875. user_to The new name for the user if to be renamed,
  4876. NULL otherwise.
  4877. DESCRIPTION
  4878. Scan through all elements in an in-memory grant structure and apply
  4879. the requested operation.
  4880. Delete from grant structure if drop is true.
  4881. Update in grant structure if drop is false and user_to is not NULL.
  4882. Search in grant structure if drop is false and user_to is NULL.
  4883. Structures are numbered as follows:
  4884. 0 acl_users
  4885. 1 acl_dbs
  4886. 2 column_priv_hash
  4887. 3 procs_priv_hash
  4888. RETURN
  4889. > 0 At least one element matched.
  4890. 0 OK, but no element matched.
  4891. -1 Wrong arguments to function
  4892. */
  4893. static int handle_grant_struct(uint struct_no, bool drop,
  4894. LEX_USER *user_from, LEX_USER *user_to)
  4895. {
  4896. int result= 0;
  4897. uint idx;
  4898. uint elements;
  4899. const char *user;
  4900. const char *host;
  4901. ACL_USER *acl_user= NULL;
  4902. ACL_DB *acl_db= NULL;
  4903. GRANT_NAME *grant_name= NULL;
  4904. DBUG_ENTER("handle_grant_struct");
  4905. DBUG_PRINT("info",("scan struct: %u search: '%s'@'%s'",
  4906. struct_no, user_from->user.str, user_from->host.str));
  4907. LINT_INIT(user);
  4908. LINT_INIT(host);
  4909. mysql_mutex_assert_owner(&acl_cache->lock);
  4910. /* Get the number of elements in the in-memory structure. */
  4911. switch (struct_no) {
  4912. case 0:
  4913. elements= acl_users.elements;
  4914. break;
  4915. case 1:
  4916. elements= acl_dbs.elements;
  4917. break;
  4918. case 2:
  4919. elements= column_priv_hash.records;
  4920. break;
  4921. case 3:
  4922. elements= proc_priv_hash.records;
  4923. break;
  4924. default:
  4925. return -1;
  4926. }
  4927. #ifdef EXTRA_DEBUG
  4928. DBUG_PRINT("loop",("scan struct: %u search user: '%s' host: '%s'",
  4929. struct_no, user_from->user.str, user_from->host.str));
  4930. #endif
  4931. /* Loop over all elements. */
  4932. for (idx= 0; idx < elements; idx++)
  4933. {
  4934. /*
  4935. Get a pointer to the element.
  4936. */
  4937. switch (struct_no) {
  4938. case 0:
  4939. acl_user= dynamic_element(&acl_users, idx, ACL_USER*);
  4940. user= acl_user->user;
  4941. host= acl_user->host.hostname;
  4942. break;
  4943. case 1:
  4944. acl_db= dynamic_element(&acl_dbs, idx, ACL_DB*);
  4945. user= acl_db->user;
  4946. host= acl_db->host.hostname;
  4947. break;
  4948. case 2:
  4949. grant_name= (GRANT_NAME*) my_hash_element(&column_priv_hash, idx);
  4950. user= grant_name->user;
  4951. host= grant_name->host.hostname;
  4952. break;
  4953. case 3:
  4954. grant_name= (GRANT_NAME*) my_hash_element(&proc_priv_hash, idx);
  4955. user= grant_name->user;
  4956. host= grant_name->host.hostname;
  4957. break;
  4958. default:
  4959. assert(0);
  4960. }
  4961. if (! user)
  4962. user= "";
  4963. if (! host)
  4964. host= "";
  4965. #ifdef EXTRA_DEBUG
  4966. DBUG_PRINT("loop",("scan struct: %u index: %u user: '%s' host: '%s'",
  4967. struct_no, idx, user, host));
  4968. #endif
  4969. if (strcmp(user_from->user.str, user) ||
  4970. my_strcasecmp(system_charset_info, user_from->host.str, host))
  4971. continue;
  4972. result= 1; /* At least one element found. */
  4973. if ( drop )
  4974. {
  4975. switch ( struct_no ) {
  4976. case 0:
  4977. delete_dynamic_element(&acl_users, idx);
  4978. break;
  4979. case 1:
  4980. delete_dynamic_element(&acl_dbs, idx);
  4981. break;
  4982. case 2:
  4983. my_hash_delete(&column_priv_hash, (uchar*) grant_name);
  4984. break;
  4985. case 3:
  4986. my_hash_delete(&proc_priv_hash, (uchar*) grant_name);
  4987. break;
  4988. }
  4989. elements--;
  4990. idx--;
  4991. }
  4992. else if ( user_to )
  4993. {
  4994. switch ( struct_no ) {
  4995. case 0:
  4996. acl_user->user= strdup_root(&mem, user_to->user.str);
  4997. acl_user->host.hostname= strdup_root(&mem, user_to->host.str);
  4998. break;
  4999. case 1:
  5000. acl_db->user= strdup_root(&mem, user_to->user.str);
  5001. acl_db->host.hostname= strdup_root(&mem, user_to->host.str);
  5002. break;
  5003. case 2:
  5004. case 3:
  5005. /*
  5006. Update the grant structure with the new user name and
  5007. host name
  5008. */
  5009. grant_name->set_user_details(user_to->host.str, grant_name->db,
  5010. user_to->user.str, grant_name->tname,
  5011. TRUE);
  5012. /*
  5013. Since username is part of the hash key, when the user name
  5014. is renamed, the hash key is changed. Update the hash to
  5015. ensure that the position matches the new hash key value
  5016. */
  5017. my_hash_update(&column_priv_hash, (uchar*) grant_name,
  5018. (uchar*) grant_name->hash_key, grant_name->key_length);
  5019. break;
  5020. }
  5021. }
  5022. else
  5023. {
  5024. /* If search is requested, we do not need to search further. */
  5025. break;
  5026. }
  5027. }
  5028. #ifdef EXTRA_DEBUG
  5029. DBUG_PRINT("loop",("scan struct: %u result %d", struct_no, result));
  5030. #endif
  5031. DBUG_RETURN(result);
  5032. }
  5033. /*
  5034. Handle all privilege tables and in-memory privilege structures.
  5035. SYNOPSIS
  5036. handle_grant_data()
  5037. tables The array with the four open tables.
  5038. drop If user_from is to be dropped.
  5039. user_from The the user to be searched/dropped/renamed.
  5040. user_to The new name for the user if to be renamed,
  5041. NULL otherwise.
  5042. DESCRIPTION
  5043. Go through all grant tables and in-memory grant structures and apply
  5044. the requested operation.
  5045. Delete from grant data if drop is true.
  5046. Update in grant data if drop is false and user_to is not NULL.
  5047. Search in grant data if drop is false and user_to is NULL.
  5048. RETURN
  5049. > 0 At least one element matched.
  5050. 0 OK, but no element matched.
  5051. < 0 Error.
  5052. */
  5053. static int handle_grant_data(TABLE_LIST *tables, bool drop,
  5054. LEX_USER *user_from, LEX_USER *user_to)
  5055. {
  5056. int result= 0;
  5057. int found;
  5058. DBUG_ENTER("handle_grant_data");
  5059. /* Handle user table. */
  5060. if ((found= handle_grant_table(tables, 0, drop, user_from, user_to)) < 0)
  5061. {
  5062. /* Handle of table failed, don't touch the in-memory array. */
  5063. result= -1;
  5064. }
  5065. else
  5066. {
  5067. /* Handle user array. */
  5068. if ((handle_grant_struct(0, drop, user_from, user_to) && ! result) ||
  5069. found)
  5070. {
  5071. result= 1; /* At least one record/element found. */
  5072. /* If search is requested, we do not need to search further. */
  5073. if (! drop && ! user_to)
  5074. goto end;
  5075. }
  5076. }
  5077. /* Handle db table. */
  5078. if ((found= handle_grant_table(tables, 1, drop, user_from, user_to)) < 0)
  5079. {
  5080. /* Handle of table failed, don't touch the in-memory array. */
  5081. result= -1;
  5082. }
  5083. else
  5084. {
  5085. /* Handle db array. */
  5086. if (((handle_grant_struct(1, drop, user_from, user_to) && ! result) ||
  5087. found) && ! result)
  5088. {
  5089. result= 1; /* At least one record/element found. */
  5090. /* If search is requested, we do not need to search further. */
  5091. if (! drop && ! user_to)
  5092. goto end;
  5093. }
  5094. }
  5095. /* Handle procedures table. */
  5096. if ((found= handle_grant_table(tables, 4, drop, user_from, user_to)) < 0)
  5097. {
  5098. /* Handle of table failed, don't touch in-memory array. */
  5099. result= -1;
  5100. }
  5101. else
  5102. {
  5103. /* Handle procs array. */
  5104. if (((handle_grant_struct(3, drop, user_from, user_to) && ! result) ||
  5105. found) && ! result)
  5106. {
  5107. result= 1; /* At least one record/element found. */
  5108. /* If search is requested, we do not need to search further. */
  5109. if (! drop && ! user_to)
  5110. goto end;
  5111. }
  5112. }
  5113. /* Handle tables table. */
  5114. if ((found= handle_grant_table(tables, 2, drop, user_from, user_to)) < 0)
  5115. {
  5116. /* Handle of table failed, don't touch columns and in-memory array. */
  5117. result= -1;
  5118. }
  5119. else
  5120. {
  5121. if (found && ! result)
  5122. {
  5123. result= 1; /* At least one record found. */
  5124. /* If search is requested, we do not need to search further. */
  5125. if (! drop && ! user_to)
  5126. goto end;
  5127. }
  5128. /* Handle columns table. */
  5129. if ((found= handle_grant_table(tables, 3, drop, user_from, user_to)) < 0)
  5130. {
  5131. /* Handle of table failed, don't touch the in-memory array. */
  5132. result= -1;
  5133. }
  5134. else
  5135. {
  5136. /* Handle columns hash. */
  5137. if (((handle_grant_struct(2, drop, user_from, user_to) && ! result) ||
  5138. found) && ! result)
  5139. result= 1; /* At least one record/element found. */
  5140. }
  5141. }
  5142. end:
  5143. DBUG_RETURN(result);
  5144. }
  5145. static void append_user(String *str, LEX_USER *user)
  5146. {
  5147. if (str->length())
  5148. str->append(',');
  5149. str->append('\'');
  5150. str->append(user->user.str);
  5151. str->append(STRING_WITH_LEN("'@'"));
  5152. str->append(user->host.str);
  5153. str->append('\'');
  5154. }
  5155. /*
  5156. Create a list of users.
  5157. SYNOPSIS
  5158. mysql_create_user()
  5159. thd The current thread.
  5160. list The users to create.
  5161. RETURN
  5162. FALSE OK.
  5163. TRUE Error.
  5164. */
  5165. bool mysql_create_user(THD *thd, List <LEX_USER> &list)
  5166. {
  5167. int result;
  5168. String wrong_users;
  5169. ulong sql_mode;
  5170. LEX_USER *user_name, *tmp_user_name;
  5171. List_iterator <LEX_USER> user_list(list);
  5172. TABLE_LIST tables[GRANT_TABLES];
  5173. bool some_users_created= FALSE;
  5174. bool save_binlog_row_based;
  5175. DBUG_ENTER("mysql_create_user");
  5176. /*
  5177. This statement will be replicated as a statement, even when using
  5178. row-based replication. The flag will be reset at the end of the
  5179. statement.
  5180. */
  5181. if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
  5182. thd->clear_current_stmt_binlog_format_row();
  5183. /* CREATE USER may be skipped on replication client. */
  5184. if ((result= open_grant_tables(thd, tables)))
  5185. {
  5186. /* Restore the state of binlog format */
  5187. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5188. if (save_binlog_row_based)
  5189. thd->set_current_stmt_binlog_format_row();
  5190. DBUG_RETURN(result != 1);
  5191. }
  5192. mysql_rwlock_wrlock(&LOCK_grant);
  5193. mysql_mutex_lock(&acl_cache->lock);
  5194. while ((tmp_user_name= user_list++))
  5195. {
  5196. if (!(user_name= get_current_user(thd, tmp_user_name)))
  5197. {
  5198. result= TRUE;
  5199. continue;
  5200. }
  5201. /*
  5202. Search all in-memory structures and grant tables
  5203. for a mention of the new user name.
  5204. */
  5205. if (handle_grant_data(tables, 0, user_name, NULL))
  5206. {
  5207. append_user(&wrong_users, user_name);
  5208. result= TRUE;
  5209. continue;
  5210. }
  5211. some_users_created= TRUE;
  5212. sql_mode= thd->variables.sql_mode;
  5213. if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0))
  5214. {
  5215. append_user(&wrong_users, user_name);
  5216. result= TRUE;
  5217. }
  5218. }
  5219. mysql_mutex_unlock(&acl_cache->lock);
  5220. if (result)
  5221. my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
  5222. if (some_users_created)
  5223. result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
  5224. mysql_rwlock_unlock(&LOCK_grant);
  5225. close_thread_tables(thd);
  5226. /* Restore the state of binlog format */
  5227. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5228. if (save_binlog_row_based)
  5229. thd->set_current_stmt_binlog_format_row();
  5230. DBUG_RETURN(result);
  5231. }
  5232. /*
  5233. Drop a list of users and all their privileges.
  5234. SYNOPSIS
  5235. mysql_drop_user()
  5236. thd The current thread.
  5237. list The users to drop.
  5238. RETURN
  5239. FALSE OK.
  5240. TRUE Error.
  5241. */
  5242. bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
  5243. {
  5244. int result;
  5245. String wrong_users;
  5246. LEX_USER *user_name, *tmp_user_name;
  5247. List_iterator <LEX_USER> user_list(list);
  5248. TABLE_LIST tables[GRANT_TABLES];
  5249. bool some_users_deleted= FALSE;
  5250. ulong old_sql_mode= thd->variables.sql_mode;
  5251. bool save_binlog_row_based;
  5252. DBUG_ENTER("mysql_drop_user");
  5253. /*
  5254. This statement will be replicated as a statement, even when using
  5255. row-based replication. The flag will be reset at the end of the
  5256. statement.
  5257. */
  5258. if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
  5259. thd->clear_current_stmt_binlog_format_row();
  5260. /* DROP USER may be skipped on replication client. */
  5261. if ((result= open_grant_tables(thd, tables)))
  5262. {
  5263. /* Restore the state of binlog format */
  5264. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5265. if (save_binlog_row_based)
  5266. thd->set_current_stmt_binlog_format_row();
  5267. DBUG_RETURN(result != 1);
  5268. }
  5269. thd->variables.sql_mode&= ~MODE_PAD_CHAR_TO_FULL_LENGTH;
  5270. mysql_rwlock_wrlock(&LOCK_grant);
  5271. mysql_mutex_lock(&acl_cache->lock);
  5272. while ((tmp_user_name= user_list++))
  5273. {
  5274. if (!(user_name= get_current_user(thd, tmp_user_name)))
  5275. {
  5276. result= TRUE;
  5277. continue;
  5278. }
  5279. if (handle_grant_data(tables, 1, user_name, NULL) <= 0)
  5280. {
  5281. append_user(&wrong_users, user_name);
  5282. result= TRUE;
  5283. continue;
  5284. }
  5285. some_users_deleted= TRUE;
  5286. }
  5287. /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
  5288. rebuild_check_host();
  5289. mysql_mutex_unlock(&acl_cache->lock);
  5290. if (result)
  5291. my_error(ER_CANNOT_USER, MYF(0), "DROP USER", wrong_users.c_ptr_safe());
  5292. if (some_users_deleted)
  5293. result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
  5294. mysql_rwlock_unlock(&LOCK_grant);
  5295. close_thread_tables(thd);
  5296. thd->variables.sql_mode= old_sql_mode;
  5297. /* Restore the state of binlog format */
  5298. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5299. if (save_binlog_row_based)
  5300. thd->set_current_stmt_binlog_format_row();
  5301. DBUG_RETURN(result);
  5302. }
  5303. /*
  5304. Rename a user.
  5305. SYNOPSIS
  5306. mysql_rename_user()
  5307. thd The current thread.
  5308. list The user name pairs: (from, to).
  5309. RETURN
  5310. FALSE OK.
  5311. TRUE Error.
  5312. */
  5313. bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
  5314. {
  5315. int result;
  5316. String wrong_users;
  5317. LEX_USER *user_from, *tmp_user_from;
  5318. LEX_USER *user_to, *tmp_user_to;
  5319. List_iterator <LEX_USER> user_list(list);
  5320. TABLE_LIST tables[GRANT_TABLES];
  5321. bool some_users_renamed= FALSE;
  5322. bool save_binlog_row_based;
  5323. DBUG_ENTER("mysql_rename_user");
  5324. /*
  5325. This statement will be replicated as a statement, even when using
  5326. row-based replication. The flag will be reset at the end of the
  5327. statement.
  5328. */
  5329. if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
  5330. thd->clear_current_stmt_binlog_format_row();
  5331. /* RENAME USER may be skipped on replication client. */
  5332. if ((result= open_grant_tables(thd, tables)))
  5333. {
  5334. /* Restore the state of binlog format */
  5335. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5336. if (save_binlog_row_based)
  5337. thd->set_current_stmt_binlog_format_row();
  5338. DBUG_RETURN(result != 1);
  5339. }
  5340. mysql_rwlock_wrlock(&LOCK_grant);
  5341. mysql_mutex_lock(&acl_cache->lock);
  5342. while ((tmp_user_from= user_list++))
  5343. {
  5344. if (!(user_from= get_current_user(thd, tmp_user_from)))
  5345. {
  5346. result= TRUE;
  5347. continue;
  5348. }
  5349. tmp_user_to= user_list++;
  5350. if (!(user_to= get_current_user(thd, tmp_user_to)))
  5351. {
  5352. result= TRUE;
  5353. continue;
  5354. }
  5355. DBUG_ASSERT(user_to != 0); /* Syntax enforces pairs of users. */
  5356. /*
  5357. Search all in-memory structures and grant tables
  5358. for a mention of the new user name.
  5359. */
  5360. if (handle_grant_data(tables, 0, user_to, NULL) ||
  5361. handle_grant_data(tables, 0, user_from, user_to) <= 0)
  5362. {
  5363. append_user(&wrong_users, user_from);
  5364. result= TRUE;
  5365. continue;
  5366. }
  5367. some_users_renamed= TRUE;
  5368. }
  5369. /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
  5370. rebuild_check_host();
  5371. mysql_mutex_unlock(&acl_cache->lock);
  5372. if (result)
  5373. my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
  5374. if (some_users_renamed && mysql_bin_log.is_open())
  5375. result |= write_bin_log(thd, FALSE, thd->query(), thd->query_length());
  5376. mysql_rwlock_unlock(&LOCK_grant);
  5377. close_thread_tables(thd);
  5378. /* Restore the state of binlog format */
  5379. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5380. if (save_binlog_row_based)
  5381. thd->set_current_stmt_binlog_format_row();
  5382. DBUG_RETURN(result);
  5383. }
  5384. /*
  5385. Revoke all privileges from a list of users.
  5386. SYNOPSIS
  5387. mysql_revoke_all()
  5388. thd The current thread.
  5389. list The users to revoke all privileges from.
  5390. RETURN
  5391. > 0 Error. Error message already sent.
  5392. 0 OK.
  5393. < 0 Error. Error message not yet sent.
  5394. */
  5395. bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
  5396. {
  5397. uint counter, revoked, is_proc;
  5398. int result;
  5399. ACL_DB *acl_db;
  5400. TABLE_LIST tables[GRANT_TABLES];
  5401. bool save_binlog_row_based;
  5402. DBUG_ENTER("mysql_revoke_all");
  5403. /*
  5404. This statement will be replicated as a statement, even when using
  5405. row-based replication. The flag will be reset at the end of the
  5406. statement.
  5407. */
  5408. if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
  5409. thd->clear_current_stmt_binlog_format_row();
  5410. if ((result= open_grant_tables(thd, tables)))
  5411. {
  5412. /* Restore the state of binlog format */
  5413. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5414. if (save_binlog_row_based)
  5415. thd->set_current_stmt_binlog_format_row();
  5416. DBUG_RETURN(result != 1);
  5417. }
  5418. mysql_rwlock_wrlock(&LOCK_grant);
  5419. mysql_mutex_lock(&acl_cache->lock);
  5420. LEX_USER *lex_user, *tmp_lex_user;
  5421. List_iterator <LEX_USER> user_list(list);
  5422. while ((tmp_lex_user= user_list++))
  5423. {
  5424. if (!(lex_user= get_current_user(thd, tmp_lex_user)))
  5425. {
  5426. result= -1;
  5427. continue;
  5428. }
  5429. if (!find_acl_user(lex_user->host.str, lex_user->user.str, TRUE))
  5430. {
  5431. result= -1;
  5432. continue;
  5433. }
  5434. if (replace_user_table(thd, tables[0].table,
  5435. *lex_user, ~(ulong)0, 1, 0, 0))
  5436. {
  5437. result= -1;
  5438. continue;
  5439. }
  5440. /* Remove db access privileges */
  5441. /*
  5442. Because acl_dbs and column_priv_hash shrink and may re-order
  5443. as privileges are removed, removal occurs in a repeated loop
  5444. until no more privileges are revoked.
  5445. */
  5446. do
  5447. {
  5448. for (counter= 0, revoked= 0 ; counter < acl_dbs.elements ; )
  5449. {
  5450. const char *user,*host;
  5451. acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
  5452. if (!(user=acl_db->user))
  5453. user= "";
  5454. if (!(host=acl_db->host.hostname))
  5455. host= "";
  5456. if (!strcmp(lex_user->user.str,user) &&
  5457. !strcmp(lex_user->host.str, host))
  5458. {
  5459. if (!replace_db_table(tables[1].table, acl_db->db, *lex_user,
  5460. ~(ulong)0, 1))
  5461. {
  5462. /*
  5463. Don't increment counter as replace_db_table deleted the
  5464. current element in acl_dbs.
  5465. */
  5466. revoked= 1;
  5467. continue;
  5468. }
  5469. result= -1; // Something went wrong
  5470. }
  5471. counter++;
  5472. }
  5473. } while (revoked);
  5474. /* Remove column access */
  5475. do
  5476. {
  5477. for (counter= 0, revoked= 0 ; counter < column_priv_hash.records ; )
  5478. {
  5479. const char *user,*host;
  5480. GRANT_TABLE *grant_table=
  5481. (GRANT_TABLE*) my_hash_element(&column_priv_hash, counter);
  5482. if (!(user=grant_table->user))
  5483. user= "";
  5484. if (!(host=grant_table->host.hostname))
  5485. host= "";
  5486. if (!strcmp(lex_user->user.str,user) &&
  5487. !strcmp(lex_user->host.str, host))
  5488. {
  5489. if (replace_table_table(thd,grant_table,tables[2].table,*lex_user,
  5490. grant_table->db,
  5491. grant_table->tname,
  5492. ~(ulong)0, 0, 1))
  5493. {
  5494. result= -1;
  5495. }
  5496. else
  5497. {
  5498. if (!grant_table->cols)
  5499. {
  5500. revoked= 1;
  5501. continue;
  5502. }
  5503. List<LEX_COLUMN> columns;
  5504. if (!replace_column_table(grant_table,tables[3].table, *lex_user,
  5505. columns,
  5506. grant_table->db,
  5507. grant_table->tname,
  5508. ~(ulong)0, 1))
  5509. {
  5510. revoked= 1;
  5511. continue;
  5512. }
  5513. result= -1;
  5514. }
  5515. }
  5516. counter++;
  5517. }
  5518. } while (revoked);
  5519. /* Remove procedure access */
  5520. for (is_proc=0; is_proc<2; is_proc++) do {
  5521. HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
  5522. for (counter= 0, revoked= 0 ; counter < hash->records ; )
  5523. {
  5524. const char *user,*host;
  5525. GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
  5526. if (!(user=grant_proc->user))
  5527. user= "";
  5528. if (!(host=grant_proc->host.hostname))
  5529. host= "";
  5530. if (!strcmp(lex_user->user.str,user) &&
  5531. !strcmp(lex_user->host.str, host))
  5532. {
  5533. if (replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
  5534. grant_proc->db,
  5535. grant_proc->tname,
  5536. is_proc,
  5537. ~(ulong)0, 1) == 0)
  5538. {
  5539. revoked= 1;
  5540. continue;
  5541. }
  5542. result= -1; // Something went wrong
  5543. }
  5544. counter++;
  5545. }
  5546. } while (revoked);
  5547. }
  5548. mysql_mutex_unlock(&acl_cache->lock);
  5549. int binlog_error=
  5550. write_bin_log(thd, FALSE, thd->query(), thd->query_length());
  5551. mysql_rwlock_unlock(&LOCK_grant);
  5552. close_thread_tables(thd);
  5553. /* error for writing binary log has already been reported */
  5554. if (result && !binlog_error)
  5555. my_message(ER_REVOKE_GRANTS, ER(ER_REVOKE_GRANTS), MYF(0));
  5556. /* Restore the state of binlog format */
  5557. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5558. if (save_binlog_row_based)
  5559. thd->set_current_stmt_binlog_format_row();
  5560. DBUG_RETURN(result || binlog_error);
  5561. }
  5562. /**
  5563. If the defining user for a routine does not exist, then the ACL lookup
  5564. code should raise two errors which we should intercept. We convert the more
  5565. descriptive error into a warning, and consume the other.
  5566. If any other errors are raised, then we set a flag that should indicate
  5567. that there was some failure we should complain at a higher level.
  5568. */
  5569. class Silence_routine_definer_errors : public Internal_error_handler
  5570. {
  5571. public:
  5572. Silence_routine_definer_errors()
  5573. : is_grave(FALSE)
  5574. {}
  5575. virtual ~Silence_routine_definer_errors()
  5576. {}
  5577. virtual bool handle_condition(THD *thd,
  5578. uint sql_errno,
  5579. const char* sqlstate,
  5580. MYSQL_ERROR::enum_warning_level level,
  5581. const char* msg,
  5582. MYSQL_ERROR ** cond_hdl);
  5583. bool has_errors() { return is_grave; }
  5584. private:
  5585. bool is_grave;
  5586. };
  5587. bool
  5588. Silence_routine_definer_errors::handle_condition(
  5589. THD *thd,
  5590. uint sql_errno,
  5591. const char*,
  5592. MYSQL_ERROR::enum_warning_level level,
  5593. const char* msg,
  5594. MYSQL_ERROR ** cond_hdl)
  5595. {
  5596. *cond_hdl= NULL;
  5597. if (level == MYSQL_ERROR::WARN_LEVEL_ERROR)
  5598. {
  5599. switch (sql_errno)
  5600. {
  5601. case ER_NONEXISTING_PROC_GRANT:
  5602. /* Convert the error into a warning. */
  5603. push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
  5604. sql_errno, msg);
  5605. return TRUE;
  5606. default:
  5607. is_grave= TRUE;
  5608. }
  5609. }
  5610. return FALSE;
  5611. }
  5612. /**
  5613. Revoke privileges for all users on a stored procedure. Use an error handler
  5614. that converts errors about missing grants into warnings.
  5615. @param
  5616. thd The current thread.
  5617. @param
  5618. db DB of the stored procedure
  5619. @param
  5620. name Name of the stored procedure
  5621. @retval
  5622. 0 OK.
  5623. @retval
  5624. < 0 Error. Error message not yet sent.
  5625. */
  5626. bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
  5627. bool is_proc)
  5628. {
  5629. uint counter, revoked;
  5630. int result;
  5631. TABLE_LIST tables[GRANT_TABLES];
  5632. HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
  5633. Silence_routine_definer_errors error_handler;
  5634. bool save_binlog_row_based;
  5635. DBUG_ENTER("sp_revoke_privileges");
  5636. if ((result= open_grant_tables(thd, tables)))
  5637. DBUG_RETURN(result != 1);
  5638. /* Be sure to pop this before exiting this scope! */
  5639. thd->push_internal_handler(&error_handler);
  5640. mysql_rwlock_wrlock(&LOCK_grant);
  5641. mysql_mutex_lock(&acl_cache->lock);
  5642. /*
  5643. This statement will be replicated as a statement, even when using
  5644. row-based replication. The flag will be reset at the end of the
  5645. statement.
  5646. */
  5647. if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
  5648. thd->clear_current_stmt_binlog_format_row();
  5649. /* Remove procedure access */
  5650. do
  5651. {
  5652. for (counter= 0, revoked= 0 ; counter < hash->records ; )
  5653. {
  5654. GRANT_NAME *grant_proc= (GRANT_NAME*) my_hash_element(hash, counter);
  5655. if (!my_strcasecmp(&my_charset_utf8_bin, grant_proc->db, sp_db) &&
  5656. !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
  5657. {
  5658. LEX_USER lex_user;
  5659. lex_user.user.str= grant_proc->user;
  5660. lex_user.user.length= strlen(grant_proc->user);
  5661. lex_user.host.str= grant_proc->host.hostname ?
  5662. grant_proc->host.hostname : (char*)"";
  5663. lex_user.host.length= grant_proc->host.hostname ?
  5664. strlen(grant_proc->host.hostname) : 0;
  5665. if (replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
  5666. grant_proc->db, grant_proc->tname,
  5667. is_proc, ~(ulong)0, 1) == 0)
  5668. {
  5669. revoked= 1;
  5670. continue;
  5671. }
  5672. }
  5673. counter++;
  5674. }
  5675. } while (revoked);
  5676. mysql_mutex_unlock(&acl_cache->lock);
  5677. mysql_rwlock_unlock(&LOCK_grant);
  5678. close_thread_tables(thd);
  5679. thd->pop_internal_handler();
  5680. /* Restore the state of binlog format */
  5681. DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
  5682. if (save_binlog_row_based)
  5683. thd->set_current_stmt_binlog_format_row();
  5684. DBUG_RETURN(error_handler.has_errors());
  5685. }
  5686. /**
  5687. Grant EXECUTE,ALTER privilege for a stored procedure
  5688. @param thd The current thread.
  5689. @param sp_db
  5690. @param sp_name
  5691. @param is_proc
  5692. @return
  5693. @retval FALSE Success
  5694. @retval TRUE An error occured. Error message not yet sent.
  5695. */
  5696. bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
  5697. bool is_proc)
  5698. {
  5699. Security_context *sctx= thd->security_ctx;
  5700. LEX_USER *combo;
  5701. TABLE_LIST tables[1];
  5702. List<LEX_USER> user_list;
  5703. bool result;
  5704. ACL_USER *au;
  5705. char passwd_buff[SCRAMBLED_PASSWORD_CHAR_LENGTH+1];
  5706. Dummy_error_handler error_handler;
  5707. DBUG_ENTER("sp_grant_privileges");
  5708. if (!(combo=(LEX_USER*) thd->alloc(sizeof(st_lex_user))))
  5709. DBUG_RETURN(TRUE);
  5710. combo->user.str= sctx->user;
  5711. mysql_mutex_lock(&acl_cache->lock);
  5712. if ((au= find_acl_user(combo->host.str=(char*)sctx->host_or_ip,combo->user.str,FALSE)))
  5713. goto found_acl;
  5714. if ((au= find_acl_user(combo->host.str=(char*)sctx->host, combo->user.str,FALSE)))
  5715. goto found_acl;
  5716. if ((au= find_acl_user(combo->host.str=(char*)sctx->ip, combo->user.str,FALSE)))
  5717. goto found_acl;
  5718. if((au= find_acl_user(combo->host.str=(char*)"%", combo->user.str, FALSE)))
  5719. goto found_acl;
  5720. mysql_mutex_unlock(&acl_cache->lock);
  5721. DBUG_RETURN(TRUE);
  5722. found_acl:
  5723. mysql_mutex_unlock(&acl_cache->lock);
  5724. bzero((char*)tables, sizeof(TABLE_LIST));
  5725. user_list.empty();
  5726. tables->db= (char*)sp_db;
  5727. tables->table_name= tables->alias= (char*)sp_name;
  5728. combo->host.length= strlen(combo->host.str);
  5729. combo->user.length= strlen(combo->user.str);
  5730. combo->host.str= thd->strmake(combo->host.str,combo->host.length);
  5731. combo->user.str= thd->strmake(combo->user.str,combo->user.length);
  5732. if(au && au->salt_len)
  5733. {
  5734. if (au->salt_len == SCRAMBLE_LENGTH)
  5735. {
  5736. make_password_from_salt(passwd_buff, au->salt);
  5737. combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH;
  5738. }
  5739. else if (au->salt_len == SCRAMBLE_LENGTH_323)
  5740. {
  5741. make_password_from_salt_323(passwd_buff, (ulong *) au->salt);
  5742. combo->password.length= SCRAMBLED_PASSWORD_CHAR_LENGTH_323;
  5743. }
  5744. else
  5745. {
  5746. push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
  5747. ER_PASSWD_LENGTH,
  5748. ER(ER_PASSWD_LENGTH),
  5749. SCRAMBLED_PASSWORD_CHAR_LENGTH);
  5750. return TRUE;
  5751. }
  5752. combo->password.str= passwd_buff;
  5753. }
  5754. else
  5755. {
  5756. combo->password.str= (char*)"";
  5757. combo->password.length= 0;
  5758. }
  5759. if (user_list.push_back(combo))
  5760. DBUG_RETURN(TRUE);
  5761. thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
  5762. thd->lex->ssl_cipher= thd->lex->x509_subject= thd->lex->x509_issuer= 0;
  5763. bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh));
  5764. /*
  5765. Only care about whether the operation failed or succeeded
  5766. as all errors will be handled later.
  5767. */
  5768. thd->push_internal_handler(&error_handler);
  5769. result= mysql_routine_grant(thd, tables, is_proc, user_list,
  5770. DEFAULT_CREATE_PROC_ACLS, FALSE, FALSE);
  5771. thd->pop_internal_handler();
  5772. DBUG_RETURN(result);
  5773. }
  5774. /*****************************************************************************
  5775. Instantiate used templates
  5776. *****************************************************************************/
  5777. #ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
  5778. template class List_iterator<LEX_COLUMN>;
  5779. template class List_iterator<LEX_USER>;
  5780. template class List<LEX_COLUMN>;
  5781. template class List<LEX_USER>;
  5782. #endif
  5783. #endif /*NO_EMBEDDED_ACCESS_CHECKS */
  5784. int wild_case_compare(CHARSET_INFO *cs, const char *str,const char *wildstr)
  5785. {
  5786. reg3 int flag;
  5787. DBUG_ENTER("wild_case_compare");
  5788. DBUG_PRINT("enter",("str: '%s' wildstr: '%s'",str,wildstr));
  5789. while (*wildstr)
  5790. {
  5791. while (*wildstr && *wildstr != wild_many && *wildstr != wild_one)
  5792. {
  5793. if (*wildstr == wild_prefix && wildstr[1])
  5794. wildstr++;
  5795. if (my_toupper(cs, *wildstr++) !=
  5796. my_toupper(cs, *str++)) DBUG_RETURN(1);
  5797. }
  5798. if (! *wildstr ) DBUG_RETURN (*str != 0);
  5799. if (*wildstr++ == wild_one)
  5800. {
  5801. if (! *str++) DBUG_RETURN (1); /* One char; skip */
  5802. }
  5803. else
  5804. { /* Found '*' */
  5805. if (!*wildstr) DBUG_RETURN(0); /* '*' as last char: OK */
  5806. flag=(*wildstr != wild_many && *wildstr != wild_one);
  5807. do
  5808. {
  5809. if (flag)
  5810. {
  5811. char cmp;
  5812. if ((cmp= *wildstr) == wild_prefix && wildstr[1])
  5813. cmp=wildstr[1];
  5814. cmp=my_toupper(cs, cmp);
  5815. while (*str && my_toupper(cs, *str) != cmp)
  5816. str++;
  5817. if (!*str) DBUG_RETURN (1);
  5818. }
  5819. if (wild_case_compare(cs, str,wildstr) == 0) DBUG_RETURN (0);
  5820. } while (*str++);
  5821. DBUG_RETURN(1);
  5822. }
  5823. }
  5824. DBUG_RETURN (*str != '\0');
  5825. }
  5826. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  5827. static bool update_schema_privilege(THD *thd, TABLE *table, char *buff,
  5828. const char* db, const char* t_name,
  5829. const char* column, uint col_length,
  5830. const char *priv, uint priv_length,
  5831. const char* is_grantable)
  5832. {
  5833. int i= 2;
  5834. CHARSET_INFO *cs= system_charset_info;
  5835. restore_record(table, s->default_values);
  5836. table->field[0]->store(buff, (uint) strlen(buff), cs);
  5837. table->field[1]->store(STRING_WITH_LEN("def"), cs);
  5838. if (db)
  5839. table->field[i++]->store(db, (uint) strlen(db), cs);
  5840. if (t_name)
  5841. table->field[i++]->store(t_name, (uint) strlen(t_name), cs);
  5842. if (column)
  5843. table->field[i++]->store(column, col_length, cs);
  5844. table->field[i++]->store(priv, priv_length, cs);
  5845. table->field[i]->store(is_grantable, strlen(is_grantable), cs);
  5846. return schema_table_store_record(thd, table);
  5847. }
  5848. #endif
  5849. int fill_schema_user_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
  5850. {
  5851. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  5852. int error= 0;
  5853. uint counter;
  5854. ACL_USER *acl_user;
  5855. ulong want_access;
  5856. char buff[100];
  5857. TABLE *table= tables->table;
  5858. bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
  5859. NULL, NULL, 1, 1);
  5860. char *curr_host= thd->security_ctx->priv_host_name();
  5861. DBUG_ENTER("fill_schema_user_privileges");
  5862. if (!initialized)
  5863. DBUG_RETURN(0);
  5864. mysql_mutex_lock(&acl_cache->lock);
  5865. for (counter=0 ; counter < acl_users.elements ; counter++)
  5866. {
  5867. const char *user,*host, *is_grantable="YES";
  5868. acl_user=dynamic_element(&acl_users,counter,ACL_USER*);
  5869. if (!(user=acl_user->user))
  5870. user= "";
  5871. if (!(host=acl_user->host.hostname))
  5872. host= "";
  5873. if (no_global_access &&
  5874. (strcmp(thd->security_ctx->priv_user, user) ||
  5875. my_strcasecmp(system_charset_info, curr_host, host)))
  5876. continue;
  5877. want_access= acl_user->access;
  5878. if (!(want_access & GRANT_ACL))
  5879. is_grantable= "NO";
  5880. strxmov(buff,"'",user,"'@'",host,"'",NullS);
  5881. if (!(want_access & ~GRANT_ACL))
  5882. {
  5883. if (update_schema_privilege(thd, table, buff, 0, 0, 0, 0,
  5884. STRING_WITH_LEN("USAGE"), is_grantable))
  5885. {
  5886. error= 1;
  5887. goto err;
  5888. }
  5889. }
  5890. else
  5891. {
  5892. uint priv_id;
  5893. ulong j,test_access= want_access & ~GRANT_ACL;
  5894. for (priv_id=0, j = SELECT_ACL;j <= GLOBAL_ACLS; priv_id++,j <<= 1)
  5895. {
  5896. if (test_access & j)
  5897. {
  5898. if (update_schema_privilege(thd, table, buff, 0, 0, 0, 0,
  5899. command_array[priv_id],
  5900. command_lengths[priv_id], is_grantable))
  5901. {
  5902. error= 1;
  5903. goto err;
  5904. }
  5905. }
  5906. }
  5907. }
  5908. }
  5909. err:
  5910. mysql_mutex_unlock(&acl_cache->lock);
  5911. DBUG_RETURN(error);
  5912. #else
  5913. return(0);
  5914. #endif
  5915. }
  5916. int fill_schema_schema_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
  5917. {
  5918. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  5919. int error= 0;
  5920. uint counter;
  5921. ACL_DB *acl_db;
  5922. ulong want_access;
  5923. char buff[100];
  5924. TABLE *table= tables->table;
  5925. bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
  5926. NULL, NULL, 1, 1);
  5927. char *curr_host= thd->security_ctx->priv_host_name();
  5928. DBUG_ENTER("fill_schema_schema_privileges");
  5929. if (!initialized)
  5930. DBUG_RETURN(0);
  5931. mysql_mutex_lock(&acl_cache->lock);
  5932. for (counter=0 ; counter < acl_dbs.elements ; counter++)
  5933. {
  5934. const char *user, *host, *is_grantable="YES";
  5935. acl_db=dynamic_element(&acl_dbs,counter,ACL_DB*);
  5936. if (!(user=acl_db->user))
  5937. user= "";
  5938. if (!(host=acl_db->host.hostname))
  5939. host= "";
  5940. if (no_global_access &&
  5941. (strcmp(thd->security_ctx->priv_user, user) ||
  5942. my_strcasecmp(system_charset_info, curr_host, host)))
  5943. continue;
  5944. want_access=acl_db->access;
  5945. if (want_access)
  5946. {
  5947. if (!(want_access & GRANT_ACL))
  5948. {
  5949. is_grantable= "NO";
  5950. }
  5951. strxmov(buff,"'",user,"'@'",host,"'",NullS);
  5952. if (!(want_access & ~GRANT_ACL))
  5953. {
  5954. if (update_schema_privilege(thd, table, buff, acl_db->db, 0, 0,
  5955. 0, STRING_WITH_LEN("USAGE"), is_grantable))
  5956. {
  5957. error= 1;
  5958. goto err;
  5959. }
  5960. }
  5961. else
  5962. {
  5963. int cnt;
  5964. ulong j,test_access= want_access & ~GRANT_ACL;
  5965. for (cnt=0, j = SELECT_ACL; j <= DB_ACLS; cnt++,j <<= 1)
  5966. if (test_access & j)
  5967. {
  5968. if (update_schema_privilege(thd, table, buff, acl_db->db, 0, 0, 0,
  5969. command_array[cnt], command_lengths[cnt],
  5970. is_grantable))
  5971. {
  5972. error= 1;
  5973. goto err;
  5974. }
  5975. }
  5976. }
  5977. }
  5978. }
  5979. err:
  5980. mysql_mutex_unlock(&acl_cache->lock);
  5981. DBUG_RETURN(error);
  5982. #else
  5983. return (0);
  5984. #endif
  5985. }
  5986. int fill_schema_table_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
  5987. {
  5988. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  5989. int error= 0;
  5990. uint index;
  5991. char buff[100];
  5992. TABLE *table= tables->table;
  5993. bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
  5994. NULL, NULL, 1, 1);
  5995. char *curr_host= thd->security_ctx->priv_host_name();
  5996. DBUG_ENTER("fill_schema_table_privileges");
  5997. mysql_rwlock_rdlock(&LOCK_grant);
  5998. for (index=0 ; index < column_priv_hash.records ; index++)
  5999. {
  6000. const char *user, *host, *is_grantable= "YES";
  6001. GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
  6002. index);
  6003. if (!(user=grant_table->user))
  6004. user= "";
  6005. if (!(host= grant_table->host.hostname))
  6006. host= "";
  6007. if (no_global_access &&
  6008. (strcmp(thd->security_ctx->priv_user, user) ||
  6009. my_strcasecmp(system_charset_info, curr_host, host)))
  6010. continue;
  6011. ulong table_access= grant_table->privs;
  6012. if (table_access)
  6013. {
  6014. ulong test_access= table_access & ~GRANT_ACL;
  6015. /*
  6016. We should skip 'usage' privilege on table if
  6017. we have any privileges on column(s) of this table
  6018. */
  6019. if (!test_access && grant_table->cols)
  6020. continue;
  6021. if (!(table_access & GRANT_ACL))
  6022. is_grantable= "NO";
  6023. strxmov(buff, "'", user, "'@'", host, "'", NullS);
  6024. if (!test_access)
  6025. {
  6026. if (update_schema_privilege(thd, table, buff, grant_table->db,
  6027. grant_table->tname, 0, 0,
  6028. STRING_WITH_LEN("USAGE"), is_grantable))
  6029. {
  6030. error= 1;
  6031. goto err;
  6032. }
  6033. }
  6034. else
  6035. {
  6036. ulong j;
  6037. int cnt;
  6038. for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1)
  6039. {
  6040. if (test_access & j)
  6041. {
  6042. if (update_schema_privilege(thd, table, buff, grant_table->db,
  6043. grant_table->tname, 0, 0,
  6044. command_array[cnt],
  6045. command_lengths[cnt], is_grantable))
  6046. {
  6047. error= 1;
  6048. goto err;
  6049. }
  6050. }
  6051. }
  6052. }
  6053. }
  6054. }
  6055. err:
  6056. mysql_rwlock_unlock(&LOCK_grant);
  6057. DBUG_RETURN(error);
  6058. #else
  6059. return (0);
  6060. #endif
  6061. }
  6062. int fill_schema_column_privileges(THD *thd, TABLE_LIST *tables, COND *cond)
  6063. {
  6064. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  6065. int error= 0;
  6066. uint index;
  6067. char buff[100];
  6068. TABLE *table= tables->table;
  6069. bool no_global_access= check_access(thd, SELECT_ACL, "mysql",
  6070. NULL, NULL, 1, 1);
  6071. char *curr_host= thd->security_ctx->priv_host_name();
  6072. DBUG_ENTER("fill_schema_table_privileges");
  6073. mysql_rwlock_rdlock(&LOCK_grant);
  6074. for (index=0 ; index < column_priv_hash.records ; index++)
  6075. {
  6076. const char *user, *host, *is_grantable= "YES";
  6077. GRANT_TABLE *grant_table= (GRANT_TABLE*) my_hash_element(&column_priv_hash,
  6078. index);
  6079. if (!(user=grant_table->user))
  6080. user= "";
  6081. if (!(host= grant_table->host.hostname))
  6082. host= "";
  6083. if (no_global_access &&
  6084. (strcmp(thd->security_ctx->priv_user, user) ||
  6085. my_strcasecmp(system_charset_info, curr_host, host)))
  6086. continue;
  6087. ulong table_access= grant_table->cols;
  6088. if (table_access != 0)
  6089. {
  6090. if (!(grant_table->privs & GRANT_ACL))
  6091. is_grantable= "NO";
  6092. ulong test_access= table_access & ~GRANT_ACL;
  6093. strxmov(buff, "'", user, "'@'", host, "'", NullS);
  6094. if (!test_access)
  6095. continue;
  6096. else
  6097. {
  6098. ulong j;
  6099. int cnt;
  6100. for (cnt= 0, j= SELECT_ACL; j <= TABLE_ACLS; cnt++, j<<= 1)
  6101. {
  6102. if (test_access & j)
  6103. {
  6104. for (uint col_index=0 ;
  6105. col_index < grant_table->hash_columns.records ;
  6106. col_index++)
  6107. {
  6108. GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
  6109. my_hash_element(&grant_table->hash_columns,col_index);
  6110. if ((grant_column->rights & j) && (table_access & j))
  6111. {
  6112. if (update_schema_privilege(thd, table, buff, grant_table->db,
  6113. grant_table->tname,
  6114. grant_column->column,
  6115. grant_column->key_length,
  6116. command_array[cnt],
  6117. command_lengths[cnt], is_grantable))
  6118. {
  6119. error= 1;
  6120. goto err;
  6121. }
  6122. }
  6123. }
  6124. }
  6125. }
  6126. }
  6127. }
  6128. }
  6129. err:
  6130. mysql_rwlock_unlock(&LOCK_grant);
  6131. DBUG_RETURN(error);
  6132. #else
  6133. return (0);
  6134. #endif
  6135. }
  6136. #ifndef NO_EMBEDDED_ACCESS_CHECKS
  6137. /*
  6138. fill effective privileges for table
  6139. SYNOPSIS
  6140. fill_effective_table_privileges()
  6141. thd thread handler
  6142. grant grants table descriptor
  6143. db db name
  6144. table table name
  6145. */
  6146. void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
  6147. const char *db, const char *table)
  6148. {
  6149. Security_context *sctx= thd->security_ctx;
  6150. DBUG_ENTER("fill_effective_table_privileges");
  6151. DBUG_PRINT("enter", ("Host: '%s', Ip: '%s', User: '%s', table: `%s`.`%s`",
  6152. sctx->priv_host, (sctx->ip ? sctx->ip : "(NULL)"),
  6153. (sctx->priv_user ? sctx->priv_user : "(NULL)"),
  6154. db, table));
  6155. /* --skip-grants */
  6156. if (!initialized)
  6157. {
  6158. DBUG_PRINT("info", ("skip grants"));
  6159. grant->privilege= ~NO_ACCESS; // everything is allowed
  6160. DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
  6161. DBUG_VOID_RETURN;
  6162. }
  6163. /* global privileges */
  6164. grant->privilege= sctx->master_access;
  6165. if (!sctx->priv_user)
  6166. {
  6167. DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
  6168. DBUG_VOID_RETURN; // it is slave
  6169. }
  6170. /* db privileges */
  6171. grant->privilege|= acl_get(sctx->host, sctx->ip, sctx->priv_user, db, 0);
  6172. /* table privileges */
  6173. mysql_rwlock_rdlock(&LOCK_grant);
  6174. if (grant->version != grant_version)
  6175. {
  6176. grant->grant_table=
  6177. table_hash_search(sctx->host, sctx->ip, db,
  6178. sctx->priv_user,
  6179. table, 0); /* purecov: inspected */
  6180. grant->version= grant_version; /* purecov: inspected */
  6181. }
  6182. if (grant->grant_table != 0)
  6183. {
  6184. grant->privilege|= grant->grant_table->privs;
  6185. }
  6186. mysql_rwlock_unlock(&LOCK_grant);
  6187. DBUG_PRINT("info", ("privilege 0x%lx", grant->privilege));
  6188. DBUG_VOID_RETURN;
  6189. }
  6190. #else /* NO_EMBEDDED_ACCESS_CHECKS */
  6191. /****************************************************************************
  6192. Dummy wrappers when we don't have any access checks
  6193. ****************************************************************************/
  6194. bool check_routine_level_acl(THD *thd, const char *db, const char *name,
  6195. bool is_proc)
  6196. {
  6197. return FALSE;
  6198. }
  6199. #endif
  6200. struct ACL_internal_schema_registry_entry
  6201. {
  6202. const LEX_STRING *m_name;
  6203. const ACL_internal_schema_access *m_access;
  6204. };
  6205. /**
  6206. Internal schema registered.
  6207. Currently, this is only:
  6208. - performance_schema
  6209. - information_schema,
  6210. This can be reused later for:
  6211. - mysql
  6212. */
  6213. static ACL_internal_schema_registry_entry registry_array[2];
  6214. static uint m_registry_array_size= 0;
  6215. /**
  6216. Add an internal schema to the registry.
  6217. @param name the schema name
  6218. @param access the schema ACL specific rules
  6219. */
  6220. void ACL_internal_schema_registry::register_schema
  6221. (const LEX_STRING *name, const ACL_internal_schema_access *access)
  6222. {
  6223. DBUG_ASSERT(m_registry_array_size < array_elements(registry_array));
  6224. /* Not thread safe, and does not need to be. */
  6225. registry_array[m_registry_array_size].m_name= name;
  6226. registry_array[m_registry_array_size].m_access= access;
  6227. m_registry_array_size++;
  6228. }
  6229. /**
  6230. Search per internal schema ACL by name.
  6231. @param name a schema name
  6232. @return per schema rules, or NULL
  6233. */
  6234. const ACL_internal_schema_access *
  6235. ACL_internal_schema_registry::lookup(const char *name)
  6236. {
  6237. DBUG_ASSERT(name != NULL);
  6238. uint i;
  6239. for (i= 0; i<m_registry_array_size; i++)
  6240. {
  6241. if (my_strcasecmp(system_charset_info, registry_array[i].m_name->str,
  6242. name) == 0)
  6243. return registry_array[i].m_access;
  6244. }
  6245. return NULL;
  6246. }
  6247. /**
  6248. Get a cached internal schema access.
  6249. @param grant_internal_info the cache
  6250. @param schema_name the name of the internal schema
  6251. */
  6252. const ACL_internal_schema_access *
  6253. get_cached_schema_access(GRANT_INTERNAL_INFO *grant_internal_info,
  6254. const char *schema_name)
  6255. {
  6256. if (grant_internal_info)
  6257. {
  6258. if (! grant_internal_info->m_schema_lookup_done)
  6259. {
  6260. grant_internal_info->m_schema_access=
  6261. ACL_internal_schema_registry::lookup(schema_name);
  6262. grant_internal_info->m_schema_lookup_done= TRUE;
  6263. }
  6264. return grant_internal_info->m_schema_access;
  6265. }
  6266. return ACL_internal_schema_registry::lookup(schema_name);
  6267. }
  6268. /**
  6269. Get a cached internal table access.
  6270. @param grant_internal_info the cache
  6271. @param schema_name the name of the internal schema
  6272. @param table_name the name of the internal table
  6273. */
  6274. const ACL_internal_table_access *
  6275. get_cached_table_access(GRANT_INTERNAL_INFO *grant_internal_info,
  6276. const char *schema_name,
  6277. const char *table_name)
  6278. {
  6279. DBUG_ASSERT(grant_internal_info);
  6280. if (! grant_internal_info->m_table_lookup_done)
  6281. {
  6282. const ACL_internal_schema_access *schema_access;
  6283. schema_access= get_cached_schema_access(grant_internal_info, schema_name);
  6284. if (schema_access)
  6285. grant_internal_info->m_table_access= schema_access->lookup(table_name);
  6286. grant_internal_info->m_table_lookup_done= TRUE;
  6287. }
  6288. return grant_internal_info->m_table_access;
  6289. }