Commit 21957c42 authored by konstantin@mysql.com's avatar konstantin@mysql.com

Implement MySQL framework to support consistent read views in

cursors. This should fix Bug#11813 when InnoDB part is in 
(tested with a draft patch).
The idea of the patch is that if a storage engine supports
consistent read views, we open one when open a cursor,
set is as the active view when fetch from the cursor, and close
together with cursor close.
parent 4570ace8
...@@ -140,16 +140,19 @@ static handlerton archive_hton = { ...@@ -140,16 +140,19 @@ static handlerton archive_hton = {
"archive", "archive",
0, /* slot */ 0, /* slot */
0, /* savepoint size. */ 0, /* savepoint size. */
0, /* close_connection */ NULL, /* close_connection */
0, /* savepoint */ NULL, /* savepoint */
0, /* rollback to savepoint */ NULL, /* rollback to savepoint */
0, /* releas savepoint */ NULL, /* releas savepoint */
0, /* commit */ NULL, /* commit */
0, /* rollback */ NULL, /* rollback */
0, /* prepare */ NULL, /* prepare */
0, /* recover */ NULL, /* recover */
0, /* commit_by_xid */ NULL, /* commit_by_xid */
0, /* rollback_by_xid */ NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS HTON_NO_FLAGS
}; };
......
...@@ -77,16 +77,19 @@ static handlerton example_hton= { ...@@ -77,16 +77,19 @@ static handlerton example_hton= {
"CSV", "CSV",
0, /* slot */ 0, /* slot */
0, /* savepoint size. */ 0, /* savepoint size. */
0, /* close_connection */ NULL, /* close_connection */
0, /* savepoint */ NULL, /* savepoint */
0, /* rollback to savepoint */ NULL, /* rollback to savepoint */
0, /* release savepoint */ NULL, /* release savepoint */
0, /* commit */ NULL, /* commit */
0, /* rollback */ NULL, /* rollback */
0, /* prepare */ NULL, /* prepare */
0, /* recover */ NULL, /* recover */
0, /* commit_by_xid */ NULL, /* commit_by_xid */
0, /* rollback_by_xid */ NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS HTON_NO_FLAGS
}; };
......
...@@ -58,16 +58,19 @@ static handlerton tina_hton= { ...@@ -58,16 +58,19 @@ static handlerton tina_hton= {
"CSV", "CSV",
0, /* slot */ 0, /* slot */
0, /* savepoint size. */ 0, /* savepoint size. */
0, /* close_connection */ NULL, /* close_connection */
0, /* savepoint */ NULL, /* savepoint */
0, /* rollback to savepoint */ NULL, /* rollback to savepoint */
0, /* release savepoint */ NULL, /* release savepoint */
0, /* commit */ NULL, /* commit */
0, /* rollback */ NULL, /* rollback */
0, /* prepare */ NULL, /* prepare */
0, /* recover */ NULL, /* recover */
0, /* commit_by_xid */ NULL, /* commit_by_xid */
0, /* rollback_by_xid */ NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS HTON_NO_FLAGS
}; };
......
...@@ -121,6 +121,9 @@ static handlerton berkeley_hton = { ...@@ -121,6 +121,9 @@ static handlerton berkeley_hton = {
NULL, /* recover */ NULL, /* recover */
NULL, /* commit_by_xid */ NULL, /* commit_by_xid */
NULL, /* rollback_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 HTON_CLOSE_CURSORS_AT_COMMIT
}; };
......
...@@ -30,16 +30,19 @@ static handlerton blackhole_hton= { ...@@ -30,16 +30,19 @@ static handlerton blackhole_hton= {
"BLACKHOLE", "BLACKHOLE",
0, /* slot */ 0, /* slot */
0, /* savepoint size. */ 0, /* savepoint size. */
0, /* close_connection */ NULL, /* close_connection */
0, /* savepoint */ NULL, /* savepoint */
0, /* rollback to savepoint */ NULL, /* rollback to savepoint */
0, /* release savepoint */ NULL, /* release savepoint */
0, /* commit */ NULL, /* commit */
0, /* rollback */ NULL, /* rollback */
0, /* prepare */ NULL, /* prepare */
0, /* recover */ NULL, /* recover */
0, /* commit_by_xid */ NULL, /* commit_by_xid */
0, /* rollback_by_xid */ NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS HTON_NO_FLAGS
}; };
......
...@@ -685,16 +685,19 @@ static handlerton federated_hton= { ...@@ -685,16 +685,19 @@ static handlerton federated_hton= {
"FEDERATED", "FEDERATED",
0, /* slot */ 0, /* slot */
0, /* savepoint size. */ 0, /* savepoint size. */
0, /* close_connection */ NULL, /* close_connection */
0, /* savepoint */ NULL, /* savepoint */
0, /* rollback to savepoint */ NULL, /* rollback to savepoint */
0, /* release savepoint */ NULL, /* release savepoint */
0, /* commit */ NULL, /* commit */
0, /* rollback */ NULL, /* rollback */
0, /* prepare */ NULL, /* prepare */
0, /* recover */ NULL, /* recover */
0, /* commit_by_xid */ NULL, /* commit_by_xid */
0, /* rollback_by_xid */ NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS HTON_NO_FLAGS
}; };
......
...@@ -27,16 +27,19 @@ static handlerton heap_hton= { ...@@ -27,16 +27,19 @@ static handlerton heap_hton= {
"MEMORY", "MEMORY",
0, /* slot */ 0, /* slot */
0, /* savepoint size. */ 0, /* savepoint size. */
0, /* close_connection */ NULL, /* close_connection */
0, /* savepoint */ NULL, /* savepoint */
0, /* rollback to savepoint */ NULL, /* rollback to savepoint */
0, /* release savepoint */ NULL, /* release savepoint */
0, /* commit */ NULL, /* commit */
0, /* rollback */ NULL, /* rollback */
0, /* prepare */ NULL, /* prepare */
0, /* recover */ NULL, /* recover */
0, /* commit_by_xid */ NULL, /* commit_by_xid */
0, /* rollback_by_xid */ NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS HTON_NO_FLAGS
}; };
......
...@@ -216,12 +216,9 @@ static handlerton innobase_hton = { ...@@ -216,12 +216,9 @@ static handlerton innobase_hton = {
innobase_xa_recover, /* recover */ innobase_xa_recover, /* recover */
innobase_commit_by_xid, /* commit_by_xid */ innobase_commit_by_xid, /* commit_by_xid */
innobase_rollback_by_xid, /* rollback_by_xid */ innobase_rollback_by_xid, /* rollback_by_xid */
/* NULL,
For now when one opens a cursor, MySQL does not create an own NULL,
InnoDB consistent read view for it, and uses the view of the NULL,
currently active transaction. Therefore, cursors can not
survive COMMIT or ROLLBACK statements, which free this view.
*/
HTON_CLOSE_CURSORS_AT_COMMIT HTON_CLOSE_CURSORS_AT_COMMIT
}; };
......
...@@ -50,16 +50,19 @@ static handlerton myisam_hton= { ...@@ -50,16 +50,19 @@ static handlerton myisam_hton= {
"MyISAM", "MyISAM",
0, /* slot */ 0, /* slot */
0, /* savepoint size. */ 0, /* savepoint size. */
0, /* close_connection */ NULL, /* close_connection */
0, /* savepoint */ NULL, /* savepoint */
0, /* rollback to savepoint */ NULL, /* rollback to savepoint */
0, /* release savepoint */ NULL, /* release savepoint */
0, /* commit */ NULL, /* commit */
0, /* rollback */ NULL, /* rollback */
0, /* prepare */ NULL, /* prepare */
0, /* recover */ NULL, /* recover */
0, /* commit_by_xid */ NULL, /* commit_by_xid */
0, /* rollback_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 MyISAM doesn't support transactions and doesn't have
transaction-dependent context: cursors can survive a commit. transaction-dependent context: cursors can survive a commit.
......
...@@ -38,16 +38,19 @@ static handlerton myisammrg_hton= { ...@@ -38,16 +38,19 @@ static handlerton myisammrg_hton= {
"MRG_MyISAM", "MRG_MyISAM",
0, /* slot */ 0, /* slot */
0, /* savepoint size. */ 0, /* savepoint size. */
0, /* close_connection */ NULL, /* close_connection */
0, /* savepoint */ NULL, /* savepoint */
0, /* rollback to savepoint */ NULL, /* rollback to savepoint */
0, /* release savepoint */ NULL, /* release savepoint */
0, /* commit */ NULL, /* commit */
0, /* rollback */ NULL, /* rollback */
0, /* prepare */ NULL, /* prepare */
0, /* recover */ NULL, /* recover */
0, /* commit_by_xid */ NULL, /* commit_by_xid */
0, /* rollback_by_xid */ NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS HTON_NO_FLAGS
}; };
......
...@@ -63,6 +63,9 @@ static handlerton ndbcluster_hton = { ...@@ -63,6 +63,9 @@ static handlerton ndbcluster_hton = {
NULL, /* recover */ NULL, /* recover */
NULL, /* commit_by_xid */ NULL, /* commit_by_xid */
NULL, /* rollback_by_xid */ NULL, /* rollback_by_xid */
NULL, /* create_cursor_read_view */
NULL, /* set_cursor_read_view */
NULL, /* close_cursor_read_view */
HTON_NO_FLAGS HTON_NO_FLAGS
}; };
......
...@@ -106,9 +106,11 @@ ...@@ -106,9 +106,11 @@
/* /*
Note: the following includes binlog and closing 0. 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) Bits in index_ddl_flags(KEY *wanted_index)
...@@ -349,6 +351,9 @@ typedef struct ...@@ -349,6 +351,9 @@ typedef struct
int (*recover)(XID *xid_list, uint len); int (*recover)(XID *xid_list, uint len);
int (*commit_by_xid)(XID *xid); int (*commit_by_xid)(XID *xid);
int (*rollback_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 */ uint32 flags; /* global handler flags */
} handlerton; } handlerton;
......
...@@ -1712,12 +1712,14 @@ Cursor::Cursor(THD *thd) ...@@ -1712,12 +1712,14 @@ Cursor::Cursor(THD *thd)
/* We will overwrite it at open anyway. */ /* We will overwrite it at open anyway. */
init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0); init_sql_alloc(&main_mem_root, ALLOC_ROOT_MIN_BLOCK_SIZE, 0);
thr_lock_owner_init(&lock_id, &thd->lock_info); thr_lock_owner_init(&lock_id, &thd->lock_info);
bzero((void*) ht_info, sizeof(ht_info));
} }
void void
Cursor::init_from_thd(THD *thd) Cursor::init_from_thd(THD *thd)
{ {
Engine_info *info;
/* /*
We need to save and reset thd->mem_root, otherwise it'll be freed We need to save and reset thd->mem_root, otherwise it'll be freed
later in mysql_parse. later in mysql_parse.
...@@ -1749,15 +1751,16 @@ Cursor::init_from_thd(THD *thd) ...@@ -1749,15 +1751,16 @@ Cursor::init_from_thd(THD *thd)
thd->lock_info.n_cursors++; thd->lock_info.n_cursors++;
close_at_commit= FALSE; /* reset in case we're reusing the cursor */ 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; const handlerton *ht= *pht;
if (ht)
close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT); close_at_commit|= (ht->flags & HTON_CLOSE_CURSORS_AT_COMMIT);
else if (ht->create_cursor_read_view)
{ {
close_at_commit= TRUE; /* handler status is unknown */ info->ht= ht;
break; info->read_view= (ht->create_cursor_read_view)();
++info;
} }
} }
/* /*
...@@ -1853,6 +1856,9 @@ Cursor::fetch(ulong num_rows) ...@@ -1853,6 +1856,9 @@ Cursor::fetch(ulong num_rows)
/* save references to memory, allocated during fetch */ /* save references to memory, allocated during fetch */
thd->set_n_backup_item_arena(this, &backup_arena); 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; join->fetch_limit+= num_rows;
error= sub_select(join, join_tab, 0); error= sub_select(join, join_tab, 0);
...@@ -1869,6 +1875,9 @@ Cursor::fetch(ulong num_rows) ...@@ -1869,6 +1875,9 @@ Cursor::fetch(ulong num_rows)
/* Grab free_list here to correctly free it in close */ /* Grab free_list here to correctly free it in close */
thd->restore_backup_item_arena(this, &backup_arena); 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) if (error == NESTED_LOOP_CURSOR_LIMIT)
{ {
/* Fetch limit worked, possibly more rows are there */ /* Fetch limit worked, possibly more rows are there */
...@@ -1909,6 +1918,13 @@ Cursor::close(bool is_active) ...@@ -1909,6 +1918,13 @@ Cursor::close(bool is_active)
else else
(void) join->select_lex->cleanup(); (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) if (is_active)
close_thread_tables(thd); close_thread_tables(thd);
else else
......
...@@ -389,6 +389,12 @@ class Cursor: public Sql_alloc, public Query_arena ...@@ -389,6 +389,12 @@ class Cursor: public Sql_alloc, public Query_arena
TABLE *derived_tables; TABLE *derived_tables;
/* List of items created during execution */ /* List of items created during execution */
query_id_t query_id; query_id_t query_id;
struct Engine_info
{
const handlerton *ht;
void *read_view;
};
Engine_info ht_info[MAX_HA];
public: public:
Item_change_list change_list; Item_change_list change_list;
select_send result; select_send result;
......
...@@ -13874,10 +13874,12 @@ static void test_bug10760() ...@@ -13874,10 +13874,12 @@ static void test_bug10760()
printf("Fetched row %s\n", id_buf); printf("Fetched row %s\n", id_buf);
rc= mysql_rollback(mysql); /* should close the cursor */ rc= mysql_rollback(mysql); /* should close the cursor */
myquery(rc); myquery(rc);
#if 0
rc= mysql_stmt_fetch(stmt); rc= mysql_stmt_fetch(stmt);
DIE_UNLESS(rc); DIE_UNLESS(rc);
if (!opt_silent) if (!opt_silent)
printf("Got error (as expected): %s\n", mysql_error(mysql)); printf("Got error (as expected): %s\n", mysql_error(mysql));
#endif
} }
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment