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:
tomas@poseidon.ndb.mysql.com 2004-12-23 09:50:53 +01:00
commit 9e3560fd4e
33 changed files with 589 additions and 121 deletions

View file

@ -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),

View file

@ -53,6 +53,7 @@ int resize_queue(QUEUE *queue, uint max_elements);
void delete_queue(QUEUE *queue);
void queue_insert(QUEUE *queue,byte *element);
byte *queue_remove(QUEUE *queue,uint idx);
#define queue_remove_all(queue) { (queue)->elements= 0; }
void _downheap(QUEUE *queue,uint idx);
void queue_fix(QUEUE *queue);
#define is_queue_inited(queue) ((queue)->root != 0)

View file

@ -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 */

View file

@ -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)

View file

@ -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++) {

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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
(
key1 int not null,
@ -335,4 +335,55 @@ key1 key2 key3 key4 key5 key6 key7 key8
select count(*) from t0;
count(*)
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;

View file

@ -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 t2 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;

View file

@ -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;

View file

@ -1,9 +1,8 @@
#
# Index merge tests
#
--disable_warnings
drop table if exists t0, t1, t2, t3,t4;
drop table if exists t0, t1, t2, t3, t4;
--enable_warnings
# 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 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;

View file

@ -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;
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;

View file

@ -64,7 +64,7 @@ class NdbEventOperationImpl;
*
* 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
* be the same for all and decided by the first NdbEventOperation
* 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
* 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
* again. Will be fixed in later versions.
*
@ -97,7 +97,7 @@ class NdbEventOperationImpl;
*
* 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.
*
*/
@ -187,8 +187,19 @@ public:
*/
NdbDictionary::Event::TableEvent getEventType();
/**
*
*/
Uint32 getGCI();
/**
*
*/
Uint32 getLatestGCI();
/*
*
*/
void print();
private:

View file

@ -296,7 +296,6 @@ int Mysql_connection_thread::check_user(const char *user, const char *password)
int Mysql_connection_thread::do_command()
{
char *packet;
uint old_timeout;
ulong packet_length;
/* We start to count packets from 0 for each new command */

View file

@ -131,7 +131,6 @@ Command *parse_command(Command_factory *factory, const char *text)
const char *instance_name;
uint instance_name_len;
Command *command;
const char *saved_text= text;
Token tok1= shift_token(&text, &word_len);

View file

@ -148,6 +148,7 @@ int Thread_registry::cond_wait(Thread_info *info, pthread_cond_t *cond,
void Thread_registry::deliver_shutdown()
{
Thread_info *info;
struct timespec shutdown_time;
set_timespec(shutdown_time, 1);
@ -161,7 +162,7 @@ void Thread_registry::deliver_shutdown()
stopped alarm processing.
*/
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);
/*
@ -190,7 +191,7 @@ void Thread_registry::deliver_shutdown()
so this time everybody should be informed (presumably each worker can
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);
if (info->current_cond)

View file

@ -123,7 +123,6 @@ int User_map::load(const char *password_file_name)
1 + /* for ':' */
1 + /* for newline */
1]; /* for trailing zero */
uint line_length;
User *user;
int rc= 1;

View file

@ -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. */

View file

@ -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);

View file

@ -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;}
/*

View file

@ -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);
}

View file

@ -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);

View file

@ -777,8 +777,7 @@ QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT()
QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
TABLE *table)
:cur_quick_it(quick_selects),pk_quick_select(NULL),unique(NULL),
thd(thd_param)
:pk_quick_select(NULL), thd(thd_param)
{
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT");
index= MAX_KEY;
@ -790,17 +789,14 @@ QUICK_INDEX_MERGE_SELECT::QUICK_INDEX_MERGE_SELECT(THD *thd_param,
int QUICK_INDEX_MERGE_SELECT::init()
{
cur_quick_it.rewind();
cur_quick_select= cur_quick_it++;
return 0;
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::init");
DBUG_RETURN(0);
}
int QUICK_INDEX_MERGE_SELECT::reset()
{
int result;
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::reset");
result= cur_quick_select->reset() || prepare_unique();
DBUG_RETURN(result);
DBUG_RETURN(read_keys_and_merge());
}
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()
{
List_iterator_fast<QUICK_RANGE_SELECT> quick_it(quick_selects);
QUICK_RANGE_SELECT* quick;
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();
delete pk_quick_select;
free_root(&alloc,MYF(0));
@ -833,7 +833,8 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
TABLE *table,
bool retrieve_full_rows,
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;
head= table;
@ -859,8 +860,9 @@ QUICK_ROR_INTERSECT_SELECT::QUICK_ROR_INTERSECT_SELECT(THD *thd_param,
int QUICK_ROR_INTERSECT_SELECT::init()
{
/* Check if last_rowid was successfully allocated in ctor */
return !last_rowid;
DBUG_ENTER("QUICK_ROR_INTERSECT_SELECT::init");
/* 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");
/* 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)
{
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()
{
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,
TABLE *table)
:thd(thd_param)
: thd(thd_param), scans_inited(false)
{
index= MAX_KEY;
head= table;
@ -1057,18 +1066,19 @@ QUICK_ROR_UNION_SELECT::QUICK_ROR_UNION_SELECT(THD *thd_param,
int QUICK_ROR_UNION_SELECT::init()
{
DBUG_ENTER("QUICK_ROR_UNION_SELECT::init");
if (init_queue(&queue, quick_selects.elements, 0,
FALSE , QUICK_ROR_UNION_SELECT::queue_cmp,
(void*) this))
{
bzero(&queue, sizeof(QUEUE));
return 1;
DBUG_RETURN(1);
}
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;
return 0;
DBUG_RETURN(0);
}
@ -1106,6 +1116,18 @@ int QUICK_ROR_UNION_SELECT::reset()
int error;
DBUG_ENTER("QUICK_ROR_UNION_SELECT::reset");
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
selects into the queue.
@ -1113,7 +1135,7 @@ int QUICK_ROR_UNION_SELECT::reset()
List_iterator_fast<QUICK_SELECT_I> it(quick_selects);
while ((quick= it++))
{
if (quick->init_ror_merged_scan(FALSE))
if (quick->reset())
DBUG_RETURN(1);
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",
keys_to_use.to_ulonglong(), (ulong) prev_tables,
(ulong) const_tables));
delete quick;
quick=0;
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
and innodb currently) and one of the index_merge scans is a scan on PK,
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
rows that will be retrieved by PK scan are not put into Unique and
primary key scan is not performed here, it is performed later separately.
RETURN
0 OK
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;
Unique *unique;
DBUG_ENTER("QUICK_INDEX_MERGE_SELECT::prepare_unique");
/* 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);
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,
head->file->ref_length,
@ -5592,24 +5630,28 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
DBUG_RETURN(1);
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_select= cur_quick_it++;
if (!cur_quick_select)
cur_quick->range_end();
cur_quick= cur_quick_it++;
if (!cur_quick)
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);
/* QUICK_RANGE_SELECT::reset never fails */
cur_quick_select->reset();
cur_quick->reset();
}
if (result)
{
if (result != HA_ERR_END_OF_FILE)
{
cur_quick->range_end();
DBUG_RETURN(result);
}
break;
}
@ -5620,8 +5662,8 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
if (pk_quick_select && pk_quick_select->row_in_ranges())
continue;
cur_quick_select->file->position(cur_quick_select->record);
result= unique->unique_add((char*)cur_quick_select->file->ref);
cur_quick->file->position(cur_quick->record);
result= unique->unique_add((char*)cur_quick->file->ref);
if (result)
DBUG_RETURN(1);
@ -5629,6 +5671,7 @@ int QUICK_INDEX_MERGE_SELECT::prepare_unique()
/* ok, all row ids are in Unique */
result= unique->get(head);
delete unique;
doing_pk_scan= FALSE;
/* start table scan */
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;
if ((result= pk_quick_select->init()))
DBUG_RETURN(result);
pk_quick_select->reset();
DBUG_RETURN(pk_quick_select->get_next());
}
}

