summaryrefslogtreecommitdiff
path: root/sql/handler.h
diff options
context:
space:
mode:
authorkostja@bodhi.(none) <>2007-07-27 16:37:29 +0400
committerkostja@bodhi.(none) <>2007-07-27 16:37:29 +0400
commit11c57540f73aa42099c3036498644bb41def1dbd (patch)
tree222b968f3296750c8756393cb2779dcfb1da2784 /sql/handler.h
parent9f8593e81c99425a028d416854a172543a6f706d (diff)
downloadmariadb-git-11c57540f73aa42099c3036498644bb41def1dbd.tar.gz
A fix and a test case for Bug#24918 drop table and lock / inconsistent
between perm and temp tables. Review fixes. The original bug report complains that if we locked a temporary table with LOCK TABLES statement, we would not leave LOCK TABLES mode when this temporary table is dropped. Additionally, the bug was escalated when it was discovered than when a temporary transactional table that was previously locked with LOCK TABLES statement was dropped, futher actions with this table, such as UNLOCK TABLES, would lead to a crash. The problem originates from incomplete support of transactional temporary tables. When we added calls to handler::store_lock()/handler::external_lock() to operations that work with such tables, we only covered the normal server code flow and did not cover LOCK TABLES mode. In LOCK TABLES mode, ::external_lock(LOCK) would sometimes be called without matching ::external_lock(UNLOCK), e.g. when a transactional temporary table was dropped. Additionally, this table would be left in the list of LOCKed TABLES. The patch aims to address this inadequacy. Now, whenever an instance of 'handler' is destroyed, we assert that it was priorly external_lock(UNLOCK)-ed. All the places that violate this assert were fixed. This patch introduces no changes in behavior -- the discrepancy in behavior will be fixed when we start calling ::store_lock()/::external_lock() for all tables, regardless whether they are transactional or not, temporary or not.
Diffstat (limited to 'sql/handler.h')
-rw-r--r--sql/handler.h40
1 files changed, 37 insertions, 3 deletions
diff --git a/sql/handler.h b/sql/handler.h
index a3767573178..cd9f9a91008 100644
--- a/sql/handler.h
+++ b/sql/handler.h
@@ -508,6 +508,29 @@ class handler :public Sql_alloc
*/
virtual int rnd_init(bool scan) =0;
virtual int rnd_end() { return 0; }
+ /**
+ Is not invoked for non-transactional temporary tables.
+
+ Tells the storage engine that we intend to read or write data
+ from the table. This call is prefixed with a call to handler::store_lock()
+ and is invoked only for those handler instances that stored the lock.
+
+ Calls to rnd_init/index_init are prefixed with this call. When table
+ IO is complete, we call external_lock(F_UNLCK).
+ A storage engine writer should expect that each call to
+ ::external_lock(F_[RD|WR]LOCK is followed by a call to
+ ::external_lock(F_UNLCK). If it is not, it is a bug in MySQL.
+
+ The name and signature originate from the first implementation
+ in MyISAM, which would call fcntl to set/clear an advisory
+ lock on the data file in this method.
+
+ @param lock_type F_RDLCK, F_WRLCK, F_UNLCK
+
+ @return non-0 in case of failure, 0 in case of success.
+ When lock_type is F_UNLCK, the return value is ignored.
+ */
+ virtual int external_lock(THD *thd, int lock_type) { return 0; }
public:
const handlerton *ht; /* storage engine of this handler */
@@ -548,6 +571,7 @@ public:
uint raid_type,raid_chunks;
FT_INFO *ft_handler;
enum {NONE=0, INDEX, RND} inited;
+ bool locked;
bool auto_increment_column_changed;
bool implicit_emptied; /* Can be !=0 only if HEAP */
const COND *pushed_cond;
@@ -560,10 +584,11 @@ public:
create_time(0), check_time(0), update_time(0),
key_used_on_scan(MAX_KEY), active_index(MAX_KEY),
ref_length(sizeof(my_off_t)), block_size(0),
- raid_type(0), ft_handler(0), inited(NONE), implicit_emptied(0),
+ raid_type(0), ft_handler(0), inited(NONE),
+ locked(FALSE), implicit_emptied(0),
pushed_cond(NULL)
{}
- virtual ~handler(void) { /* TODO: DBUG_ASSERT(inited == NONE); */ }
+ virtual ~handler(void) { DBUG_ASSERT(locked == FALSE); /* TODO: DBUG_ASSERT(inited == NONE); */ }
virtual handler *clone(MEM_ROOT *mem_root);
int ha_open(const char *name, int mode, int test_if_locked);
void adjust_next_insert_id_after_explicit_value(ulonglong nr);
@@ -597,6 +622,13 @@ public:
virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return "";}
+ int ha_external_lock(THD *thd, int lock_type)
+ {
+ int rc;
+ DBUG_ENTER("ha_external_lock");
+ locked= lock_type != F_UNLCK;
+ DBUG_RETURN(external_lock(thd, lock_type));
+ }
int ha_index_init(uint idx)
{
DBUG_ENTER("ha_index_init");
@@ -689,7 +721,6 @@ public:
virtual int extra_opt(enum ha_extra_function operation, ulong cache_size)
{ return extra(operation); }
virtual int reset() { return extra(HA_EXTRA_RESET); }
- virtual int external_lock(THD *thd, int lock_type) { return 0; }
virtual void unlock_row() {}
virtual int start_stmt(THD *thd, thr_lock_type lock_type) {return 0;}
/*
@@ -837,6 +868,9 @@ public:
/* lock_count() can be more than one if the table is a MERGE */
virtual uint lock_count(void) const { return 1; }
+ /**
+ Is not invoked for non-transactional temporary tables.
+ */
virtual THR_LOCK_DATA **store_lock(THD *thd,
THR_LOCK_DATA **to,
enum thr_lock_type lock_type)=0;