diff options
author | unknown <konstantin@mysql.com> | 2005-07-19 22:22:12 +0400 |
---|---|---|
committer | unknown <konstantin@mysql.com> | 2005-07-19 22:22:12 +0400 |
commit | cd4bce0244f588798060a6f04c004edfcc8c2b94 (patch) | |
tree | 830ecb8cde21d2fbd50c5ef14bdbfa2d7a79b607 /sql | |
parent | 185520584dff8f5f23ac719754e4ea2ca499b7ad (diff) | |
parent | de6f5ae5abd127923ce71c0d785e66fdf2ce249f (diff) | |
download | mariadb-git-cd4bce0244f588798060a6f04c004edfcc8c2b94.tar.gz |
Merge bk-internal.mysql.com:/home/bk/mysql-5.0
into mysql.com:/home/kostja/mysql/mysql-5.0-10760-new
sql/handler.cc:
Auto merged
sql/mysqld.cc:
Auto merged
Diffstat (limited to 'sql')
-rw-r--r-- | sql/examples/ha_archive.cc | 12 | ||||
-rw-r--r-- | sql/examples/ha_archive.h | 9 | ||||
-rw-r--r-- | sql/examples/ha_example.cc | 22 | ||||
-rw-r--r-- | sql/examples/ha_example.h | 4 | ||||
-rw-r--r-- | sql/examples/ha_tina.cc | 31 | ||||
-rw-r--r-- | sql/examples/ha_tina.h | 14 | ||||
-rw-r--r-- | sql/ha_berkeley.cc | 14 | ||||
-rw-r--r-- | sql/ha_berkeley.h | 7 | ||||
-rw-r--r-- | sql/ha_blackhole.cc | 28 | ||||
-rw-r--r-- | sql/ha_blackhole.h | 4 | ||||
-rw-r--r-- | sql/ha_federated.cc | 31 | ||||
-rw-r--r-- | sql/ha_federated.h | 6 | ||||
-rw-r--r-- | sql/ha_heap.cc | 24 | ||||
-rw-r--r-- | sql/ha_heap.h | 3 | ||||
-rw-r--r-- | sql/ha_innodb.cc | 27 | ||||
-rw-r--r-- | sql/ha_innodb.h | 14 | ||||
-rw-r--r-- | sql/ha_myisam.cc | 34 | ||||
-rw-r--r-- | sql/ha_myisam.h | 8 | ||||
-rw-r--r-- | sql/ha_myisammrg.cc | 24 | ||||
-rw-r--r-- | sql/ha_myisammrg.h | 2 | ||||
-rw-r--r-- | sql/ha_ndbcluster.cc | 5 | ||||
-rw-r--r-- | sql/handler.cc | 16 | ||||
-rw-r--r-- | sql/handler.h | 9 | ||||
-rw-r--r-- | sql/lock.cc | 19 | ||||
-rw-r--r-- | sql/mysqld.cc | 10 | ||||
-rw-r--r-- | sql/set_var.cc | 4 | ||||
-rw-r--r-- | sql/sql_class.cc | 20 | ||||
-rw-r--r-- | sql/sql_class.h | 24 | ||||
-rw-r--r-- | sql/sql_prepare.cc | 17 | ||||
-rw-r--r-- | sql/sql_select.cc | 20 | ||||
-rw-r--r-- | sql/sql_select.h | 2 |
31 files changed, 374 insertions, 90 deletions
diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index c362985f565..e5c35ae019d 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -149,7 +149,8 @@ static handlerton archive_hton = { 0, /* prepare */ 0, /* recover */ 0, /* commit_by_xid */ - 0 /* rollback_by_xid */ + 0, /* rollback_by_xid */ + HTON_NO_FLAGS }; @@ -208,6 +209,15 @@ bool archive_db_end() return FALSE; } +ha_archive::ha_archive(TABLE *table_arg) + :handler(&archive_hton, table_arg), delayed_insert(0), bulk_insert(0) +{ + /* Set our original buffer from pre-allocated memory */ + buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info); + + /* The size of the offset value we will use for position() */ + ref_length = sizeof(z_off_t); +} /* This method reads the header of a datafile and returns whether or not it was successful. diff --git a/sql/examples/ha_archive.h b/sql/examples/ha_archive.h index 3932b62980c..41835c5fb6f 100644 --- a/sql/examples/ha_archive.h +++ b/sql/examples/ha_archive.h @@ -58,14 +58,7 @@ class ha_archive: public handler bool bulk_insert; /* If we are performing a bulk insert */ public: - ha_archive(TABLE *table): handler(table), delayed_insert(0), bulk_insert(0) - { - /* Set our original buffer from pre-allocated memory */ - buffer.set((char *)byte_buffer, IO_SIZE, system_charset_info); - - /* The size of the offset value we will use for position() */ - ref_length = sizeof(z_off_t); - } + ha_archive(TABLE *table_arg); ~ha_archive() { } diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index 9da297ccd1f..2818c176cd3 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -72,6 +72,24 @@ #ifdef HAVE_EXAMPLE_DB #include "ha_example.h" + +static handlerton example_hton= { + "CSV", + 0, /* slot */ + 0, /* savepoint size. */ + 0, /* close_connection */ + 0, /* savepoint */ + 0, /* rollback to savepoint */ + 0, /* release savepoint */ + 0, /* commit */ + 0, /* rollback */ + 0, /* prepare */ + 0, /* recover */ + 0, /* commit_by_xid */ + 0, /* rollback_by_xid */ + HTON_NO_FLAGS +}; + /* Variables for example share methods */ static HASH example_open_tables; // Hash used to track open tables pthread_mutex_t example_mutex; // This is the mutex we use to init the hash @@ -179,6 +197,10 @@ static int free_share(EXAMPLE_SHARE *share) } +ha_example::ha_example(TABLE *table_arg) + :handler(&example_hton, table_arg) +{} + /* If frm_error() is called then we will use this to to find out what file extentions exist for the storage engine. This is also used by the default rename_table and diff --git a/sql/examples/ha_example.h b/sql/examples/ha_example.h index ae72e5bb275..37f38fe5210 100644 --- a/sql/examples/ha_example.h +++ b/sql/examples/ha_example.h @@ -45,9 +45,7 @@ class ha_example: public handler EXAMPLE_SHARE *share; /* Shared lock info */ public: - ha_example(TABLE *table): handler(table) - { - } + ha_example(TABLE *table_arg); ~ha_example() { } diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index a030960d08a..9c774c1f75c 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -54,6 +54,23 @@ pthread_mutex_t tina_mutex; static HASH tina_open_tables; static int tina_init= 0; +static handlerton tina_hton= { + "CSV", + 0, /* slot */ + 0, /* savepoint size. */ + 0, /* close_connection */ + 0, /* savepoint */ + 0, /* rollback to savepoint */ + 0, /* release savepoint */ + 0, /* commit */ + 0, /* rollback */ + 0, /* prepare */ + 0, /* recover */ + 0, /* commit_by_xid */ + 0, /* rollback_by_xid */ + HTON_NO_FLAGS +}; + /***************************************************************************** ** TINA tables *****************************************************************************/ @@ -228,6 +245,20 @@ byte * find_eoln(byte *data, off_t begin, off_t end) return 0; } + +ha_tina::ha_tina(TABLE *table_arg) + :handler(&tina_hton, table_arg), + /* + These definitions are found in hanler.h + These are not probably completely right. + */ + current_position(0), next_position(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH) +{ + /* Set our original buffers from pre-allocated memory */ + buffer.set(byte_buffer, IO_SIZE, system_charset_info); + chain= chain_buffer; +} + /* Encode a buffer into the quoted format. */ diff --git a/sql/examples/ha_tina.h b/sql/examples/ha_tina.h index 22193c01013..5679d77a4dc 100644 --- a/sql/examples/ha_tina.h +++ b/sql/examples/ha_tina.h @@ -49,18 +49,8 @@ class ha_tina: public handler byte chain_alloced; uint32 chain_size; - public: - ha_tina(TABLE *table): handler(table), - /* - These definitions are found in hanler.h - Theses are not probably completely right. - */ - current_position(0), next_position(0), chain_alloced(0), chain_size(DEFAULT_CHAIN_LENGTH) - { - /* Set our original buffers from pre-allocated memory */ - buffer.set(byte_buffer, IO_SIZE, system_charset_info); - chain = chain_buffer; - } +public: + ha_tina(TABLE *table_arg); ~ha_tina() { if (chain_alloced) diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 568fb727e63..26e743d4a71 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -120,7 +120,8 @@ static handlerton berkeley_hton = { NULL, /* prepare */ NULL, /* recover */ NULL, /* commit_by_xid */ - NULL /* rollback_by_xid */ + NULL, /* rollback_by_xid */ + HTON_CLOSE_CURSORS_AT_COMMIT }; typedef struct st_berkeley_trx_data { @@ -372,6 +373,17 @@ void berkeley_cleanup_log_files(void) /***************************************************************************** ** Berkeley DB tables *****************************************************************************/ + +ha_berkeley::ha_berkeley(TABLE *table_arg) + :handler(&berkeley_hton, table_arg), alloc_ptr(0), rec_buff(0), file(0), + int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ | + HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT | + HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | + HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX), + changed_rows(0), last_dup_key((uint) -1), version(0), using_ignore(0) +{} + + static const char *ha_berkeley_exts[] = { ha_berkeley_ext, NullS diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index f6376939445..aa92908ecde 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -85,12 +85,7 @@ class ha_berkeley: public handler DBT *get_pos(DBT *to, byte *pos); public: - ha_berkeley(TABLE *table): handler(table), alloc_ptr(0),rec_buff(0), file(0), - int_table_flags(HA_REC_NOT_IN_SEQ | HA_FAST_KEY_READ | - HA_NULL_IN_KEY | HA_CAN_INDEX_BLOBS | HA_NOT_EXACT_COUNT | - HA_PRIMARY_KEY_IN_READ_INDEX | HA_FILE_BASED | - HA_AUTO_PART_KEY | HA_TABLE_SCAN_ON_INDEX), - changed_rows(0),last_dup_key((uint) -1),version(0),using_ignore(0) {} + ha_berkeley(TABLE *table_arg); ~ha_berkeley() {} const char *table_type() const { return "BerkeleyDB"; } ulong index_flags(uint idx, uint part, bool all_parts) const; diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index 6abbe983f48..856a053db9e 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -24,6 +24,34 @@ #include "ha_blackhole.h" +/* Blackhole storage engine handlerton */ + +static handlerton myisam_hton= { + "BLACKHOLE", + 0, /* slot */ + 0, /* savepoint size. */ + 0, /* close_connection */ + 0, /* savepoint */ + 0, /* rollback to savepoint */ + 0, /* release savepoint */ + 0, /* commit */ + 0, /* rollback */ + 0, /* prepare */ + 0, /* recover */ + 0, /* commit_by_xid */ + 0, /* rollback_by_xid */ + HTON_NO_FLAGS +}; + +/***************************************************************************** +** BLACKHOLE tables +*****************************************************************************/ + +ha_blackhole::ha_blackhole(TABLE *table_arg) + :handler(&blackhole_hton, table_arg) +{} + + static const char *ha_blackhole_exts[] = { NullS }; diff --git a/sql/ha_blackhole.h b/sql/ha_blackhole.h index 84a386e17f8..2dccabf17cc 100644 --- a/sql/ha_blackhole.h +++ b/sql/ha_blackhole.h @@ -28,9 +28,7 @@ class ha_blackhole: public handler THR_LOCK thr_lock; public: - ha_blackhole(TABLE *table): handler(table) - { - } + ha_blackhole(TABLE *table_arg); ~ha_blackhole() { } diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index e0e35c6b866..1d7b8cda8e2 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -679,6 +679,37 @@ error: } +/* Federated storage engine handlerton */ + +static handlerton federated_hton= { + "FEDERATED", + 0, /* slot */ + 0, /* savepoint size. */ + 0, /* close_connection */ + 0, /* savepoint */ + 0, /* rollback to savepoint */ + 0, /* release savepoint */ + 0, /* commit */ + 0, /* rollback */ + 0, /* prepare */ + 0, /* recover */ + 0, /* commit_by_xid */ + 0, /* rollback_by_xid */ + HTON_NO_FLAGS +}; + + +/***************************************************************************** +** FEDERATED tables +*****************************************************************************/ + +ha_federated::ha_federated(TABLE *table_arg) + :handler(&federated_hton, table_arg), + mysql(0), stored_result(0), scan_flag(0), + ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0) +{} + + /* Convert MySQL result set row to handler internal format diff --git a/sql/ha_federated.h b/sql/ha_federated.h index 3e55419f266..58b78ab0dde 100644 --- a/sql/ha_federated.h +++ b/sql/ha_federated.h @@ -162,11 +162,7 @@ private: bool records_in_range); public: - ha_federated(TABLE *table): handler(table), - mysql(0), stored_result(0), scan_flag(0), - ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0) - { - } + ha_federated(TABLE *table_arg); ~ha_federated() { } diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 6e609a94be3..92a5fe0ea09 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -23,9 +23,33 @@ #include <myisampack.h> #include "ha_heap.h" +static handlerton heap_hton= { + "MEMORY", + 0, /* slot */ + 0, /* savepoint size. */ + 0, /* close_connection */ + 0, /* savepoint */ + 0, /* rollback to savepoint */ + 0, /* release savepoint */ + 0, /* commit */ + 0, /* rollback */ + 0, /* prepare */ + 0, /* recover */ + 0, /* commit_by_xid */ + 0, /* rollback_by_xid */ + HTON_NO_FLAGS +}; + /***************************************************************************** ** HEAP tables *****************************************************************************/ + +ha_heap::ha_heap(TABLE *table_arg) + :handler(&heap_hton, table_arg), file(0), records_changed(0), + key_stats_ok(0) +{} + + static const char *ha_heap_exts[] = { NullS }; diff --git a/sql/ha_heap.h b/sql/ha_heap.h index 7a97c727049..f7368436456 100644 --- a/sql/ha_heap.h +++ b/sql/ha_heap.h @@ -31,8 +31,7 @@ class ha_heap: public handler uint records_changed; bool key_stats_ok; public: - ha_heap(TABLE *table): handler(table), file(0), records_changed(0), - key_stats_ok(0) {} + ha_heap(TABLE *table); ~ha_heap() {} const char *table_type() const { diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 98199a22efe..69451493d4b 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -215,7 +215,14 @@ static handlerton innobase_hton = { innobase_xa_prepare, /* prepare */ innobase_xa_recover, /* recover */ innobase_commit_by_xid, /* commit_by_xid */ - innobase_rollback_by_xid /* rollback_by_xid */ + innobase_rollback_by_xid, /* rollback_by_xid */ + /* + For now when one opens a cursor, MySQL does not create an own + InnoDB consistent read view for it, and uses the view of the + currently active transaction. Therefore, cursors can not + survive COMMIT or ROLLBACK statements, which free this view. + */ + HTON_CLOSE_CURSORS_AT_COMMIT }; /********************************************************************* @@ -765,6 +772,24 @@ check_trx_exists( return(trx); } + +/************************************************************************* +Construct ha_innobase handler. */ + +ha_innobase::ha_innobase(TABLE *table_arg) + :handler(&innobase_hton, table_arg), + int_table_flags(HA_REC_NOT_IN_SEQ | + HA_NULL_IN_KEY | + HA_CAN_INDEX_BLOBS | + HA_CAN_SQL_HANDLER | + HA_NOT_EXACT_COUNT | + HA_PRIMARY_KEY_IN_READ_INDEX | + HA_TABLE_SCAN_ON_INDEX), + last_dup_key((uint) -1), + start_of_scan(0), + num_write_row(0) +{} + /************************************************************************* Updates the user_thd field in a handle and also allocates a new InnoDB transaction handle if needed, and updates the transaction fields in the diff --git a/sql/ha_innodb.h b/sql/ha_innodb.h index 90cae3998ed..1584a2182c9 100644 --- a/sql/ha_innodb.h +++ b/sql/ha_innodb.h @@ -81,19 +81,7 @@ class ha_innobase: public handler /* Init values for the class: */ public: - ha_innobase(TABLE *table): handler(table), - int_table_flags(HA_REC_NOT_IN_SEQ | - HA_NULL_IN_KEY | - HA_CAN_INDEX_BLOBS | - HA_CAN_SQL_HANDLER | - HA_NOT_EXACT_COUNT | - HA_PRIMARY_KEY_IN_READ_INDEX | - HA_TABLE_SCAN_ON_INDEX), - last_dup_key((uint) -1), - start_of_scan(0), - num_write_row(0) - { - } + ha_innobase(TABLE *table_arg); ~ha_innobase() {} /* Get the row type from the storage engine. If this method returns diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index e94b697e0bb..fefa05e92b0 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -44,6 +44,29 @@ TYPELIB myisam_recover_typelib= {array_elements(myisam_recover_names)-1,"", ** MyISAM tables *****************************************************************************/ +/* MyISAM handlerton */ + +static handlerton myisam_hton= { + "MyISAM", + 0, /* slot */ + 0, /* savepoint size. */ + 0, /* close_connection */ + 0, /* savepoint */ + 0, /* rollback to savepoint */ + 0, /* release savepoint */ + 0, /* commit */ + 0, /* rollback */ + 0, /* prepare */ + 0, /* recover */ + 0, /* commit_by_xid */ + 0, /* rollback_by_xid */ + /* + MyISAM doesn't support transactions and doesn't have + transaction-dependent context: cursors can survive a commit. + */ + HTON_NO_FLAGS +}; + // collect errors printed by mi_check routines static void mi_check_print_msg(MI_CHECK *param, const char* msg_type, @@ -123,6 +146,17 @@ void mi_check_print_warning(MI_CHECK *param, const char *fmt,...) } + +ha_myisam::ha_myisam(TABLE *table_arg) + :handler(&myisam_hton, table_arg), file(0), + int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | + HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | + HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME | + HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD), + can_enable_indexes(1) +{} + + static const char *ha_myisam_exts[] = { ".MYI", ".MYD", diff --git a/sql/ha_myisam.h b/sql/ha_myisam.h index bbd9721f8e2..ca684463311 100644 --- a/sql/ha_myisam.h +++ b/sql/ha_myisam.h @@ -43,13 +43,7 @@ class ha_myisam: public handler int repair(THD *thd, MI_CHECK ¶m, bool optimize); public: - ha_myisam(TABLE *table): handler(table), file(0), - int_table_flags(HA_NULL_IN_KEY | HA_CAN_FULLTEXT | HA_CAN_SQL_HANDLER | - HA_DUPP_POS | HA_CAN_INDEX_BLOBS | HA_AUTO_PART_KEY | - HA_FILE_BASED | HA_CAN_GEOMETRY | HA_READ_RND_SAME | - HA_CAN_INSERT_DELAYED | HA_CAN_BIT_FIELD), - can_enable_indexes(1) - {} + ha_myisam(TABLE *table_arg); ~ha_myisam() {} const char *table_type() const { return "MyISAM"; } const char *index_type(uint key_number); diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index 5d3f379081c..8c4b4e790b1 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -32,6 +32,30 @@ ** MyISAM MERGE tables *****************************************************************************/ +/* MyISAM MERGE handlerton */ + +static handlerton myisammrg_hton= { + "MRG_MyISAM", + 0, /* slot */ + 0, /* savepoint size. */ + 0, /* close_connection */ + 0, /* savepoint */ + 0, /* rollback to savepoint */ + 0, /* release savepoint */ + 0, /* commit */ + 0, /* rollback */ + 0, /* prepare */ + 0, /* recover */ + 0, /* commit_by_xid */ + 0, /* rollback_by_xid */ + HTON_NO_FLAGS +}; + + +ha_myisammrg::ha_myisammrg(TABLE *table_arg) + :handler(&myisammrg_hton, table_arg), file(0) +{} + static const char *ha_myisammrg_exts[] = { ".MRG", NullS diff --git a/sql/ha_myisammrg.h b/sql/ha_myisammrg.h index 7348096b695..c762b7c286e 100644 --- a/sql/ha_myisammrg.h +++ b/sql/ha_myisammrg.h @@ -28,7 +28,7 @@ class ha_myisammrg: public handler MYRG_INFO *file; public: - ha_myisammrg(TABLE *table): handler(table), file(0) {} + ha_myisammrg(TABLE *table_arg); ~ha_myisammrg() {} const char *table_type() const { return "MRG_MyISAM"; } const char **bas_ext() const; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index d35b8af80aa..81723690b83 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -62,7 +62,8 @@ static handlerton ndbcluster_hton = { NULL, /* prepare */ NULL, /* recover */ NULL, /* commit_by_xid */ - NULL /* rollback_by_xid */ + NULL, /* rollback_by_xid */ + HTON_NO_FLAGS }; #define NDB_HIDDEN_PRIMARY_KEY_LENGTH 8 @@ -4174,7 +4175,7 @@ ulonglong ha_ndbcluster::get_auto_increment() */ ha_ndbcluster::ha_ndbcluster(TABLE *table_arg): - handler(table_arg), + handler(&ndbcluster_hton, table_arg), m_active_trans(NULL), m_active_cursor(NULL), m_table(NULL), diff --git a/sql/handler.cc b/sql/handler.cc index 9f8fdceb69e..0d0f9a75e52 100644 --- a/sql/handler.cc +++ b/sql/handler.cc @@ -208,15 +208,8 @@ handler *get_new_handler(TABLE *table, enum db_type db_type) case DB_TYPE_HASH: return new ha_hash(table); #endif -#ifdef HAVE_ISAM - case DB_TYPE_MRG_ISAM: - return new ha_isammrg(table); - case DB_TYPE_ISAM: - return new ha_isam(table); -#else case DB_TYPE_MRG_ISAM: return new ha_myisammrg(table); -#endif #ifdef HAVE_BERKELEY_DB case DB_TYPE_BERKELEY_DB: return new ha_berkeley(table); @@ -634,6 +627,11 @@ int ha_commit_trans(THD *thd, bool all) DBUG_RETURN(1); } DBUG_EXECUTE_IF("crash_commit_before", abort();); + + /* Close all cursors that can not survive COMMIT */ + if (is_real_trans) /* not a statement commit */ + thd->stmt_map.close_transient_cursors(); + if (!trans->no_2pc && trans->nht > 1) { for (; *ht && !error; ht++) @@ -735,6 +733,10 @@ int ha_rollback_trans(THD *thd, bool all) #ifdef USING_TRANSACTIONS if (trans->nht) { + /* Close all cursors that can not survive ROLLBACK */ + if (is_real_trans) /* not a statement commit */ + thd->stmt_map.close_transient_cursors(); + for (handlerton **ht=trans->ht; *ht; ht++) { int err; diff --git a/sql/handler.h b/sql/handler.h index df906e284e7..02b2353b890 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -349,8 +349,13 @@ typedef struct int (*recover)(XID *xid_list, uint len); int (*commit_by_xid)(XID *xid); int (*rollback_by_xid)(XID *xid); + uint32 flags; /* global handler flags */ } handlerton; +/* Possible flags of a handlerton */ +#define HTON_NO_FLAGS 0 +#define HTON_CLOSE_CURSORS_AT_COMMIT 1 + typedef struct st_thd_trans { /* number of entries in the ht[] */ @@ -445,6 +450,7 @@ class handler :public Sql_alloc virtual int rnd_end() { return 0; } public: + const handlerton *ht; /* storage engine of this handler */ byte *ref; /* Pointer to current row */ byte *dupp_ref; /* Pointer to dupp row */ ulonglong data_file_length; /* Length off data file */ @@ -486,7 +492,8 @@ public: bool implicit_emptied; /* Can be !=0 only if HEAP */ const COND *pushed_cond; - handler(TABLE *table_arg) :table(table_arg), + handler(const handlerton *ht_arg, TABLE *table_arg) :table(table_arg), + ht(ht_arg), ref(0), data_file_length(0), max_data_file_length(0), index_file_length(0), delete_length(0), auto_increment_value(0), records(0), deleted(0), mean_rec_length(0), diff --git a/sql/lock.cc b/sql/lock.cc index 7f3fe5ac5da..aa162a23b40 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -103,6 +103,10 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) { MYSQL_LOCK *sql_lock; TABLE *write_lock_used; + int rc; + /* Map the return value of thr_lock to an error from errmsg.txt */ + const static int thr_lock_errno_to_mysql[]= + { 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK }; DBUG_ENTER("mysql_lock_tables"); for (;;) @@ -135,15 +139,24 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) { my_free((gptr) sql_lock,MYF(0)); sql_lock=0; - thd->proc_info=0; break; } thd->proc_info="Table lock"; thd->locked=1; - if (thr_multi_lock(sql_lock->locks,sql_lock->lock_count)) + rc= thr_lock_errno_to_mysql[(int) thr_multi_lock(sql_lock->locks, + sql_lock->lock_count, + thd->lock_id)]; + if (rc > 1) /* a timeout or a deadlock */ + { + my_error(rc, MYF(0)); + my_free((gptr) sql_lock,MYF(0)); + sql_lock= 0; + break; + } + else if (rc == 1) /* aborted */ { thd->some_tables_deleted=1; // Try again - sql_lock->lock_count=0; // Locks are alread freed + sql_lock->lock_count= 0; // Locks are already freed } else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH)) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 6ddc9734ad8..30f7c1c6b3d 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4342,7 +4342,8 @@ enum options_mysqld OPT_ENABLE_LARGE_PAGES, OPT_TIMED_MUTEXES, OPT_OLD_STYLE_USER_LIMITS, - OPT_LOG_SLOW_ADMIN_STATEMENTS + OPT_LOG_SLOW_ADMIN_STATEMENTS, + OPT_TABLE_LOCK_WAIT_TIMEOUT }; @@ -5595,6 +5596,11 @@ The minimum value for this variable is 4096.", "The number of open tables for all threads.", (gptr*) &table_cache_size, (gptr*) &table_cache_size, 0, GET_ULONG, REQUIRED_ARG, 64, 1, 512*1024L, 0, 1, 0}, + {"table_lock_wait_timeout", OPT_TABLE_LOCK_WAIT_TIMEOUT, "Timeout in " + "seconds to wait for a table level lock before returning an error. Used" + " only if the connection has active cursors.", + (gptr*) &table_lock_wait_timeout, (gptr*) &table_lock_wait_timeout, + 0, GET_ULONG, REQUIRED_ARG, 50, 1, 1024 * 1024 * 1024, 0, 1, 0}, {"thread_cache_size", OPT_THREAD_CACHE_SIZE, "How many threads we should keep in a cache for reuse.", (gptr*) &thread_cache_size, (gptr*) &thread_cache_size, 0, GET_ULONG, @@ -7084,4 +7090,6 @@ template class I_List_iterator<THD>; template class I_List<i_string>; template class I_List<i_string_pair>; template class I_List<NAMED_LIST>; +template class I_List<Statement>; +template class I_List_iterator<Statement>; #endif diff --git a/sql/set_var.cc b/sql/set_var.cc index 2d7c3364e41..09581aed217 100644 --- a/sql/set_var.cc +++ b/sql/set_var.cc @@ -375,6 +375,8 @@ sys_var_thd_ulong sys_sync_replication_timeout( sys_var_bool_ptr sys_sync_frm("sync_frm", &opt_sync_frm); sys_var_long_ptr sys_table_cache_size("table_cache", &table_cache_size); +sys_var_long_ptr sys_table_lock_wait_timeout("table_lock_wait_timeout", + &table_lock_wait_timeout); sys_var_long_ptr sys_thread_cache_size("thread_cache_size", &thread_cache_size); sys_var_thd_enum sys_tx_isolation("tx_isolation", @@ -682,6 +684,7 @@ sys_var *sys_variables[]= #endif &sys_sync_frm, &sys_table_cache_size, + &sys_table_lock_wait_timeout, &sys_table_type, &sys_thread_cache_size, &sys_time_format, @@ -972,6 +975,7 @@ struct show_var_st init_vars[]= { {"system_time_zone", system_time_zone, SHOW_CHAR}, #endif {"table_cache", (char*) &table_cache_size, SHOW_LONG}, + {"table_lock_wait_timeout", (char*) &table_lock_wait_timeout, SHOW_LONG }, {sys_table_type.name, (char*) &sys_table_type, SHOW_SYS}, {sys_thread_cache_size.name,(char*) &sys_thread_cache_size, SHOW_SYS}, #ifdef HAVE_THR_SETCONCURRENCY diff --git a/sql/sql_class.cc b/sql/sql_class.cc index d0ac1a16f6b..89d5b543dfc 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -173,6 +173,7 @@ Open_tables_state::Open_tables_state() THD::THD() :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0), Open_tables_state(), + lock_id(&main_lock_id), user_time(0), global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), @@ -265,6 +266,8 @@ THD::THD() tablespace_op=FALSE; ulong tmp=sql_rnd_with_mutex(); randominit(&rand, tmp + (ulong) &rand, tmp + (ulong) ::query_id); + thr_lock_info_init(&lock_info); /* safety: will be reset after start */ + thr_lock_owner_init(&main_lock_id, &lock_info); } @@ -406,6 +409,8 @@ THD::~THD() net_end(&net); } #endif + stmt_map.destroy(); /* close all prepared statements */ + DBUG_ASSERT(lock_info.n_cursors == 0); if (!cleanup_done) cleanup(); @@ -518,6 +523,7 @@ bool THD::store_globals() if this is the slave SQL thread. */ variables.pseudo_thread_id= thread_id; + thr_lock_info_init(&lock_info); return 0; } @@ -1563,6 +1569,12 @@ void Statement::restore_backup_statement(Statement *stmt, Statement *backup) } +void Statement::close_cursor() +{ + DBUG_ASSERT("Statement::close_cursor()" == "not implemented"); +} + + void THD::end_statement() { /* Cleanup SQL processing state to resuse this statement in next query. */ @@ -1683,6 +1695,14 @@ int Statement_map::insert(Statement *statement) } +void Statement_map::close_transient_cursors() +{ + Statement *stmt; + while ((stmt= transient_cursor_list.head())) + stmt->close_cursor(); /* deletes itself from the list */ +} + + bool select_dumpvar::send_data(List<Item> &items) { List_iterator_fast<Item_func_set_user_var> li(vars); diff --git a/sql/sql_class.h b/sql/sql_class.h index 6c4315b95fa..d6847f5fb35 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -756,7 +756,7 @@ class Cursor; be used explicitly. */ -class Statement: public Query_arena +class Statement: public ilink, public Query_arena { Statement(const Statement &rhs); /* not implemented: */ Statement &operator=(const Statement &rhs); /* non-copyable */ @@ -833,6 +833,8 @@ public: void restore_backup_statement(Statement *stmt, Statement *backup); /* return class type */ virtual Type type() const; + /* Close the cursor open for this statement, if there is one */ + virtual void close_cursor(); }; @@ -884,15 +886,25 @@ public: } hash_delete(&st_hash, (byte *) statement); } + void add_transient_cursor(Statement *stmt) + { transient_cursor_list.append(stmt); } + void erase_transient_cursor(Statement *stmt) { stmt->unlink(); } + /* + Close all cursors of this connection that use tables of a storage + engine that has transaction-specific state and therefore can not + survive COMMIT or ROLLBACK. Currently all but MyISAM cursors are closed. + */ + void close_transient_cursors(); /* Erase all statements (calls Statement destructor) */ void reset() { my_hash_reset(&names_hash); my_hash_reset(&st_hash); + transient_cursor_list.empty(); last_found_statement= 0; } - ~Statement_map() + void destroy() { hash_free(&names_hash); hash_free(&st_hash); @@ -900,6 +912,7 @@ public: private: HASH st_hash; HASH names_hash; + I_List<Statement> transient_cursor_list; Statement *last_found_statement; }; @@ -1017,8 +1030,7 @@ public: a thread/connection descriptor */ -class THD :public ilink, - public Statement, +class THD :public Statement, public Open_tables_state { public: @@ -1044,6 +1056,10 @@ public: struct rand_struct rand; // used for authentication struct system_variables variables; // Changeable local variables struct system_status_var status_var; // Per thread statistic vars + THR_LOCK_INFO lock_info; // Locking info of this thread + THR_LOCK_OWNER main_lock_id; // To use for conventional queries + THR_LOCK_OWNER *lock_id; // If not main_lock_id, points to + // the lock_id of a cursor. pthread_mutex_t LOCK_delete; // Locked before thd is deleted /* all prepared statements and cursors of this connection */ Statement_map stmt_map; diff --git a/sql/sql_prepare.cc b/sql/sql_prepare.cc index aa47b506f73..b0f93463a8e 100644 --- a/sql/sql_prepare.cc +++ b/sql/sql_prepare.cc @@ -2020,6 +2020,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) DBUG_VOID_RETURN; /* If lex->result is set, mysql_execute_command will use it */ stmt->lex->result= &cursor->result; + thd->lock_id= &cursor->lock_id; } } #ifndef EMBEDDED_LIBRARY @@ -2069,6 +2070,9 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) Cursor::open is buried deep in JOIN::exec of the top level join. */ cursor->init_from_thd(thd); + + if (cursor->close_at_commit) + thd->stmt_map.add_transient_cursor(stmt); } else { @@ -2078,6 +2082,7 @@ void mysql_stmt_execute(THD *thd, char *packet, uint packet_length) } thd->set_statement(&stmt_backup); + thd->lock_id= &thd->main_lock_id; thd->current_arena= thd; DBUG_VOID_RETURN; @@ -2252,6 +2257,8 @@ void mysql_stmt_fetch(THD *thd, char *packet, uint packet_length) the previous calls. */ free_root(cursor->mem_root, MYF(0)); + if (cursor->close_at_commit) + thd->stmt_map.erase_transient_cursor(stmt); } thd->restore_backup_statement(stmt, &stmt_backup); @@ -2291,14 +2298,6 @@ void mysql_stmt_reset(THD *thd, char *packet) DBUG_VOID_RETURN; stmt->close_cursor(); /* will reset statement params */ - cursor= stmt->cursor; - if (cursor && cursor->is_open()) - { - thd->change_list= cursor->change_list; - cursor->close(FALSE); - cleanup_stmt_and_thd_after_use(stmt, thd); - free_root(cursor->mem_root, MYF(0)); - } stmt->state= Query_arena::PREPARED; @@ -2478,6 +2477,8 @@ void Prepared_statement::close_cursor() cursor->close(FALSE); cleanup_stmt_and_thd_after_use(this, thd); free_root(cursor->mem_root, MYF(0)); + if (cursor->close_at_commit) + thd->stmt_map.erase_transient_cursor(this); } /* Clear parameters from data which could be set by diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b333e369dc4..6147a1b62a5 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1702,10 +1702,12 @@ JOIN::destroy() Cursor::Cursor(THD *thd) :Query_arena(&main_mem_root, INITIALIZED), - join(0), unit(0) + join(0), unit(0), + close_at_commit(FALSE) { /* We will overwrite it at open anyway. */ init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); + thr_lock_owner_init(&lock_id, &thd->lock_info); } @@ -1739,6 +1741,21 @@ Cursor::init_from_thd(THD *thd) free_list= thd->free_list; change_list= thd->change_list; reset_thd(thd); + /* Now we have an active cursor and can cause a deadlock */ + thd->lock_info.n_cursors++; + + close_at_commit= FALSE; /* reset in case we're reusing the cursor */ + for (TABLE *table= open_tables; table; table= table->next) + { + const handlerton *ht= table->file->ht; + if (ht) + close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); + else + { + close_at_commit= TRUE; /* handler status is unknown */ + break; + } + } /* XXX: thd->locked_tables is not changed. What problems can we have with it if cursor is open? @@ -1907,6 +1924,7 @@ Cursor::close(bool is_active) thd->derived_tables= tmp_derived_tables; thd->lock= tmp_lock; } + thd->lock_info.n_cursors--; /* Decrease the number of active cursors */ join= 0; unit= 0; free_items(); diff --git a/sql/sql_select.h b/sql/sql_select.h index 9285e33be33..7f6d661a4de 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -392,6 +392,8 @@ class Cursor: public Sql_alloc, public Query_arena public: Item_change_list change_list; select_send result; + THR_LOCK_OWNER lock_id; + my_bool close_at_commit; /* Temporary implementation as now we replace THD state by value */ /* Save THD state into cursor */ |