Specifically:
Revert "MDEV-29664 Assertion `!n_mysql_tables_in_use' failed in innobase_close_connection"
This reverts commit ba875e9396.
Revert "MDEV-29620 Assertion `next_insert_id == 0' failed in handler::ha_external_lock"
This reverts commit aa08a7442a.
Revert "MDEV-29628 Memory leak after CREATE OR REPLACE with foreign key"
This reverts commit c579d66ba6.
Revert "MDEV-29609 create_not_windows test fails with different result"
This reverts commit cb583b2f1b.
Revert "MDEV-29544 SIGSEGV in HA_CREATE_INFO::finalize_locked_tables"
This reverts commit dcd66c3814.
Revert "MDEV-28933 CREATE OR REPLACE fails to recreate same constraint name"
This reverts commit cf6c517632.
Revert "MDEV-28933 Moved RENAME_CONSTRAINT_IDS to include/sql_funcs.h"
This reverts commit f1e1c1335b.
Revert "MDEV-28956 Locking is broken if CREATE OR REPLACE fails under LOCK TABLES"
This reverts commit a228ec80e3.
Revert "MDEV-25292 gcol.gcol_bugfixes --ps fix"
This reverts commit 24fff8267d.
Revert "MDEV-25292 Disable atomic replace for slave-generated or-replace"
This reverts commit 2af15914cb.
Revert "MDEV-25292 backup_log improved"
This reverts commit 34398a20b5.
Revert "MDEV-25292 Atomic CREATE OR REPLACE TABLE"
This reverts commit 93c8252f02.
Revert "MDEV-25292 Table_name class for (db, table_name, alias)"
This reverts commit d145dda9c7.
Revert "MDEV-25292 ha_table_exists() cleanup and improvement"
This reverts commit 409b8a86de.
Revert "MDEV-25292 Cleanups"
This reverts commit 595dad83ad.
Revert "MDEV-25292 Refactoring: moved select_field_count into Alter_info."
This reverts commit f02af1d229.
The problem is that if table definition cache (TDC) is full of real tables
which are in tables cache, view definition can not stay there so will be
removed by its own underlying tables.
In situation above old mechanism of detection matching definition in PS
and current version always require reprepare and so prevent executing
the PS.
One work around is to increase TDC, other - improve version check for
views/triggers (which is done here). Now in suspicious cases we check:
- timestamp (microseconds) of the view to be sure that version really
have changed;
- time (microseconds) of creation of a trigger related to time
(microseconds) of statement preparation.
Atomic CREATE OR REPLACE allows to keep an old table intact if the
command fails or during the crash. That is done through creating
a table with a temporary name and filling it with the data
(for CREATE OR REPLACE .. SELECT), then renaming the original table
to another temporary (backup) name and renaming the replacement table
to original table. The backup table is kept until the last chance of
failure and if that happens, the replacement table is thrown off and
backup recovered. When the command is complete and logged the backup
table is deleted.
Atomic replace algorithm
Two DDL chains are used for CREATE OR REPLACE:
ddl_log_state_create (C) and ddl_log_state_rm (D).
1. (C) Log CREATE_TABLE_ACTION of TMP table (drops TMP table);
2. Create new table as TMP;
3. Do everything with TMP (like insert data);
finalize_atomic_replace():
4. Link chains: (D) is executed only if (C) is closed;
5. (D) Log DROP_ACTION of BACKUP;
6. (C) Log RENAME_TABLE_ACTION from ORIG to BACKUP (replays BACKUP -> ORIG);
7. Rename ORIG to BACKUP;
8. (C) Log CREATE_TABLE_ACTION of ORIG (drops ORIG);
9. Rename TMP to ORIG;
finalize_ddl() in case of success:
10. Close (C);
11. Replay (D): BACKUP is dropped.
finalize_ddl() in case of error:
10. Close (D);
11. Replay (C):
1) ORIG is dropped (only after finalize_atomic_replace());
2) BACKUP renamed to ORIG (only after finalize_atomic_replace());
3) drop TMP.
If crash happens (C) or (D) is replayed in reverse order. (C) is
replayed if crash happens before it is closed, otherwise (D) is
replayed.
Temporary table for CREATE OR REPLACE
Before dropping "old" table, CREATE OR REPLACE creates "tmp" table.
ddl_log_state_create holds the drop of the "tmp" table. When
everything is OK (data is inserted, "tmp" is ready) ddl_log_state_rm
is written to replace "old" with "tmp". Until ddl_log_state_create
is closed ddl_log_state_rm is not executed.
After the binlogging is done ddl_log_state_create is closed. At that
point ddl_log_state_rm is executed and "tmp" is replaced with
"old". That is: final rename is done by the DDL log.
With that important role of DDL log for CREATE OR REPLACE operation
replay of ddl_log_state_rm must fail at the first hit error and
print the error message if possible. F.ex. foreign key error is
discovered at this phase: InnoDB rejects to drop the "old" table and
returns corresponding foreign key error code.
Additional notes
- CREATE TABLE without REPLACE is not affected by this commit.
- Engines having HTON_EXPENSIVE_RENAME flag set are not affected by
this commit.
- CREATE TABLE .. SELECT XID usage is fixed and now there is no need
to log DROP TABLE via DDL_CREATE_TABLE_PHASE_LOG (see comments in
do_postlock()). XID is now correctly updated so it disables
DDL_LOG_DROP_TABLE_ACTION. Note that binary log is flushed at the
final stage when the table is ready. So if we have XID in the
binary log we don't need to drop the table.
- Three variations of CREATE OR REPLACE handled:
1. CREATE OR REPLACE TABLE t1 (..);
2. CREATE OR REPLACE TABLE t1 LIKE t2;
3. CREATE OR REPLACE TABLE t1 SELECT ..;
- Test case uses 6 combinations for engines (aria, aria_notrans,
myisam, ib, lock_tables, expensive_rename) and 2 combinations for
binlog types (row, stmt). Combinations help to check differences
between the results. Error failures are tested for the above three
variations.
- expensive_rename tests CREATE OR REPLACE without atomic
replace. The effect should be the same as with the old behaviour
before this commit.
- Triggers mechanism is unaffected by this change. This is tested in
create_replace.test.
- LOCK TABLES is affected. Lock restoration must be done after "rm"
chain is replayed.
- Moved ddl_log_complete() from send_eof() to finalize_ddl(). This
checkpoint was not executed before for normal CREATE TABLE but is
executed now.
- CREATE TABLE will now rollback also if writing to the binary
logging failed. See rpl_gtid_strict.test
Rename and drop via DDL log
We replay ddl_log_state_rm to drop the old table and rename the
temporary table. In that case we must throw the correct error
message if ddl_log_revert() fails (f.ex. on FK error).
If table is deleted earlier and not via DDL log and the crash
happened, the create chain is not closed. Linked drop chain is not
executed and the new table is not installed. But the old table is
already deleted.
ddl_log.cc changes
Now we can place action before DDL_LOG_DROP_INIT_ACTION and it will
be replayed after DDL_LOG_DROP_TABLE_ACTION.
report_error parameter for ddl_log_revert() allows to fail at first
error and print the error message if possible.
ddl_log_execute_action() now can print error message.
Since we now can handle errors from ddl_log_execute_action() (in
case of non-recovery execution) unconditional setting "error= TRUE"
is wrong (it was wrong anyway because it was overwritten at the end
of the function).
On XID usage
Like with all other atomic DDL operations XID is used to avoid
inconsistency between master and slave in the case of a crash after
binary log is written and before ddl_log_state_create is closed. On
recovery XIDs are taken from binary log and corresponding DDL log
events get disabled. That is done by
ddl_log_close_binlogged_events().
On linking two chains together
Chains are executed in the ascending order of entry_pos of execute
entries. But entry_pos assignment order is undefined: it may assign
bigger number for the first chain and then smaller number for the
second chain. So the execution order in that case will be reverse:
second chain will be executed first.
To avoid that we link one chain to another. While the base chain
(ddl_log_state_create) is active the secondary chain
(ddl_log_state_rm) is not executed. That is: only one chain can be
executed in two linked chains.
The interface ddl_log_link_chains() was done in "MDEV-22166
ddl_log_write_execute_entry() extension".
More on CREATE OR REPLACE .. SELECT
We use create_and_open_tmp_table() like in ALTER TABLE to create
temporary TABLE object (tmp_table is (NON_)TRANSACTIONAL_TMP_TABLE).
After we created such TABLE object we use create_info->tmp_table()
instead of table->s->tmp_table when we need to check for
parser-requested tmp-table.
External locking is required for temporary table created by
create_and_open_tmp_table(). F.ex. that disables logging for Aria
transactional tables and without that (when no mysql_lock_tables()
is done) it cannot work correctly.
For making external lock the patch requires Aria table to work in
non-transactional mode. That is usually done by
ha_enable_transaction(false). But we cannot disable transaction
completely because: 1. binlog rollback removes pending row events
(binlog_remove_pending_rows_event()). The row events are added
during CREATE .. SELECT data insertion phase. 2. replication slave
highly depends on transaction and cannot work without it.
So we put temporary Aria table into non-transactional mode with
"thd->transaction->on hack". See comment for on_save variable.
Note that Aria table has internal_table mode. But we cannot use it
because:
if (!internal_table)
{
mysql_mutex_lock(&THR_LOCK_myisam);
old_info= test_if_reopen(name_buff);
}
For internal_table test_if_reopen() is not called and we get a new
MARIA_SHARE for each file handler. In that case duplicate errors are
missed because insert and lookup in CREATE .. SELECT is done via two
different handlers (see create_lookup_handler()).
For temporary table before dropping TABLE_SHARE by
drop_temporary_table() we must do ha_reset(). ha_reset() releases
storage share. Without that the share is kept and the second CREATE
OR REPLACE .. SELECT fails with:
HA_ERR_TABLE_EXIST (156): MyISAM table '#sql-create-b5377-4-t2' is
in use (most likely by a MERGE table). Try FLUSH TABLES.
HA_EXTRA_PREPARE_FOR_DROP also removes MYISAM_SHARE, but that is
not needed as ha_reset() does the job.
ha_reset() is usually done by
mark_tmp_table_as_free_for_reuse(). But we don't need that mechanism
for our temporary table.
Atomic_info in HA_CREATE_INFO
Many functions in CREATE TABLE pass the same parameters. These
parameters are part of table creation info and should be in
HA_CREATE_INFO (or whatever). Passing parameters via single
structure is much easier for adding new data and
refactoring.
InnoDB changes (revised by Marko Mäkelä)
row_rename_table_for_mysql(): Specify the treatment of FOREIGN KEY
constraints in a 4-valued enum parameter. In cases where FOREIGN KEY
constraints cannot exist (partitioned tables, or internal tables of
FULLTEXT INDEX), we can use the mode RENAME_IGNORE_FK.
The mod RENAME_REBUILD is for any DDL operation that rebuilds the
table inside InnoDB, such as TRUNCATE and native ALTER TABLE
(or OPTIMIZE TABLE). The mode RENAME_ALTER_COPY is used solely
during non-native ALTER TABLE in ha_innobase::rename_table().
Normal ha_innobase::rename_table() will use the mode RENAME_FK.
CREATE OR REPLACE will rename the old table (if one exists) along
with its FOREIGN KEY constraints into a temporary name. The replacement
table will be initially created with another temporary name.
Unlike in ALTER TABLE, all FOREIGN KEY constraints must be renamed
and not inherited as part of these operations, using the mode RENAME_FK.
dict_get_referenced_table(): Let the callers convert names when needed.
create_table_info_t::create_foreign_keys(): CREATE OR REPLACE creates
the replacement table with a temporary name table, so for
self-references foreign->referenced_table will be a table with
temporary name and charset conversion must be skipped for it.
Reviewed by:
Michael Widenius <monty@mariadb.org>
ALTER TABLE .. RENAME, when used with the inplace algorithm, does:
- Do an inplace or online alter to the new definition
- Rename to new name
- Update triggers.
If update triggers would fail, we would rename the table back.
The problem with this approach is that the table would have the new
definition but the rename would fail. The binary log would also not be
updated.
The solution to this is to very early check if we can rename triggers
and give an error if this would fail.
Both ALTER TABLE ... RENAME and RENAME TABLE is fixed.
This was implemented by moving the pre-check of rename table in triggers
from Table_triggers_list::change_table_name() to
Table_triggers_list::prepare_for_rename().
The purpose of this task is to ensure that CREATE TRIGGER is atomic
When a trigger is created, we first create a trigger_name.TRN file and then
create or update the table_name.TRG files.
This is done by creating .TRN~ and .TRG~ files and replacing (or creating)
the result files.
The new logic is
- Log CREATE TRIGGER to DDL log, with a marker if old trigger existsted
- If old .TRN or .TRG files exists, make backup copies of these
- Create the new .TRN and .TRG files as before
- Remove the backups
Crash recovery
- If query has been logged to binary log:
- delete any left over backup files
- else
- Delete any old .TRN~ or .TRG~ files
- If there was orignally some triggers (old .TRG file existed)
- If we crashed before creating all backup files
- Delete existing backup files
- else
- Restore backup files
- end
- Delete .TRN and .TRG file (as there was no triggers before
One benefit of the new code is that CREATE OR REPLACE TRIGGER is now
totally atomic even if there existed an old trigger: Either the old
trigger will be replaced or the old one will be left untouched.
Other things:
- If sql_create_definition_file() would fail, there could be memory leaks
in CREATE TRIGGER, DROP TRIGGER or CREATE OR REPLACE TRIGGER. This
is now fixed.
The purpose of this task is to ensure that DROP TRIGGER is atomic.
Description of how atomic drop trigger works:
Logging of DROP TRIGGER
Log the following information:
db
table name
trigger name
xid /* Used to check if query was already logged to binary log */
initial length of the .TRG file
query if there is space for it, if not log a zero length query.
Recovery operations:
- Delete if exists 'database/trigger_name.TRN~'
- If this file existed, it means that we crashed before the trigger
was deleted and there is nothing else to do.
- Get length of .TRG file
- If file length is unchanged, trigger was not dropped. Nothing else to
do.
- Log original query to binary, if it was stored in the ddl log. If it was
not stored (long query string), log the following query to binary log:
use `database` ; DROP TRIGGER IF EXISTS `trigger_name`
/* generated by ddl log */;
Other things:
- Added trigger name and DDL_LOG_STATE to drop_trigger()
Trigger name was added to make the interface more consistent and
more general.
The used code is largely based on code from Tencent
The problem is that in some rare cases there may be a conflict between .frm
files and the files in the storage engine. In this case the DROP TABLE
was not able to properly drop the table.
Some MariaDB/MySQL forks has solved this by adding a FORCE option to
DROP TABLE. After some discussion among MariaDB developers, we concluded
that users expects that DROP TABLE should always work, even if the
table would not be consistent. There should not be a need to use a
separate keyword to ensure that the table is really deleted.
The used solution is:
- If a .frm table doesn't exists, try dropping the table from all storage
engines.
- If the .frm table exists but the table does not exist in the engine
try dropping the table from all storage engines.
- Update storage engines using many table files (.CVS, MyISAM, Aria) to
succeed with the drop even if some of the files are missing.
- Add HTON_AUTOMATIC_DELETE_TABLE to handlerton's where delete_table()
is not needed and always succeed. This is used by ha_delete_table_force()
to know which handlers to ignore when trying to drop a table without
a .frm file.
The disadvantage of this solution is that a DROP TABLE on a non existing
table will be a bit slower as we have to ask all active storage engines
if they know anything about the table.
Other things:
- Added a new flag MY_IGNORE_ENOENT to my_delete() to not give an error
if the file doesn't exist. This simplifies some of the code.
- Don't clear thd->error in ha_delete_table() if there was an active
error. This is a bug fix.
- handler::delete_table() will not abort if first file doesn't exists.
This is bug fix to handle the case when a drop table was aborted in
the middle.
- Cleaned up mysql_rm_table_no_locks() to ensure that if_exists uses
same code path as when it's not used.
- Use non_existing_Table_error() to detect if table didn't exists.
Old code used different errors tests in different position.
- Table_triggers_list::drop_all_triggers() now drops trigger file if
it can't be parsed instead of leaving it hanging around (bug fix)
- InnoDB doesn't anymore print error about .frm file out of sync with
InnoDB directory if .frm file does not exists. This change was required
to be able to try to drop an InnoDB file when .frm doesn't exists.
- Fixed bug in mi_delete_table() where the .MYD file would not be dropped
if the .MYI file didn't exists.
- Fixed memory leak in Mroonga when deleting non existing table
- Fixed memory leak in Connect when deleting non existing table
Bugs fixed introduced by the original version of this commit:
MDEV-22826 Presence of Spider prevents tables from being force-deleted from
other engines
use s->fields instead of s->stored_fields. extra_null_bitmap is allocated in Table_triggers_list::prepare_record_accessors with respect to virtual fields, so it will not overflow
Closes#1292
This was done in, among other things:
- thd->db and thd->db_length
- TABLE_LIST tablename, db, alias and schema_name
- Audit plugin database name
- lex->db
- All db and table names in Alter_table_ctx
- st_select_lex db
Other things:
- Changed a lot of functions to take const LEX_CSTRING* as argument
for db, table_name and alias. See init_one_table() as an example.
- Changed some function arguments from LEX_CSTRING to const LEX_CSTRING
- Changed some lists from LEX_STRING to LEX_CSTRING
- threads_mysql.result changed because process list_db wasn't always
correctly updated
- New append_identifier() function that takes LEX_CSTRING* as arguments
- Added new element tmp_buff to Alter_table_ctx to separate temp name
handling from temporary space
- Ensure we store the length after my_casedn_str() of table/db names
- Removed not used version of rename_table_in_stat_tables()
- Changed Natural_join_column::table_name and db_name() to never return
NULL (used for print)
- thd->get_db() now returns db as a printable string (thd->db.str or "")
Benefits of this patch:
- Removed a lot of calls to strlen(), especially for field_string
- Strings generated by parser are now const strings, less chance of
accidently changing a string
- Removed a lot of calls with LEX_STRING as parameter (changed to pointer)
- More uniform code
- Item::name_length was not kept up to date. Now fixed
- Several bugs found and fixed (Access to null pointers,
access of freed memory, wrong arguments to printf like functions)
- Removed a lot of casts from (const char*) to (char*)
Changes:
- This caused some ABI changes
- lex_string_set now uses LEX_CSTRING
- Some fucntions are now taking const char* instead of char*
- Create_field::change and after changed to LEX_CSTRING
- handler::connect_string, comment and engine_name() changed to LEX_CSTRING
- Checked printf() related calls to find bugs. Found and fixed several
errors in old code.
- A lot of changes from LEX_STRING to LEX_CSTRING, especially related to
parsing and events.
- Some changes from LEX_STRING and LEX_STRING & to LEX_CSTRING*
- Some changes for char* to const char*
- Added printf argument checking for my_snprintf()
- Introduced null_clex_str, star_clex_string, temp_lex_str to simplify
code
- Added item_empty_name and item_used_name to be able to distingush between
items that was given an empty name and items that was not given a name
This is used in sql_yacc.yy to know when to give an item a name.
- select table_name."*' is not anymore same as table_name.*
- removed not used function Item::rename()
- Added comparision of item->name_length before some calls to
my_strcasecmp() to speed up comparison
- Moved Item_sp_variable::make_field() from item.h to item.cc
- Some minimal code changes to avoid copying to const char *
- Fixed wrong error message in wsrep_mysql_parse()
- Fixed wrong code in find_field_in_natural_join() where real_item() was
set when it shouldn't
- ER_ERROR_ON_RENAME was used with extra arguments.
- Removed some (wrong) ER_OUTOFMEMORY, as alloc_root will already
give the error.
TODO:
- Check possible unsafe casts in plugin/auth_examples/qa_auth_interface.c
- Change code to not modify LEX_CSTRING for database name
(as part of lower_case_table_names)
Define my_thread_id as an unsigned type, to avoid mismatch with
ulonglong. Change some parameters to this type.
Use size_t in a few more places.
Declare many flag constants as unsigned to avoid sign mismatch
when shifting bits or applying the unary ~ operator.
When applying the unary ~ operator to enum constants, explictly
cast the result to an unsigned type, because enum constants can
be treated as signed.
In InnoDB, change the source code line number parameters from
ulint to unsigned type. Also, make some InnoDB functions return
a narrower type (unsigned or uint32_t instead of ulint;
bool instead of ibool).
This is similar to MysQL Worklog 3253, but with
a different implementation. The disk format and
SQL syntax is identical with MySQL 5.7.
Fetures supported:
- "Any" ammount of any trigger
- Supports FOLLOWS and PRECEDES to be
able to put triggers in a certain execution order.
Implementation details:
- Class Trigger added to hold information about a trigger.
Before this trigger information was stored in a set of lists in
Table_triggers_list and in Table_triggers_list::bodies
- Each Trigger has a next field that poinst to the next Trigger with the
same action and time.
- When accessing a trigger, we now always access all linked triggers
- The list are now only used to load and save trigger files.
- MySQL trigger test case (trigger_wl3253) added and we execute these
identically.
- Even more gracefully handling of wrong trigger files than before. This
is useful if a trigger file uses functions or syntax not provided by
the server.
- Each trigger now has a "Created" field that shows when the trigger was
created, with 2 decimals.
Other comments:
- Many of the changes in test files was done because of the new "Created"
field in the trigger file. This shows up in SHOW ... TRIGGER and when
using information_schema.trigger.
- Don't check if all memory is released if on uses --gdb; This is needed
to be able to get a list from safemalloc of not freed memory while
debugging.
- Added option to trim_whitespace() to know how many prefix characters
was skipped.
- Changed a few ulonglong sql_mode to sql_mode_t, to find some wrong usage
of sql_mode.
NOT NULL constraint must be checked *after* the BEFORE triggers.
That is for INSERT and UPDATE statements even NOT NULL fields
must be able to store a NULL temporarily at least while
BEFORE INSERT/UPDATE triggers are running.
* move common code to a new set_bad_null_error() function
* move repeated comparison out of the loop
* remove unused code
* unused method Table_triggers_list::set_table
* redundant condition (if (table) after table was dereferenced)
* add an assert
sql/sql_insert.cc:
CREATE ... IF NOT EXISTS may do nothing, but
it is still not a failure. don't forget to my_ok it.
******
CREATE ... IF NOT EXISTS may do nothing, but
it is still not a failure. don't forget to my_ok it.
sql/sql_table.cc:
small cleanup
******
small cleanup
SYNTAX TRIGGERS IN ANY WAY
Table with triggers which were using deprecated (5.0-only) syntax became
unavailable for any DML and DDL after upgrade to 5.1 version of server.
Attempt to execute any statement on such a table resulted in parsing
error reported. Since this included DROP TRIGGER and DROP TABLE
statements (actually, the latter was allowed but was not functioning
properly for such tables) it was impossible to fix the problem without
manual operations on .TRG and .TRN files in data directory.
The problem was that failure to parse trigger body (due to 5.0-only
syntax) when opening trigger file for a table prevented the table
from being open. This made all operations on the table impossible
(except DROP TABLE which due to peculiarity in its implementation
dropped the table but left trigger files around).
This patch solves this problem by silencing error which occurs when
we parse trigger body during table open. Error message is preserved
for the future use and table is marked as having a broken trigger.
We also try to analyze parse tree to recover trigger name, which
will be needed in order to drop the broken trigger. DML statements
which invoke triggers on the table marked as having broken trigger
are prohibited and emit saved error message. The same happens for
DDL which change triggers except DROP TRIGGER and DROP TABLE which
try their best to do what was requested. Table becomes no longer
marked as having broken trigger when last such trigger is dropped.
mysql-test/r/trigger-compat.result:
Add results for test case for bug#45235
mysql-test/t/trigger-compat.test:
Add test case for bug#45235.
sql/sp_head.cc:
Added protection against MEM_ROOT double restoring to
sp_head::restore_thd_mem_root() method. Since this
method can be sometimes called twice during parsing
of stored routine (the first time during normal flow
of parsing, and the second time when a syntax error
is detected) we need to shortcut execution of the
method to avoid damaging MEM_ROOT by the second
consecutive call to this method.
sql/sql_trigger.cc:
Added error handler Deprecated_trigger_syntax_handler to
catch non-OOM errors during parsing of trigger body.
Added handling of parse errors into method
Table_triggers_list::check_n_load().
sql/sql_trigger.h:
Added new members to handle broken triggers and error messages.
- Changed Cached_item_field not copy data for fields with NULL value
- In key_copy() and key_restore() don't copy data for fields with NULL value
Fixed code to avoid valgrind warnings
- Use c_ptr_safe instead of c_ptr()
Removed "QQ" from comments (QQ was ment to be used for internal comments that should be removed before pushing)
Fixed wrong alias used (from previous patch)
sql/event_db_repository.cc:
Update testing if event table is valid (to avoid valgrind errors)
sql/ha_partition.cc:
m_ordered_scan_ongoing was not initialized
Reset null bits in record to avoid valgrind errors
sql/handler.h:
Added flag if storage engine will write row verbatim and the row contains varchar or null fields
(in which case we must clear the row to avoid valgrind warnings)
sql/item_buff.cc:
Changed Cached_item_field not copy data for fields with NULL value
(Optimization and avoids valgrind warnings)
sql/item_func.cc:
c_ptr() -> c_ptr_safe()
sql/key.cc:
In key_copy() and key_restore() don't copy data for fields with NULL value
sql/opt_range.cc:
c_ptr() -> c_ptr_safe()
sql/sql_base.cc:
Added TRASH() to table->record[0] to find out if we access not initialzed data.
Initialize null_bytes to:
- Get consistent tests
- Ensure we don't get valgrind warnings for null fields (as we may only update a couple of bits in a byte)
sql/sql_class.cc:
Removed "QQ" from comments
sql/sql_insert.cc:
Initialize row to default values if we are using valgrind and row will be copied verbatim to disk in storage engine.
sql/sql_load.cc:
QQ -> TODO
sql/sql_parse.cc:
Removed old not used code marked QQ and withing "#ifdef REMOVED"
sql/sql_select.cc:
QQ -> TODO
Initialize some variables that was used uninitialized
Added DBUG_ASSERT() to find out if thd was not properly initialized for sub queries
sql/sql_test.cc:
Fixed format for printing to DBUG file
Fixed wrong alias used (from previous patch)
sql/sql_trigger.h:
QQ -> TODO
sql/table.cc:
QQ -> TODO
storage/maria/ha_maria.cc:
Mark table with HA_RECORD_MUST_BE_CLEAN_ON_WRITE, if row is written verbatim to disk and contains varchar or null fields.
storage/maria/ma_open.c:
Added flags if table has varchar or null fields
storage/maria/maria_def.h:
Added flags if table has varchar or null fields
storage/myisam/ha_myisam.cc:
Mark table with HA_RECORD_MUST_BE_CLEAN_ON_WRITE, if row is written verbatim to disk and contains varchar or null fields.
storage/myisam/mi_open.c:
Fixed memory overrun bug when using fulltext keys
storage/xtradb/row/row0sel.c:
Removed initialization of null bits. (not needed anymore)
The problem was that RENAME TABLE caused an assert if the system variable
lower_case_table_names was 2 (default on Mac OS X) and the old table name
was given in upper case. This caused lowercase_table2.test to fail.
The assert checks that an exclusive metadata lock is held by the connection
trying to do RENAME TABLE - specificially during updates of table triggers.
The assert was triggered since the check is case sensitive and the lock
was held on the normalized (lower case) version of the table name.
This patch fixes the problem by making sure a normalized version of the
table name is used for the metadata lock check, while using a non-normalized
version of the table name for the rename of trigger files. The same is done
for ALTER TABLE ... RENAME.
Regression testing for the bug itself is already covered by
lowercase_table2.test. Additional coverage added to lowercase_fs_off.test.
This patch:
- Moves all definitions from the mysql_priv.h file into
header files for the component where the variable is
defined
- Creates header files if the component lacks one
- Eliminates all include directives from mysql_priv.h
- Eliminates all circular include cycles
- Rename time.cc to sql_time.cc
- Rename mysql_priv.h to sql_priv.h
----------------------------------------------------------
revno: 2617.69.24
committer: Konstantin Osipov <kostja@sun.com>
branch nick: 5.4-42546
timestamp: Fri 2009-08-14 19:22:05 +0400
message:
A pre-requisite for a fix for Bug#42546 "Backup: RESTORE fails, thinking it
finds an existing table"
Back-port from WL 148 "Foreign keys" feature tree a patch
that introduced Prelocking_strategy class -- a way to parameterize
open_tables() behaviour, implemented by Dmitry Lenev.
(Part of WL#4284).
sql/sql_base.cc:
Implement different prelocking strategies. Use an instance of
prelocking_strategy in open_tables().
sql/sql_class.h:
Add declarations for class Prelocking_strategy.
sql/sql_lex.h:
Add a helper method to access last table of the global table list
(lex->query_tables).
sql/sql_parse.cc:
Use a special prelocking strategy when locking tables for LOCK TABLES.
sql/sql_table.cc:
Use normal open_and_lock_tables_derived() in ALTER TABLE.
sql/sql_yacc.yy:
Modify the grammar to not pollute the global table list with tables
that should not be opened.
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains
triggers
and
#41385: Crash when attempting to repair a #mysql50# upgraded table
with triggers.
Problem:
1. trigger code didn't assume a table name may have
a "#mysql50#" prefix, that may lead to a failing ASSERT().
2. "ALTER DATABASE ... UPGRADE DATA DIRECTORY NAME" failed
for databases with "#mysql50#" prefix if any trigger.
3. mysqlcheck --fix-table-name didn't use UTF8 as a default
character set that resulted in (parsing) errors for tables with
non-latin symbols in their names and definitions of triggers.
Fix:
1. properly handle table/database names with "#mysql50#" prefix.
2. handle --default-character-set mysqlcheck option;
if mysqlcheck is launched with --fix-table-name or --fix-db-name
set default character set to UTF8 if no --default-character-set
option given.
Note: if given --fix-table-name or --fix-db-name option,
without --default-character-set mysqlcheck option
default character set is UTF8.
client/mysqlcheck.c:
Fix for
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains
triggers
and
#41385: Crash when attempting to repair a #mysql50# upgraded table
with triggers.
- check and set default charset if --default-character-set option
given.
- set default charset to "utf8" if there's
--fix-table-name or --fix-db-name and no --default-character-set.
mysql-test/r/mysqlcheck.result:
Fix for
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains
triggers
and
#41385: Crash when attempting to repair a #mysql50# upgraded table
with triggers.
- test result.
mysql-test/t/mysqlcheck.test:
Fix for
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains
triggers
and
#41385: Crash when attempting to repair a #mysql50# upgraded table
with triggers.
- test case.
sql/mysql_priv.h:
Fix for
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains
triggers
and
#41385: Crash when attempting to repair a #mysql50# upgraded table
with triggers.
- check_n_cut_mysql50_prefix() introduced.
sql/sql_table.cc:
Fix for
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains
triggers
and
#41385: Crash when attempting to repair a #mysql50# upgraded table
with triggers.
- tablename_to_filename() code split into 2 parts
- check_n_cut_mysql50_prefix() introduced to cut #mysql50# prefixes,
used in the trigger code as well.
sql/sql_trigger.cc:
Fix for
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains
triggers
and
#41385: Crash when attempting to repair a #mysql50# upgraded table
with triggers.
- Table_triggers_list::check_n_load() - checking triggers assume
a table/database name given may have "#mysql50#" prefix in some cases.
- Table_triggers_list::change_table_name_in_triggers() -
create .TRG file in new database directory and delete it in old one,
as they may differ in case of
"ALTER DATABASE ... UPGRADE DATA DIRECTORY NAME"
- Table_triggers_list::change_table_name_in_trignames() - remove stale .TRN
files in #mysql50#dbname directory in case of database upgrade
- Table_triggers_list::change_table_name() - allow changing trigger's
database in case of its upgrading
sql/sql_trigger.h:
Fix for
bug#33094: Error in upgrading from 5.0 to 5.1 when table contains
triggers
and
#41385: Crash when attempting to repair a #mysql50# upgraded table
with triggers.
- new old_db_name parameter added in
Table_triggers_list::change_table_name_in_trignames() and
Table_triggers_list::change_table_name_in_triggers()
causes full table lock on innodb table.
Also fixes Bug#28502 Triggers that update another innodb table
will block on X lock unnecessarily (duplciate).
Code review fixes.
Both bugs' synopses are misleading: InnoDB table is
not X locked. The statements, however, cannot proceed concurrently,
but this happens due to lock conflicts for tables used in triggers,
not for the InnoDB table.
If a user had an InnoDB table, and two triggers, AFTER UPDATE and
AFTER INSERT, competing for different resources (e.g. two distinct
MyISAM tables), then these two triggers would not be able to execute
concurrently. Moreover, INSERTS/UPDATES of the InnoDB table would
not be able to run concurrently.
The problem had other side-effects (see respective bug reports).
This behavior was a consequence of a shortcoming of the pre-locking
algorithm, which would not distinguish between different DML operations
(e.g. INSERT and DELETE) and pre-lock all the tables
that are used by any trigger defined on the subject table.
The idea of the fix is to extend the pre-locking algorithm to keep track,
for each table, what DML operation it is used for and not
load triggers that are known to never be fired.
mysql-test/r/trigger-trans.result:
Update results (Bug#26141)
mysql-test/r/trigger.result:
Update results (Bug#28502)
mysql-test/t/trigger-trans.test:
Add a test case for Bug#26141 mixing table types in trigger causes
full table lock on innodb table.
mysql-test/t/trigger.test:
Add a test case for Bug#28502 Triggers that update another innodb
table will block echo on X lock unnecessarily. Add more test
coverage for triggers.
sql/item.h:
enum trg_event_type is needed in table.h
sql/sp.cc:
Take into account table_list->trg_event_map when determining
what tables to pre-lock.
After this change, if we attempt to fire a
trigger for which we had not pre-locked any tables, error
'Table was not locked with LOCK TABLES' will be printed.
This, however, should never happen, provided the pre-locking
algorithm has no programming bugs.
Previously a trigger key in the sroutines hash was based on the name
of the table the trigger belongs to. This was possible because we would
always add to the pre-locking list all the triggers defined for a table when
handling this table.
Now the key is based on the name of the trigger, owing
to the fact that a trigger name must be unique in the database it
belongs to.
sql/sp_head.cc:
Generate sroutines hash key in init_spname(). This is a convenient
place since there we have all the necessary information and can
avoid an extra alloc.
Maintain and merge trg_event_map when adding and merging elements
of the pre-locking list.
sql/sp_head.h:
Add ,m_sroutines_key member, used when inserting the sphead for a
trigger into the cache of routines used by a statement.
Previously the key was based on the table name the trigger belonged
to, since for a given table we would add to the sroutines list
all the triggers defined on it.
sql/sql_lex.cc:
Introduce a new lex step: set_trg_event_type_for_tables().
It is called when we have finished parsing but before opening
and locking tables. Now this step is used to evaluate for each
TABLE_LIST instance which INSERT/UPDATE/DELETE operation, if any,
it is used in.
In future this method could be extended to aggregate other information
that is hard to aggregate during parsing.
sql/sql_lex.h:
Add declaration for set_trg_event_type_for_tables().
sql/sql_parse.cc:
Call set_trg_event_type_for_tables() after MYSQLparse(). Remove tabs.
sql/sql_prepare.cc:
Call set_trg_event_type_for_tables() after MYSQLparse().
sql/sql_trigger.cc:
Call set_trg_event_type_for_tables() after MYSQLparse().
sql/sql_trigger.h:
Remove an obsolete member.
sql/sql_view.cc:
Call set_trg_event_type_for_tables() after MYSQLparse().
sql/sql_yacc.yy:
Move assignment of sp_head::m_type before calling sp_head::init_spname(),
one is now used inside another.
sql/table.cc:
Implement TABLE_LIST::set_trg_event_map() - a method that calculates
wh triggers may be fired on this table when executing a statement.
sql/table.h:
Add missing declarations.
Move declaration of trg_event_type from item.h (it will be needed for
trg_event_map bitmap when we start using Bitmap template instead
of uint8).