Commit 0732f747 authored by monty@donna.mysql.com's avatar monty@donna.mysql.com

Fixed for bugs that was found when getting full code coverage of BDB

Fixed bug with HEAP tables on windows
Fixed bug with HAVING on empty tables
parent 5f4a3f51
......@@ -31588,17 +31588,22 @@ message to less than 80 characters so that it fits the width of a standard
terminal screen.
The return value of the main function @code{xxx()} is the function value, for
@code{long long} and @code{double} functions. For string functions, the
string is returned in the @code{result} and @code{length} arguments.
@code{result} is a buffer at least 255 bytes long. Set these to the contents
and length of the return value. For example:
@code{long long} and @code{double} functions. A string functions should
return a pointer to the result and store the length of the string in the
@code{length} arguments. @code{result} is a buffer at least 255 bytes long.
Set these to the contents and length of the return value. For example:
@example
memcpy(result, "result string", 13);
*length = 13;
@end example
The string function return value normally also points to the result.
If your string functions that needs to return a string longer than 255
bytes, you must allocate the space for it with @code{malloc()} in your
@code{xxx_init()} function or your @code{xxx()} function and free it in
your @code{xxx_deinit()} function. You can store the allocated memory
in the @code{ptr} slot in the @code{UDF_INIT} structure for reuse by
future @code{xxx()} calls. @xref{UDF calling sequences}.
To indicate a return value of @code{NULL} in the main function, set
@code{is_null} to @code{1}:
......@@ -40403,6 +40408,12 @@ though, so Version 3.23 is not released as a stable version yet.
@appendixsubsec Changes in release 3.23.31
@itemize @bullet
@item
Using @code{HAVING} on an empty table could produce one result row.
@item
Fixed that the @strong{MySQL} RPM is not depending on perl5 anymore.
@item
Fixed some problems with @code{HEAP} tables on windows.
@item
@code{SHOW TABLE STATUS} didn't show correct average row length for tables
bigger than 4G.
@item
......@@ -40412,15 +40423,16 @@ Added option @code{MEDIUM} to @code{CHECK TABLE}.
@item
Fixed problem when using @code{DECIMAL()} keys on negative numbers.
@item
@code{HOUR()} on a @code{CHAR} column always returned @code{NULL}.
@code{HOUR()} (and some other @code{TIME} functions) on a @code{CHAR} column
always returned @code{NULL}.
@item
Fixed security bug in something (please upgrade if you are using a earlier
MySQL 3.23 version).
@item
Fixed buffer overflow bug when writing a certain error message.
@item
Added usage of @code{getrlimit()} on Linux to get @code{-O --open-files-limit=#}
to work on Linux.
Added usage of @code{getrlimit()} on Linux to get @code{-O
--open-files-limit=#} to work on Linux.
@item
Added new mysqld variable: bdb_version.
@item
......@@ -100,10 +100,12 @@ DO_GCOV=""
DO_GDB=""
DO_DDD=""
SLEEP_TIME=2
DBUSER=""
while test $# -gt 0; do
case "$1" in
--force ) FORCE=1 ;;
--user=*) DBUSER=`$ECHO "$1" | $SED -e "s;--user=;;"` ;;
--force) FORCE=1 ;;
--local) USE_RUNNING_SERVER="" ;;
--tmpdir=*) MYSQL_TMP_DIR=`$ECHO "$1" | $SED -e "s;--tmpdir=;;"` ;;
--master_port=*) MASTER_MYPORT=`$ECHO "$1" | $SED -e "s;--master_port=;;"` ;;
......@@ -209,9 +211,9 @@ fi
if [ -n "$USE_RUNNING_SERVER" ]
then
MASTER_MYSOCK="/tmp/mysql.sock"
DBUSER=test
DBUSER=${DBUSER:-test}
else
DBUSER=root # We want to do FLUSH xxx commands
DBUSER=${DBUSER:-root} # We want to do FLUSH xxx commands
fi
if [ -w / ]
......
......@@ -147,6 +147,12 @@ Table Op Msg_type Msg_text
test.t1 check error The handler for the table doesn't support check/repair
a b
2 testing
Table Op Msg_type Msg_text
test.t1 analyze status OK
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
t1 1 skr 1 a A 3 NULL NULL
a b
1
a b
a 1
a 2
......@@ -429,6 +435,8 @@ count(*)
count(*)
1
count(*)
0
count(*)
1
count(*)
1
......@@ -468,4 +476,4 @@ hello 1
Table Op Msg_type Msg_text
test.t1 optimize status OK
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Comment
t1 0 PRIMARY 1 a A 1 NULL NULL
t1 0 PRIMARY 1 a A 2 NULL NULL
......@@ -4,7 +4,7 @@
# Small basic test with ignore
#
drop table if exists t1;
drop table if exists t1,t2;
create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=bdb;
insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt');
......@@ -81,6 +81,17 @@ create table t1 (a int,b varchar(20)) type=bdb;
insert into t1 values (1,""), (2,"testing");
delete from t1 where a = 1;
select * from t1;
create index skr on t1 (a);
insert into t1 values (3,""), (4,"testing");
analyze table t1;
show keys from t1;
drop table t1;
# Test of reading on secondary key with may be null
create table t1 (a int,b varchar(20),key(a)) type=bdb;
insert into t1 values (1,""), (2,"testing");
select * from t1 where a = 1;
drop table t1;
#
......@@ -352,12 +363,15 @@ CREATE TABLE t1 (
INDEX sca_pic (sca_pic)
) type = bdb ;
INSERT INTO t1 ( sca_code, cat_code, sca_desc, lan_code, sca_pic, sca_sdesc, sca_sch_desc) VALUES ( 'PD', 'J', 'PENDANT', 'EN', NULL, NULL, 'PENDANT'),( 'RI', 'J', 'RING', 'EN', NULL, NULL, 'RING'),( 'QQ', 'J', 'RING', 'EN', 'not null', NULL, 'RING');
INSERT INTO t1 ( sca_code, cat_code, sca_desc, lan_code, sca_pic, sca_sdesc, sca_sch_desc) VALUES ( 'PD', 'J', 'PENDANT', 'EN', NULL, NULL, 'PENDANT'),( 'RI', 'J', 'RING', 'EN', NULL, NULL, 'RING'),( 'QQ', 'N', 'RING', 'EN', 'not null', NULL, 'RING');
select count(*) from t1 where sca_code = 'PD';
select count(*) from t1 where sca_code <= 'PD';
select count(*) from t1 where sca_pic is null;
alter table t1 drop index sca_pic, add index sca_pic (cat_code, sca_pic);
select count(*) from t1 where sca_code='PD' and sca_pic is null;
select count(*) from t1 where cat_code='E';
alter table t1 drop index sca_pic, add index (sca_pic, cat_code);
select count(*) from t1 where sca_code='PD' and sca_pic is null;
select count(*) from t1 where sca_pic >= 'n';
......@@ -385,7 +399,7 @@ flush logs;
#
# Test key on blob with null values
#
create table t1 (b blob, i int, key (b(100)), key (i), key (i, b(20)));
create table t1 (b blob, i int, key (b(100)), key (i), key (i, b(20))) type=bdb;
insert into t1 values ('this is a blob', 1), (null, -1), (null, null),("",1),("",2),("",3);
select b from t1 where b = 'this is a blob';
select * from t1 where b like 't%';
......@@ -399,7 +413,7 @@ drop table t1;
#
# Test with variable length primary key
#
create table t1 (a varchar(100) not null, primary key(a), b int not null);
create table t1 (a varchar(100) not null, primary key(a), b int not null) type=bdb;
insert into t1 values("hello",1),("world",2);
select * from t1 order by b desc;
optimize table t1;
......
# test of problems with having (Reported by Mark Rogers)
#
drop table if exists t1;
create table t1 (a int);
select count(a) as b from t1 where a=0 having b > 0;
insert into t1 values (null);
select count(a) as b from t1 where a=0 having b > 0;
select count(a) as b from t1 where a=0 having b >=0;
drop table t1;
......@@ -3599,7 +3599,7 @@ void Field_varstring::sql_type(String &res) const
char *Field_varstring::pack(char *to, const char *from, uint max_length)
{
uint length=uint2korr(to);
uint length=uint2korr(from);
if (length > max_length)
length=max_length;
*to++= (length & 255);
......@@ -4037,6 +4037,43 @@ void Field_blob::sql_type(String &res) const
}
char *Field_blob::pack(char *to, const char *from, uint max_length)
{
char *save=ptr;
ptr=(char*) from;
ulong length=get_length(); // Length of from string
if (length > max_length)
{
ptr=to;
length=max_length;
store_length(length); // Store max length
ptr=(char*) from;
}
else
memcpy(to,from,packlength); // Copy length
if (length)
{
get_ptr((char**) &from);
memcpy(to+packlength, from,length);
}
ptr=save; // Restore org row pointer
return to+packlength+length;
}
const char *Field_blob::unpack(char *to, const char *from)
{
memcpy(to,from,packlength);
from+=packlength;
ulong length=get_length();
if (length)
memcpy_fixed(to+packlength, &from, sizeof(from));
else
bzero(to+packlength,sizeof(from));
return from+length;
}
/* Keys for blobs are like keys on varchars */
int Field_blob::pack_cmp(const char *a, const char *b, uint key_length)
......@@ -4087,10 +4124,33 @@ int Field_blob::pack_cmp(const char *b, uint key_length)
return my_sortncmp(a,a_length, b,b_length);
}
/* Create a packed key that will be used for storage from a MySQL row */
char *Field_blob::pack_key(char *to, const char *from, uint max_length)
{
uint length=uint2korr(to);
char *save=ptr;
ptr=(char*) from;
ulong length=get_length(); // Length of from string
if (length > max_length)
length=max_length;
*to++= (uchar) length;
if (max_length > 255) // 2 byte length
*to++= (uchar) (length >> 8);
if (length)
{
get_ptr((char**) &from);
memcpy(to, from, length);
}
ptr=save; // Restore org row pointer
return to+length;
}
/* Create a packed key that will be used for storage from a MySQL key */
char *Field_blob::pack_key_from_key_image(char *to, const char *from,
uint max_length)
{
uint length=uint2korr(from);
if (length > max_length)
length=max_length;
*to++= (length & 255);
......@@ -4101,6 +4161,7 @@ char *Field_blob::pack_key(char *to, const char *from, uint max_length)
return to+length;
}
/****************************************************************************
** enum type.
** This is a string which only can have a selection of different values.
......
......@@ -166,7 +166,12 @@ public:
memcpy(to,from,length);
return from+length;
}
virtual char *keypack(char* to, const char *from, uint max_length=~(uint) 0)
virtual char *pack_key(char* to, const char *from, uint max_length)
{
return pack(to,from,max_length);
}
virtual char *pack_key_from_key_image(char* to, const char *from,
uint max_length)
{
return pack(to,from,max_length);
}
......@@ -861,39 +866,10 @@ public:
tmp=(char*) value.ptr(); memcpy_fixed(ptr+packlength,&tmp,sizeof(char*));
return 0;
}
char *pack(char *to, const char *from, uint max_length= ~(uint) 0)
{
ulong length=get_length();
if (length > max_length)
{
length=max_length;
char *save=ptr;
ptr=to;
store_length(length);
ptr=save;
}
else
memcpy(to,from,packlength);
if (length)
{
get_ptr((char**) &from);
memcpy(to+packlength, from,length);
return to+packlength+length;
}
return to+packlength;
}
const char *unpack(char *to, const char *from)
{
memcpy(to,from,packlength);
from+=packlength;
ulong length=get_length();
if (length)
memcpy_fixed(to+packlength, &from, sizeof(from));
else
bzero(to+packlength,sizeof(from));
return from+length;
}
char *pack_key(char *to, const char *from, uint max_length=~(uint) 0);
char *pack(char *to, const char *from, uint max_length= ~(uint) 0);
const char *unpack(char *to, const char *from);
char *pack_key(char *to, const char *from, uint max_length);
char *pack_key_from_key_image(char* to, const char *from, uint max_length);
int pack_cmp(const char *a, const char *b, uint key_length);
int pack_cmp(const char *b, uint key_length);
uint packed_col_length(const char *col_ptr)
......
......@@ -42,7 +42,6 @@
Testing of:
- LOCK TABLES
- BLOBS
- Mark tables that participate in a transaction so that they are not
closed during the transaction. We need to test what happens if
MySQL closes a table that is updated by a not commit transaction.
......@@ -290,7 +289,7 @@ static void berkeley_noticecall(DB_ENV *db_env, db_notices notice)
{
switch (notice)
{
case DB_NOTICE_LOGFILE_CHANGED:
case DB_NOTICE_LOGFILE_CHANGED: /* purecov: tested */
pthread_mutex_lock(&LOCK_manager);
manager_status |= MANAGER_BERKELEY_LOG_CLEANUP;
pthread_mutex_unlock(&LOCK_manager);
......@@ -418,6 +417,10 @@ berkeley_key_cmp(TABLE *table, KEY *key_info, const char *key, uint key_length)
if (key_part->null_bit)
{
key_length--;
/*
With the current usage, the following case will always be FALSE,
because NULL keys are sorted before any other key
*/
if (*key != (table->record[0][key_part->null_offset] &
key_part->null_bit) ? 0 : 1)
return 1;
......@@ -731,7 +734,6 @@ DBT *ha_berkeley::create_key(DBT *key, uint keynr, char *buff,
DBUG_ENTER("create_key");
key->data=buff;
for ( ; key_part != end && key_length > 0; key_part++)
{
if (key_part->null_bit)
......@@ -745,7 +747,7 @@ DBT *ha_berkeley::create_key(DBT *key, uint keynr, char *buff,
}
*buff++ = 1; // Store NOT NULL marker
}
buff=key_part->field->pack(buff,record + key_part->offset,
buff=key_part->field->pack_key(buff,record + key_part->offset,
key_part->length);
key_length-=key_part->length;
}
......@@ -783,7 +785,8 @@ DBT *ha_berkeley::pack_key(DBT *key, uint keynr, char *buff,
}
key_ptr++;
}
buff=key_part->field->keypack(buff,key_ptr,key_part->length);
buff=key_part->field->pack_key_from_key_image(buff,key_ptr,
key_part->length);
key_ptr+=key_part->store_length;
key_length-=key_part->store_length;
}
......@@ -807,7 +810,7 @@ int ha_berkeley::write_row(byte * record)
if ((error=pack_row(&row, record,1)))
DBUG_RETURN(error); /* purecov: inspected */
if (table->keys == 1)
if (table->keys + test(hidden_primary_key) == 1)
{
error=file->put(file, transaction, create_key(&prim_key, primary_key,
key_buff, record),
......@@ -859,8 +862,8 @@ int ha_berkeley::write_row(byte * record)
int new_error = 0;
if (thd_options & OPTION_INTERNAL_SUBTRANSACTIONS)
{
DBUG_PRINT("trans",("aborting subtransaction"));
new_error=txn_abort(sub_trans);
DBUG_PRINT("trans",("aborting subtransaction")); /* purecov: deadcode */
new_error=txn_abort(sub_trans); /* purecov: deadcode */
}
else if (changed_keys)
{
......@@ -871,14 +874,14 @@ int ha_berkeley::write_row(byte * record)
{
if ((new_error = remove_key(sub_trans, keynr, record,
(DBT*) 0, &prim_key)))
break;
break; /* purecov: inspected */
}
}
}
if (new_error)
{
error=new_error; // This shouldn't happen
break;
error=new_error; // This shouldn't happen /* purecov: inspected */
break; /* purecov: inspected */
}
}
}
......@@ -1185,7 +1188,8 @@ int ha_berkeley::remove_key(DB_TXN *trans, uint keynr, const byte *record,
*/
dbug_assert(keynr != primary_key && prim_key->data != key_buff2);
DBC *tmp_cursor;
if (!(error=file->cursor(key_file[keynr], trans, &tmp_cursor, 0)))
if (!(error=key_file[keynr]->cursor(key_file[keynr], trans,
&tmp_cursor, 0)))
{
if (!(error=cursor->c_get(tmp_cursor,
(keynr == primary_key ?
......@@ -1294,8 +1298,9 @@ int ha_berkeley::index_init(uint keynr)
DBUG_ENTER("index_init");
active_index=keynr;
dbug_assert(cursor == 0);
if ((error=file->cursor(key_file[keynr], transaction, &cursor,
table->reginfo.lock_type > TL_WRITE_ALLOW_READ ?
if ((error=key_file[keynr]->cursor(key_file[keynr], transaction, &cursor,
table->reginfo.lock_type >
TL_WRITE_ALLOW_READ ?
0 : 0)))
cursor=0; // Safety /* purecov: inspected */
bzero((char*) &last_key,sizeof(last_key));
......@@ -1353,8 +1358,8 @@ int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row,
current_row.flags=DB_DBT_REALLOC;
if ((error=file->get(file, transaction, &key, &current_row, 0)))
{
table->status=STATUS_NOT_FOUND;
DBUG_RETURN(error == DB_NOTFOUND ? HA_ERR_CRASHED : error);
table->status=STATUS_NOT_FOUND; /* purecov: inspected */
DBUG_RETURN(error == DB_NOTFOUND ? HA_ERR_CRASHED : error); /* purecov: inspected */
}
row= &current_row;
}
......@@ -1371,7 +1376,7 @@ int ha_berkeley::index_read_idx(byte * buf, uint keynr, const byte * key,
statistic_increment(ha_read_key_count,&LOCK_status);
DBUG_ENTER("index_read_idx");
current_row.flags=DB_DBT_REALLOC;
DBUG_RETURN(read_row(file->get(key_file[keynr], transaction,
DBUG_RETURN(read_row(key_file[keynr]->get(key_file[keynr], transaction,
pack_key(&last_key, keynr, key_buff, key,
key_len),
&current_row,0),
......@@ -1389,13 +1394,15 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
statistic_increment(ha_read_key_count,&LOCK_status);
bzero((char*) &row,sizeof(row));
if (key_len == key_info->key_length)
if (key_len == key_info->key_length + key_info->extra_length)
{
error=read_row(cursor->c_get(cursor, pack_key(&last_key,
active_index,
key_buff,
key, key_len),
&row, DB_SET),
&row,
(find_flag == HA_READ_KEY_EXACT ?
DB_SET : DB_SET_RANGE)),
buf, active_index, &row, (DBT*) 0, 0);
}
else
......@@ -1840,13 +1847,15 @@ ha_rows ha_berkeley::records_in_range(int keynr,
{
DBT key;
DB_KEY_RANGE start_range, end_range;
DB *kfile=key_file[keynr];
double start_pos,end_pos,rows;
DBUG_ENTER("records_in_range");
if ((start_key && file->key_range(key_file[keynr],transaction,
if ((start_key && kfile->key_range(kfile,transaction,
pack_key(&key, keynr, key_buff, start_key,
start_key_len),
&start_range,0)) ||
(end_key && file->key_range(key_file[keynr],transaction,
(end_key && kfile->key_range(kfile,transaction,
pack_key(&key, keynr, key_buff, end_key,
end_key_len),
&end_range,0)))
......@@ -1969,8 +1978,8 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
free(stat);
stat=0;
}
if (file->stat(key_file[i], (void*) &stat, 0, 0))
goto err;
if (key_file[i]->stat(key_file[i], (void*) &stat, 0, 0))
goto err; /* purecov: inspected */
share->rec_per_key[i]= (stat->bt_ndata /
(stat->bt_nkeys ? stat->bt_nkeys : 1));
}
......@@ -1983,7 +1992,7 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
stat=0;
}
if (file->stat(file, (void*) &stat, 0, 0))
goto err;
goto err; /* purecov: inspected */
}
pthread_mutex_lock(&share->mutex);
share->rows=stat->bt_ndata;
......@@ -1997,9 +2006,9 @@ int ha_berkeley::analyze(THD* thd, HA_CHECK_OPT* check_opt)
HA_ADMIN_OK);
err:
if (stat)
free(stat);
return HA_ADMIN_FAILED;
if (stat) /* purecov: inspected */
free(stat); /* purecov: inspected */
return HA_ADMIN_FAILED; /* purecov: inspected */
}
int ha_berkeley::optimize(THD* thd, HA_CHECK_OPT* check_opt)
......@@ -2036,7 +2045,7 @@ int ha_berkeley::check(THD* thd, HA_CHECK_OPT* check_opt)
tmp_file->set_bt_compare(tmp_file,
(hidden_primary_key ? berkeley_cmp_hidden_key :
berkeley_cmp_packed_key));
file->app_private= (void*) (table->key_info+table->primary_key);
tmp_file->app_private= (void*) (table->key_info+table->primary_key);
fn_format(name_buff,share->table_name,"", ha_berkeley_ext, 2 | 4);
if ((error=tmp_file->verify(tmp_file, name_buff, NullS, (FILE*) 0,
hidden_primary_key ? 0 : DB_NOORDERCHK)))
......@@ -2196,7 +2205,7 @@ void ha_berkeley::get_status()
{
share->org_rows=share->rows=
table->max_rows ? table->max_rows : HA_BERKELEY_MAX_ROWS;
if (!file->cursor(share->status_block, 0, &cursor, 0))
if (!share->status_block->cursor(share->status_block, 0, &cursor, 0))
{
DBT row;
char rec_buff[64];
......
......@@ -70,7 +70,7 @@ int ha_heap::open(const char *name, int mode, uint test_if_locked)
}
mem_per_row += MY_ALIGN(table->reclength+1, sizeof(char*));
max_rows = (ulong) (max_heap_table_size / mem_per_row);
file=heap_open(table->path,mode,
file=heap_open(name,mode,
table->keys,keydef,
table->reclength,
((table->max_rows < max_rows && table->max_rows) ?
......@@ -278,5 +278,5 @@ int ha_heap::create(const char *name, TABLE *form, HA_CREATE_INFO *create_info)
{
char buff[FN_REFLEN];
return heap_create(fn_format(buff,name,"","",2));
return heap_create(fn_format(buff,name,"","",4+2));
}
......@@ -952,7 +952,7 @@ void sql_print_error(const char *format,...)
#ifndef DBUG_OFF
{
char buff[1024];
vsnprintf(buff,sizeof(buff)-1,format,args);
my_vsnprintf(buff,sizeof(buff)-1,format,args);
DBUG_PRINT("error",("%s",buff));
}
#endif
......
......@@ -314,7 +314,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
{ /* Impossible cond */
error=return_zero_rows(result, tables, fields,
join.tmp_table_param.sum_func_count != 0 && !group,
select_options,"Impossible WHERE",join.having,
select_options,"Impossible WHERE",having,
procedure);
delete procedure;
DBUG_RETURN(error);
......@@ -330,7 +330,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
{
error=return_zero_rows(result, tables, fields, !group,
select_options,"No matching min/max row",
join.having,procedure);
having,procedure);
delete procedure;
DBUG_RETURN(error);
}
......@@ -383,7 +383,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
{
error=return_zero_rows(result,tables,fields,
join.tmp_table_param.sum_func_count != 0 &&
!group,0,"",join.having,procedure);
!group,0,"",having,procedure);
goto err;
}
if (!(thd->options & OPTION_BIG_SELECTS) &&
......@@ -414,7 +414,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
join.tmp_table_param.sum_func_count != 0 && !group,
select_options,
"Impossible WHERE noticed after reading const tables",
join.having,procedure);
having,procedure);
goto err;
}
......
......@@ -531,7 +531,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
{
int err;
if ((err=(outparam->file->
ha_open(index_file,
ha_open(unpack_filename(index_file,index_file),
(db_stat & HA_READ_ONLY ? O_RDONLY : O_RDWR),
(db_stat & HA_OPEN_TEMPORARY ? HA_OPEN_TMP_TABLE :
((db_stat & HA_WAIT_IF_LOCKED) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment