diff --git a/sql/examples/ha_archive.cc b/sql/examples/ha_archive.cc index e5c35ae019d..fd47b45ce52 100644 --- a/sql/examples/ha_archive.cc +++ b/sql/examples/ha_archive.cc @@ -140,16 +140,19 @@ static handlerton archive_hton = { "archive", 0, /* slot */ 0, /* savepoint size. */ - 0, /* close_connection */ - 0, /* savepoint */ - 0, /* rollback to savepoint */ - 0, /* releas savepoint */ - 0, /* commit */ - 0, /* rollback */ - 0, /* prepare */ - 0, /* recover */ - 0, /* commit_by_xid */ - 0, /* rollback_by_xid */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* releas savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; diff --git a/sql/examples/ha_example.cc b/sql/examples/ha_example.cc index 2818c176cd3..a7e193b9730 100644 --- a/sql/examples/ha_example.cc +++ b/sql/examples/ha_example.cc @@ -77,16 +77,19 @@ 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 */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; diff --git a/sql/examples/ha_tina.cc b/sql/examples/ha_tina.cc index 50fec4e2883..8a31d9c0b22 100644 --- a/sql/examples/ha_tina.cc +++ b/sql/examples/ha_tina.cc @@ -58,16 +58,19 @@ 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 */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; diff --git a/sql/field.cc b/sql/field.cc index 02b7ca3f406..2f7358f5816 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4544,9 +4544,9 @@ int Field_timestamp::store(longlong nr) THD *thd= table->in_use; /* We don't want to store invalid or fuzzy datetime values in TIMESTAMP */ - long tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode & - MODE_NO_ZERO_DATE) | - MODE_NO_ZERO_IN_DATE, &error); + longlong tmp= number_to_datetime(nr, &l_time, (thd->variables.sql_mode & + MODE_NO_ZERO_DATE) | + MODE_NO_ZERO_IN_DATE, &error); if (tmp < 0) { error= 2; @@ -5390,7 +5390,7 @@ int Field_newdate::store(double nr) int Field_newdate::store(longlong nr) { TIME l_time; - long tmp; + longlong tmp; int error; if ((tmp= number_to_datetime(nr, &l_time, (TIME_FUZZY_DATE | diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 3b9cdbe29f7..9728e8ef00e 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -121,6 +121,9 @@ static handlerton berkeley_hton = { NULL, /* recover */ NULL, /* commit_by_xid */ NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_CLOSE_CURSORS_AT_COMMIT }; diff --git a/sql/ha_blackhole.cc b/sql/ha_blackhole.cc index ae6952d4e5b..43a286a541f 100644 --- a/sql/ha_blackhole.cc +++ b/sql/ha_blackhole.cc @@ -30,16 +30,19 @@ static handlerton blackhole_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 */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 63454bf88ed..f36df13c5e9 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -685,16 +685,19 @@ 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 */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc index 92a5fe0ea09..94ee3f8e656 100644 --- a/sql/ha_heap.cc +++ b/sql/ha_heap.cc @@ -27,16 +27,19 @@ 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 */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 3f86399aacd..f8b9aa90ea1 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -216,12 +216,9 @@ static handlerton innobase_hton = { innobase_xa_recover, /* recover */ innobase_commit_by_xid, /* commit_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. - */ + NULL, + NULL, + NULL, HTON_CLOSE_CURSORS_AT_COMMIT }; diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc index 2595a1cca26..6dae3e4b465 100644 --- a/sql/ha_myisam.cc +++ b/sql/ha_myisam.cc @@ -50,16 +50,19 @@ 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 */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ /* MyISAM doesn't support transactions and doesn't have transaction-dependent context: cursors can survive a commit. diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc index ae17b60b7e1..97d9ff555b1 100644 --- a/sql/ha_myisammrg.cc +++ b/sql/ha_myisammrg.cc @@ -38,16 +38,19 @@ 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 */ + NULL, /* close_connection */ + NULL, /* savepoint */ + NULL, /* rollback to savepoint */ + NULL, /* release savepoint */ + NULL, /* commit */ + NULL, /* rollback */ + NULL, /* prepare */ + NULL, /* recover */ + NULL, /* commit_by_xid */ + NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 59d05368779..16529e40b99 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -64,6 +64,9 @@ static handlerton ndbcluster_hton = { NULL, /* recover */ NULL, /* commit_by_xid */ NULL, /* rollback_by_xid */ + NULL, /* create_cursor_read_view */ + NULL, /* set_cursor_read_view */ + NULL, /* close_cursor_read_view */ HTON_NO_FLAGS }; diff --git a/sql/handler.h b/sql/handler.h index 39da4f65272..575210e8669 100644 --- a/sql/handler.h +++ b/sql/handler.h @@ -111,9 +111,11 @@ /* Note: the following includes binlog and closing 0. - so: innodb+bdb+ndb+binlog+0 + so: innodb + bdb + ndb + binlog + myisam + myisammrg + archive + + example + csv + heap + blackhole + federated + 0 + (yes, the sum is deliberately inaccurate) */ -#define MAX_HA 6 +#define MAX_HA 14 /* Bits in index_ddl_flags(KEY *wanted_index) @@ -355,6 +357,9 @@ typedef struct int (*recover)(XID *xid_list, uint len); int (*commit_by_xid)(XID *xid); int (*rollback_by_xid)(XID *xid); + void *(*create_cursor_read_view)(); + void (*set_cursor_read_view)(void *); + void (*close_cursor_read_view)(void *); uint32 flags; /* global handler flags */ } handlerton; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index e994b5ff26b..c2d547261ff 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1724,12 +1724,14 @@ Cursor::Cursor(THD *thd) /* 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); + bzero((void*) ht_info, sizeof(ht_info)); } void Cursor::init_from_thd(THD *thd) { + Engine_info *info; /* We need to save and reset thd->mem_root, otherwise it'll be freed later in mysql_parse. @@ -1761,15 +1763,16 @@ Cursor::init_from_thd(THD *thd) 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) + info= &ht_info[0]; + for (handlerton **pht= thd->transaction.stmt.ht; *pht; pht++) { - const handlerton *ht= table->file->ht; - if (ht) - close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); - else + const handlerton *ht= *pht; + close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); + if (ht->create_cursor_read_view) { - close_at_commit= TRUE; /* handler status is unknown */ - break; + info->ht= ht; + info->read_view= (ht->create_cursor_read_view)(); + ++info; } } /* @@ -1865,6 +1868,9 @@ Cursor::fetch(ulong num_rows) /* save references to memory, allocated during fetch */ thd->set_n_backup_item_arena(this, &backup_arena); + for (Engine_info *info= ht_info; info->read_view ; info++) + (info->ht->set_cursor_read_view)(info->read_view); + join->fetch_limit+= num_rows; error= sub_select(join, join_tab, 0); @@ -1881,6 +1887,9 @@ Cursor::fetch(ulong num_rows) /* Grab free_list here to correctly free it in close */ thd->restore_backup_item_arena(this, &backup_arena); + for (Engine_info *info= ht_info; info->read_view; info++) + (info->ht->set_cursor_read_view)(0); + if (error == NESTED_LOOP_CURSOR_LIMIT) { /* Fetch limit worked, possibly more rows are there */ @@ -1921,6 +1930,13 @@ Cursor::close(bool is_active) else (void) join->select_lex->cleanup(); + for (Engine_info *info= ht_info; info->read_view; info++) + { + (info->ht->close_cursor_read_view)(info->read_view); + info->read_view= 0; + info->ht= 0; + } + if (is_active) close_thread_tables(thd); else diff --git a/sql/sql_select.h b/sql/sql_select.h index 2b2557de180..7fdd26846a6 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -390,6 +390,12 @@ class Cursor: public Sql_alloc, public Query_arena TABLE *derived_tables; /* List of items created during execution */ query_id_t query_id; + struct Engine_info + { + const handlerton *ht; + void *read_view; + }; + Engine_info ht_info[MAX_HA]; public: Item_change_list change_list; select_send result; diff --git a/tests/mysql_client_test.c b/tests/mysql_client_test.c index 76d0ab2e4cc..78948548716 100644 --- a/tests/mysql_client_test.c +++ b/tests/mysql_client_test.c @@ -13874,10 +13874,12 @@ static void test_bug10760() printf("Fetched row %s\n", id_buf); rc= mysql_rollback(mysql); /* should close the cursor */ myquery(rc); +#if 0 rc= mysql_stmt_fetch(stmt); DIE_UNLESS(rc); if (!opt_silent) printf("Got error (as expected): %s\n", mysql_error(mysql)); +#endif } mysql_stmt_close(stmt);