summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavi Arnaut <Davi.Arnaut@Sun.COM>2010-03-10 10:36:40 -0300
committerDavi Arnaut <Davi.Arnaut@Sun.COM>2010-03-10 10:36:40 -0300
commitb11740894eb4aceeafde2bbd848adb24ef7cc67e (patch)
tree63a59799aa68a830ed65ed4c3589abbcd1580e75
parente58f200a3df514dede23874d6874e8ad295a5eea (diff)
downloadmariadb-git-b11740894eb4aceeafde2bbd848adb24ef7cc67e.tar.gz
Bug#33669: Transactional temporary tables do not work under --read-only
The problem was that in read only mode (read_only enabled), the server would mistakenly deny data modification attempts for temporary tables which belong to a transactional storage engine (eg. InnoDB). The solution is to allow transactional temporary tables to be modified under read only mode. As a whole, the read only mode does not apply to any kind of temporary table. mysql-test/r/read_only_innodb.result: Add test case result for Bug#33669 mysql-test/t/read_only_innodb.test: Add test case for Bug#33669 sql/lock.cc: Rename mysql_lock_tables_check to lock_tables_check and make it static. Move locking related checks from get_lock_data to lock_tables_check. Allow write locks to temporary tables even under read-only.
-rw-r--r--mysql-test/r/read_only_innodb.result171
-rw-r--r--mysql-test/t/read_only_innodb.test146
-rw-r--r--sql/lock.cc105
3 files changed, 363 insertions, 59 deletions
diff --git a/mysql-test/r/read_only_innodb.result b/mysql-test/r/read_only_innodb.result
index 690de085bf9..13e5980f900 100644
--- a/mysql-test/r/read_only_innodb.result
+++ b/mysql-test/r/read_only_innodb.result
@@ -46,3 +46,174 @@ UNLOCK TABLES;
DROP TABLE t1;
DROP USER test@localhost;
echo End of 5.1 tests
+#
+# Bug#33669: Transactional temporary tables do not work under --read-only
+#
+DROP DATABASE IF EXISTS db1;
+# Setup user and tables
+CREATE USER bug33669@localhost;
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (a INT) ENGINE=INNODB;
+CREATE TABLE db1.t2 (a INT) ENGINE=INNODB;
+INSERT INTO db1.t1 VALUES (1);
+INSERT INTO db1.t2 VALUES (2);
+GRANT CREATE TEMPORARY TABLES, DROP, INSERT, DELETE, UPDATE,
+SELECT, LOCK TABLES ON db1.* TO bug33669@localhost;
+SET GLOBAL READ_ONLY = ON;
+# Connection con1 (user bug33669):
+
+# Create, insert and drop temporary table:
+
+CREATE TEMPORARY TABLE temp (a INT) ENGINE=INNODB;
+INSERT INTO temp VALUES (1);
+DROP TABLE temp;
+
+# Lock base tables and use temporary table:
+
+CREATE TEMPORARY TABLE temp (a INT) ENGINE=INNODB;
+LOCK TABLES t1 READ, t2 READ;
+SELECT * FROM t1;
+a
+1
+INSERT INTO temp values (1);
+SELECT * FROM t2;
+a
+2
+UNLOCK TABLES;
+DROP TABLE temp;
+
+# Transaction
+
+BEGIN;
+SELECT * FROM t1;
+a
+1
+CREATE TEMPORARY TABLE temp (a INT) ENGINE=INNODB;
+INSERT INTO t1 VALUES (1);
+ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
+INSERT INTO temp VALUES (1);
+SELECT * FROM t2;
+a
+2
+ROLLBACK;
+SELECT * FROM temp;
+a
+DROP TABLE temp;
+
+# Lock base table as READ and temporary table as WRITE:
+
+CREATE TEMPORARY TABLE temp (a INT) ENGINE=INNODB;
+LOCK TABLES t1 READ, temp WRITE;
+SELECT * FROM t1;
+a
+1
+SELECT * FROM temp;
+a
+INSERT INTO t1 VALUES (1);
+ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
+INSERT INTO temp VALUES (1);
+DROP TABLE temp;
+UNLOCK TABLES;
+
+# Lock temporary table that shadows a base table:
+
+CREATE TEMPORARY TABLE t1 (a INT) ENGINE=INNODB;
+LOCK TABLES t1 WRITE;
+DROP TABLE t1;
+SELECT * FROM t1;
+ERROR HY000: Table 't1' was not locked with LOCK TABLES
+
+# INSERT SELECT from base table into temporary table:
+
+CREATE TEMPORARY TABLE temp1 (a INT) ENGINE=INNODB;
+CREATE TEMPORARY TABLE temp2 LIKE temp1;
+BEGIN;
+INSERT INTO temp1 VALUES (10);
+INSERT INTO temp2 VALUES (10);
+INSERT INTO temp1 SELECT * FROM t1;
+INSERT INTO temp2 SELECT * FROM t2;
+SELECT * FROM temp1 ORDER BY a;
+a
+1
+10
+SELECT * FROM temp2 ORDER BY a;
+a
+2
+10
+ROLLBACK;
+SELECT * FROM temp1,temp2;
+a a
+LOCK TABLES t1 READ, t2 READ;
+INSERT INTO temp1 VALUES (10);
+INSERT INTO temp2 VALUES (10);
+INSERT INTO temp1 SELECT * FROM t1;
+INSERT INTO temp2 SELECT * FROM t2;
+SELECT * FROM temp1 ORDER BY a;
+a
+1
+10
+SELECT * FROM temp2 ORDER BY a;
+a
+2
+10
+UNLOCK TABLES;
+DELETE temp1, temp2 FROM temp1, temp2;
+INSERT INTO temp1 VALUES (10);
+INSERT INTO temp2 VALUES (10);
+INSERT INTO temp1 SELECT * FROM t1;
+INSERT INTO temp2 SELECT * FROM t2;
+SELECT * FROM temp1 ORDER BY a;
+a
+1
+10
+SELECT * FROM temp2 ORDER BY a;
+a
+2
+10
+DROP TABLE temp1, temp2;
+
+# INSERT and INSERT SELECT that uses subqueries:
+CREATE TEMPORARY TABLE temp1 (a INT) ENGINE=INNODB;
+CREATE TEMPORARY TABLE temp2 LIKE temp1;
+INSERT INTO temp1 (a) VALUES ((SELECT MAX(a) FROM t1));
+LOCK TABLES t2 READ;
+INSERT INTO temp2 (a) VALUES ((SELECT MAX(a) FROM t2));
+UNLOCK TABLES;
+LOCK TABLES t1 READ, t2 READ;
+INSERT INTO temp1 SELECT * FROM t1 WHERE a < (SELECT MAX(a) FROM t2);
+INSERT INTO temp2 SELECT * FROM t2 WHERE a > (SELECT MAX(a) FROM t1);
+UNLOCK TABLES;
+INSERT INTO temp1 SELECT * FROM t1 WHERE a < (SELECT MAX(a) FROM t2);
+INSERT INTO temp2 SELECT * FROM t2 WHERE a > (SELECT MAX(a) FROM t1);
+SELECT * FROM temp1 ORDER BY a;
+a
+1
+1
+1
+SELECT * FROM temp2 ORDER BY a;
+a
+2
+2
+2
+DROP TABLE temp1, temp2;
+
+# Multiple table update:
+
+CREATE TEMPORARY TABLE temp1 (a INT) ENGINE=INNODB;
+CREATE TEMPORARY TABLE temp2 LIKE temp1;
+INSERT INTO temp1 VALUES (1),(2);
+INSERT INTO temp2 VALUES (3),(4);
+UPDATE temp1,temp2 SET temp1.a = 5, temp2.a = 10;
+SELECT * FROM temp1, temp2;
+a a
+5 10
+5 10
+5 10
+5 10
+DROP TABLE temp1, temp2;
+
+# Disconnect and cleanup
+
+SET GLOBAL READ_ONLY = OFF;
+DROP USER bug33669@localhost;
+DROP DATABASE db1;
diff --git a/mysql-test/t/read_only_innodb.test b/mysql-test/t/read_only_innodb.test
index 9e001f2b997..3bb626f2ca7 100644
--- a/mysql-test/t/read_only_innodb.test
+++ b/mysql-test/t/read_only_innodb.test
@@ -83,3 +83,149 @@ DROP USER test@localhost;
disconnect con1;
--echo echo End of 5.1 tests
+
+--echo #
+--echo # Bug#33669: Transactional temporary tables do not work under --read-only
+--echo #
+
+--disable_warnings
+DROP DATABASE IF EXISTS db1;
+--enable_warnings
+
+--echo # Setup user and tables
+CREATE USER bug33669@localhost;
+CREATE DATABASE db1;
+CREATE TABLE db1.t1 (a INT) ENGINE=INNODB;
+CREATE TABLE db1.t2 (a INT) ENGINE=INNODB;
+INSERT INTO db1.t1 VALUES (1);
+INSERT INTO db1.t2 VALUES (2);
+GRANT CREATE TEMPORARY TABLES, DROP, INSERT, DELETE, UPDATE,
+ SELECT, LOCK TABLES ON db1.* TO bug33669@localhost;
+SET GLOBAL READ_ONLY = ON;
+connect(con1,localhost,bug33669,,db1);
+--echo # Connection con1 (user bug33669):
+
+--echo
+--echo # Create, insert and drop temporary table:
+--echo
+CREATE TEMPORARY TABLE temp (a INT) ENGINE=INNODB;
+INSERT INTO temp VALUES (1);
+DROP TABLE temp;
+
+--echo
+--echo # Lock base tables and use temporary table:
+--echo
+CREATE TEMPORARY TABLE temp (a INT) ENGINE=INNODB;
+LOCK TABLES t1 READ, t2 READ;
+SELECT * FROM t1;
+INSERT INTO temp values (1);
+SELECT * FROM t2;
+UNLOCK TABLES;
+DROP TABLE temp;
+
+--echo
+--echo # Transaction
+--echo
+BEGIN;
+SELECT * FROM t1;
+CREATE TEMPORARY TABLE temp (a INT) ENGINE=INNODB;
+--error ER_OPTION_PREVENTS_STATEMENT
+INSERT INTO t1 VALUES (1);
+INSERT INTO temp VALUES (1);
+SELECT * FROM t2;
+ROLLBACK;
+SELECT * FROM temp;
+DROP TABLE temp;
+
+--echo
+--echo # Lock base table as READ and temporary table as WRITE:
+--echo
+CREATE TEMPORARY TABLE temp (a INT) ENGINE=INNODB;
+LOCK TABLES t1 READ, temp WRITE;
+SELECT * FROM t1;
+SELECT * FROM temp;
+--error ER_OPTION_PREVENTS_STATEMENT
+INSERT INTO t1 VALUES (1);
+INSERT INTO temp VALUES (1);
+DROP TABLE temp;
+UNLOCK TABLES;
+
+--echo
+--echo # Lock temporary table that shadows a base table:
+--echo
+CREATE TEMPORARY TABLE t1 (a INT) ENGINE=INNODB;
+LOCK TABLES t1 WRITE;
+DROP TABLE t1;
+--error ER_TABLE_NOT_LOCKED
+SELECT * FROM t1;
+
+--echo
+--echo # INSERT SELECT from base table into temporary table:
+--echo
+
+CREATE TEMPORARY TABLE temp1 (a INT) ENGINE=INNODB;
+CREATE TEMPORARY TABLE temp2 LIKE temp1;
+BEGIN;
+INSERT INTO temp1 VALUES (10);
+INSERT INTO temp2 VALUES (10);
+INSERT INTO temp1 SELECT * FROM t1;
+INSERT INTO temp2 SELECT * FROM t2;
+SELECT * FROM temp1 ORDER BY a;
+SELECT * FROM temp2 ORDER BY a;
+ROLLBACK;
+SELECT * FROM temp1,temp2;
+LOCK TABLES t1 READ, t2 READ;
+INSERT INTO temp1 VALUES (10);
+INSERT INTO temp2 VALUES (10);
+INSERT INTO temp1 SELECT * FROM t1;
+INSERT INTO temp2 SELECT * FROM t2;
+SELECT * FROM temp1 ORDER BY a;
+SELECT * FROM temp2 ORDER BY a;
+UNLOCK TABLES;
+DELETE temp1, temp2 FROM temp1, temp2;
+INSERT INTO temp1 VALUES (10);
+INSERT INTO temp2 VALUES (10);
+INSERT INTO temp1 SELECT * FROM t1;
+INSERT INTO temp2 SELECT * FROM t2;
+SELECT * FROM temp1 ORDER BY a;
+SELECT * FROM temp2 ORDER BY a;
+DROP TABLE temp1, temp2;
+
+--echo
+--echo # INSERT and INSERT SELECT that uses subqueries:
+CREATE TEMPORARY TABLE temp1 (a INT) ENGINE=INNODB;
+CREATE TEMPORARY TABLE temp2 LIKE temp1;
+INSERT INTO temp1 (a) VALUES ((SELECT MAX(a) FROM t1));
+LOCK TABLES t2 READ;
+INSERT INTO temp2 (a) VALUES ((SELECT MAX(a) FROM t2));
+UNLOCK TABLES;
+LOCK TABLES t1 READ, t2 READ;
+INSERT INTO temp1 SELECT * FROM t1 WHERE a < (SELECT MAX(a) FROM t2);
+INSERT INTO temp2 SELECT * FROM t2 WHERE a > (SELECT MAX(a) FROM t1);
+UNLOCK TABLES;
+INSERT INTO temp1 SELECT * FROM t1 WHERE a < (SELECT MAX(a) FROM t2);
+INSERT INTO temp2 SELECT * FROM t2 WHERE a > (SELECT MAX(a) FROM t1);
+SELECT * FROM temp1 ORDER BY a;
+SELECT * FROM temp2 ORDER BY a;
+DROP TABLE temp1, temp2;
+
+--echo
+--echo # Multiple table update:
+--echo
+
+CREATE TEMPORARY TABLE temp1 (a INT) ENGINE=INNODB;
+CREATE TEMPORARY TABLE temp2 LIKE temp1;
+INSERT INTO temp1 VALUES (1),(2);
+INSERT INTO temp2 VALUES (3),(4);
+UPDATE temp1,temp2 SET temp1.a = 5, temp2.a = 10;
+SELECT * FROM temp1, temp2;
+DROP TABLE temp1, temp2;
+
+--echo
+--echo # Disconnect and cleanup
+--echo
+disconnect con1;
+connection default;
+SET GLOBAL READ_ONLY = OFF;
+DROP USER bug33669@localhost;
+DROP DATABASE db1;
diff --git a/sql/lock.cc b/sql/lock.cc
index 3ff131bb828..78a16cea18a 100644
--- a/sql/lock.cc
+++ b/sql/lock.cc
@@ -89,8 +89,8 @@ extern HASH open_cache;
#define GET_LOCK_UNLOCK 1
#define GET_LOCK_STORE_LOCKS 2
-static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
- uint flags, TABLE **write_locked);
+static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
+ uint flags);
static int lock_external(THD *thd, TABLE **table,uint count);
static int unlock_external(THD *thd, TABLE **table,uint count);
static void print_lock_error(int error, const char *);
@@ -107,15 +107,18 @@ static int thr_lock_errno_to_mysql[]=
@param flags Lock flags
@return 0 if all the check passed, non zero if a check failed.
*/
-int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
+static int
+lock_tables_check(THD *thd, TABLE **tables, uint count,
+ bool *write_lock_used, uint flags)
{
- bool log_table_write_query;
- uint system_count;
- uint i;
+ uint system_count, i;
+ bool is_superuser, log_table_write_query;
- DBUG_ENTER("mysql_lock_tables_check");
+ DBUG_ENTER("lock_tables_check");
system_count= 0;
+ *write_lock_used= FALSE;
+ is_superuser= thd->security_ctx->master_access & SUPER_ACL;
log_table_write_query= (is_log_table_write_query(thd->lex->sql_command)
|| ((flags & MYSQL_LOCK_PERF_SCHEMA) != 0));
@@ -148,10 +151,18 @@ int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
}
}
- if ((t->s->table_category == TABLE_CATEGORY_SYSTEM) &&
- (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE))
+ if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE)
{
- system_count++;
+ *write_lock_used= TRUE;
+
+ if (t->s->table_category == TABLE_CATEGORY_SYSTEM)
+ system_count++;
+
+ if (t->db_stat & HA_READ_ONLY)
+ {
+ my_error(ER_OPEN_AS_READONLY, MYF(0), t->alias);
+ DBUG_RETURN(1);
+ }
}
/*
@@ -172,6 +183,20 @@ int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
thd->mdl_context.is_lock_owner(MDL_key::TABLE,
t->s->db.str, t->s->table_name.str,
MDL_SHARED)));
+
+ /*
+ Prevent modifications to base tables if READ_ONLY is activated.
+ In any case, read only does not apply to temporary tables.
+ */
+ if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) && !t->s->tmp_table)
+ {
+ if (t->reginfo.lock_type >= TL_WRITE_ALLOW_WRITE &&
+ !is_superuser && opt_readonly && !thd->slave_thread)
+ {
+ my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
+ DBUG_RETURN(1);
+ }
+ }
}
/*
@@ -267,15 +292,15 @@ static void reset_lock_data_and_free(MYSQL_LOCK **mysql_lock)
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
uint flags, bool *need_reopen)
{
- MYSQL_LOCK *sql_lock;
- TABLE *write_lock_used;
int rc;
+ MYSQL_LOCK *sql_lock;
+ bool write_lock_used;
DBUG_ENTER("mysql_lock_tables");
*need_reopen= FALSE;
- if (mysql_lock_tables_check(thd, tables, count, flags))
+ if (lock_tables_check(thd, tables, count, &write_lock_used, flags))
DBUG_RETURN (NULL);
ulong timeout= (flags & MYSQL_LOCK_IGNORE_TIMEOUT) ?
@@ -283,8 +308,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
for (;;)
{
- if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
- &write_lock_used)))
+ if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS)))
break;
if (global_read_lock && write_lock_used &&
@@ -308,21 +332,6 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
}
}
- if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) &&
- write_lock_used &&
- opt_readonly &&
- !(thd->security_ctx->master_access & SUPER_ACL) &&
- !thd->slave_thread)
- {
- /*
- Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
- We do not wait for READ_ONLY=0, and fail.
- */
- reset_lock_data_and_free(&sql_lock);
- my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
- break;
- }
-
thd_proc_info(thd, "System lock");
DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
if (sql_lock->table_count && lock_external(thd, sql_lock->table,
@@ -459,9 +468,7 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count)
{
MYSQL_LOCK *sql_lock;
- TABLE *write_lock_used;
- if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK,
- &write_lock_used)))
+ if ((sql_lock= get_lock_data(thd, table, count, GET_LOCK_UNLOCK)))
mysql_unlock_tables(thd, sql_lock);
}
@@ -603,9 +610,7 @@ void mysql_lock_downgrade_write(THD *thd, TABLE *table,
thr_lock_type new_lock_type)
{
MYSQL_LOCK *locked;
- TABLE *write_lock_used;
- if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
- &write_lock_used)))
+ if ((locked = get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
{
for (uint i=0; i < locked->lock_count; i++)
thr_downgrade_write_lock(locked->locks[i], new_lock_type);
@@ -619,11 +624,9 @@ void mysql_lock_downgrade_write(THD *thd, TABLE *table,
void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
{
MYSQL_LOCK *locked;
- TABLE *write_lock_used;
DBUG_ENTER("mysql_lock_abort");
- if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
- &write_lock_used)))
+ if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
{
for (uint i=0; i < locked->lock_count; i++)
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
@@ -648,12 +651,10 @@ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
{
MYSQL_LOCK *locked;
- TABLE *write_lock_used;
bool result= FALSE;
DBUG_ENTER("mysql_lock_abort_for_thread");
- if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
- &write_lock_used)))
+ if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK)))
{
for (uint i=0; i < locked->lock_count; i++)
{
@@ -848,11 +849,10 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
@param flags One of:
- GET_LOCK_UNLOCK : If we should send TL_IGNORE to store lock
- GET_LOCK_STORE_LOCKS : Store lock info in TABLE
- @param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
*/
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
- uint flags, TABLE **write_lock_used)
+ uint flags)
{
uint i,tables,lock_count;
MYSQL_LOCK *sql_lock;
@@ -861,9 +861,8 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
DBUG_ENTER("get_lock_data");
DBUG_ASSERT((flags == GET_LOCK_UNLOCK) || (flags == GET_LOCK_STORE_LOCKS));
-
DBUG_PRINT("info", ("count %d", count));
- *write_lock_used=0;
+
for (i=tables=lock_count=0 ; i < count ; i++)
{
TABLE *t= table_ptr[i];
@@ -895,24 +894,12 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
{
TABLE *table;
enum thr_lock_type lock_type;
+ THR_LOCK_DATA **org_locks = locks;
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
continue;
lock_type= table->reginfo.lock_type;
DBUG_ASSERT(lock_type != TL_WRITE_DEFAULT && lock_type != TL_READ_DEFAULT);
- if (lock_type >= TL_WRITE_ALLOW_WRITE)
- {
- *write_lock_used=table;
- if (table->db_stat & HA_READ_ONLY)
- {
- my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias);
- /* Clear the lock type of the lock data that are stored already. */
- sql_lock->lock_count= (uint) (locks - sql_lock->locks);
- reset_lock_data_and_free(&sql_lock);
- DBUG_RETURN(0);
- }
- }
- THR_LOCK_DATA **org_locks = locks;
locks_start= locks;
locks= table->file->store_lock(thd, locks,
(flags & GET_LOCK_UNLOCK) ? TL_IGNORE :