mirror of
https://github.com/MariaDB/server.git
synced 2025-01-19 13:32:33 +01:00
76de7d788c
innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Fixes: - Bug #21409: Incorrect result returned when in READ-COMMITTED with query_cache ON At low transaction isolation levels we let each consistent read set its own snapshot. - Bug #23666: strange Innodb_row_lock_time_% values in show status; also millisecs wrong On Windows ut_usectime returns secs and usecs relative to the UNIX epoch (which is Jan, 1 1970). - Bug #25494: LATEST DEADLOCK INFORMATION is not always cleared lock_deadlock_recursive(): When the search depth or length is exceeded, rewind lock_latest_err_file and display the two transactions at the point of aborting the search. - Bug #25927: Foreign key with ON DELETE SET NULL on NOT NULL can crash server Prevent ALTER TABLE ... MODIFY ... NOT NULL on columns for which there is a foreign key constraint ON ... SET NULL. - Bug #26835: Repeatable corruption of utf8-enabled tables inside InnoDB The bug could be reproduced as follows: Define a table so that the first column of the clustered index is a VARCHAR or a UTF-8 CHAR in a collation where sequences of bytes of differing length are considered equivalent. Insert and delete a record. Before the delete-marked record is purged, insert another record whose first column is of different length but equivalent to the first record. Under certain conditions, the insertion can be incorrectly performed as update-in-place. Likewise, an operation that could be done as update-in-place can unnecessarily be performed as delete and insert, but that would not cause corruption but merely degraded performance. mysql-test/r/innodb.result: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1284: Merge changes from MySQL AB: ChangeSet 2007/01/24 14:49:36+04:00 holyfoot@mysql.com bug 22682 Test fails --without-geometry geometry dependent parts moved to proper .test files mysql-test/r/innodb.result 2007/01/24 14:49:34+04:00 holyfoot@mysql.com +0 -2 result fixed mysql-test/r/innodb_gis.result 2007/01/24 14:49:34+04:00 holyfoot@mysql.com +2 -0 result fixed mysql-test/t/innodb.test 2007/01/24 14:49:34+04:00 holyfoot@mysql.com +0 -6 HAVE_GEOMETRY dependent part moved to innodb_gis.test mysql-test/t/innodb_gis.test 2007/01/24 14:49:35+04:00 holyfoot@mysql.com +6 -0 HAVE_GEOMETRY dependent part moved here from innodb.test Revision r1186: dict_load_foreign(): Use a local variable instead of the 10-bit field foreign->n_fields in order to preserve ON UPDATE CASCADE and ON DELETE CASCADE flags. For some reason, gcc does not warn about shifting a 10-bit field to right by 24 bits. (Bug 24741) This bug was introduced while reducing the memory footprint of the InnoDB data dictionary (Bug 20877). innodb.test, innodb.result: Add a test case. Revision r1318: Add a test case for r1316 (Bug #25927). Revision r1340: innodb.test, innodb.result: Add test case for Bug #26835. The bug could be reproduced as follows: Define a table so that the first column of the clustered index is a VARCHAR or a UTF-8 CHAR in a collation where sequences of bytes of differing length are considered equivalent. Insert and delete a record. Before the delete-marked record is purged, insert another record whose first column is of different length but equivalent to the first record. Under certain conditions, the insertion can be incorrectly performed as update-in-place. Likewise, an operation that could be done as update-in-place can unnecessarily be performed as delete and insert, but that would not cause corruption but merely degraded performance. mysql-test/t/innodb.test: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1284: Merge changes from MySQL AB: ChangeSet 2007/01/24 14:49:36+04:00 holyfoot@mysql.com bug 22682 Test fails --without-geometry geometry dependent parts moved to proper .test files mysql-test/r/innodb.result 2007/01/24 14:49:34+04:00 holyfoot@mysql.com +0 -2 result fixed mysql-test/r/innodb_gis.result 2007/01/24 14:49:34+04:00 holyfoot@mysql.com +2 -0 result fixed mysql-test/t/innodb.test 2007/01/24 14:49:34+04:00 holyfoot@mysql.com +0 -6 HAVE_GEOMETRY dependent part moved to innodb_gis.test mysql-test/t/innodb_gis.test 2007/01/24 14:49:35+04:00 holyfoot@mysql.com +6 -0 HAVE_GEOMETRY dependent part moved here from innodb.test Revision r1283: Merge changes from MySQL AB: ChangeSet 2007/01/22 18:42:52+02:00 monty@mysql.com Give warnings for unused objects Changed error message to be compatible with old error file Added new error message for new DUP_ENTRY syntax mysql-test/t/innodb.test 2007/01/22 18:42:49+02:00 monty@mysql.com +14 -14 Changed to use new error message Revision r1186: dict_load_foreign(): Use a local variable instead of the 10-bit field foreign->n_fields in order to preserve ON UPDATE CASCADE and ON DELETE CASCADE flags. For some reason, gcc does not warn about shifting a 10-bit field to right by 24 bits. (Bug 24741) This bug was introduced while reducing the memory footprint of the InnoDB data dictionary (Bug 20877). innodb.test, innodb.result: Add a test case. Revision r1318: Add a test case for r1316 (Bug #25927). Revision r1329: Merge changes from MySQL AB to mysql-test directives. The results are not affected. Revision r1340: innodb.test, innodb.result: Add test case for Bug #26835. The bug could be reproduced as follows: Define a table so that the first column of the clustered index is a VARCHAR or a UTF-8 CHAR in a collation where sequences of bytes of differing length are considered equivalent. Insert and delete a record. Before the delete-marked record is purged, insert another record whose first column is of different length but equivalent to the first record. Under certain conditions, the insertion can be incorrectly performed as update-in-place. Likewise, an operation that could be done as update-in-place can unnecessarily be performed as delete and insert, but that would not cause corruption but merely degraded performance. storage/innobase/buf/buf0buf.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/buf/buf0flu.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/buf/buf0lru.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/dict/dict0boot.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/dict/dict0crea.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1324: Merge changes from MySQL AB: ChangeSet@1.2452, 2007-02-23 13:13:55+02:00, monty@mysql.com +177 -0 Fixed compiler warnings ... Fixed compiler warnings detected on windows64 storage/innobase/dict/dict0dict.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1316: Prevent ALTER TABLE ... MODIFY ... NOT NULL on columns for which there is a foreign key constraint ON ... SET NULL. (Bug #25927) dict_foreign_find_index(): Add paramettter check_null. dict_foreign_add_to_cache(): Do not allow ON DELETE SET NULL or ON UPDATE SET NULL if any of the referencing columns are declared NOT NULL. Revision r1324: Merge changes from MySQL AB: ChangeSet@1.2452, 2007-02-23 13:13:55+02:00, monty@mysql.com +177 -0 Fixed compiler warnings ... Fixed compiler warnings detected on windows64 storage/innobase/dict/dict0load.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1186: dict_load_foreign(): Use a local variable instead of the 10-bit field foreign->n_fields in order to preserve ON UPDATE CASCADE and ON DELETE CASCADE flags. For some reason, gcc does not warn about shifting a 10-bit field to right by 24 bits. (Bug 24741) This bug was introduced while reducing the memory footprint of the InnoDB data dictionary (Bug 20877). innodb.test, innodb.result: Add a test case. Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1324: Merge changes from MySQL AB: ChangeSet@1.2452, 2007-02-23 13:13:55+02:00, monty@mysql.com +177 -0 Fixed compiler warnings ... Fixed compiler warnings detected on windows64 storage/innobase/fil/fil0fil.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/fsp/fsp0fsp.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/ha/ha0ha.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/handler/ha_innodb.cc: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1204: Change this in ha_innobase: void* innobase_prebuilt; to this: row_prebuilt_t* prebuilt; by introducing the typedef in ha_innodb.h, and remove all the now needless local variables and casts in ha_innodb.cc. Revision r1298: ha_innodb.cc: Remove all references to thd->ha_data[hton->slot]. thd_to_trx(thd, hton): Accessor for getting the InnoDB trx object of a MySQL thread object and an InnoDB handlerton. Revision r1292: Remove the declarations of some global functions in ha_innodb.h and declare them static in ha_innodb.cc. These functions are invoked via function pointers in handlerton. Revision r1300: ha_innodb.cc: Replace thd->tablespace_op with thd_tablespace_op(thd). Plugins must treat class THD as an opaque type. Revision r1198: Merge a change from MySQL AB: ChangeSet@1.2372, 2006-12-31 02:29:11+01:00, kent@mysql.com +79 -0 Many files: Removed "MySQL Finland AB & TCX DataKonsult AB" from copyright header Adjusted year(s) in copyright header Added GPL copyright text Revision r1271: Merge changes from MySQL AB: Rename some FIELD_TYPE_ constants to MYSQL_TYPE_. Change the scope of a type cast of two dividends. Revision r1299: ha_innodb.cc: Replace thd->in_lock_tables with thd_in_lock_tables(thd). Plugins must treat class THD as an opaque type. Revision r1201: Apply patch from MySQL: ChangeSet@1.2353, 2006-12-19 16:57:51-07:00, tsmith@siva.hindu.god +13 -0 Added innodb_rollback_on_timeout option to restore the 4.1 InnoDB timeout behavior (Bug 24200) Revision r1322: ha_innodb.cc: Remove the unused innobase_repl_ variables. Revision r1324: Merge changes from MySQL AB: ChangeSet@1.2452, 2007-02-23 13:13:55+02:00, monty@mysql.com +177 -0 Fixed compiler warnings ... Fixed compiler warnings detected on windows64 Revision r1334: Fix for Bug# 21409. At low transaction isolation levels we let each consistent read set its own snapshot storage/innobase/handler/ha_innodb.h: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1204: Change this in ha_innobase: void* innobase_prebuilt; to this: row_prebuilt_t* prebuilt; by introducing the typedef in ha_innodb.h, and remove all the now needless local variables and casts in ha_innodb.cc. Revision r1292: Remove the declarations of some global functions in ha_innodb.h and declare them static in ha_innodb.cc. These functions are invoked via function pointers in handlerton. Revision r1198: Merge a change from MySQL AB: ChangeSet@1.2372, 2006-12-31 02:29:11+01:00, kent@mysql.com +79 -0 Many files: Removed "MySQL Finland AB & TCX DataKonsult AB" from copyright header Adjusted year(s) in copyright header Added GPL copyright text Revision r1201: Apply patch from MySQL: ChangeSet@1.2353, 2006-12-19 16:57:51-07:00, tsmith@siva.hindu.god +13 -0 Added innodb_rollback_on_timeout option to restore the 4.1 InnoDB timeout behavior (Bug 24200) storage/innobase/ibuf/ibuf0ibuf.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/buf0buf.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/buf0flu.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/dict0dict.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/ha0ha.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/lock0lock.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/log0log.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/mem0mem.h: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1241: Remove the unused function mem_strdupq(). storage/innobase/include/mem0mem.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1241: Remove the unused function mem_strdupq(). storage/innobase/include/rem0rec.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1338: rec_offs_nth_size(): Treat n==0 as a special case. (Bug #26835) storage/innobase/include/sync0rw.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/sync0sync.h: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1247: Rename mutex_enter_nowait to mutex_enter_nowait_func and add macro mutex_enter_nowait that supplies the default __FILE__ and __LINE__ arguments. Adjust callers. storage/innobase/include/sync0sync.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1294: Fixed inline asm code, it didn't work with GCC > ver 3.x. Revision r1244: Add ut_ad() debug assertions. UT_LIST_ADD_FIRST(), UT_LIST_ADD_LAST(), UT_LIST_INSERT_AFTER(): Assert against some trivial cases of cyclic lists. mutex_enter_func(): Assert that the current thread is not holding the mutex. Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/trx0sys.ic: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/include/univ.i: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1285: Merge a change from MySQL AB: ChangeSet 2006/10/26 15:41:47-04:00 iggy@amd64. Post Merge Cleanup storage/innobase/include/univ.i 2006/10/26 15:38:50-04:00 iggy@amd64. +9 -0 Post Merge Cleanup storage/innobase/include/ut0lst.h: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1244: Add ut_ad() debug assertions. UT_LIST_ADD_FIRST(), UT_LIST_ADD_LAST(), UT_LIST_INSERT_AFTER(): Assert against some trivial cases of cyclic lists. mutex_enter_func(): Assert that the current thread is not holding the mutex. storage/innobase/lock/lock0lock.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1330: lock_deadlock_recursive(): When the search depth or length is exceeded, rewind lock_latest_err_file and display the two transactions at the point of aborting the search. (Bug #25494) Revision r1332: lock_deadlock_recursive(): When aborting the search, display a note regardless of start->undo_no. Otherwise, aborted searches may show up as genuine deadlocks. This mistake was made in r1330. storage/innobase/log/log0log.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1247: Rename mutex_enter_nowait to mutex_enter_nowait_func and add macro mutex_enter_nowait that supplies the default __FILE__ and __LINE__ arguments. Adjust callers. storage/innobase/log/log0recv.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/mem/mem0pool.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/pars/pars0pars.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/que/que0que.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/read/read0read.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/row/row0mysql.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1201: Apply patch from MySQL: ChangeSet@1.2353, 2006-12-19 16:57:51-07:00, tsmith@siva.hindu.god +13 -0 Added innodb_rollback_on_timeout option to restore the 4.1 InnoDB timeout behavior (Bug 24200) Revision r1324: Merge changes from MySQL AB: ChangeSet@1.2452, 2007-02-23 13:13:55+02:00, monty@mysql.com +177 -0 Fixed compiler warnings ... Fixed compiler warnings detected on windows64 storage/innobase/row/row0vers.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/srv/srv0que.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/srv/srv0srv.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1262: Fix for Bug# 23666. On Windows ut_usectime returns secs and usecs relative to the UNIX epoch (which is Jan, 1 1970). Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/sync/sync0rw.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1247: Rename mutex_enter_nowait to mutex_enter_nowait_func and add macro mutex_enter_nowait that supplies the default __FILE__ and __LINE__ arguments. Adjust callers. Revision r1324: Merge changes from MySQL AB: ChangeSet@1.2452, 2007-02-23 13:13:55+02:00, monty@mysql.com +177 -0 Fixed compiler warnings ... Fixed compiler warnings detected on windows64 storage/innobase/sync/sync0sync.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1247: Rename mutex_enter_nowait to mutex_enter_nowait_func and add macro mutex_enter_nowait that supplies the default __FILE__ and __LINE__ arguments. Adjust callers. storage/innobase/thr/thr0loc.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/trx/trx0purge.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/trx/trx0roll.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/trx/trx0rseg.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/trx/trx0sys.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/trx/trx0trx.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. Revision r1324: Merge changes from MySQL AB: ChangeSet@1.2452, 2007-02-23 13:13:55+02:00, monty@mysql.com +177 -0 Fixed compiler warnings ... Fixed compiler warnings detected on windows64 storage/innobase/trx/trx0undo.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/usr/usr0sess.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1242: Merge r1239 from branches/zip: Make mutex_own() work with UNIV_DEBUG, without UNIV_SYNC_DEBUG. storage/innobase/ut/ut0ut.c: Apply the following InnoDB snapshots: innodb-5.1-ss1318 innodb-5.1-ss1330 innodb-5.1-ss1332 innodb-5.1-ss1340 Revision r1262: Fix for Bug# 23666. On Windows ut_usectime returns secs and usecs relative to the UNIX epoch (which is Jan, 1 1970).
1443 lines
34 KiB
C
1443 lines
34 KiB
C
/******************************************************
|
|
Query graph
|
|
|
|
(c) 1996 Innobase Oy
|
|
|
|
Created 5/27/1996 Heikki Tuuri
|
|
*******************************************************/
|
|
|
|
#include "que0que.h"
|
|
|
|
#ifdef UNIV_NONINL
|
|
#include "que0que.ic"
|
|
#endif
|
|
|
|
#include "srv0que.h"
|
|
#include "usr0sess.h"
|
|
#include "trx0trx.h"
|
|
#include "trx0roll.h"
|
|
#include "row0undo.h"
|
|
#include "row0ins.h"
|
|
#include "row0upd.h"
|
|
#include "row0sel.h"
|
|
#include "row0purge.h"
|
|
#include "dict0crea.h"
|
|
#include "log0log.h"
|
|
#include "eval0proc.h"
|
|
#include "eval0eval.h"
|
|
#include "pars0types.h"
|
|
|
|
#define QUE_PARALLELIZE_LIMIT (64 * 256 * 256 * 256)
|
|
#define QUE_ROUND_ROBIN_LIMIT (64 * 256 * 256 * 256)
|
|
#define QUE_MAX_LOOPS_WITHOUT_CHECK 16
|
|
|
|
/* If the following flag is set TRUE, the module will print trace info
|
|
of SQL execution in the UNIV_SQL_DEBUG version */
|
|
ibool que_trace_on = FALSE;
|
|
|
|
ibool que_always_false = FALSE;
|
|
|
|
/* Short introduction to query graphs
|
|
==================================
|
|
|
|
A query graph consists of nodes linked to each other in various ways. The
|
|
execution starts at que_run_threads() which takes a que_thr_t parameter.
|
|
que_thr_t contains two fields that control query graph execution: run_node
|
|
and prev_node. run_node is the next node to execute and prev_node is the
|
|
last node executed.
|
|
|
|
Each node has a pointer to a 'next' statement, i.e., its brother, and a
|
|
pointer to its parent node. The next pointer is NULL in the last statement
|
|
of a block.
|
|
|
|
Loop nodes contain a link to the first statement of the enclosed statement
|
|
list. While the loop runs, que_thr_step() checks if execution to the loop
|
|
node came from its parent or from one of the statement nodes in the loop. If
|
|
it came from the parent of the loop node it starts executing the first
|
|
statement node in the loop. If it came from one of the statement nodes in
|
|
the loop, then it checks if the statement node has another statement node
|
|
following it, and runs it if so.
|
|
|
|
To signify loop ending, the loop statements (see e.g. while_step()) set
|
|
que_thr_t->run_node to the loop node's parent node. This is noticed on the
|
|
next call of que_thr_step() and execution proceeds to the node pointed to by
|
|
the loop node's 'next' pointer.
|
|
|
|
For example, the code:
|
|
|
|
X := 1;
|
|
WHILE X < 5 LOOP
|
|
X := X + 1;
|
|
X := X + 1;
|
|
X := 5
|
|
|
|
will result in the following node hierarchy, with the X-axis indicating
|
|
'next' links and the Y-axis indicating parent/child links:
|
|
|
|
A - W - A
|
|
|
|
|
|
|
|
A - A
|
|
|
|
A = assign_node_t, W = while_node_t. */
|
|
|
|
/* How a stored procedure containing COMMIT or ROLLBACK commands
|
|
is executed?
|
|
|
|
The commit or rollback can be seen as a subprocedure call.
|
|
The problem is that if there are several query threads
|
|
currently running within the transaction, their action could
|
|
mess the commit or rollback operation. Or, at the least, the
|
|
operation would be difficult to visualize and keep in control.
|
|
|
|
Therefore the query thread requesting a commit or a rollback
|
|
sends to the transaction a signal, which moves the transaction
|
|
to TRX_QUE_SIGNALED state. All running query threads of the
|
|
transaction will eventually notice that the transaction is now in
|
|
this state and voluntarily suspend themselves. Only the last
|
|
query thread which suspends itself will trigger handling of
|
|
the signal.
|
|
|
|
When the transaction starts to handle a rollback or commit
|
|
signal, it builds a query graph which, when executed, will
|
|
roll back or commit the incomplete transaction. The transaction
|
|
is moved to the TRX_QUE_ROLLING_BACK or TRX_QUE_COMMITTING state.
|
|
If specified, the SQL cursors opened by the transaction are closed.
|
|
When the execution of the graph completes, it is like returning
|
|
from a subprocedure: the query thread which requested the operation
|
|
starts running again. */
|
|
|
|
/**************************************************************************
|
|
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
|
|
the n_active_thrs counters of the query graph and transaction.
|
|
***NOTE***: This is the only function in which such a transition is allowed
|
|
to happen! */
|
|
static
|
|
void
|
|
que_thr_move_to_run_state(
|
|
/*======================*/
|
|
que_thr_t* thr); /* in: an query thread */
|
|
|
|
/***************************************************************************
|
|
Adds a query graph to the session's list of graphs. */
|
|
|
|
void
|
|
que_graph_publish(
|
|
/*==============*/
|
|
que_t* graph, /* in: graph */
|
|
sess_t* sess) /* in: session */
|
|
{
|
|
ut_ad(mutex_own(&kernel_mutex));
|
|
|
|
UT_LIST_ADD_LAST(graphs, sess->graphs, graph);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Creates a query graph fork node. */
|
|
|
|
que_fork_t*
|
|
que_fork_create(
|
|
/*============*/
|
|
/* out, own: fork node */
|
|
que_t* graph, /* in: graph, if NULL then this
|
|
fork node is assumed to be the
|
|
graph root */
|
|
que_node_t* parent, /* in: parent node */
|
|
ulint fork_type, /* in: fork type */
|
|
mem_heap_t* heap) /* in: memory heap where created */
|
|
{
|
|
que_fork_t* fork;
|
|
|
|
ut_ad(heap);
|
|
|
|
fork = mem_heap_alloc(heap, sizeof(que_fork_t));
|
|
|
|
fork->common.type = QUE_NODE_FORK;
|
|
fork->n_active_thrs = 0;
|
|
|
|
fork->state = QUE_FORK_COMMAND_WAIT;
|
|
|
|
if (graph != NULL) {
|
|
fork->graph = graph;
|
|
} else {
|
|
fork->graph = fork;
|
|
}
|
|
|
|
fork->common.parent = parent;
|
|
fork->fork_type = fork_type;
|
|
|
|
fork->caller = NULL;
|
|
|
|
UT_LIST_INIT(fork->thrs);
|
|
|
|
fork->sym_tab = NULL;
|
|
fork->info = NULL;
|
|
|
|
fork->heap = heap;
|
|
|
|
return(fork);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Creates a query graph thread node. */
|
|
|
|
que_thr_t*
|
|
que_thr_create(
|
|
/*===========*/
|
|
/* out, own: query thread node */
|
|
que_fork_t* parent, /* in: parent node, i.e., a fork node */
|
|
mem_heap_t* heap) /* in: memory heap where created */
|
|
{
|
|
que_thr_t* thr;
|
|
|
|
ut_ad(parent && heap);
|
|
|
|
thr = mem_heap_alloc(heap, sizeof(que_thr_t));
|
|
|
|
thr->common.type = QUE_NODE_THR;
|
|
thr->common.parent = parent;
|
|
|
|
thr->magic_n = QUE_THR_MAGIC_N;
|
|
|
|
thr->graph = parent->graph;
|
|
|
|
thr->state = QUE_THR_COMMAND_WAIT;
|
|
|
|
thr->is_active = FALSE;
|
|
|
|
thr->run_node = NULL;
|
|
thr->resource = 0;
|
|
thr->lock_state = QUE_THR_LOCK_NOLOCK;
|
|
|
|
UT_LIST_ADD_LAST(thrs, parent->thrs, thr);
|
|
|
|
return(thr);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Moves a suspended query thread to the QUE_THR_RUNNING state and may release
|
|
a single worker thread to execute it. This function should be used to end
|
|
the wait state of a query thread waiting for a lock or a stored procedure
|
|
completion. */
|
|
|
|
void
|
|
que_thr_end_wait(
|
|
/*=============*/
|
|
que_thr_t* thr, /* in: query thread in the
|
|
QUE_THR_LOCK_WAIT,
|
|
or QUE_THR_PROCEDURE_WAIT, or
|
|
QUE_THR_SIG_REPLY_WAIT state */
|
|
que_thr_t** next_thr) /* in/out: next query thread to run;
|
|
if the value which is passed in is
|
|
a pointer to a NULL pointer, then the
|
|
calling function can start running
|
|
a new query thread; if NULL is passed
|
|
as the parameter, it is ignored */
|
|
{
|
|
ibool was_active;
|
|
|
|
ut_ad(mutex_own(&kernel_mutex));
|
|
ut_ad(thr);
|
|
ut_ad((thr->state == QUE_THR_LOCK_WAIT)
|
|
|| (thr->state == QUE_THR_PROCEDURE_WAIT)
|
|
|| (thr->state == QUE_THR_SIG_REPLY_WAIT));
|
|
ut_ad(thr->run_node);
|
|
|
|
thr->prev_node = thr->run_node;
|
|
|
|
was_active = thr->is_active;
|
|
|
|
que_thr_move_to_run_state(thr);
|
|
|
|
if (was_active) {
|
|
|
|
return;
|
|
}
|
|
|
|
if (next_thr && *next_thr == NULL) {
|
|
*next_thr = thr;
|
|
} else {
|
|
ut_a(0);
|
|
srv_que_task_enqueue_low(thr);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
Same as que_thr_end_wait, but no parameter next_thr available. */
|
|
|
|
void
|
|
que_thr_end_wait_no_next_thr(
|
|
/*=========================*/
|
|
que_thr_t* thr) /* in: query thread in the QUE_THR_LOCK_WAIT,
|
|
or QUE_THR_PROCEDURE_WAIT, or
|
|
QUE_THR_SIG_REPLY_WAIT state */
|
|
{
|
|
ibool was_active;
|
|
|
|
ut_a(thr->state == QUE_THR_LOCK_WAIT); /* In MySQL this is the
|
|
only possible state here */
|
|
ut_ad(mutex_own(&kernel_mutex));
|
|
ut_ad(thr);
|
|
ut_ad((thr->state == QUE_THR_LOCK_WAIT)
|
|
|| (thr->state == QUE_THR_PROCEDURE_WAIT)
|
|
|| (thr->state == QUE_THR_SIG_REPLY_WAIT));
|
|
|
|
was_active = thr->is_active;
|
|
|
|
que_thr_move_to_run_state(thr);
|
|
|
|
if (was_active) {
|
|
|
|
return;
|
|
}
|
|
|
|
/* In MySQL we let the OS thread (not just the query thread) to wait
|
|
for the lock to be released: */
|
|
|
|
srv_release_mysql_thread_if_suspended(thr);
|
|
|
|
/* srv_que_task_enqueue_low(thr); */
|
|
}
|
|
|
|
/**************************************************************************
|
|
Inits a query thread for a command. */
|
|
UNIV_INLINE
|
|
void
|
|
que_thr_init_command(
|
|
/*=================*/
|
|
que_thr_t* thr) /* in: query thread */
|
|
{
|
|
thr->run_node = thr;
|
|
thr->prev_node = thr->common.parent;
|
|
|
|
que_thr_move_to_run_state(thr);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Starts execution of a command in a query fork. Picks a query thread which
|
|
is not in the QUE_THR_RUNNING state and moves it to that state. If none
|
|
can be chosen, a situation which may arise in parallelized fetches, NULL
|
|
is returned. */
|
|
|
|
que_thr_t*
|
|
que_fork_start_command(
|
|
/*===================*/
|
|
/* out: a query thread of the graph moved to
|
|
QUE_THR_RUNNING state, or NULL; the query
|
|
thread should be executed by que_run_threads
|
|
by the caller */
|
|
que_fork_t* fork) /* in: a query fork */
|
|
{
|
|
que_thr_t* thr;
|
|
que_thr_t* suspended_thr = NULL;
|
|
que_thr_t* completed_thr = NULL;
|
|
|
|
fork->state = QUE_FORK_ACTIVE;
|
|
|
|
fork->last_sel_node = NULL;
|
|
|
|
/* Choose the query thread to run: usually there is just one thread,
|
|
but in a parallelized select, which necessarily is non-scrollable,
|
|
there may be several to choose from */
|
|
|
|
/* First we try to find a query thread in the QUE_THR_COMMAND_WAIT
|
|
state. Then we try to find a query thread in the QUE_THR_SUSPENDED
|
|
state, finally we try to find a query thread in the QUE_THR_COMPLETED
|
|
state */
|
|
|
|
thr = UT_LIST_GET_FIRST(fork->thrs);
|
|
|
|
/* We make a single pass over the thr list within which we note which
|
|
threads are ready to run. */
|
|
while (thr) {
|
|
switch (thr->state) {
|
|
case QUE_THR_COMMAND_WAIT:
|
|
|
|
/* We have to send the initial message to query thread
|
|
to start it */
|
|
|
|
que_thr_init_command(thr);
|
|
|
|
return(thr);
|
|
|
|
case QUE_THR_SUSPENDED:
|
|
/* In this case the execution of the thread was
|
|
suspended: no initial message is needed because
|
|
execution can continue from where it was left */
|
|
if (!suspended_thr) {
|
|
suspended_thr = thr;
|
|
}
|
|
|
|
break;
|
|
|
|
case QUE_THR_COMPLETED:
|
|
if (!completed_thr) {
|
|
completed_thr = thr;
|
|
}
|
|
|
|
break;
|
|
|
|
case QUE_THR_LOCK_WAIT:
|
|
ut_error;
|
|
|
|
}
|
|
|
|
thr = UT_LIST_GET_NEXT(thrs, thr);
|
|
}
|
|
|
|
if (suspended_thr) {
|
|
|
|
thr = suspended_thr;
|
|
que_thr_move_to_run_state(thr);
|
|
|
|
} else if (completed_thr) {
|
|
|
|
thr = completed_thr;
|
|
que_thr_init_command(thr);
|
|
}
|
|
|
|
return(thr);
|
|
}
|
|
|
|
/**************************************************************************
|
|
After signal handling is finished, returns control to a query graph error
|
|
handling routine. (Currently, just returns the control to the root of the
|
|
graph so that the graph can communicate an error message to the client.) */
|
|
|
|
void
|
|
que_fork_error_handle(
|
|
/*==================*/
|
|
trx_t* trx __attribute__((unused)), /* in: trx */
|
|
que_t* fork) /* in: query graph which was run before signal
|
|
handling started, NULL not allowed */
|
|
{
|
|
que_thr_t* thr;
|
|
|
|
ut_ad(mutex_own(&kernel_mutex));
|
|
ut_ad(trx->sess->state == SESS_ERROR);
|
|
ut_ad(UT_LIST_GET_LEN(trx->reply_signals) == 0);
|
|
ut_ad(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
|
|
|
|
thr = UT_LIST_GET_FIRST(fork->thrs);
|
|
|
|
while (thr != NULL) {
|
|
ut_ad(!thr->is_active);
|
|
ut_ad(thr->state != QUE_THR_SIG_REPLY_WAIT);
|
|
ut_ad(thr->state != QUE_THR_LOCK_WAIT);
|
|
|
|
thr->run_node = thr;
|
|
thr->prev_node = thr->child;
|
|
thr->state = QUE_THR_COMPLETED;
|
|
|
|
thr = UT_LIST_GET_NEXT(thrs, thr);
|
|
}
|
|
|
|
thr = UT_LIST_GET_FIRST(fork->thrs);
|
|
|
|
que_thr_move_to_run_state(thr);
|
|
|
|
ut_a(0);
|
|
srv_que_task_enqueue_low(thr);
|
|
}
|
|
|
|
/********************************************************************
|
|
Tests if all the query threads in the same fork have a given state. */
|
|
UNIV_INLINE
|
|
ibool
|
|
que_fork_all_thrs_in_state(
|
|
/*=======================*/
|
|
/* out: TRUE if all the query threads in the
|
|
same fork were in the given state */
|
|
que_fork_t* fork, /* in: query fork */
|
|
ulint state) /* in: state */
|
|
{
|
|
que_thr_t* thr_node;
|
|
|
|
thr_node = UT_LIST_GET_FIRST(fork->thrs);
|
|
|
|
while (thr_node != NULL) {
|
|
if (thr_node->state != state) {
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
thr_node = UT_LIST_GET_NEXT(thrs, thr_node);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Calls que_graph_free_recursive for statements in a statement list. */
|
|
static
|
|
void
|
|
que_graph_free_stat_list(
|
|
/*=====================*/
|
|
que_node_t* node) /* in: first query graph node in the list */
|
|
{
|
|
while (node) {
|
|
que_graph_free_recursive(node);
|
|
|
|
node = que_node_get_next(node);
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
Frees a query graph, but not the heap where it was created. Does not free
|
|
explicit cursor declarations, they are freed in que_graph_free. */
|
|
|
|
void
|
|
que_graph_free_recursive(
|
|
/*=====================*/
|
|
que_node_t* node) /* in: query graph node */
|
|
{
|
|
que_fork_t* fork;
|
|
que_thr_t* thr;
|
|
undo_node_t* undo;
|
|
sel_node_t* sel;
|
|
ins_node_t* ins;
|
|
upd_node_t* upd;
|
|
tab_node_t* cre_tab;
|
|
ind_node_t* cre_ind;
|
|
|
|
if (node == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
switch (que_node_get_type(node)) {
|
|
|
|
case QUE_NODE_FORK:
|
|
fork = node;
|
|
|
|
thr = UT_LIST_GET_FIRST(fork->thrs);
|
|
|
|
while (thr) {
|
|
que_graph_free_recursive(thr);
|
|
|
|
thr = UT_LIST_GET_NEXT(thrs, thr);
|
|
}
|
|
|
|
break;
|
|
case QUE_NODE_THR:
|
|
|
|
thr = node;
|
|
|
|
if (thr->magic_n != QUE_THR_MAGIC_N) {
|
|
fprintf(stderr,
|
|
"que_thr struct appears corrupt;"
|
|
" magic n %lu\n",
|
|
(unsigned long) thr->magic_n);
|
|
mem_analyze_corruption(thr);
|
|
ut_error;
|
|
}
|
|
|
|
thr->magic_n = QUE_THR_MAGIC_FREED;
|
|
|
|
que_graph_free_recursive(thr->child);
|
|
|
|
break;
|
|
case QUE_NODE_UNDO:
|
|
|
|
undo = node;
|
|
|
|
mem_heap_free(undo->heap);
|
|
|
|
break;
|
|
case QUE_NODE_SELECT:
|
|
|
|
sel = node;
|
|
|
|
sel_node_free_private(sel);
|
|
|
|
break;
|
|
case QUE_NODE_INSERT:
|
|
|
|
ins = node;
|
|
|
|
que_graph_free_recursive(ins->select);
|
|
|
|
mem_heap_free(ins->entry_sys_heap);
|
|
|
|
break;
|
|
case QUE_NODE_UPDATE:
|
|
|
|
upd = node;
|
|
|
|
if (upd->in_mysql_interface) {
|
|
|
|
btr_pcur_free_for_mysql(upd->pcur);
|
|
}
|
|
|
|
que_graph_free_recursive(upd->cascade_node);
|
|
|
|
if (upd->cascade_heap) {
|
|
mem_heap_free(upd->cascade_heap);
|
|
}
|
|
|
|
que_graph_free_recursive(upd->select);
|
|
|
|
mem_heap_free(upd->heap);
|
|
|
|
break;
|
|
case QUE_NODE_CREATE_TABLE:
|
|
cre_tab = node;
|
|
|
|
que_graph_free_recursive(cre_tab->tab_def);
|
|
que_graph_free_recursive(cre_tab->col_def);
|
|
que_graph_free_recursive(cre_tab->commit_node);
|
|
|
|
mem_heap_free(cre_tab->heap);
|
|
|
|
break;
|
|
case QUE_NODE_CREATE_INDEX:
|
|
cre_ind = node;
|
|
|
|
que_graph_free_recursive(cre_ind->ind_def);
|
|
que_graph_free_recursive(cre_ind->field_def);
|
|
que_graph_free_recursive(cre_ind->commit_node);
|
|
|
|
mem_heap_free(cre_ind->heap);
|
|
|
|
break;
|
|
case QUE_NODE_PROC:
|
|
que_graph_free_stat_list(((proc_node_t*)node)->stat_list);
|
|
|
|
break;
|
|
case QUE_NODE_IF:
|
|
que_graph_free_stat_list(((if_node_t*)node)->stat_list);
|
|
que_graph_free_stat_list(((if_node_t*)node)->else_part);
|
|
que_graph_free_stat_list(((if_node_t*)node)->elsif_list);
|
|
|
|
break;
|
|
case QUE_NODE_ELSIF:
|
|
que_graph_free_stat_list(((elsif_node_t*)node)->stat_list);
|
|
|
|
break;
|
|
case QUE_NODE_WHILE:
|
|
que_graph_free_stat_list(((while_node_t*)node)->stat_list);
|
|
|
|
break;
|
|
case QUE_NODE_FOR:
|
|
que_graph_free_stat_list(((for_node_t*)node)->stat_list);
|
|
|
|
break;
|
|
|
|
case QUE_NODE_ASSIGNMENT:
|
|
case QUE_NODE_EXIT:
|
|
case QUE_NODE_RETURN:
|
|
case QUE_NODE_COMMIT:
|
|
case QUE_NODE_ROLLBACK:
|
|
case QUE_NODE_LOCK:
|
|
case QUE_NODE_FUNC:
|
|
case QUE_NODE_ORDER:
|
|
case QUE_NODE_ROW_PRINTF:
|
|
case QUE_NODE_OPEN:
|
|
case QUE_NODE_FETCH:
|
|
/* No need to do anything */
|
|
|
|
break;
|
|
default:
|
|
fprintf(stderr,
|
|
"que_node struct appears corrupt; type %lu\n",
|
|
(unsigned long) que_node_get_type(node));
|
|
mem_analyze_corruption(node);
|
|
ut_error;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************
|
|
Frees a query graph. */
|
|
|
|
void
|
|
que_graph_free(
|
|
/*===========*/
|
|
que_t* graph) /* in: query graph; we assume that the memory
|
|
heap where this graph was created is private
|
|
to this graph: if not, then use
|
|
que_graph_free_recursive and free the heap
|
|
afterwards! */
|
|
{
|
|
ut_ad(graph);
|
|
|
|
if (graph->sym_tab) {
|
|
/* The following call frees dynamic memory allocated
|
|
for variables etc. during execution. Frees also explicit
|
|
cursor definitions. */
|
|
|
|
sym_tab_free_private(graph->sym_tab);
|
|
}
|
|
|
|
if (graph->info && graph->info->graph_owns_us) {
|
|
pars_info_free(graph->info);
|
|
}
|
|
|
|
que_graph_free_recursive(graph);
|
|
|
|
mem_heap_free(graph->heap);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Checks if the query graph is in a state where it should be freed, and
|
|
frees it in that case. If the session is in a state where it should be
|
|
closed, also this is done. */
|
|
|
|
ibool
|
|
que_graph_try_free(
|
|
/*===============*/
|
|
/* out: TRUE if freed */
|
|
que_t* graph) /* in: query graph */
|
|
{
|
|
sess_t* sess;
|
|
|
|
ut_ad(mutex_own(&kernel_mutex));
|
|
|
|
sess = (graph->trx)->sess;
|
|
|
|
if ((graph->state == QUE_FORK_BEING_FREED)
|
|
&& (graph->n_active_thrs == 0)) {
|
|
|
|
UT_LIST_REMOVE(graphs, sess->graphs, graph);
|
|
que_graph_free(graph);
|
|
|
|
sess_try_close(sess);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
/********************************************************************
|
|
Performs an execution step on a thr node. */
|
|
static
|
|
que_thr_t*
|
|
que_thr_node_step(
|
|
/*==============*/
|
|
/* out: query thread to run next, or NULL
|
|
if none */
|
|
que_thr_t* thr) /* in: query thread where run_node must
|
|
be the thread node itself */
|
|
{
|
|
ut_ad(thr->run_node == thr);
|
|
|
|
if (thr->prev_node == thr->common.parent) {
|
|
/* If control to the node came from above, it is just passed
|
|
on */
|
|
|
|
thr->run_node = thr->child;
|
|
|
|
return(thr);
|
|
}
|
|
|
|
mutex_enter(&kernel_mutex);
|
|
|
|
if (que_thr_peek_stop(thr)) {
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
|
|
return(thr);
|
|
}
|
|
|
|
/* Thread execution completed */
|
|
|
|
thr->state = QUE_THR_COMPLETED;
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
|
|
the n_active_thrs counters of the query graph and transaction if thr was
|
|
not active.
|
|
***NOTE***: This and ..._mysql are the only functions in which such a
|
|
transition is allowed to happen! */
|
|
static
|
|
void
|
|
que_thr_move_to_run_state(
|
|
/*======================*/
|
|
que_thr_t* thr) /* in: an query thread */
|
|
{
|
|
trx_t* trx;
|
|
|
|
ut_ad(thr->state != QUE_THR_RUNNING);
|
|
|
|
trx = thr_get_trx(thr);
|
|
|
|
if (!thr->is_active) {
|
|
|
|
(thr->graph)->n_active_thrs++;
|
|
|
|
trx->n_active_thrs++;
|
|
|
|
thr->is_active = TRUE;
|
|
|
|
ut_ad((thr->graph)->n_active_thrs == 1);
|
|
ut_ad(trx->n_active_thrs == 1);
|
|
}
|
|
|
|
thr->state = QUE_THR_RUNNING;
|
|
}
|
|
|
|
/**************************************************************************
|
|
Decrements the query thread reference counts in the query graph and the
|
|
transaction. May start signal handling, e.g., a rollback.
|
|
*** NOTE ***:
|
|
This and que_thr_stop_for_mysql are the only functions where the reference
|
|
count can be decremented and this function may only be called from inside
|
|
que_run_threads or que_thr_check_if_switch! These restrictions exist to make
|
|
the rollback code easier to maintain. */
|
|
static
|
|
void
|
|
que_thr_dec_refer_count(
|
|
/*====================*/
|
|
que_thr_t* thr, /* in: query thread */
|
|
que_thr_t** next_thr) /* in/out: next query thread to run;
|
|
if the value which is passed in is
|
|
a pointer to a NULL pointer, then the
|
|
calling function can start running
|
|
a new query thread */
|
|
{
|
|
que_fork_t* fork;
|
|
trx_t* trx;
|
|
sess_t* sess;
|
|
ulint fork_type;
|
|
ibool stopped;
|
|
|
|
fork = thr->common.parent;
|
|
trx = thr_get_trx(thr);
|
|
sess = trx->sess;
|
|
|
|
mutex_enter(&kernel_mutex);
|
|
|
|
ut_a(thr->is_active);
|
|
|
|
if (thr->state == QUE_THR_RUNNING) {
|
|
|
|
stopped = que_thr_stop(thr);
|
|
|
|
if (!stopped) {
|
|
/* The reason for the thr suspension or wait was
|
|
already canceled before we came here: continue
|
|
running the thread */
|
|
|
|
/* fputs("!!!!!!!! Wait already ended: continue thr\n",
|
|
stderr); */
|
|
|
|
if (next_thr && *next_thr == NULL) {
|
|
/* Normally srv_suspend_mysql_thread resets
|
|
the state to DB_SUCCESS before waiting, but
|
|
in this case we have to do it here,
|
|
otherwise nobody does it. */
|
|
trx->error_state = DB_SUCCESS;
|
|
|
|
*next_thr = thr;
|
|
} else {
|
|
ut_a(0);
|
|
srv_que_task_enqueue_low(thr);
|
|
}
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
ut_ad(fork->n_active_thrs == 1);
|
|
ut_ad(trx->n_active_thrs == 1);
|
|
|
|
fork->n_active_thrs--;
|
|
trx->n_active_thrs--;
|
|
|
|
thr->is_active = FALSE;
|
|
|
|
if (trx->n_active_thrs > 0) {
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
|
|
return;
|
|
}
|
|
|
|
fork_type = fork->fork_type;
|
|
|
|
/* Check if all query threads in the same fork are completed */
|
|
|
|
if (que_fork_all_thrs_in_state(fork, QUE_THR_COMPLETED)) {
|
|
|
|
if (fork_type == QUE_FORK_ROLLBACK) {
|
|
/* This is really the undo graph used in rollback,
|
|
no roll_node in this graph */
|
|
|
|
ut_ad(UT_LIST_GET_LEN(trx->signals) > 0);
|
|
ut_ad(trx->handling_signals == TRUE);
|
|
|
|
trx_finish_rollback_off_kernel(fork, trx, next_thr);
|
|
|
|
} else if (fork_type == QUE_FORK_PURGE) {
|
|
|
|
/* Do nothing */
|
|
} else if (fork_type == QUE_FORK_RECOVERY) {
|
|
|
|
/* Do nothing */
|
|
} else if (fork_type == QUE_FORK_MYSQL_INTERFACE) {
|
|
|
|
/* Do nothing */
|
|
} else {
|
|
ut_error; /* not used in MySQL */
|
|
}
|
|
}
|
|
|
|
if (UT_LIST_GET_LEN(trx->signals) > 0 && trx->n_active_thrs == 0) {
|
|
|
|
/* If the trx is signaled and its query thread count drops to
|
|
zero, then we start processing a signal; from it we may get
|
|
a new query thread to run */
|
|
|
|
trx_sig_start_handle(trx, next_thr);
|
|
}
|
|
|
|
if (trx->handling_signals && UT_LIST_GET_LEN(trx->signals) == 0) {
|
|
|
|
trx_end_signal_handling(trx);
|
|
}
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Stops a query thread if graph or trx is in a state requiring it. The
|
|
conditions are tested in the order (1) graph, (2) trx. The kernel mutex has
|
|
to be reserved. */
|
|
|
|
ibool
|
|
que_thr_stop(
|
|
/*=========*/
|
|
/* out: TRUE if stopped */
|
|
que_thr_t* thr) /* in: query thread */
|
|
{
|
|
trx_t* trx;
|
|
que_t* graph;
|
|
ibool ret = TRUE;
|
|
|
|
ut_ad(mutex_own(&kernel_mutex));
|
|
|
|
graph = thr->graph;
|
|
trx = graph->trx;
|
|
|
|
if (graph->state == QUE_FORK_COMMAND_WAIT) {
|
|
thr->state = QUE_THR_SUSPENDED;
|
|
|
|
} else if (trx->que_state == TRX_QUE_LOCK_WAIT) {
|
|
|
|
UT_LIST_ADD_FIRST(trx_thrs, trx->wait_thrs, thr);
|
|
thr->state = QUE_THR_LOCK_WAIT;
|
|
|
|
} else if (trx->error_state != DB_SUCCESS
|
|
&& trx->error_state != DB_LOCK_WAIT) {
|
|
|
|
/* Error handling built for the MySQL interface */
|
|
thr->state = QUE_THR_COMPLETED;
|
|
|
|
} else if (UT_LIST_GET_LEN(trx->signals) > 0
|
|
&& graph->fork_type != QUE_FORK_ROLLBACK) {
|
|
|
|
thr->state = QUE_THR_SUSPENDED;
|
|
} else {
|
|
ut_ad(graph->state == QUE_FORK_ACTIVE);
|
|
|
|
ret = FALSE;
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
|
|
/**************************************************************************
|
|
A patch for MySQL used to 'stop' a dummy query thread used in MySQL. The
|
|
query thread is stopped and made inactive, except in the case where
|
|
it was put to the lock wait state in lock0lock.c, but the lock has already
|
|
been granted or the transaction chosen as a victim in deadlock resolution. */
|
|
|
|
void
|
|
que_thr_stop_for_mysql(
|
|
/*===================*/
|
|
que_thr_t* thr) /* in: query thread */
|
|
{
|
|
trx_t* trx;
|
|
|
|
trx = thr_get_trx(thr);
|
|
|
|
mutex_enter(&kernel_mutex);
|
|
|
|
if (thr->state == QUE_THR_RUNNING) {
|
|
|
|
if (trx->error_state != DB_SUCCESS
|
|
&& trx->error_state != DB_LOCK_WAIT) {
|
|
|
|
/* Error handling built for the MySQL interface */
|
|
thr->state = QUE_THR_COMPLETED;
|
|
} else {
|
|
/* It must have been a lock wait but the lock was
|
|
already released, or this transaction was chosen
|
|
as a victim in selective deadlock resolution */
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
ut_ad(thr->is_active == TRUE);
|
|
ut_ad(trx->n_active_thrs == 1);
|
|
ut_ad(thr->graph->n_active_thrs == 1);
|
|
|
|
thr->is_active = FALSE;
|
|
(thr->graph)->n_active_thrs--;
|
|
|
|
trx->n_active_thrs--;
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Moves a thread from another state to the QUE_THR_RUNNING state. Increments
|
|
the n_active_thrs counters of the query graph and transaction if thr was
|
|
not active. */
|
|
|
|
void
|
|
que_thr_move_to_run_state_for_mysql(
|
|
/*================================*/
|
|
que_thr_t* thr, /* in: an query thread */
|
|
trx_t* trx) /* in: transaction */
|
|
{
|
|
if (thr->magic_n != QUE_THR_MAGIC_N) {
|
|
fprintf(stderr,
|
|
"que_thr struct appears corrupt; magic n %lu\n",
|
|
(unsigned long) thr->magic_n);
|
|
|
|
mem_analyze_corruption(thr);
|
|
|
|
ut_error;
|
|
}
|
|
|
|
if (!thr->is_active) {
|
|
|
|
thr->graph->n_active_thrs++;
|
|
|
|
trx->n_active_thrs++;
|
|
|
|
thr->is_active = TRUE;
|
|
}
|
|
|
|
thr->state = QUE_THR_RUNNING;
|
|
}
|
|
|
|
/**************************************************************************
|
|
A patch for MySQL used to 'stop' a dummy query thread used in MySQL
|
|
select, when there is no error or lock wait. */
|
|
|
|
void
|
|
que_thr_stop_for_mysql_no_error(
|
|
/*============================*/
|
|
que_thr_t* thr, /* in: query thread */
|
|
trx_t* trx) /* in: transaction */
|
|
{
|
|
ut_ad(thr->state == QUE_THR_RUNNING);
|
|
ut_ad(thr->is_active == TRUE);
|
|
ut_ad(trx->n_active_thrs == 1);
|
|
ut_ad(thr->graph->n_active_thrs == 1);
|
|
|
|
if (thr->magic_n != QUE_THR_MAGIC_N) {
|
|
fprintf(stderr,
|
|
"que_thr struct appears corrupt; magic n %lu\n",
|
|
(unsigned long) thr->magic_n);
|
|
|
|
mem_analyze_corruption(thr);
|
|
|
|
ut_error;
|
|
}
|
|
|
|
thr->state = QUE_THR_COMPLETED;
|
|
|
|
thr->is_active = FALSE;
|
|
(thr->graph)->n_active_thrs--;
|
|
|
|
trx->n_active_thrs--;
|
|
}
|
|
|
|
/********************************************************************
|
|
Get the first containing loop node (e.g. while_node_t or for_node_t) for the
|
|
given node, or NULL if the node is not within a loop. */
|
|
|
|
que_node_t*
|
|
que_node_get_containing_loop_node(
|
|
/*==============================*/
|
|
/* out: containing loop node, or NULL. */
|
|
que_node_t* node) /* in: node */
|
|
{
|
|
ut_ad(node);
|
|
|
|
for (;;) {
|
|
ulint type;
|
|
|
|
node = que_node_get_parent(node);
|
|
|
|
if (!node) {
|
|
break;
|
|
}
|
|
|
|
type = que_node_get_type(node);
|
|
|
|
if ((type == QUE_NODE_FOR) || (type == QUE_NODE_WHILE)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(node);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Prints info of an SQL query graph node. */
|
|
|
|
void
|
|
que_node_print_info(
|
|
/*================*/
|
|
que_node_t* node) /* in: query graph node */
|
|
{
|
|
ulint type;
|
|
const char* str;
|
|
|
|
type = que_node_get_type(node);
|
|
|
|
if (type == QUE_NODE_SELECT) {
|
|
str = "SELECT";
|
|
} else if (type == QUE_NODE_INSERT) {
|
|
str = "INSERT";
|
|
} else if (type == QUE_NODE_UPDATE) {
|
|
str = "UPDATE";
|
|
} else if (type == QUE_NODE_WHILE) {
|
|
str = "WHILE";
|
|
} else if (type == QUE_NODE_ASSIGNMENT) {
|
|
str = "ASSIGNMENT";
|
|
} else if (type == QUE_NODE_IF) {
|
|
str = "IF";
|
|
} else if (type == QUE_NODE_FETCH) {
|
|
str = "FETCH";
|
|
} else if (type == QUE_NODE_OPEN) {
|
|
str = "OPEN";
|
|
} else if (type == QUE_NODE_PROC) {
|
|
str = "STORED PROCEDURE";
|
|
} else if (type == QUE_NODE_FUNC) {
|
|
str = "FUNCTION";
|
|
} else if (type == QUE_NODE_LOCK) {
|
|
str = "LOCK";
|
|
} else if (type == QUE_NODE_THR) {
|
|
str = "QUERY THREAD";
|
|
} else if (type == QUE_NODE_COMMIT) {
|
|
str = "COMMIT";
|
|
} else if (type == QUE_NODE_UNDO) {
|
|
str = "UNDO ROW";
|
|
} else if (type == QUE_NODE_PURGE) {
|
|
str = "PURGE ROW";
|
|
} else if (type == QUE_NODE_ROLLBACK) {
|
|
str = "ROLLBACK";
|
|
} else if (type == QUE_NODE_CREATE_TABLE) {
|
|
str = "CREATE TABLE";
|
|
} else if (type == QUE_NODE_CREATE_INDEX) {
|
|
str = "CREATE INDEX";
|
|
} else if (type == QUE_NODE_FOR) {
|
|
str = "FOR LOOP";
|
|
} else if (type == QUE_NODE_RETURN) {
|
|
str = "RETURN";
|
|
} else if (type == QUE_NODE_EXIT) {
|
|
str = "EXIT";
|
|
} else {
|
|
str = "UNKNOWN NODE TYPE";
|
|
}
|
|
|
|
fprintf(stderr, "Node type %lu: %s, address %p\n",
|
|
(ulong) type, str, (void*) node);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Performs an execution step on a query thread. */
|
|
UNIV_INLINE
|
|
que_thr_t*
|
|
que_thr_step(
|
|
/*=========*/
|
|
/* out: query thread to run next: it may
|
|
differ from the input parameter if, e.g., a
|
|
subprocedure call is made */
|
|
que_thr_t* thr) /* in: query thread */
|
|
{
|
|
que_node_t* node;
|
|
que_thr_t* old_thr;
|
|
trx_t* trx;
|
|
ulint type;
|
|
|
|
trx = thr_get_trx(thr);
|
|
|
|
ut_ad(thr->state == QUE_THR_RUNNING);
|
|
ut_a(trx->error_state == DB_SUCCESS);
|
|
|
|
thr->resource++;
|
|
|
|
node = thr->run_node;
|
|
type = que_node_get_type(node);
|
|
|
|
old_thr = thr;
|
|
|
|
#ifdef UNIV_DEBUG
|
|
if (que_trace_on) {
|
|
fputs("To execute: ", stderr);
|
|
que_node_print_info(node);
|
|
}
|
|
#endif
|
|
if (type & QUE_NODE_CONTROL_STAT) {
|
|
if ((thr->prev_node != que_node_get_parent(node))
|
|
&& que_node_get_next(thr->prev_node)) {
|
|
|
|
/* The control statements, like WHILE, always pass the
|
|
control to the next child statement if there is any
|
|
child left */
|
|
|
|
thr->run_node = que_node_get_next(thr->prev_node);
|
|
|
|
} else if (type == QUE_NODE_IF) {
|
|
if_step(thr);
|
|
} else if (type == QUE_NODE_FOR) {
|
|
for_step(thr);
|
|
} else if (type == QUE_NODE_PROC) {
|
|
|
|
/* We can access trx->undo_no without reserving
|
|
trx->undo_mutex, because there cannot be active query
|
|
threads doing updating or inserting at the moment! */
|
|
|
|
if (thr->prev_node == que_node_get_parent(node)) {
|
|
trx->last_sql_stat_start.least_undo_no
|
|
= trx->undo_no;
|
|
}
|
|
|
|
proc_step(thr);
|
|
} else if (type == QUE_NODE_WHILE) {
|
|
while_step(thr);
|
|
} else {
|
|
ut_error;
|
|
}
|
|
} else if (type == QUE_NODE_ASSIGNMENT) {
|
|
assign_step(thr);
|
|
} else if (type == QUE_NODE_SELECT) {
|
|
thr = row_sel_step(thr);
|
|
} else if (type == QUE_NODE_INSERT) {
|
|
thr = row_ins_step(thr);
|
|
} else if (type == QUE_NODE_UPDATE) {
|
|
thr = row_upd_step(thr);
|
|
} else if (type == QUE_NODE_FETCH) {
|
|
thr = fetch_step(thr);
|
|
} else if (type == QUE_NODE_OPEN) {
|
|
thr = open_step(thr);
|
|
} else if (type == QUE_NODE_FUNC) {
|
|
proc_eval_step(thr);
|
|
|
|
} else if (type == QUE_NODE_LOCK) {
|
|
|
|
ut_error;
|
|
/*
|
|
thr = que_lock_step(thr);
|
|
*/
|
|
} else if (type == QUE_NODE_THR) {
|
|
thr = que_thr_node_step(thr);
|
|
} else if (type == QUE_NODE_COMMIT) {
|
|
thr = trx_commit_step(thr);
|
|
} else if (type == QUE_NODE_UNDO) {
|
|
thr = row_undo_step(thr);
|
|
} else if (type == QUE_NODE_PURGE) {
|
|
thr = row_purge_step(thr);
|
|
} else if (type == QUE_NODE_RETURN) {
|
|
thr = return_step(thr);
|
|
} else if (type == QUE_NODE_EXIT) {
|
|
thr = exit_step(thr);
|
|
} else if (type == QUE_NODE_ROLLBACK) {
|
|
thr = trx_rollback_step(thr);
|
|
} else if (type == QUE_NODE_CREATE_TABLE) {
|
|
thr = dict_create_table_step(thr);
|
|
} else if (type == QUE_NODE_CREATE_INDEX) {
|
|
thr = dict_create_index_step(thr);
|
|
} else if (type == QUE_NODE_ROW_PRINTF) {
|
|
thr = row_printf_step(thr);
|
|
} else {
|
|
ut_error;
|
|
}
|
|
|
|
if (type == QUE_NODE_EXIT) {
|
|
old_thr->prev_node = que_node_get_containing_loop_node(node);
|
|
} else {
|
|
old_thr->prev_node = node;
|
|
}
|
|
|
|
if (thr) {
|
|
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
|
|
}
|
|
|
|
return(thr);
|
|
}
|
|
|
|
/**************************************************************************
|
|
Run a query thread until it finishes or encounters e.g. a lock wait. */
|
|
static
|
|
void
|
|
que_run_threads_low(
|
|
/*================*/
|
|
que_thr_t* thr) /* in: query thread */
|
|
{
|
|
que_thr_t* next_thr;
|
|
ulint cumul_resource;
|
|
ulint loop_count;
|
|
|
|
ut_ad(thr->state == QUE_THR_RUNNING);
|
|
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
|
|
ut_ad(!mutex_own(&kernel_mutex));
|
|
|
|
/* cumul_resource counts how much resources the OS thread (NOT the
|
|
query thread) has spent in this function */
|
|
|
|
loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
|
|
cumul_resource = 0;
|
|
loop:
|
|
/* Check that there is enough space in the log to accommodate
|
|
possible log entries by this query step; if the operation can touch
|
|
more than about 4 pages, checks must be made also within the query
|
|
step! */
|
|
|
|
log_free_check();
|
|
|
|
/* Perform the actual query step: note that the query thread
|
|
may change if, e.g., a subprocedure call is made */
|
|
|
|
/*-------------------------*/
|
|
next_thr = que_thr_step(thr);
|
|
/*-------------------------*/
|
|
|
|
ut_a(!next_thr || (thr_get_trx(next_thr)->error_state == DB_SUCCESS));
|
|
|
|
loop_count++;
|
|
|
|
if (next_thr != thr) {
|
|
ut_a(next_thr == NULL);
|
|
|
|
/* This can change next_thr to a non-NULL value if there was
|
|
a lock wait that already completed. */
|
|
que_thr_dec_refer_count(thr, &next_thr);
|
|
|
|
if (next_thr == NULL) {
|
|
|
|
return;
|
|
}
|
|
|
|
loop_count = QUE_MAX_LOOPS_WITHOUT_CHECK;
|
|
|
|
thr = next_thr;
|
|
}
|
|
|
|
goto loop;
|
|
}
|
|
|
|
/**************************************************************************
|
|
Run a query thread. Handles lock waits. */
|
|
void
|
|
que_run_threads(
|
|
/*============*/
|
|
que_thr_t* thr) /* in: query thread */
|
|
{
|
|
loop:
|
|
ut_a(thr_get_trx(thr)->error_state == DB_SUCCESS);
|
|
que_run_threads_low(thr);
|
|
|
|
mutex_enter(&kernel_mutex);
|
|
|
|
switch (thr->state) {
|
|
|
|
case QUE_THR_RUNNING:
|
|
/* There probably was a lock wait, but it already ended
|
|
before we came here: continue running thr */
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
|
|
goto loop;
|
|
|
|
case QUE_THR_LOCK_WAIT:
|
|
mutex_exit(&kernel_mutex);
|
|
|
|
/* The ..._mysql_... function works also for InnoDB's
|
|
internal threads. Let us wait that the lock wait ends. */
|
|
|
|
srv_suspend_mysql_thread(thr);
|
|
|
|
if (thr_get_trx(thr)->error_state != DB_SUCCESS) {
|
|
/* thr was chosen as a deadlock victim or there was
|
|
a lock wait timeout */
|
|
|
|
que_thr_dec_refer_count(thr, NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
goto loop;
|
|
|
|
case QUE_THR_COMPLETED:
|
|
case QUE_THR_COMMAND_WAIT:
|
|
/* Do nothing */
|
|
break;
|
|
|
|
default:
|
|
ut_error;
|
|
}
|
|
|
|
mutex_exit(&kernel_mutex);
|
|
}
|
|
|
|
/*************************************************************************
|
|
Evaluate the given SQL. */
|
|
|
|
ulint
|
|
que_eval_sql(
|
|
/*=========*/
|
|
/* out: error code or DB_SUCCESS */
|
|
pars_info_t* info, /* in: info struct, or NULL */
|
|
const char* sql, /* in: SQL string */
|
|
ibool reserve_dict_mutex,
|
|
/* in: if TRUE, acquire/release
|
|
dict_sys->mutex around call to pars_sql. */
|
|
trx_t* trx) /* in: trx */
|
|
{
|
|
que_thr_t* thr;
|
|
que_t* graph;
|
|
|
|
ut_a(trx->error_state == DB_SUCCESS);
|
|
|
|
if (reserve_dict_mutex) {
|
|
mutex_enter(&dict_sys->mutex);
|
|
}
|
|
|
|
graph = pars_sql(info, sql);
|
|
|
|
if (reserve_dict_mutex) {
|
|
mutex_exit(&dict_sys->mutex);
|
|
}
|
|
|
|
ut_a(graph);
|
|
|
|
graph->trx = trx;
|
|
trx->graph = NULL;
|
|
|
|
graph->fork_type = QUE_FORK_MYSQL_INTERFACE;
|
|
|
|
ut_a(thr = que_fork_start_command(graph));
|
|
|
|
que_run_threads(thr);
|
|
|
|
que_graph_free(graph);
|
|
|
|
return(trx->error_state);
|
|
}
|