mirror of
https://github.com/MariaDB/server.git
synced 2025-08-07 00:04:31 +03:00
Merge poseidon.ndb.mysql.com:/home/tomas/mysql-5.0
into poseidon.ndb.mysql.com:/home/tomas/mysql-5.0-ndb
This commit is contained in:
@@ -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 */
|
/* Allocate array with bind structs, lengths and NULL flags */
|
||||||
bind= (MYSQL_BIND*) my_malloc(num_fields * sizeof(MYSQL_BIND),
|
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),
|
length= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long),
|
||||||
MYF(MY_WME | MY_FAE));
|
MYF(MY_WME | MY_FAE));
|
||||||
is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
|
is_null= (my_bool*) my_malloc(num_fields * sizeof(my_bool),
|
||||||
|
@@ -53,6 +53,7 @@ int resize_queue(QUEUE *queue, uint max_elements);
|
|||||||
void delete_queue(QUEUE *queue);
|
void delete_queue(QUEUE *queue);
|
||||||
void queue_insert(QUEUE *queue,byte *element);
|
void queue_insert(QUEUE *queue,byte *element);
|
||||||
byte *queue_remove(QUEUE *queue,uint idx);
|
byte *queue_remove(QUEUE *queue,uint idx);
|
||||||
|
#define queue_remove_all(queue) { (queue)->elements= 0; }
|
||||||
void _downheap(QUEUE *queue,uint idx);
|
void _downheap(QUEUE *queue,uint idx);
|
||||||
void queue_fix(QUEUE *queue);
|
void queue_fix(QUEUE *queue);
|
||||||
#define is_queue_inited(queue) ((queue)->root != 0)
|
#define is_queue_inited(queue) ((queue)->root != 0)
|
||||||
|
@@ -612,6 +612,8 @@ extern lock_sys_t* lock_sys;
|
|||||||
#define LOCK_TABLE 16 /* these type values should be so high that */
|
#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_REC 32 /* they can be ORed to the lock mode */
|
||||||
#define LOCK_TABLE_EXP 80 /* explicit table lock (80 = 16 + 64) */
|
#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
|
#define LOCK_TYPE_MASK 0xF0UL /* mask used to extract lock type from the
|
||||||
type_mode field in a lock */
|
type_mode field in a lock */
|
||||||
/* Waiting lock flag */
|
/* Waiting lock flag */
|
||||||
|
@@ -464,6 +464,10 @@ struct trx_struct{
|
|||||||
ulint n_lock_table_exp;/* number of explicit table locks
|
ulint n_lock_table_exp;/* number of explicit table locks
|
||||||
(LOCK TABLES) reserved by the
|
(LOCK TABLES) reserved by the
|
||||||
transaction, stored in trx_locks */
|
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)
|
UT_LIST_NODE_T(trx_t)
|
||||||
trx_list; /* list of transactions */
|
trx_list; /* list of transactions */
|
||||||
UT_LIST_NODE_T(trx_t)
|
UT_LIST_NODE_T(trx_t)
|
||||||
|
@@ -2207,7 +2207,8 @@ lock_grant(
|
|||||||
release it at the end of the SQL statement */
|
release it at the end of the SQL statement */
|
||||||
|
|
||||||
lock->trx->auto_inc_lock = lock;
|
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
|
ut_a(lock_get_mode(lock) == LOCK_S
|
||||||
|| lock_get_mode(lock) == LOCK_X);
|
|| lock_get_mode(lock) == LOCK_X);
|
||||||
}
|
}
|
||||||
@@ -3421,6 +3422,10 @@ lock_table_create(
|
|||||||
lock->trx->n_lock_table_exp++;
|
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;
|
lock->un_member.tab_lock.table = table;
|
||||||
|
|
||||||
UT_LIST_ADD_LAST(un_member.tab_lock.locks, table->locks, lock);
|
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) {
|
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);
|
UT_LIST_REMOVE(trx_locks, trx->trx_locks, lock);
|
||||||
@@ -3592,7 +3601,8 @@ lock_table(
|
|||||||
DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
|
DB_DEADLOCK, or DB_QUE_THR_SUSPENDED */
|
||||||
ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
|
ulint flags, /* in: if BTR_NO_LOCKING_FLAG bit is set,
|
||||||
does nothing;
|
does nothing;
|
||||||
if LOCK_TABLE_EXP bits are set,
|
if LOCK_TABLE_EXP|LOCK_TABLE_TRANSACTIONAL
|
||||||
|
bits are set,
|
||||||
creates an explicit table lock */
|
creates an explicit table lock */
|
||||||
dict_table_t* table, /* in: database table in dictionary cache */
|
dict_table_t* table, /* in: database table in dictionary cache */
|
||||||
ulint mode, /* in: lock mode */
|
ulint mode, /* in: lock mode */
|
||||||
@@ -3608,7 +3618,8 @@ lock_table(
|
|||||||
return(DB_SUCCESS);
|
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);
|
trx = thr_get_trx(thr);
|
||||||
|
|
||||||
@@ -3631,7 +3642,7 @@ lock_table(
|
|||||||
/* Another trx has a request on the table in an incompatible
|
/* Another trx has a request on the table in an incompatible
|
||||||
mode: this trx may have to wait */
|
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();
|
lock_mutex_exit_kernel();
|
||||||
|
|
||||||
@@ -3722,7 +3733,8 @@ lock_table_dequeue(
|
|||||||
ut_ad(mutex_own(&kernel_mutex));
|
ut_ad(mutex_own(&kernel_mutex));
|
||||||
#endif /* UNIV_SYNC_DEBUG */
|
#endif /* UNIV_SYNC_DEBUG */
|
||||||
ut_a(lock_get_type(in_lock) == LOCK_TABLE ||
|
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);
|
lock = UT_LIST_GET_NEXT(un_member.tab_lock.locks, in_lock);
|
||||||
|
|
||||||
@@ -3826,7 +3838,9 @@ lock_release_off_kernel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
lock_table_dequeue(lock);
|
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
|
ut_a(lock_get_mode(lock) == LOCK_S
|
||||||
|| lock_get_mode(lock) == LOCK_X);
|
|| lock_get_mode(lock) == LOCK_X);
|
||||||
}
|
}
|
||||||
@@ -3850,6 +3864,7 @@ lock_release_off_kernel(
|
|||||||
|
|
||||||
ut_a(trx->auto_inc_lock == NULL);
|
ut_a(trx->auto_inc_lock == NULL);
|
||||||
ut_a(trx->n_lock_table_exp == 0);
|
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_exp == 0);
|
||||||
|
ut_a(trx->n_lock_table_transactional == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************************************************************
|
/*************************************************************************
|
||||||
@@ -4028,11 +4044,15 @@ lock_table_print(
|
|||||||
ut_ad(mutex_own(&kernel_mutex));
|
ut_ad(mutex_own(&kernel_mutex));
|
||||||
#endif /* UNIV_SYNC_DEBUG */
|
#endif /* UNIV_SYNC_DEBUG */
|
||||||
ut_a(lock_get_type(lock) == LOCK_TABLE ||
|
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) {
|
if (lock_get_type(lock) == LOCK_TABLE_EXP) {
|
||||||
fputs("EXPLICIT ", file);
|
fputs("EXPLICIT ", file);
|
||||||
|
} else if (lock_get_type(lock) == LOCK_TABLE_TRANSACTIONAL) {
|
||||||
|
fputs("TRANSACTIONAL ", file);
|
||||||
}
|
}
|
||||||
|
|
||||||
fputs("TABLE LOCK table ", file);
|
fputs("TABLE LOCK table ", file);
|
||||||
ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name);
|
ut_print_name(file, lock->trx, lock->un_member.tab_lock.table->name);
|
||||||
fprintf(file, " trx id %lu %lu",
|
fprintf(file, " trx id %lu %lu",
|
||||||
@@ -4418,6 +4438,7 @@ lock_table_queue_validate(
|
|||||||
|
|
||||||
while (lock) {
|
while (lock) {
|
||||||
ut_a(((lock->trx)->conc_state == TRX_ACTIVE)
|
ut_a(((lock->trx)->conc_state == TRX_ACTIVE)
|
||||||
|
|| ((lock->trx)->conc_state == TRX_PREPARED)
|
||||||
|| ((lock->trx)->conc_state == TRX_COMMITTED_IN_MEMORY));
|
|| ((lock->trx)->conc_state == TRX_COMMITTED_IN_MEMORY));
|
||||||
|
|
||||||
if (!lock_get_wait(lock)) {
|
if (!lock_get_wait(lock)) {
|
||||||
@@ -4465,6 +4486,7 @@ lock_rec_queue_validate(
|
|||||||
|
|
||||||
while (lock) {
|
while (lock) {
|
||||||
ut_a(lock->trx->conc_state == TRX_ACTIVE
|
ut_a(lock->trx->conc_state == TRX_ACTIVE
|
||||||
|
|| lock->trx->conc_state == TRX_PREPARED
|
||||||
|| lock->trx->conc_state
|
|| lock->trx->conc_state
|
||||||
== TRX_COMMITTED_IN_MEMORY);
|
== TRX_COMMITTED_IN_MEMORY);
|
||||||
|
|
||||||
@@ -4519,6 +4541,7 @@ lock_rec_queue_validate(
|
|||||||
|
|
||||||
while (lock) {
|
while (lock) {
|
||||||
ut_a(lock->trx->conc_state == TRX_ACTIVE
|
ut_a(lock->trx->conc_state == TRX_ACTIVE
|
||||||
|
|| lock->trx->conc_state == TRX_PREPARED
|
||||||
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
|
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
|
||||||
ut_a(trx_in_trx_list(lock->trx));
|
ut_a(trx_in_trx_list(lock->trx));
|
||||||
|
|
||||||
@@ -4601,6 +4624,7 @@ loop:
|
|||||||
|
|
||||||
ut_a(trx_in_trx_list(lock->trx));
|
ut_a(trx_in_trx_list(lock->trx));
|
||||||
ut_a(lock->trx->conc_state == TRX_ACTIVE
|
ut_a(lock->trx->conc_state == TRX_ACTIVE
|
||||||
|
|| lock->trx->conc_state == TRX_PREPARED
|
||||||
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
|
|| lock->trx->conc_state == TRX_COMMITTED_IN_MEMORY);
|
||||||
|
|
||||||
for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) {
|
for (i = nth_bit; i < lock_rec_get_n_bits(lock); i++) {
|
||||||
|
@@ -784,7 +784,7 @@ row_lock_table_for_mysql(
|
|||||||
table handle */
|
table handle */
|
||||||
dict_table_t* table, /* in: table to lock, or NULL
|
dict_table_t* table, /* in: table to lock, or NULL
|
||||||
if prebuilt->table should be
|
if prebuilt->table should be
|
||||||
locked as LOCK_TABLE_EXP |
|
locked or a
|
||||||
prebuilt->select_lock_type */
|
prebuilt->select_lock_type */
|
||||||
ulint mode) /* in: lock mode of table */
|
ulint mode) /* in: lock mode of table */
|
||||||
{
|
{
|
||||||
@@ -822,8 +822,14 @@ run_again:
|
|||||||
if (table) {
|
if (table) {
|
||||||
err = lock_table(0, table, mode, thr);
|
err = lock_table(0, table, mode, thr);
|
||||||
} else {
|
} else {
|
||||||
err = lock_table(LOCK_TABLE_EXP, prebuilt->table,
|
if (mode == LOCK_TABLE_TRANSACTIONAL) {
|
||||||
prebuilt->select_lock_type, thr);
|
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;
|
trx->error_state = err;
|
||||||
|
@@ -153,6 +153,7 @@ trx_create(
|
|||||||
|
|
||||||
trx->auto_inc_lock = NULL;
|
trx->auto_inc_lock = NULL;
|
||||||
trx->n_lock_table_exp = 0;
|
trx->n_lock_table_exp = 0;
|
||||||
|
trx->n_lock_table_transactional = 0;
|
||||||
|
|
||||||
trx->read_view_heap = mem_heap_create(256);
|
trx->read_view_heap = mem_heap_create(256);
|
||||||
trx->read_view = NULL;
|
trx->read_view = NULL;
|
||||||
@@ -285,6 +286,7 @@ trx_free(
|
|||||||
ut_a(!trx->has_search_latch);
|
ut_a(!trx->has_search_latch);
|
||||||
ut_a(!trx->auto_inc_lock);
|
ut_a(!trx->auto_inc_lock);
|
||||||
ut_a(!trx->n_lock_table_exp);
|
ut_a(!trx->n_lock_table_exp);
|
||||||
|
ut_a(!trx->n_lock_table_transactional);
|
||||||
|
|
||||||
ut_a(trx->dict_operation_lock_mode == 0);
|
ut_a(trx->dict_operation_lock_mode == 0);
|
||||||
|
|
||||||
@@ -1645,10 +1647,15 @@ trx_print(
|
|||||||
putc('\n', f);
|
putc('\n', f);
|
||||||
|
|
||||||
if (trx->n_mysql_tables_in_use > 0 || trx->mysql_n_tables_locked > 0) {
|
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",
|
if (trx->n_lock_table_transactional > 0 || trx->n_lock_table_exp > 0) {
|
||||||
(ulong) trx->n_mysql_tables_in_use,
|
fprintf(f, "mysql explicit table locks %lu, transactional table locks %lu\n",
|
||||||
(ulong) trx->mysql_n_tables_locked);
|
(ulong) trx->n_lock_table_exp,
|
||||||
|
(ulong) trx->n_lock_table_transactional);
|
||||||
}
|
}
|
||||||
|
|
||||||
newline = TRUE;
|
newline = TRUE;
|
||||||
|
@@ -330,3 +330,8 @@ SELECT MIN(price) min, MAX(price) max, AVG(price) avg FROM (SELECT SUBSTRING( MA
|
|||||||
min max avg
|
min max avg
|
||||||
10.00 10.00 10
|
10.00 10.00 10
|
||||||
DROP TABLE t1;
|
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;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
drop table if exists t0, t1, t2, t3,t4;
|
drop table if exists t0, t1, t2, t3, t4;
|
||||||
create table t0
|
create table t0
|
||||||
(
|
(
|
||||||
key1 int not null,
|
key1 int not null,
|
||||||
@@ -335,4 +335,55 @@ key1 key2 key3 key4 key5 key6 key7 key8
|
|||||||
select count(*) from t0;
|
select count(*) from t0;
|
||||||
count(*)
|
count(*)
|
||||||
1021
|
1021
|
||||||
|
drop table t4;
|
||||||
|
create table t4 (a int);
|
||||||
|
insert into t4 values (1),(4),(3);
|
||||||
|
set @save_join_buffer_size=@@join_buffer_size;
|
||||||
|
set join_buffer_size= 4000;
|
||||||
|
show variables like 'join_buffer_size';
|
||||||
|
Variable_name Value
|
||||||
|
join_buffer_size 8228
|
||||||
|
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A force index(i1,i2), t0 as B force index (i1,i2)
|
||||||
|
where (A.key1 < 500000 or A.key2 < 3)
|
||||||
|
and (B.key1 < 500000 or B.key2 < 3);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL 1016 Using sort_union(i1,i2); Using where
|
||||||
|
1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL 1016 Using sort_union(i1,i2); Using where
|
||||||
|
select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A force index(i1,i2), t0 as B force index (i1,i2)
|
||||||
|
where (A.key1 < 500000 or A.key2 < 3)
|
||||||
|
and (B.key1 < 500000 or B.key2 < 3);
|
||||||
|
max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
10240
|
||||||
|
update t0 set key1=1;
|
||||||
|
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A force index(i1,i2), t0 as B force index (i1,i2)
|
||||||
|
where (A.key1 = 1 or A.key2 = 1)
|
||||||
|
and (B.key1 = 1 or B.key2 = 1);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE A index_merge i1,i2 i1,i2 4,4 NULL 1020 Using union(i1,i2); Using where
|
||||||
|
1 SIMPLE B index_merge i1,i2 i1,i2 4,4 NULL 1020 Using union(i1,i2); Using where
|
||||||
|
select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A force index(i1,i2), t0 as B force index (i1,i2)
|
||||||
|
where (A.key1 = 1 or A.key2 = 1)
|
||||||
|
and (B.key1 = 1 or B.key2 = 1);
|
||||||
|
max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
8194
|
||||||
|
alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200);
|
||||||
|
update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500;
|
||||||
|
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A, t0 as B
|
||||||
|
where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1)
|
||||||
|
and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1);
|
||||||
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
|
1 SIMPLE A index_merge i1,i2,i3,i4,i5,i6,i7,i8 i2,i3,i4,i5,i6,i8 4,4,4,4,4,4 NULL 16 Using union(intersect(i2,i3,i4,i5,i6),i8); Using where
|
||||||
|
1 SIMPLE B index_merge i1,i2,i3,i4,i5,i6,i7,i8 i2,i3,i4,i5,i6,i8 4,4,4,4,4,4 NULL 16 Using union(intersect(i2,i3,i4,i5,i6),i8); Using where
|
||||||
|
select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A, t0 as B
|
||||||
|
where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1)
|
||||||
|
and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1);
|
||||||
|
max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
8186
|
||||||
|
set join_buffer_size= @save_join_buffer_size;
|
||||||
drop table t0, t1, t2, t3, t4;
|
drop table t0, t1, t2, t3, t4;
|
||||||
|
@@ -853,4 +853,19 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||||||
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
|
1 SIMPLE t1 const PRIMARY PRIMARY 4 const 1 Using index
|
||||||
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
|
1 SIMPLE t2 ALL NULL NULL NULL NULL 2
|
||||||
1 SIMPLE t3 ALL NULL NULL NULL NULL 2
|
1 SIMPLE t3 ALL NULL NULL NULL NULL 2
|
||||||
|
drop table t1,t2;
|
||||||
|
create table t1 (a int, b int);
|
||||||
|
insert into t1 values (1,1),(2,2),(3,3);
|
||||||
|
create table t2 (a int, b int);
|
||||||
|
insert into t2 values (1,1), (2,2);
|
||||||
|
select * from t2 right join t1 on t2.a=t1.a;
|
||||||
|
a b a b
|
||||||
|
1 1 1 1
|
||||||
|
2 2 2 2
|
||||||
|
NULL NULL 3 3
|
||||||
|
select straight_join * from t2 right join t1 on t2.a=t1.a;
|
||||||
|
a b a b
|
||||||
|
1 1 1 1
|
||||||
|
2 2 2 2
|
||||||
|
NULL NULL 3 3
|
||||||
DROP TABLE t0,t1,t2,t3;
|
DROP TABLE t0,t1,t2,t3;
|
||||||
|
@@ -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);
|
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;
|
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;
|
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;
|
||||||
|
@@ -1,9 +1,8 @@
|
|||||||
#
|
#
|
||||||
# Index merge tests
|
# Index merge tests
|
||||||
#
|
#
|
||||||
|
|
||||||
--disable_warnings
|
--disable_warnings
|
||||||
drop table if exists t0, t1, t2, t3,t4;
|
drop table if exists t0, t1, t2, t3, t4;
|
||||||
--enable_warnings
|
--enable_warnings
|
||||||
|
|
||||||
# Create and fill a table with simple keys
|
# Create and fill a table with simple keys
|
||||||
@@ -278,4 +277,48 @@ delete from t0 where key1 < 3 or key2 < 4;
|
|||||||
select * from t0 where key1 < 3 or key2 < 4;
|
select * from t0 where key1 < 3 or key2 < 4;
|
||||||
select count(*) from t0;
|
select count(*) from t0;
|
||||||
|
|
||||||
drop table t0, t1, t2, t3, t4;
|
# Test for BUG#4177
|
||||||
|
drop table t4;
|
||||||
|
create table t4 (a int);
|
||||||
|
insert into t4 values (1),(4),(3);
|
||||||
|
set @save_join_buffer_size=@@join_buffer_size;
|
||||||
|
set join_buffer_size= 4000;
|
||||||
|
show variables like 'join_buffer_size';
|
||||||
|
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A force index(i1,i2), t0 as B force index (i1,i2)
|
||||||
|
where (A.key1 < 500000 or A.key2 < 3)
|
||||||
|
and (B.key1 < 500000 or B.key2 < 3);
|
||||||
|
|
||||||
|
select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A force index(i1,i2), t0 as B force index (i1,i2)
|
||||||
|
where (A.key1 < 500000 or A.key2 < 3)
|
||||||
|
and (B.key1 < 500000 or B.key2 < 3);
|
||||||
|
|
||||||
|
update t0 set key1=1;
|
||||||
|
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A force index(i1,i2), t0 as B force index (i1,i2)
|
||||||
|
where (A.key1 = 1 or A.key2 = 1)
|
||||||
|
and (B.key1 = 1 or B.key2 = 1);
|
||||||
|
|
||||||
|
select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A force index(i1,i2), t0 as B force index (i1,i2)
|
||||||
|
where (A.key1 = 1 or A.key2 = 1)
|
||||||
|
and (B.key1 = 1 or B.key2 = 1);
|
||||||
|
|
||||||
|
alter table t0 add filler1 char(200), add filler2 char(200), add filler3 char(200);
|
||||||
|
update t0 set key2=1, key3=1, key4=1, key5=1,key6=1,key7=1 where key7 < 500;
|
||||||
|
explain select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A, t0 as B
|
||||||
|
where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1)
|
||||||
|
and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1);
|
||||||
|
|
||||||
|
select max(A.key1 + B.key1 + A.key2 + B.key2 + A.key3 + B.key3 + A.key4 + B.key4 + A.key5 + B.key5)
|
||||||
|
from t0 as A, t0 as B
|
||||||
|
where (A.key1 = 1 and A.key2 = 1 and A.key3 = 1 and A.key4=1 and A.key5=1 and A.key6=1 and A.key7 = 1 or A.key8=1)
|
||||||
|
and (B.key1 = 1 and B.key2 = 1 and B.key3 = 1 and B.key4=1 and B.key5=1 and B.key6=1 and B.key7 = 1 or B.key8=1);
|
||||||
|
|
||||||
|
set join_buffer_size= @save_join_buffer_size;
|
||||||
|
# Test for BUG#4177 ends
|
||||||
|
|
||||||
|
drop table t0, t1, t2, t3, t4;
|
||||||
|
|
||||||
|
@@ -606,4 +606,14 @@ INSERT INTO t1 VALUES (0);
|
|||||||
SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
|
SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
|
||||||
EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
|
EXPLAIN SELECT * FROM t0, t1 LEFT JOIN (t2,t3) ON a1=5 WHERE a0=a1 AND a0=1;
|
||||||
|
|
||||||
|
# Test for BUG#4480
|
||||||
|
drop table t1,t2;
|
||||||
|
create table t1 (a int, b int);
|
||||||
|
insert into t1 values (1,1),(2,2),(3,3);
|
||||||
|
create table t2 (a int, b int);
|
||||||
|
insert into t2 values (1,1), (2,2);
|
||||||
|
|
||||||
|
select * from t2 right join t1 on t2.a=t1.a;
|
||||||
|
select straight_join * from t2 right join t1 on t2.a=t1.a;
|
||||||
|
|
||||||
DROP TABLE t0,t1,t2,t3;
|
DROP TABLE t0,t1,t2,t3;
|
||||||
|
@@ -64,7 +64,7 @@ class NdbEventOperationImpl;
|
|||||||
*
|
*
|
||||||
* Known issues:
|
* Known issues:
|
||||||
*
|
*
|
||||||
* When several NdbEventOperation s are tied to the same event in the same
|
* When several NdbEventOperation's are tied to the same event in the same
|
||||||
* process they will share the circular buffer. The BufferLength will then
|
* process they will share the circular buffer. The BufferLength will then
|
||||||
* be the same for all and decided by the first NdbEventOperation
|
* be the same for all and decided by the first NdbEventOperation
|
||||||
* instantiation. Just make sure to instantiate the "largest" one first.
|
* instantiation. Just make sure to instantiate the "largest" one first.
|
||||||
@@ -84,7 +84,7 @@ class NdbEventOperationImpl;
|
|||||||
* replica. If a node fails events will not be received twice anymore
|
* replica. If a node fails events will not be received twice anymore
|
||||||
* for data in corresponding fragment. Will be optimized in later versions.
|
* for data in corresponding fragment. Will be optimized in later versions.
|
||||||
*
|
*
|
||||||
* If a nodefailiure has occured not all events will be recieved
|
* If a node failure has occured not all events will be recieved
|
||||||
* anymore. Drop NdbEventOperation and Create again after nodes are up
|
* anymore. Drop NdbEventOperation and Create again after nodes are up
|
||||||
* again. Will be fixed in later versions.
|
* again. Will be fixed in later versions.
|
||||||
*
|
*
|
||||||
@@ -97,7 +97,7 @@ class NdbEventOperationImpl;
|
|||||||
*
|
*
|
||||||
* Useful API programs:
|
* Useful API programs:
|
||||||
*
|
*
|
||||||
* select_all -d sys 'NDB$EVENTS_0'
|
* ndb_select_all -d sys 'NDB$EVENTS_0'
|
||||||
* Will show contents in the system table containing created events.
|
* Will show contents in the system table containing created events.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
@@ -187,8 +187,19 @@ public:
|
|||||||
*/
|
*/
|
||||||
NdbDictionary::Event::TableEvent getEventType();
|
NdbDictionary::Event::TableEvent getEventType();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
Uint32 getGCI();
|
Uint32 getGCI();
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
Uint32 getLatestGCI();
|
Uint32 getLatestGCI();
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
*/
|
||||||
void print();
|
void print();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -296,7 +296,6 @@ int Mysql_connection_thread::check_user(const char *user, const char *password)
|
|||||||
int Mysql_connection_thread::do_command()
|
int Mysql_connection_thread::do_command()
|
||||||
{
|
{
|
||||||
char *packet;
|
char *packet;
|
||||||
uint old_timeout;
|
|
||||||
ulong packet_length;
|
ulong packet_length;
|
||||||
|
|
||||||
/* We start to count packets from 0 for each new command */
|
/* We start to count packets from 0 for each new command */
|
||||||
|
@@ -131,7 +131,6 @@ Command *parse_command(Command_factory *factory, const char *text)
|
|||||||
const char *instance_name;
|
const char *instance_name;
|
||||||
uint instance_name_len;
|
uint instance_name_len;
|
||||||
Command *command;
|
Command *command;
|
||||||
const char *saved_text= text;
|
|
||||||
|
|
||||||
Token tok1= shift_token(&text, &word_len);
|
Token tok1= shift_token(&text, &word_len);
|
||||||
|
|
||||||
|
@@ -148,6 +148,7 @@ int Thread_registry::cond_wait(Thread_info *info, pthread_cond_t *cond,
|
|||||||
|
|
||||||
void Thread_registry::deliver_shutdown()
|
void Thread_registry::deliver_shutdown()
|
||||||
{
|
{
|
||||||
|
Thread_info *info;
|
||||||
struct timespec shutdown_time;
|
struct timespec shutdown_time;
|
||||||
set_timespec(shutdown_time, 1);
|
set_timespec(shutdown_time, 1);
|
||||||
|
|
||||||
@@ -161,7 +162,7 @@ void Thread_registry::deliver_shutdown()
|
|||||||
stopped alarm processing.
|
stopped alarm processing.
|
||||||
*/
|
*/
|
||||||
process_alarm(THR_SERVER_ALARM);
|
process_alarm(THR_SERVER_ALARM);
|
||||||
for (Thread_info *info= head.next; info != &head; info= info->next)
|
for (info= head.next; info != &head; info= info->next)
|
||||||
{
|
{
|
||||||
pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL);
|
pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL);
|
||||||
/*
|
/*
|
||||||
@@ -190,7 +191,7 @@ void Thread_registry::deliver_shutdown()
|
|||||||
so this time everybody should be informed (presumably each worker can
|
so this time everybody should be informed (presumably each worker can
|
||||||
get CPU during shutdown_time.)
|
get CPU during shutdown_time.)
|
||||||
*/
|
*/
|
||||||
for (Thread_info *info= head.next; info != &head; info= info->next)
|
for (info= head.next; info != &head; info= info->next)
|
||||||
{
|
{
|
||||||
pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL);
|
pthread_kill(info->thread_id, THREAD_KICK_OFF_SIGNAL);
|
||||||
if (info->current_cond)
|
if (info->current_cond)
|
||||||
|
@@ -123,7 +123,6 @@ int User_map::load(const char *password_file_name)
|
|||||||
1 + /* for ':' */
|
1 + /* for ':' */
|
||||||
1 + /* for newline */
|
1 + /* for newline */
|
||||||
1]; /* for trailing zero */
|
1]; /* for trailing zero */
|
||||||
uint line_length;
|
|
||||||
User *user;
|
User *user;
|
||||||
int rc= 1;
|
int rc= 1;
|
||||||
|
|
||||||
|
@@ -1356,7 +1356,8 @@ innobase_commit(
|
|||||||
3. innobase_query_caching_of_table_permitted(),
|
3. innobase_query_caching_of_table_permitted(),
|
||||||
4. innobase_savepoint(),
|
4. innobase_savepoint(),
|
||||||
5. ::init_table_handle_for_HANDLER(),
|
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
|
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.
|
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
|
select_lock_type value. The value of
|
||||||
stored_select_lock_type was decided in:
|
stored_select_lock_type was decided in:
|
||||||
1) ::store_lock(),
|
1) ::store_lock(),
|
||||||
2) ::external_lock(), and
|
2) ::external_lock(),
|
||||||
3) ::init_table_handle_for_HANDLER(). */
|
3) ::init_table_handle_for_HANDLER(), and
|
||||||
|
4) :.transactional_table_lock(). */
|
||||||
|
|
||||||
prebuilt->select_lock_type =
|
prebuilt->select_lock_type =
|
||||||
prebuilt->stored_select_lock_type;
|
prebuilt->stored_select_lock_type;
|
||||||
@@ -5326,6 +5328,94 @@ ha_innobase::external_lock(
|
|||||||
DBUG_RETURN(0);
|
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. */
|
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 discard_or_import_tablespace(my_bool discard);
|
||||||
int extra(enum ha_extra_function operation);
|
int extra(enum ha_extra_function operation);
|
||||||
int external_lock(THD *thd, int lock_type);
|
int external_lock(THD *thd, int lock_type);
|
||||||
|
int transactional_table_lock(THD *thd, int lock_type);
|
||||||
int start_stmt(THD *thd);
|
int start_stmt(THD *thd);
|
||||||
|
|
||||||
void position(byte *record);
|
void position(byte *record);
|
||||||
|
@@ -454,6 +454,13 @@ public:
|
|||||||
{ return extra(operation); }
|
{ return extra(operation); }
|
||||||
virtual int reset() { return extra(HA_EXTRA_RESET); }
|
virtual int reset() { return extra(HA_EXTRA_RESET); }
|
||||||
virtual int external_lock(THD *thd, int lock_type) { return 0; }
|
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 void unlock_row() {}
|
||||||
virtual int start_stmt(THD *thd) {return 0;}
|
virtual int start_stmt(THD *thd) {return 0;}
|
||||||
/*
|
/*
|
||||||
|
80
sql/lock.cc
80
sql/lock.cc
@@ -79,7 +79,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
|
|||||||
bool unlock, TABLE **write_locked);
|
bool unlock, TABLE **write_locked);
|
||||||
static int lock_external(THD *thd, TABLE **table,uint count);
|
static int lock_external(THD *thd, TABLE **table,uint count);
|
||||||
static int unlock_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)
|
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)->file->external_lock(thd, F_UNLCK);
|
||||||
(*tables)->current_lock=F_UNLCK;
|
(*tables)->current_lock=F_UNLCK;
|
||||||
}
|
}
|
||||||
print_lock_error(error);
|
print_lock_error(error, (*tables)->file->table_type());
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -380,7 +380,7 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
|
|||||||
table++;
|
table++;
|
||||||
} while (--count);
|
} while (--count);
|
||||||
if (error_code)
|
if (error_code)
|
||||||
print_lock_error(error_code);
|
print_lock_error(error_code, (*table)->file->table_type());
|
||||||
DBUG_RETURN(error_code);
|
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;
|
int textno;
|
||||||
DBUG_ENTER("print_lock_error");
|
DBUG_ENTER("print_lock_error");
|
||||||
@@ -695,11 +695,22 @@ static void print_lock_error(int error)
|
|||||||
case HA_ERR_READ_ONLY_TRANSACTION:
|
case HA_ERR_READ_ONLY_TRANSACTION:
|
||||||
textno=ER_READ_ONLY_TRANSACTION;
|
textno=ER_READ_ONLY_TRANSACTION;
|
||||||
break;
|
break;
|
||||||
|
case HA_ERR_LOCK_DEADLOCK:
|
||||||
|
textno=ER_LOCK_DEADLOCK;
|
||||||
|
break;
|
||||||
|
case HA_ERR_WRONG_COMMAND:
|
||||||
|
textno=ER_ILLEGAL_HA;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
textno=ER_CANT_LOCK;
|
textno=ER_CANT_LOCK;
|
||||||
break;
|
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;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -927,3 +938,62 @@ bool make_global_read_lock_block_commit(THD *thd)
|
|||||||
thd->exit_cond(old_message);
|
thd->exit_cond(old_message);
|
||||||
DBUG_RETURN(error);
|
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);
|
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
|
||||||
bool open_and_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 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,
|
TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
|
||||||
const char *table_name, bool link_in_list);
|
const char *table_name, bool link_in_list);
|
||||||
bool rm_temporary_table(enum db_type base, char *path);
|
bool rm_temporary_table(enum db_type base, char *path);
|
||||||
|
114
sql/opt_range.cc
114
sql/opt_range.cc
@@ -777,8 +777,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
|
|||||||
|
|
||||||
QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
|
QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
|
||||||
TABLE *table)
|
TABLE *table)
|
||||||
:cur_quick_it(quick_selects),pk_quick_select(NULL),unique(NULL),
|
:pk_quick_select(NULL), thd(thd_param)
|
||||||
thd(thd_param)
|
|
||||||
{
|
{
|
||||||
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT");
|
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT");
|
||||||
index= MAX_KEY;
|
index= MAX_KEY;
|
||||||
@@ -790,17 +789,14 @@ QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
|
|||||||
|
|
||||||
int QUICK_INDEX_MERGE_SELECT::init()
|
int QUICK_INDEX_MERGE_SELECT::init()
|
||||||
{
|
{
|
||||||
cur_quick_it.rewind();
|
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::init");
|
||||||
cur_quick_select= cur_quick_it++;
|
DBUG_RETURN(0);
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int QUICK_INDEX_MERGE_SELECT::reset()
|
int QUICK_INDEX_MERGE_SELECT::reset()
|
||||||
{
|
{
|
||||||
int result;
|
|
||||||
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::reset");
|
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::reset");
|
||||||
result= cur_quick_select->reset() || prepare_unique();
|
DBUG_RETURN(read_keys_and_merge());
|
||||||
DBUG_RETURN(result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -820,8 +816,12 @@ QUICK_INDEX_MERGE_SELECT::push_quick_back(QUICK_RANGE_SELECT *quick_sel_range)
|
|||||||
|
|
||||||
QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT()
|
QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT()
|
||||||
{
|
{
|
||||||
|
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
|
||||||
|
QUICK_RANGE_SELECT* quick;
|
||||||
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT");
|
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::~QUICK_INDEX_MERGE_SELECT");
|
||||||
delete unique;
|
quick_it.rewind();
|
||||||
|
while ((quick= quick_it++))
|
||||||
|
quick->file= NULL;
|
||||||
quick_selects.delete_elements();
|
quick_selects.delete_elements();
|
||||||
delete pk_quick_select;
|
delete pk_quick_select;
|
||||||
free_root(&alloc,MYF(0));
|
free_root(&alloc,MYF(0));
|
||||||
@@ -833,7 +833,8 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
|
|||||||
TABLE *table,
|
TABLE *table,
|
||||||
bool retrieve_full_rows,
|
bool retrieve_full_rows,
|
||||||
MEM_ROOT *parent_alloc)
|
MEM_ROOT *parent_alloc)
|
||||||
: cpk_quick(NULL), thd(thd_param), need_to_fetch_row(retrieve_full_rows)
|
: cpk_quick(NULL), thd(thd_param), need_to_fetch_row(retrieve_full_rows),
|
||||||
|
scans_inited(false)
|
||||||
{
|
{
|
||||||
index= MAX_KEY;
|
index= MAX_KEY;
|
||||||
head= table;
|
head= table;
|
||||||
@@ -859,8 +860,9 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
|
|||||||
|
|
||||||
int QUICK_ROR_INTERSECT_SELECT::init()
|
int QUICK_ROR_INTERSECT_SELECT::init()
|
||||||
{
|
{
|
||||||
/* Check if last_rowid was successfully allocated in ctor */
|
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init");
|
||||||
return !last_rowid;
|
/* Check if last_rowid was successfully allocated in ctor */
|
||||||
|
DBUG_RETURN(!last_rowid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -953,7 +955,7 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler)
|
|||||||
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan");
|
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan");
|
||||||
|
|
||||||
/* Initialize all merged "children" quick selects */
|
/* Initialize all merged "children" quick selects */
|
||||||
DBUG_ASSERT(!(need_to_fetch_row && !reuse_handler));
|
DBUG_ASSERT(!need_to_fetch_row || reuse_handler);
|
||||||
if (!need_to_fetch_row && reuse_handler)
|
if (!need_to_fetch_row && reuse_handler)
|
||||||
{
|
{
|
||||||
quick= quick_it++;
|
quick= quick_it++;
|
||||||
@@ -995,7 +997,14 @@ int QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan(bool reuse_handler)
|
|||||||
int QUICK_ROR_INTERSECT_SELECT::reset()
|
int QUICK_ROR_INTERSECT_SELECT::reset()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::reset");
|
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::reset");
|
||||||
DBUG_RETURN(init_ror_merged_scan(TRUE));
|
if (!scans_inited && init_ror_merged_scan(TRUE))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
scans_inited= true;
|
||||||
|
List_iterator_fast<QUICK_RANGE_SELECT> it(quick_selects);
|
||||||
|
QUICK_RANGE_SELECT *quick;
|
||||||
|
while ((quick= it++))
|
||||||
|
quick->reset();
|
||||||
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1034,7 +1043,7 @@ QUICK_ROR_INTERSECT_SELECT::~QUICK_ROR_INTERSECT_SELECT()
|
|||||||
|
|
||||||
QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
|
QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
|
||||||
TABLE *table)
|
TABLE *table)
|
||||||
:thd(thd_param)
|
: thd(thd_param), scans_inited(false)
|
||||||
{
|
{
|
||||||
index= MAX_KEY;
|
index= MAX_KEY;
|
||||||
head= table;
|
head= table;
|
||||||
@@ -1057,18 +1066,19 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
|
|||||||
|
|
||||||
int QUICK_ROR_UNION_SELECT::init()
|
int QUICK_ROR_UNION_SELECT::init()
|
||||||
{
|
{
|
||||||
|
DBUG_ENTER("QUICK_ROR_UNION_SELECT::init");
|
||||||
if (init_queue(&queue, quick_selects.elements, 0,
|
if (init_queue(&queue, quick_selects.elements, 0,
|
||||||
FALSE , QUICK_ROR_UNION_SELECT::queue_cmp,
|
FALSE , QUICK_ROR_UNION_SELECT::queue_cmp,
|
||||||
(void*) this))
|
(void*) this))
|
||||||
{
|
{
|
||||||
bzero(&queue, sizeof(QUEUE));
|
bzero(&queue, sizeof(QUEUE));
|
||||||
return 1;
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(cur_rowid= (byte*)alloc_root(&alloc, 2*head->file->ref_length)))
|
if (!(cur_rowid= (byte*)alloc_root(&alloc, 2*head->file->ref_length)))
|
||||||
return 1;
|
DBUG_RETURN(1);
|
||||||
prev_rowid= cur_rowid + head->file->ref_length;
|
prev_rowid= cur_rowid + head->file->ref_length;
|
||||||
return 0;
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1106,6 +1116,18 @@ int QUICK_ROR_UNION_SELECT::reset()
|
|||||||
int error;
|
int error;
|
||||||
DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset");
|
DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset");
|
||||||
have_prev_rowid= FALSE;
|
have_prev_rowid= FALSE;
|
||||||
|
if (!scans_inited)
|
||||||
|
{
|
||||||
|
QUICK_SELECT_I *quick;
|
||||||
|
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
|
||||||
|
while ((quick= it++))
|
||||||
|
{
|
||||||
|
if (quick->init_ror_merged_scan(FALSE))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
scans_inited= true;
|
||||||
|
}
|
||||||
|
queue_remove_all(&queue);
|
||||||
/*
|
/*
|
||||||
Initialize scans for merged quick selects and put all merged quick
|
Initialize scans for merged quick selects and put all merged quick
|
||||||
selects into the queue.
|
selects into the queue.
|
||||||
@@ -1113,7 +1135,7 @@ int QUICK_ROR_UNION_SELECT::reset()
|
|||||||
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
|
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
|
||||||
while ((quick= it++))
|
while ((quick= it++))
|
||||||
{
|
{
|
||||||
if (quick->init_ror_merged_scan(FALSE))
|
if (quick->reset())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
if ((error= quick->get_next()))
|
if ((error= quick->get_next()))
|
||||||
{
|
{
|
||||||
@@ -1591,7 +1613,6 @@ int SQL_SELECT::test_quick_select(THD *thd, key_map keys_to_use,
|
|||||||
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
|
DBUG_PRINT("enter",("keys_to_use: %lu prev_tables: %lu const_tables: %lu",
|
||||||
keys_to_use.to_ulonglong(), (ulong) prev_tables,
|
keys_to_use.to_ulonglong(), (ulong) prev_tables,
|
||||||
(ulong) const_tables));
|
(ulong) const_tables));
|
||||||
|
|
||||||
delete quick;
|
delete quick;
|
||||||
quick=0;
|
quick=0;
|
||||||
needed_reg.clear_all();
|
needed_reg.clear_all();
|
||||||
@@ -5553,22 +5574,29 @@ err:
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Fetch all row ids into unique.
|
Perform key scans for all used indexes (except CPK), get rowids and merge
|
||||||
|
them into an ordered non-recurrent sequence of rowids.
|
||||||
|
|
||||||
|
The merge/duplicate removal is performed using Unique class. We put all
|
||||||
|
rowids into Unique, get the sorted sequence and destroy the Unique.
|
||||||
|
|
||||||
If table has a clustered primary key that covers all rows (TRUE for bdb
|
If table has a clustered primary key that covers all rows (TRUE for bdb
|
||||||
and innodb currently) and one of the index_merge scans is a scan on PK,
|
and innodb currently) and one of the index_merge scans is a scan on PK,
|
||||||
then
|
then
|
||||||
primary key scan rowids are not put into Unique and also
|
rows that will be retrieved by PK scan are not put into Unique and
|
||||||
rows that will be retrieved by PK scan are not put into Unique
|
primary key scan is not performed here, it is performed later separately.
|
||||||
|
|
||||||
RETURN
|
RETURN
|
||||||
0 OK
|
0 OK
|
||||||
other error
|
other error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int QUICK_INDEX_MERGE_SELECT::prepare_unique()
|
int QUICK_INDEX_MERGE_SELECT::read_keys_and_merge()
|
||||||
{
|
{
|
||||||
|
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it(quick_selects);
|
||||||
|
QUICK_RANGE_SELECT* cur_quick;
|
||||||
int result;
|
int result;
|
||||||
|
Unique *unique;
|
||||||
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique");
|
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique");
|
||||||
|
|
||||||
/* We're going to just read rowids. */
|
/* We're going to just read rowids. */
|
||||||
@@ -5583,7 +5611,17 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
|
|||||||
*/
|
*/
|
||||||
head->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
|
head->file->extra(HA_EXTRA_RETRIEVE_ALL_COLS);
|
||||||
|
|
||||||
cur_quick_select->init();
|
cur_quick_it.rewind();
|
||||||
|
cur_quick= cur_quick_it++;
|
||||||
|
DBUG_ASSERT(cur_quick);
|
||||||
|
|
||||||
|
/*
|
||||||
|
We reuse the same instance of handler so we need to call both init and
|
||||||
|
reset here.
|
||||||
|
*/
|
||||||
|
if (cur_quick->init())
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
cur_quick->reset();
|
||||||
|
|
||||||
unique= new Unique(refpos_order_cmp, (void *)head->file,
|
unique= new Unique(refpos_order_cmp, (void *)head->file,
|
||||||
head->file->ref_length,
|
head->file->ref_length,
|
||||||
@@ -5592,24 +5630,28 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
|
|||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
while ((result= cur_quick_select->get_next()) == HA_ERR_END_OF_FILE)
|
while ((result= cur_quick->get_next()) == HA_ERR_END_OF_FILE)
|
||||||
{
|
{
|
||||||
cur_quick_select->range_end();
|
cur_quick->range_end();
|
||||||
cur_quick_select= cur_quick_it++;
|
cur_quick= cur_quick_it++;
|
||||||
if (!cur_quick_select)
|
if (!cur_quick)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (cur_quick_select->init())
|
if (cur_quick->file->inited != handler::NONE)
|
||||||
|
cur_quick->file->ha_index_end();
|
||||||
|
if (cur_quick->init())
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
/* QUICK_RANGE_SELECT::reset never fails */
|
/* QUICK_RANGE_SELECT::reset never fails */
|
||||||
cur_quick_select->reset();
|
cur_quick->reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result)
|
if (result)
|
||||||
{
|
{
|
||||||
if (result != HA_ERR_END_OF_FILE)
|
if (result != HA_ERR_END_OF_FILE)
|
||||||
|
{
|
||||||
|
cur_quick->range_end();
|
||||||
DBUG_RETURN(result);
|
DBUG_RETURN(result);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5620,8 +5662,8 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
|
|||||||
if (pk_quick_select && pk_quick_select->row_in_ranges())
|
if (pk_quick_select && pk_quick_select->row_in_ranges())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cur_quick_select->file->position(cur_quick_select->record);
|
cur_quick->file->position(cur_quick->record);
|
||||||
result= unique->unique_add((char*)cur_quick_select->file->ref);
|
result= unique->unique_add((char*)cur_quick->file->ref);
|
||||||
if (result)
|
if (result)
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
@@ -5629,6 +5671,7 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
|
|||||||
|
|
||||||
/* ok, all row ids are in Unique */
|
/* ok, all row ids are in Unique */
|
||||||
result= unique->get(head);
|
result= unique->get(head);
|
||||||
|
delete unique;
|
||||||
doing_pk_scan= FALSE;
|
doing_pk_scan= FALSE;
|
||||||
/* start table scan */
|
/* start table scan */
|
||||||
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1);
|
init_read_record(&read_record, thd, head, (SQL_SELECT*) 0, 1, 1);
|
||||||
@@ -5668,6 +5711,7 @@ int QUICK_INDEX_MERGE_SELECT::get_next()
|
|||||||
doing_pk_scan= TRUE;
|
doing_pk_scan= TRUE;
|
||||||
if ((result= pk_quick_select->init()))
|
if ((result= pk_quick_select->init()))
|
||||||
DBUG_RETURN(result);
|
DBUG_RETURN(result);
|
||||||
|
pk_quick_select->reset();
|
||||||
DBUG_RETURN(pk_quick_select->get_next());
|
DBUG_RETURN(pk_quick_select->get_next());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -127,7 +127,8 @@ public:
|
|||||||
reset() should be called when it is certain that row retrieval will be
|
reset() should be called when it is certain that row retrieval will be
|
||||||
necessary. This call may do heavyweight initialization like buffering first
|
necessary. This call may do heavyweight initialization like buffering first
|
||||||
N records etc. If reset() call fails get_next() must not be called.
|
N records etc. If reset() call fails get_next() must not be called.
|
||||||
|
Note that reset() may be called several times if this quick select
|
||||||
|
executes in a subselect.
|
||||||
RETURN
|
RETURN
|
||||||
0 OK
|
0 OK
|
||||||
other Error code
|
other Error code
|
||||||
@@ -274,6 +275,10 @@ public:
|
|||||||
next=0;
|
next=0;
|
||||||
range= NULL;
|
range= NULL;
|
||||||
cur_range= NULL;
|
cur_range= NULL;
|
||||||
|
/*
|
||||||
|
Note: in opt_range.cc there are places where it is assumed that this
|
||||||
|
function always succeeds
|
||||||
|
*/
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int init();
|
int init();
|
||||||
@@ -388,21 +393,15 @@ public:
|
|||||||
/* range quick selects this index_merge read consists of */
|
/* range quick selects this index_merge read consists of */
|
||||||
List<QUICK_RANGE_SELECT> quick_selects;
|
List<QUICK_RANGE_SELECT> quick_selects;
|
||||||
|
|
||||||
/* quick select which is currently used for rows retrieval */
|
|
||||||
List_iterator_fast<QUICK_RANGE_SELECT> cur_quick_it;
|
|
||||||
QUICK_RANGE_SELECT* cur_quick_select;
|
|
||||||
|
|
||||||
/* quick select that uses clustered primary key (NULL if none) */
|
/* quick select that uses clustered primary key (NULL if none) */
|
||||||
QUICK_RANGE_SELECT* pk_quick_select;
|
QUICK_RANGE_SELECT* pk_quick_select;
|
||||||
|
|
||||||
/* true if this select is currently doing a clustered PK scan */
|
/* true if this select is currently doing a clustered PK scan */
|
||||||
bool doing_pk_scan;
|
bool doing_pk_scan;
|
||||||
|
|
||||||
Unique *unique;
|
|
||||||
MEM_ROOT alloc;
|
MEM_ROOT alloc;
|
||||||
|
|
||||||
THD *thd;
|
THD *thd;
|
||||||
int prepare_unique();
|
int read_keys_and_merge();
|
||||||
|
|
||||||
/* used to get rows collected in Unique */
|
/* used to get rows collected in Unique */
|
||||||
READ_RECORD read_record;
|
READ_RECORD read_record;
|
||||||
@@ -465,6 +464,8 @@ public:
|
|||||||
MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */
|
MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */
|
||||||
THD *thd; /* current thread */
|
THD *thd; /* current thread */
|
||||||
bool need_to_fetch_row; /* if true, do retrieve full table records. */
|
bool need_to_fetch_row; /* if true, do retrieve full table records. */
|
||||||
|
/* in top-level quick select, true if merged scans where initialized */
|
||||||
|
bool scans_inited;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -514,6 +515,7 @@ public:
|
|||||||
uint rowid_length; /* table rowid length */
|
uint rowid_length; /* table rowid length */
|
||||||
private:
|
private:
|
||||||
static int queue_cmp(void *arg, byte *val1, byte *val2);
|
static int queue_cmp(void *arg, byte *val1, byte *val2);
|
||||||
|
bool scans_inited;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1864,8 +1864,7 @@ bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
|
|||||||
|
|
||||||
static void relink_tables_for_multidelete(THD *thd)
|
static void relink_tables_for_multidelete(THD *thd)
|
||||||
{
|
{
|
||||||
if (thd->lex->all_selects_list->next_select_in_list() ||
|
if (thd->lex->all_selects_list->next_select_in_list())
|
||||||
thd->lex->time_zone_tables_used)
|
|
||||||
{
|
{
|
||||||
for (SELECT_LEX *sl= thd->lex->all_selects_list;
|
for (SELECT_LEX *sl= thd->lex->all_selects_list;
|
||||||
sl;
|
sl;
|
||||||
|
@@ -30,15 +30,6 @@
|
|||||||
*/
|
*/
|
||||||
sys_var_long_ptr trg_new_row_fake_var(0, 0);
|
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 */
|
/* Macros to look like lex */
|
||||||
|
|
||||||
#define yyGet() *(lex->ptr++)
|
#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()
|
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_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE,
|
||||||
SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW,
|
SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW,
|
||||||
SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
|
SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
|
||||||
|
SQLCOM_LOCK_TABLES_TRANSACTIONAL,
|
||||||
/* This should be the last !!! */
|
/* This should be the last !!! */
|
||||||
SQLCOM_END
|
SQLCOM_END
|
||||||
};
|
};
|
||||||
@@ -735,9 +736,8 @@ typedef struct st_lex
|
|||||||
/* Names of user variables holding parameters (in EXECUTE) */
|
/* Names of user variables holding parameters (in EXECUTE) */
|
||||||
List<LEX_STRING> prepared_stmt_params;
|
List<LEX_STRING> prepared_stmt_params;
|
||||||
/*
|
/*
|
||||||
If points to fake_time_zone_tables_list indicates that time zone
|
Points to part of global table list which contains time zone tables
|
||||||
tables are implicitly used by statement, also is used for holding
|
implicitly used by the statement.
|
||||||
list of those tables after they are opened.
|
|
||||||
*/
|
*/
|
||||||
TABLE_LIST *time_zone_tables_used;
|
TABLE_LIST *time_zone_tables_used;
|
||||||
sp_head *sphead;
|
sp_head *sphead;
|
||||||
@@ -802,6 +802,7 @@ typedef struct st_lex
|
|||||||
*(table->prev_global= query_tables_last)= table;
|
*(table->prev_global= query_tables_last)= table;
|
||||||
query_tables_last= &table->next_global;
|
query_tables_last= &table->next_global;
|
||||||
}
|
}
|
||||||
|
bool add_time_zone_tables_to_query_tables(THD *thd);
|
||||||
|
|
||||||
bool can_be_merged();
|
bool can_be_merged();
|
||||||
bool can_use_merged();
|
bool can_use_merged();
|
||||||
@@ -810,7 +811,6 @@ typedef struct st_lex
|
|||||||
bool need_correct_ident();
|
bool need_correct_ident();
|
||||||
} LEX;
|
} LEX;
|
||||||
|
|
||||||
extern TABLE_LIST fake_time_zone_tables_list;
|
|
||||||
struct st_lex_local: public st_lex
|
struct st_lex_local: public st_lex
|
||||||
{
|
{
|
||||||
static void *operator new(size_t size)
|
static void *operator new(size_t size)
|
||||||
|
@@ -2123,19 +2123,6 @@ mysql_execute_command(THD *thd)
|
|||||||
}
|
}
|
||||||
#endif /* !HAVE_REPLICATION */
|
#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.
|
When option readonly is set deny operations which change tables.
|
||||||
Except for the replication thread and the 'super' users.
|
Except for the replication thread and the 'super' users.
|
||||||
@@ -3266,6 +3253,27 @@ create_error:
|
|||||||
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
|
thd->options&= ~(ulong) (OPTION_TABLE_LOCK);
|
||||||
thd->in_lock_tables=0;
|
thd->in_lock_tables=0;
|
||||||
break;
|
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:
|
case SQLCOM_CREATE_DB:
|
||||||
{
|
{
|
||||||
char *alias;
|
char *alias;
|
||||||
|
@@ -64,6 +64,7 @@ static void best_extension_by_limited_search(JOIN *join,
|
|||||||
uint prune_level);
|
uint prune_level);
|
||||||
static uint determine_search_depth(JOIN* join);
|
static uint determine_search_depth(JOIN* join);
|
||||||
static int join_tab_cmp(const void* ptr1, const void* ptr2);
|
static int join_tab_cmp(const void* ptr1, const void* ptr2);
|
||||||
|
static int join_tab_cmp_straight(const void* ptr1, const void* ptr2);
|
||||||
/*
|
/*
|
||||||
TODO: 'find_best' is here only temporarily until 'greedy_search' is
|
TODO: 'find_best' is here only temporarily until 'greedy_search' is
|
||||||
tested and approved.
|
tested and approved.
|
||||||
@@ -3678,22 +3679,26 @@ choose_plan(JOIN *join, table_map join_tables)
|
|||||||
{
|
{
|
||||||
uint search_depth= join->thd->variables.optimizer_search_depth;
|
uint search_depth= join->thd->variables.optimizer_search_depth;
|
||||||
uint prune_level= join->thd->variables.optimizer_prune_level;
|
uint prune_level= join->thd->variables.optimizer_prune_level;
|
||||||
|
bool straight_join= join->select_options & SELECT_STRAIGHT_JOIN;
|
||||||
DBUG_ENTER("choose_plan");
|
DBUG_ENTER("choose_plan");
|
||||||
|
|
||||||
if (join->select_options & SELECT_STRAIGHT_JOIN)
|
/*
|
||||||
|
if (SELECT_STRAIGHT_JOIN option is set)
|
||||||
|
reorder tables so dependent tables come after tables they depend
|
||||||
|
on, otherwise keep tables in the order they were specified in the query
|
||||||
|
else
|
||||||
|
Apply heuristic: pre-sort all access plans with respect to the number of
|
||||||
|
records accessed.
|
||||||
|
*/
|
||||||
|
qsort(join->best_ref + join->const_tables, join->tables - join->const_tables,
|
||||||
|
sizeof(JOIN_TAB*), straight_join?join_tab_cmp_straight:join_tab_cmp);
|
||||||
|
|
||||||
|
if (straight_join)
|
||||||
{
|
{
|
||||||
optimize_straight_join(join, join_tables);
|
optimize_straight_join(join, join_tables);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
Heuristic: pre-sort all access plans with respect to the number of
|
|
||||||
records accessed.
|
|
||||||
*/
|
|
||||||
qsort(join->best_ref + join->const_tables, join->tables - join->const_tables,
|
|
||||||
sizeof(JOIN_TAB*), join_tab_cmp);
|
|
||||||
|
|
||||||
if (search_depth == MAX_TABLES+2)
|
if (search_depth == MAX_TABLES+2)
|
||||||
{ /*
|
{ /*
|
||||||
TODO: 'MAX_TABLES+2' denotes the old implementation of find_best before
|
TODO: 'MAX_TABLES+2' denotes the old implementation of find_best before
|
||||||
@@ -3750,6 +3755,23 @@ join_tab_cmp(const void* ptr1, const void* ptr2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Same as join_tab_cmp, but for use with SELECT_STRAIGHT_JOIN.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
join_tab_cmp_straight(const void* ptr1, const void* ptr2)
|
||||||
|
{
|
||||||
|
JOIN_TAB *jt1= *(JOIN_TAB**) ptr1;
|
||||||
|
JOIN_TAB *jt2= *(JOIN_TAB**) ptr2;
|
||||||
|
|
||||||
|
if (jt1->dependent & jt2->table->map)
|
||||||
|
return 1;
|
||||||
|
if (jt2->dependent & jt1->table->map)
|
||||||
|
return -1;
|
||||||
|
return jt1 > jt2 ? 1 : (jt1 < jt2 ? -1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Heuristic procedure to automatically guess a reasonable degree of
|
Heuristic procedure to automatically guess a reasonable degree of
|
||||||
exhaustiveness for the greedy search procedure.
|
exhaustiveness for the greedy search procedure.
|
||||||
@@ -3832,7 +3854,7 @@ optimize_straight_join(JOIN *join, table_map join_tables)
|
|||||||
uint idx= join->const_tables;
|
uint idx= join->const_tables;
|
||||||
double record_count= 1.0;
|
double record_count= 1.0;
|
||||||
double read_time= 0.0;
|
double read_time= 0.0;
|
||||||
|
|
||||||
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
|
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
|
||||||
{
|
{
|
||||||
/* Find the best access method from 's' to the current partial plan */
|
/* Find the best access method from 's' to the current partial plan */
|
||||||
|
@@ -4269,7 +4269,8 @@ simple_expr:
|
|||||||
{ $$= create_func_contains($3, $5); }
|
{ $$= create_func_contains($3, $5); }
|
||||||
| CONVERT_TZ_SYM '(' expr ',' expr ',' expr ')'
|
| 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);
|
$$= new Item_func_convert_tz($3, $5, $7);
|
||||||
}
|
}
|
||||||
| CURDATE optional_braces
|
| CURDATE optional_braces
|
||||||
@@ -7307,8 +7308,9 @@ internal_variable_name:
|
|||||||
If this is time_zone variable we should open time zone
|
If this is time_zone variable we should open time zone
|
||||||
describing tables
|
describing tables
|
||||||
*/
|
*/
|
||||||
if (tmp == &sys_time_zone)
|
if (tmp == &sys_time_zone &&
|
||||||
Lex->time_zone_tables_used= &fake_time_zone_tables_list;
|
lex->add_time_zone_tables_to_query_tables(YYTHD))
|
||||||
|
YYABORT;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -7413,8 +7415,8 @@ lock:
|
|||||||
{
|
{
|
||||||
Lex->sql_command=SQLCOM_LOCK_TABLES;
|
Lex->sql_command=SQLCOM_LOCK_TABLES;
|
||||||
}
|
}
|
||||||
table_lock_list
|
table_lock_list lock_engine_opt
|
||||||
{}
|
{}
|
||||||
;
|
;
|
||||||
|
|
||||||
table_or_tables:
|
table_or_tables:
|
||||||
@@ -7440,6 +7442,15 @@ lock_option:
|
|||||||
| READ_SYM LOCAL_SYM { $$= TL_READ; }
|
| 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:
|
||||||
UNLOCK_SYM table_or_tables { Lex->sql_command=SQLCOM_UNLOCK_TABLES; }
|
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
|
Create table list with time zone related tables and add it to the end
|
||||||
of global table list.
|
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 my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
|
||||||
extern void my_tz_free();
|
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
|
Check if we have pointer to the beggining of list of implictly used
|
||||||
|
Reference in New Issue
Block a user