View file

@ -127,7 +127,8 @@ public:
reset() should be called when it is certain that row retrieval will be
necessary. This call may do heavyweight initialization like buffering first
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
0 OK
other Error code
@ -274,6 +275,10 @@ public:
next=0;
range= NULL;
cur_range= NULL;
/*
Note: in opt_range.cc there are places where it is assumed that this
function always succeeds
*/
return 0;
}
int init();
@ -388,21 +393,15 @@ public:
/* range quick selects this index_merge read consists of */
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_RANGE_SELECT* pk_quick_select;
/* true if this select is currently doing a clustered PK scan */
bool doing_pk_scan;
Unique *unique;
MEM_ROOT alloc;
THD *thd;
int prepare_unique();
int read_keys_and_merge();
/* used to get rows collected in Unique */
READ_RECORD read_record;
@ -465,6 +464,8 @@ public:
MEM_ROOT alloc; /* Memory pool for this and merged quick selects data. */
THD *thd; /* current thread */
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 */
private:
static int queue_cmp(void *arg, byte *val1, byte *val2);
bool scans_inited;
};

View file

@ -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;

View file

@ -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()

View file

@ -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)

View file

@ -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;

View file

@ -64,6 +64,7 @@ static void best_extension_by_limited_search(JOIN *join,
uint prune_level);
static uint determine_search_depth(JOIN* join);
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
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 prune_level= join->thd->variables.optimizer_prune_level;
bool straight_join= join->select_options & SELECT_STRAIGHT_JOIN;
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);
}
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)
{ /*
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
exhaustiveness for the greedy search procedure.
@ -3832,7 +3854,7 @@ optimize_straight_join(JOIN *join, table_map join_tables)
uint idx= join->const_tables;
double record_count= 1.0;
double read_time= 0.0;
for (JOIN_TAB **pos= join->best_ref + idx ; (s= *pos) ; pos++)
{
/* Find the best access method from 's' to the current partial plan */

View file

@ -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; }
;

View file

@ -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.

View file

@ -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