Commit 8d63e069 authored by joreland@mysql.com's avatar joreland@mysql.com

Merge joreland@bk-internal.mysql.com:/home/bk/mysql-5.0

into mysql.com:/home/jonas/src/mysql-5.0
parents 1071273b 348c2ea8
......@@ -2896,7 +2896,7 @@ static int run_query_stmt(MYSQL *mysql, struct st_query *q, int flags)
/* Allocate array with bind structs, lengths and NULL flags */
bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
MYF(MY_WME | MY_FAE));
MYF(MY_WME | MY_FAE | MY_ZEROFILL));
length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long),
MYF(MY_WME | MY_FAE));
is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
......
......@@ -612,6 +612,8 @@ extern lock_sys_t* lock_sys;
#define LOCK_TABLE 16 /* these type values should be so high that */
#define LOCK_REC 32 /* they can be ORed to the lock mode */
#define LOCK_TABLE_EXP 80 /* explicit table lock (80 = 16 + 64) */
#define LOCK_TABLE_TRANSACTIONAL 144
/* transactional table lock (144 = 16 + 128)*/
#define LOCK_TYPE_MASK 0xF0UL /* mask used to extract lock type from the
type_mode field in a lock */
/* Waiting lock flag */
......
......@@ -464,6 +464,10 @@ struct trx_struct{
ulint n_lock_table_exp;/* number of explicit table locks
(LOCK TABLES) reserved by the
transaction, stored in trx_locks */
ulint n_lock_table_transactional;
/* number of transactional table locks
(LOCK TABLES..WHERE ENGINE) reserved by
the transaction, stored in trx_locks */
UT_LIST_NODE_T(trx_t)
trx_list; /* list of transactions */
UT_LIST_NODE_T(trx_t)
......
......@@ -2207,7 +2207,8 @@ lock_grant(
release it at the end of the SQL statement */
lock->trx->auto_inc_lock = lock;
} else if (lock_get_type(lock) == LOCK_TABLE_EXP) {
} else if (lock_get_type(lock) == LOCK_TABLE_EXP ||
lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
ut_a(lock_get_mode(lock) == LOCK_S
|| lock_get_mode(lock) == LOCK_X);
}
......@@ -3421,6 +3422,10 @@ lock_table_create(
lock->trx->n_lock_table_exp++;
}
if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
lock->trx->n_lock_table_transactional++;
}
lock->un_member.tab_lock.table = table;
UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
......@@ -3458,7 +3463,11 @@ lock_table_remove_low(
}
if (lock_get_type(lock) == LOCK_TABLE_EXP) {
lock->trx->n_lock_table_exp--;
trx->n_lock_table_exp--;
}
if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
trx->n_lock_table_transactional--;
}
UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock);
......@@ -3592,7 +3601,8 @@ lock_table(
DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
does nothing;
if LOCK_TABLE_EXP bits are set,
if LOCK_TABLE_EXP|LOCK_TABLE_TRANSACTIONAL
bits are set,
creates an explicit table lock */
dict_table_t* table, /* in: database table in dictionary cache */
ulint mode, /* in: lock mode */
......@@ -3608,7 +3618,8 @@ lock_table(
return(DB_SUCCESS);
}
ut_a(flags == 0 || flags == LOCK_TABLE_EXP);
ut_a(flags == 0 || flags == LOCK_TABLE_EXP ||
flags == LOCK_TABLE_TRANSACTIONAL);
trx = thr_get_trx(thr);
......@@ -3631,7 +3642,7 @@ lock_table(
/* Another trx has a request on the table in an incompatible
mode: this trx may have to wait */
err = lock_table_enqueue_waiting(mode, table, thr);
err = lock_table_enqueue_waiting(mode | flags, table, thr);
lock_mutex_exit_kernel();
......@@ -3722,7 +3733,8 @@ lock_table_dequeue(
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
ut_a(lock_get_type(in_lock) == LOCK_TABLE ||
lock_get_type(in_lock) == LOCK_TABLE_EXP);
lock_get_type(in_lock) == LOCK_TABLE_EXP ||
lock_get_type(in_lock) == LOCK_TABLE_TRANSACTIONAL);
lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock);
......@@ -3826,7 +3838,9 @@ lock_release_off_kernel(
}
lock_table_dequeue(lock);
if (lock_get_type(lock) == LOCK_TABLE_EXP) {
if (lock_get_type(lock) == LOCK_TABLE_EXP ||
lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
ut_a(lock_get_mode(lock) == LOCK_S
|| lock_get_mode(lock) == LOCK_X);
}
......@@ -3850,6 +3864,7 @@ lock_release_off_kernel(
ut_a(trx->auto_inc_lock == NULL);
ut_a(trx->n_lock_table_exp == 0);
ut_a(trx->n_lock_table_transactional == 0);
}
/*************************************************************************
......@@ -3915,6 +3930,7 @@ lock_release_tables_off_kernel(
}
ut_a(trx->n_lock_table_exp == 0);
ut_a(trx->n_lock_table_transactional == 0);
}
/*************************************************************************
......@@ -4028,11 +4044,15 @@ lock_table_print(
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
ut_a(lock_get_type(lock) == LOCK_TABLE ||
lock_get_type(lock) == LOCK_TABLE_EXP);
lock_get_type(lock) == LOCK_TABLE_EXP ||
lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL);
if (lock_get_type(lock) == LOCK_TABLE_EXP) {
fputs("EXPLICIT ", file);
} else if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
fputs("TRANSACTIONAL ", file);
}
fputs("TABLE LOCK table ", file);
ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name);
fprintf(file, " trx id %lu %lu",
......@@ -4418,6 +4438,7 @@ lock_table_queue_validate(
while (lock) {
ut_a(((lock->trx)->conc_state == TRX_ACTIVE)
|| ((lock->trx)->conc_state == TRX_PREPARED)
|| ((lock->trx)->conc_state == TRX_COMMITTED_IN_MEMORY));
if (!lock_get_wait(lock)) {
......@@ -4465,6 +4486,7 @@ lock_rec_queue_validate(
while (lock) {
ut_a(lock->trx->conc_state == TRX_ACTIVE
|| lock->trx->conc_state == TRX_PREPARED
|| lock->trx->conc_state
== TRX_COMMITTED_IN_MEMORY);
......@@ -4519,6 +4541,7 @@ lock_rec_queue_validate(
while (lock) {
ut_a(lock->trx->conc_state == TRX_ACTIVE
|| lock->trx->conc_state == TRX_PREPARED
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
ut_a(trx_in_trx_list(lock->trx));
......@@ -4601,6 +4624,7 @@ loop:
ut_a(trx_in_trx_list(lock->trx));
ut_a(lock->trx->conc_state == TRX_ACTIVE
|| lock->trx->conc_state == TRX_PREPARED
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) {
......
......@@ -784,7 +784,7 @@ row_lock_table_for_mysql(
table handle */
dict_table_t* table, /* in: table to lock, or NULL
if prebuilt->table should be
locked as LOCK_TABLE_EXP |
locked or a
prebuilt->select_lock_type */
ulint mode) /* in: lock mode of table */
{
......@@ -822,8 +822,14 @@ run_again:
if (table) {
err = lock_table(0, table, mode, thr);
} else {
err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
prebuilt->select_lock_type, thr);
if (mode == LOCK_TABLE_TRANSACTIONAL) {
err = lock_table(LOCK_TABLE_TRANSACTIONAL,
prebuilt->table,
prebuilt->select_lock_type, thr);
} else {
err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
prebuilt->select_lock_type, thr);
}
}
trx->error_state = err;
......
......@@ -153,6 +153,7 @@ trx_create(
trx->auto_inc_lock = NULL;
trx->n_lock_table_exp = 0;
trx->n_lock_table_transactional = 0;
trx->read_view_heap = mem_heap_create(256);
trx->read_view = NULL;
......@@ -285,6 +286,7 @@ trx_free(
ut_a(!trx->has_search_latch);
ut_a(!trx->auto_inc_lock);
ut_a(!trx->n_lock_table_exp);
ut_a(!trx->n_lock_table_transactional);
ut_a(trx->dict_operation_lock_mode == 0);
......@@ -1645,10 +1647,15 @@ trx_print(
putc('\n', f);
if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
fprintf(f, "mysql tables in use %lu, locked %lu\n",
(ulong) trx->n_mysql_tables_in_use,
(ulong) trx->mysql_n_tables_locked);
}
fprintf(f, "mysql tables in use %lu, locked %lu\n",
(ulong) trx->n_mysql_tables_in_use,
(ulong) trx->mysql_n_tables_locked);
if (trx->n_lock_table_transactional > 0 || trx->n_lock_table_exp > 0) {
fprintf(f, "mysql explicit table locks %lu, transactional table locks %lu\n",
(ulong) trx->n_lock_table_exp,
(ulong) trx->n_lock_table_transactional);
}
newline = TRUE;
......
......@@ -330,3 +330,8 @@ SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MA
min max avg
10.00 10.00 10
DROP TABLE t1;
CREATE TABLE t1 (a char(10), b char(10));
INSERT INTO t1 VALUES ('root','localhost'), ('root','%');
SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c;
ERROR 21000: Subquery returns more than 1 row
DROP TABLE t1;
......@@ -214,3 +214,16 @@ CREATE TABLE `t1` ( `itemid` int(11) NOT NULL default '0', `grpid` varchar(15) N
insert into t1 values (128, 'rozn', 2, now(), 10),(128, 'rozn', 1, now(), 10);
SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MAX(concat(date_,";",price)), 12) price FROM t1 WHERE itemid=128 AND grpid='rozn' GROUP BY itemid, grpid, vendor) lastprices;
DROP TABLE t1;
#
# Test for bug #7413 "Subquery with non-scalar results participating in
# select list of derived table crashes server" aka "VIEW with sub query can
# cause the MySQL server to crash". If we have encountered problem during
# filling of derived table we should report error and perform cleanup
# properly.
#
CREATE TABLE t1 (a char(10), b char(10));
INSERT INTO t1 VALUES ('root','localhost'), ('root','%');
--error 1242
SELECT * FROM (SELECT (SELECT a.a FROM t1 AS a WHERE a.a = b.a) FROM t1 AS b) AS c;
DROP TABLE t1;
......@@ -1356,7 +1356,8 @@ innobase_commit(
3. innobase_query_caching_of_table_permitted(),
4. innobase_savepoint(),
5. ::init_table_handle_for_HANDLER(),
6. innobase_start_trx_and_assign_read_view()
6. innobase_start_trx_and_assign_read_view(),
7. ::transactional_table_lock()
and it is only set to 0 in a commit or a rollback. If it is 0 we know
there cannot be resources to be freed and we could return immediately.
......@@ -5134,8 +5135,9 @@ ha_innobase::start_stmt(
select_lock_type value. The value of
stored_select_lock_type was decided in:
1) ::store_lock(),
2) ::external_lock(), and
3) ::init_table_handle_for_HANDLER(). */
2) ::external_lock(),
3) ::init_table_handle_for_HANDLER(), and
4) :.transactional_table_lock(). */
prebuilt->select_lock_type =
prebuilt->stored_select_lock_type;
......@@ -5326,6 +5328,94 @@ ha_innobase::external_lock(
DBUG_RETURN(0);
}
/**********************************************************************
With this function MySQL request a transactional lock to a table when
user issued query LOCK TABLES..WHERE ENGINE = InnoDB. */
int
ha_innobase::transactional_table_lock(
/*==================================*/
/* out: 0 */
THD* thd, /* in: handle to the user thread */
int lock_type) /* in: lock type */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
trx_t* trx;
DBUG_ENTER("ha_innobase::transactional_table_lock");
DBUG_PRINT("enter",("lock_type: %d", lock_type));
/* We do not know if MySQL can call this function before calling
external_lock(). To be safe, update the thd of the current table
handle. */
update_thd(thd);
if (prebuilt->table->ibd_file_missing && !current_thd->tablespace_op) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB error:\n"
"MySQL is trying to use a table handle but the .ibd file for\n"
"table %s does not exist.\n"
"Have you deleted the .ibd file from the database directory under\n"
"the MySQL datadir?"
"Look from section 15.1 of http://www.innodb.com/ibman.html\n"
"how you can resolve the problem.\n",
prebuilt->table->name);
DBUG_RETURN(HA_ERR_CRASHED);
}
trx = prebuilt->trx;
prebuilt->sql_stat_start = TRUE;
prebuilt->hint_need_to_fetch_extra_cols = 0;
prebuilt->read_just_key = 0;
prebuilt->keep_other_fields_on_keyread = FALSE;
if (lock_type == F_WRLCK) {
prebuilt->select_lock_type = LOCK_X;
prebuilt->stored_select_lock_type = LOCK_X;
} else if (lock_type == F_RDLCK) {
prebuilt->select_lock_type = LOCK_S;
prebuilt->stored_select_lock_type = LOCK_S;
} else {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB error:\n"
"MySQL is trying to set transactional table lock with corrupted lock type\n"
"to table %s, lock type %d does not exist.\n",
prebuilt->table->name, lock_type);
DBUG_RETURN(HA_ERR_CRASHED);
}
/* MySQL is setting a new transactional table lock */
/* Set the MySQL flag to mark that there is an active transaction */
thd->transaction.all.innodb_active_trans = 1;
if (thd->in_lock_tables && thd->variables.innodb_table_locks) {
ulint error = DB_SUCCESS;
error = row_lock_table_for_mysql(prebuilt,NULL,
LOCK_TABLE_TRANSACTIONAL);
if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error, user_thd);
DBUG_RETURN(error);
}
if (thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
/* Store the current undo_no of the transaction
so that we know where to roll back if we have
to roll back the next SQL statement */
trx_mark_sql_stat_end(trx);
}
}
DBUG_RETURN(0);
}
/****************************************************************************
Here we export InnoDB status variables to MySQL. */
......
......@@ -150,6 +150,7 @@ class ha_innobase: public handler
int discard_or_import_tablespace(my_bool discard);
int extra(enum ha_extra_function operation);
int external_lock(THD *thd, int lock_type);
int transactional_table_lock(THD *thd, int lock_type);
int start_stmt(THD *thd);
void position(byte *record);
......
......@@ -454,6 +454,13 @@ public:
{ return extra(operation); }
virtual int reset() { return extra(HA_EXTRA_RESET); }
virtual int external_lock(THD *thd, int lock_type) { return 0; }
/*
This is called to set transactional table lock to a table.
If the handler don't support this, then this function will
return HA_ERR_WRONG_COMMAND and MySQL will give
ER_ILLEGAL_HA error message.
*/
virtual int transactional_table_lock(THD *thd, int lock_type) {return HA_ERR_WRONG_COMMAND;}
virtual void unlock_row() {}
virtual int start_stmt(THD *thd) {return 0;}
/*
......
......@@ -79,7 +79,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
bool unlock, TABLE **write_locked);
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);
static void print_lock_error(int error, const char *);
MYSQL_LOCK *mysql_lock_tables(THD *thd,TABLE **tables,uint count)
......@@ -187,7 +187,7 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
(*tables)->file->external_lock(thd, F_UNLCK);
(*tables)->current_lock=F_UNLCK;
}
print_lock_error(error);
print_lock_error(error, (*tables)->file->table_type());
DBUG_RETURN(error);
}
else
......@@ -380,7 +380,7 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
table++;
} while (--count);
if (error_code)
print_lock_error(error_code);
print_lock_error(error_code, (*table)->file->table_type());
DBUG_RETURN(error_code);
}
......@@ -683,7 +683,7 @@ void unlock_table_names(THD *thd, TABLE_LIST *table_list,
}
static void print_lock_error(int error)
static void print_lock_error(int error, const char *table)
{
int textno;
DBUG_ENTER("print_lock_error");
......@@ -695,11 +695,22 @@ static void print_lock_error(int error)
case HA_ERR_READ_ONLY_TRANSACTION:
textno=ER_READ_ONLY_TRANSACTION;
break;
case HA_ERR_LOCK_DEADLOCK:
textno=ER_LOCK_DEADLOCK;
break;
case HA_ERR_WRONG_COMMAND:
textno=ER_ILLEGAL_HA;
break;
default:
textno=ER_CANT_LOCK;
break;
}
my_error(textno,MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG),error);
if ( textno == ER_ILLEGAL_HA )
my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), table);
else
my_error(textno, MYF(ME_BELL+ME_OLDWIN+ME_WAITTANG), error);
DBUG_VOID_RETURN;
}
......@@ -927,3 +938,62 @@ bool make_global_read_lock_block_commit(THD *thd)
thd->exit_cond(old_message);
DBUG_RETURN(error);
}
/*
Take transactional table lock for all tables in the list
SYNOPSIS
transactional_lock_tables
thd Thread THD
tables list of tables
counter number of tables in the list
NOTES
RETURN
0 - OK
-1 - error
*/
int transactional_lock_tables(THD *thd, TABLE_LIST *tables, uint counter)
{
uint i;
int lock_type,error=0;
TABLE_LIST *table;
TABLE **start,**ptr;
DBUG_ENTER("transactional_lock_tables");
if (!(ptr=start=(TABLE**) sql_alloc(sizeof(TABLE*) * counter)))
return -1;
for (table= tables; table; table= table->next_global)
{
if (!table->placeholder() && !table->schema_table)
*(ptr++)= table->table;
}
for (i=1 ; i <= counter ; i++, start++)
{
DBUG_ASSERT((*start)->reginfo.lock_type >= TL_READ);
lock_type=F_WRLCK; /* Lock exclusive */
if ((*start)->db_stat & HA_READ_ONLY ||
((*start)->reginfo.lock_type >= TL_READ &&
(*start)->reginfo.lock_type <= TL_READ_NO_INSERT))
lock_type=F_RDLCK;
if ((error=(*start)->file->transactional_table_lock(thd, lock_type)))
{
print_lock_error(error, (*start)->file->table_type());
DBUG_RETURN(-1);
}
else
{
(*start)->db_stat &= ~ HA_BLOCK_LOCK;
(*start)->current_lock= lock_type;
}
}
DBUG_RETURN(0);
}
......@@ -828,6 +828,7 @@ int open_tables(THD *thd, TABLE_LIST *tables, uint *counter);
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
bool open_and_lock_tables(THD *thd,TABLE_LIST *tables);
int lock_tables(THD *thd, TABLE_LIST *tables, uint counter);
int transactional_lock_tables(THD *thd, TABLE_LIST *tables, uint counter);
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list);
bool rm_temporary_table(enum db_type base, char *path);
......
......@@ -1864,8 +1864,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
static void relink_tables_for_multidelete(THD *thd)
{
if (thd->lex->all_selects_list->next_select_in_list() ||
thd->lex->time_zone_tables_used)
if (thd->lex->all_selects_list->next_select_in_list())
{
for (SELECT_LEX *sl= thd->lex->all_selects_list;
sl;
......
......@@ -30,15 +30,6 @@
*/
sys_var_long_ptr trg_new_row_fake_var(0, 0);
/*
Fake table list object, pointer to which is used as special value for
st_lex::time_zone_tables_used indicating that we implicitly use time
zone tables in this statement but real table list was not yet created.
Pointer to it is also returned by my_tz_get_tables_list() as indication
of transient error;
*/
TABLE_LIST fake_time_zone_tables_list;
/* Macros to look like lex */
#define yyGet() *(lex->ptr++)
......@@ -1911,6 +1902,31 @@ void st_lex::first_lists_tables_same()
}
/*
Add implicitly used time zone description tables to global table list
(if needed).
SYNOPSYS
st_lex::add_time_zone_tables_to_query_tables()
thd - pointer to current thread context
RETURN VALUE
TRUE - error
FALSE - success
*/
bool st_lex::add_time_zone_tables_to_query_tables(THD *thd)
{
/* We should not add these tables twice */
if (!time_zone_tables_used)
{
time_zone_tables_used= my_tz_get_table_list(thd, &query_tables_last);
if (time_zone_tables_used == &fake_time_zone_tables_list)
return TRUE;
}
return FALSE;
}
/*
Link table back that was unlinked with unlink_first_table()
......
......@@ -87,6 +87,7 @@ enum enum_sql_command {
SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE,
SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW,
SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
SQLCOM_LOCK_TABLES_TRANSACTIONAL,
/* This should be the last !!! */
SQLCOM_END
};
......@@ -735,9 +736,8 @@ typedef struct st_lex
/* Names of user variables holding parameters (in EXECUTE) */
List<LEX_STRING> prepared_stmt_params;
/*
If points to fake_time_zone_tables_list indicates that time zone
tables are implicitly used by statement, also is used for holding
list of those tables after they are opened.
Points to part of global table list which contains time zone tables
implicitly used by the statement.
*/
TABLE_LIST *time_zone_tables_used;
sp_head *sphead;
......@@ -802,6 +802,7 @@ typedef struct st_lex
*(table->prev_global= query_tables_last)= table;
query_tables_last= &table->next_global;
}
bool add_time_zone_tables_to_query_tables(THD *thd);
bool can_be_merged();
bool can_use_merged();
......@@ -810,7 +811,6 @@ typedef struct st_lex
bool need_correct_ident();
} LEX;
extern TABLE_LIST fake_time_zone_tables_list;
struct st_lex_local: public st_lex
{
static void *operator new(size_t size)
......
......@@ -2123,19 +2123,6 @@ mysql_execute_command(THD *thd)
}
#endif /* !HAVE_REPLICATION */
if (lex->time_zone_tables_used)
{
TABLE_LIST *tmp;
if ((tmp= my_tz_get_table_list(thd, &lex->query_tables_last)) ==
&fake_time_zone_tables_list)
{
DBUG_RETURN(-1);
}
lex->time_zone_tables_used= tmp;
if (!all_tables)
all_tables= tmp;
}
/*
When option readonly is set deny operations which change tables.
Except for the replication thread and the 'super' users.
......@@ -3266,6 +3253,27 @@ create_error:
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
thd->in_lock_tables=0;
break;
case SQLCOM_LOCK_TABLES_TRANSACTIONAL:
{
uint counter = 0;
if (check_db_used(thd, all_tables))
goto error;
if (check_table_access(thd, LOCK_TABLES_ACL | SELECT_ACL, all_tables, 0))
goto error;
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
if (open_tables(thd, all_tables, &counter) == 0 &&
transactional_lock_tables(thd, all_tables, counter) == 0)
send_ok(thd);
else
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
thd->in_lock_tables=0;
break;
}
case SQLCOM_CREATE_DB:
{
char *alias;
......
......@@ -4269,7 +4269,8 @@ simple_expr:
{ $$= create_func_contains($3, $5); }
| CONVERT_TZ_SYM '(' expr ',' expr ',' expr ')'
{
Lex->time_zone_tables_used= &fake_time_zone_tables_list;
if (Lex->add_time_zone_tables_to_query_tables(YYTHD))
YYABORT;
$$= new Item_func_convert_tz($3, $5, $7);
}
| CURDATE optional_braces
......@@ -7307,8 +7308,9 @@ internal_variable_name:
If this is time_zone variable we should open time zone
describing tables
*/
if (tmp == &sys_time_zone)
Lex->time_zone_tables_used= &fake_time_zone_tables_list;
if (tmp == &sys_time_zone &&
lex->add_time_zone_tables_to_query_tables(YYTHD))
YYABORT;
}
else
{
......@@ -7413,8 +7415,8 @@ lock:
{
Lex->sql_command=SQLCOM_LOCK_TABLES;
}
table_lock_list
{}
table_lock_list lock_engine_opt
{}
;
table_or_tables:
......@@ -7440,6 +7442,15 @@ lock_option:
| READ_SYM LOCAL_SYM { $$= TL_READ; }
;
lock_engine_opt:
/* empty */
| WHERE
{
Lex->sql_command=SQLCOM_LOCK_TABLES_TRANSACTIONAL;
}
ENGINE_SYM opt_equal storage_engines
;
unlock:
UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }
;
......
......@@ -1439,6 +1439,12 @@ tz_init_table_list(TABLE_LIST *tz_tabs, TABLE_LIST ***global_next_ptr)
}
/*
Fake table list object, pointer to which is returned by
my_tz_get_tables_list() as indication of error.
*/
TABLE_LIST fake_time_zone_tables_list;
/*
Create table list with time zone related tables and add it to the end
of global table list.
......
......@@ -64,6 +64,7 @@ extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
extern void my_tz_free();
extern TABLE_LIST fake_time_zone_tables_list;
/*
Check if we have pointer to the beggining of list of implictly used
......
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